@burdenoff/microfe-coolandlovely 2026.1028.3 → 2026.1028.4
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;
|
|
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}}.
|
|
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":";;;;;;;;;;;;AAuBA,IAAM,IAAW,GACX,IAAW,KACX,IAA4B,CAAC,QAAQ,qBAAqB,EAE1D,KAAe,MAA2B;CAC9C,IAAM,IAAU,EAAM,MAAM;AAC5B,QAAO,EAAQ,UAAU,KAAY,EAAQ,UAAU;GAGnD,IACJ,8MACI,IACJ;AAGF,SAAgB,EAAmB,GAA6C,IAAM,KAAK,KAAK,EAAE;AAEhG,QADK,EAAM,qBACJ,IAAI,KAAK,EAAM,mBAAmB,CAAC,SAAS,GAAG,IADhB;;AAKxC,SAAgB,EAAiB,GAAiB,GAAiB,IAAM,KAAK,KAAK,EAAW;AAE5F,KADI,CAAC,EAA0B,SAAS,EAAM,OAAO,IACjD,EAAM,gBAAgB,MAAM,MAAY,EAAQ,YAAY,EAAQ,CAAE,QAAO;CACjF,IAAM,IAAS,EAAM,SAAS,MAAM,MAAU,EAAM,YAAY,EAAQ;AAExE,QADI,MAAW,EAAO,WAAW,eAAe,EAAO,WAAW,aAAmB,KAC9E,EAAmB,GAAO,EAAI;;AAGvC,SAAS,EAAe,EAAE,cAA0C;CAClE,IAAM,IAAK,GAAO;AAClB,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,KAAD,EAAA,UACG,EAAG,qCAAqC,sBAAsB,EAAE,QAAQ,EAAQ,QAAQ,CAAC,EACxF,CAAA;GACH,EAAQ,WAAW,eAClB,kBAAC,KAAD,EAAA,UACG,EACC,uCACA,yDACA,EAAE,MAAM,EAAW,EAAQ,UAAU,EAAE,CACxC,EACC,CAAA;GAEL,EAAQ,WAAW,eAAe,EAAQ,gBACzC,kBAAC,KAAD;IAAG,eAAY;cACZ,EAAG,mCAAmC,0BAA0B,EAC/D,MAAM,EAAQ,cACf,CAAC;IACA,CAAA;GAEL,EAAQ,WAAW,eAAe,EAAQ,aACzC,kBAAC,KAAD,EAAA,UACG,EAAQ,WAAW,aAChB,EACE,oCACA,gDACA,EACE,MAAM,EAAW,EAAQ,UAAU,EACpC,CACF,GACD,EAAG,oCAAoC,sBAAsB,EAC3D,MAAM,EAAW,EAAQ,UAAU,EACpC,CAAC,EACJ,CAAA;GAEF;;;AAIV,SAAS,EAAkB,EAAE,YAAS,cAAiD;CACrF,IAAM,IAAK,GAAO,EACZ,IAAU,GAAkB,EAC5B,CAAC,GAAM,KAAW,EAAS,GAAM,EACjC,CAAC,GAAQ,KAAa,EAAS,GAAG;AAexC,QAbK,IAcH,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD;IACE,IAAI,qBAAqB;IACzB,OAAO,EAAG,gCAAgC,sCAAsC;IAChF,MAAM,EAAG,oCAAoC,sBAAsB;IACnE,OAAO;IACP,UAAU;IACV,MAAM;IACN,CAAA;GACD,EAAQ,SACP,kBAAC,KAAD;IAAG,WAAU;IAAiC,MAAK;cAChD,EAAQ,MAAM;IACb,CAAA;GAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,UAAD;KACE,MAAK;KACL,UAAU,EAAQ,aAAa,CAAC,EAAY,EAAO;KACnD,eACE,EAAQ,OACN;MAAE;MAAS;MAAS,QAAQ,EAAO,MAAM;MAAE,EAC3C,EAAE,iBAAiB,EAAQ,GAAM,EAAE,CACpC;KAEH,WAAW;KACX,eAAY;eAVd,CAYG,EAAQ,aAAa,kBAAC,GAAD,EAAS,WAAU,wBAAyB,CAAA,EACjE,EAAG,8BAA8B,sBAAsB,CACjD;QACT,kBAAC,UAAD;KACE,MAAK;KACL,UAAU,EAAQ;KAClB,eAAe,EAAQ,GAAM;KAC7B,WAAW;eAEV,EAAG,+BAA+B,SAAS;KACrC,CAAA,CACL;;GACF;MAnDJ,kBAAC,UAAD;EACE,MAAK;EACL,eAAe,EAAQ,GAAK;EAC5B,WAAW;EACX,eAAY;YAJd,CAME,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA,EAC5B,EAAG,iCAAiC,mBAAmB,CACjD;;;AAgDf,SAAgB,EAAa,EAAE,YAA8B;CAC3D,IAAM,IAAK,GAAO,EACZ,IAAO,EAAM,WAAW,UAAU,EAAM,WAAW,sBACnD,IAAW,EAAM,kBAAkB,EAAE;AAC3C,KAAI,CAAC,KAAQ,EAAS,WAAW,EAAG,QAAO;CAE3C,IAAM,IAAW,CAAC,GAAG,IAAI,IAAI,EAAM,MAAM,KAAK,MAAS,EAAK,QAAQ,CAAC,CAAC,EAChE,KAAa,MACjB,EAAS,MAAM,MAAY,EAAQ,YAAY,EAAQ,EAAE,aACzD,EAAM,aAAa,MAAM,MAAe,EAAW,YAAY,EAAQ,EAAE,aACzE,EAAM,SAAS,MAAM,MAAW,EAAO,YAAY,EAAQ,EAAE,aAC7D,EAAG,8BAA8B,QAAQ,EACrC,IAAa,EAAmB,EAAM;AAE5C,QACE,kBAAC,GAAD;EAAW,WAAU;EAAQ,WAAU;EAAgB,eAAY;YAAnE,CACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,KAAD;IAAG,WAAU;cACV,EAAG,+BAA+B,UAAU;IAC3C,CAAA,EACH,KAAQ,EAAM,sBACb,kBAAC,KAAD;IAAG,WAAU;IAA8B,eAAY;cACpD,IACG,EACE,oCACA,+DACA,EAAE,MAAM,EAAW,EAAM,mBAAmB,EAAE,CAC/C,GACD,EAAG,sCAAsC,yCAAyC,EAChF,MAAM,EAAW,EAAM,mBAAmB,EAC3C,CAAC;IACJ,CAAA,CAEF;MACL,EAAS,KAAK,MAAY;GACzB,IAAM,IAAU,EAAS,MAAM,MAAU,EAAM,YAAY,EAAQ,EAC7D,IAAW,EAAiB,GAAO,EAAQ;AAEjD,UADI,CAAC,KAAW,CAAC,IAAiB,OAEhC,kBAAC,OAAD;IAAmB,WAAU;IAAY,eAAY;cAArD,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,QAAD;MAAM,WAAU;gBAAyC,EAAU,EAAQ;MAAQ,CAAA,EAClF,KACC,kBAAC,QAAD;MAAM,eAAY;gBAChB,kBAAC,GAAD,EAAa,QAAQ,EAAQ,QAAU,CAAA;MAClC,CAAA,CAEL;QACL,IACC,kBAAC,GAAD,EAAyB,YAAW,CAAA,GAEpC,kBAAC,GAAD;KAAmB,SAAS,EAAM;KAAa;KAAW,CAAA,CAExD;MAdI,EAcJ;IAER,CACQ;;;AAKhB,SAAgB,EAAmB,EAAE,YAAmC;CACtE,IAAM,IAAK,GAAO,EACZ,IAAU,GAAyB,EACnC,IAAU,GAAyB,EACnC,CAAC,GAAM,KAAW,EAAyC,OAAO,EAClE,CAAC,GAAM,KAAW,EAAS,GAAG,EAC9B,IAAU,EAAM;AACtB,KAAI,CAAC,EAAS,QAAO;CAErB,IAAM,IAAO,EAAQ,aAAa,EAAQ,WACpC,IAAQ,EAAQ,SAAS,EAAQ,OACjC,IAAS,MAAS,aAAY,EAAK,MAAM,KAAK,MAA0B,EAAY,EAAK,EACzF,UAAc;AAElB,EADA,EAAQ,OAAO,EACf,EAAQ,GAAG;;AAWb,QACE,kBAAC,OAAD;EAAK,WAAU;EAA6C,eAAY;YAAxE;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,QAAD;KAAM,WAAU;eACb,EAAG,oCAAoC,iBAAiB;KACpD,CAAA,EACP,kBAAC,QAAD;KAAM,eAAY;eAChB,kBAAC,GAAD,EAAa,QAAQ,EAAQ,QAAU,CAAA;KAClC,CAAA,CACH;;GACN,kBAAC,GAAD,EAAyB,YAAW,CAAA;GAEnC,EAAQ,WAAW,gBACjB,MAAS,SACR,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAQ,UAAU;KACjC,WAAW;KACX,eAAY;eAJd,CAME,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA,EACnC,EAAG,iCAAiC,UAAU,CACxC;QACT,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAQ,UAAU;KACjC,WAAW;KACX,eAAY;eAJd,CAME,kBAAC,GAAD,EAAS,WAAU,WAAY,CAAA,EAC9B,EAAG,iCAAiC,UAAU,CACxC;OACL;QAEN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,KAAD;MAAG,WAAU;gBACV,MAAS,YACN,EACE,wCACA,mKACD,GACD,EACE,wCACA,oEACD;MACH,CAAA;KACJ,kBAAC,GAAD;MACE,IAAG;MACH,OACE,MAAS,YACL,EAAG,qCAAqC,iCAAiC,GACzE,EAAG,qCAAqC,yBAAyB;MAEvE,OAAO;MACP,UAAU;MACV,MAAM;MACN,CAAA;KACD,KACC,kBAAC,KAAD;MAAG,WAAU;MAAiC,MAAK;gBAChD,EAAM;MACL,CAAA;KAEN,kBAAC,UAAD;MACE,MAAK;MACL,UAAU,KAAQ,CAAC;MACnB,eA3ES;OACnB,IAAM,IAAQ;QAAE,SAAS,EAAM;QAAS,SAAS,EAAM;QAAI;AAC3D,OAAI,MAAS,YACX,EAAQ,OAAO;QAAE,GAAG;QAAO,MAAM,EAAK,MAAM,IAAI;QAAM,EAAE,EAAE,WAAW,GAAO,CAAC,GAE7E,EAAQ,OAAO;QAAE,GAAG;QAAO,MAAM,EAAK,MAAM;QAAE,EAAE,EAAE,WAAW,GAAO,CAAC;;MAuE7D,WACE,MAAS,YACL,GAAG,EAAc,WACjB,GAAG,EAAgB;MAEzB,eAAY;gBATd,CAWG,KAAQ,kBAAC,GAAD,EAAS,WAAU,wBAAyB,CAAA,EACpD,MAAS,YACN,EAAG,wCAAwC,qBAAqB,GAChE,EAAG,wCAAwC,iBAAiB,CACzD;;KACT,kBAAC,UAAD;MACE,MAAK;MACL,UAAU;MACV,SAAS;MACT,WAAW,GAAG,EAAgB;gBAE7B,EAAG,+BAA+B,SAAS;MACrC,CAAA;KACL;;GAEN"}
|