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