@burdenoff/microfe-coolandlovely 2026.1028.3 → 2026.1029.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ReturnRequests.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/components/ReturnRequests.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AASH,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAoB,MAAM,UAAU,CAAC;AAmB1E,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,oBAAoB,CAAC,EAAE,GAAG,SAAa,WAG/F;AAED,yFAAyF;AACzF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,OAAO,CAM5F;AAuGD,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,QAAQ,CAAA;CAAE,sCA0D1D;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,aAAa,CAAA;CAAE,sCAoHrE"}
1
+ {"version":3,"file":"ReturnRequests.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/components/ReturnRequests.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AASH,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAoB,MAAM,UAAU,CAAC;AAmB1E,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,oBAAoB,CAAC,EAAE,GAAG,SAAa,WAG/F;AAED,yFAAyF;AACzF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,OAAO,CAM5F;AA2GD,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,QAAQ,CAAA;CAAE,sCA0D1D;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,aAAa,CAAA;CAAE,sCAoHrE"}
@@ -33,7 +33,7 @@ function C({ request: t }) {
33
33
  "data-testid": "return-decision-note",
34
34
  children: r("coolandlovely.returns.brandNote", "Brand’s note: {{note}}", { note: t.decisionNote })
35
35
  }),
36
- t.status !== "REQUESTED" && t.decidedAt && /* @__PURE__ */ f("p", { children: t.status === "APPROVED" ? r("coolandlovely.returns.approvedOn", "Approved {{date}}. See the refund above.", { date: n(t.decidedAt) }) : r("coolandlovely.returns.declinedOn", "Declined {{date}}.", { date: n(t.decidedAt) }) })
36
+ t.status !== "REQUESTED" && t.decidedAt && /* @__PURE__ */ f("p", { children: t.status === "APPROVED" ? r("coolandlovely.returns.approvedOn", "Approved {{date}}. The pieces were refunded.", { date: n(t.decidedAt) }) : r("coolandlovely.returns.declinedOn", "Declined {{date}}.", { date: n(t.decidedAt) }) })
37
37
  ]
38
38
  });
39
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ReturnRequests.js","names":[],"sources":["../../../src/coolandlovely/components/ReturnRequests.tsx"],"sourcesContent":["/**\n * Shopper return requests (BOFF-9900)\n * @module coolandlovely/components\n *\n * `OrderReturns` sits on the shopper's order detail: for each brand in a paid order the shopper\n * can ask for a return (`cooRequestReturn`) inside the return window, and sees the request and\n * the brand's decision once it exists. `ReturnRequestPanel` sits on the brand's order detail: the\n * brand approves the request, which refunds its pieces through the brand refund\n * (`cooApproveReturnRequest`), or declines it with a note (`cooDeclineReturnRequest`).\n */\n\nimport { useState } from 'react';\nimport { CheckCircle2, Loader2, Undo2, XCircle } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\n\nimport { useTr } from '../hooks';\nimport { useApproveReturnRequest, useDeclineReturnRequest } from '../hooks/useBrandOrdersApi';\nimport { useRequestReturn } from '../hooks/useCommerceApi';\nimport type { CooBrandOrder, CooOrder, CooReturnRequest } from '../types';\nimport { formatDate } from '../utils/formatters';\nimport { TextAreaField } from './Field';\nimport { StatusBadge } from './StatusBadge';\n\nconst MIN_TEXT = 3;\nconst MAX_TEXT = 1000;\nconst RETURNABLE_ORDER_STATUSES = ['PAID', 'PARTIALLY_REFUNDED'];\n\nconst isValidText = (value: string): boolean => {\n const trimmed = value.trim();\n return trimmed.length >= MIN_TEXT && trimmed.length <= MAX_TEXT;\n};\n\nconst primaryButton =\n 'inline-flex items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-semibold text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-50';\nconst secondaryButton =\n 'inline-flex items-center justify-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:opacity-50';\n\n/** Whether the return window of a paid order is still open. */\nexport function isReturnWindowOpen(order: Pick<CooOrder, 'returnWindowEndsAt'>, now = Date.now()) {\n if (!order.returnWindowEndsAt) return false;\n return new Date(order.returnWindowEndsAt).getTime() > now;\n}\n\n/** Whether the shopper can still ask the brand to take back its pieces of this order. */\nexport function canRequestReturn(order: CooOrder, brandId: string, now = Date.now()): boolean {\n if (!RETURNABLE_ORDER_STATUSES.includes(order.status)) return false;\n if (order.returnRequests?.some((request) => request.brandId === brandId)) return false;\n const refund = order.refunds?.find((entry) => entry.brandId === brandId);\n if (refund && (refund.status === 'COMPLETED' || refund.status === 'PENDING')) return false;\n return isReturnWindowOpen(order, now);\n}\n\nfunction RequestDetails({ request }: { request: CooReturnRequest }) {\n const tr = useTr();\n return (\n <div className=\"space-y-1 text-xs text-text-secondary\">\n <p>\n {tr('coolandlovely.returns.reasonShown', 'Reason: {{reason}}', { reason: request.reason })}\n </p>\n {request.status === 'REQUESTED' && (\n <p>\n {tr(\n 'coolandlovely.returns.awaitingBrand',\n 'Asked {{date}}. The brand will approve or decline it.',\n { date: formatDate(request.createdAt) }\n )}\n </p>\n )}\n {request.status !== 'REQUESTED' && request.decisionNote && (\n <p data-testid=\"return-decision-note\">\n {tr('coolandlovely.returns.brandNote', 'Brand’s note: {{note}}', {\n note: request.decisionNote,\n })}\n </p>\n )}\n {request.status !== 'REQUESTED' && request.decidedAt && (\n <p>\n {request.status === 'APPROVED'\n ? tr('coolandlovely.returns.approvedOn', 'Approved {{date}}. See the refund above.', {\n date: formatDate(request.decidedAt),\n })\n : tr('coolandlovely.returns.declinedOn', 'Declined {{date}}.', {\n date: formatDate(request.decidedAt),\n })}\n </p>\n )}\n </div>\n );\n}\n\nfunction RequestReturnForm({ orderId, brandId }: { orderId: string; brandId: string }) {\n const tr = useTr();\n const request = useRequestReturn();\n const [open, setOpen] = useState(false);\n const [reason, setReason] = useState('');\n\n if (!open) {\n return (\n <button\n type=\"button\"\n onClick={() => setOpen(true)}\n className={secondaryButton}\n data-testid=\"order-return-open\"\n >\n <Undo2 className=\"h-4 w-4\" />\n {tr('coolandlovely.returns.request', 'Request a return')}\n </button>\n );\n }\n return (\n <div className=\"space-y-2\">\n <TextAreaField\n id={`coo-return-reason-${brandId}`}\n label={tr('coolandlovely.returns.reason', 'Why are you returning these pieces?')}\n hint={tr('coolandlovely.returns.reasonHint', 'Shown to the brand.')}\n value={reason}\n onChange={setReason}\n rows={3}\n />\n {request.error && (\n <p className=\"text-sm text-status-error-text\" role=\"alert\">\n {request.error.message}\n </p>\n )}\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n disabled={request.isPending || !isValidText(reason)}\n onClick={() =>\n request.mutate(\n { orderId, brandId, reason: reason.trim() },\n { onSuccess: () => setOpen(false) }\n )\n }\n className={primaryButton}\n data-testid=\"order-return-submit\"\n >\n {request.isPending && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n {tr('coolandlovely.returns.send', 'Send return request')}\n </button>\n <button\n type=\"button\"\n disabled={request.isPending}\n onClick={() => setOpen(false)}\n className={secondaryButton}\n >\n {tr('coolandlovely.common.cancel', 'Cancel')}\n </button>\n </div>\n </div>\n );\n}\n\n/** The shopper's returns card on a paid order: one row per brand in the order. */\nexport function OrderReturns({ order }: { order: CooOrder }) {\n const tr = useTr();\n const paid = order.status === 'PAID' || order.status === 'PARTIALLY_REFUNDED';\n const requests = order.returnRequests ?? [];\n if (!paid && requests.length === 0) return null;\n\n const brandIds = [...new Set(order.items.map((item) => item.brandId))];\n const brandName = (brandId: string): string =>\n requests.find((request) => request.brandId === brandId)?.brandName ??\n order.fulfilments?.find((fulfilment) => fulfilment.brandId === brandId)?.brandName ??\n order.refunds?.find((refund) => refund.brandId === brandId)?.brandName ??\n tr('coolandlovely.orders.brand', 'Brand');\n const windowOpen = isReturnWindowOpen(order);\n\n return (\n <GlassCard treatment=\"plain\" className=\"space-y-4 p-4\" data-testid=\"order-returns\">\n <div className=\"space-y-1\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">\n {tr('coolandlovely.returns.title', 'Returns')}\n </p>\n {paid && order.returnWindowEndsAt && (\n <p className=\"text-xs text-text-secondary\" data-testid=\"order-return-window\">\n {windowOpen\n ? tr(\n 'coolandlovely.returns.windowOpen',\n 'You can ask a brand to take back its pieces until {{date}}.',\n { date: formatDate(order.returnWindowEndsAt) }\n )\n : tr('coolandlovely.returns.windowClosed', 'The return window closed on {{date}}.', {\n date: formatDate(order.returnWindowEndsAt),\n })}\n </p>\n )}\n </div>\n {brandIds.map((brandId) => {\n const request = requests.find((entry) => entry.brandId === brandId);\n const eligible = canRequestReturn(order, brandId);\n if (!request && !eligible) return null;\n return (\n <div key={brandId} className=\"space-y-2\" data-testid=\"order-return\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"text-sm font-medium text-text-primary\">{brandName(brandId)}</span>\n {request && (\n <span data-testid=\"order-return-status\">\n <StatusBadge status={request.status} />\n </span>\n )}\n </div>\n {request ? (\n <RequestDetails request={request} />\n ) : (\n <RequestReturnForm orderId={order.id} brandId={brandId} />\n )}\n </div>\n );\n })}\n </GlassCard>\n );\n}\n\n/** The brand's view of the shopper's return request, with approve and decline. */\nexport function ReturnRequestPanel({ order }: { order: CooBrandOrder }) {\n const tr = useTr();\n const approve = useApproveReturnRequest();\n const decline = useDeclineReturnRequest();\n const [mode, setMode] = useState<'idle' | 'approve' | 'decline'>('idle');\n const [note, setNote] = useState('');\n const request = order.returnRequest;\n if (!request) return null;\n\n const busy = approve.isPending || decline.isPending;\n const error = approve.error ?? decline.error;\n const noteOk = mode === 'approve' ? note.trim() === '' || isValidText(note) : isValidText(note);\n const reset = () => {\n setMode('idle');\n setNote('');\n };\n const submit = () => {\n const input = { brandId: order.brandId, orderId: order.id };\n if (mode === 'approve') {\n approve.mutate({ ...input, note: note.trim() || null }, { onSuccess: reset });\n } else {\n decline.mutate({ ...input, note: note.trim() }, { onSuccess: reset });\n }\n };\n\n return (\n <div className=\"space-y-3 border-t border-border-seam pt-4\" data-testid=\"brand-return-panel\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">\n {tr('coolandlovely.returns.brandTitle', 'Return request')}\n </span>\n <span data-testid=\"brand-return-status\">\n <StatusBadge status={request.status} />\n </span>\n </div>\n <RequestDetails request={request} />\n\n {request.status === 'REQUESTED' &&\n (mode === 'idle' ? (\n <div className=\"grid grid-cols-2 gap-2\">\n <button\n type=\"button\"\n onClick={() => setMode('approve')}\n className={primaryButton}\n data-testid=\"brand-return-approve-open\"\n >\n <CheckCircle2 className=\"h-4 w-4\" />\n {tr('coolandlovely.returns.approve', 'Approve')}\n </button>\n <button\n type=\"button\"\n onClick={() => setMode('decline')}\n className={secondaryButton}\n data-testid=\"brand-return-decline-open\"\n >\n <XCircle className=\"h-4 w-4\" />\n {tr('coolandlovely.returns.decline', 'Decline')}\n </button>\n </div>\n ) : (\n <div className=\"space-y-3\">\n <p className=\"text-sm text-text-secondary\">\n {mode === 'approve'\n ? tr(\n 'coolandlovely.returns.approveExplain',\n 'Approving refunds all of your pieces in this order to the shopper, with their share of tax, and reverses the creator commissions on them. This cannot be undone.'\n )\n : tr(\n 'coolandlovely.returns.declineExplain',\n 'The shopper sees your note. A declined return cannot be reopened.'\n )}\n </p>\n <TextAreaField\n id=\"coo-return-decision-note\"\n label={\n mode === 'approve'\n ? tr('coolandlovely.returns.approveNote', 'Note to the shopper (optional)')\n : tr('coolandlovely.returns.declineNote', 'Why are you declining?')\n }\n value={note}\n onChange={setNote}\n rows={3}\n />\n {error && (\n <p className=\"text-sm text-status-error-text\" role=\"alert\">\n {error.message}\n </p>\n )}\n <button\n type=\"button\"\n disabled={busy || !noteOk}\n onClick={submit}\n className={\n mode === 'approve'\n ? `${primaryButton} w-full`\n : `${secondaryButton} w-full text-status-error-text`\n }\n data-testid=\"brand-return-confirm\"\n >\n {busy && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n {mode === 'approve'\n ? tr('coolandlovely.returns.approveConfirm', 'Approve and refund')\n : tr('coolandlovely.returns.declineConfirm', 'Decline return')}\n </button>\n <button\n type=\"button\"\n disabled={busy}\n onClick={reset}\n className={`${secondaryButton} w-full`}\n >\n {tr('coolandlovely.common.cancel', 'Cancel')}\n </button>\n </div>\n ))}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ReturnRequests.js","names":[],"sources":["../../../src/coolandlovely/components/ReturnRequests.tsx"],"sourcesContent":["/**\n * Shopper return requests (BOFF-9900)\n * @module coolandlovely/components\n *\n * `OrderReturns` sits on the shopper's order detail: for each brand in a paid order the shopper\n * can ask for a return (`cooRequestReturn`) inside the return window, and sees the request and\n * the brand's decision once it exists. `ReturnRequestPanel` sits on the brand's order detail: the\n * brand approves the request, which refunds its pieces through the brand refund\n * (`cooApproveReturnRequest`), or declines it with a note (`cooDeclineReturnRequest`).\n */\n\nimport { useState } from 'react';\nimport { CheckCircle2, Loader2, Undo2, XCircle } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\n\nimport { useTr } from '../hooks';\nimport { useApproveReturnRequest, useDeclineReturnRequest } from '../hooks/useBrandOrdersApi';\nimport { useRequestReturn } from '../hooks/useCommerceApi';\nimport type { CooBrandOrder, CooOrder, CooReturnRequest } from '../types';\nimport { formatDate } from '../utils/formatters';\nimport { TextAreaField } from './Field';\nimport { StatusBadge } from './StatusBadge';\n\nconst MIN_TEXT = 3;\nconst MAX_TEXT = 1000;\nconst RETURNABLE_ORDER_STATUSES = ['PAID', 'PARTIALLY_REFUNDED'];\n\nconst isValidText = (value: string): boolean => {\n const trimmed = value.trim();\n return trimmed.length >= MIN_TEXT && trimmed.length <= MAX_TEXT;\n};\n\nconst primaryButton =\n 'inline-flex items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-semibold text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-50';\nconst secondaryButton =\n 'inline-flex items-center justify-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:opacity-50';\n\n/** Whether the return window of a paid order is still open. */\nexport function isReturnWindowOpen(order: Pick<CooOrder, 'returnWindowEndsAt'>, now = Date.now()) {\n if (!order.returnWindowEndsAt) return false;\n return new Date(order.returnWindowEndsAt).getTime() > now;\n}\n\n/** Whether the shopper can still ask the brand to take back its pieces of this order. */\nexport function canRequestReturn(order: CooOrder, brandId: string, now = Date.now()): boolean {\n if (!RETURNABLE_ORDER_STATUSES.includes(order.status)) return false;\n if (order.returnRequests?.some((request) => request.brandId === brandId)) return false;\n const refund = order.refunds?.find((entry) => entry.brandId === brandId);\n if (refund && (refund.status === 'COMPLETED' || refund.status === 'PENDING')) return false;\n return isReturnWindowOpen(order, now);\n}\n\nfunction RequestDetails({ request }: { request: CooReturnRequest }) {\n const tr = useTr();\n return (\n <div className=\"space-y-1 text-xs text-text-secondary\">\n <p>\n {tr('coolandlovely.returns.reasonShown', 'Reason: {{reason}}', { reason: request.reason })}\n </p>\n {request.status === 'REQUESTED' && (\n <p>\n {tr(\n 'coolandlovely.returns.awaitingBrand',\n 'Asked {{date}}. The brand will approve or decline it.',\n { date: formatDate(request.createdAt) }\n )}\n </p>\n )}\n {request.status !== 'REQUESTED' && request.decisionNote && (\n <p data-testid=\"return-decision-note\">\n {tr('coolandlovely.returns.brandNote', 'Brand’s note: {{note}}', {\n note: request.decisionNote,\n })}\n </p>\n )}\n {request.status !== 'REQUESTED' && request.decidedAt && (\n <p>\n {request.status === 'APPROVED'\n ? tr(\n 'coolandlovely.returns.approvedOn',\n 'Approved {{date}}. The pieces were refunded.',\n {\n date: formatDate(request.decidedAt),\n }\n )\n : tr('coolandlovely.returns.declinedOn', 'Declined {{date}}.', {\n date: formatDate(request.decidedAt),\n })}\n </p>\n )}\n </div>\n );\n}\n\nfunction RequestReturnForm({ orderId, brandId }: { orderId: string; brandId: string }) {\n const tr = useTr();\n const request = useRequestReturn();\n const [open, setOpen] = useState(false);\n const [reason, setReason] = useState('');\n\n if (!open) {\n return (\n <button\n type=\"button\"\n onClick={() => setOpen(true)}\n className={secondaryButton}\n data-testid=\"order-return-open\"\n >\n <Undo2 className=\"h-4 w-4\" />\n {tr('coolandlovely.returns.request', 'Request a return')}\n </button>\n );\n }\n return (\n <div className=\"space-y-2\">\n <TextAreaField\n id={`coo-return-reason-${brandId}`}\n label={tr('coolandlovely.returns.reason', 'Why are you returning these pieces?')}\n hint={tr('coolandlovely.returns.reasonHint', 'Shown to the brand.')}\n value={reason}\n onChange={setReason}\n rows={3}\n />\n {request.error && (\n <p className=\"text-sm text-status-error-text\" role=\"alert\">\n {request.error.message}\n </p>\n )}\n <div className=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n disabled={request.isPending || !isValidText(reason)}\n onClick={() =>\n request.mutate(\n { orderId, brandId, reason: reason.trim() },\n { onSuccess: () => setOpen(false) }\n )\n }\n className={primaryButton}\n data-testid=\"order-return-submit\"\n >\n {request.isPending && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n {tr('coolandlovely.returns.send', 'Send return request')}\n </button>\n <button\n type=\"button\"\n disabled={request.isPending}\n onClick={() => setOpen(false)}\n className={secondaryButton}\n >\n {tr('coolandlovely.common.cancel', 'Cancel')}\n </button>\n </div>\n </div>\n );\n}\n\n/** The shopper's returns card on a paid order: one row per brand in the order. */\nexport function OrderReturns({ order }: { order: CooOrder }) {\n const tr = useTr();\n const paid = order.status === 'PAID' || order.status === 'PARTIALLY_REFUNDED';\n const requests = order.returnRequests ?? [];\n if (!paid && requests.length === 0) return null;\n\n const brandIds = [...new Set(order.items.map((item) => item.brandId))];\n const brandName = (brandId: string): string =>\n requests.find((request) => request.brandId === brandId)?.brandName ??\n order.fulfilments?.find((fulfilment) => fulfilment.brandId === brandId)?.brandName ??\n order.refunds?.find((refund) => refund.brandId === brandId)?.brandName ??\n tr('coolandlovely.orders.brand', 'Brand');\n const windowOpen = isReturnWindowOpen(order);\n\n return (\n <GlassCard treatment=\"plain\" className=\"space-y-4 p-4\" data-testid=\"order-returns\">\n <div className=\"space-y-1\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">\n {tr('coolandlovely.returns.title', 'Returns')}\n </p>\n {paid && order.returnWindowEndsAt && (\n <p className=\"text-xs text-text-secondary\" data-testid=\"order-return-window\">\n {windowOpen\n ? tr(\n 'coolandlovely.returns.windowOpen',\n 'You can ask a brand to take back its pieces until {{date}}.',\n { date: formatDate(order.returnWindowEndsAt) }\n )\n : tr('coolandlovely.returns.windowClosed', 'The return window closed on {{date}}.', {\n date: formatDate(order.returnWindowEndsAt),\n })}\n </p>\n )}\n </div>\n {brandIds.map((brandId) => {\n const request = requests.find((entry) => entry.brandId === brandId);\n const eligible = canRequestReturn(order, brandId);\n if (!request && !eligible) return null;\n return (\n <div key={brandId} className=\"space-y-2\" data-testid=\"order-return\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"text-sm font-medium text-text-primary\">{brandName(brandId)}</span>\n {request && (\n <span data-testid=\"order-return-status\">\n <StatusBadge status={request.status} />\n </span>\n )}\n </div>\n {request ? (\n <RequestDetails request={request} />\n ) : (\n <RequestReturnForm orderId={order.id} brandId={brandId} />\n )}\n </div>\n );\n })}\n </GlassCard>\n );\n}\n\n/** The brand's view of the shopper's return request, with approve and decline. */\nexport function ReturnRequestPanel({ order }: { order: CooBrandOrder }) {\n const tr = useTr();\n const approve = useApproveReturnRequest();\n const decline = useDeclineReturnRequest();\n const [mode, setMode] = useState<'idle' | 'approve' | 'decline'>('idle');\n const [note, setNote] = useState('');\n const request = order.returnRequest;\n if (!request) return null;\n\n const busy = approve.isPending || decline.isPending;\n const error = approve.error ?? decline.error;\n const noteOk = mode === 'approve' ? note.trim() === '' || isValidText(note) : isValidText(note);\n const reset = () => {\n setMode('idle');\n setNote('');\n };\n const submit = () => {\n const input = { brandId: order.brandId, orderId: order.id };\n if (mode === 'approve') {\n approve.mutate({ ...input, note: note.trim() || null }, { onSuccess: reset });\n } else {\n decline.mutate({ ...input, note: note.trim() }, { onSuccess: reset });\n }\n };\n\n return (\n <div className=\"space-y-3 border-t border-border-seam pt-4\" data-testid=\"brand-return-panel\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">\n {tr('coolandlovely.returns.brandTitle', 'Return request')}\n </span>\n <span data-testid=\"brand-return-status\">\n <StatusBadge status={request.status} />\n </span>\n </div>\n <RequestDetails request={request} />\n\n {request.status === 'REQUESTED' &&\n (mode === 'idle' ? (\n <div className=\"grid grid-cols-2 gap-2\">\n <button\n type=\"button\"\n onClick={() => setMode('approve')}\n className={primaryButton}\n data-testid=\"brand-return-approve-open\"\n >\n <CheckCircle2 className=\"h-4 w-4\" />\n {tr('coolandlovely.returns.approve', 'Approve')}\n </button>\n <button\n type=\"button\"\n onClick={() => setMode('decline')}\n className={secondaryButton}\n data-testid=\"brand-return-decline-open\"\n >\n <XCircle className=\"h-4 w-4\" />\n {tr('coolandlovely.returns.decline', 'Decline')}\n </button>\n </div>\n ) : (\n <div className=\"space-y-3\">\n <p className=\"text-sm text-text-secondary\">\n {mode === 'approve'\n ? tr(\n 'coolandlovely.returns.approveExplain',\n 'Approving refunds all of your pieces in this order to the shopper, with their share of tax, and reverses the creator commissions on them. This cannot be undone.'\n )\n : tr(\n 'coolandlovely.returns.declineExplain',\n 'The shopper sees your note. A declined return cannot be reopened.'\n )}\n </p>\n <TextAreaField\n id=\"coo-return-decision-note\"\n label={\n mode === 'approve'\n ? tr('coolandlovely.returns.approveNote', 'Note to the shopper (optional)')\n : tr('coolandlovely.returns.declineNote', 'Why are you declining?')\n }\n value={note}\n onChange={setNote}\n rows={3}\n />\n {error && (\n <p className=\"text-sm text-status-error-text\" role=\"alert\">\n {error.message}\n </p>\n )}\n <button\n type=\"button\"\n disabled={busy || !noteOk}\n onClick={submit}\n className={\n mode === 'approve'\n ? `${primaryButton} w-full`\n : `${secondaryButton} w-full text-status-error-text`\n }\n data-testid=\"brand-return-confirm\"\n >\n {busy && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n {mode === 'approve'\n ? tr('coolandlovely.returns.approveConfirm', 'Approve and refund')\n : tr('coolandlovely.returns.declineConfirm', 'Decline return')}\n </button>\n <button\n type=\"button\"\n disabled={busy}\n onClick={reset}\n className={`${secondaryButton} w-full`}\n >\n {tr('coolandlovely.common.cancel', 'Cancel')}\n </button>\n </div>\n ))}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { CooAddToCartInput, CooCart, CooCheckoutInput, CooCollaborationPaymentCheckout, CooCollaborationPayout, CooCollaborationPayoutConnection, CooCreatorEarningConnection, CooCreatorEarningsSummary, CooCreatorPayout, CooOrder, CooOrderCheckout, CooOrderConnection, CooOrderStatus, CooRequestReturnInput, CooReturnRequest } from '../types';
1
+ import { CooAddToCartInput, CooBuyStoreListedPieceInput, CooCart, CooCheckoutInput, CooCollaborationPaymentCheckout, CooCollaborationPayout, CooCollaborationPayoutConnection, CooCreatorEarningConnection, CooCreatorEarningsSummary, CooCreatorPayout, CooOrder, CooOrderCheckout, CooOrderConnection, CooOrderStatus, CooRequestReturnInput, CooReturnRequest, CooStoreListedPiece } from '../types';
2
2
 
3
3
  /** Per-brand fulfilment (BOFF-9636): shared by the shopper's order detail and the brand view. */
4
4
  export declare const FULFILMENT_FIELDS = "\n id orderId brandId brandName status refunded carrier trackingNumber trackingUrl note\n confirmedAt shippedAt deliveredAt updatedAt\n";
@@ -23,6 +23,13 @@ export declare const useCheckout: () => import('@tanstack/react-query').UseMutat
23
23
  export declare const useResumeOrderPayment: () => import('@tanstack/react-query').UseMutationResult<CooOrderCheckout, Error, string, unknown>;
24
24
  export declare const useSyncOrderPayment: () => import('@tanstack/react-query').UseMutationResult<CooOrder, Error, string, unknown>;
25
25
  export declare const useCancelOrder: () => import('@tanstack/react-query').UseMutationResult<CooOrder, Error, string, unknown>;
26
+ /**
27
+ * A piece listed in the Burdenoff store, readable from any workspace. Only fetched once the
28
+ * workspace's own catalogue has no such piece (the shopper followed a store listing here).
29
+ */
30
+ export declare const useStoreListedPiece: (id: string | undefined, enabled: boolean) => import('@tanstack/react-query').UseQueryResult<NoInfer<CooStoreListedPiece | null>, Error>;
31
+ /** Buy a store-listed piece directly: the order is created and its payment started. */
32
+ export declare const useBuyStoreListedPiece: () => import('@tanstack/react-query').UseMutationResult<CooOrderCheckout, Error, CooBuyStoreListedPieceInput, unknown>;
26
33
  /**
27
34
  * Ask a brand to take back its pieces of one of the caller's paid orders (BOFF-9900). The brand
28
35
  * approves (which refunds them) or declines; the order detail is refetched to show the request.
@@ -1 +1 @@
1
- {"version":3,"file":"useCommerceApi.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/hooks/useCommerceApi.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EACV,iBAAiB,EACjB,OAAO,EACP,gBAAgB,EAChB,+BAA+B,EAC/B,sBAAsB,EACtB,gCAAgC,EAChC,2BAA2B,EAC3B,yBAAyB,EACzB,gBAAgB,EAChB,QAAQ,EACR,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,UAAU,CAAC;AAwBlB,iGAAiG;AACjG,eAAO,MAAM,iBAAiB,8IAG7B,CAAC;AAEF,iGAAiG;AACjG,eAAO,MAAM,aAAa,uJAGzB,CAAC;AAEF,6FAA6F;AAC7F,eAAO,MAAM,qBAAqB,wHAGjC,CAAC;AAoBF,eAAO,MAAM,SAAS,+EAarB,CAAC;AAuBF,eAAO,MAAM,YAAY;WACE,iBAAiB;WAGzC,CAAC;AAEJ,eAAO,MAAM,iBAAiB;QACN,MAAM;cAAY,MAAM;WAK7C,CAAC;AAEJ,eAAO,MAAM,iBAAiB;QACN,MAAM;WAG3B,CAAC;AAMJ,eAAO,MAAM,WAAW,GAAI,SAAS,cAAc,uFAkBlD,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,IAAI,MAAM,GAAG,SAAS,oFAchD,CAAC;AAWF,eAAO,MAAM,WAAW,6GAcvB,CAAC;AAEF,eAAO,MAAM,qBAAqB,mGAcjC,CAAC;AAEF,eAAO,MAAM,mBAAmB,2FAc/B,CAAC;AAEF,eAAO,MAAM,cAAc,2FAc1B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,kHAkB5B,CAAC;AAMF,eAAO,MAAM,oBAAoB,mGAqBhC,CAAC;AAEF,eAAO,MAAM,2BAA2B,iGAkBvC,CAAC;AAEF,eAAO,MAAM,uBAAuB;YAII,MAAM;cAAY,MAAM;YAAU,MAAM,GAAG,IAAI;WActF,CAAC;AAWF,uFAAuF;AACvF,eAAO,MAAM,yBAAyB,wGAkBrC,CAAC;AAWF,2EAA2E;AAC3E,eAAO,MAAM,sBAAsB,kHAgBlC,CAAC;AAEF,6FAA6F;AAC7F,eAAO,MAAM,2BAA2B,yGAgBvC,CAAC"}
1
+ {"version":3,"file":"useCommerceApi.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/hooks/useCommerceApi.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EACV,iBAAiB,EACjB,2BAA2B,EAC3B,OAAO,EACP,gBAAgB,EAChB,+BAA+B,EAC/B,sBAAsB,EACtB,gCAAgC,EAChC,2BAA2B,EAC3B,yBAAyB,EACzB,gBAAgB,EAChB,QAAQ,EACR,gBAAgB,EAChB,kBAAkB,EAClB,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,UAAU,CAAC;AAwBlB,iGAAiG;AACjG,eAAO,MAAM,iBAAiB,8IAG7B,CAAC;AAEF,iGAAiG;AACjG,eAAO,MAAM,aAAa,uJAGzB,CAAC;AAEF,6FAA6F;AAC7F,eAAO,MAAM,qBAAqB,wHAGjC,CAAC;AAoBF,eAAO,MAAM,SAAS,+EAarB,CAAC;AAuBF,eAAO,MAAM,YAAY;WACE,iBAAiB;WAGzC,CAAC;AAEJ,eAAO,MAAM,iBAAiB;QACN,MAAM;cAAY,MAAM;WAK7C,CAAC;AAEJ,eAAO,MAAM,iBAAiB;QACN,MAAM;WAG3B,CAAC;AAMJ,eAAO,MAAM,WAAW,GAAI,SAAS,cAAc,uFAkBlD,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,IAAI,MAAM,GAAG,SAAS,oFAchD,CAAC;AAWF,eAAO,MAAM,WAAW,6GAcvB,CAAC;AAEF,eAAO,MAAM,qBAAqB,mGAcjC,CAAC;AAEF,eAAO,MAAM,mBAAmB,2FAc/B,CAAC;AAEF,eAAO,MAAM,cAAc,2FAc1B,CAAC;AAYF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAAI,IAAI,MAAM,GAAG,SAAS,EAAE,SAAS,OAAO,+FAc3E,CAAC;AAEF,uFAAuF;AACvF,eAAO,MAAM,sBAAsB,wHAgBlC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,kHAkB5B,CAAC;AAMF,eAAO,MAAM,oBAAoB,mGAqBhC,CAAC;AAEF,eAAO,MAAM,2BAA2B,iGAkBvC,CAAC;AAEF,eAAO,MAAM,uBAAuB;YAII,MAAM;cAAY,MAAM;YAAU,MAAM,GAAG,IAAI;WActF,CAAC;AAWF,uFAAuF;AACvF,eAAO,MAAM,yBAAyB,wGAkBrC,CAAC;AAWF,2EAA2E;AAC3E,eAAO,MAAM,sBAAsB,kHAgBlC,CAAC;AAEF,6FAA6F;AAC7F,eAAO,MAAM,2BAA2B,yGAgBvC,CAAC"}
@@ -98,7 +98,26 @@ var o = "coolandlovely", s = "\n items {\n id styleItemId quantity size colo
98
98
  mutationFn: async (e) => (await n(`mutation CooCancelOrder($id: ID!) { cooCancelOrder(id: $id) { ${c} } }`, { id: e }, t)).cooCancelOrder,
99
99
  onSuccess: x()
100
100
  });
101
- }, E = () => {
101
+ }, E = "\n id name description category price currency sku colours sizes materials tags\n brandName brandHandle trackInventory inStock\n variants { size colour available }\n", D = (t, r) => {
102
+ let { apiGatewayUrl: a } = e();
103
+ return i({
104
+ queryKey: [
105
+ o,
106
+ "store-listed-piece",
107
+ t
108
+ ],
109
+ enabled: !!t && r,
110
+ queryFn: async () => (await n(`query CooStoreListedPiece($id: ID!) { cooStoreListedPiece(id: $id) { ${E} } }`, { id: t }, a)).cooStoreListedPiece
111
+ });
112
+ }, O = () => {
113
+ let { apiGatewayUrl: t } = e(), i = x();
114
+ return r({
115
+ mutationFn: async (e) => (await n(`mutation CooBuyStoreListedPiece($input: CooBuyStoreListedPieceInput!) {
116
+ cooBuyStoreListedPiece(input: $input) { ${p} }
117
+ }`, { input: e }, t)).cooBuyStoreListedPiece,
118
+ onSuccess: (e) => i(e.order)
119
+ });
120
+ }, k = () => {
102
121
  let { apiGatewayUrl: t } = e(), i = a();
103
122
  return r({
104
123
  mutationFn: async (e) => (await n(`mutation CooRequestReturn($input: CooRequestReturnInput!) {
@@ -112,7 +131,7 @@ var o = "coolandlovely", s = "\n items {\n id styleItemId quantity size colo
112
131
  ] });
113
132
  }
114
133
  });
115
- }, D = () => {
134
+ }, A = () => {
116
135
  let { apiGatewayUrl: t } = e();
117
136
  return i({
118
137
  queryKey: [o, "creator-earnings"],
@@ -121,13 +140,13 @@ var o = "coolandlovely", s = "\n items {\n id styleItemId quantity size colo
121
140
  offset: 0
122
141
  } }, t)).cooMyCreatorEarnings
123
142
  });
124
- }, O = () => {
143
+ }, j = () => {
125
144
  let { apiGatewayUrl: t } = e();
126
145
  return i({
127
146
  queryKey: [o, "creator-earnings-summary"],
128
147
  queryFn: async () => (await n("query CooMyCreatorEarningsSummary {\n cooMyCreatorEarningsSummary {\n commissionRate holdDays currency totalLifetimeAmount availableAmount pendingAmount\n reservedAmount paidAmount pendingPayoutCount unsyncedCount billingAvailable\n }\n }", {}, t)).cooMyCreatorEarningsSummary
129
148
  });
130
- }, k = () => {
149
+ }, M = () => {
131
150
  let { apiGatewayUrl: t } = e(), i = a();
132
151
  return r({
133
152
  mutationFn: async (e) => (await n("mutation CooRequestCreatorPayout($input: CooRequestCreatorPayoutInput!) {\n cooRequestCreatorPayout(input: $input) { id status requestedAmount currency createdAt }\n }", { input: e }, t)).cooRequestCreatorPayout,
@@ -135,10 +154,10 @@ var o = "coolandlovely", s = "\n items {\n id styleItemId quantity size colo
135
154
  i.invalidateQueries({ queryKey: [o, "creator-earnings-summary"] });
136
155
  }
137
156
  });
138
- }, A = `
157
+ }, N = `
139
158
  payout { ${t} }
140
159
  provider providerOrderId razorpayKeyId clientSecret stripePublishableKey subtotal taxAmount total currency
141
- `, j = () => {
160
+ `, P = () => {
142
161
  let { apiGatewayUrl: r } = e();
143
162
  return i({
144
163
  queryKey: [o, "collaboration-payouts"],
@@ -152,7 +171,7 @@ var o = "coolandlovely", s = "\n items {\n id styleItemId quantity size colo
152
171
  offset: 0
153
172
  } }, r)).cooMyCollaborationPayouts
154
173
  });
155
- }, M = () => {
174
+ }, F = () => {
156
175
  let e = a();
157
176
  return (t) => {
158
177
  e.invalidateQueries({ queryKey: [
@@ -161,16 +180,16 @@ var o = "coolandlovely", s = "\n items {\n id styleItemId quantity size colo
161
180
  t
162
181
  ] }), e.invalidateQueries({ queryKey: [o, "collaboration-payouts"] }), e.invalidateQueries({ queryKey: [o, "creator-earnings-summary"] });
163
182
  };
164
- }, N = () => {
165
- let { apiGatewayUrl: t } = e(), i = M();
183
+ }, I = () => {
184
+ let { apiGatewayUrl: t } = e(), i = F();
166
185
  return r({
167
186
  mutationFn: async (e) => (await n(`mutation CooPayCollaborationFee($id: ID!) {
168
- cooPayCollaborationFee(id: $id) { ${A} }
187
+ cooPayCollaborationFee(id: $id) { ${N} }
169
188
  }`, { id: e }, t)).cooPayCollaborationFee,
170
189
  onSuccess: (e) => i(e.payout.collaborationId)
171
190
  });
172
- }, P = () => {
173
- let { apiGatewayUrl: i } = e(), a = M();
191
+ }, L = () => {
192
+ let { apiGatewayUrl: i } = e(), a = F();
174
193
  return r({
175
194
  mutationFn: async (e) => (await n(`mutation CooSyncCollaborationPayment($id: ID!) {
176
195
  cooSyncCollaborationPayment(id: $id) { ${t} }
@@ -179,6 +198,6 @@ var o = "coolandlovely", s = "\n items {\n id styleItemId quantity size colo
179
198
  });
180
199
  };
181
200
  //#endregion
182
- export { l as FULFILMENT_FIELDS, u as REFUND_FIELDS, d as RETURN_REQUEST_FIELDS, g as useAddToCart, T as useCancelOrder, S as useCheckout, m as useMyCart, j as useMyCollaborationPayouts, D as useMyCreatorEarnings, O as useMyCreatorEarningsSummary, b as useMyOrder, y as useMyOrders, N as usePayCollaborationFee, v as useRemoveCartItem, k as useRequestCreatorPayout, E as useRequestReturn, C as useResumeOrderPayment, P as useSyncCollaborationPayment, w as useSyncOrderPayment, _ as useUpdateCartItem };
201
+ export { l as FULFILMENT_FIELDS, u as REFUND_FIELDS, d as RETURN_REQUEST_FIELDS, g as useAddToCart, O as useBuyStoreListedPiece, T as useCancelOrder, S as useCheckout, m as useMyCart, P as useMyCollaborationPayouts, A as useMyCreatorEarnings, j as useMyCreatorEarningsSummary, b as useMyOrder, y as useMyOrders, I as usePayCollaborationFee, v as useRemoveCartItem, M as useRequestCreatorPayout, k as useRequestReturn, C as useResumeOrderPayment, D as useStoreListedPiece, L as useSyncCollaborationPayment, w as useSyncOrderPayment, _ as useUpdateCartItem };
183
202
 
184
203
  //# sourceMappingURL=useCommerceApi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useCommerceApi.js","names":[],"sources":["../../../src/coolandlovely/hooks/useCommerceApi.ts"],"sourcesContent":["/**\n * Commerce API hooks (BOFF-3370)\n * @module coolandlovely/hooks\n *\n * React Query layer over the self-scoped commerce fields of `wspace-coolandlovely-svc`:\n * the shopper's cart, checkout and orders, and the creator's look commissions + payouts.\n * The client never decides that an order is paid — it opens the provider's checkout that\n * global-billing prepared and then asks the backend to settle against billing's record.\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\n\nimport { useCoolAndLovely } from '../context';\nimport type {\n CooAddToCartInput,\n CooCart,\n CooCheckoutInput,\n CooCollaborationPaymentCheckout,\n CooCollaborationPayout,\n CooCollaborationPayoutConnection,\n CooCreatorEarningConnection,\n CooCreatorEarningsSummary,\n CooCreatorPayout,\n CooOrder,\n CooOrderCheckout,\n CooOrderConnection,\n CooOrderStatus,\n CooRequestReturnInput,\n CooReturnRequest,\n} from '../types';\nimport { COLLABORATION_PAYOUT_FIELDS, coolQuery } from './useCoolAndLovelyApi';\n\nconst QK = 'coolandlovely';\n\nconst CART_FIELDS = `\n items {\n id styleItemId quantity size colour lookId unitPrice currency lineTotal isPurchasable\n availableQuantity\n styleItem { id name status image { id } brand { id name } }\n }\n itemCount subtotal currency canCheckout blockedReason\n`;\n\nconst ORDER_FIELDS = `\n id orderNumber status currency subtotal taxAmount total itemCount\n shippingName shippingAddress buyerNote paymentProvider paidAt cancelledAt refundedAmount refundedAt\n createdAt updatedAt\n items {\n id styleItemId brandId name sku image { id } size colour unitPrice quantity lineTotal\n lookId isCreatorAttributed\n }\n`;\n\n/** Per-brand fulfilment (BOFF-9636): shared by the shopper's order detail and the brand view. */\nexport const FULFILMENT_FIELDS = `\n id orderId brandId brandName status refunded carrier trackingNumber trackingUrl note\n confirmedAt shippedAt deliveredAt updatedAt\n`;\n\n/** A brand's refund of its pieces (BOFF-9702): the shopper's order detail and the brand view. */\nexport const REFUND_FIELDS = `\n id orderId brandId brandName amount currency reason status failureReason refundedAt\n restockStatus restockedQuantity restockedAt createdAt\n`;\n\n/** A shopper's return request (BOFF-9900): the shopper's order detail and the brand view. */\nexport const RETURN_REQUEST_FIELDS = `\n id orderId orderNumber brandId brandName reason status decisionNote decidedAt refundId\n createdAt updatedAt\n`;\n\nconst ORDER_DETAIL_FIELDS = `\n ${ORDER_FIELDS}\n fulfilmentStatus\n fulfilments { ${FULFILMENT_FIELDS} }\n refunds { ${REFUND_FIELDS} }\n returnRequests { ${RETURN_REQUEST_FIELDS} }\n returnWindowEndsAt\n`;\n\nconst CHECKOUT_FIELDS = `\n order { ${ORDER_FIELDS} }\n provider providerOrderId razorpayKeyId clientSecret stripePublishableKey subtotal taxAmount total currency\n`;\n\n// ---------------------------------------------------------------------------\n// Cart\n// ---------------------------------------------------------------------------\n\nexport const useMyCart = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n return useQuery({\n queryKey: [QK, 'cart'],\n queryFn: async () => {\n const data = await coolQuery<{ cooMyCart: CooCart }>(\n `query CooMyCart { cooMyCart { ${CART_FIELDS} } }`,\n {},\n apiGatewayUrl\n );\n return data.cooMyCart;\n },\n });\n};\n\n/** Every cart mutation answers with the fresh cart, which is written straight into the cache. */\nconst useCartMutation = <TVars>(document: string, field: string) => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: async (variables: TVars) => {\n const data = await coolQuery<Record<string, CooCart>>(\n document,\n variables as Record<string, unknown>,\n apiGatewayUrl\n );\n const cart = data[field];\n if (!cart) throw new Error('The cart could not be updated');\n return cart;\n },\n onSuccess: (cart) => {\n queryClient.setQueryData([QK, 'cart'], cart);\n },\n });\n};\n\nexport const useAddToCart = () =>\n useCartMutation<{ input: CooAddToCartInput }>(\n `mutation CooAddToCart($input: CooAddToCartInput!) { cooAddToCart(input: $input) { ${CART_FIELDS} } }`,\n 'cooAddToCart'\n );\n\nexport const useUpdateCartItem = () =>\n useCartMutation<{ id: string; quantity: number }>(\n `mutation CooUpdateCartItem($id: ID!, $quantity: Int!) {\n cooUpdateCartItem(id: $id, quantity: $quantity) { ${CART_FIELDS} }\n }`,\n 'cooUpdateCartItem'\n );\n\nexport const useRemoveCartItem = () =>\n useCartMutation<{ id: string }>(\n `mutation CooRemoveCartItem($id: ID!) { cooRemoveCartItem(id: $id) { ${CART_FIELDS} } }`,\n 'cooRemoveCartItem'\n );\n\n// ---------------------------------------------------------------------------\n// Orders + checkout\n// ---------------------------------------------------------------------------\n\nexport const useMyOrders = (status?: CooOrderStatus) => {\n const { apiGatewayUrl } = useCoolAndLovely();\n return useQuery({\n queryKey: [QK, 'orders', status ?? 'ALL'],\n queryFn: async () => {\n const data = await coolQuery<{ cooMyOrders: CooOrderConnection }>(\n `query CooMyOrders($status: CooOrderStatus, $pagination: PaginationInput) {\n cooMyOrders(status: $status, pagination: $pagination) {\n items { ${ORDER_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { status, pagination: { limit: 50, offset: 0 } },\n apiGatewayUrl\n );\n return data.cooMyOrders;\n },\n });\n};\n\nexport const useMyOrder = (id: string | undefined) => {\n const { apiGatewayUrl } = useCoolAndLovely();\n return useQuery({\n queryKey: [QK, 'order', id],\n enabled: !!id,\n queryFn: async () => {\n const data = await coolQuery<{ cooMyOrder: CooOrder | null }>(\n `query CooMyOrder($id: ID!) { cooMyOrder(id: $id) { ${ORDER_DETAIL_FIELDS} } }`,\n { id },\n apiGatewayUrl\n );\n return data.cooMyOrder;\n },\n });\n};\n\nconst useOrderInvalidation = () => {\n const queryClient = useQueryClient();\n return (order: CooOrder) => {\n queryClient.setQueryData([QK, 'order', order.id], order);\n void queryClient.invalidateQueries({ queryKey: [QK, 'orders'] });\n void queryClient.invalidateQueries({ queryKey: [QK, 'cart'] });\n };\n};\n\nexport const useCheckout = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const settle = useOrderInvalidation();\n return useMutation({\n mutationFn: async (input: CooCheckoutInput) => {\n const data = await coolQuery<{ cooCheckout: CooOrderCheckout }>(\n `mutation CooCheckout($input: CooCheckoutInput!) { cooCheckout(input: $input) { ${CHECKOUT_FIELDS} } }`,\n { input },\n apiGatewayUrl\n );\n return data.cooCheckout;\n },\n onSuccess: (checkout) => settle(checkout.order),\n });\n};\n\nexport const useResumeOrderPayment = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const settle = useOrderInvalidation();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await coolQuery<{ cooResumeOrderPayment: CooOrderCheckout }>(\n `mutation CooResumeOrderPayment($id: ID!) { cooResumeOrderPayment(id: $id) { ${CHECKOUT_FIELDS} } }`,\n { id },\n apiGatewayUrl\n );\n return data.cooResumeOrderPayment;\n },\n onSuccess: (checkout) => settle(checkout.order),\n });\n};\n\nexport const useSyncOrderPayment = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const settle = useOrderInvalidation();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await coolQuery<{ cooSyncOrderPayment: CooOrder }>(\n `mutation CooSyncOrderPayment($id: ID!) { cooSyncOrderPayment(id: $id) { ${ORDER_FIELDS} } }`,\n { id },\n apiGatewayUrl\n );\n return data.cooSyncOrderPayment;\n },\n onSuccess: settle,\n });\n};\n\nexport const useCancelOrder = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const settle = useOrderInvalidation();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await coolQuery<{ cooCancelOrder: CooOrder }>(\n `mutation CooCancelOrder($id: ID!) { cooCancelOrder(id: $id) { ${ORDER_FIELDS} } }`,\n { id },\n apiGatewayUrl\n );\n return data.cooCancelOrder;\n },\n onSuccess: settle,\n });\n};\n\n/**\n * Ask a brand to take back its pieces of one of the caller's paid orders (BOFF-9900). The brand\n * approves (which refunds them) or declines; the order detail is refetched to show the request.\n */\nexport const useRequestReturn = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: async (input: CooRequestReturnInput) => {\n const data = await coolQuery<{ cooRequestReturn: CooReturnRequest }>(\n `mutation CooRequestReturn($input: CooRequestReturnInput!) {\n cooRequestReturn(input: $input) { ${RETURN_REQUEST_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return data.cooRequestReturn;\n },\n onSettled: (_request, _error, input) => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'order', input.orderId] });\n },\n });\n};\n\n// ---------------------------------------------------------------------------\n// Creator earnings + payouts\n// ---------------------------------------------------------------------------\n\nexport const useMyCreatorEarnings = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n return useQuery({\n queryKey: [QK, 'creator-earnings'],\n queryFn: async () => {\n const data = await coolQuery<{ cooMyCreatorEarnings: CooCreatorEarningConnection }>(\n `query CooMyCreatorEarnings($pagination: PaginationInput) {\n cooMyCreatorEarnings(pagination: $pagination) {\n items {\n id orderId orderNumber lookId collaborationId commissionRate saleAmount amount currency\n availableAt billingSyncStatus reversalStatus reversedAt createdAt\n }\n pageInfo { cursor hasMore }\n }\n }`,\n { pagination: { limit: 50, offset: 0 } },\n apiGatewayUrl\n );\n return data.cooMyCreatorEarnings;\n },\n });\n};\n\nexport const useMyCreatorEarningsSummary = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n return useQuery({\n queryKey: [QK, 'creator-earnings-summary'],\n queryFn: async () => {\n const data = await coolQuery<{ cooMyCreatorEarningsSummary: CooCreatorEarningsSummary }>(\n `query CooMyCreatorEarningsSummary {\n cooMyCreatorEarningsSummary {\n commissionRate holdDays currency totalLifetimeAmount availableAmount pendingAmount\n reservedAmount paidAmount pendingPayoutCount unsyncedCount billingAvailable\n }\n }`,\n {},\n apiGatewayUrl\n );\n return data.cooMyCreatorEarningsSummary;\n },\n });\n};\n\nexport const useRequestCreatorPayout = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: async (input: { amount: number; currency: string; notes?: string | null }) => {\n const data = await coolQuery<{ cooRequestCreatorPayout: CooCreatorPayout }>(\n `mutation CooRequestCreatorPayout($input: CooRequestCreatorPayoutInput!) {\n cooRequestCreatorPayout(input: $input) { id status requestedAmount currency createdAt }\n }`,\n { input },\n apiGatewayUrl\n );\n return data.cooRequestCreatorPayout;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'creator-earnings-summary'] });\n },\n });\n};\n\n// ---------------------------------------------------------------------------\n// Collaboration fees (BOFF-9637)\n// ---------------------------------------------------------------------------\n\nconst COLLABORATION_PAYMENT_FIELDS = `\n payout { ${COLLABORATION_PAYOUT_FIELDS} }\n provider providerOrderId razorpayKeyId clientSecret stripePublishableKey subtotal taxAmount total currency\n`;\n\n/** The calling creator's collaboration fees: awaiting the brand's payment, or paid. */\nexport const useMyCollaborationPayouts = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n return useQuery({\n queryKey: [QK, 'collaboration-payouts'],\n queryFn: async () => {\n const data = await coolQuery<{ cooMyCollaborationPayouts: CooCollaborationPayoutConnection }>(\n `query CooMyCollaborationPayouts($pagination: PaginationInput) {\n cooMyCollaborationPayouts(pagination: $pagination) {\n items { ${COLLABORATION_PAYOUT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { pagination: { limit: 50, offset: 0 } },\n apiGatewayUrl\n );\n return data.cooMyCollaborationPayouts;\n },\n });\n};\n\nconst useCollaborationPayoutInvalidation = () => {\n const queryClient = useQueryClient();\n return (collaborationId: string) => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'collaboration', collaborationId] });\n void queryClient.invalidateQueries({ queryKey: [QK, 'collaboration-payouts'] });\n void queryClient.invalidateQueries({ queryKey: [QK, 'creator-earnings-summary'] });\n };\n};\n\n/** Start (or re-open) the brand owner's payment of a collaboration fee. */\nexport const usePayCollaborationFee = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const refresh = useCollaborationPayoutInvalidation();\n return useMutation({\n mutationFn: async (collaborationId: string) => {\n const data = await coolQuery<{ cooPayCollaborationFee: CooCollaborationPaymentCheckout }>(\n `mutation CooPayCollaborationFee($id: ID!) {\n cooPayCollaborationFee(id: $id) { ${COLLABORATION_PAYMENT_FIELDS} }\n }`,\n { id: collaborationId },\n apiGatewayUrl\n );\n return data.cooPayCollaborationFee;\n },\n onSuccess: (checkout) => refresh(checkout.payout.collaborationId),\n });\n};\n\n/** Ask the backend to settle a collaboration fee against global-billing's payment record. */\nexport const useSyncCollaborationPayment = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const refresh = useCollaborationPayoutInvalidation();\n return useMutation({\n mutationFn: async (collaborationId: string) => {\n const data = await coolQuery<{ cooSyncCollaborationPayment: CooCollaborationPayout }>(\n `mutation CooSyncCollaborationPayment($id: ID!) {\n cooSyncCollaborationPayment(id: $id) { ${COLLABORATION_PAYOUT_FIELDS} }\n }`,\n { id: collaborationId },\n apiGatewayUrl\n );\n return data.cooSyncCollaborationPayment;\n },\n onSuccess: (payout) => refresh(payout.collaborationId),\n });\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"useCommerceApi.js","names":[],"sources":["../../../src/coolandlovely/hooks/useCommerceApi.ts"],"sourcesContent":["/**\n * Commerce API hooks (BOFF-3370)\n * @module coolandlovely/hooks\n *\n * React Query layer over the self-scoped commerce fields of `wspace-coolandlovely-svc`:\n * the shopper's cart, checkout and orders, and the creator's look commissions + payouts.\n * The client never decides that an order is paid — it opens the provider's checkout that\n * global-billing prepared and then asks the backend to settle against billing's record.\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\n\nimport { useCoolAndLovely } from '../context';\nimport type {\n CooAddToCartInput,\n CooBuyStoreListedPieceInput,\n CooCart,\n CooCheckoutInput,\n CooCollaborationPaymentCheckout,\n CooCollaborationPayout,\n CooCollaborationPayoutConnection,\n CooCreatorEarningConnection,\n CooCreatorEarningsSummary,\n CooCreatorPayout,\n CooOrder,\n CooOrderCheckout,\n CooOrderConnection,\n CooOrderStatus,\n CooRequestReturnInput,\n CooReturnRequest,\n CooStoreListedPiece,\n} from '../types';\nimport { COLLABORATION_PAYOUT_FIELDS, coolQuery } from './useCoolAndLovelyApi';\n\nconst QK = 'coolandlovely';\n\nconst CART_FIELDS = `\n items {\n id styleItemId quantity size colour lookId unitPrice currency lineTotal isPurchasable\n availableQuantity\n styleItem { id name status image { id } brand { id name } }\n }\n itemCount subtotal currency canCheckout blockedReason\n`;\n\nconst ORDER_FIELDS = `\n id orderNumber status currency subtotal taxAmount total itemCount\n shippingName shippingAddress buyerNote paymentProvider paidAt cancelledAt refundedAmount refundedAt\n createdAt updatedAt\n items {\n id styleItemId brandId name sku image { id } size colour unitPrice quantity lineTotal\n lookId isCreatorAttributed\n }\n`;\n\n/** Per-brand fulfilment (BOFF-9636): shared by the shopper's order detail and the brand view. */\nexport const FULFILMENT_FIELDS = `\n id orderId brandId brandName status refunded carrier trackingNumber trackingUrl note\n confirmedAt shippedAt deliveredAt updatedAt\n`;\n\n/** A brand's refund of its pieces (BOFF-9702): the shopper's order detail and the brand view. */\nexport const REFUND_FIELDS = `\n id orderId brandId brandName amount currency reason status failureReason refundedAt\n restockStatus restockedQuantity restockedAt createdAt\n`;\n\n/** A shopper's return request (BOFF-9900): the shopper's order detail and the brand view. */\nexport const RETURN_REQUEST_FIELDS = `\n id orderId orderNumber brandId brandName reason status decisionNote decidedAt refundId\n createdAt updatedAt\n`;\n\nconst ORDER_DETAIL_FIELDS = `\n ${ORDER_FIELDS}\n fulfilmentStatus\n fulfilments { ${FULFILMENT_FIELDS} }\n refunds { ${REFUND_FIELDS} }\n returnRequests { ${RETURN_REQUEST_FIELDS} }\n returnWindowEndsAt\n`;\n\nconst CHECKOUT_FIELDS = `\n order { ${ORDER_FIELDS} }\n provider providerOrderId razorpayKeyId clientSecret stripePublishableKey subtotal taxAmount total currency\n`;\n\n// ---------------------------------------------------------------------------\n// Cart\n// ---------------------------------------------------------------------------\n\nexport const useMyCart = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n return useQuery({\n queryKey: [QK, 'cart'],\n queryFn: async () => {\n const data = await coolQuery<{ cooMyCart: CooCart }>(\n `query CooMyCart { cooMyCart { ${CART_FIELDS} } }`,\n {},\n apiGatewayUrl\n );\n return data.cooMyCart;\n },\n });\n};\n\n/** Every cart mutation answers with the fresh cart, which is written straight into the cache. */\nconst useCartMutation = <TVars>(document: string, field: string) => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: async (variables: TVars) => {\n const data = await coolQuery<Record<string, CooCart>>(\n document,\n variables as Record<string, unknown>,\n apiGatewayUrl\n );\n const cart = data[field];\n if (!cart) throw new Error('The cart could not be updated');\n return cart;\n },\n onSuccess: (cart) => {\n queryClient.setQueryData([QK, 'cart'], cart);\n },\n });\n};\n\nexport const useAddToCart = () =>\n useCartMutation<{ input: CooAddToCartInput }>(\n `mutation CooAddToCart($input: CooAddToCartInput!) { cooAddToCart(input: $input) { ${CART_FIELDS} } }`,\n 'cooAddToCart'\n );\n\nexport const useUpdateCartItem = () =>\n useCartMutation<{ id: string; quantity: number }>(\n `mutation CooUpdateCartItem($id: ID!, $quantity: Int!) {\n cooUpdateCartItem(id: $id, quantity: $quantity) { ${CART_FIELDS} }\n }`,\n 'cooUpdateCartItem'\n );\n\nexport const useRemoveCartItem = () =>\n useCartMutation<{ id: string }>(\n `mutation CooRemoveCartItem($id: ID!) { cooRemoveCartItem(id: $id) { ${CART_FIELDS} } }`,\n 'cooRemoveCartItem'\n );\n\n// ---------------------------------------------------------------------------\n// Orders + checkout\n// ---------------------------------------------------------------------------\n\nexport const useMyOrders = (status?: CooOrderStatus) => {\n const { apiGatewayUrl } = useCoolAndLovely();\n return useQuery({\n queryKey: [QK, 'orders', status ?? 'ALL'],\n queryFn: async () => {\n const data = await coolQuery<{ cooMyOrders: CooOrderConnection }>(\n `query CooMyOrders($status: CooOrderStatus, $pagination: PaginationInput) {\n cooMyOrders(status: $status, pagination: $pagination) {\n items { ${ORDER_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { status, pagination: { limit: 50, offset: 0 } },\n apiGatewayUrl\n );\n return data.cooMyOrders;\n },\n });\n};\n\nexport const useMyOrder = (id: string | undefined) => {\n const { apiGatewayUrl } = useCoolAndLovely();\n return useQuery({\n queryKey: [QK, 'order', id],\n enabled: !!id,\n queryFn: async () => {\n const data = await coolQuery<{ cooMyOrder: CooOrder | null }>(\n `query CooMyOrder($id: ID!) { cooMyOrder(id: $id) { ${ORDER_DETAIL_FIELDS} } }`,\n { id },\n apiGatewayUrl\n );\n return data.cooMyOrder;\n },\n });\n};\n\nconst useOrderInvalidation = () => {\n const queryClient = useQueryClient();\n return (order: CooOrder) => {\n queryClient.setQueryData([QK, 'order', order.id], order);\n void queryClient.invalidateQueries({ queryKey: [QK, 'orders'] });\n void queryClient.invalidateQueries({ queryKey: [QK, 'cart'] });\n };\n};\n\nexport const useCheckout = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const settle = useOrderInvalidation();\n return useMutation({\n mutationFn: async (input: CooCheckoutInput) => {\n const data = await coolQuery<{ cooCheckout: CooOrderCheckout }>(\n `mutation CooCheckout($input: CooCheckoutInput!) { cooCheckout(input: $input) { ${CHECKOUT_FIELDS} } }`,\n { input },\n apiGatewayUrl\n );\n return data.cooCheckout;\n },\n onSuccess: (checkout) => settle(checkout.order),\n });\n};\n\nexport const useResumeOrderPayment = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const settle = useOrderInvalidation();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await coolQuery<{ cooResumeOrderPayment: CooOrderCheckout }>(\n `mutation CooResumeOrderPayment($id: ID!) { cooResumeOrderPayment(id: $id) { ${CHECKOUT_FIELDS} } }`,\n { id },\n apiGatewayUrl\n );\n return data.cooResumeOrderPayment;\n },\n onSuccess: (checkout) => settle(checkout.order),\n });\n};\n\nexport const useSyncOrderPayment = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const settle = useOrderInvalidation();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await coolQuery<{ cooSyncOrderPayment: CooOrder }>(\n `mutation CooSyncOrderPayment($id: ID!) { cooSyncOrderPayment(id: $id) { ${ORDER_FIELDS} } }`,\n { id },\n apiGatewayUrl\n );\n return data.cooSyncOrderPayment;\n },\n onSuccess: settle,\n });\n};\n\nexport const useCancelOrder = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const settle = useOrderInvalidation();\n return useMutation({\n mutationFn: async (id: string) => {\n const data = await coolQuery<{ cooCancelOrder: CooOrder }>(\n `mutation CooCancelOrder($id: ID!) { cooCancelOrder(id: $id) { ${ORDER_FIELDS} } }`,\n { id },\n apiGatewayUrl\n );\n return data.cooCancelOrder;\n },\n onSuccess: settle,\n });\n};\n\n// ---------------------------------------------------------------------------\n// Burdenoff store shoppers outside the brand's workspace (BOFF-10017)\n// ---------------------------------------------------------------------------\n\nconst STORE_LISTED_PIECE_FIELDS = `\n id name description category price currency sku colours sizes materials tags\n brandName brandHandle trackInventory inStock\n variants { size colour available }\n`;\n\n/**\n * A piece listed in the Burdenoff store, readable from any workspace. Only fetched once the\n * workspace's own catalogue has no such piece (the shopper followed a store listing here).\n */\nexport const useStoreListedPiece = (id: string | undefined, enabled: boolean) => {\n const { apiGatewayUrl } = useCoolAndLovely();\n return useQuery({\n queryKey: [QK, 'store-listed-piece', id],\n enabled: !!id && enabled,\n queryFn: async () => {\n const data = await coolQuery<{ cooStoreListedPiece: CooStoreListedPiece | null }>(\n `query CooStoreListedPiece($id: ID!) { cooStoreListedPiece(id: $id) { ${STORE_LISTED_PIECE_FIELDS} } }`,\n { id },\n apiGatewayUrl\n );\n return data.cooStoreListedPiece;\n },\n });\n};\n\n/** Buy a store-listed piece directly: the order is created and its payment started. */\nexport const useBuyStoreListedPiece = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const settle = useOrderInvalidation();\n return useMutation({\n mutationFn: async (input: CooBuyStoreListedPieceInput) => {\n const data = await coolQuery<{ cooBuyStoreListedPiece: CooOrderCheckout }>(\n `mutation CooBuyStoreListedPiece($input: CooBuyStoreListedPieceInput!) {\n cooBuyStoreListedPiece(input: $input) { ${CHECKOUT_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return data.cooBuyStoreListedPiece;\n },\n onSuccess: (checkout) => settle(checkout.order),\n });\n};\n\n/**\n * Ask a brand to take back its pieces of one of the caller's paid orders (BOFF-9900). The brand\n * approves (which refunds them) or declines; the order detail is refetched to show the request.\n */\nexport const useRequestReturn = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: async (input: CooRequestReturnInput) => {\n const data = await coolQuery<{ cooRequestReturn: CooReturnRequest }>(\n `mutation CooRequestReturn($input: CooRequestReturnInput!) {\n cooRequestReturn(input: $input) { ${RETURN_REQUEST_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return data.cooRequestReturn;\n },\n onSettled: (_request, _error, input) => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'order', input.orderId] });\n },\n });\n};\n\n// ---------------------------------------------------------------------------\n// Creator earnings + payouts\n// ---------------------------------------------------------------------------\n\nexport const useMyCreatorEarnings = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n return useQuery({\n queryKey: [QK, 'creator-earnings'],\n queryFn: async () => {\n const data = await coolQuery<{ cooMyCreatorEarnings: CooCreatorEarningConnection }>(\n `query CooMyCreatorEarnings($pagination: PaginationInput) {\n cooMyCreatorEarnings(pagination: $pagination) {\n items {\n id orderId orderNumber lookId collaborationId commissionRate saleAmount amount currency\n availableAt billingSyncStatus reversalStatus reversedAt createdAt\n }\n pageInfo { cursor hasMore }\n }\n }`,\n { pagination: { limit: 50, offset: 0 } },\n apiGatewayUrl\n );\n return data.cooMyCreatorEarnings;\n },\n });\n};\n\nexport const useMyCreatorEarningsSummary = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n return useQuery({\n queryKey: [QK, 'creator-earnings-summary'],\n queryFn: async () => {\n const data = await coolQuery<{ cooMyCreatorEarningsSummary: CooCreatorEarningsSummary }>(\n `query CooMyCreatorEarningsSummary {\n cooMyCreatorEarningsSummary {\n commissionRate holdDays currency totalLifetimeAmount availableAmount pendingAmount\n reservedAmount paidAmount pendingPayoutCount unsyncedCount billingAvailable\n }\n }`,\n {},\n apiGatewayUrl\n );\n return data.cooMyCreatorEarningsSummary;\n },\n });\n};\n\nexport const useRequestCreatorPayout = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: async (input: { amount: number; currency: string; notes?: string | null }) => {\n const data = await coolQuery<{ cooRequestCreatorPayout: CooCreatorPayout }>(\n `mutation CooRequestCreatorPayout($input: CooRequestCreatorPayoutInput!) {\n cooRequestCreatorPayout(input: $input) { id status requestedAmount currency createdAt }\n }`,\n { input },\n apiGatewayUrl\n );\n return data.cooRequestCreatorPayout;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'creator-earnings-summary'] });\n },\n });\n};\n\n// ---------------------------------------------------------------------------\n// Collaboration fees (BOFF-9637)\n// ---------------------------------------------------------------------------\n\nconst COLLABORATION_PAYMENT_FIELDS = `\n payout { ${COLLABORATION_PAYOUT_FIELDS} }\n provider providerOrderId razorpayKeyId clientSecret stripePublishableKey subtotal taxAmount total currency\n`;\n\n/** The calling creator's collaboration fees: awaiting the brand's payment, or paid. */\nexport const useMyCollaborationPayouts = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n return useQuery({\n queryKey: [QK, 'collaboration-payouts'],\n queryFn: async () => {\n const data = await coolQuery<{ cooMyCollaborationPayouts: CooCollaborationPayoutConnection }>(\n `query CooMyCollaborationPayouts($pagination: PaginationInput) {\n cooMyCollaborationPayouts(pagination: $pagination) {\n items { ${COLLABORATION_PAYOUT_FIELDS} }\n pageInfo { cursor hasMore }\n }\n }`,\n { pagination: { limit: 50, offset: 0 } },\n apiGatewayUrl\n );\n return data.cooMyCollaborationPayouts;\n },\n });\n};\n\nconst useCollaborationPayoutInvalidation = () => {\n const queryClient = useQueryClient();\n return (collaborationId: string) => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'collaboration', collaborationId] });\n void queryClient.invalidateQueries({ queryKey: [QK, 'collaboration-payouts'] });\n void queryClient.invalidateQueries({ queryKey: [QK, 'creator-earnings-summary'] });\n };\n};\n\n/** Start (or re-open) the brand owner's payment of a collaboration fee. */\nexport const usePayCollaborationFee = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const refresh = useCollaborationPayoutInvalidation();\n return useMutation({\n mutationFn: async (collaborationId: string) => {\n const data = await coolQuery<{ cooPayCollaborationFee: CooCollaborationPaymentCheckout }>(\n `mutation CooPayCollaborationFee($id: ID!) {\n cooPayCollaborationFee(id: $id) { ${COLLABORATION_PAYMENT_FIELDS} }\n }`,\n { id: collaborationId },\n apiGatewayUrl\n );\n return data.cooPayCollaborationFee;\n },\n onSuccess: (checkout) => refresh(checkout.payout.collaborationId),\n });\n};\n\n/** Ask the backend to settle a collaboration fee against global-billing's payment record. */\nexport const useSyncCollaborationPayment = () => {\n const { apiGatewayUrl } = useCoolAndLovely();\n const refresh = useCollaborationPayoutInvalidation();\n return useMutation({\n mutationFn: async (collaborationId: string) => {\n const data = await coolQuery<{ cooSyncCollaborationPayment: CooCollaborationPayout }>(\n `mutation CooSyncCollaborationPayment($id: ID!) {\n cooSyncCollaborationPayment(id: $id) { ${COLLABORATION_PAYOUT_FIELDS} }\n }`,\n { id: collaborationId },\n apiGatewayUrl\n );\n return data.cooSyncCollaborationPayment;\n },\n onSuccess: (payout) => refresh(payout.collaborationId),\n });\n};\n"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { FC } from 'react';
2
+
3
+ /**
4
+ * The fallback piece page for a store shopper. Renders "Item not found" when the store does not
5
+ * list the piece either (drafts, retired pieces, pieces of unpublished brands).
6
+ */
7
+ export declare const StoreListedPieceView: FC<{
8
+ itemId: string | undefined;
9
+ onRetry: () => void;
10
+ }>;
11
+ //# sourceMappingURL=StoreListedPieceView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StoreListedPieceView.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/items/StoreListedPieceView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,KAAK,EAAE,EAAY,MAAM,OAAO,CAAC;AAkS1C;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC;IAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CAkIxF,CAAC"}