Skip to content

Commit b31f417

Browse files
committed
feature(search-component): add highlted item when in previewTopicId mode
1 parent f1fb53f commit b31f417

8 files changed

Lines changed: 154 additions & 80 deletions

File tree

clients/search-component/src/TrieveModal/Chat/ChatMode.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import { InlineChatHeader } from "./InlineChatHeader";
1111
import { ChatInput } from "./ChatInput";
1212

1313
export const ChatMode = () => {
14-
const { props, modalRef, minHeight, resetHeight, addHeight } = useModalState();
14+
const { props, modalRef, minHeight, resetHeight, addHeight } =
15+
useModalState();
1516
const { messages } = useChatState();
1617

1718
const actualChatRef = useRef<HTMLDivElement>(null);
@@ -101,8 +102,9 @@ export const ChatMode = () => {
101102

102103
return (
103104
<Suspense>
104-
{props.previewTopicId == undefined &&
105-
<InlineChatHeader resetHeight={resetHeight} />}
105+
{props.previewTopicId == undefined && (
106+
<InlineChatHeader resetHeight={resetHeight} />
107+
)}
106108
<div
107109
ref={modalRef}
108110
className="chat-modal-wrapper tv-justify-items-stretch tv-flex-grow tv-pt-3 tv-pb-2 tv-px-2 tv-relative tv-overflow-y-auto tv-flex tv-overflow-x-hidden"

clients/search-component/src/TrieveModal/Chat/FollowupQueries.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ export const FollowupQueries = () => {
1919
const handleFollowupQuery = async (q: string) => {
2020
askQuestion(q);
2121

22-
const requestId = messages[messages.length - 1]?.queryId ?? "00000000-0000-0000-0000-000000000000";
22+
const requestId =
23+
messages[messages.length - 1]?.queryId ??
24+
"00000000-0000-0000-0000-000000000000";
2325

2426
await trieveSDK.sendAnalyticsEvent({
2527
event_name: `site-followup_query`,
@@ -35,16 +37,17 @@ export const FollowupQueries = () => {
3537
request_type: "rag",
3638
},
3739
});
38-
}
40+
};
3941

4042
return (
4143
<div ref={parent} className="followup-questions">
4244
{suggestedQuestions?.map((q) => (
4345
<button
4446
onClick={() => handleFollowupQuery(q)}
4547
key={q}
46-
className={`followup-question ${isLoadingSuggestedQueries ? "loading" : ""
47-
}`}
48+
className={`followup-question ${
49+
isLoadingSuggestedQueries ? "loading" : ""
50+
}`}
4851
>
4952
<SparklesIcon className="followup-icon" />
5053
{q}

clients/search-component/src/TrieveModal/Chat/ResponseMessage.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export const Message = ({
9090
idx: number;
9191
message: Message;
9292
}) => {
93-
const { rateChatCompletion, messages } = useChatState();
93+
const { rateChatCompletion, messages, productsWithClicks } = useChatState();
9494
const [positive, setPositive] = React.useState<boolean | null>(null);
9595
const [copied, setCopied] = React.useState<boolean>(false);
9696
const { props, trieveSDK, fingerprint } = useModalState();
@@ -152,9 +152,13 @@ export const Message = ({
152152
.map((item, index) => {
153153
const { title, descriptionHtml } = guessTitleAndDesc(item);
154154

155+
const clicked =
156+
productsWithClicks?.find(
157+
(product) => product.chunk_id === item.chunk.id,
158+
) != undefined;
155159
return (
156160
<a
157-
className="tv-flex tv-flex-col"
161+
className={`tv-flex tv-flex-col ${clicked ? "tv-highlighted-item" : ""}`}
158162
key={index}
159163
href={item.link ?? ""}
160164
target="_blank"

clients/search-component/src/TrieveModal/Search/UploadImage.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ export const UploadImage = () => {
5959
<button
6060
onClick={handleClick}
6161
className={`tv-rounded ${
62-
mode === "chat" && "tv-right-9 tv-top-[0.825rem] tv-absolute image-button-container"
62+
mode === "chat" &&
63+
"tv-right-9 tv-top-[0.825rem] tv-absolute image-button-container"
6364
} tv-z-20 tv-dark-text-white tv-text-zinc-700`}
6465
disabled={props.previewTopicId != undefined}
6566
>

clients/search-component/src/TrieveModal/index.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,10 @@ body {
304304
flex: 0 0 100% 100%;
305305
}
306306

307+
&.tv-highlighted-item {
308+
background-color: yellow;
309+
}
310+
307311
&.yt-anchor {
308312
@apply tv-text-center;
309313
}

clients/search-component/src/TrieveModal/index.tsx

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import { InferenceFiltersForm } from "./FilterSidebarComponents";
2020
import { getFingerprint } from "@thumbmarkjs/thumbmarkjs";
2121
import { createPortal } from "react-dom";
2222

23-
2423
const SearchPage = () => {
2524
const { props } = useModalState();
2625
if (!props.searchPageProps?.display) return null;
@@ -44,16 +43,22 @@ const SearchPage = () => {
4443
};
4544

4645
function findCartChanges(oldCart: any, newCart: any) {
47-
if (!oldCart.items) return { added: newCart.items.map((item: any) => item.variant_id), removed: [] };
48-
const onlyInLeft = (l: any, r: any) => l.filter((li: any) => !r.some((ri: any) => li.key == ri.key));
46+
if (!oldCart.items)
47+
return {
48+
added: newCart.items.map((item: any) => item.variant_id),
49+
removed: [],
50+
};
51+
const onlyInLeft = (l: any, r: any) =>
52+
l.filter((li: any) => !r.some((ri: any) => li.key == ri.key));
4953
const result = {
5054
added: onlyInLeft(newCart.items, oldCart.items),
5155
removed: onlyInLeft(oldCart.items, newCart.items),
5256
};
5357

54-
5558
oldCart.items.forEach((oi: any) => {
56-
const ni = newCart.items.find((i: any) => i.key == oi.key && i.quantity != oi.quantity);
59+
const ni = newCart.items.find(
60+
(i: any) => i.key == oi.key && i.quantity != oi.quantity,
61+
);
5762
if (!ni) return;
5863
const quantity = ni.quantity - oi.quantity;
5964
const item = { ...ni };
@@ -65,7 +70,6 @@ function findCartChanges(oldCart: any, newCart: any) {
6570
}
6671
});
6772

68-
6973
return result;
7074
}
7175

@@ -131,29 +135,41 @@ const Modal = () => {
131135

132136
const cartObserver = new PerformanceObserver((list) => {
133137
list.getEntries().forEach((entry) => {
134-
const isValidRequestType = ['xmlhttprequest', 'fetch'].includes((entry as any).initiatorType);
138+
const isValidRequestType = ["xmlhttprequest", "fetch"].includes(
139+
(entry as any).initiatorType,
140+
);
135141
const isCartChangeRequest = /\/cart\/add\.js/.test(entry.name);
136142
if (isValidRequestType && isCartChangeRequest) {
137143
(async function () {
138-
const oldCart = JSON.parse(localStorage.getItem('trieve-cart') ?? '{}');
139-
const newCart = await fetch((window as any).Shopify.routes.root + 'cart.js')
140-
.then(response => response.json())
141-
.then(data => {
142-
localStorage.setItem('trieve-cart', JSON.stringify(data));
144+
const oldCart = JSON.parse(
145+
localStorage.getItem("trieve-cart") ?? "{}",
146+
);
147+
const newCart = await fetch(
148+
(window as any).Shopify.routes.root + "cart.js",
149+
)
150+
.then((response) => response.json())
151+
.then((data) => {
152+
localStorage.setItem("trieve-cart", JSON.stringify(data));
143153
return data;
144154
});
145155

146156
const cartChanges = findCartChanges(oldCart, newCart);
147157

148-
const items = cartChanges.added.map((item: any) => item.toString());
158+
const items = cartChanges.added.map((item: any) =>
159+
item.toString(),
160+
);
149161
console.log("cartItems", items);
150162

151163
if (items.length > 0) {
152-
const lastMessage = JSON.parse(window.localStorage.getItem("lastMessage") ?? "{}");
164+
const lastMessage = JSON.parse(
165+
window.localStorage.getItem("lastMessage") ?? "{}",
166+
);
153167
let requestId = "00000000-0000-0000-0000-000000000000";
154168
for (const id in lastMessage) {
155169
const storedItems = lastMessage[id];
156-
if (storedItems.some((item: any) => items.includes(item))) {
170+
if (
171+
storedItems.some((item: any) => items.includes(item))
172+
) {
157173
requestId = id;
158174
break;
159175
}
@@ -197,28 +213,35 @@ const Modal = () => {
197213

198214
checkout.addEventListener("click", () => {
199215
(async function () {
200-
const checkoutItems = await fetch((window as any).Shopify.routes.root + 'cart.js')
201-
.then(response => response.json())
202-
.then(data => {
216+
const checkoutItems = await fetch(
217+
(window as any).Shopify.routes.root + "cart.js",
218+
)
219+
.then((response) => response.json())
220+
.then((data) => {
203221
return data;
204222
});
205223

224+
const items = checkoutItems.items.map((item: any) => {
225+
const price = item.final_line_price.toString();
226+
return {
227+
tracking_id: item.variant_id.toString(),
228+
revenue: parseFloat(
229+
price.slice(0, -2) + "." + price.slice(-2),
230+
),
231+
};
232+
});
206233

207-
const items = checkoutItems
208-
.items
209-
.map((item: any) => {
210-
const price = item.final_line_price.toString();
211-
return {
212-
tracking_id: item.variant_id.toString(),
213-
revenue: parseFloat(price.slice(0, -2) + "." + price.slice(-2)),
214-
};
215-
});
216-
217-
const lastMessage = JSON.parse(window.localStorage.getItem("lastMessage") ?? "{}");
234+
const lastMessage = JSON.parse(
235+
window.localStorage.getItem("lastMessage") ?? "{}",
236+
);
218237
let requestId = "00000000-0000-0000-0000-000000000000";
219238
for (const id in lastMessage) {
220239
const storedItems = lastMessage[id];
221-
if (storedItems.some((item: any) => items.map((i: any) => i.tracking_id).includes(item))) {
240+
if (
241+
storedItems.some((item: any) =>
242+
items.map((i: any) => i.tracking_id).includes(item),
243+
)
244+
) {
222245
requestId = id;
223246
break;
224247
}
@@ -482,7 +505,7 @@ export const TrieveModalSearch = (props: ModalProps) => {
482505
document.documentElement.style.setProperty(
483506
"--tv-prop-brand-font-family",
484507
props.brandFontFamily ??
485-
`Maven Pro, ui-sans-serif, system-ui, sans-serif,
508+
`Maven Pro, ui-sans-serif, system-ui, sans-serif,
486509
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"`,
487510
);
488511
}, [props.brandColor, props.brandFontFamily]);

clients/search-component/src/utils/hooks/chat-context.tsx

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,20 @@ import { Chunk } from "../types";
55
import { getFingerprint } from "@thumbmarkjs/thumbmarkjs";
66
import { useEffect } from "react";
77
import { trackViews } from "../trieve";
8-
import { ChunkFilter, ChunkGroup, ToolFunctionParameter } from "trieve-ts-sdk";
8+
import {
9+
ChunkFilter,
10+
ChunkGroup,
11+
EventsForTopicResponse,
12+
RAGAnalyticsResponse,
13+
ToolFunctionParameter,
14+
} from "trieve-ts-sdk";
915
import { defaultHighlightOptions } from "../highlight";
1016

17+
export type ChunkIdWithIndex = {
18+
chunk_id: string;
19+
index: number;
20+
};
21+
1122
const scrollToBottomOfChatModalWrapper = () => {
1223
const chatModal = document.querySelector(".chat-modal-wrapper");
1324
if (chatModal) {
@@ -43,18 +54,20 @@ const ChatContext = createContext<{
4354
chatWithGroup: (group: ChunkGroup, betterGroupName?: string) => void;
4455
isDoneReading?: boolean;
4556
rateChatCompletion: (isPositive: boolean, queryId: string | null) => void;
57+
productsWithClicks: ChunkIdWithIndex[];
4658
}>({
47-
askQuestion: async () => { },
59+
askQuestion: async () => {},
4860
currentQuestion: "",
4961
isLoading: false,
5062
messages: [],
51-
setCurrentQuestion: () => { },
52-
cancelGroupChat: () => { },
53-
clearConversation: () => { },
54-
chatWithGroup: () => { },
55-
switchToChatAndAskQuestion: async () => { },
56-
stopGeneratingMessage: () => { },
57-
rateChatCompletion: () => { },
63+
setCurrentQuestion: () => {},
64+
cancelGroupChat: () => {},
65+
clearConversation: () => {},
66+
chatWithGroup: () => {},
67+
switchToChatAndAskQuestion: async () => {},
68+
stopGeneratingMessage: () => {},
69+
rateChatCompletion: () => {},
70+
productsWithClicks: [],
5871
});
5972

6073
function ChatProvider({ children }: { children: React.ReactNode }) {
@@ -83,6 +96,9 @@ function ChatProvider({ children }: { children: React.ReactNode }) {
8396
new AbortController(),
8497
);
8598
const [isDoneReading, setIsDoneReading] = useState(true);
99+
const [productsWithClicks, setProductsWithClicks] = useState<
100+
ChunkIdWithIndex[]
101+
>([]);
86102

87103
const createTopic = async ({
88104
question,
@@ -147,6 +163,26 @@ function ChatProvider({ children }: { children: React.ReactNode }) {
147163
);
148164
setMessages(componentMessages.slice(1));
149165
});
166+
167+
trieveSDK
168+
.getRagAnalytics({
169+
type: "events_for_topic",
170+
topic_id: props.previewTopicId,
171+
})
172+
.then((topicEvents: RAGAnalyticsResponse) => {
173+
const topicEventsResponse = topicEvents as EventsForTopicResponse;
174+
175+
const allProductsWithClicks = topicEventsResponse.events
176+
.filter((event) => event.event_type === "click")
177+
.flatMap((event) => {
178+
const productsWithClicks = event.items.map((jsonItem) => {
179+
const serializedItem = JSON.parse(jsonItem) as ChunkIdWithIndex;
180+
return serializedItem;
181+
});
182+
return productsWithClicks;
183+
});
184+
setProductsWithClicks(allProductsWithClicks);
185+
});
150186
}
151187
}, []);
152188

@@ -424,13 +460,13 @@ function ChatProvider({ children }: { children: React.ReactNode }) {
424460
user_message_text:
425461
questionProp || currentQuestion
426462
? `Get filters from the following messages: ${messages
427-
.slice(0, -1)
428-
.filter((message) => {
429-
return message.type == "user";
430-
})
431-
.map(
432-
(message) => `\n\n${message.text}`,
433-
)} \n\n ${questionProp || currentQuestion}`
463+
.slice(0, -1)
464+
.filter((message) => {
465+
return message.type == "user";
466+
})
467+
.map(
468+
(message) => `\n\n${message.text}`,
469+
)} \n\n ${questionProp || currentQuestion}`
434470
: null,
435471
image_url: imageUrl ? imageUrl : null,
436472
audio_input: curAudioBase64 ? curAudioBase64 : null,
@@ -804,6 +840,7 @@ function ChatProvider({ children }: { children: React.ReactNode }) {
804840
stopGeneratingMessage,
805841
isDoneReading,
806842
rateChatCompletion,
843+
productsWithClicks,
807844
}}
808845
>
809846
{children}

0 commit comments

Comments
 (0)