docs: improved analytics and tracking (#13671)
* docs: improved analytics and tracking * remove detailed feedback component * remove ignore build script for api reference * improvements * fix pathname
This commit is contained in:
@@ -1,83 +0,0 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import { useState } from "react"
|
|
||||||
import { Label, TextArea, useAnalytics, useModal, ModalFooter } from "docs-ui"
|
|
||||||
|
|
||||||
const DetailedFeedback = () => {
|
|
||||||
const [improvementFeedback, setImprovementFeedback] = useState("")
|
|
||||||
const [positiveFeedback, setPositiveFeedback] = useState("")
|
|
||||||
const [additionalFeedback, setAdditionalFeedback] = useState("")
|
|
||||||
const { loaded, track } = useAnalytics()
|
|
||||||
const { closeModal } = useModal()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="flex flex-col gap-1 overflow-auto py-1.5 px-2 lg:min-h-[400px]">
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<Label>What should be improved in this API reference?</Label>
|
|
||||||
<TextArea
|
|
||||||
rows={4}
|
|
||||||
value={improvementFeedback}
|
|
||||||
onChange={(e) => setImprovementFeedback(e.target.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<Label>Is there a feature you like in this API reference?</Label>
|
|
||||||
<TextArea
|
|
||||||
rows={4}
|
|
||||||
value={positiveFeedback}
|
|
||||||
onChange={(e) => setPositiveFeedback(e.target.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<Label>Do you have any additional notes or feedback?</Label>
|
|
||||||
<TextArea
|
|
||||||
rows={4}
|
|
||||||
value={additionalFeedback}
|
|
||||||
onChange={(e) => setAdditionalFeedback(e.target.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ModalFooter
|
|
||||||
actions={[
|
|
||||||
{
|
|
||||||
children: "Save",
|
|
||||||
onClick: (e) => {
|
|
||||||
if (
|
|
||||||
!loaded ||
|
|
||||||
(!improvementFeedback &&
|
|
||||||
!positiveFeedback &&
|
|
||||||
!additionalFeedback)
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const buttonElm = e.target as HTMLButtonElement
|
|
||||||
buttonElm.classList.add("cursor-not-allowed")
|
|
||||||
buttonElm.textContent = "Please wait"
|
|
||||||
track(
|
|
||||||
"api-ref-general-feedback",
|
|
||||||
{
|
|
||||||
feedbackData: {
|
|
||||||
improvementFeedback,
|
|
||||||
positiveFeedback,
|
|
||||||
additionalFeedback,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
function () {
|
|
||||||
buttonElm.textContent = "Thank you!"
|
|
||||||
setTimeout(() => {
|
|
||||||
closeModal()
|
|
||||||
}, 1000)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
variant: "primary",
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
className="mt-1"
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default DetailedFeedback
|
|
||||||
23
www/apps/api-reference/components/Feedback/index.tsx
Normal file
23
www/apps/api-reference/components/Feedback/index.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { Feedback as UiFeedback, FeedbackProps } from "docs-ui"
|
||||||
|
import { usePathname } from "next/navigation"
|
||||||
|
import { useArea } from "../../providers/area"
|
||||||
|
|
||||||
|
export const Feedback = (props: Partial<FeedbackProps>) => {
|
||||||
|
const pathname = usePathname()
|
||||||
|
const { area } = useArea()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UiFeedback
|
||||||
|
vertical={true}
|
||||||
|
{...props}
|
||||||
|
event="survey_api-ref"
|
||||||
|
extraData={{
|
||||||
|
area,
|
||||||
|
...props.extraData,
|
||||||
|
}}
|
||||||
|
pathName={`/api/${pathname}`}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -7,9 +7,7 @@ import type { TagsOperationDescriptionSectionResponsesProps } from "./Responses"
|
|||||||
import dynamic from "next/dynamic"
|
import dynamic from "next/dynamic"
|
||||||
import TagsOperationDescriptionSectionParameters from "./Parameters"
|
import TagsOperationDescriptionSectionParameters from "./Parameters"
|
||||||
import MDXContentClient from "@/components/MDXContent/Client"
|
import MDXContentClient from "@/components/MDXContent/Client"
|
||||||
import { useArea } from "../../../../providers/area"
|
|
||||||
import {
|
import {
|
||||||
Feedback,
|
|
||||||
Badge,
|
Badge,
|
||||||
Link,
|
Link,
|
||||||
FeatureFlagNotice,
|
FeatureFlagNotice,
|
||||||
@@ -17,10 +15,10 @@ import {
|
|||||||
Tooltip,
|
Tooltip,
|
||||||
MarkdownContent,
|
MarkdownContent,
|
||||||
} from "docs-ui"
|
} from "docs-ui"
|
||||||
import { usePathname } from "next/navigation"
|
|
||||||
import { TagsOperationDescriptionSectionWorkflowBadgeProps } from "./WorkflowBadge"
|
import { TagsOperationDescriptionSectionWorkflowBadgeProps } from "./WorkflowBadge"
|
||||||
import { TagsOperationDescriptionSectionEventsProps } from "./Events"
|
import { TagsOperationDescriptionSectionEventsProps } from "./Events"
|
||||||
import { TagsOperationDescriptionSectionDeprecationNoticeProps } from "./DeprecationNotice"
|
import { TagsOperationDescriptionSectionDeprecationNoticeProps } from "./DeprecationNotice"
|
||||||
|
import { Feedback } from "@/components/Feedback"
|
||||||
|
|
||||||
const TagsOperationDescriptionSectionSecurity =
|
const TagsOperationDescriptionSectionSecurity =
|
||||||
dynamic<TagsOperationDescriptionSectionSecurityProps>(
|
dynamic<TagsOperationDescriptionSectionSecurityProps>(
|
||||||
@@ -58,9 +56,6 @@ type TagsOperationDescriptionSectionProps = {
|
|||||||
const TagsOperationDescriptionSection = ({
|
const TagsOperationDescriptionSection = ({
|
||||||
operation,
|
operation,
|
||||||
}: TagsOperationDescriptionSectionProps) => {
|
}: TagsOperationDescriptionSectionProps) => {
|
||||||
const { area } = useArea()
|
|
||||||
const pathname = usePathname()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<H2>
|
<H2>
|
||||||
@@ -127,14 +122,10 @@ const TagsOperationDescriptionSection = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area,
|
|
||||||
section: operation.summary,
|
section: operation.summary,
|
||||||
}}
|
}}
|
||||||
pathName={pathname}
|
|
||||||
className="!my-2"
|
className="!my-2"
|
||||||
vertical={true}
|
|
||||||
question="Did this API Route run successfully?"
|
question="Did this API Route run successfully?"
|
||||||
/>
|
/>
|
||||||
{operation.security && (
|
{operation.security && (
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ import SectionContainer from "../../Section/Container"
|
|||||||
import { useArea } from "@/providers/area"
|
import { useArea } from "@/providers/area"
|
||||||
import SectionDivider from "../../Section/Divider"
|
import SectionDivider from "../../Section/Divider"
|
||||||
import clsx from "clsx"
|
import clsx from "clsx"
|
||||||
import { Feedback, Loading, Link } from "docs-ui"
|
import { Loading, Link } from "docs-ui"
|
||||||
import { usePathname, useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
import { OpenAPI } from "types"
|
import { OpenAPI } from "types"
|
||||||
import TagSectionSchema from "./Schema"
|
import TagSectionSchema from "./Schema"
|
||||||
import checkElementInViewport from "../../../utils/check-element-in-viewport"
|
import checkElementInViewport from "../../../utils/check-element-in-viewport"
|
||||||
@@ -29,6 +29,7 @@ import useSWR from "swr"
|
|||||||
import basePathUrl from "../../../utils/base-path-url"
|
import basePathUrl from "../../../utils/base-path-url"
|
||||||
import { getSectionId } from "docs-utils"
|
import { getSectionId } from "docs-utils"
|
||||||
import { RoutesSummary } from "./RoutesSummary"
|
import { RoutesSummary } from "./RoutesSummary"
|
||||||
|
import { Feedback } from "../../Feedback"
|
||||||
|
|
||||||
export type TagSectionProps = {
|
export type TagSectionProps = {
|
||||||
tag: OpenAPI.TagObject
|
tag: OpenAPI.TagObject
|
||||||
@@ -51,7 +52,6 @@ const TagSectionComponent = ({ tag }: TagSectionProps) => {
|
|||||||
const [loadData, setLoadData] = useState(false)
|
const [loadData, setLoadData] = useState(false)
|
||||||
const slugTagName = useMemo(() => getSectionId([tag.name]), [tag])
|
const slugTagName = useMemo(() => getSectionId([tag.name]), [tag])
|
||||||
const { area } = useArea()
|
const { area } = useArea()
|
||||||
const pathname = usePathname()
|
|
||||||
const { scrollableElement, scrollToTop } = useScrollController()
|
const { scrollableElement, scrollToTop } = useScrollController()
|
||||||
const { isBrowser } = useIsBrowser()
|
const { isBrowser } = useIsBrowser()
|
||||||
|
|
||||||
@@ -163,13 +163,9 @@ const TagSectionComponent = ({ tag }: TagSectionProps) => {
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area,
|
|
||||||
section: tag.name,
|
section: tag.name,
|
||||||
}}
|
}}
|
||||||
pathName={pathname}
|
|
||||||
vertical
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
7
www/apps/api-reference/instrumentation-client.ts
Normal file
7
www/apps/api-reference/instrumentation-client.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import posthog from "posthog-js"
|
||||||
|
|
||||||
|
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
||||||
|
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||||
|
person_profiles: "always",
|
||||||
|
defaults: "2025-05-24",
|
||||||
|
})
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Feedback, CodeTabs, CodeTab, H1 } from "docs-ui"
|
import { CodeTabs, CodeTab, H1 } from "docs-ui"
|
||||||
|
import { Feedback } from "@/components/Feedback"
|
||||||
import SectionContainer from "@/components/Section/Container"
|
import SectionContainer from "@/components/Section/Container"
|
||||||
import DividedMarkdownLayout from "@/layouts/DividedMarkdown"
|
import DividedMarkdownLayout from "@/layouts/DividedMarkdown"
|
||||||
import {
|
import {
|
||||||
@@ -24,14 +25,10 @@ This API reference includes Medusa v2's Admin APIs, which are REST APIs exposed
|
|||||||
All API Routes are prefixed with `/admin`. So, during development, the API Routes will be available under the path `http://localhost:9000/admin`. For production, replace `http://localhost:9000` with your Medusa application URL.
|
All API Routes are prefixed with `/admin`. So, during development, the API Routes will be available under the path `http://localhost:9000/admin`. For production, replace `http://localhost:9000` with your Medusa application URL.
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "admin",
|
|
||||||
section: "introduction"
|
section: "introduction"
|
||||||
}}
|
}}
|
||||||
pathName="/api/admin"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownContent>
|
</DividedMarkdownContent>
|
||||||
@@ -391,14 +388,10 @@ fetch(`<BACKEND_URL>/admin/products`, {
|
|||||||
<DividedMarkdownLayout addYSpacing>
|
<DividedMarkdownLayout addYSpacing>
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "admin",
|
|
||||||
section: "authentication-cookie"
|
section: "authentication-cookie"
|
||||||
}}
|
}}
|
||||||
pathName="/api/admin"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownLayout>
|
</DividedMarkdownLayout>
|
||||||
@@ -463,14 +456,10 @@ x-no-compression: false
|
|||||||
<DividedMarkdownLayout addYSpacing>
|
<DividedMarkdownLayout addYSpacing>
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "admin",
|
|
||||||
section: "http-compression"
|
section: "http-compression"
|
||||||
}}
|
}}
|
||||||
pathName="/api/admin"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownLayout>
|
</DividedMarkdownLayout>
|
||||||
@@ -648,14 +637,10 @@ sdk.admin.product.update("prod_123", {
|
|||||||
To remove a property from the `metadata`, pass the property in the request body with an empty string value. This will remove the property from the `metadata` without affecting other properties.
|
To remove a property from the `metadata`, pass the property in the request body with an empty string value. This will remove the property from the `metadata` without affecting other properties.
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "store",
|
|
||||||
section: "metadata"
|
section: "metadata"
|
||||||
}}
|
}}
|
||||||
pathName="/api/store"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownContent>
|
</DividedMarkdownContent>
|
||||||
@@ -942,14 +927,10 @@ However, some API routes restrict the fields and relations you can retrieve. To
|
|||||||
<DividedMarkdownLayout>
|
<DividedMarkdownLayout>
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "admin",
|
|
||||||
section: "select-fields"
|
section: "select-fields"
|
||||||
}}
|
}}
|
||||||
pathName="/api/admin"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownLayout>
|
</DividedMarkdownLayout>
|
||||||
@@ -1315,14 +1296,10 @@ curl -g "http://localhost:9000/admin/products?created_at[$lt]=2023-02-17&created
|
|||||||
<DividedMarkdownLayout>
|
<DividedMarkdownLayout>
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "admin",
|
|
||||||
section: "query-parameters"
|
section: "query-parameters"
|
||||||
}}
|
}}
|
||||||
pathName="/api/admin"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownLayout>
|
</DividedMarkdownLayout>
|
||||||
@@ -1496,14 +1473,10 @@ This sorts the products by their `created_at` field in the descending order.
|
|||||||
<DividedMarkdownLayout>
|
<DividedMarkdownLayout>
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "admin",
|
|
||||||
section: "pagination"
|
section: "pagination"
|
||||||
}}
|
}}
|
||||||
pathName="/api/admin"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownLayout>
|
</DividedMarkdownLayout>
|
||||||
@@ -1527,14 +1500,10 @@ This is useful if you want to extend an API route and pass additional data or pe
|
|||||||
Refer to [this guide](!docs!/learn/customization/extend-features/extend-create-product) to find an example of extending an API route.
|
Refer to [this guide](!docs!/learn/customization/extend-features/extend-create-product) to find an example of extending an API route.
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "admin",
|
|
||||||
section: "workflows"
|
section: "workflows"
|
||||||
}}
|
}}
|
||||||
pathName="/api/admin"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownContent>
|
</DividedMarkdownContent>
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import {
|
|||||||
DividedMarkdownCode
|
DividedMarkdownCode
|
||||||
} from "@/layouts/DividedMarkdown/Sections"
|
} from "@/layouts/DividedMarkdown/Sections"
|
||||||
import Section from "@/components/Section"
|
import Section from "@/components/Section"
|
||||||
import { Feedback, CodeTabs, CodeTab, H1 } from "docs-ui"
|
import { CodeTabs, CodeTab, H1 } from "docs-ui"
|
||||||
|
import { Feedback } from "@/components/Feedback"
|
||||||
|
|
||||||
import ClientLibraries from "./client-libraries.mdx"
|
import ClientLibraries from "./client-libraries.mdx"
|
||||||
|
|
||||||
@@ -24,14 +25,10 @@ This API reference includes Medusa v2's Store APIs, which are REST APIs exposed
|
|||||||
All API Routes are prefixed with `/store`. So, during development, the API Routes will be available under the path `http://localhost:9000/store`. For production, replace `http://localhost:9000` with your Medusa application URL.
|
All API Routes are prefixed with `/store`. So, during development, the API Routes will be available under the path `http://localhost:9000/store`. For production, replace `http://localhost:9000` with your Medusa application URL.
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "store",
|
|
||||||
section: "introduction"
|
section: "introduction"
|
||||||
}}
|
}}
|
||||||
pathName="/api/store"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownContent>
|
</DividedMarkdownContent>
|
||||||
@@ -264,14 +261,10 @@ fetch(`<BACKEND_URL>/store/products`, {
|
|||||||
<DividedMarkdownLayout addYSpacing>
|
<DividedMarkdownLayout addYSpacing>
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "store",
|
|
||||||
section: "authentication-cookie"
|
section: "authentication-cookie"
|
||||||
}}
|
}}
|
||||||
pathName="/api/store"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownLayout>
|
</DividedMarkdownLayout>
|
||||||
@@ -349,14 +342,10 @@ Where `{your_publishable_api_key}` is the token of the publishable API key. When
|
|||||||
<DividedMarkdownLayout>
|
<DividedMarkdownLayout>
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "store",
|
|
||||||
section: "publishable-api-key"
|
section: "publishable-api-key"
|
||||||
}}
|
}}
|
||||||
pathName="/api/store"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownLayout>
|
</DividedMarkdownLayout>
|
||||||
@@ -421,14 +410,10 @@ x-no-compression: false
|
|||||||
<DividedMarkdownLayout>
|
<DividedMarkdownLayout>
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "store",
|
|
||||||
section: "http-compression"
|
section: "http-compression"
|
||||||
}}
|
}}
|
||||||
pathName="/api/store"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownLayout>
|
</DividedMarkdownLayout>
|
||||||
@@ -624,14 +609,10 @@ sdk.store.cart.updateLineItem(
|
|||||||
To remove a property from the `metadata`, pass the property in the request body with an empty string value. This will remove the property from the `metadata` without affecting other properties.
|
To remove a property from the `metadata`, pass the property in the request body with an empty string value. This will remove the property from the `metadata` without affecting other properties.
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "store",
|
|
||||||
section: "metadata"
|
section: "metadata"
|
||||||
}}
|
}}
|
||||||
pathName="/api/store"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownContent>
|
</DividedMarkdownContent>
|
||||||
@@ -925,14 +906,10 @@ However, some API routes restrict the fields and relations you can retrieve. To
|
|||||||
<DividedMarkdownLayout>
|
<DividedMarkdownLayout>
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "store",
|
|
||||||
section: "select-fields"
|
section: "select-fields"
|
||||||
}}
|
}}
|
||||||
pathName="/api/store"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownLayout>
|
</DividedMarkdownLayout>
|
||||||
@@ -1289,14 +1266,10 @@ curl -g "http://localhost:9000/store/products?created_at[$lt]=2023-02-17&created
|
|||||||
<DividedMarkdownLayout>
|
<DividedMarkdownLayout>
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "store",
|
|
||||||
section: "query-parameters"
|
section: "query-parameters"
|
||||||
}}
|
}}
|
||||||
pathName="/api/store"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownLayout>
|
</DividedMarkdownLayout>
|
||||||
@@ -1468,14 +1441,10 @@ This sorts the products by their `created_at` field in the descending order.
|
|||||||
<DividedMarkdownLayout>
|
<DividedMarkdownLayout>
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "store",
|
|
||||||
section: "pagination"
|
section: "pagination"
|
||||||
}}
|
}}
|
||||||
pathName="/api/store"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownLayout>
|
</DividedMarkdownLayout>
|
||||||
@@ -1499,14 +1468,10 @@ This is useful if you want to extend an API route and pass additional data or pe
|
|||||||
Refer to [this guide](!docs!/learn/customization/extend-features/extend-create-product) to find an example of extending an API route.
|
Refer to [this guide](!docs!/learn/customization/extend-features/extend-create-product) to find an example of extending an API route.
|
||||||
|
|
||||||
<Feedback
|
<Feedback
|
||||||
event="survey_api-ref"
|
|
||||||
extraData={{
|
extraData={{
|
||||||
area: "store",
|
|
||||||
section: "workflows"
|
section: "workflows"
|
||||||
}}
|
}}
|
||||||
pathName="/api/store"
|
|
||||||
question="Was this section helpful?"
|
question="Was this section helpful?"
|
||||||
vertical={true}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</DividedMarkdownContent>
|
</DividedMarkdownContent>
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
"openapi-sampler": "^1.3.1",
|
"openapi-sampler": "^1.3.1",
|
||||||
"pluralize": "^8.0.0",
|
"pluralize": "^8.0.0",
|
||||||
"postcss": "8.4.27",
|
"postcss": "8.4.27",
|
||||||
|
"posthog-js": "^1.269.1",
|
||||||
"prism-react-renderer": "2.4.0",
|
"prism-react-renderer": "2.4.0",
|
||||||
"react": "rc",
|
"react": "rc",
|
||||||
"react-dom": "rc",
|
"react-dom": "rc",
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ const Providers = ({ children }: ProvidersProps) => {
|
|||||||
<AnalyticsProvider
|
<AnalyticsProvider
|
||||||
segmentWriteKey={process.env.NEXT_PUBLIC_SEGMENT_API_KEY}
|
segmentWriteKey={process.env.NEXT_PUBLIC_SEGMENT_API_KEY}
|
||||||
reoDevKey={process.env.NEXT_PUBLIC_REO_DEV_CLIENT_ID}
|
reoDevKey={process.env.NEXT_PUBLIC_REO_DEV_CLIENT_ID}
|
||||||
postHogKey={process.env.NEXT_PUBLIC_POSTHOG_KEY}
|
|
||||||
postHogApiHost={process.env.NEXT_PUBLIC_POSTHOG_HOST}
|
|
||||||
>
|
>
|
||||||
<SiteConfigProvider config={config}>
|
<SiteConfigProvider config={config}>
|
||||||
<PageLoadingProvider>
|
<PageLoadingProvider>
|
||||||
|
|||||||
@@ -6,6 +6,5 @@
|
|||||||
"framework": "nextjs",
|
"framework": "nextjs",
|
||||||
"installCommand": "yarn install",
|
"installCommand": "yarn install",
|
||||||
"buildCommand": "turbo run build",
|
"buildCommand": "turbo run build",
|
||||||
"outputDirectory": ".next",
|
"outputDirectory": ".next"
|
||||||
"ignoreCommand": "bash ../../ignore-build-script.sh api-reference"
|
|
||||||
}
|
}
|
||||||
|
|||||||
7
www/apps/book/instrumentation-client.ts
Normal file
7
www/apps/book/instrumentation-client.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import posthog from "posthog-js"
|
||||||
|
|
||||||
|
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
||||||
|
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||||
|
person_profiles: "always",
|
||||||
|
defaults: "2025-05-24",
|
||||||
|
})
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
"docs-ui": "*",
|
"docs-ui": "*",
|
||||||
"docs-utils": "*",
|
"docs-utils": "*",
|
||||||
"next": "15.3.5",
|
"next": "15.3.5",
|
||||||
|
"posthog-js": "^1.269.1",
|
||||||
"react": "rc",
|
"react": "rc",
|
||||||
"react-dom": "rc",
|
"react-dom": "rc",
|
||||||
"rehype-mdx-code-props": "^2.0.0",
|
"rehype-mdx-code-props": "^2.0.0",
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ const Providers = ({ children, aiAssistantProps = {} }: ProvidersProps) => {
|
|||||||
<AnalyticsProvider
|
<AnalyticsProvider
|
||||||
segmentWriteKey={process.env.NEXT_PUBLIC_SEGMENT_API_KEY}
|
segmentWriteKey={process.env.NEXT_PUBLIC_SEGMENT_API_KEY}
|
||||||
reoDevKey={process.env.NEXT_PUBLIC_REO_DEV_CLIENT_ID}
|
reoDevKey={process.env.NEXT_PUBLIC_REO_DEV_CLIENT_ID}
|
||||||
postHogKey={process.env.NEXT_PUBLIC_POSTHOG_KEY}
|
|
||||||
postHogApiHost={process.env.NEXT_PUBLIC_POSTHOG_HOST}
|
|
||||||
>
|
>
|
||||||
<SiteConfigProvider config={config}>
|
<SiteConfigProvider config={config}>
|
||||||
<LearningPathProvider>
|
<LearningPathProvider>
|
||||||
|
|||||||
7
www/apps/cloud/instrumentation-client.ts
Normal file
7
www/apps/cloud/instrumentation-client.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import posthog from "posthog-js"
|
||||||
|
|
||||||
|
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
||||||
|
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||||
|
person_profiles: "always",
|
||||||
|
defaults: "2025-05-24",
|
||||||
|
})
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"docs-ui": "*",
|
"docs-ui": "*",
|
||||||
"next": "15.3.5",
|
"next": "15.3.5",
|
||||||
|
"posthog-js": "^1.269.1",
|
||||||
"react": "rc",
|
"react": "rc",
|
||||||
"react-dom": "rc",
|
"react-dom": "rc",
|
||||||
"rehype-mdx-code-props": "^2.0.0",
|
"rehype-mdx-code-props": "^2.0.0",
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ const Providers = ({ children }: ProvidersProps) => {
|
|||||||
<AnalyticsProvider
|
<AnalyticsProvider
|
||||||
segmentWriteKey={process.env.NEXT_PUBLIC_SEGMENT_API_KEY}
|
segmentWriteKey={process.env.NEXT_PUBLIC_SEGMENT_API_KEY}
|
||||||
reoDevKey={process.env.NEXT_PUBLIC_REO_DEV_CLIENT_ID}
|
reoDevKey={process.env.NEXT_PUBLIC_REO_DEV_CLIENT_ID}
|
||||||
postHogKey={process.env.NEXT_PUBLIC_POSTHOG_KEY}
|
|
||||||
postHogApiHost={process.env.NEXT_PUBLIC_POSTHOG_HOST}
|
|
||||||
>
|
>
|
||||||
<SiteConfigProvider config={config}>
|
<SiteConfigProvider config={config}>
|
||||||
<MobileProvider>
|
<MobileProvider>
|
||||||
|
|||||||
7
www/apps/resources/instrumentation-client.ts
Normal file
7
www/apps/resources/instrumentation-client.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import posthog from "posthog-js"
|
||||||
|
|
||||||
|
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
||||||
|
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||||
|
person_profiles: "always",
|
||||||
|
defaults: "2025-05-24",
|
||||||
|
})
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"docs-ui": "*",
|
"docs-ui": "*",
|
||||||
"next": "15.3.5",
|
"next": "15.3.5",
|
||||||
|
"posthog-js": "^1.269.1",
|
||||||
"react": "rc",
|
"react": "rc",
|
||||||
"react-dom": "rc",
|
"react-dom": "rc",
|
||||||
"rehype-mdx-code-props": "^2.0.0",
|
"rehype-mdx-code-props": "^2.0.0",
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ const Providers = ({ children }: ProvidersProps) => {
|
|||||||
<AnalyticsProvider
|
<AnalyticsProvider
|
||||||
segmentWriteKey={process.env.NEXT_PUBLIC_SEGMENT_API_KEY}
|
segmentWriteKey={process.env.NEXT_PUBLIC_SEGMENT_API_KEY}
|
||||||
reoDevKey={process.env.NEXT_PUBLIC_REO_DEV_CLIENT_ID}
|
reoDevKey={process.env.NEXT_PUBLIC_REO_DEV_CLIENT_ID}
|
||||||
postHogKey={process.env.NEXT_PUBLIC_POSTHOG_KEY}
|
|
||||||
postHogApiHost={process.env.NEXT_PUBLIC_POSTHOG_HOST}
|
|
||||||
>
|
>
|
||||||
<SiteConfigProvider config={config}>
|
<SiteConfigProvider config={config}>
|
||||||
<LearningPathProvider
|
<LearningPathProvider
|
||||||
|
|||||||
7
www/apps/ui/instrumentation-client.ts
Normal file
7
www/apps/ui/instrumentation-client.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import posthog from "posthog-js"
|
||||||
|
|
||||||
|
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
||||||
|
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||||
|
person_profiles: "always",
|
||||||
|
defaults: "2025-05-24",
|
||||||
|
})
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"docs-ui": "*",
|
"docs-ui": "*",
|
||||||
"next": "15.3.5",
|
"next": "15.3.5",
|
||||||
|
"posthog-js": "^1.269.1",
|
||||||
"react": "rc",
|
"react": "rc",
|
||||||
"react-dom": "rc",
|
"react-dom": "rc",
|
||||||
"rehype-mdx-code-props": "^2.0.0",
|
"rehype-mdx-code-props": "^2.0.0",
|
||||||
|
|||||||
@@ -28,8 +28,6 @@ const Providers = ({ children }: ProvidersProps) => {
|
|||||||
<AnalyticsProvider
|
<AnalyticsProvider
|
||||||
segmentWriteKey={process.env.NEXT_PUBLIC_SEGMENT_API_KEY}
|
segmentWriteKey={process.env.NEXT_PUBLIC_SEGMENT_API_KEY}
|
||||||
reoDevKey={process.env.NEXT_PUBLIC_REO_DEV_CLIENT_ID}
|
reoDevKey={process.env.NEXT_PUBLIC_REO_DEV_CLIENT_ID}
|
||||||
postHogKey={process.env.NEXT_PUBLIC_POSTHOG_KEY}
|
|
||||||
postHogApiHost={process.env.NEXT_PUBLIC_POSTHOG_HOST}
|
|
||||||
>
|
>
|
||||||
<SiteConfigProvider config={config}>
|
<SiteConfigProvider config={config}>
|
||||||
<MobileProvider>
|
<MobileProvider>
|
||||||
|
|||||||
7
www/apps/user-guide/instrumentation-client.ts
Normal file
7
www/apps/user-guide/instrumentation-client.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import posthog from "posthog-js"
|
||||||
|
|
||||||
|
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
||||||
|
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||||
|
person_profiles: "always",
|
||||||
|
defaults: "2025-05-24",
|
||||||
|
})
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"docs-ui": "*",
|
"docs-ui": "*",
|
||||||
"next": "15.3.5",
|
"next": "15.3.5",
|
||||||
|
"posthog-js": "^1.269.1",
|
||||||
"react": "rc",
|
"react": "rc",
|
||||||
"react-dom": "rc",
|
"react-dom": "rc",
|
||||||
"rehype-mdx-code-props": "^2.0.0",
|
"rehype-mdx-code-props": "^2.0.0",
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ const Providers = ({ children }: ProvidersProps) => {
|
|||||||
<AnalyticsProvider
|
<AnalyticsProvider
|
||||||
segmentWriteKey={process.env.NEXT_PUBLIC_SEGMENT_API_KEY}
|
segmentWriteKey={process.env.NEXT_PUBLIC_SEGMENT_API_KEY}
|
||||||
reoDevKey={process.env.NEXT_PUBLIC_REO_DEV_CLIENT_ID}
|
reoDevKey={process.env.NEXT_PUBLIC_REO_DEV_CLIENT_ID}
|
||||||
postHogKey={process.env.NEXT_PUBLIC_POSTHOG_KEY}
|
|
||||||
postHogApiHost={process.env.NEXT_PUBLIC_POSTHOG_HOST}
|
|
||||||
>
|
>
|
||||||
<SiteConfigProvider config={config}>
|
<SiteConfigProvider config={config}>
|
||||||
<MobileProvider>
|
<MobileProvider>
|
||||||
|
|||||||
@@ -52,6 +52,7 @@
|
|||||||
"@types/react": "*",
|
"@types/react": "*",
|
||||||
"@types/react-dom": "*",
|
"@types/react-dom": "*",
|
||||||
"next": "*",
|
"next": "*",
|
||||||
|
"posthog-js": "*",
|
||||||
"react": "*",
|
"react": "*",
|
||||||
"react-dom": "*"
|
"react-dom": "*"
|
||||||
},
|
},
|
||||||
@@ -70,7 +71,6 @@
|
|||||||
"mermaid": "^10.9.0",
|
"mermaid": "^10.9.0",
|
||||||
"minisearch": "^7.1.1",
|
"minisearch": "^7.1.1",
|
||||||
"npm-to-yarn": "^2.1.0",
|
"npm-to-yarn": "^2.1.0",
|
||||||
"posthog-js": "^1.269.0",
|
|
||||||
"prism-react-renderer": "2.4.0",
|
"prism-react-renderer": "2.4.0",
|
||||||
"react": "rc",
|
"react": "rc",
|
||||||
"react-dom": "rc",
|
"react-dom": "rc",
|
||||||
|
|||||||
@@ -105,28 +105,31 @@ export const Feedback = ({
|
|||||||
if (showForm) {
|
if (showForm) {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
}
|
}
|
||||||
track(
|
track({
|
||||||
event,
|
event: {
|
||||||
{
|
event,
|
||||||
url: pathName,
|
options: {
|
||||||
label: document.title,
|
url: pathName,
|
||||||
feedback:
|
label: document.title,
|
||||||
(feedback !== null && feedback) ||
|
feedback:
|
||||||
(feedback === null && positiveFeedback)
|
(feedback !== null && feedback) ||
|
||||||
? "yes"
|
(feedback === null && positiveFeedback)
|
||||||
: "no",
|
? "yes"
|
||||||
message: message?.length ? message : null,
|
: "no",
|
||||||
os: window.navigator.userAgent,
|
message: message?.length ? message : null,
|
||||||
feedbackOption,
|
os: window.navigator.userAgent,
|
||||||
...extraData,
|
feedbackOption,
|
||||||
|
...extraData,
|
||||||
|
},
|
||||||
|
callback: function () {
|
||||||
|
if (showForm) {
|
||||||
|
setLoading(false)
|
||||||
|
resetForm()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tracker: ["segment", "posthog"],
|
||||||
},
|
},
|
||||||
function () {
|
})
|
||||||
if (showForm) {
|
|
||||||
setLoading(false)
|
|
||||||
resetForm()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetForm() {
|
function resetForm() {
|
||||||
|
|||||||
@@ -31,14 +31,16 @@ export const Rating: React.FC<RatingProps> = ({
|
|||||||
|
|
||||||
const submitTracking = useCallback(
|
const submitTracking = useCallback(
|
||||||
(selectedRating?: number, feedback?: string) => {
|
(selectedRating?: number, feedback?: string) => {
|
||||||
track(
|
track({
|
||||||
event,
|
event: {
|
||||||
{
|
event,
|
||||||
rating: selectedRating || rating,
|
options: {
|
||||||
additionalFeedback: feedback || additionalFeedback,
|
rating: selectedRating || rating,
|
||||||
|
additionalFeedback: feedback || additionalFeedback,
|
||||||
|
},
|
||||||
|
callback: () => onRating?.(selectedRating || rating),
|
||||||
},
|
},
|
||||||
() => onRating?.(selectedRating || rating)
|
})
|
||||||
)
|
|
||||||
},
|
},
|
||||||
[rating, additionalFeedback]
|
[rating, additionalFeedback]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,98 +0,0 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import clsx from "clsx"
|
|
||||||
import React, { useRef, useState } from "react"
|
|
||||||
import {
|
|
||||||
BorderedIcon,
|
|
||||||
getOsShortcut,
|
|
||||||
useAnalytics,
|
|
||||||
useClickOutside,
|
|
||||||
useSidebar,
|
|
||||||
} from "../../../.."
|
|
||||||
import {
|
|
||||||
EllipsisHorizontal,
|
|
||||||
SidebarLeft,
|
|
||||||
TimelineVertical,
|
|
||||||
} from "@medusajs/icons"
|
|
||||||
import { HouseIcon } from "../../../Icons/House"
|
|
||||||
import { Menu } from "../../../Menu"
|
|
||||||
|
|
||||||
export const SidebarTopMedusaMenu = () => {
|
|
||||||
const [openMenu, setOpenMenu] = useState(false)
|
|
||||||
const { setDesktopSidebarOpen } = useSidebar()
|
|
||||||
const { track } = useAnalytics()
|
|
||||||
const ref = useRef<HTMLDivElement>(null)
|
|
||||||
|
|
||||||
const toggleOpen = () => {
|
|
||||||
setOpenMenu((prev) => !prev)
|
|
||||||
if (!openMenu) {
|
|
||||||
track("nav_sidebar_open", {
|
|
||||||
url: window.location.href,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useClickOutside({
|
|
||||||
elmRef: ref,
|
|
||||||
onClickOutside: () => {
|
|
||||||
setOpenMenu(false)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={clsx("p-docs_0.75", "relative")} ref={ref}>
|
|
||||||
<div
|
|
||||||
className={clsx(
|
|
||||||
"flex justify-between items-center gap-docs_0.5",
|
|
||||||
"rounded-docs_sm hover:bg-medusa-bg-subtle-hover cursor-pointer",
|
|
||||||
"py-docs_0.125 pl-docs_0.125 pr-docs_0.5"
|
|
||||||
)}
|
|
||||||
tabIndex={-1}
|
|
||||||
onClick={toggleOpen}
|
|
||||||
>
|
|
||||||
<BorderedIcon icon="/images/logo.png" />
|
|
||||||
<span className="text-compact-small-plus text-medusa-fg-base flex-1">
|
|
||||||
Medusa Docs
|
|
||||||
</span>
|
|
||||||
<EllipsisHorizontal className="text-medusa-fg-muted" />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={clsx(
|
|
||||||
"absolute w-[calc(100%-16px)] bottom-[calc(-100%-40px)]",
|
|
||||||
"left-docs_0.5 z-40",
|
|
||||||
!openMenu && "hidden"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Menu
|
|
||||||
items={[
|
|
||||||
{
|
|
||||||
type: "link",
|
|
||||||
icon: <HouseIcon />,
|
|
||||||
title: "Homepage",
|
|
||||||
link: "https://medusajs.com",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "link",
|
|
||||||
icon: <TimelineVertical />,
|
|
||||||
title: "Changelog",
|
|
||||||
link: "https://medusajs.com/changelog",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "divider",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: "action",
|
|
||||||
title: "Hide Sidebar",
|
|
||||||
icon: <SidebarLeft />,
|
|
||||||
shortcut: `${getOsShortcut()}.`,
|
|
||||||
action: () => {
|
|
||||||
setDesktopSidebarOpen(false)
|
|
||||||
setOpenMenu(false)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,6 @@ import React, {
|
|||||||
useState,
|
useState,
|
||||||
} from "react"
|
} from "react"
|
||||||
import { Analytics, AnalyticsBrowser } from "@segment/analytics-next"
|
import { Analytics, AnalyticsBrowser } from "@segment/analytics-next"
|
||||||
import { PostHogProvider as PHProvider } from "posthog-js/react"
|
|
||||||
import posthog from "posthog-js"
|
import posthog from "posthog-js"
|
||||||
|
|
||||||
// @ts-expect-error Doesn't have a types package
|
// @ts-expect-error Doesn't have a types package
|
||||||
@@ -22,16 +21,22 @@ export type ExtraData = {
|
|||||||
export type AnalyticsContextType = {
|
export type AnalyticsContextType = {
|
||||||
loaded: boolean
|
loaded: boolean
|
||||||
analytics: Analytics | null
|
analytics: Analytics | null
|
||||||
track: (
|
track: ({
|
||||||
event: string,
|
event,
|
||||||
options?: Record<string, any>,
|
instant,
|
||||||
callback?: () => void
|
}: {
|
||||||
) => void
|
event: TrackedEvent
|
||||||
|
instant?: boolean
|
||||||
|
}) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Trackers = "segment" | "posthog"
|
||||||
|
|
||||||
export type TrackedEvent = {
|
export type TrackedEvent = {
|
||||||
event: string
|
event: string
|
||||||
options?: Record<string, any>
|
options?: Record<string, any>
|
||||||
|
callback?: () => void
|
||||||
|
tracker?: Trackers | Trackers[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const AnalyticsContext = createContext<AnalyticsContextType | null>(null)
|
const AnalyticsContext = createContext<AnalyticsContextType | null>(null)
|
||||||
@@ -39,8 +44,6 @@ const AnalyticsContext = createContext<AnalyticsContextType | null>(null)
|
|||||||
export type AnalyticsProviderProps = {
|
export type AnalyticsProviderProps = {
|
||||||
segmentWriteKey?: string
|
segmentWriteKey?: string
|
||||||
reoDevKey?: string
|
reoDevKey?: string
|
||||||
postHogKey?: string
|
|
||||||
postHogApiHost?: string
|
|
||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,8 +53,6 @@ export const AnalyticsProvider = ({
|
|||||||
segmentWriteKey = "temp",
|
segmentWriteKey = "temp",
|
||||||
reoDevKey,
|
reoDevKey,
|
||||||
children,
|
children,
|
||||||
postHogKey,
|
|
||||||
postHogApiHost = "https://eu.i.posthog.com",
|
|
||||||
}: AnalyticsProviderProps) => {
|
}: AnalyticsProviderProps) => {
|
||||||
// loaded is used to ensure that a connection has been made to segment
|
// loaded is used to ensure that a connection has been made to segment
|
||||||
// even if it failed. This is to ensure that the connection isn't
|
// even if it failed. This is to ensure that the connection isn't
|
||||||
@@ -85,21 +86,13 @@ export const AnalyticsProvider = ({
|
|||||||
}
|
}
|
||||||
}, [loaded, segmentWriteKey])
|
}, [loaded, segmentWriteKey])
|
||||||
|
|
||||||
const track = useCallback(
|
const trackWithSegment = useCallback(
|
||||||
async (
|
async ({ event, options }: TrackedEvent) => {
|
||||||
event: string,
|
|
||||||
options?: Record<string, any>,
|
|
||||||
callback?: () => void
|
|
||||||
) => {
|
|
||||||
if (analytics) {
|
if (analytics) {
|
||||||
void analytics.track(
|
void analytics.track(event, {
|
||||||
event,
|
...options,
|
||||||
{
|
uuid: analytics.user().anonymousId(),
|
||||||
...options,
|
})
|
||||||
uuid: analytics.user().anonymousId(),
|
|
||||||
},
|
|
||||||
callback
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
// push the event into the queue
|
// push the event into the queue
|
||||||
setQueue((prevQueue) => [
|
setQueue((prevQueue) => [
|
||||||
@@ -107,45 +100,70 @@ export const AnalyticsProvider = ({
|
|||||||
{
|
{
|
||||||
event,
|
event,
|
||||||
options,
|
options,
|
||||||
|
tracker: "segment",
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
if (callback) {
|
console.warn(
|
||||||
console.warn(
|
"Segment is either not installed or not configured. Simulating success..."
|
||||||
"Segment is either not installed or not configured. Simulating success..."
|
)
|
||||||
)
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[analytics, loaded]
|
[analytics, loaded]
|
||||||
)
|
)
|
||||||
|
|
||||||
const initPostHog = useCallback(() => {
|
const trackWithPostHog = async ({ event, options }: TrackedEvent) => {
|
||||||
if (!postHogKey) {
|
posthog.capture(event, options)
|
||||||
return
|
}
|
||||||
}
|
|
||||||
|
|
||||||
posthog.init(postHogKey, {
|
const processEvent = useCallback(
|
||||||
api_host: postHogApiHost,
|
async (event: TrackedEvent) => {
|
||||||
person_profiles: "always",
|
const trackers = Array.isArray(event.tracker)
|
||||||
defaults: "2025-05-24",
|
? event.tracker
|
||||||
})
|
: [event.tracker]
|
||||||
}, [])
|
await Promise.all(
|
||||||
|
trackers.map(async (tracker) => {
|
||||||
|
switch (tracker) {
|
||||||
|
case "posthog":
|
||||||
|
return trackWithPostHog(event)
|
||||||
|
case "segment":
|
||||||
|
default:
|
||||||
|
return trackWithSegment(event)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
},
|
||||||
|
[trackWithSegment, trackWithPostHog]
|
||||||
|
)
|
||||||
|
|
||||||
|
const track = ({ event }: { event: TrackedEvent }) => {
|
||||||
|
// Always queue events - this makes tracking non-blocking
|
||||||
|
setQueue((prevQueue) => [...prevQueue, event])
|
||||||
|
|
||||||
|
// Process event callback immediately
|
||||||
|
// This ensures that the callback is called even if the event is queued
|
||||||
|
event.callback?.()
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
initSegment()
|
initSegment()
|
||||||
initPostHog()
|
|
||||||
}, [initSegment])
|
}, [initSegment])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (analytics && queue.length) {
|
if (analytics && queue.length) {
|
||||||
// track stuff in queue
|
// Process queue in background without blocking
|
||||||
queue.forEach(async (trackEvent) =>
|
const currentQueue = [...queue]
|
||||||
track(trackEvent.event, trackEvent.options)
|
|
||||||
)
|
|
||||||
setQueue([])
|
setQueue([])
|
||||||
|
|
||||||
|
// Process events asynchronously in batches to avoid overwhelming the system
|
||||||
|
const batchSize = 5
|
||||||
|
for (let i = 0; i < currentQueue.length; i += batchSize) {
|
||||||
|
const batch = currentQueue.slice(i, i + batchSize)
|
||||||
|
setTimeout(() => {
|
||||||
|
batch.forEach(processEvent)
|
||||||
|
}, i * 10) // Small delay between batches
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [analytics, queue])
|
}, [analytics, queue, trackWithSegment, trackWithPostHog, processEvent])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!reoDevKey) {
|
if (!reoDevKey) {
|
||||||
@@ -155,12 +173,12 @@ export const AnalyticsProvider = ({
|
|||||||
loadReoScript({
|
loadReoScript({
|
||||||
clientID: reoDevKey,
|
clientID: reoDevKey,
|
||||||
})
|
})
|
||||||
.then((Reo: any) => {
|
.then((Reo: unknown) => {
|
||||||
Reo.init({
|
;(Reo as { init: (config: { clientID: string }) => void }).init({
|
||||||
clientID: reoDevKey,
|
clientID: reoDevKey,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch((e: any) => {
|
.catch((e: Error) => {
|
||||||
console.error(`Could not connect to Reodotdev. Error: ${e}`)
|
console.error(`Could not connect to Reodotdev. Error: ${e}`)
|
||||||
})
|
})
|
||||||
}, [reoDevKey])
|
}, [reoDevKey])
|
||||||
@@ -173,11 +191,7 @@ export const AnalyticsProvider = ({
|
|||||||
loaded,
|
loaded,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{postHogKey ? (
|
{children}
|
||||||
<PHProvider client={posthog}>{children}</PHProvider>
|
|
||||||
) : (
|
|
||||||
children
|
|
||||||
)}
|
|
||||||
</AnalyticsContext.Provider>
|
</AnalyticsContext.Provider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,9 +71,14 @@ export const LearningPathProvider: React.FC<LearningPathProviderProps> = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
track(`learning_path_${path.name}`, {
|
track({
|
||||||
url: pathname,
|
event: {
|
||||||
state: `start`,
|
event: `learning_path_${path.name}`,
|
||||||
|
options: {
|
||||||
|
url: pathname,
|
||||||
|
state: `start`,
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,14 +91,19 @@ export const LearningPathProvider: React.FC<LearningPathProviderProps> = ({
|
|||||||
const endPath = () => {
|
const endPath = () => {
|
||||||
const didFinish = currentStep === (path?.steps.length || 0) - 1
|
const didFinish = currentStep === (path?.steps.length || 0) - 1
|
||||||
const reachedIndex = currentStep === -1 ? 0 : currentStep
|
const reachedIndex = currentStep === -1 ? 0 : currentStep
|
||||||
track(`learning_path_${path?.name}`, {
|
track({
|
||||||
url: pathname,
|
event: {
|
||||||
state: !didFinish ? `closed` : `end`,
|
event: `learning_path_${path?.name}`,
|
||||||
reachedStep:
|
options: {
|
||||||
path?.steps[reachedIndex]?.title ||
|
url: pathname,
|
||||||
path?.steps[reachedIndex]?.description ||
|
state: !didFinish ? `closed` : `end`,
|
||||||
path?.steps[reachedIndex]?.descriptionJSX ||
|
reachedStep:
|
||||||
reachedIndex,
|
path?.steps[reachedIndex]?.title ||
|
||||||
|
path?.steps[reachedIndex]?.description ||
|
||||||
|
path?.steps[reachedIndex]?.descriptionJSX ||
|
||||||
|
reachedIndex,
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
setPath(null)
|
setPath(null)
|
||||||
setCurrentStep(-1)
|
setCurrentStep(-1)
|
||||||
|
|||||||
@@ -5483,6 +5483,7 @@ __metadata:
|
|||||||
openapi-sampler: ^1.3.1
|
openapi-sampler: ^1.3.1
|
||||||
pluralize: ^8.0.0
|
pluralize: ^8.0.0
|
||||||
postcss: 8.4.27
|
postcss: 8.4.27
|
||||||
|
posthog-js: ^1.269.1
|
||||||
prism-react-renderer: 2.4.0
|
prism-react-renderer: 2.4.0
|
||||||
react: rc
|
react: rc
|
||||||
react-dom: rc
|
react-dom: rc
|
||||||
@@ -5843,6 +5844,7 @@ __metadata:
|
|||||||
eslint-plugin-react-hooks: ^5.0.0
|
eslint-plugin-react-hooks: ^5.0.0
|
||||||
next: 15.3.5
|
next: 15.3.5
|
||||||
postcss: ^8
|
postcss: ^8
|
||||||
|
posthog-js: ^1.269.1
|
||||||
react: rc
|
react: rc
|
||||||
react-dom: rc
|
react-dom: rc
|
||||||
rehype-mdx-code-props: ^2.0.0
|
rehype-mdx-code-props: ^2.0.0
|
||||||
@@ -6198,6 +6200,7 @@ __metadata:
|
|||||||
eslint-plugin-react-hooks: ^5.0.0
|
eslint-plugin-react-hooks: ^5.0.0
|
||||||
next: 15.3.5
|
next: 15.3.5
|
||||||
postcss: ^8
|
postcss: ^8
|
||||||
|
posthog-js: ^1.269.1
|
||||||
react: rc
|
react: rc
|
||||||
react-dom: rc
|
react-dom: rc
|
||||||
rehype-mdx-code-props: ^2.0.0
|
rehype-mdx-code-props: ^2.0.0
|
||||||
@@ -7175,7 +7178,6 @@ __metadata:
|
|||||||
minisearch: ^7.1.1
|
minisearch: ^7.1.1
|
||||||
next: 15.3.5
|
next: 15.3.5
|
||||||
npm-to-yarn: ^2.1.0
|
npm-to-yarn: ^2.1.0
|
||||||
posthog-js: ^1.269.0
|
|
||||||
prism-react-renderer: 2.4.0
|
prism-react-renderer: 2.4.0
|
||||||
react: rc
|
react: rc
|
||||||
react-dom: rc
|
react-dom: rc
|
||||||
@@ -7198,6 +7200,7 @@ __metadata:
|
|||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
"@types/react-dom": "*"
|
"@types/react-dom": "*"
|
||||||
next: "*"
|
next: "*"
|
||||||
|
posthog-js: "*"
|
||||||
react: "*"
|
react: "*"
|
||||||
react-dom: "*"
|
react-dom: "*"
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
@@ -12428,9 +12431,9 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"posthog-js@npm:^1.269.0":
|
"posthog-js@npm:^1.269.1":
|
||||||
version: 1.269.0
|
version: 1.269.1
|
||||||
resolution: "posthog-js@npm:1.269.0"
|
resolution: "posthog-js@npm:1.269.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@posthog/core": 1.2.2
|
"@posthog/core": 1.2.2
|
||||||
core-js: ^3.38.1
|
core-js: ^3.38.1
|
||||||
@@ -12445,7 +12448,7 @@ __metadata:
|
|||||||
optional: true
|
optional: true
|
||||||
rrweb-snapshot:
|
rrweb-snapshot:
|
||||||
optional: true
|
optional: true
|
||||||
checksum: e29de2d4e33b643bc7dc57902d45294879915129bf5eba97e9486a4094cbaf0fbfc3d1ed55959434d0ffc94b55a640020d8ef786cddb6d48dc9c608667cd1ac4
|
checksum: 93b5d050f06dedb70820a2749d999451b37b24b61bb6041d61a1a05fe78405677284b00e1cfeae8e7b298645615002951febb275a4f87cf25191070172855590
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -13390,6 +13393,7 @@ __metadata:
|
|||||||
eslint-plugin-react-hooks: ^5.0.0
|
eslint-plugin-react-hooks: ^5.0.0
|
||||||
next: 15.3.5
|
next: 15.3.5
|
||||||
postcss: ^8
|
postcss: ^8
|
||||||
|
posthog-js: ^1.269.1
|
||||||
react: rc
|
react: rc
|
||||||
react-dom: rc
|
react-dom: rc
|
||||||
rehype-mdx-code-props: ^2.0.0
|
rehype-mdx-code-props: ^2.0.0
|
||||||
@@ -15129,6 +15133,7 @@ turbo@latest:
|
|||||||
eslint-plugin-react-hooks: ^5.0.0
|
eslint-plugin-react-hooks: ^5.0.0
|
||||||
next: 15.3.5
|
next: 15.3.5
|
||||||
postcss: ^8
|
postcss: ^8
|
||||||
|
posthog-js: ^1.269.1
|
||||||
react: rc
|
react: rc
|
||||||
react-dom: rc
|
react-dom: rc
|
||||||
rehype-mdx-code-props: ^2.0.0
|
rehype-mdx-code-props: ^2.0.0
|
||||||
@@ -15482,6 +15487,7 @@ turbo@latest:
|
|||||||
eslint-plugin-react-hooks: ^5.0.0
|
eslint-plugin-react-hooks: ^5.0.0
|
||||||
next: 15.3.5
|
next: 15.3.5
|
||||||
postcss: ^8
|
postcss: ^8
|
||||||
|
posthog-js: ^1.269.1
|
||||||
react: rc
|
react: rc
|
||||||
react-dom: rc
|
react-dom: rc
|
||||||
rehype-mdx-code-props: ^2.0.0
|
rehype-mdx-code-props: ^2.0.0
|
||||||
|
|||||||
Reference in New Issue
Block a user