Skip to content

Commit ecb4b37

Browse files
densumeshskeptrunedev
authored andcommitted
feature: add settings item for setting the checkout selector
1 parent f3ca07f commit ecb4b37

4 files changed

Lines changed: 151 additions & 23 deletions

File tree

clients/trieve-shopify-extension/app/components/DatasetSettings.tsx

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ export type DatasetConfig = Exclude<
3737
LLM_API_KEY?: string | null;
3838
};
3939

40+
export type RevenueTrackingOptions = {
41+
checkout_selector: string;
42+
};
43+
4044
export const defaultServerEnvsConfiguration: DatasetConfig = {
4145
LLM_BASE_URL: "",
4246
LLM_DEFAULT_MODEL: "",
@@ -66,22 +70,29 @@ export const defaultServerEnvsConfiguration: DatasetConfig = {
6670
BM25_AVG_LEN: 256,
6771
};
6872

73+
export const defaultRevenueTrackingOptions: RevenueTrackingOptions = {
74+
checkout_selector: "",
75+
};
76+
6977
export const DatasetSettings = ({
7078
initalCrawlOptions,
79+
initalRevenueTrackingOptions,
7180
shopDataset,
7281
}: {
7382
initalCrawlOptions: ExtendedCrawlOptions;
83+
initalRevenueTrackingOptions: RevenueTrackingOptions;
7484
shopDataset: Dataset;
7585
}) => {
7686
const [unsavedCrawlOptions, setUnsavedCrawlOptions] =
7787
useState(initalCrawlOptions);
88+
const [unsavedRevenueTrackingOptions, setUnsavedRevenueTrackingOptions] =
89+
useState(initalRevenueTrackingOptions);
7890
const shopify = useAppBridge();
7991
const submit = useSubmit();
8092
const [datasetSettings, setDatasetSettings] = useState<DatasetConfig>(
8193
shopDataset.server_configuration ?? ({} as DatasetConfig),
8294
);
8395

84-
8596
useEffect(() => {
8697
// Quickly set the nonnegotiable options for shopify to work
8798
setUnsavedCrawlOptions({
@@ -133,6 +144,21 @@ export const DatasetSettings = ({
133144
shopify.toast.show("Saved LLM settings!");
134145
};
135146

147+
const onRevenueTrackingSettingsSave = async () => {
148+
submit(
149+
{
150+
revenue_tracking_options: JSON.stringify(unsavedRevenueTrackingOptions),
151+
dataset_id: shopDataset.id,
152+
type: "revenue_tracking",
153+
},
154+
{
155+
method: "POST",
156+
},
157+
);
158+
159+
shopify.toast.show("Saved revenue tracking settings!");
160+
};
161+
136162
return (
137163
<BlockStack gap="200">
138164
<Card>
@@ -180,6 +206,34 @@ export const DatasetSettings = ({
180206
</InlineStack>
181207
</BlockStack>
182208
</Card>
209+
<Card>
210+
<BlockStack gap="200">
211+
<Text variant="headingLg" as="h1">
212+
Revenue Tracking Settings
213+
</Text>
214+
215+
<FormLayout>
216+
<TextField
217+
autoComplete="off"
218+
label="Checkout Selector"
219+
helpText="The HTML selector of the checkout button on your shopify store. This is used to track revenue when a user clicks the checkout button."
220+
value={
221+
unsavedRevenueTrackingOptions?.checkout_selector || ""
222+
}
223+
onChange={(e) => {
224+
setUnsavedRevenueTrackingOptions({
225+
...unsavedRevenueTrackingOptions,
226+
checkout_selector: e,
227+
});
228+
}}
229+
/>
230+
</FormLayout>
231+
232+
<InlineStack align="end">
233+
<Button onClick={onRevenueTrackingSettingsSave}>Save</Button>
234+
</InlineStack>
235+
</BlockStack>
236+
</Card>
183237
<Card>
184238
<BlockStack gap="200">
185239
<Text variant="headingLg" as="h1">

clients/trieve-shopify-extension/app/routes/app._dashboard.settings.tsx

Lines changed: 86 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { sdkFromKey, validateTrieveAuth } from "app/auth";
66
import {
77
DatasetSettings as DatasetSettings,
88
ExtendedCrawlOptions,
9+
RevenueTrackingOptions,
910
} from "app/components/DatasetSettings";
1011
import { useTrieve } from "app/context/trieveContext";
1112
import { AdminApiCaller } from "app/loaders";
@@ -19,7 +20,10 @@ import { AppInstallData } from "./app.setup";
1920

2021
const setAppMetafields = async (
2122
adminApi: AdminApiCaller,
22-
trieveKey: TrieveKey,
23+
valuesToSet: {
24+
key: string;
25+
value: string;
26+
}[],
2327
) => {
2428
const response = await adminApi<AppInstallData>(`
2529
#graphql
@@ -54,31 +58,60 @@ const setAppMetafields = async (
5458
`,
5559
{
5660
variables: {
57-
metafieldsSetInput: [
58-
{
59-
namespace: "trieve",
60-
key: "dataset_id",
61-
value: trieveKey.currentDatasetId,
62-
type: "single_line_text_field",
63-
ownerId: appId.currentAppInstallation.id,
64-
},
65-
{
66-
namespace: "trieve",
67-
key: "api_key",
68-
value: trieveKey.key,
69-
type: "single_line_text_field",
70-
ownerId: appId.currentAppInstallation.id,
71-
},
72-
],
61+
metafieldsSetInput: valuesToSet.map((value) => ({
62+
namespace: "trieve",
63+
key: value.key,
64+
value: value.value,
65+
type: "single_line_text_field",
66+
ownerId: appId.currentAppInstallation.id,
67+
})),
7368
},
7469
},
7570
);
7671
};
7772

73+
type Metafields = {
74+
currentAppInstallation: {
75+
metafields: {
76+
nodes: {
77+
id: string;
78+
namespace: string;
79+
key: string;
80+
value: string;
81+
}[];
82+
};
83+
};
84+
};
85+
86+
const getAppMetafields = async (adminApi: AdminApiCaller) => {
87+
const response = await adminApi<Metafields>(`
88+
#graphql
89+
query {
90+
currentAppInstallation {
91+
metafields(first: 10) {
92+
nodes {
93+
id
94+
namespace
95+
key
96+
value
97+
}
98+
}
99+
}
100+
}
101+
`);
102+
103+
if (response.error) {
104+
throw response.error;
105+
}
106+
107+
return response.data.currentAppInstallation.metafields.nodes;
108+
};
109+
78110
export const loader = async ({
79111
request,
80112
}: LoaderFunctionArgs): Promise<{
81113
crawlSettings: ExtendedCrawlOptions | undefined;
114+
revenueTrackingSettings: RevenueTrackingOptions | undefined;
82115
}> => {
83116
const { session } = await authenticate.admin(request);
84117
const key = await validateTrieveAuth(request);
@@ -87,7 +120,13 @@ export const loader = async ({
87120
session.shop,
88121
session.accessToken!,
89122
);
90-
setAppMetafields(fetcher, key).catch(console.error);
123+
setAppMetafields(fetcher, [{
124+
key: "dataset_id",
125+
value: key.currentDatasetId || "",
126+
}, {
127+
key: "api_key",
128+
value: key.key,
129+
}]).catch(console.error);
91130

92131
const crawlSettings: {
93132
crawlSettings: ExtendedCrawlOptions | undefined;
@@ -98,13 +137,21 @@ export const loader = async ({
98137
},
99138
})) as any;
100139

101-
return { crawlSettings: crawlSettings?.crawlSettings };
140+
const revenueTrackingSettings: RevenueTrackingOptions = {
141+
checkout_selector: (await getAppMetafields(fetcher)).find((metafield) => metafield.key === "checkout_selector")?.value ?? "",
142+
};
143+
144+
return { crawlSettings: crawlSettings?.crawlSettings, revenueTrackingSettings };
102145
};
103146

104147
export const action = async ({ request }: ActionFunctionArgs) => {
105148
const { session } = await authenticate.admin(request);
106149
const key = await validateTrieveAuth(request);
107150
const trieve = sdkFromKey(key);
151+
const fetcher = buildAdminApiFetcherForServer(
152+
session.shop,
153+
session.accessToken!,
154+
);
108155
const formData = await request.formData();
109156
const type = formData.get("type");
110157
if (type === "crawl") {
@@ -132,7 +179,13 @@ export const action = async ({ request }: ActionFunctionArgs) => {
132179
sendChunks(datasetId as string, key, fetcher, session, crawlSettings).catch(
133180
console.error,
134181
);
135-
setAppMetafields(fetcher, key).catch(console.error);
182+
setAppMetafields(fetcher, [{
183+
key: "dataset_id",
184+
value: key.currentDatasetId || "",
185+
}, {
186+
key: "api_key",
187+
value: key.key,
188+
}]).catch(console.error);
136189

137190
return { success: true };
138191
} else if (type === "dataset") {
@@ -145,20 +198,31 @@ export const action = async ({ request }: ActionFunctionArgs) => {
145198
});
146199

147200
return { success: true };
148-
}
201+
} else if (type === "revenue_tracking") {
202+
const revenueTrackingSettingsString = formData.get("revenue_tracking_options");
203+
const revenueTrackingSettings = JSON.parse(revenueTrackingSettingsString as string);
204+
await setAppMetafields(fetcher, [
205+
{
206+
key: "checkout_selector",
207+
value: revenueTrackingSettings.checkout_selector,
208+
},
209+
]).catch(console.error);
149210

211+
return { success: true };
212+
}
150213
return { success: false };
151214
};
152215

153216
export default function Dataset() {
154217
const { trieve } = useTrieve();
155218
const { data: shopDataset } = useSuspenseQuery(shopDatasetQuery(trieve));
156-
const { crawlSettings } = useLoaderData<typeof loader>();
219+
const { crawlSettings, revenueTrackingSettings } = useLoaderData<typeof loader>();
157220

158221
return (
159222
<Box paddingBlockStart="400">
160223
<DatasetSettings
161224
initalCrawlOptions={crawlSettings as ExtendedCrawlOptions}
225+
initalRevenueTrackingOptions={revenueTrackingSettings as RevenueTrackingOptions}
162226
shopDataset={shopDataset as Dataset}
163227
/>
164228
</Box>

clients/trieve-shopify-extension/extensions/global-search/blocks/global_component.liquid

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@
9797
showFloatingSearchIcon: toBool(getValue("{{ block.settings.show_floating_search_icon }}", true)),
9898
floatingSearchIconPosition: getValue("{{ block.settings.floating_icon_pos }}", "left"),
9999
allowSwitchingModes: false,
100+
analyticsSelectors: {
101+
checkout: {
102+
querySelector: appMetafieldTrieve.checkout_selector,
103+
},
104+
},
100105
});
101106
}
102107
</script>

clients/trieve-shopify-extension/extensions/global-search/blocks/inline_component.liquid

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@
108108
inline: true,
109109
groupTrackingId: productId ? productId.toString() : undefined,
110110
cleanGroupName: productTitle ?? undefined,
111+
analyticsSelectors: {
112+
checkout: {
113+
querySelector: appMetafieldTrieve.checkout_selector,
114+
},
115+
},
111116
});
112117
}
113118
</script>

0 commit comments

Comments
 (0)