@jytextiles/medusa-plugin-faire-store-sync 0.2.4 → 0.2.6
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/__tests__/faire-client.spec.js +27 -7
- package/.medusa/server/src/__tests__/ingest-faire-order-support.spec.js +61 -1
- package/.medusa/server/src/admin/index.js +182 -132
- package/.medusa/server/src/admin/index.mjs +184 -134
- package/.medusa/server/src/lib/faire-client.js +100 -18
- package/.medusa/server/src/lib/types.js +6 -2
- package/.medusa/server/src/modules/faire-sync/migrations/Migration20260709161201.js +14 -0
- package/.medusa/server/src/modules/faire-sync/models/faire-sync-account.js +5 -1
- package/.medusa/server/src/modules/faire-sync/service.js +33 -14
- package/.medusa/server/src/workflows/ingest-faire-order-support.js +81 -28
- package/.medusa/server/src/workflows/ingest-faire-orders-bulk.js +2 -2
- package/.medusa/server/src/workflows/sync-product-to-faire.js +109 -37
- package/package.json +1 -1
- package/src/__tests__/faire-client.spec.ts +28 -6
- package/src/__tests__/ingest-faire-order-support.spec.ts +63 -0
- package/src/admin/routes/settings/faire/[id]/page.tsx +56 -61
- package/src/admin/routes/settings/faire/page.tsx +78 -8
- package/src/lib/faire-client.ts +112 -16
- package/src/lib/types.ts +57 -18
- package/src/modules/faire-sync/migrations/.snapshot-medusa-faire-sync.json +19 -0
- package/src/modules/faire-sync/migrations/Migration20260709161201.ts +13 -0
- package/src/modules/faire-sync/models/faire-sync-account.ts +4 -0
- package/src/modules/faire-sync/service.ts +42 -16
- package/src/workflows/ingest-faire-order-support.ts +96 -29
- package/src/workflows/ingest-faire-orders-bulk.ts +1 -1
- package/src/workflows/sync-product-to-faire.ts +143 -41
|
@@ -1,9 +1,9 @@
|
|
|
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, Tooltip, Button, createDataTableColumnHelper, toast, createDataTableFilterHelper, useDataTable, Skeleton, DataTable,
|
|
3
|
+
import { Container, Heading, Text, StatusBadge, Alert, Tooltip, Button, createDataTableColumnHelper, toast, createDataTableFilterHelper, useDataTable, Skeleton, DropdownMenu, DataTable, Drawer, Label, Input, Toaster, FocusModal, Badge, IconButton, Switch, clx } from "@medusajs/ui";
|
|
4
4
|
import { useQueryClient, useQuery, useMutation, keepPreviousData } from "@tanstack/react-query";
|
|
5
5
|
import Medusa from "@medusajs/js-sdk";
|
|
6
|
-
import { BuildingStorefront, EllipsisHorizontal, ArrowPath, ArrowUpRightOnBox } from "@medusajs/icons";
|
|
6
|
+
import { BuildingStorefront, ChevronDownMini, EllipsisHorizontal, ArrowPath, ArrowUpRightOnBox } from "@medusajs/icons";
|
|
7
7
|
import { useState, useEffect, useMemo } from "react";
|
|
8
8
|
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
|
|
9
9
|
const sdk = new Medusa({
|
|
@@ -236,6 +236,8 @@ const FaireSettingsPage = () => {
|
|
|
236
236
|
pageSize: PAGE_SIZE$1
|
|
237
237
|
});
|
|
238
238
|
const [filtering, setFiltering] = useState({});
|
|
239
|
+
const [apiKeyOpen, setApiKeyOpen] = useState(false);
|
|
240
|
+
const [apiKey, setApiKey] = useState("");
|
|
239
241
|
const statusQuery = useQuery({
|
|
240
242
|
queryKey: STATUS_KEY$1,
|
|
241
243
|
queryFn: () => faireApi.status()
|
|
@@ -268,6 +270,18 @@ const FaireSettingsPage = () => {
|
|
|
268
270
|
description: err.message
|
|
269
271
|
})
|
|
270
272
|
});
|
|
273
|
+
const apiKeyMutation = useMutation({
|
|
274
|
+
mutationFn: () => faireApi.connectApiKey(apiKey.trim()),
|
|
275
|
+
onSuccess: () => {
|
|
276
|
+
queryClient.invalidateQueries({ queryKey: STATUS_KEY$1 });
|
|
277
|
+
setApiKeyOpen(false);
|
|
278
|
+
setApiKey("");
|
|
279
|
+
toast.success("Connected to Faire with API key");
|
|
280
|
+
},
|
|
281
|
+
onError: (err) => toast.error("Failed to connect with API key", {
|
|
282
|
+
description: err.message
|
|
283
|
+
})
|
|
284
|
+
});
|
|
271
285
|
const disconnectMutation = useMutation({
|
|
272
286
|
mutationFn: () => faireApi.disconnect(),
|
|
273
287
|
onSuccess: () => {
|
|
@@ -363,15 +377,16 @@ const FaireSettingsPage = () => {
|
|
|
363
377
|
children: "Disconnect"
|
|
364
378
|
}
|
|
365
379
|
)
|
|
366
|
-
] }) : /* @__PURE__ */
|
|
367
|
-
Button,
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
children: "Connect
|
|
373
|
-
|
|
374
|
-
|
|
380
|
+
] }) : /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
381
|
+
/* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { size: "small", isLoading: connectMutation.isPending, children: [
|
|
382
|
+
"Connect Faire",
|
|
383
|
+
/* @__PURE__ */ jsx(ChevronDownMini, {})
|
|
384
|
+
] }) }),
|
|
385
|
+
/* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
|
|
386
|
+
/* @__PURE__ */ jsx(DropdownMenu.Item, { onClick: () => connectMutation.mutate(), children: "Connect with OAuth" }),
|
|
387
|
+
/* @__PURE__ */ jsx(DropdownMenu.Item, { onClick: () => setApiKeyOpen(true), children: "Connect with API key (private)" })
|
|
388
|
+
] })
|
|
389
|
+
] })
|
|
375
390
|
] }),
|
|
376
391
|
connected && (status == null ? void 0 : status.account) && /* @__PURE__ */ jsxs("div", { className: "px-6 py-4 grid grid-cols-4 gap-4", children: [
|
|
377
392
|
/* @__PURE__ */ jsx(InfoField, { label: "Brand", value: status.account.brand_name }),
|
|
@@ -409,6 +424,46 @@ const FaireSettingsPage = () => {
|
|
|
409
424
|
/* @__PURE__ */ jsx(DataTable.Table, {}),
|
|
410
425
|
/* @__PURE__ */ jsx(DataTable.Pagination, {})
|
|
411
426
|
] }) }),
|
|
427
|
+
/* @__PURE__ */ jsx(Drawer, { open: apiKeyOpen, onOpenChange: setApiKeyOpen, children: /* @__PURE__ */ jsxs(Drawer.Content, { children: [
|
|
428
|
+
/* @__PURE__ */ jsx(Drawer.Header, { children: /* @__PURE__ */ jsx(Drawer.Title, { children: "Connect with API key" }) }),
|
|
429
|
+
/* @__PURE__ */ jsxs(Drawer.Body, { className: "flex flex-col gap-y-3", children: [
|
|
430
|
+
/* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", size: "small", children: "For private / unpublished Faire integrations, paste the API key your Faire brand issued for this app. This connects without OAuth." }),
|
|
431
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-1", children: [
|
|
432
|
+
/* @__PURE__ */ jsx(Label, { size: "small", children: "Faire API key" }),
|
|
433
|
+
/* @__PURE__ */ jsx(
|
|
434
|
+
Input,
|
|
435
|
+
{
|
|
436
|
+
type: "password",
|
|
437
|
+
placeholder: "Paste the Faire API key…",
|
|
438
|
+
value: apiKey,
|
|
439
|
+
onChange: (e) => setApiKey(e.target.value),
|
|
440
|
+
autoComplete: "off"
|
|
441
|
+
}
|
|
442
|
+
)
|
|
443
|
+
] })
|
|
444
|
+
] }),
|
|
445
|
+
/* @__PURE__ */ jsxs(Drawer.Footer, { children: [
|
|
446
|
+
/* @__PURE__ */ jsx(
|
|
447
|
+
Button,
|
|
448
|
+
{
|
|
449
|
+
variant: "secondary",
|
|
450
|
+
size: "small",
|
|
451
|
+
onClick: () => setApiKeyOpen(false),
|
|
452
|
+
children: "Cancel"
|
|
453
|
+
}
|
|
454
|
+
),
|
|
455
|
+
/* @__PURE__ */ jsx(
|
|
456
|
+
Button,
|
|
457
|
+
{
|
|
458
|
+
size: "small",
|
|
459
|
+
onClick: () => apiKeyMutation.mutate(),
|
|
460
|
+
isLoading: apiKeyMutation.isPending,
|
|
461
|
+
disabled: !apiKey.trim(),
|
|
462
|
+
children: "Connect"
|
|
463
|
+
}
|
|
464
|
+
)
|
|
465
|
+
] })
|
|
466
|
+
] }) }),
|
|
412
467
|
/* @__PURE__ */ jsx(Toaster, {})
|
|
413
468
|
] });
|
|
414
469
|
};
|
|
@@ -423,124 +478,6 @@ const config = defineRouteConfig({
|
|
|
423
478
|
const handle$3 = {
|
|
424
479
|
breadcrumb: () => "Faire Sync"
|
|
425
480
|
};
|
|
426
|
-
const STATUS_COLORS = {
|
|
427
|
-
success: "green",
|
|
428
|
-
failed: "red",
|
|
429
|
-
draft: "orange",
|
|
430
|
-
pending: "grey",
|
|
431
|
-
syncing: "grey"
|
|
432
|
-
};
|
|
433
|
-
const FaireSyncDetailPage = () => {
|
|
434
|
-
const { id } = useParams();
|
|
435
|
-
const navigate = useNavigate();
|
|
436
|
-
const [record, setRecord] = useState(null);
|
|
437
|
-
const [loading, setLoading] = useState(true);
|
|
438
|
-
const [retrying, setRetrying] = useState(false);
|
|
439
|
-
const [error, setError] = useState(null);
|
|
440
|
-
useEffect(() => {
|
|
441
|
-
if (!id) return;
|
|
442
|
-
setLoading(true);
|
|
443
|
-
faireApi.getSync(id).then((res) => {
|
|
444
|
-
setRecord(res.sync || res);
|
|
445
|
-
}).catch((err) => setError(err.message || "Failed to load sync record")).finally(() => setLoading(false));
|
|
446
|
-
}, [id]);
|
|
447
|
-
const handleRetry = async () => {
|
|
448
|
-
if (!record) return;
|
|
449
|
-
setRetrying(true);
|
|
450
|
-
setError(null);
|
|
451
|
-
try {
|
|
452
|
-
await faireApi.retrySync(record.id);
|
|
453
|
-
const updated = await faireApi.getSync(record.id).catch(() => null);
|
|
454
|
-
if (updated) setRecord(updated.sync || updated);
|
|
455
|
-
} catch (err) {
|
|
456
|
-
setError(err.message || "Retry failed");
|
|
457
|
-
} finally {
|
|
458
|
-
setRetrying(false);
|
|
459
|
-
}
|
|
460
|
-
};
|
|
461
|
-
if (loading) {
|
|
462
|
-
return /* @__PURE__ */ jsx(Container, { className: "p-6", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-12 rounded-md" }) });
|
|
463
|
-
}
|
|
464
|
-
if (!record) {
|
|
465
|
-
return /* @__PURE__ */ jsxs(Container, { className: "p-6 flex flex-col gap-4", children: [
|
|
466
|
-
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Sync record not found" }),
|
|
467
|
-
/* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", onClick: () => navigate("/settings/faire"), children: "Back to Faire settings" })
|
|
468
|
-
] });
|
|
469
|
-
}
|
|
470
|
-
const warnings = record.error_message ? record.error_message.split(" | ") : [];
|
|
471
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
472
|
-
error && /* @__PURE__ */ jsx(Container, { className: "p-4", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-tag-red-text", children: error }) }),
|
|
473
|
-
/* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
|
|
474
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
|
|
475
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
476
|
-
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Sync record" }),
|
|
477
|
-
/* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle font-mono text-xs", children: record.id })
|
|
478
|
-
] }),
|
|
479
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
480
|
-
/* @__PURE__ */ jsx(StatusBadge, { color: STATUS_COLORS[record.status] || "grey", children: record.status }),
|
|
481
|
-
/* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
482
|
-
/* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(IconButton, { size: "small", variant: "transparent", disabled: retrying, children: /* @__PURE__ */ jsx(EllipsisHorizontal, {}) }) }),
|
|
483
|
-
/* @__PURE__ */ jsxs(DropdownMenu.Content, { align: "end", children: [
|
|
484
|
-
/* @__PURE__ */ jsxs(
|
|
485
|
-
DropdownMenu.Item,
|
|
486
|
-
{
|
|
487
|
-
className: "gap-x-2",
|
|
488
|
-
onClick: handleRetry,
|
|
489
|
-
disabled: retrying,
|
|
490
|
-
children: [
|
|
491
|
-
/* @__PURE__ */ jsx(ArrowPath, { className: "text-ui-fg-subtle" }),
|
|
492
|
-
retrying ? "Re-syncing…" : "Re-sync product"
|
|
493
|
-
]
|
|
494
|
-
}
|
|
495
|
-
),
|
|
496
|
-
record.product_url && /* @__PURE__ */ jsxs(
|
|
497
|
-
DropdownMenu.Item,
|
|
498
|
-
{
|
|
499
|
-
className: "gap-x-2",
|
|
500
|
-
onClick: () => window.open(record.product_url, "_blank"),
|
|
501
|
-
children: [
|
|
502
|
-
/* @__PURE__ */ jsx(ArrowUpRightOnBox, { className: "text-ui-fg-subtle" }),
|
|
503
|
-
"Open on Faire"
|
|
504
|
-
]
|
|
505
|
-
}
|
|
506
|
-
)
|
|
507
|
-
] })
|
|
508
|
-
] })
|
|
509
|
-
] })
|
|
510
|
-
] }),
|
|
511
|
-
/* @__PURE__ */ jsxs("div", { className: "px-6 py-4 grid grid-cols-2 gap-4", children: [
|
|
512
|
-
/* @__PURE__ */ jsx(Detail, { label: "Product", value: record.product_id, mono: true }),
|
|
513
|
-
/* @__PURE__ */ jsx(Detail, { label: "Action", value: record.action }),
|
|
514
|
-
/* @__PURE__ */ jsx(Detail, { label: "Faire product token", value: record.product_token || "—", mono: true }),
|
|
515
|
-
/* @__PURE__ */ jsx(Detail, { label: "State", value: record.product_state || "—" }),
|
|
516
|
-
/* @__PURE__ */ jsx(Detail, { label: "Published", value: record.published ? "Yes" : "No" }),
|
|
517
|
-
/* @__PURE__ */ jsx(
|
|
518
|
-
Detail,
|
|
519
|
-
{
|
|
520
|
-
label: "Synced at",
|
|
521
|
-
value: record.synced_at ? new Date(record.synced_at).toLocaleString() : "—"
|
|
522
|
-
}
|
|
523
|
-
)
|
|
524
|
-
] })
|
|
525
|
-
] }),
|
|
526
|
-
warnings.length > 0 && /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
|
|
527
|
-
/* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Issues" }) }),
|
|
528
|
-
/* @__PURE__ */ jsx("div", { className: "px-6 py-4 flex flex-col gap-2", children: warnings.map((w, i) => /* @__PURE__ */ jsx(Text, { className: "text-ui-tag-red-text text-sm", children: w }, i)) })
|
|
529
|
-
] }),
|
|
530
|
-
/* @__PURE__ */ jsx(Toaster, {})
|
|
531
|
-
] });
|
|
532
|
-
};
|
|
533
|
-
const Detail = ({
|
|
534
|
-
label,
|
|
535
|
-
value,
|
|
536
|
-
mono
|
|
537
|
-
}) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
538
|
-
/* @__PURE__ */ jsx(Label, { children: label }),
|
|
539
|
-
/* @__PURE__ */ jsx(Text, { className: mono ? "font-mono text-xs" : "", children: value })
|
|
540
|
-
] });
|
|
541
|
-
const handle$2 = {
|
|
542
|
-
breadcrumb: () => "Sync record"
|
|
543
|
-
};
|
|
544
481
|
const Root = ({ prev = "..", children }) => {
|
|
545
482
|
const navigate = useNavigate();
|
|
546
483
|
const [open, setOpen] = useState(false);
|
|
@@ -837,9 +774,122 @@ const FaireBulkPage = () => {
|
|
|
837
774
|
/* @__PURE__ */ jsx(Toaster, {})
|
|
838
775
|
] });
|
|
839
776
|
};
|
|
840
|
-
const handle$
|
|
777
|
+
const handle$2 = {
|
|
841
778
|
breadcrumb: () => "Bulk sync"
|
|
842
779
|
};
|
|
780
|
+
const PARENT$1 = "/settings/faire";
|
|
781
|
+
const STATUS_COLORS = {
|
|
782
|
+
success: "green",
|
|
783
|
+
failed: "red",
|
|
784
|
+
draft: "orange",
|
|
785
|
+
pending: "grey",
|
|
786
|
+
syncing: "grey"
|
|
787
|
+
};
|
|
788
|
+
const FaireSyncDetailPage = () => {
|
|
789
|
+
const { id } = useParams();
|
|
790
|
+
const navigate = useNavigate();
|
|
791
|
+
const [record, setRecord] = useState(null);
|
|
792
|
+
const [loading, setLoading] = useState(true);
|
|
793
|
+
const [retrying, setRetrying] = useState(false);
|
|
794
|
+
const [error, setError] = useState(null);
|
|
795
|
+
useEffect(() => {
|
|
796
|
+
if (!id) return;
|
|
797
|
+
setLoading(true);
|
|
798
|
+
faireApi.getSync(id).then((res) => {
|
|
799
|
+
setRecord(res.sync || res);
|
|
800
|
+
}).catch((err) => setError(err.message || "Failed to load sync record")).finally(() => setLoading(false));
|
|
801
|
+
}, [id]);
|
|
802
|
+
const handleRetry = async () => {
|
|
803
|
+
if (!record) return;
|
|
804
|
+
setRetrying(true);
|
|
805
|
+
setError(null);
|
|
806
|
+
try {
|
|
807
|
+
await faireApi.retrySync(record.id);
|
|
808
|
+
const updated = await faireApi.getSync(record.id).catch(() => null);
|
|
809
|
+
if (updated) setRecord(updated.sync || updated);
|
|
810
|
+
} catch (err) {
|
|
811
|
+
setError(err.message || "Retry failed");
|
|
812
|
+
} finally {
|
|
813
|
+
setRetrying(false);
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
const warnings = (record == null ? void 0 : record.error_message) ? record.error_message.split(" | ") : [];
|
|
817
|
+
return /* @__PURE__ */ jsxs(RouteFocusModal, { prev: PARENT$1, children: [
|
|
818
|
+
/* @__PURE__ */ jsxs(RouteFocusModal.Header, { children: [
|
|
819
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
820
|
+
/* @__PURE__ */ jsx(Heading, { level: "h1", children: "Sync record" }),
|
|
821
|
+
record && /* @__PURE__ */ jsx(StatusBadge, { color: STATUS_COLORS[record.status] || "grey", children: record.status })
|
|
822
|
+
] }),
|
|
823
|
+
record && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
824
|
+
/* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(IconButton, { size: "small", variant: "transparent", disabled: retrying, children: /* @__PURE__ */ jsx(EllipsisHorizontal, {}) }) }),
|
|
825
|
+
/* @__PURE__ */ jsxs(DropdownMenu.Content, { align: "end", children: [
|
|
826
|
+
/* @__PURE__ */ jsxs(
|
|
827
|
+
DropdownMenu.Item,
|
|
828
|
+
{
|
|
829
|
+
className: "gap-x-2",
|
|
830
|
+
onClick: handleRetry,
|
|
831
|
+
disabled: retrying,
|
|
832
|
+
children: [
|
|
833
|
+
/* @__PURE__ */ jsx(ArrowPath, { className: "text-ui-fg-subtle" }),
|
|
834
|
+
retrying ? "Re-syncing…" : "Re-sync product"
|
|
835
|
+
]
|
|
836
|
+
}
|
|
837
|
+
),
|
|
838
|
+
record.product_url && /* @__PURE__ */ jsxs(
|
|
839
|
+
DropdownMenu.Item,
|
|
840
|
+
{
|
|
841
|
+
className: "gap-x-2",
|
|
842
|
+
onClick: () => window.open(record.product_url, "_blank"),
|
|
843
|
+
children: [
|
|
844
|
+
/* @__PURE__ */ jsx(ArrowUpRightOnBox, { className: "text-ui-fg-subtle" }),
|
|
845
|
+
"Open on Faire"
|
|
846
|
+
]
|
|
847
|
+
}
|
|
848
|
+
)
|
|
849
|
+
] })
|
|
850
|
+
] }) })
|
|
851
|
+
] }),
|
|
852
|
+
/* @__PURE__ */ jsxs(RouteFocusModal.Body, { className: "flex flex-col gap-4 overflow-y-auto p-6", children: [
|
|
853
|
+
error && /* @__PURE__ */ jsx(Text, { className: "text-ui-tag-red-text", children: error }),
|
|
854
|
+
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: [
|
|
855
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", children: "Sync record not found" }),
|
|
856
|
+
/* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", onClick: () => navigate(PARENT$1), children: "Back to Faire settings" })
|
|
857
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
858
|
+
/* @__PURE__ */ jsxs("div", { className: "border-ui-border-base grid grid-cols-2 gap-4 rounded-lg border p-4", children: [
|
|
859
|
+
/* @__PURE__ */ jsx(Detail, { label: "Record id", value: record.id, mono: true }),
|
|
860
|
+
/* @__PURE__ */ jsx(Detail, { label: "Product", value: record.product_id, mono: true }),
|
|
861
|
+
/* @__PURE__ */ jsx(Detail, { label: "Action", value: record.action }),
|
|
862
|
+
/* @__PURE__ */ jsx(Detail, { label: "Faire product token", value: record.product_token || "—", mono: true }),
|
|
863
|
+
/* @__PURE__ */ jsx(Detail, { label: "State", value: record.product_state || "—" }),
|
|
864
|
+
/* @__PURE__ */ jsx(Detail, { label: "Published", value: record.published ? "Yes" : "No" }),
|
|
865
|
+
/* @__PURE__ */ jsx(
|
|
866
|
+
Detail,
|
|
867
|
+
{
|
|
868
|
+
label: "Synced at",
|
|
869
|
+
value: record.synced_at ? new Date(record.synced_at).toLocaleString() : "—"
|
|
870
|
+
}
|
|
871
|
+
)
|
|
872
|
+
] }),
|
|
873
|
+
warnings.length > 0 && /* @__PURE__ */ jsxs("div", { className: "border-ui-border-base flex flex-col gap-2 rounded-lg border p-4", children: [
|
|
874
|
+
/* @__PURE__ */ jsx(Heading, { level: "h2", children: "Issues" }),
|
|
875
|
+
warnings.map((w, i) => /* @__PURE__ */ jsx(Text, { className: "text-ui-tag-red-text text-sm", children: w }, i))
|
|
876
|
+
] })
|
|
877
|
+
] })
|
|
878
|
+
] }),
|
|
879
|
+
/* @__PURE__ */ jsx(Toaster, {})
|
|
880
|
+
] });
|
|
881
|
+
};
|
|
882
|
+
const Detail = ({
|
|
883
|
+
label,
|
|
884
|
+
value,
|
|
885
|
+
mono
|
|
886
|
+
}) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
887
|
+
/* @__PURE__ */ jsx(Label, { children: label }),
|
|
888
|
+
/* @__PURE__ */ jsx(Text, { className: mono ? "font-mono text-xs" : "", children: value })
|
|
889
|
+
] });
|
|
890
|
+
const handle$1 = {
|
|
891
|
+
breadcrumb: () => "Sync record"
|
|
892
|
+
};
|
|
843
893
|
const STATUS_KEY = ["faire", "status"];
|
|
844
894
|
const PARENT = "/settings/faire";
|
|
845
895
|
const NONE = "__none__";
|
|
@@ -1107,13 +1157,13 @@ const routeModule = {
|
|
|
1107
1157
|
handle: handle$3
|
|
1108
1158
|
},
|
|
1109
1159
|
{
|
|
1110
|
-
Component:
|
|
1111
|
-
path: "/settings/faire
|
|
1160
|
+
Component: FaireBulkPage,
|
|
1161
|
+
path: "/settings/faire/bulk",
|
|
1112
1162
|
handle: handle$2
|
|
1113
1163
|
},
|
|
1114
1164
|
{
|
|
1115
|
-
Component:
|
|
1116
|
-
path: "/settings/faire
|
|
1165
|
+
Component: FaireSyncDetailPage,
|
|
1166
|
+
path: "/settings/faire/:id",
|
|
1117
1167
|
handle: handle$1
|
|
1118
1168
|
},
|
|
1119
1169
|
{
|