Skip to content

Commit 7a07319

Browse files
authored
docs: open AI assistant based on search query (medusajs#13063)
* docs: open AI assistant based on search query * use URLSearchParams * fix vale error
1 parent ea9ed62 commit 7a07319

File tree

5 files changed

+162
-88
lines changed

5 files changed

+162
-88
lines changed

www/apps/book/app/learn/introduction/from-v1-to-v2/page.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1897,7 +1897,7 @@ If your use case is complex and these rules are not enough, you can create a new
18971897

18981898
Medusa v1 has gift card features out-of-the-box.
18991899

1900-
In Medusa v2, gift card features are now only available to [Medusa Cloud](https://medusajs.com/cloud/) users.
1900+
In Medusa v2, gift card features are now only available to [Cloud](https://medusajs.com/cloud/) users.
19011901

19021902
---
19031903

www/packages/docs-ui/src/components/AiAssistant/ChatWindow/Input/index.tsx

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import React, { useEffect, useRef } from "react"
1+
import React, { useEffect, useMemo, useRef } from "react"
22
import clsx from "clsx"
33
import { ArrowUpCircleSolid } from "@medusajs/icons"
4-
import { useAiAssistant } from "../../../../providers"
4+
import { useAiAssistant, useIsBrowser } from "../../../../providers"
55
import { useChat } from "@kapaai/react-sdk"
66
import { useAiAssistantChatNavigation } from "../../../../hooks"
77

@@ -12,8 +12,20 @@ type AiAssistantChatWindowInputProps = {
1212
export const AiAssistantChatWindowInput = ({
1313
chatWindowRef,
1414
}: AiAssistantChatWindowInputProps) => {
15-
const { chatOpened, inputRef, loading } = useAiAssistant()
15+
const { chatOpened, inputRef, loading, setChatOpened } = useAiAssistant()
1616
const { submitQuery, conversation } = useChat()
17+
const { isBrowser } = useIsBrowser()
18+
const { searchQuery, searchQueryType } = useMemo(() => {
19+
if (!isBrowser) {
20+
return {}
21+
}
22+
const searchParams = new URLSearchParams(location.search)
23+
24+
return {
25+
searchQuery: searchParams.get("query"),
26+
searchQueryType: searchParams.get("queryType"),
27+
}
28+
}, [isBrowser])
1729
const [question, setQuestion] = React.useState("")
1830
const formRef = useRef<HTMLFormElement | null>(null)
1931

@@ -97,6 +109,21 @@ export const AiAssistantChatWindowInput = ({
97109
question,
98110
})
99111

112+
useEffect(() => {
113+
if (searchQueryType === "submit") {
114+
onSubmit()
115+
}
116+
}, [searchQueryType])
117+
118+
useEffect(() => {
119+
if (!searchQuery) {
120+
return
121+
}
122+
123+
setQuestion(searchQuery)
124+
setChatOpened(true)
125+
}, [searchQuery])
126+
100127
return (
101128
<div
102129
className={clsx(

www/packages/docs-ui/src/components/AiAssistant/ThreadItem/Actions/index.tsx

Lines changed: 68 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
import React, { useState } from "react"
22
import clsx from "clsx"
33
import { Badge, Button, Link, type ButtonProps } from "@/components"
4-
import { ThumbDown, ThumbUp } from "@medusajs/icons"
5-
import { AiAssistantThreadItem as AiAssistantThreadItemType } from "../../../../providers"
4+
import {
5+
ThumbDown,
6+
ThumbUp,
7+
Link as LinkIcon,
8+
CheckCircle,
9+
} from "@medusajs/icons"
10+
import {
11+
AiAssistantThreadItem as AiAssistantThreadItemType,
12+
useSiteConfig,
13+
} from "../../../../providers"
614
import { Reaction, useChat } from "@kapaai/react-sdk"
15+
import { useCopy } from "../../../../hooks"
716

817
export type AiAssistantThreadItemActionsProps = {
918
item: AiAssistantThreadItemType
@@ -14,6 +23,12 @@ export const AiAssistantThreadItemActions = ({
1423
}: AiAssistantThreadItemActionsProps) => {
1524
const [feedback, setFeedback] = useState<Reaction | null>(null)
1625
const { addFeedback } = useChat()
26+
const {
27+
config: { baseUrl },
28+
} = useSiteConfig()
29+
const { handleCopy, isCopied } = useCopy(
30+
`${baseUrl}?query=${encodeURI(item.content)}`
31+
)
1732

1833
const handleFeedback = async (
1934
reaction: Reaction,
@@ -31,36 +46,59 @@ export const AiAssistantThreadItemActions = ({
3146
}
3247

3348
return (
34-
<div className={clsx("flex gap-docs_0.75 justify-between items-center")}>
35-
{item.sources !== undefined && item.sources.length > 0 && (
36-
<div className="flex gap-[6px] items-center flex-wrap">
37-
{item.sources.map((source) => (
38-
<Badge key={source.source_url} variant="neutral">
39-
<Link href={source.source_url} className="!text-inherit">
40-
{source.title}
41-
</Link>
42-
</Badge>
43-
))}
44-
</div>
49+
<div
50+
className={clsx(
51+
"flex gap-docs_0.75 items-center",
52+
item.type === "question" && "justify-end",
53+
item.type === "answer" && "justify-between"
4554
)}
46-
<div className="flex gap-docs_0.25 items-center text-medusa-fg-muted">
47-
{(feedback === null || feedback === "upvote") && (
48-
<ActionButton
49-
onClick={async () => handleFeedback("upvote", item.question_id)}
50-
className={clsx(feedback === "upvote" && "!text-medusa-fg-muted")}
51-
>
52-
<ThumbUp />
53-
</ActionButton>
54-
)}
55-
{(feedback === null || feedback === "downvote") && (
56-
<ActionButton
57-
onClick={async () => handleFeedback("downvote", item.question_id)}
58-
className={clsx(feedback === "downvote" && "!text-medusa-fg-muted")}
59-
>
60-
<ThumbDown />
55+
>
56+
{item.type === "question" && (
57+
<div className="flex gap-docs_0.25 items-center text-medusa-fg-muted">
58+
<ActionButton onClick={handleCopy}>
59+
{isCopied ? <CheckCircle /> : <LinkIcon />}
6160
</ActionButton>
62-
)}
63-
</div>
61+
</div>
62+
)}
63+
{item.type === "answer" && (
64+
<>
65+
{item.sources !== undefined && item.sources.length > 0 && (
66+
<div className="flex gap-[6px] items-center flex-wrap">
67+
{item.sources.map((source) => (
68+
<Badge key={source.source_url} variant="neutral">
69+
<Link href={source.source_url} className="!text-inherit">
70+
{source.title}
71+
</Link>
72+
</Badge>
73+
))}
74+
</div>
75+
)}
76+
<div className="flex gap-docs_0.25 items-center text-medusa-fg-muted">
77+
{(feedback === null || feedback === "upvote") && (
78+
<ActionButton
79+
onClick={async () => handleFeedback("upvote", item.question_id)}
80+
className={clsx(
81+
feedback === "upvote" && "!text-medusa-fg-muted"
82+
)}
83+
>
84+
<ThumbUp />
85+
</ActionButton>
86+
)}
87+
{(feedback === null || feedback === "downvote") && (
88+
<ActionButton
89+
onClick={async () =>
90+
handleFeedback("downvote", item.question_id)
91+
}
92+
className={clsx(
93+
feedback === "downvote" && "!text-medusa-fg-muted"
94+
)}
95+
>
96+
<ThumbDown />
97+
</ActionButton>
98+
)}
99+
</div>
100+
</>
101+
)}
64102
</div>
65103
)
66104
}

www/packages/docs-ui/src/components/AiAssistant/ThreadItem/index.tsx

Lines changed: 62 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -41,80 +41,89 @@ export const AiAssistantThreadItem = ({ item }: AiAssistantThreadItemProps) => {
4141
<div
4242
className={clsx(
4343
"txt-small text-medusa-fg-base",
44-
item.type === "question" && [
45-
"rounded-docs_xl bg-medusa-tag-neutral-bg",
46-
"px-docs_0.75 py-docs_0.5 max-w-full md:max-w-[400px]",
47-
],
44+
"flex flex-col gap-docs_0.75",
4845
item.type !== "question" && "flex-1",
4946
item.type === "answer" && "text-pretty flex-1 max-w-[calc(100%-20px)]"
5047
)}
5148
>
52-
{item.type === "question" && (
53-
<MarkdownContent
54-
className="[&>*:last-child]:mb-0"
55-
allowedElements={["br", "p", "code", "pre"]}
56-
unwrapDisallowed={true}
57-
components={{
58-
...MDXComponents,
59-
code: (props: CodeMdxProps) => {
60-
return (
61-
<CodeMdx
62-
{...props}
63-
noCopy
64-
noReport
65-
forceNoTitle
66-
noAskAi
67-
inlineCodeProps={{
68-
...props.inlineCodeProps,
69-
className: "!text-wrap !break-words",
70-
variant: "grey-bg",
71-
}}
72-
collapsibleLines="11"
73-
codeBlockProps={{
74-
className: clsx(
75-
"rounded-docs_lg p-[5px]",
76-
props.className
77-
),
78-
wrapperClassName: "rounded-docs_lg",
79-
innerClassName: "border rounded-docs_lg",
80-
overrideColors: {
81-
bg: "bg-medusa-contrast-bg-subtle",
82-
innerBg: "bg-medusa-contrast-bg-subtle",
83-
innerBorder: "border-medusa-contrast-border-bot",
84-
},
85-
}}
86-
/>
87-
)
88-
},
89-
}}
90-
>
91-
{item.content}
92-
</MarkdownContent>
93-
)}
94-
{item.type === "answer" && (
95-
<div className="flex flex-col gap-docs_0.75">
96-
{showLoading && <DotsLoading />}
49+
<div
50+
className={clsx(
51+
"flex flex-col gap-docs_0.75",
52+
item.type === "question" && [
53+
"rounded-docs_xl bg-medusa-tag-neutral-bg",
54+
"px-docs_0.75 py-docs_0.5 max-w-full md:max-w-[400px]",
55+
]
56+
)}
57+
>
58+
{item.type === "question" && (
9759
<MarkdownContent
9860
className="[&>*:last-child]:mb-0"
61+
allowedElements={["br", "p", "code", "pre"]}
62+
unwrapDisallowed={true}
9963
components={{
10064
...MDXComponents,
10165
code: (props: CodeMdxProps) => {
10266
return (
10367
<CodeMdx
10468
{...props}
69+
noCopy
10570
noReport
71+
forceNoTitle
10672
noAskAi
107-
wrapperClassName="mt-docs_1"
73+
inlineCodeProps={{
74+
...props.inlineCodeProps,
75+
className: "!text-wrap !break-words",
76+
variant: "grey-bg",
77+
}}
78+
collapsibleLines="11"
79+
codeBlockProps={{
80+
className: clsx(
81+
"rounded-docs_lg p-[5px]",
82+
props.className
83+
),
84+
wrapperClassName: "rounded-docs_lg",
85+
innerClassName: "border rounded-docs_lg",
86+
overrideColors: {
87+
bg: "bg-medusa-contrast-bg-subtle",
88+
innerBg: "bg-medusa-contrast-bg-subtle",
89+
innerBorder: "border-medusa-contrast-border-bot",
90+
},
91+
}}
10892
/>
10993
)
11094
},
11195
}}
112-
disallowedElements={["h1", "h2", "h3", "h4", "h5", "h6"]}
11396
>
11497
{item.content}
11598
</MarkdownContent>
116-
{item.question_id && <AiAssistantThreadItemActions item={item} />}
117-
</div>
99+
)}
100+
{item.type === "answer" && (
101+
<>
102+
{showLoading && <DotsLoading />}
103+
<MarkdownContent
104+
className="[&>*:last-child]:mb-0"
105+
components={{
106+
...MDXComponents,
107+
code: (props: CodeMdxProps) => {
108+
return (
109+
<CodeMdx
110+
{...props}
111+
noReport
112+
noAskAi
113+
wrapperClassName="mt-docs_1"
114+
/>
115+
)
116+
},
117+
}}
118+
disallowedElements={["h1", "h2", "h3", "h4", "h5", "h6"]}
119+
>
120+
{item.content}
121+
</MarkdownContent>
122+
</>
123+
)}
124+
</div>
125+
{(item.question_id || item.type === "question") && (
126+
<AiAssistantThreadItemActions item={item} />
118127
)}
119128
{item.type === "error" && (
120129
<span className="text-medusa-fg-error">{item.content}</span>

www/packages/docs-ui/src/components/InlineCode/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const InlineCode = ({
2323
<code
2424
{...props}
2525
className={clsx(
26-
"text-medusa-tag-neutral-text border",
26+
"text-medusa-tag-neutral-text border whitespace-break-spaces",
2727
"font-monospace text-code-label rounded-docs_sm py-0 px-[5px]",
2828
variant === "default" && [
2929
"bg-medusa-tag-neutral-bg group-hover:bg-medusa-tag-neutral-bg-hover",

0 commit comments

Comments
 (0)