@burdenoff/microfe-coolandlovely 2026.1028.4 → 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.
- package/dist/coolandlovely/hooks/useCommerceApi.d.ts +8 -1
- package/dist/coolandlovely/hooks/useCommerceApi.d.ts.map +1 -1
- package/dist/coolandlovely/hooks/useCommerceApi.js +32 -13
- package/dist/coolandlovely/hooks/useCommerceApi.js.map +1 -1
- package/dist/coolandlovely/pages/items/StoreListedPieceView.d.ts +11 -0
- package/dist/coolandlovely/pages/items/StoreListedPieceView.d.ts.map +1 -0
- package/dist/coolandlovely/pages/items/StoreListedPieceView.js +352 -0
- package/dist/coolandlovely/pages/items/StoreListedPieceView.js.map +1 -0
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.d.ts +4 -0
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.js +116 -111
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.js.map +1 -1
- package/dist/coolandlovely/types/commerce.d.ts +38 -1
- package/dist/coolandlovely/types/commerce.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StoreListedPieceView.js","names":[],"sources":["../../../../src/coolandlovely/pages/items/StoreListedPieceView.tsx"],"sourcesContent":["/**\n * Store-listed piece view (BOFF-10017)\n * @module coolandlovely/pages/items\n *\n * What a shopper sees when they follow a Burdenoff store listing (\"View on CoolAndLovely\") to a\n * piece that belongs to a brand outside their workspace. The workspace catalogue has no such\n * piece, so the page falls back to `cooStoreListedPiece` (product facts only, readable from any\n * workspace) and lets the shopper buy it directly with `cooBuyStoreListedPiece`. The order is\n * held by the brand, paid through the provider global-billing chose, and settled only once the\n * backend re-reads billing's record; the shopper follows it from My Orders.\n */\n\nimport { type FC, useState } from 'react';\nimport { ArrowLeft, Loader2, ShoppingBag, Store } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\n\nimport { ColourSwatchRow } from '../../components/ColourSwatchRow';\nimport { TextAreaField, TextField } from '../../components/Field';\nimport { PageLayout } from '../../components/PageLayout';\nimport { PayForOrder } from '../../components/PayForOrder';\nimport { ErrorView, LoadingView } from '../../components/StateViews';\nimport { TagList } from '../../components/TagList';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useTr } from '../../hooks';\nimport {\n useBuyStoreListedPiece,\n useStoreListedPiece,\n useSyncOrderPayment,\n} from '../../hooks/useCommerceApi';\nimport type { CooOrderCheckout, CooStoreListedPiece } from '../../types';\nimport { cn } from '../../utils/cn';\nimport { formatPrice, titleCase } from '../../utils/formatters';\nimport { categoryIcon } from '../../utils/icons';\n\nconst MAX_QUANTITY = 10;\n/** Stock at or below this is shown to the shopper as \"Only N left\". */\nconst LOW_STOCK = 5;\n\nconst chip = (selected: boolean) =>\n cn(\n 'inline-flex min-w-9 items-center justify-center rounded-full border px-3 py-1 text-sm font-medium transition-colors disabled:opacity-40 disabled:line-through',\n selected\n ? 'border-action-primary-bg bg-action-primary-bg text-action-primary-text'\n : 'border-border-seam text-text-primary hover:bg-bg-sunken'\n );\n\nconst primaryButton =\n 'inline-flex w-full items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2.5 text-sm font-semibold text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-50';\n\n/**\n * Units left of a (possibly partial) size/colour choice while the piece tracks stock; null when\n * it does not. The service checks the stock again when the order is placed.\n */\nfunction unitsLeft(\n piece: CooStoreListedPiece,\n size: string | null,\n colour: string | null\n): number | null {\n if (!piece.trackInventory) return null;\n return piece.variants\n .filter(\n (variant) =>\n (size === null || (variant.size ?? '') === size) &&\n (colour === null || (variant.colour ?? '') === colour)\n )\n .reduce((sum, variant) => sum + variant.available, 0);\n}\n\n/** Size/colour/quantity, shipping details and \"Buy now\" for a store-listed piece. */\nconst BuyListedPiecePanel: FC<{\n piece: CooStoreListedPiece;\n onCheckout: (checkout: CooOrderCheckout) => void;\n}> = ({ piece, onCheckout }) => {\n const tr = useTr();\n const buy = useBuyStoreListedPiece();\n const [size, setSize] = useState<string | null>(\n piece.sizes.length === 1 ? (piece.sizes[0] ?? null) : null\n );\n const [colour, setColour] = useState<string | null>(\n piece.colours.length === 1 ? (piece.colours[0] ?? null) : null\n );\n const [quantity, setQuantity] = useState(1);\n const [shippingName, setShippingName] = useState('');\n const [shippingAddress, setShippingAddress] = useState('');\n const [buyerNote, setBuyerNote] = useState('');\n\n if (!piece.inStock) {\n return (\n <p className=\"rounded-lg border border-border-seam bg-bg-sunken p-3 text-sm text-text-secondary\">\n {tr('coolandlovely.storePiece.soldOut', 'This piece is sold out right now.')}\n </p>\n );\n }\n\n const needsSize = piece.sizes.length > 0 && !size;\n const needsColour = piece.colours.length > 0 && !colour;\n const left = needsSize || needsColour ? null : unitsLeft(piece, size ?? '', colour ?? '');\n const soldOut = left !== null && left <= 0;\n const maxQuantity = left === null ? MAX_QUANTITY : Math.max(1, Math.min(MAX_QUANTITY, left));\n const canSubmit =\n !needsSize &&\n !needsColour &&\n !soldOut &&\n shippingName.trim() !== '' &&\n shippingAddress.trim() !== '';\n\n const submit = () => {\n buy.mutate(\n {\n styleItemId: piece.id,\n quantity,\n size,\n colour,\n shippingName: shippingName.trim(),\n shippingAddress: shippingAddress.trim(),\n buyerNote: buyerNote.trim() || null,\n },\n { onSuccess: onCheckout }\n );\n };\n\n return (\n <div className=\"space-y-4\" data-testid=\"store-buy-panel\">\n {piece.sizes.length > 0 && (\n <div>\n <p className=\"mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n {tr('coolandlovely.cart.chooseSize', 'Choose a size')}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {piece.sizes.map((option) => (\n <button\n key={option}\n type=\"button\"\n aria-pressed={size === option}\n disabled={unitsLeft(piece, option, colour) === 0}\n onClick={() => {\n setSize(option);\n setQuantity(1);\n }}\n className={chip(size === option)}\n >\n {option}\n </button>\n ))}\n </div>\n </div>\n )}\n {piece.colours.length > 0 && (\n <div>\n <p className=\"mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n {tr('coolandlovely.cart.chooseColour', 'Choose a colour')}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {piece.colours.map((option) => (\n <button\n key={option}\n type=\"button\"\n aria-pressed={colour === option}\n disabled={unitsLeft(piece, size, option) === 0}\n onClick={() => {\n setColour(option);\n setQuantity(1);\n }}\n className={chip(colour === option)}\n >\n {option}\n </button>\n ))}\n </div>\n </div>\n )}\n <div className=\"flex items-center gap-3\">\n <label htmlFor=\"coo-store-quantity\" className=\"text-sm text-text-secondary\">\n {tr('coolandlovely.cart.quantity', 'Quantity')}\n </label>\n <select\n id=\"coo-store-quantity\"\n value={quantity}\n onChange={(event) => setQuantity(Number(event.target.value))}\n className=\"rounded-lg border border-border-seam bg-bg-surface px-2 py-1.5 text-sm text-text-primary\"\n >\n {Array.from({ length: maxQuantity }, (_, index) => index + 1).map((value) => (\n <option key={value} value={value}>\n {value}\n </option>\n ))}\n </select>\n </div>\n {left !== null && (\n <p\n data-testid=\"store-stock-left\"\n className={cn(\n 'text-sm font-medium',\n soldOut || left <= LOW_STOCK ? 'text-status-warning-text' : 'text-text-secondary'\n )}\n >\n {soldOut\n ? tr('coolandlovely.cart.soldOut', 'Sold out in this size and colour')\n : left <= LOW_STOCK\n ? tr('coolandlovely.cart.onlyLeft', 'Only {{count}} left', { count: left })\n : tr('coolandlovely.cart.inStock', 'In stock')}\n </p>\n )}\n <div className=\"space-y-3 border-t border-border-seam pt-4\">\n <TextField\n id=\"coo-store-shipping-name\"\n label={tr('coolandlovely.checkout.shippingName', 'Full name')}\n value={shippingName}\n onChange={setShippingName}\n required\n />\n <TextAreaField\n id=\"coo-store-shipping-address\"\n label={tr('coolandlovely.checkout.shippingAddress', 'Shipping address')}\n value={shippingAddress}\n onChange={setShippingAddress}\n rows={3}\n required\n />\n <TextField\n id=\"coo-store-buyer-note\"\n label={tr('coolandlovely.checkout.note', 'Note for the brand (optional)')}\n value={buyerNote}\n onChange={setBuyerNote}\n />\n </div>\n <p className=\"text-xs text-text-secondary\">\n {tr('coolandlovely.cart.taxNote', 'Tax is calculated when you place the order.')}\n </p>\n {buy.error && <p className=\"text-sm text-status-error-text\">{buy.error.message}</p>}\n <button\n type=\"button\"\n disabled={!canSubmit || buy.isPending}\n onClick={submit}\n className={primaryButton}\n >\n {buy.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <ShoppingBag className=\"h-4 w-4\" />\n )}\n {tr('coolandlovely.storePiece.buyNow', 'Buy now · {{amount}}', {\n amount: formatPrice(piece.price * quantity, piece.currency),\n })}\n </button>\n </div>\n );\n};\n\n/** Pay for the order the store purchase created. */\nconst PayForStorePurchase: FC<{ session: CooOrderCheckout }> = ({ session }) => {\n const tr = useTr();\n const { navigateTo } = useCoolAndLovely();\n const sync = useSyncOrderPayment();\n const settle = async () => {\n await sync.mutateAsync(session.order.id).catch(() => undefined);\n navigateTo(`/orders/${session.order.id}`);\n };\n return (\n <PageLayout\n title={tr('coolandlovely.checkout.payTitle', 'Pay for your order')}\n description={session.order.orderNumber}\n >\n <div className=\"mx-auto max-w-lg space-y-4\">\n <GlassCard treatment=\"glass\" className=\"space-y-4 p-6\">\n <dl className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">\n {tr('coolandlovely.checkout.subtotal', 'Subtotal')}\n </dt>\n <dd className=\"tabular-nums text-text-primary\">\n {formatPrice(session.subtotal, session.currency)}\n </dd>\n </div>\n <div className=\"flex justify-between\">\n <dt className=\"text-text-secondary\">{tr('coolandlovely.checkout.tax', 'Tax')}</dt>\n <dd className=\"tabular-nums text-text-primary\">\n {formatPrice(session.taxAmount, session.currency)}\n </dd>\n </div>\n <div className=\"flex justify-between border-t border-border-seam pt-2 text-base font-semibold\">\n <dt className=\"text-text-primary\">{tr('coolandlovely.checkout.total', 'Total')}</dt>\n <dd className=\"tabular-nums text-text-primary\" data-testid=\"store-checkout-total\">\n {formatPrice(session.total, session.currency)}\n </dd>\n </div>\n </dl>\n <PayForOrder checkout={session} onSettle={settle} />\n <button\n type=\"button\"\n onClick={() => navigateTo(`/orders/${session.order.id}`)}\n className=\"w-full text-center text-sm font-medium text-text-secondary hover:underline\"\n >\n {tr('coolandlovely.checkout.payLater', 'Pay later from My Orders')}\n </button>\n </GlassCard>\n </div>\n </PageLayout>\n );\n};\n\n/**\n * The fallback piece page for a store shopper. Renders \"Item not found\" when the store does not\n * list the piece either (drafts, retired pieces, pieces of unpublished brands).\n */\nexport const StoreListedPieceView: FC<{ itemId: string | undefined; onRetry: () => void }> = ({\n itemId,\n onRetry,\n}) => {\n const tr = useTr();\n const { navigateTo } = useCoolAndLovely();\n const query = useStoreListedPiece(itemId, true);\n const [session, setSession] = useState<CooOrderCheckout | null>(null);\n const pageTitle = tr('coolandlovely.storePiece.pageTitle', 'Style item');\n\n if (session) return <PayForStorePurchase session={session} />;\n\n if (query.isLoading) {\n return (\n <PageLayout title={pageTitle}>\n <LoadingView label={tr('coolandlovely.storePiece.loading', 'Loading item…')} />\n </PageLayout>\n );\n }\n\n const piece = query.data;\n if (query.isError || !piece) {\n return (\n <PageLayout title={pageTitle}>\n <ErrorView\n title={tr('coolandlovely.storePiece.notFound', 'Item not found')}\n onRetry={() => {\n onRetry();\n void query.refetch();\n }}\n />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={piece.name}\n description={piece.brandName}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/discover')}\n className=\"inline-flex items-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\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> {tr('coolandlovely.storePiece.back', 'Discover')}\n </button>\n }\n >\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\" data-testid=\"store-listed-piece\">\n <div className=\"lg:col-span-2\">\n <GlassCard treatment=\"glass\" className=\"overflow-hidden p-0\">\n <Thumbnail\n icon={categoryIcon(piece.category, 48)}\n seed={piece.id}\n alt={piece.name}\n className=\"aspect-[4/5] w-full\"\n />\n {piece.description && (\n <div className=\"p-6\">\n <p className=\"text-sm leading-relaxed text-text-secondary\">{piece.description}</p>\n </div>\n )}\n </GlassCard>\n </div>\n\n <div className=\"space-y-4\">\n <GlassCard treatment=\"glass\" className=\"space-y-5 p-6\">\n <div>\n <p className=\"inline-flex items-center gap-1.5 text-xs font-medium text-accent-primary\">\n <Store className=\"h-3.5 w-3.5\" />\n {tr('coolandlovely.storePiece.fromStore', 'Listed in the Burdenoff store')}\n </p>\n <h2 className=\"mt-2 text-2xl font-semibold leading-tight text-text-primary\">\n {piece.name}\n </h2>\n <p className=\"mt-1 text-sm font-medium text-text-secondary\">\n {piece.brandName}\n <span className=\"ml-1 text-text-tertiary\">@{piece.brandHandle}</span>\n </p>\n <p className=\"mt-3 text-3xl font-bold text-text-primary tabular-nums\">\n {formatPrice(piece.price, piece.currency)}\n <span className=\"ml-2 text-base font-medium text-text-secondary\">\n {piece.currency}\n </span>\n </p>\n </div>\n {piece.colours.length > 0 && <ColourSwatchRow colours={piece.colours} max={12} />}\n <div className=\"border-t border-border-seam pt-5\">\n <BuyListedPiecePanel piece={piece} onCheckout={setSession} />\n </div>\n {piece.materials.length > 0 && (\n <div>\n <p className=\"mb-1 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n {tr('coolandlovely.storePiece.materials', 'Materials')}\n </p>\n <p className=\"text-sm text-text-primary\">{piece.materials.join(', ')}</p>\n </div>\n )}\n {piece.tags.length > 0 && <TagList tags={piece.tags} max={12} tone=\"accent\" />}\n </GlassCard>\n\n <GlassCard treatment=\"plain\" className=\"p-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">\n {tr('coolandlovely.storePiece.details', 'Details')}\n </h3>\n <dl className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">\n {tr('coolandlovely.storePiece.category', 'Category')}\n </dt>\n <dd className=\"text-text-primary\">{titleCase(piece.category)}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">SKU</dt>\n <dd className=\"text-text-primary\">{piece.sku ?? '—'}</dd>\n </div>\n </dl>\n <p className=\"mt-3 text-xs text-text-secondary\">\n {tr(\n 'coolandlovely.storePiece.soldBy',\n 'Sold and shipped by {{brand}}. Your order appears in My Orders.',\n { brand: piece.brandName }\n )}\n </p>\n </GlassCard>\n </div>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Renders a single catalogue piece (`cooStyleItem`) with edit + archive
|
|
6
6
|
* (`cooArchiveStyleItem`) actions and its Burdenoff store listing state.
|
|
7
|
+
*
|
|
8
|
+
* A shopper who follows a Burdenoff store listing to a brand outside their
|
|
9
|
+
* workspace finds no such piece in the workspace catalogue; the page then
|
|
10
|
+
* falls back to the store-listed piece view, where they can buy it (BOFF-10017).
|
|
7
11
|
*/
|
|
8
12
|
export declare function StyleItemDetailPage(): import("react").JSX.Element;
|
|
9
13
|
//# sourceMappingURL=StyleItemDetailPage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StyleItemDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/items/StyleItemDetailPage.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"StyleItemDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/items/StyleItemDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA0BH,wBAAgB,mBAAmB,gCA2QlC"}
|
|
@@ -14,195 +14,200 @@ import { TagList as g } from "../../components/TagList.js";
|
|
|
14
14
|
import { ColourSwatchRow as _ } from "../../components/ColourSwatchRow.js";
|
|
15
15
|
import { StoreListingCard as v } from "../../components/StoreListingCard.js";
|
|
16
16
|
import { AddToCartPanel as y } from "../../components/AddToCartPanel.js";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
17
|
+
import { StoreListedPieceView as b } from "./StoreListedPieceView.js";
|
|
18
|
+
import { Archive as x, ArrowLeft as S, ChevronRight as C, Loader2 as w, Pencil as T, Shapes as E } from "lucide-react";
|
|
19
|
+
import { useParams as D, useSearchParams as O } from "react-router";
|
|
20
|
+
import { jsx as k, jsxs as A } from "react/jsx-runtime";
|
|
21
|
+
import { GlassCard as j } from "@burdenoff/fe-libs/ui";
|
|
21
22
|
//#region src/coolandlovely/pages/items/StyleItemDetailPage.tsx
|
|
22
|
-
function
|
|
23
|
-
let { itemId:
|
|
23
|
+
function M() {
|
|
24
|
+
let { itemId: M } = D(), [N] = O(), P = N.get("look"), { navigateTo: F } = e(), I = i(M), L = r({ pagination: {
|
|
24
25
|
limit: 100,
|
|
25
26
|
offset: 0
|
|
26
|
-
} }),
|
|
27
|
-
if (a(
|
|
27
|
+
} }), R = n();
|
|
28
|
+
if (a(M, I.data?.name), I.isLoading) return /* @__PURE__ */ k(t, {
|
|
28
29
|
title: "Style item",
|
|
29
|
-
children: /* @__PURE__ */
|
|
30
|
+
children: /* @__PURE__ */ k(c, { label: "Loading item…" })
|
|
30
31
|
});
|
|
31
|
-
if (
|
|
32
|
+
if (!I.isError && !I.data) return /* @__PURE__ */ k(b, {
|
|
33
|
+
itemId: M,
|
|
34
|
+
onRetry: () => void I.refetch()
|
|
35
|
+
});
|
|
36
|
+
if (I.isError || !I.data) return /* @__PURE__ */ k(t, {
|
|
32
37
|
title: "Style item",
|
|
33
|
-
children: /* @__PURE__ */
|
|
38
|
+
children: /* @__PURE__ */ k(s, {
|
|
34
39
|
title: "Item not found",
|
|
35
|
-
onRetry: () => void
|
|
40
|
+
onRetry: () => void I.refetch()
|
|
36
41
|
})
|
|
37
42
|
});
|
|
38
|
-
let
|
|
39
|
-
return /* @__PURE__ */
|
|
40
|
-
title:
|
|
41
|
-
description:
|
|
42
|
-
actions: /* @__PURE__ */
|
|
43
|
+
let z = I.data, B = z.status === "RETIRED", V = (L.data?.items ?? []).filter((e) => e.items?.some((e) => e.styleItemId === z.id)).slice(0, 4);
|
|
44
|
+
return /* @__PURE__ */ A(t, {
|
|
45
|
+
title: z.name,
|
|
46
|
+
description: z.brand?.name ?? void 0,
|
|
47
|
+
actions: /* @__PURE__ */ A("div", {
|
|
43
48
|
className: "flex flex-wrap items-center gap-2",
|
|
44
49
|
children: [
|
|
45
|
-
/* @__PURE__ */
|
|
50
|
+
/* @__PURE__ */ A("button", {
|
|
46
51
|
type: "button",
|
|
47
|
-
onClick: () =>
|
|
52
|
+
onClick: () => F("/items"),
|
|
48
53
|
className: "inline-flex items-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",
|
|
49
|
-
children: [/* @__PURE__ */
|
|
54
|
+
children: [/* @__PURE__ */ k(S, { className: "h-4 w-4" }), " Back"]
|
|
50
55
|
}),
|
|
51
|
-
/* @__PURE__ */
|
|
52
|
-
/* @__PURE__ */
|
|
56
|
+
/* @__PURE__ */ k(u, { styleItemId: z.id }),
|
|
57
|
+
/* @__PURE__ */ A("button", {
|
|
53
58
|
type: "button",
|
|
54
|
-
onClick: () =>
|
|
59
|
+
onClick: () => F(`/items/${z.id}/edit`),
|
|
55
60
|
className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90",
|
|
56
|
-
children: [/* @__PURE__ */
|
|
61
|
+
children: [/* @__PURE__ */ k(T, { className: "h-4 w-4" }), " Edit"]
|
|
57
62
|
}),
|
|
58
|
-
!
|
|
63
|
+
!B && /* @__PURE__ */ A("button", {
|
|
59
64
|
type: "button",
|
|
60
|
-
disabled:
|
|
61
|
-
onClick: () =>
|
|
65
|
+
disabled: R.isPending,
|
|
66
|
+
onClick: () => R.mutate(z.id, { onSuccess: () => F("/items") }),
|
|
62
67
|
className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-50",
|
|
63
|
-
children: [
|
|
68
|
+
children: [R.isPending ? /* @__PURE__ */ k(w, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ k(x, { className: "h-4 w-4" }), "Archive"]
|
|
64
69
|
})
|
|
65
70
|
]
|
|
66
71
|
}),
|
|
67
|
-
children: [/* @__PURE__ */
|
|
72
|
+
children: [/* @__PURE__ */ A("div", {
|
|
68
73
|
className: "grid grid-cols-1 gap-6 lg:grid-cols-3",
|
|
69
|
-
children: [/* @__PURE__ */
|
|
74
|
+
children: [/* @__PURE__ */ k("div", {
|
|
70
75
|
className: "lg:col-span-2",
|
|
71
|
-
children: /* @__PURE__ */
|
|
76
|
+
children: /* @__PURE__ */ A(j, {
|
|
72
77
|
treatment: "glass",
|
|
73
78
|
className: "group overflow-hidden p-0",
|
|
74
|
-
children: [/* @__PURE__ */
|
|
75
|
-
icon: h(
|
|
76
|
-
seed:
|
|
77
|
-
fileId:
|
|
78
|
-
alt:
|
|
79
|
+
children: [/* @__PURE__ */ k(l, {
|
|
80
|
+
icon: h(z.category, 48),
|
|
81
|
+
seed: z.id,
|
|
82
|
+
fileId: z.image?.id,
|
|
83
|
+
alt: z.name,
|
|
79
84
|
className: "aspect-[4/5] w-full"
|
|
80
|
-
}),
|
|
85
|
+
}), z.description && /* @__PURE__ */ k("div", {
|
|
81
86
|
className: "p-6",
|
|
82
|
-
children: /* @__PURE__ */
|
|
87
|
+
children: /* @__PURE__ */ k("p", {
|
|
83
88
|
className: "text-sm leading-relaxed text-text-secondary",
|
|
84
|
-
children:
|
|
89
|
+
children: z.description
|
|
85
90
|
})
|
|
86
91
|
})]
|
|
87
92
|
})
|
|
88
|
-
}), /* @__PURE__ */
|
|
93
|
+
}), /* @__PURE__ */ A("div", {
|
|
89
94
|
className: "space-y-4",
|
|
90
95
|
children: [
|
|
91
|
-
/* @__PURE__ */
|
|
96
|
+
/* @__PURE__ */ A(j, {
|
|
92
97
|
treatment: "glass",
|
|
93
98
|
className: "space-y-5 p-6",
|
|
94
99
|
children: [
|
|
95
|
-
/* @__PURE__ */
|
|
96
|
-
/* @__PURE__ */
|
|
100
|
+
/* @__PURE__ */ A("div", { children: [
|
|
101
|
+
/* @__PURE__ */ k("h2", {
|
|
97
102
|
className: "text-2xl font-semibold leading-tight text-text-primary",
|
|
98
|
-
children:
|
|
103
|
+
children: z.name
|
|
99
104
|
}),
|
|
100
|
-
|
|
105
|
+
z.brand && /* @__PURE__ */ A("button", {
|
|
101
106
|
type: "button",
|
|
102
|
-
onClick: () =>
|
|
107
|
+
onClick: () => F(`/brands/${z.brand?.id}`),
|
|
103
108
|
className: "mt-1 inline-flex items-center gap-0.5 text-sm font-medium text-action-primary-bg hover:underline",
|
|
104
|
-
children: [
|
|
109
|
+
children: [z.brand.name, /* @__PURE__ */ k(C, { className: "h-3.5 w-3.5" })]
|
|
105
110
|
}),
|
|
106
|
-
/* @__PURE__ */
|
|
111
|
+
/* @__PURE__ */ A("div", {
|
|
107
112
|
className: "mt-3 flex flex-wrap items-center justify-between gap-2",
|
|
108
|
-
children: [/* @__PURE__ */
|
|
113
|
+
children: [/* @__PURE__ */ A("p", {
|
|
109
114
|
className: "text-3xl font-bold text-text-primary tabular-nums",
|
|
110
|
-
children: [f(
|
|
115
|
+
children: [f(z.price, z.currency), /* @__PURE__ */ k("span", {
|
|
111
116
|
className: "ml-2 text-base font-medium text-text-secondary",
|
|
112
|
-
children:
|
|
117
|
+
children: z.currency
|
|
113
118
|
})]
|
|
114
|
-
}), /* @__PURE__ */
|
|
119
|
+
}), /* @__PURE__ */ k(o, { status: z.status })]
|
|
115
120
|
})
|
|
116
121
|
] }),
|
|
117
|
-
/* @__PURE__ */
|
|
118
|
-
|
|
122
|
+
/* @__PURE__ */ k("div", { className: "border-t border-border-seam" }),
|
|
123
|
+
z.colours.length > 0 && /* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("p", {
|
|
119
124
|
className: "mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
120
125
|
children: "Colours"
|
|
121
|
-
}), /* @__PURE__ */
|
|
122
|
-
colours:
|
|
126
|
+
}), /* @__PURE__ */ k(_, {
|
|
127
|
+
colours: z.colours,
|
|
123
128
|
max: 12
|
|
124
129
|
})] }),
|
|
125
|
-
|
|
130
|
+
z.sizes.length > 0 && /* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("p", {
|
|
126
131
|
className: "mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
127
132
|
children: "Size"
|
|
128
|
-
}), /* @__PURE__ */
|
|
133
|
+
}), /* @__PURE__ */ k("div", {
|
|
129
134
|
className: "flex flex-wrap gap-2",
|
|
130
|
-
children:
|
|
135
|
+
children: z.sizes.map((e) => /* @__PURE__ */ k("span", {
|
|
131
136
|
className: "inline-flex min-w-9 items-center justify-center rounded-full border border-border-seam px-3 py-1 text-sm font-medium text-text-primary",
|
|
132
137
|
children: e
|
|
133
138
|
}, e))
|
|
134
139
|
})] }),
|
|
135
|
-
/* @__PURE__ */
|
|
140
|
+
/* @__PURE__ */ k("div", {
|
|
136
141
|
className: "border-t border-border-seam pt-5",
|
|
137
|
-
children: /* @__PURE__ */
|
|
138
|
-
item:
|
|
139
|
-
lookId:
|
|
142
|
+
children: /* @__PURE__ */ k(y, {
|
|
143
|
+
item: z,
|
|
144
|
+
lookId: P
|
|
140
145
|
})
|
|
141
146
|
}),
|
|
142
|
-
|
|
147
|
+
z.materials.length > 0 && /* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("p", {
|
|
143
148
|
className: "mb-1 text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
144
149
|
children: "Materials"
|
|
145
|
-
}), /* @__PURE__ */
|
|
150
|
+
}), /* @__PURE__ */ k("p", {
|
|
146
151
|
className: "text-sm text-text-primary",
|
|
147
|
-
children:
|
|
152
|
+
children: z.materials.join(", ")
|
|
148
153
|
})] }),
|
|
149
|
-
|
|
154
|
+
z.tags.length > 0 && /* @__PURE__ */ A("div", { children: [/* @__PURE__ */ k("p", {
|
|
150
155
|
className: "mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
151
156
|
children: "Tags"
|
|
152
|
-
}), /* @__PURE__ */
|
|
153
|
-
tags:
|
|
157
|
+
}), /* @__PURE__ */ k(g, {
|
|
158
|
+
tags: z.tags,
|
|
154
159
|
max: 12,
|
|
155
160
|
tone: "accent"
|
|
156
161
|
})] })
|
|
157
162
|
]
|
|
158
163
|
}),
|
|
159
|
-
/* @__PURE__ */
|
|
164
|
+
/* @__PURE__ */ A(j, {
|
|
160
165
|
treatment: "plain",
|
|
161
166
|
className: "p-5",
|
|
162
|
-
children: [/* @__PURE__ */
|
|
167
|
+
children: [/* @__PURE__ */ k("h3", {
|
|
163
168
|
className: "mb-3 text-sm font-semibold text-text-primary",
|
|
164
169
|
children: "Details"
|
|
165
|
-
}), /* @__PURE__ */
|
|
170
|
+
}), /* @__PURE__ */ A("dl", {
|
|
166
171
|
className: "space-y-2 text-sm",
|
|
167
172
|
children: [
|
|
168
|
-
/* @__PURE__ */
|
|
173
|
+
/* @__PURE__ */ A("div", {
|
|
169
174
|
className: "flex justify-between gap-2",
|
|
170
|
-
children: [/* @__PURE__ */
|
|
175
|
+
children: [/* @__PURE__ */ k("dt", {
|
|
171
176
|
className: "text-text-secondary",
|
|
172
177
|
children: "Category"
|
|
173
|
-
}), /* @__PURE__ */
|
|
178
|
+
}), /* @__PURE__ */ k("dd", {
|
|
174
179
|
className: "text-text-primary",
|
|
175
|
-
children: p(
|
|
180
|
+
children: p(z.category)
|
|
176
181
|
})]
|
|
177
182
|
}),
|
|
178
|
-
/* @__PURE__ */
|
|
183
|
+
/* @__PURE__ */ A("div", {
|
|
179
184
|
className: "flex justify-between gap-2",
|
|
180
|
-
children: [/* @__PURE__ */
|
|
185
|
+
children: [/* @__PURE__ */ k("dt", {
|
|
181
186
|
className: "text-text-secondary",
|
|
182
187
|
children: "SKU"
|
|
183
|
-
}), /* @__PURE__ */
|
|
188
|
+
}), /* @__PURE__ */ k("dd", {
|
|
184
189
|
className: "text-text-primary",
|
|
185
|
-
children:
|
|
190
|
+
children: z.sku ?? "—"
|
|
186
191
|
})]
|
|
187
192
|
}),
|
|
188
|
-
/* @__PURE__ */
|
|
193
|
+
/* @__PURE__ */ A("div", {
|
|
189
194
|
className: "flex justify-between gap-2",
|
|
190
|
-
children: [/* @__PURE__ */
|
|
195
|
+
children: [/* @__PURE__ */ k("dt", {
|
|
191
196
|
className: "text-text-secondary",
|
|
192
197
|
children: "Currency"
|
|
193
|
-
}), /* @__PURE__ */
|
|
198
|
+
}), /* @__PURE__ */ k("dd", {
|
|
194
199
|
className: "text-text-primary",
|
|
195
|
-
children:
|
|
200
|
+
children: z.currency
|
|
196
201
|
})]
|
|
197
202
|
}),
|
|
198
|
-
/* @__PURE__ */
|
|
203
|
+
/* @__PURE__ */ A("div", {
|
|
199
204
|
className: "flex justify-between gap-2",
|
|
200
|
-
children: [/* @__PURE__ */
|
|
205
|
+
children: [/* @__PURE__ */ k("dt", {
|
|
201
206
|
className: "text-text-secondary",
|
|
202
207
|
children: "Created"
|
|
203
|
-
}), /* @__PURE__ */
|
|
208
|
+
}), /* @__PURE__ */ k("dd", {
|
|
204
209
|
className: "text-text-primary",
|
|
205
|
-
children: d(
|
|
210
|
+
children: d(z.createdAt, {
|
|
206
211
|
hour: void 0,
|
|
207
212
|
minute: void 0
|
|
208
213
|
})
|
|
@@ -211,21 +216,21 @@ function j() {
|
|
|
211
216
|
]
|
|
212
217
|
})]
|
|
213
218
|
}),
|
|
214
|
-
/* @__PURE__ */
|
|
215
|
-
|
|
219
|
+
/* @__PURE__ */ k(v, { item: z }),
|
|
220
|
+
z.collection && /* @__PURE__ */ A("button", {
|
|
216
221
|
type: "button",
|
|
217
|
-
onClick: () =>
|
|
222
|
+
onClick: () => F(`/collections/${z.collection?.id}`),
|
|
218
223
|
className: "flex w-full items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken/50",
|
|
219
|
-
children: [/* @__PURE__ */
|
|
220
|
-
icon: /* @__PURE__ */
|
|
221
|
-
seed:
|
|
224
|
+
children: [/* @__PURE__ */ k(l, {
|
|
225
|
+
icon: /* @__PURE__ */ k(E, { className: "h-5 w-5" }),
|
|
226
|
+
seed: z.collection.id,
|
|
222
227
|
className: "h-10 w-10 shrink-0"
|
|
223
|
-
}), /* @__PURE__ */
|
|
228
|
+
}), /* @__PURE__ */ A("div", {
|
|
224
229
|
className: "min-w-0",
|
|
225
|
-
children: [/* @__PURE__ */
|
|
230
|
+
children: [/* @__PURE__ */ k("p", {
|
|
226
231
|
className: "truncate text-sm font-medium text-text-primary",
|
|
227
|
-
children:
|
|
228
|
-
}), /* @__PURE__ */
|
|
232
|
+
children: z.collection.name
|
|
233
|
+
}), /* @__PURE__ */ k("p", {
|
|
229
234
|
className: "truncate text-xs text-text-secondary",
|
|
230
235
|
children: "View collection"
|
|
231
236
|
})]
|
|
@@ -233,28 +238,28 @@ function j() {
|
|
|
233
238
|
})
|
|
234
239
|
]
|
|
235
240
|
})]
|
|
236
|
-
}), /* @__PURE__ */
|
|
241
|
+
}), /* @__PURE__ */ A("section", {
|
|
237
242
|
className: "mt-8",
|
|
238
|
-
children: [/* @__PURE__ */
|
|
243
|
+
children: [/* @__PURE__ */ A("div", {
|
|
239
244
|
className: "mb-3 flex items-center justify-between gap-3",
|
|
240
|
-
children: [/* @__PURE__ */
|
|
245
|
+
children: [/* @__PURE__ */ k("h3", {
|
|
241
246
|
className: "text-lg font-semibold text-text-primary",
|
|
242
247
|
children: "Appears in looks"
|
|
243
|
-
}),
|
|
248
|
+
}), V.length > 0 && /* @__PURE__ */ A("button", {
|
|
244
249
|
type: "button",
|
|
245
|
-
onClick: () =>
|
|
250
|
+
onClick: () => F("/looks"),
|
|
246
251
|
className: "inline-flex items-center gap-1 text-sm font-medium text-action-primary-bg hover:underline",
|
|
247
|
-
children: ["View all ", /* @__PURE__ */
|
|
252
|
+
children: ["View all ", /* @__PURE__ */ k(C, { className: "h-3.5 w-3.5" })]
|
|
248
253
|
})]
|
|
249
|
-
}),
|
|
254
|
+
}), L.isLoading ? /* @__PURE__ */ A("div", {
|
|
250
255
|
className: "flex items-center gap-2 rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary",
|
|
251
|
-
children: [/* @__PURE__ */
|
|
252
|
-
}) :
|
|
256
|
+
children: [/* @__PURE__ */ k(w, { className: "h-4 w-4 animate-spin" }), " Loading referenced looks…"]
|
|
257
|
+
}) : V.length === 0 ? /* @__PURE__ */ k("p", {
|
|
253
258
|
className: "rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary",
|
|
254
259
|
children: "This piece has not been tagged in any looks yet."
|
|
255
|
-
}) : /* @__PURE__ */
|
|
260
|
+
}) : /* @__PURE__ */ k("div", {
|
|
256
261
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
257
|
-
children:
|
|
262
|
+
children: V.map((e) => /* @__PURE__ */ k(m, {
|
|
258
263
|
id: e.id,
|
|
259
264
|
title: e.title,
|
|
260
265
|
occasion: e.occasion,
|
|
@@ -262,7 +267,7 @@ function j() {
|
|
|
262
267
|
likeCount: e.likeCount,
|
|
263
268
|
isLikedByMe: e.isLikedByMe,
|
|
264
269
|
isSavedByMe: e.isSavedByMe,
|
|
265
|
-
onOpen: () =>
|
|
270
|
+
onOpen: () => F(`/looks/${e.id}`),
|
|
266
271
|
showActions: !0
|
|
267
272
|
}, e.id))
|
|
268
273
|
})]
|
|
@@ -270,6 +275,6 @@ function j() {
|
|
|
270
275
|
});
|
|
271
276
|
}
|
|
272
277
|
//#endregion
|
|
273
|
-
export {
|
|
278
|
+
export { M as StyleItemDetailPage };
|
|
274
279
|
|
|
275
280
|
//# sourceMappingURL=StyleItemDetailPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StyleItemDetailPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/items/StyleItemDetailPage.tsx"],"sourcesContent":["/**\n * Style Item Detail Page\n * @module coolandlovely/pages/items\n *\n * Renders a single catalogue piece (`cooStyleItem`) with edit + archive\n * (`cooArchiveStyleItem`) actions and its Burdenoff store listing state.\n */\n\nimport { useParams, useSearchParams } from 'react-router';\nimport { ArrowLeft, Pencil, Archive, Loader2, ChevronRight, Shapes } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { LookCard } from '../../components/LookCard';\nimport { TagList } from '../../components/TagList';\nimport { ColourSwatchRow } from '../../components/ColourSwatchRow';\nimport { AddToLookbookButton } from '../../components/AddToLookbookButton';\nimport { AddToCartPanel } from '../../components/AddToCartPanel';\nimport { StoreListingCard } from '../../components/StoreListingCard';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport {\n useAssistantEntityName,\n useStyleItem,\n useArchiveStyleItem,\n useLooksWithItems,\n} from '../../hooks';\nimport { categoryIcon } from '../../utils/icons';\nimport { formatPrice, formatDate, titleCase } from '../../utils/formatters';\n\nexport function StyleItemDetailPage() {\n const { itemId } = useParams<{ itemId: string }>();\n // \"Shop the look\" links carry the look id so the look's creator earns the commission.\n const [searchParams] = useSearchParams();\n const fromLookId = searchParams.get('look');\n const { navigateTo } = useCoolAndLovely();\n const query = useStyleItem(itemId);\n const looksQuery = useLooksWithItems({ pagination: { limit: 100, offset: 0 } });\n const archive = useArchiveStyleItem();\n // Name the piece for the assistant's screen context (see useAssistantEntity).\n useAssistantEntityName(itemId, query.data?.name);\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Style item\">\n <LoadingView label=\"Loading item…\" />\n </PageLayout>\n );\n }\n\n if (query.isError || !query.data) {\n return (\n <PageLayout title=\"Style item\">\n <ErrorView title=\"Item not found\" onRetry={() => void query.refetch()} />\n </PageLayout>\n );\n }\n\n const item = query.data;\n const isArchived = item.status === 'RETIRED';\n const appearsInLooks = (looksQuery.data?.items ?? [])\n .filter((look) => look.items?.some((lookItem) => lookItem.styleItemId === item.id))\n .slice(0, 4);\n\n return (\n <PageLayout\n title={item.name}\n description={item.brand?.name ?? undefined}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/items')}\n className=\"inline-flex items-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\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n <AddToLookbookButton styleItemId={item.id} />\n <button\n type=\"button\"\n onClick={() => navigateTo(`/items/${item.id}/edit`)}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n <Pencil className=\"h-4 w-4\" /> Edit\n </button>\n {!isArchived && (\n <button\n type=\"button\"\n disabled={archive.isPending}\n onClick={() => archive.mutate(item.id, { onSuccess: () => navigateTo('/items') })}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-50\"\n >\n {archive.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Archive className=\"h-4 w-4\" />\n )}\n Archive\n </button>\n )}\n </div>\n }\n >\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Product image */}\n <div className=\"lg:col-span-2\">\n <GlassCard treatment=\"glass\" className=\"group overflow-hidden p-0\">\n <Thumbnail\n icon={categoryIcon(item.category, 48)}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"aspect-[4/5] w-full\"\n />\n {item.description && (\n <div className=\"p-6\">\n <p className=\"text-sm leading-relaxed text-text-secondary\">{item.description}</p>\n </div>\n )}\n </GlassCard>\n </div>\n\n {/* Product panel */}\n <div className=\"space-y-4\">\n <GlassCard treatment=\"glass\" className=\"space-y-5 p-6\">\n <div>\n <h2 className=\"text-2xl font-semibold leading-tight text-text-primary\">\n {item.name}\n </h2>\n {item.brand && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/brands/${item.brand?.id}`)}\n className=\"mt-1 inline-flex items-center gap-0.5 text-sm font-medium text-action-primary-bg hover:underline\"\n >\n {item.brand.name}\n <ChevronRight className=\"h-3.5 w-3.5\" />\n </button>\n )}\n <div className=\"mt-3 flex flex-wrap items-center justify-between gap-2\">\n <p className=\"text-3xl font-bold text-text-primary tabular-nums\">\n {formatPrice(item.price, item.currency)}\n <span className=\"ml-2 text-base font-medium text-text-secondary\">\n {item.currency}\n </span>\n </p>\n <StatusBadge status={item.status} />\n </div>\n </div>\n\n <div className=\"border-t border-border-seam\" />\n\n {item.colours.length > 0 && (\n <div>\n <p className=\"mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Colours\n </p>\n <ColourSwatchRow colours={item.colours} max={12} />\n </div>\n )}\n\n {item.sizes.length > 0 && (\n <div>\n <p className=\"mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Size\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {item.sizes.map((size) => (\n <span\n key={size}\n className=\"inline-flex min-w-9 items-center justify-center rounded-full border border-border-seam px-3 py-1 text-sm font-medium text-text-primary\"\n >\n {size}\n </span>\n ))}\n </div>\n </div>\n )}\n\n <div className=\"border-t border-border-seam pt-5\">\n <AddToCartPanel item={item} lookId={fromLookId} />\n </div>\n\n {item.materials.length > 0 && (\n <div>\n <p className=\"mb-1 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Materials\n </p>\n <p className=\"text-sm text-text-primary\">{item.materials.join(', ')}</p>\n </div>\n )}\n\n {item.tags.length > 0 && (\n <div>\n <p className=\"mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Tags\n </p>\n <TagList tags={item.tags} max={12} tone=\"accent\" />\n </div>\n )}\n </GlassCard>\n\n <GlassCard treatment=\"plain\" className=\"p-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">Details</h3>\n <dl className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Category</dt>\n <dd className=\"text-text-primary\">{titleCase(item.category)}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">SKU</dt>\n <dd className=\"text-text-primary\">{item.sku ?? '—'}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Currency</dt>\n <dd className=\"text-text-primary\">{item.currency}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Created</dt>\n <dd className=\"text-text-primary\">\n {formatDate(item.createdAt, { hour: undefined, minute: undefined })}\n </dd>\n </div>\n </dl>\n </GlassCard>\n\n <StoreListingCard item={item} />\n\n {item.collection && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/collections/${item.collection?.id}`)}\n className=\"flex w-full items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <Thumbnail\n icon={<Shapes className=\"h-5 w-5\" />}\n seed={item.collection.id}\n className=\"h-10 w-10 shrink-0\"\n />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {item.collection.name}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">View collection</p>\n </div>\n </button>\n )}\n </div>\n </div>\n\n <section className=\"mt-8\">\n <div className=\"mb-3 flex items-center justify-between gap-3\">\n <h3 className=\"text-lg font-semibold text-text-primary\">Appears in looks</h3>\n {appearsInLooks.length > 0 && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/looks')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-action-primary-bg hover:underline\"\n >\n View all <ChevronRight className=\"h-3.5 w-3.5\" />\n </button>\n )}\n </div>\n {looksQuery.isLoading ? (\n <div className=\"flex items-center gap-2 rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n <Loader2 className=\"h-4 w-4 animate-spin\" /> Loading referenced looks…\n </div>\n ) : appearsInLooks.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n This piece has not been tagged in any looks yet.\n </p>\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {appearsInLooks.map((look) => (\n <LookCard\n key={look.id}\n id={look.id}\n title={look.title}\n occasion={look.occasion}\n imageFileId={look.image?.id}\n likeCount={look.likeCount}\n isLikedByMe={look.isLikedByMe}\n isSavedByMe={look.isSavedByMe}\n onOpen={() => navigateTo(`/looks/${look.id}`)}\n showActions\n />\n ))}\n </div>\n )}\n </section>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"StyleItemDetailPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/items/StyleItemDetailPage.tsx"],"sourcesContent":["/**\n * Style Item Detail Page\n * @module coolandlovely/pages/items\n *\n * Renders a single catalogue piece (`cooStyleItem`) with edit + archive\n * (`cooArchiveStyleItem`) actions and its Burdenoff store listing state.\n *\n * A shopper who follows a Burdenoff store listing to a brand outside their\n * workspace finds no such piece in the workspace catalogue; the page then\n * falls back to the store-listed piece view, where they can buy it (BOFF-10017).\n */\n\nimport { useParams, useSearchParams } from 'react-router';\nimport { ArrowLeft, Pencil, Archive, Loader2, ChevronRight, Shapes } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { LookCard } from '../../components/LookCard';\nimport { TagList } from '../../components/TagList';\nimport { ColourSwatchRow } from '../../components/ColourSwatchRow';\nimport { AddToLookbookButton } from '../../components/AddToLookbookButton';\nimport { AddToCartPanel } from '../../components/AddToCartPanel';\nimport { StoreListingCard } from '../../components/StoreListingCard';\nimport { StoreListedPieceView } from './StoreListedPieceView';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport {\n useAssistantEntityName,\n useStyleItem,\n useArchiveStyleItem,\n useLooksWithItems,\n} from '../../hooks';\nimport { categoryIcon } from '../../utils/icons';\nimport { formatPrice, formatDate, titleCase } from '../../utils/formatters';\n\nexport function StyleItemDetailPage() {\n const { itemId } = useParams<{ itemId: string }>();\n // \"Shop the look\" links carry the look id so the look's creator earns the commission.\n const [searchParams] = useSearchParams();\n const fromLookId = searchParams.get('look');\n const { navigateTo } = useCoolAndLovely();\n const query = useStyleItem(itemId);\n const looksQuery = useLooksWithItems({ pagination: { limit: 100, offset: 0 } });\n const archive = useArchiveStyleItem();\n // Name the piece for the assistant's screen context (see useAssistantEntity).\n useAssistantEntityName(itemId, query.data?.name);\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Style item\">\n <LoadingView label=\"Loading item…\" />\n </PageLayout>\n );\n }\n\n // Not in this workspace's catalogue: a store shopper from outside the brand's workspace.\n if (!query.isError && !query.data) {\n return <StoreListedPieceView itemId={itemId} onRetry={() => void query.refetch()} />;\n }\n\n if (query.isError || !query.data) {\n return (\n <PageLayout title=\"Style item\">\n <ErrorView title=\"Item not found\" onRetry={() => void query.refetch()} />\n </PageLayout>\n );\n }\n\n const item = query.data;\n const isArchived = item.status === 'RETIRED';\n const appearsInLooks = (looksQuery.data?.items ?? [])\n .filter((look) => look.items?.some((lookItem) => lookItem.styleItemId === item.id))\n .slice(0, 4);\n\n return (\n <PageLayout\n title={item.name}\n description={item.brand?.name ?? undefined}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/items')}\n className=\"inline-flex items-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\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n <AddToLookbookButton styleItemId={item.id} />\n <button\n type=\"button\"\n onClick={() => navigateTo(`/items/${item.id}/edit`)}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n <Pencil className=\"h-4 w-4\" /> Edit\n </button>\n {!isArchived && (\n <button\n type=\"button\"\n disabled={archive.isPending}\n onClick={() => archive.mutate(item.id, { onSuccess: () => navigateTo('/items') })}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-50\"\n >\n {archive.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Archive className=\"h-4 w-4\" />\n )}\n Archive\n </button>\n )}\n </div>\n }\n >\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Product image */}\n <div className=\"lg:col-span-2\">\n <GlassCard treatment=\"glass\" className=\"group overflow-hidden p-0\">\n <Thumbnail\n icon={categoryIcon(item.category, 48)}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"aspect-[4/5] w-full\"\n />\n {item.description && (\n <div className=\"p-6\">\n <p className=\"text-sm leading-relaxed text-text-secondary\">{item.description}</p>\n </div>\n )}\n </GlassCard>\n </div>\n\n {/* Product panel */}\n <div className=\"space-y-4\">\n <GlassCard treatment=\"glass\" className=\"space-y-5 p-6\">\n <div>\n <h2 className=\"text-2xl font-semibold leading-tight text-text-primary\">\n {item.name}\n </h2>\n {item.brand && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/brands/${item.brand?.id}`)}\n className=\"mt-1 inline-flex items-center gap-0.5 text-sm font-medium text-action-primary-bg hover:underline\"\n >\n {item.brand.name}\n <ChevronRight className=\"h-3.5 w-3.5\" />\n </button>\n )}\n <div className=\"mt-3 flex flex-wrap items-center justify-between gap-2\">\n <p className=\"text-3xl font-bold text-text-primary tabular-nums\">\n {formatPrice(item.price, item.currency)}\n <span className=\"ml-2 text-base font-medium text-text-secondary\">\n {item.currency}\n </span>\n </p>\n <StatusBadge status={item.status} />\n </div>\n </div>\n\n <div className=\"border-t border-border-seam\" />\n\n {item.colours.length > 0 && (\n <div>\n <p className=\"mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Colours\n </p>\n <ColourSwatchRow colours={item.colours} max={12} />\n </div>\n )}\n\n {item.sizes.length > 0 && (\n <div>\n <p className=\"mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Size\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {item.sizes.map((size) => (\n <span\n key={size}\n className=\"inline-flex min-w-9 items-center justify-center rounded-full border border-border-seam px-3 py-1 text-sm font-medium text-text-primary\"\n >\n {size}\n </span>\n ))}\n </div>\n </div>\n )}\n\n <div className=\"border-t border-border-seam pt-5\">\n <AddToCartPanel item={item} lookId={fromLookId} />\n </div>\n\n {item.materials.length > 0 && (\n <div>\n <p className=\"mb-1 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Materials\n </p>\n <p className=\"text-sm text-text-primary\">{item.materials.join(', ')}</p>\n </div>\n )}\n\n {item.tags.length > 0 && (\n <div>\n <p className=\"mb-2 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Tags\n </p>\n <TagList tags={item.tags} max={12} tone=\"accent\" />\n </div>\n )}\n </GlassCard>\n\n <GlassCard treatment=\"plain\" className=\"p-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">Details</h3>\n <dl className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Category</dt>\n <dd className=\"text-text-primary\">{titleCase(item.category)}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">SKU</dt>\n <dd className=\"text-text-primary\">{item.sku ?? '—'}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Currency</dt>\n <dd className=\"text-text-primary\">{item.currency}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Created</dt>\n <dd className=\"text-text-primary\">\n {formatDate(item.createdAt, { hour: undefined, minute: undefined })}\n </dd>\n </div>\n </dl>\n </GlassCard>\n\n <StoreListingCard item={item} />\n\n {item.collection && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/collections/${item.collection?.id}`)}\n className=\"flex w-full items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <Thumbnail\n icon={<Shapes className=\"h-5 w-5\" />}\n seed={item.collection.id}\n className=\"h-10 w-10 shrink-0\"\n />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {item.collection.name}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">View collection</p>\n </div>\n </button>\n )}\n </div>\n </div>\n\n <section className=\"mt-8\">\n <div className=\"mb-3 flex items-center justify-between gap-3\">\n <h3 className=\"text-lg font-semibold text-text-primary\">Appears in looks</h3>\n {appearsInLooks.length > 0 && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/looks')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-action-primary-bg hover:underline\"\n >\n View all <ChevronRight className=\"h-3.5 w-3.5\" />\n </button>\n )}\n </div>\n {looksQuery.isLoading ? (\n <div className=\"flex items-center gap-2 rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n <Loader2 className=\"h-4 w-4 animate-spin\" /> Loading referenced looks…\n </div>\n ) : appearsInLooks.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n This piece has not been tagged in any looks yet.\n </p>\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n {appearsInLooks.map((look) => (\n <LookCard\n key={look.id}\n id={look.id}\n title={look.title}\n occasion={look.occasion}\n imageFileId={look.image?.id}\n likeCount={look.likeCount}\n isLikedByMe={look.isLikedByMe}\n isSavedByMe={look.isSavedByMe}\n onOpen={() => navigateTo(`/looks/${look.id}`)}\n showActions\n />\n ))}\n </div>\n )}\n </section>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CooFileRef, CooStyleItem } from './index';
|
|
1
|
+
import { CooFileRef, CooStyleCategory, CooStyleItem } from './index';
|
|
2
2
|
|
|
3
3
|
export type CooOrderStatus = 'PENDING_PAYMENT' | 'PAID' | 'PARTIALLY_REFUNDED' | 'REFUNDED' | 'CANCELLED';
|
|
4
4
|
/** A brand's refund of its pieces of an order (BOFF-9702). */
|
|
@@ -238,6 +238,43 @@ export interface CooPaymentHandles {
|
|
|
238
238
|
export interface CooOrderCheckout extends CooPaymentHandles {
|
|
239
239
|
order: CooOrder;
|
|
240
240
|
}
|
|
241
|
+
/** One size/colour variant of a store-listed piece and the units left to buy (BOFF-10017). */
|
|
242
|
+
export interface CooStoreListedPieceVariant {
|
|
243
|
+
size: string | null;
|
|
244
|
+
colour: string | null;
|
|
245
|
+
available: number;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* A piece listed in the Burdenoff store, as a shopper outside the brand's workspace sees it
|
|
249
|
+
* (`cooStoreListedPiece`, BOFF-10017): product facts only.
|
|
250
|
+
*/
|
|
251
|
+
export interface CooStoreListedPiece {
|
|
252
|
+
id: string;
|
|
253
|
+
name: string;
|
|
254
|
+
description: string | null;
|
|
255
|
+
category: CooStyleCategory;
|
|
256
|
+
price: number;
|
|
257
|
+
currency: string;
|
|
258
|
+
sku: string | null;
|
|
259
|
+
colours: string[];
|
|
260
|
+
sizes: string[];
|
|
261
|
+
materials: string[];
|
|
262
|
+
tags: string[];
|
|
263
|
+
brandName: string;
|
|
264
|
+
brandHandle: string;
|
|
265
|
+
trackInventory: boolean;
|
|
266
|
+
variants: CooStoreListedPieceVariant[];
|
|
267
|
+
inStock: boolean;
|
|
268
|
+
}
|
|
269
|
+
export interface CooBuyStoreListedPieceInput {
|
|
270
|
+
styleItemId: string;
|
|
271
|
+
quantity: number;
|
|
272
|
+
size: string | null;
|
|
273
|
+
colour: string | null;
|
|
274
|
+
shippingName: string;
|
|
275
|
+
shippingAddress: string;
|
|
276
|
+
buyerNote: string | null;
|
|
277
|
+
}
|
|
241
278
|
export interface CooAddToCartInput {
|
|
242
279
|
styleItemId: string;
|
|
243
280
|
quantity?: number;
|