@jytextiles/medusa-plugin-faire-store-sync 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.medusa/server/src/admin/index.js +368 -242
- package/.medusa/server/src/admin/index.mjs +370 -244
- package/.medusa/server/src/api/admin/faire/status/route.js +1 -3
- package/.medusa/server/src/lib/faire-client.js +8 -3
- package/.medusa/server/src/modules/faire-sync/service.js +7 -2
- package/.medusa/server/src/workflows/sync-product-to-faire.js +10 -4
- package/package.json +1 -1
- package/src/admin/lib/api.ts +1 -1
- package/src/admin/routes/settings/faire/{bulk → @bulk}/page.tsx +17 -7
- package/src/admin/routes/settings/faire/{settings → @settings}/page.tsx +11 -22
- package/src/admin/routes/settings/faire/page.tsx +9 -2
- package/src/admin/widgets/faire-product-widget.tsx +182 -1
- package/src/api/admin/faire/status/route.ts +0 -2
- package/src/lib/faire-client.ts +7 -2
- package/src/modules/faire-sync/service.ts +6 -1
- package/src/workflows/sync-product-to-faire.ts +9 -3
- /package/src/admin/routes/settings/faire/{bulk → @bulk}/use-bulk-product-columns.tsx +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { defineWidgetConfig, defineRouteConfig } from "@medusajs/admin-sdk";
|
|
3
|
-
import { Container, Heading, Text, StatusBadge, Alert,
|
|
3
|
+
import { toast, Container, Heading, Text, StatusBadge, Alert, Badge, Button, Tooltip, Drawer, Input, clx, createDataTableColumnHelper, createDataTableFilterHelper, useDataTable, Skeleton, DropdownMenu, DataTable, Label, Toaster, Switch, Select, FocusModal, IconButton } from "@medusajs/ui";
|
|
4
4
|
import { useQueryClient, useQuery, useMutation, keepPreviousData } from "@tanstack/react-query";
|
|
5
|
+
import { useState, useMemo, useEffect } from "react";
|
|
5
6
|
import Medusa from "@medusajs/js-sdk";
|
|
6
7
|
import { BuildingStorefront, ChevronDownMini, EllipsisHorizontal, ArrowPath, ArrowUpRightOnBox } from "@medusajs/icons";
|
|
7
|
-
import {
|
|
8
|
-
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
|
|
8
|
+
import { useNavigate, Outlet, useParams, useSearchParams } from "react-router-dom";
|
|
9
9
|
const sdk = new Medusa({
|
|
10
10
|
baseUrl: "/",
|
|
11
11
|
auth: {
|
|
@@ -71,6 +71,7 @@ const faireApi = {
|
|
|
71
71
|
return sdk.client.fetch("/admin/faire/products", { query });
|
|
72
72
|
}
|
|
73
73
|
};
|
|
74
|
+
const MAX_RENDERED = 60;
|
|
74
75
|
const badgeColor = (status) => {
|
|
75
76
|
switch (status) {
|
|
76
77
|
case "synced":
|
|
@@ -86,7 +87,7 @@ const badgeColor = (status) => {
|
|
|
86
87
|
}
|
|
87
88
|
};
|
|
88
89
|
const FaireProductWidget = ({ data }) => {
|
|
89
|
-
var _a, _b, _c;
|
|
90
|
+
var _a, _b, _c, _d;
|
|
90
91
|
const queryClient = useQueryClient();
|
|
91
92
|
const productKey = ["faire", "product-status", data.id];
|
|
92
93
|
const statusQuery = useQuery({
|
|
@@ -129,6 +130,45 @@ const FaireProductWidget = ({ data }) => {
|
|
|
129
130
|
status: latest.status
|
|
130
131
|
} : null;
|
|
131
132
|
const notReady = connected && readiness && !readiness.ready_to_publish;
|
|
133
|
+
const metadata = data.metadata || {};
|
|
134
|
+
const productType = (_d = data.type) == null ? void 0 : _d.value;
|
|
135
|
+
const [pickerOpen, setPickerOpen] = useState(false);
|
|
136
|
+
const [pickerSearch, setPickerSearch] = useState("");
|
|
137
|
+
const [pinnedOverride, setPinnedOverride] = useState(
|
|
138
|
+
void 0
|
|
139
|
+
);
|
|
140
|
+
const taxonomyQuery = useQuery({
|
|
141
|
+
queryKey: ["faire", "taxonomy"],
|
|
142
|
+
enabled: pickerOpen,
|
|
143
|
+
queryFn: async () => (await faireApi.taxonomy()).taxonomy ?? []
|
|
144
|
+
});
|
|
145
|
+
const taxonomy = taxonomyQuery.data ?? [];
|
|
146
|
+
const pinnedId = pinnedOverride !== void 0 ? pinnedOverride ?? void 0 : metadata.faire_taxonomy_type_id;
|
|
147
|
+
const pinnedName = useMemo(() => {
|
|
148
|
+
var _a2;
|
|
149
|
+
if (!pinnedId) return void 0;
|
|
150
|
+
if (!/^tt_/.test(String(pinnedId))) return String(pinnedId);
|
|
151
|
+
return (_a2 = taxonomy.find((t) => t.id === pinnedId)) == null ? void 0 : _a2.name;
|
|
152
|
+
}, [pinnedId, taxonomy]);
|
|
153
|
+
const resolvedSource = pinnedId ? { label: pinnedName || String(pinnedId), from: "pinned" } : metadata.faire_category ? { label: String(metadata.faire_category), from: "metadata" } : productType ? { label: productType, from: "type" } : { label: "Account fallback", from: "fallback" };
|
|
154
|
+
const filteredTaxonomy = useMemo(() => {
|
|
155
|
+
const q = pickerSearch.trim().toLowerCase();
|
|
156
|
+
const list = q ? taxonomy.filter((t) => t.name.toLowerCase().includes(q)) : taxonomy;
|
|
157
|
+
return list.slice(0, MAX_RENDERED);
|
|
158
|
+
}, [taxonomy, pickerSearch]);
|
|
159
|
+
const saveCategory = useMutation({
|
|
160
|
+
mutationFn: (value) => sdk.admin.product.update(data.id, {
|
|
161
|
+
metadata: { ...metadata, faire_taxonomy_type_id: value }
|
|
162
|
+
}),
|
|
163
|
+
onSuccess: (_res, value) => {
|
|
164
|
+
setPinnedOverride(value);
|
|
165
|
+
queryClient.invalidateQueries({ queryKey: ["product", data.id] });
|
|
166
|
+
setPickerOpen(false);
|
|
167
|
+
setPickerSearch("");
|
|
168
|
+
toast.success(value ? "Faire category set" : "Faire category cleared");
|
|
169
|
+
},
|
|
170
|
+
onError: (err) => toast.error("Failed to save category", { description: err == null ? void 0 : err.message })
|
|
171
|
+
});
|
|
132
172
|
return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
|
|
133
173
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
|
|
134
174
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
@@ -155,6 +195,25 @@ const FaireProductWidget = ({ data }) => {
|
|
|
155
195
|
}
|
|
156
196
|
)
|
|
157
197
|
] }) }),
|
|
198
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 rounded-lg border px-3 py-2", children: [
|
|
199
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
200
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
201
|
+
/* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: "Faire category" }),
|
|
202
|
+
/* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: resolvedSource.from === "fallback" ? "orange" : "grey", children: resolvedSource.from === "pinned" ? "Pinned" : resolvedSource.from === "type" ? "From Type" : resolvedSource.from === "metadata" ? "Metadata" : "Fallback" })
|
|
203
|
+
] }),
|
|
204
|
+
/* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: resolvedSource.label })
|
|
205
|
+
] }),
|
|
206
|
+
/* @__PURE__ */ jsx(
|
|
207
|
+
Button,
|
|
208
|
+
{
|
|
209
|
+
size: "small",
|
|
210
|
+
variant: "secondary",
|
|
211
|
+
disabled: !connected,
|
|
212
|
+
onClick: () => setPickerOpen(true),
|
|
213
|
+
children: pinnedId ? "Change" : "Set category"
|
|
214
|
+
}
|
|
215
|
+
)
|
|
216
|
+
] }),
|
|
158
217
|
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsx(
|
|
159
218
|
Tooltip,
|
|
160
219
|
{
|
|
@@ -171,7 +230,68 @@ const FaireProductWidget = ({ data }) => {
|
|
|
171
230
|
)
|
|
172
231
|
}
|
|
173
232
|
) })
|
|
174
|
-
] })
|
|
233
|
+
] }),
|
|
234
|
+
/* @__PURE__ */ jsx(Drawer, { open: pickerOpen, onOpenChange: setPickerOpen, children: /* @__PURE__ */ jsxs(Drawer.Content, { children: [
|
|
235
|
+
/* @__PURE__ */ jsxs(Drawer.Header, { children: [
|
|
236
|
+
/* @__PURE__ */ jsx(Drawer.Title, { children: "Pick a Faire category" }),
|
|
237
|
+
/* @__PURE__ */ jsx(Drawer.Description, { children: "Search Faire's product taxonomy and pin an exact category to this product." })
|
|
238
|
+
] }),
|
|
239
|
+
/* @__PURE__ */ jsxs(Drawer.Body, { className: "flex flex-col gap-3 overflow-hidden", children: [
|
|
240
|
+
/* @__PURE__ */ jsx(
|
|
241
|
+
Input,
|
|
242
|
+
{
|
|
243
|
+
type: "search",
|
|
244
|
+
autoFocus: true,
|
|
245
|
+
placeholder: "Search categories…",
|
|
246
|
+
value: pickerSearch,
|
|
247
|
+
onChange: (e) => setPickerSearch(e.target.value)
|
|
248
|
+
}
|
|
249
|
+
),
|
|
250
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 overflow-y-auto", children: [
|
|
251
|
+
taxonomyQuery.isLoading ? /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle px-1 py-2", children: "Loading categories…" }) : filteredTaxonomy.length === 0 ? /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle px-1 py-2", children: [
|
|
252
|
+
"No categories match “",
|
|
253
|
+
pickerSearch,
|
|
254
|
+
"”."
|
|
255
|
+
] }) : filteredTaxonomy.map((t) => /* @__PURE__ */ jsxs(
|
|
256
|
+
"button",
|
|
257
|
+
{
|
|
258
|
+
type: "button",
|
|
259
|
+
onClick: () => saveCategory.mutate(t.id),
|
|
260
|
+
disabled: saveCategory.isPending,
|
|
261
|
+
className: clx(
|
|
262
|
+
"flex items-center justify-between rounded-md px-3 py-2 text-left text-sm",
|
|
263
|
+
"hover:bg-ui-bg-base-hover",
|
|
264
|
+
t.id === pinnedId && "bg-ui-bg-highlight"
|
|
265
|
+
),
|
|
266
|
+
children: [
|
|
267
|
+
/* @__PURE__ */ jsx("span", { children: t.name }),
|
|
268
|
+
t.id === pinnedId && /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "green", children: "Current" })
|
|
269
|
+
]
|
|
270
|
+
},
|
|
271
|
+
t.id
|
|
272
|
+
)),
|
|
273
|
+
!taxonomyQuery.isLoading && taxonomy.length > filteredTaxonomy.length && /* @__PURE__ */ jsxs(Text, { size: "xsmall", className: "text-ui-fg-muted px-1 py-1", children: [
|
|
274
|
+
"Showing ",
|
|
275
|
+
filteredTaxonomy.length,
|
|
276
|
+
" of ",
|
|
277
|
+
taxonomy.length,
|
|
278
|
+
" — refine your search to narrow down."
|
|
279
|
+
] })
|
|
280
|
+
] })
|
|
281
|
+
] }),
|
|
282
|
+
/* @__PURE__ */ jsxs(Drawer.Footer, { children: [
|
|
283
|
+
pinnedId && /* @__PURE__ */ jsx(
|
|
284
|
+
Button,
|
|
285
|
+
{
|
|
286
|
+
variant: "secondary",
|
|
287
|
+
onClick: () => saveCategory.mutate(null),
|
|
288
|
+
isLoading: saveCategory.isPending,
|
|
289
|
+
children: "Clear"
|
|
290
|
+
}
|
|
291
|
+
),
|
|
292
|
+
/* @__PURE__ */ jsx(Drawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "secondary", children: "Cancel" }) })
|
|
293
|
+
] })
|
|
294
|
+
] }) })
|
|
175
295
|
] });
|
|
176
296
|
};
|
|
177
297
|
defineWidgetConfig({
|
|
@@ -339,7 +459,8 @@ const FaireSettingsPage = () => {
|
|
|
339
459
|
/* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
|
|
340
460
|
/* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-32" }) }),
|
|
341
461
|
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3 px-6 pb-6", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" }, i)) })
|
|
342
|
-
] })
|
|
462
|
+
] }),
|
|
463
|
+
/* @__PURE__ */ jsx(Outlet, {})
|
|
343
464
|
] });
|
|
344
465
|
}
|
|
345
466
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
@@ -467,6 +588,7 @@ const FaireSettingsPage = () => {
|
|
|
467
588
|
)
|
|
468
589
|
] })
|
|
469
590
|
] }) }),
|
|
591
|
+
/* @__PURE__ */ jsx(Outlet, {}),
|
|
470
592
|
/* @__PURE__ */ jsx(Toaster, {})
|
|
471
593
|
] });
|
|
472
594
|
};
|
|
@@ -481,6 +603,213 @@ const config = defineRouteConfig({
|
|
|
481
603
|
const handle$3 = {
|
|
482
604
|
breadcrumb: () => "Faire Sync"
|
|
483
605
|
};
|
|
606
|
+
const STATUS_KEY = ["faire", "status"];
|
|
607
|
+
const TAXONOMY_KEY = ["faire", "taxonomy"];
|
|
608
|
+
const PARENT$1 = "/settings/faire";
|
|
609
|
+
const NONE = "__none__";
|
|
610
|
+
const cleanSettings = (form) => {
|
|
611
|
+
const out = { ...form };
|
|
612
|
+
for (const key of [
|
|
613
|
+
"default_brand_id",
|
|
614
|
+
"default_category"
|
|
615
|
+
]) {
|
|
616
|
+
if (!out[key] || out[key] === NONE) out[key] = null;
|
|
617
|
+
}
|
|
618
|
+
if (out.default_wholesale_markup_percent === "" || out.default_wholesale_markup_percent === NONE) {
|
|
619
|
+
out.default_wholesale_markup_percent = null;
|
|
620
|
+
}
|
|
621
|
+
if (out.default_lead_time_days === "" || out.default_lead_time_days === NONE) {
|
|
622
|
+
out.default_lead_time_days = null;
|
|
623
|
+
}
|
|
624
|
+
return out;
|
|
625
|
+
};
|
|
626
|
+
const FaireSyncSettingsDrawer = () => {
|
|
627
|
+
const navigate = useNavigate();
|
|
628
|
+
const queryClient = useQueryClient();
|
|
629
|
+
const [open, setOpen] = useState(true);
|
|
630
|
+
const [form, setForm] = useState({});
|
|
631
|
+
const close = () => {
|
|
632
|
+
setOpen(false);
|
|
633
|
+
navigate(PARENT$1);
|
|
634
|
+
};
|
|
635
|
+
const statusQuery = useQuery({
|
|
636
|
+
queryKey: STATUS_KEY,
|
|
637
|
+
queryFn: () => faireApi.status()
|
|
638
|
+
});
|
|
639
|
+
const status = statusQuery.data;
|
|
640
|
+
const connected = !!(status == null ? void 0 : status.connected);
|
|
641
|
+
const taxonomyQuery = useQuery({
|
|
642
|
+
queryKey: TAXONOMY_KEY,
|
|
643
|
+
queryFn: async () => (await faireApi.taxonomy().catch(() => ({ taxonomy: [] }))).taxonomy || []
|
|
644
|
+
});
|
|
645
|
+
const taxonomy = taxonomyQuery.data ?? [];
|
|
646
|
+
useEffect(() => {
|
|
647
|
+
if (status == null ? void 0 : status.settings) setForm(status.settings);
|
|
648
|
+
}, [status == null ? void 0 : status.settings]);
|
|
649
|
+
const saveMutation = useMutation({
|
|
650
|
+
mutationFn: (payload) => faireApi.saveSettings(payload),
|
|
651
|
+
onSuccess: () => {
|
|
652
|
+
queryClient.invalidateQueries({ queryKey: STATUS_KEY });
|
|
653
|
+
toast.success("Sync settings saved");
|
|
654
|
+
close();
|
|
655
|
+
},
|
|
656
|
+
onError: (err) => toast.error("Failed to save settings", { description: err.message })
|
|
657
|
+
});
|
|
658
|
+
return /* @__PURE__ */ jsxs(Drawer, { open, onOpenChange: (o) => o ? setOpen(true) : close(), children: [
|
|
659
|
+
/* @__PURE__ */ jsxs(Drawer.Content, { children: [
|
|
660
|
+
/* @__PURE__ */ jsxs(Drawer.Header, { children: [
|
|
661
|
+
/* @__PURE__ */ jsx(Drawer.Title, { children: "Sync settings" }),
|
|
662
|
+
/* @__PURE__ */ jsx(Drawer.Description, { children: "Publish readiness and the defaults applied to every product pushed to Faire." })
|
|
663
|
+
] }),
|
|
664
|
+
/* @__PURE__ */ jsx(Drawer.Body, { className: "flex flex-col gap-6 overflow-y-auto", children: statusQuery.isLoading ? /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3", children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" }, i)) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
665
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
666
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
667
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", children: "Publish readiness" }),
|
|
668
|
+
/* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", size: "small", children: "Faire needs a brand and a wholesale-pricing strategy to publish products. Missing fields sync products as drafts." })
|
|
669
|
+
] }),
|
|
670
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
671
|
+
/* @__PURE__ */ jsx(ChecklistItem, { ok: status == null ? void 0 : status.readiness.connected, label: "Faire connected" }),
|
|
672
|
+
/* @__PURE__ */ jsx(ChecklistItem, { ok: status == null ? void 0 : status.readiness.brand, label: "Brand configured" }),
|
|
673
|
+
/* @__PURE__ */ jsx(ChecklistItem, { ok: status == null ? void 0 : status.readiness.wholesale_pricing, label: "Wholesale pricing" }),
|
|
674
|
+
/* @__PURE__ */ jsx(ChecklistItem, { ok: status == null ? void 0 : status.readiness.taxonomy, label: "Default category" })
|
|
675
|
+
] })
|
|
676
|
+
] }),
|
|
677
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
678
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
679
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", children: "Sync defaults" }),
|
|
680
|
+
/* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", size: "small", children: "Applied to every product unless overridden in product metadata." })
|
|
681
|
+
] }),
|
|
682
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4", children: [
|
|
683
|
+
/* @__PURE__ */ jsx(Field, { label: "Brand ID", children: /* @__PURE__ */ jsx(
|
|
684
|
+
Input,
|
|
685
|
+
{
|
|
686
|
+
value: String(form.default_brand_id ?? ""),
|
|
687
|
+
onChange: (e) => setForm({ ...form, default_brand_id: e.target.value || null }),
|
|
688
|
+
disabled: !connected,
|
|
689
|
+
placeholder: "b_..."
|
|
690
|
+
}
|
|
691
|
+
) }),
|
|
692
|
+
/* @__PURE__ */ jsx(Field, { label: "Wholesale markup % (off retail)", children: /* @__PURE__ */ jsx(Tooltip, { content: "Wholesale price = retail × (100 − markup%) / 100. E.g. 50 → half of retail.", children: /* @__PURE__ */ jsx(
|
|
693
|
+
Input,
|
|
694
|
+
{
|
|
695
|
+
type: "number",
|
|
696
|
+
value: String(form.default_wholesale_markup_percent ?? ""),
|
|
697
|
+
onChange: (e) => setForm({
|
|
698
|
+
...form,
|
|
699
|
+
default_wholesale_markup_percent: e.target.value ? Number(e.target.value) : null
|
|
700
|
+
}),
|
|
701
|
+
disabled: !connected,
|
|
702
|
+
placeholder: "e.g. 50"
|
|
703
|
+
}
|
|
704
|
+
) }) }),
|
|
705
|
+
/* @__PURE__ */ jsx(Field, { label: "Default min order quantity", children: /* @__PURE__ */ jsx(
|
|
706
|
+
Input,
|
|
707
|
+
{
|
|
708
|
+
type: "number",
|
|
709
|
+
value: String(form.default_min_order_quantity ?? 1),
|
|
710
|
+
onChange: (e) => setForm({
|
|
711
|
+
...form,
|
|
712
|
+
default_min_order_quantity: e.target.value ? Number(e.target.value) : 1
|
|
713
|
+
}),
|
|
714
|
+
disabled: !connected
|
|
715
|
+
}
|
|
716
|
+
) }),
|
|
717
|
+
/* @__PURE__ */ jsx(Field, { label: "Default lead time (days)", children: /* @__PURE__ */ jsx(
|
|
718
|
+
Input,
|
|
719
|
+
{
|
|
720
|
+
type: "number",
|
|
721
|
+
value: String(form.default_lead_time_days ?? ""),
|
|
722
|
+
onChange: (e) => setForm({
|
|
723
|
+
...form,
|
|
724
|
+
default_lead_time_days: e.target.value ? Number(e.target.value) : null
|
|
725
|
+
}),
|
|
726
|
+
disabled: !connected,
|
|
727
|
+
placeholder: "e.g. 14"
|
|
728
|
+
}
|
|
729
|
+
) }),
|
|
730
|
+
/* @__PURE__ */ jsx(Field, { label: "Fallback category (taxonomy)", children: /* @__PURE__ */ jsx(Tooltip, { content: "Faire requires a category per product. Resolution order: product metadata → the product's Type (matched by name) → this fallback. Set the product Type or pick a category on the product page for accuracy.", children: /* @__PURE__ */ jsx(
|
|
731
|
+
SelectField,
|
|
732
|
+
{
|
|
733
|
+
value: String(form.default_category ?? ""),
|
|
734
|
+
onValueChange: (v) => setForm({ ...form, default_category: v || null }),
|
|
735
|
+
disabled: !connected,
|
|
736
|
+
options: taxonomy.map((t) => ({ value: t.id, label: t.name }))
|
|
737
|
+
}
|
|
738
|
+
) }) }),
|
|
739
|
+
/* @__PURE__ */ jsx(Field, { label: "Follow product status", children: /* @__PURE__ */ jsx(Tooltip, { content: "If on, published Medusa products are published on Faire; draft products sync as drafts.", children: /* @__PURE__ */ jsx(
|
|
740
|
+
Switch,
|
|
741
|
+
{
|
|
742
|
+
checked: form.follow_product_status !== false,
|
|
743
|
+
onCheckedChange: (v) => setForm({ ...form, follow_product_status: v })
|
|
744
|
+
}
|
|
745
|
+
) }) }),
|
|
746
|
+
/* @__PURE__ */ jsx(Field, { label: "Auto publish", children: /* @__PURE__ */ jsx(Tooltip, { content: "Publish products to Faire automatically on sync (otherwise create as draft).", children: /* @__PURE__ */ jsx(
|
|
747
|
+
Switch,
|
|
748
|
+
{
|
|
749
|
+
checked: !!form.auto_publish,
|
|
750
|
+
onCheckedChange: (v) => setForm({ ...form, auto_publish: v })
|
|
751
|
+
}
|
|
752
|
+
) }) })
|
|
753
|
+
] })
|
|
754
|
+
] })
|
|
755
|
+
] }) }),
|
|
756
|
+
/* @__PURE__ */ jsxs(Drawer.Footer, { children: [
|
|
757
|
+
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: close, children: "Cancel" }),
|
|
758
|
+
/* @__PURE__ */ jsx(
|
|
759
|
+
Button,
|
|
760
|
+
{
|
|
761
|
+
onClick: () => saveMutation.mutate(cleanSettings(form)),
|
|
762
|
+
isLoading: saveMutation.isPending,
|
|
763
|
+
disabled: !connected,
|
|
764
|
+
children: "Save settings"
|
|
765
|
+
}
|
|
766
|
+
)
|
|
767
|
+
] })
|
|
768
|
+
] }),
|
|
769
|
+
/* @__PURE__ */ jsx(Toaster, {})
|
|
770
|
+
] });
|
|
771
|
+
};
|
|
772
|
+
const Field = ({ label, children }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
773
|
+
/* @__PURE__ */ jsx(Label, { children: label }),
|
|
774
|
+
children
|
|
775
|
+
] });
|
|
776
|
+
const SelectField = ({
|
|
777
|
+
value,
|
|
778
|
+
onValueChange,
|
|
779
|
+
options,
|
|
780
|
+
disabled
|
|
781
|
+
}) => /* @__PURE__ */ jsxs(
|
|
782
|
+
Select,
|
|
783
|
+
{
|
|
784
|
+
value: value ? value : NONE,
|
|
785
|
+
onValueChange: (v) => onValueChange(v === NONE ? "" : v),
|
|
786
|
+
disabled,
|
|
787
|
+
size: "small",
|
|
788
|
+
children: [
|
|
789
|
+
/* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "Not set" }) }),
|
|
790
|
+
/* @__PURE__ */ jsxs(Select.Content, { children: [
|
|
791
|
+
/* @__PURE__ */ jsx(Select.Item, { value: NONE, children: "Not set" }),
|
|
792
|
+
options.map((o) => /* @__PURE__ */ jsx(Select.Item, { value: o.value, children: o.label }, o.value))
|
|
793
|
+
] })
|
|
794
|
+
]
|
|
795
|
+
}
|
|
796
|
+
);
|
|
797
|
+
const ChecklistItem = ({ ok, label }) => /* @__PURE__ */ jsxs(
|
|
798
|
+
"div",
|
|
799
|
+
{
|
|
800
|
+
className: clx(
|
|
801
|
+
"flex items-center gap-2 rounded-lg border px-3 py-2",
|
|
802
|
+
ok ? "border-ui-tag-green-border bg-ui-tag-green-bg" : "border-ui-tag-red-border bg-ui-tag-red-bg"
|
|
803
|
+
),
|
|
804
|
+
children: [
|
|
805
|
+
/* @__PURE__ */ jsx(StatusBadge, { color: ok ? "green" : "red", children: ok ? "Ready" : "Missing" }),
|
|
806
|
+
/* @__PURE__ */ jsx(Text, { children: label })
|
|
807
|
+
]
|
|
808
|
+
}
|
|
809
|
+
);
|
|
810
|
+
const handle$2 = {
|
|
811
|
+
breadcrumb: () => "Sync settings"
|
|
812
|
+
};
|
|
484
813
|
const Root = ({ prev = "..", children }) => {
|
|
485
814
|
const navigate = useNavigate();
|
|
486
815
|
const [open, setOpen] = useState(false);
|
|
@@ -689,10 +1018,7 @@ const FaireBulkPage = () => {
|
|
|
689
1018
|
search: { state: search, onSearchChange: setSearch }
|
|
690
1019
|
});
|
|
691
1020
|
return /* @__PURE__ */ jsxs(RouteFocusModal, { prev: "/settings/faire", children: [
|
|
692
|
-
/* @__PURE__ */ jsx(RouteFocusModal.Header, { children: /* @__PURE__ */
|
|
693
|
-
/* @__PURE__ */ jsx(Heading, { children: "Bulk sync products to Faire" }),
|
|
694
|
-
/* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", size: "small", children: "Select products (or all matching) and push them to Faire as a background sync via the command bar." })
|
|
695
|
-
] }) }),
|
|
1021
|
+
/* @__PURE__ */ jsx(RouteFocusModal.Header, { children: /* @__PURE__ */ jsx(RouteFocusModal.Title, { asChild: true, children: /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Bulk sync" }) }) }),
|
|
696
1022
|
/* @__PURE__ */ jsx(RouteFocusModal.Body, { className: "flex flex-1 flex-col overflow-hidden p-0", children: /* @__PURE__ */ jsxs(DataTable, { instance: table, children: [
|
|
697
1023
|
/* @__PURE__ */ jsxs(DataTable.Toolbar, { className: "flex flex-col gap-y-3 border-b px-6 py-4", children: [
|
|
698
1024
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-2 md:flex-row md:items-center md:justify-between", children: [
|
|
@@ -732,6 +1058,22 @@ const FaireBulkPage = () => {
|
|
|
732
1058
|
},
|
|
733
1059
|
children: selectAllMatching ? `All ${count} selected` : `Select all ${count}`
|
|
734
1060
|
}
|
|
1061
|
+
),
|
|
1062
|
+
/* @__PURE__ */ jsx(
|
|
1063
|
+
Button,
|
|
1064
|
+
{
|
|
1065
|
+
size: "small",
|
|
1066
|
+
onClick: () => {
|
|
1067
|
+
if (!connected) {
|
|
1068
|
+
toast.error("Faire is not connected");
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
pushMutation.mutate();
|
|
1072
|
+
},
|
|
1073
|
+
disabled: !connected || targetCount === 0,
|
|
1074
|
+
isLoading: pushMutation.isPending,
|
|
1075
|
+
children: "Push to Faire"
|
|
1076
|
+
}
|
|
735
1077
|
)
|
|
736
1078
|
] })
|
|
737
1079
|
] }),
|
|
@@ -777,10 +1119,10 @@ const FaireBulkPage = () => {
|
|
|
777
1119
|
/* @__PURE__ */ jsx(Toaster, {})
|
|
778
1120
|
] });
|
|
779
1121
|
};
|
|
780
|
-
const handle$
|
|
1122
|
+
const handle$1 = {
|
|
781
1123
|
breadcrumb: () => "Bulk sync"
|
|
782
1124
|
};
|
|
783
|
-
const PARENT
|
|
1125
|
+
const PARENT = "/settings/faire";
|
|
784
1126
|
const STATUS_COLORS = {
|
|
785
1127
|
success: "green",
|
|
786
1128
|
failed: "red",
|
|
@@ -817,7 +1159,7 @@ const FaireSyncDetailPage = () => {
|
|
|
817
1159
|
}
|
|
818
1160
|
};
|
|
819
1161
|
const warnings = (record == null ? void 0 : record.error_message) ? record.error_message.split(" | ") : [];
|
|
820
|
-
return /* @__PURE__ */ jsxs(RouteFocusModal, { prev: PARENT
|
|
1162
|
+
return /* @__PURE__ */ jsxs(RouteFocusModal, { prev: PARENT, children: [
|
|
821
1163
|
/* @__PURE__ */ jsxs(RouteFocusModal.Header, { children: [
|
|
822
1164
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
823
1165
|
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Sync record" }),
|
|
@@ -856,7 +1198,7 @@ const FaireSyncDetailPage = () => {
|
|
|
856
1198
|
error && /* @__PURE__ */ jsx(Text, { className: "text-ui-tag-red-text", children: error }),
|
|
857
1199
|
loading ? /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3", children: Array.from({ length: 4 }).map((_, i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" }, i)) }) : !record ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start gap-4", children: [
|
|
858
1200
|
/* @__PURE__ */ jsx(Heading, { level: "h2", children: "Sync record not found" }),
|
|
859
|
-
/* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", onClick: () => navigate(PARENT
|
|
1201
|
+
/* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", onClick: () => navigate(PARENT), children: "Back to Faire settings" })
|
|
860
1202
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
861
1203
|
/* @__PURE__ */ jsxs("div", { className: "border-ui-border-base grid grid-cols-2 gap-4 rounded-lg border p-4", children: [
|
|
862
1204
|
/* @__PURE__ */ jsx(Detail, { label: "Record id", value: record.id, mono: true }),
|
|
@@ -890,226 +1232,8 @@ const Detail = ({
|
|
|
890
1232
|
/* @__PURE__ */ jsx(Label, { children: label }),
|
|
891
1233
|
/* @__PURE__ */ jsx(Text, { className: mono ? "font-mono text-xs" : "", children: value })
|
|
892
1234
|
] });
|
|
893
|
-
const handle$1 = {
|
|
894
|
-
breadcrumb: () => "Sync record"
|
|
895
|
-
};
|
|
896
|
-
const STATUS_KEY = ["faire", "status"];
|
|
897
|
-
const TAXONOMY_KEY = ["faire", "taxonomy"];
|
|
898
|
-
const PARENT = "/settings/faire";
|
|
899
|
-
const NONE = "__none__";
|
|
900
|
-
const cleanSettings = (form) => {
|
|
901
|
-
const out = { ...form };
|
|
902
|
-
for (const key of [
|
|
903
|
-
"default_brand_id",
|
|
904
|
-
"default_shipping_policy_id",
|
|
905
|
-
"default_category"
|
|
906
|
-
]) {
|
|
907
|
-
if (!out[key] || out[key] === NONE) out[key] = null;
|
|
908
|
-
}
|
|
909
|
-
if (out.default_wholesale_markup_percent === "" || out.default_wholesale_markup_percent === NONE) {
|
|
910
|
-
out.default_wholesale_markup_percent = null;
|
|
911
|
-
}
|
|
912
|
-
if (out.default_lead_time_days === "" || out.default_lead_time_days === NONE) {
|
|
913
|
-
out.default_lead_time_days = null;
|
|
914
|
-
}
|
|
915
|
-
return out;
|
|
916
|
-
};
|
|
917
|
-
const FaireSyncSettingsDrawer = () => {
|
|
918
|
-
const navigate = useNavigate();
|
|
919
|
-
const queryClient = useQueryClient();
|
|
920
|
-
const [open, setOpen] = useState(true);
|
|
921
|
-
const [form, setForm] = useState({});
|
|
922
|
-
const close = () => {
|
|
923
|
-
setOpen(false);
|
|
924
|
-
navigate(PARENT);
|
|
925
|
-
};
|
|
926
|
-
const statusQuery = useQuery({
|
|
927
|
-
queryKey: STATUS_KEY,
|
|
928
|
-
queryFn: () => faireApi.status()
|
|
929
|
-
});
|
|
930
|
-
const status = statusQuery.data;
|
|
931
|
-
const connected = !!(status == null ? void 0 : status.connected);
|
|
932
|
-
const taxonomyQuery = useQuery({
|
|
933
|
-
queryKey: TAXONOMY_KEY,
|
|
934
|
-
queryFn: async () => (await faireApi.taxonomy().catch(() => ({ taxonomy: [] }))).taxonomy || []
|
|
935
|
-
});
|
|
936
|
-
const taxonomy = taxonomyQuery.data ?? [];
|
|
937
|
-
useEffect(() => {
|
|
938
|
-
if (status == null ? void 0 : status.settings) setForm(status.settings);
|
|
939
|
-
}, [status == null ? void 0 : status.settings]);
|
|
940
|
-
const saveMutation = useMutation({
|
|
941
|
-
mutationFn: (payload) => faireApi.saveSettings(payload),
|
|
942
|
-
onSuccess: () => {
|
|
943
|
-
queryClient.invalidateQueries({ queryKey: STATUS_KEY });
|
|
944
|
-
toast.success("Sync settings saved");
|
|
945
|
-
close();
|
|
946
|
-
},
|
|
947
|
-
onError: (err) => toast.error("Failed to save settings", { description: err.message })
|
|
948
|
-
});
|
|
949
|
-
return /* @__PURE__ */ jsxs(Drawer, { open, onOpenChange: (o) => o ? setOpen(true) : close(), children: [
|
|
950
|
-
/* @__PURE__ */ jsxs(Drawer.Content, { children: [
|
|
951
|
-
/* @__PURE__ */ jsxs(Drawer.Header, { children: [
|
|
952
|
-
/* @__PURE__ */ jsx(Drawer.Title, { children: "Sync settings" }),
|
|
953
|
-
/* @__PURE__ */ jsx(Drawer.Description, { children: "Publish readiness and the defaults applied to every product pushed to Faire." })
|
|
954
|
-
] }),
|
|
955
|
-
/* @__PURE__ */ jsx(Drawer.Body, { className: "flex flex-col gap-6 overflow-y-auto", children: statusQuery.isLoading ? /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3", children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" }, i)) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
956
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
957
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
958
|
-
/* @__PURE__ */ jsx(Heading, { level: "h2", children: "Publish readiness" }),
|
|
959
|
-
/* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", size: "small", children: "Faire needs a brand and a wholesale-pricing strategy to publish products. Missing fields sync products as drafts." })
|
|
960
|
-
] }),
|
|
961
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
962
|
-
/* @__PURE__ */ jsx(ChecklistItem, { ok: status == null ? void 0 : status.readiness.connected, label: "Faire connected" }),
|
|
963
|
-
/* @__PURE__ */ jsx(ChecklistItem, { ok: status == null ? void 0 : status.readiness.brand, label: "Brand configured" }),
|
|
964
|
-
/* @__PURE__ */ jsx(ChecklistItem, { ok: status == null ? void 0 : status.readiness.wholesale_pricing, label: "Wholesale pricing" }),
|
|
965
|
-
/* @__PURE__ */ jsx(ChecklistItem, { ok: status == null ? void 0 : status.readiness.shipping_policy, label: "Shipping policy" }),
|
|
966
|
-
/* @__PURE__ */ jsx(ChecklistItem, { ok: status == null ? void 0 : status.readiness.taxonomy, label: "Default category" })
|
|
967
|
-
] })
|
|
968
|
-
] }),
|
|
969
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
970
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
971
|
-
/* @__PURE__ */ jsx(Heading, { level: "h2", children: "Sync defaults" }),
|
|
972
|
-
/* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", size: "small", children: "Applied to every product unless overridden in product metadata." })
|
|
973
|
-
] }),
|
|
974
|
-
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4", children: [
|
|
975
|
-
/* @__PURE__ */ jsx(Field, { label: "Brand ID", children: /* @__PURE__ */ jsx(
|
|
976
|
-
Input,
|
|
977
|
-
{
|
|
978
|
-
value: String(form.default_brand_id ?? ""),
|
|
979
|
-
onChange: (e) => setForm({ ...form, default_brand_id: e.target.value || null }),
|
|
980
|
-
disabled: !connected,
|
|
981
|
-
placeholder: "b_..."
|
|
982
|
-
}
|
|
983
|
-
) }),
|
|
984
|
-
/* @__PURE__ */ jsx(Field, { label: "Wholesale markup % (off retail)", children: /* @__PURE__ */ jsx(Tooltip, { content: "Wholesale price = retail × (100 − markup%) / 100. E.g. 50 → half of retail.", children: /* @__PURE__ */ jsx(
|
|
985
|
-
Input,
|
|
986
|
-
{
|
|
987
|
-
type: "number",
|
|
988
|
-
value: String(form.default_wholesale_markup_percent ?? ""),
|
|
989
|
-
onChange: (e) => setForm({
|
|
990
|
-
...form,
|
|
991
|
-
default_wholesale_markup_percent: e.target.value ? Number(e.target.value) : null
|
|
992
|
-
}),
|
|
993
|
-
disabled: !connected,
|
|
994
|
-
placeholder: "e.g. 50"
|
|
995
|
-
}
|
|
996
|
-
) }) }),
|
|
997
|
-
/* @__PURE__ */ jsx(Field, { label: "Default min order quantity", children: /* @__PURE__ */ jsx(
|
|
998
|
-
Input,
|
|
999
|
-
{
|
|
1000
|
-
type: "number",
|
|
1001
|
-
value: String(form.default_min_order_quantity ?? 1),
|
|
1002
|
-
onChange: (e) => setForm({
|
|
1003
|
-
...form,
|
|
1004
|
-
default_min_order_quantity: e.target.value ? Number(e.target.value) : 1
|
|
1005
|
-
}),
|
|
1006
|
-
disabled: !connected
|
|
1007
|
-
}
|
|
1008
|
-
) }),
|
|
1009
|
-
/* @__PURE__ */ jsx(Field, { label: "Default lead time (days)", children: /* @__PURE__ */ jsx(
|
|
1010
|
-
Input,
|
|
1011
|
-
{
|
|
1012
|
-
type: "number",
|
|
1013
|
-
value: String(form.default_lead_time_days ?? ""),
|
|
1014
|
-
onChange: (e) => setForm({
|
|
1015
|
-
...form,
|
|
1016
|
-
default_lead_time_days: e.target.value ? Number(e.target.value) : null
|
|
1017
|
-
}),
|
|
1018
|
-
disabled: !connected,
|
|
1019
|
-
placeholder: "e.g. 14"
|
|
1020
|
-
}
|
|
1021
|
-
) }),
|
|
1022
|
-
/* @__PURE__ */ jsx(Field, { label: "Default category (taxonomy)", children: /* @__PURE__ */ jsx(
|
|
1023
|
-
SelectField,
|
|
1024
|
-
{
|
|
1025
|
-
value: String(form.default_category ?? ""),
|
|
1026
|
-
onValueChange: (v) => setForm({ ...form, default_category: v || null }),
|
|
1027
|
-
disabled: !connected,
|
|
1028
|
-
options: taxonomy.map((t) => ({ value: t.id, label: t.name }))
|
|
1029
|
-
}
|
|
1030
|
-
) }),
|
|
1031
|
-
/* @__PURE__ */ jsx(Field, { label: "Shipping policy ID", children: /* @__PURE__ */ jsx(
|
|
1032
|
-
Input,
|
|
1033
|
-
{
|
|
1034
|
-
value: String(form.default_shipping_policy_id ?? ""),
|
|
1035
|
-
onChange: (e) => setForm({ ...form, default_shipping_policy_id: e.target.value || null }),
|
|
1036
|
-
disabled: !connected,
|
|
1037
|
-
placeholder: "sp_..."
|
|
1038
|
-
}
|
|
1039
|
-
) }),
|
|
1040
|
-
/* @__PURE__ */ jsx(Field, { label: "Follow product status", children: /* @__PURE__ */ jsx(Tooltip, { content: "If on, published Medusa products are published on Faire; draft products sync as drafts.", children: /* @__PURE__ */ jsx(
|
|
1041
|
-
Switch,
|
|
1042
|
-
{
|
|
1043
|
-
checked: form.follow_product_status !== false,
|
|
1044
|
-
onCheckedChange: (v) => setForm({ ...form, follow_product_status: v })
|
|
1045
|
-
}
|
|
1046
|
-
) }) }),
|
|
1047
|
-
/* @__PURE__ */ jsx(Field, { label: "Auto publish", children: /* @__PURE__ */ jsx(Tooltip, { content: "Publish products to Faire automatically on sync (otherwise create as draft).", children: /* @__PURE__ */ jsx(
|
|
1048
|
-
Switch,
|
|
1049
|
-
{
|
|
1050
|
-
checked: !!form.auto_publish,
|
|
1051
|
-
onCheckedChange: (v) => setForm({ ...form, auto_publish: v })
|
|
1052
|
-
}
|
|
1053
|
-
) }) })
|
|
1054
|
-
] })
|
|
1055
|
-
] })
|
|
1056
|
-
] }) }),
|
|
1057
|
-
/* @__PURE__ */ jsxs(Drawer.Footer, { children: [
|
|
1058
|
-
/* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: close, children: "Cancel" }),
|
|
1059
|
-
/* @__PURE__ */ jsx(
|
|
1060
|
-
Button,
|
|
1061
|
-
{
|
|
1062
|
-
onClick: () => saveMutation.mutate(cleanSettings(form)),
|
|
1063
|
-
isLoading: saveMutation.isPending,
|
|
1064
|
-
disabled: !connected,
|
|
1065
|
-
children: "Save settings"
|
|
1066
|
-
}
|
|
1067
|
-
)
|
|
1068
|
-
] })
|
|
1069
|
-
] }),
|
|
1070
|
-
/* @__PURE__ */ jsx(Toaster, {})
|
|
1071
|
-
] });
|
|
1072
|
-
};
|
|
1073
|
-
const Field = ({ label, children }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
1074
|
-
/* @__PURE__ */ jsx(Label, { children: label }),
|
|
1075
|
-
children
|
|
1076
|
-
] });
|
|
1077
|
-
const SelectField = ({
|
|
1078
|
-
value,
|
|
1079
|
-
onValueChange,
|
|
1080
|
-
options,
|
|
1081
|
-
disabled
|
|
1082
|
-
}) => /* @__PURE__ */ jsxs(
|
|
1083
|
-
Select,
|
|
1084
|
-
{
|
|
1085
|
-
value: value ? value : NONE,
|
|
1086
|
-
onValueChange: (v) => onValueChange(v === NONE ? "" : v),
|
|
1087
|
-
disabled,
|
|
1088
|
-
size: "small",
|
|
1089
|
-
children: [
|
|
1090
|
-
/* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "Not set" }) }),
|
|
1091
|
-
/* @__PURE__ */ jsxs(Select.Content, { children: [
|
|
1092
|
-
/* @__PURE__ */ jsx(Select.Item, { value: NONE, children: "Not set" }),
|
|
1093
|
-
options.map((o) => /* @__PURE__ */ jsx(Select.Item, { value: o.value, children: o.label }, o.value))
|
|
1094
|
-
] })
|
|
1095
|
-
]
|
|
1096
|
-
}
|
|
1097
|
-
);
|
|
1098
|
-
const ChecklistItem = ({ ok, label }) => /* @__PURE__ */ jsxs(
|
|
1099
|
-
"div",
|
|
1100
|
-
{
|
|
1101
|
-
className: clx(
|
|
1102
|
-
"flex items-center gap-2 rounded-lg border px-3 py-2",
|
|
1103
|
-
ok ? "border-ui-tag-green-border bg-ui-tag-green-bg" : "border-ui-tag-red-border bg-ui-tag-red-bg"
|
|
1104
|
-
),
|
|
1105
|
-
children: [
|
|
1106
|
-
/* @__PURE__ */ jsx(StatusBadge, { color: ok ? "green" : "red", children: ok ? "Ready" : "Missing" }),
|
|
1107
|
-
/* @__PURE__ */ jsx(Text, { children: label })
|
|
1108
|
-
]
|
|
1109
|
-
}
|
|
1110
|
-
);
|
|
1111
1235
|
const handle = {
|
|
1112
|
-
breadcrumb: () => "Sync
|
|
1236
|
+
breadcrumb: () => "Sync record"
|
|
1113
1237
|
};
|
|
1114
1238
|
const EXCHANGED_PREFIX = "faire:oauth:exchanged:";
|
|
1115
1239
|
const FaireOauthCallback = () => {
|
|
@@ -1189,21 +1313,23 @@ const routeModule = {
|
|
|
1189
1313
|
{
|
|
1190
1314
|
Component: FaireSettingsPage,
|
|
1191
1315
|
path: "/settings/faire",
|
|
1192
|
-
handle: handle$3
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1316
|
+
handle: handle$3,
|
|
1317
|
+
children: [
|
|
1318
|
+
{
|
|
1319
|
+
Component: FaireSyncSettingsDrawer,
|
|
1320
|
+
path: "/settings/faire/settings",
|
|
1321
|
+
handle: handle$2
|
|
1322
|
+
},
|
|
1323
|
+
{
|
|
1324
|
+
Component: FaireBulkPage,
|
|
1325
|
+
path: "/settings/faire/bulk",
|
|
1326
|
+
handle: handle$1
|
|
1327
|
+
}
|
|
1328
|
+
]
|
|
1198
1329
|
},
|
|
1199
1330
|
{
|
|
1200
1331
|
Component: FaireSyncDetailPage,
|
|
1201
1332
|
path: "/settings/faire/:id",
|
|
1202
|
-
handle: handle$1
|
|
1203
|
-
},
|
|
1204
|
-
{
|
|
1205
|
-
Component: FaireSyncSettingsDrawer,
|
|
1206
|
-
path: "/settings/faire/settings",
|
|
1207
1333
|
handle
|
|
1208
1334
|
},
|
|
1209
1335
|
{
|