@burdenoff/microfe-coolandlovely 2026.1024.4 → 2026.1027.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/CoolAndLovelyRoutes.d.ts.map +1 -1
- package/dist/coolandlovely/CoolAndLovelyRoutes.js +20 -12
- package/dist/coolandlovely/CoolAndLovelyRoutes.js.map +1 -1
- package/dist/coolandlovely/components/FulfilmentTimeline.d.ts +7 -0
- package/dist/coolandlovely/components/FulfilmentTimeline.d.ts.map +1 -0
- package/dist/coolandlovely/components/FulfilmentTimeline.js +77 -0
- package/dist/coolandlovely/components/FulfilmentTimeline.js.map +1 -0
- package/dist/coolandlovely/components/RefundPanel.d.ts +8 -0
- package/dist/coolandlovely/components/RefundPanel.d.ts.map +1 -0
- package/dist/coolandlovely/components/RefundPanel.js +113 -0
- package/dist/coolandlovely/components/RefundPanel.js.map +1 -0
- package/dist/coolandlovely/components/StatusBadge.d.ts.map +1 -1
- package/dist/coolandlovely/components/StatusBadge.js +17 -1
- package/dist/coolandlovely/components/StatusBadge.js.map +1 -1
- package/dist/coolandlovely/hooks/useBrandOrdersApi.d.ts +12 -0
- package/dist/coolandlovely/hooks/useBrandOrdersApi.d.ts.map +1 -0
- package/dist/coolandlovely/hooks/useBrandOrdersApi.js +124 -0
- package/dist/coolandlovely/hooks/useBrandOrdersApi.js.map +1 -0
- package/dist/coolandlovely/hooks/useCommerceApi.d.ts +4 -0
- package/dist/coolandlovely/hooks/useCommerceApi.d.ts.map +1 -1
- package/dist/coolandlovely/hooks/useCommerceApi.js +28 -23
- package/dist/coolandlovely/hooks/useCommerceApi.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandDetailPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js +157 -148
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/commerce/BrandOrdersPage.d.ts +14 -0
- package/dist/coolandlovely/pages/commerce/BrandOrdersPage.d.ts.map +1 -0
- package/dist/coolandlovely/pages/commerce/BrandOrdersPage.js +362 -0
- package/dist/coolandlovely/pages/commerce/BrandOrdersPage.js.map +1 -0
- package/dist/coolandlovely/pages/commerce/CartPage.js +4 -4
- package/dist/coolandlovely/pages/commerce/CreatorEarningsPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/commerce/CreatorEarningsPage.js +108 -106
- package/dist/coolandlovely/pages/commerce/CreatorEarningsPage.js.map +1 -1
- package/dist/coolandlovely/pages/commerce/OrdersPage.d.ts +2 -1
- package/dist/coolandlovely/pages/commerce/OrdersPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/commerce/OrdersPage.js +206 -123
- package/dist/coolandlovely/pages/commerce/OrdersPage.js.map +1 -1
- package/dist/coolandlovely/types/commerce.d.ts +98 -1
- package/dist/coolandlovely/types/commerce.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrandDetailPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/brands/BrandDetailPage.tsx"],"sourcesContent":["/**\n * Brand Detail Page\n * @module coolandlovely/pages/brands\n *\n * Renders a single brand storefront (`cooBrand`) with its publish-lifecycle\n * transitions (`cooTransitionBrand`), collections and style items.\n */\n\nimport { useParams } from 'react-router';\nimport { Store, ExternalLink, Pencil, ArrowLeft, Shapes, Shirt, Loader2, Plus } 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 { BrandCover } from '../../components/BrandCover';\nimport { TagList } from '../../components/TagList';\nimport { Comments } from '../../components/Comments';\nimport { StepTracker } from '../../components/StepTracker';\nimport { ActivityTrail } from '../../components/ActivityTrail';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useAssistantEntityName, useBrand, useTransitionBrand, useUpdateBrand } from '../../hooks';\nimport { categoryIcon } from '../../utils/icons';\nimport { formatPrice, formatDate, titleCase } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\nimport type { CooBrandStatus } from '../../types';\n\n/** Allowed next states per the svc brand state machine (UX guidance only;\n * the service is the authority and rejects illegal jumps). */\nconst NEXT_STATES: Record<CooBrandStatus, CooBrandStatus[]> = {\n DRAFT: ['PENDING_REVIEW', 'ARCHIVED'],\n PENDING_REVIEW: ['PUBLISHED', 'DRAFT', 'ARCHIVED'],\n PUBLISHED: ['SUSPENDED', 'ARCHIVED'],\n SUSPENDED: ['PUBLISHED', 'ARCHIVED'],\n ARCHIVED: [],\n};\n\n/** The publish path a storefront walks. SUSPENDED/ARCHIVED are exits from it,\n * not steps on it, so a brand sitting in one is tracked separately below. */\nconst LIFECYCLE_STEPS: CooBrandStatus[] = ['DRAFT', 'PENDING_REVIEW', 'PUBLISHED'];\n\n/**\n * Reframe the gateway's RBAC refusal in the operator's language. ONLY a\n * permission refusal is relabelled — every other failure keeps the service's\n * own message, so a validation error is never disguised as a role problem.\n */\nfunction transitionErrorMessage(error: unknown): string {\n const raw = error instanceof Error ? error.message : 'Transition failed';\n return /forbidden|permission|not allowed|unauthori[sz]ed/i.test(raw)\n ? 'Your role does not permit this action.'\n : raw;\n}\n\nexport function BrandDetailPage() {\n const { brandId } = useParams<{ brandId: string }>();\n const { navigateTo } = useCoolAndLovely();\n const query = useBrand(brandId);\n const transition = useTransitionBrand();\n const updateBrand = useUpdateBrand();\n // Tell the assistant WHICH storefront is on screen (see useAssistantEntity).\n useAssistantEntityName(brandId, query.data?.name);\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Brand\">\n <LoadingView label=\"Loading brand…\" />\n </PageLayout>\n );\n }\n\n if (query.isError || !query.data) {\n return (\n <PageLayout title=\"Brand\">\n <ErrorView\n title=\"Brand not found\"\n message=\"This storefront could not be loaded or does not exist.\"\n onRetry={() => void query.refetch()}\n />\n </PageLayout>\n );\n }\n\n const brand = query.data;\n const collections = brand.collections ?? [];\n const items = brand.items ?? [];\n const nextStates = NEXT_STATES[brand.status];\n const trackerSteps = LIFECYCLE_STEPS.includes(brand.status)\n ? LIFECYCLE_STEPS\n : ([...LIFECYCLE_STEPS.slice(0, 1), brand.status] as CooBrandStatus[]);\n // Only render a website link for safe http(s) URLs (block javascript:/data: sinks).\n const safeWebsiteUrl =\n brand.websiteUrl && /^https?:\\/\\//i.test(brand.websiteUrl) ? brand.websiteUrl : undefined;\n\n return (\n <PageLayout title={brand.name} description={`@${brand.handle}`}>\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Main column */}\n <div className=\"space-y-6 lg:col-span-2\">\n {/* Storefront hero — cover + logo + identity overlay, floating actions */}\n <BrandCover\n coverFileId={brand.cover?.id}\n logoFileId={brand.logo?.id}\n name={brand.name}\n seed={brand.id}\n className=\"overflow-hidden rounded-xl border border-border-seam shadow-sm\"\n overlay={\n <>\n <div className=\"absolute right-3 top-3 flex flex-wrap items-center justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/brands')}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-bg-surface/80 px-3 py-2 text-sm font-medium text-text-primary shadow-sm backdrop-blur transition-colors hover:bg-bg-surface\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/brands/${brand.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 shadow-sm transition-colors hover:bg-action-primary-bg/90\"\n >\n <Pencil className=\"h-4 w-4\" /> Edit\n </button>\n </div>\n <div className=\"absolute inset-x-0 bottom-0 flex items-end gap-3 p-4 sm:gap-4 sm:p-5\">\n <Thumbnail\n icon={<Store className=\"h-7 w-7\" />}\n seed={brand.id}\n fileId={brand.logo?.id}\n alt={`${brand.name} logo`}\n className=\"h-16 w-16 shrink-0 rounded-full shadow-md ring-2 ring-bg-surface\"\n />\n <div className=\"min-w-0 pb-1\">\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-0.5\">\n <h2 className=\"truncate text-xl font-semibold text-text-primary sm:text-2xl\">\n {brand.name}\n </h2>\n <span className=\"text-sm text-text-secondary\">@{brand.handle}</span>\n </div>\n {brand.tagline && (\n <p className=\"mt-1 line-clamp-2 text-sm text-text-primary\">{brand.tagline}</p>\n )}\n </div>\n </div>\n </>\n }\n />\n\n {/* Storefront meta — aesthetics, status, bio, tags, website */}\n <section className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n {brand.aesthetics.length > 0 ? (\n <TagList tags={brand.aesthetics.map(titleCase)} tone=\"accent\" max={12} />\n ) : (\n <span />\n )}\n <StatusBadge status={brand.status} />\n </div>\n {brand.bio && <p className=\"text-sm text-text-secondary\">{brand.bio}</p>}\n {brand.tags.length > 0 && <TagList tags={brand.tags} max={12} />}\n {safeWebsiteUrl ? (\n <a\n href={safeWebsiteUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex max-w-full items-center gap-1.5 text-sm font-medium text-action-primary-bg hover:underline\"\n >\n <ExternalLink className=\"h-4 w-4 shrink-0\" />{' '}\n <span className=\"break-all\">{safeWebsiteUrl}</span>\n </a>\n ) : brand.websiteUrl ? (\n <p className=\"break-all text-sm text-text-secondary\">{brand.websiteUrl}</p>\n ) : null}\n </section>\n\n {/* Collections */}\n <section className=\"mt-6\">\n <div className=\"mb-3 flex items-center justify-between gap-2\">\n <h3 className=\"flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Shapes className=\"h-5 w-5\" /> Collections ({collections.length})\n </h3>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/collections/new?brandId=${brand.id}`)}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <Plus className=\"h-4 w-4\" /> Add collection\n </button>\n </div>\n {collections.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n No collections yet.\n </p>\n ) : (\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n {collections.map((c) => (\n <button\n key={c.id}\n type=\"button\"\n onClick={() => navigateTo(`/collections/${c.id}`)}\n className=\"flex items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-3 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <Thumbnail\n icon={<Shapes className=\"h-5 w-5\" />}\n seed={c.id}\n fileId={c.cover?.id}\n alt={c.name}\n className=\"h-11 w-11 shrink-0\"\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{c.name}</p>\n <p className=\"text-xs text-text-secondary\">{titleCase(c.season)}</p>\n </div>\n <StatusBadge status={c.status} />\n </button>\n ))}\n </div>\n )}\n </section>\n\n {/* Items */}\n <section className=\"mt-6\">\n <h3 className=\"mb-3 flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Shirt className=\"h-5 w-5\" /> Style items ({items.length})\n </h3>\n {items.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n No items yet.\n </p>\n ) : (\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-3\">\n {items.map((item) => (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => navigateTo(`/items/${item.id}`)}\n className=\"overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-all hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={categoryIcon(item.category, 24)}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"h-24 w-full\"\n />\n <div className=\"p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{item.name}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {formatPrice(item.price, item.currency)}\n </p>\n </div>\n </button>\n ))}\n </div>\n )}\n </section>\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-4\">\n <GlassCard treatment=\"insight\" className=\"p-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">Publish lifecycle</h3>\n <StepTracker steps={trackerSteps} current={brand.status} className=\"mb-5\" />\n <div className=\"mb-3 flex items-center gap-2\">\n <span className=\"text-sm text-text-secondary\">Current:</span>\n <StatusBadge status={brand.status} />\n </div>\n {nextStates.length === 0 ? (\n <p className=\"text-xs text-text-secondary\">\n This brand is archived (terminal state).\n </p>\n ) : (\n <div className=\"flex flex-col gap-2\">\n {nextStates.map((next) => (\n <button\n key={next}\n type=\"button\"\n disabled={transition.isPending}\n onClick={() => transition.mutate({ id: brand.id, status: next })}\n className={cn(\n 'inline-flex items-center justify-center gap-2 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 >\n {transition.isPending && <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />}\n Move to {titleCase(next)}\n </button>\n ))}\n </div>\n )}\n {transition.isError && (\n <p className=\"mt-2 text-xs text-status-error-text\">\n {transitionErrorMessage(transition.error)}\n </p>\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\">Handle</dt>\n <dd className=\"text-text-primary\">@{brand.handle}</dd>\n </div>\n <div className=\"flex items-center justify-between gap-2\">\n <dt className=\"text-text-secondary\">Featured</dt>\n <dd className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={brand.isFeatured}\n aria-label={brand.isFeatured ? 'Unfeature this brand' : 'Feature this brand'}\n disabled={updateBrand.isPending}\n onClick={() =>\n updateBrand.mutate({\n id: brand.id,\n input: { isFeatured: !brand.isFeatured },\n })\n }\n className={cn(\n 'relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] disabled:opacity-60',\n brand.isFeatured ? 'bg-action-primary-bg' : 'bg-bg-sunken'\n )}\n >\n <span\n className={cn(\n 'inline-block h-4 w-4 rounded-full bg-bg-surface shadow transition-transform',\n brand.isFeatured ? 'translate-x-[1.125rem]' : 'translate-x-0.5'\n )}\n />\n </button>\n {updateBrand.isPending && (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin text-text-secondary\" />\n )}\n </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(brand.createdAt, { hour: undefined, minute: undefined })}\n </dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Updated</dt>\n <dd className=\"text-text-primary\">\n {formatDate(brand.updatedAt, { hour: undefined, minute: undefined })}\n </dd>\n </div>\n </dl>\n </GlassCard>\n\n {/* Audit trail — who moved this storefront through its lifecycle, from\n the platform ActivityLog rows the svc's audit plugin writes. */}\n <ActivityTrail resourceType=\"coolandlovely-brand\" resourceId={brand.id} />\n\n {/* Reviews & feedback — moved into the sidebar to match the storefront layout */}\n <Comments entityType=\"CooBrand\" entityId={brand.id} className=\"mt-0\" />\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA6BA,IAAM,IAAwD;CAC5D,OAAO,CAAC,kBAAkB,WAAW;CACrC,gBAAgB;EAAC;EAAa;EAAS;EAAW;CAClD,WAAW,CAAC,aAAa,WAAW;CACpC,WAAW,CAAC,aAAa,WAAW;CACpC,UAAU,EAAE;CACb,EAIK,IAAoC;CAAC;CAAS;CAAkB;CAAY;AAOlF,SAAS,EAAuB,GAAwB;CACtD,IAAM,IAAM,aAAiB,QAAQ,EAAM,UAAU;AACrD,QAAO,oDAAoD,KAAK,EAAI,GAChE,2CACA;;AAGN,SAAgB,IAAkB;CAChC,IAAM,EAAE,eAAY,GAAgC,EAC9C,EAAE,kBAAe,GAAkB,EACnC,IAAQ,EAAS,EAAQ,EACzB,IAAa,GAAoB,EACjC,IAAc,GAAgB;AAIpC,KAFA,EAAuB,GAAS,EAAM,MAAM,KAAK,EAE7C,EAAM,UACR,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD,EAAa,OAAM,kBAAmB,CAAA;EAC3B,CAAA;AAIjB,KAAI,EAAM,WAAW,CAAC,EAAM,KAC1B,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD;GACE,OAAM;GACN,SAAQ;GACR,eAAe,KAAK,EAAM,SAAS;GACnC,CAAA;EACS,CAAA;CAIjB,IAAM,IAAQ,EAAM,MACd,IAAc,EAAM,eAAe,EAAE,EACrC,IAAQ,EAAM,SAAS,EAAE,EACzB,IAAa,EAAY,EAAM,SAC/B,IAAe,EAAgB,SAAS,EAAM,OAAO,GACvD,IACC,CAAC,GAAG,EAAgB,MAAM,GAAG,EAAE,EAAE,EAAM,OAAO,EAE7C,IACJ,EAAM,cAAc,gBAAgB,KAAK,EAAM,WAAW,GAAG,EAAM,aAAa,KAAA;AAElF,QACE,kBAAC,GAAD;EAAY,OAAO,EAAM;EAAM,aAAa,IAAI,EAAM;YACpD,kBAAC,OAAD;GAAK,WAAU;aAAf,CAEE,kBAAC,OAAD;IAAK,WAAU;cAAf;KAEE,kBAAC,GAAD;MACE,aAAa,EAAM,OAAO;MAC1B,YAAY,EAAM,MAAM;MACxB,MAAM,EAAM;MACZ,MAAM,EAAM;MACZ,WAAU;MACV,SACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,EAAW,UAAU;QACpC,WAAU;kBAHZ,CAKE,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA,EAAA,QAC1B;WACT,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,EAAW,WAAW,EAAM,GAAG,OAAO;QACrD,WAAU;kBAHZ,CAKE,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA,EAAA,QACvB;UACL;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QACE,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;QACnC,MAAM,EAAM;QACZ,QAAQ,EAAM,MAAM;QACpB,KAAK,GAAG,EAAM,KAAK;QACnB,WAAU;QACV,CAAA,EACF,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAM;UACJ,CAAA,EACL,kBAAC,QAAD;UAAM,WAAU;oBAAhB,CAA8C,KAAE,EAAM,OAAc;YAChE;YACL,EAAM,WACL,kBAAC,KAAD;SAAG,WAAU;mBAA+C,EAAM;SAAY,CAAA,CAE5E;UACF;SACL,EAAA,CAAA;MAEL,CAAA;KAGF,kBAAC,WAAD;MAAS,WAAU;gBAAnB;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACG,EAAM,WAAW,SAAS,IACzB,kBAAC,GAAD;SAAS,MAAM,EAAM,WAAW,IAAI,EAAU;SAAE,MAAK;SAAS,KAAK;SAAM,CAAA,GAEzE,kBAAC,QAAD,EAAQ,CAAA,EAEV,kBAAC,GAAD,EAAa,QAAQ,EAAM,QAAU,CAAA,CACjC;;OACL,EAAM,OAAO,kBAAC,KAAD;QAAG,WAAU;kBAA+B,EAAM;QAAQ,CAAA;OACvE,EAAM,KAAK,SAAS,KAAK,kBAAC,GAAD;QAAS,MAAM,EAAM;QAAM,KAAK;QAAM,CAAA;OAC/D,IACC,kBAAC,KAAD;QACE,MAAM;QACN,QAAO;QACP,KAAI;QACJ,WAAU;kBAJZ;SAME,kBAAC,GAAD,EAAc,WAAU,oBAAqB,CAAA;SAAC;SAC9C,kBAAC,QAAD;UAAM,WAAU;oBAAa;UAAsB,CAAA;SACjD;YACF,EAAM,aACR,kBAAC,KAAD;QAAG,WAAU;kBAAyC,EAAM;QAAe,CAAA,GACzE;OACI;;KAGV,kBAAC,WAAD;MAAS,WAAU;gBAAnB,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,MAAD;QAAI,WAAU;kBAAd;SACE,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;;SAAe,EAAY;SAAO;SAC7D;WACL,kBAAC,UAAD;QACE,MAAK;QACL,eAAe,EAAW,4BAA4B,EAAM,KAAK;QACjE,WAAU;kBAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,kBACrB;UACL;UACL,EAAY,WAAW,IACtB,kBAAC,KAAD;OAAG,WAAU;iBAAqF;OAE9F,CAAA,GAEJ,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAY,KAAK,MAChB,kBAAC,UAAD;QAEE,MAAK;QACL,eAAe,EAAW,gBAAgB,EAAE,KAAK;QACjD,WAAU;kBAJZ;SAME,kBAAC,GAAD;UACE,MAAM,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;UACpC,MAAM,EAAE;UACR,QAAQ,EAAE,OAAO;UACjB,KAAK,EAAE;UACP,WAAU;UACV,CAAA;SACF,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,KAAD;WAAG,WAAU;qBAAkD,EAAE;WAAS,CAAA,EAC1E,kBAAC,KAAD;WAAG,WAAU;qBAA+B,EAAU,EAAE,OAAO;WAAK,CAAA,CAChE;;SACN,kBAAC,GAAD,EAAa,QAAQ,EAAE,QAAU,CAAA;SAC1B;UAjBF,EAAE,GAiBA,CACT;OACE,CAAA,CAEA;;KAGV,kBAAC,WAAD;MAAS,WAAU;gBAAnB,CACE,kBAAC,MAAD;OAAI,WAAU;iBAAd;QACE,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;;QAAe,EAAM;QAAO;QACtD;UACJ,EAAM,WAAW,IAChB,kBAAC,KAAD;OAAG,WAAU;iBAAqF;OAE9F,CAAA,GAEJ,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAM,KAAK,MACV,kBAAC,UAAD;QAEE,MAAK;QACL,eAAe,EAAW,UAAU,EAAK,KAAK;QAC9C,WAAU;kBAJZ,CAME,kBAAC,GAAD;SACE,MAAM,EAAa,EAAK,UAAU,GAAG;SACrC,MAAM,EAAK;SACX,QAAQ,EAAK,OAAO;SACpB,KAAK,EAAK;SACV,WAAU;SACV,CAAA,EACF,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,KAAD;UAAG,WAAU;oBAAkD,EAAK;UAAS,CAAA,EAC7E,kBAAC,KAAD;UAAG,WAAU;oBACV,EAAY,EAAK,OAAO,EAAK,SAAS;UACrC,CAAA,CACA;WACC;UAlBF,EAAK,GAkBH,CACT;OACE,CAAA,CAEA;;KACN;OAGN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAW,WAAU;MAAU,WAAU;gBAAzC;OACE,kBAAC,MAAD;QAAI,WAAU;kBAA+C;QAAsB,CAAA;OACnF,kBAAC,GAAD;QAAa,OAAO;QAAc,SAAS,EAAM;QAAQ,WAAU;QAAS,CAAA;OAC5E,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBAA8B;SAAe,CAAA,EAC7D,kBAAC,GAAD,EAAa,QAAQ,EAAM,QAAU,CAAA,CACjC;;OACL,EAAW,WAAW,IACrB,kBAAC,KAAD;QAAG,WAAU;kBAA8B;QAEvC,CAAA,GAEJ,kBAAC,OAAD;QAAK,WAAU;kBACZ,EAAW,KAAK,MACf,kBAAC,UAAD;SAEE,MAAK;SACL,UAAU,EAAW;SACrB,eAAe,EAAW,OAAO;UAAE,IAAI,EAAM;UAAI,QAAQ;UAAM,CAAC;SAChE,WAAW,EACT,8LACD;mBAPH;UASG,EAAW,aAAa,kBAAC,GAAD,EAAS,WAAU,4BAA6B,CAAA;UAAC;UACjE,EAAU,EAAK;UACjB;WAVF,EAUE,CACT;QACE,CAAA;OAEP,EAAW,WACV,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAuB,EAAW,MAAM;QACvC,CAAA;OAEI;;KAEZ,kBAAC,GAAD;MAAW,WAAU;MAAQ,WAAU;gBAAvC,CACE,kBAAC,MAAD;OAAI,WAAU;iBAA+C;OAAY,CAAA,EACzE,kBAAC,MAAD;OAAI,WAAU;iBAAd;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBAAsB;UAAW,CAAA,EAC/C,kBAAC,MAAD;UAAI,WAAU;oBAAd,CAAkC,KAAE,EAAM,OAAY;YAClD;;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBAAsB;UAAa,CAAA,EACjD,kBAAC,MAAD;UAAI,WAAU;oBAAd,CACE,kBAAC,UAAD;WACE,MAAK;WACL,MAAK;WACL,gBAAc,EAAM;WACpB,cAAY,EAAM,aAAa,yBAAyB;WACxD,UAAU,EAAY;WACtB,eACE,EAAY,OAAO;YACjB,IAAI,EAAM;YACV,OAAO,EAAE,YAAY,CAAC,EAAM,YAAY;YACzC,CAAC;WAEJ,WAAW,EACT,sMACA,EAAM,aAAa,yBAAyB,eAC7C;qBAED,kBAAC,QAAD,EACE,WAAW,EACT,+EACA,EAAM,aAAa,2BAA2B,kBAC/C,EACD,CAAA;WACK,CAAA,EACR,EAAY,aACX,kBAAC,GAAD,EAAS,WAAU,gDAAiD,CAAA,CAEnE;YACD;;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBAAsB;UAAY,CAAA,EAChD,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAW,EAAM,WAAW;WAAE,MAAM,KAAA;WAAW,QAAQ,KAAA;WAAW,CAAC;UACjE,CAAA,CACD;;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBAAsB;UAAY,CAAA,EAChD,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAW,EAAM,WAAW;WAAE,MAAM,KAAA;WAAW,QAAQ,KAAA;WAAW,CAAC;UACjE,CAAA,CACD;;QACH;SACK;;KAIZ,kBAAC,GAAD;MAAe,cAAa;MAAsB,YAAY,EAAM;MAAM,CAAA;KAG1E,kBAAC,GAAD;MAAU,YAAW;MAAW,UAAU,EAAM;MAAI,WAAU;MAAS,CAAA;KACnE;MACF;;EACK,CAAA"}
|
|
1
|
+
{"version":3,"file":"BrandDetailPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/brands/BrandDetailPage.tsx"],"sourcesContent":["/**\n * Brand Detail Page\n * @module coolandlovely/pages/brands\n *\n * Renders a single brand storefront (`cooBrand`) with its publish-lifecycle\n * transitions (`cooTransitionBrand`), collections and style items.\n */\n\nimport { useParams } from 'react-router';\nimport {\n Store,\n ExternalLink,\n Pencil,\n ArrowLeft,\n Shapes,\n Shirt,\n Loader2,\n Plus,\n Package,\n} 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 { BrandCover } from '../../components/BrandCover';\nimport { TagList } from '../../components/TagList';\nimport { Comments } from '../../components/Comments';\nimport { StepTracker } from '../../components/StepTracker';\nimport { ActivityTrail } from '../../components/ActivityTrail';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useAssistantEntityName, useBrand, useTransitionBrand, useUpdateBrand } from '../../hooks';\nimport { categoryIcon } from '../../utils/icons';\nimport { formatPrice, formatDate, titleCase } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\nimport type { CooBrandStatus } from '../../types';\n\n/** Allowed next states per the svc brand state machine (UX guidance only;\n * the service is the authority and rejects illegal jumps). */\nconst NEXT_STATES: Record<CooBrandStatus, CooBrandStatus[]> = {\n DRAFT: ['PENDING_REVIEW', 'ARCHIVED'],\n PENDING_REVIEW: ['PUBLISHED', 'DRAFT', 'ARCHIVED'],\n PUBLISHED: ['SUSPENDED', 'ARCHIVED'],\n SUSPENDED: ['PUBLISHED', 'ARCHIVED'],\n ARCHIVED: [],\n};\n\n/** The publish path a storefront walks. SUSPENDED/ARCHIVED are exits from it,\n * not steps on it, so a brand sitting in one is tracked separately below. */\nconst LIFECYCLE_STEPS: CooBrandStatus[] = ['DRAFT', 'PENDING_REVIEW', 'PUBLISHED'];\n\n/**\n * Reframe the gateway's RBAC refusal in the operator's language. ONLY a\n * permission refusal is relabelled — every other failure keeps the service's\n * own message, so a validation error is never disguised as a role problem.\n */\nfunction transitionErrorMessage(error: unknown): string {\n const raw = error instanceof Error ? error.message : 'Transition failed';\n return /forbidden|permission|not allowed|unauthori[sz]ed/i.test(raw)\n ? 'Your role does not permit this action.'\n : raw;\n}\n\nexport function BrandDetailPage() {\n const { brandId } = useParams<{ brandId: string }>();\n const { navigateTo } = useCoolAndLovely();\n const query = useBrand(brandId);\n const transition = useTransitionBrand();\n const updateBrand = useUpdateBrand();\n // Tell the assistant WHICH storefront is on screen (see useAssistantEntity).\n useAssistantEntityName(brandId, query.data?.name);\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Brand\">\n <LoadingView label=\"Loading brand…\" />\n </PageLayout>\n );\n }\n\n if (query.isError || !query.data) {\n return (\n <PageLayout title=\"Brand\">\n <ErrorView\n title=\"Brand not found\"\n message=\"This storefront could not be loaded or does not exist.\"\n onRetry={() => void query.refetch()}\n />\n </PageLayout>\n );\n }\n\n const brand = query.data;\n const collections = brand.collections ?? [];\n const items = brand.items ?? [];\n const nextStates = NEXT_STATES[brand.status];\n const trackerSteps = LIFECYCLE_STEPS.includes(brand.status)\n ? LIFECYCLE_STEPS\n : ([...LIFECYCLE_STEPS.slice(0, 1), brand.status] as CooBrandStatus[]);\n // Only render a website link for safe http(s) URLs (block javascript:/data: sinks).\n const safeWebsiteUrl =\n brand.websiteUrl && /^https?:\\/\\//i.test(brand.websiteUrl) ? brand.websiteUrl : undefined;\n\n return (\n <PageLayout title={brand.name} description={`@${brand.handle}`}>\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Main column */}\n <div className=\"space-y-6 lg:col-span-2\">\n {/* Storefront hero — cover + logo + identity overlay, floating actions */}\n <BrandCover\n coverFileId={brand.cover?.id}\n logoFileId={brand.logo?.id}\n name={brand.name}\n seed={brand.id}\n className=\"overflow-hidden rounded-xl border border-border-seam shadow-sm\"\n overlay={\n <>\n <div className=\"absolute right-3 top-3 flex flex-wrap items-center justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/brands')}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-bg-surface/80 px-3 py-2 text-sm font-medium text-text-primary shadow-sm backdrop-blur transition-colors hover:bg-bg-surface\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/brand-orders?brand=${brand.id}`)}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-bg-surface/80 px-3 py-2 text-sm font-medium text-text-primary shadow-sm backdrop-blur transition-colors hover:bg-bg-surface\"\n >\n <Package className=\"h-4 w-4\" /> Orders\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/brands/${brand.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 shadow-sm transition-colors hover:bg-action-primary-bg/90\"\n >\n <Pencil className=\"h-4 w-4\" /> Edit\n </button>\n </div>\n <div className=\"absolute inset-x-0 bottom-0 flex items-end gap-3 p-4 sm:gap-4 sm:p-5\">\n <Thumbnail\n icon={<Store className=\"h-7 w-7\" />}\n seed={brand.id}\n fileId={brand.logo?.id}\n alt={`${brand.name} logo`}\n className=\"h-16 w-16 shrink-0 rounded-full shadow-md ring-2 ring-bg-surface\"\n />\n <div className=\"min-w-0 pb-1\">\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-0.5\">\n <h2 className=\"truncate text-xl font-semibold text-text-primary sm:text-2xl\">\n {brand.name}\n </h2>\n <span className=\"text-sm text-text-secondary\">@{brand.handle}</span>\n </div>\n {brand.tagline && (\n <p className=\"mt-1 line-clamp-2 text-sm text-text-primary\">{brand.tagline}</p>\n )}\n </div>\n </div>\n </>\n }\n />\n\n {/* Storefront meta — aesthetics, status, bio, tags, website */}\n <section className=\"space-y-3\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n {brand.aesthetics.length > 0 ? (\n <TagList tags={brand.aesthetics.map(titleCase)} tone=\"accent\" max={12} />\n ) : (\n <span />\n )}\n <StatusBadge status={brand.status} />\n </div>\n {brand.bio && <p className=\"text-sm text-text-secondary\">{brand.bio}</p>}\n {brand.tags.length > 0 && <TagList tags={brand.tags} max={12} />}\n {safeWebsiteUrl ? (\n <a\n href={safeWebsiteUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex max-w-full items-center gap-1.5 text-sm font-medium text-action-primary-bg hover:underline\"\n >\n <ExternalLink className=\"h-4 w-4 shrink-0\" />{' '}\n <span className=\"break-all\">{safeWebsiteUrl}</span>\n </a>\n ) : brand.websiteUrl ? (\n <p className=\"break-all text-sm text-text-secondary\">{brand.websiteUrl}</p>\n ) : null}\n </section>\n\n {/* Collections */}\n <section className=\"mt-6\">\n <div className=\"mb-3 flex items-center justify-between gap-2\">\n <h3 className=\"flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Shapes className=\"h-5 w-5\" /> Collections ({collections.length})\n </h3>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/collections/new?brandId=${brand.id}`)}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <Plus className=\"h-4 w-4\" /> Add collection\n </button>\n </div>\n {collections.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n No collections yet.\n </p>\n ) : (\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n {collections.map((c) => (\n <button\n key={c.id}\n type=\"button\"\n onClick={() => navigateTo(`/collections/${c.id}`)}\n className=\"flex items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-3 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <Thumbnail\n icon={<Shapes className=\"h-5 w-5\" />}\n seed={c.id}\n fileId={c.cover?.id}\n alt={c.name}\n className=\"h-11 w-11 shrink-0\"\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{c.name}</p>\n <p className=\"text-xs text-text-secondary\">{titleCase(c.season)}</p>\n </div>\n <StatusBadge status={c.status} />\n </button>\n ))}\n </div>\n )}\n </section>\n\n {/* Items */}\n <section className=\"mt-6\">\n <h3 className=\"mb-3 flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Shirt className=\"h-5 w-5\" /> Style items ({items.length})\n </h3>\n {items.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n No items yet.\n </p>\n ) : (\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-3\">\n {items.map((item) => (\n <button\n key={item.id}\n type=\"button\"\n onClick={() => navigateTo(`/items/${item.id}`)}\n className=\"overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-all hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={categoryIcon(item.category, 24)}\n seed={item.id}\n fileId={item.image?.id}\n alt={item.name}\n className=\"h-24 w-full\"\n />\n <div className=\"p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{item.name}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {formatPrice(item.price, item.currency)}\n </p>\n </div>\n </button>\n ))}\n </div>\n )}\n </section>\n </div>\n\n {/* Sidebar */}\n <div className=\"space-y-4\">\n <GlassCard treatment=\"insight\" className=\"p-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">Publish lifecycle</h3>\n <StepTracker steps={trackerSteps} current={brand.status} className=\"mb-5\" />\n <div className=\"mb-3 flex items-center gap-2\">\n <span className=\"text-sm text-text-secondary\">Current:</span>\n <StatusBadge status={brand.status} />\n </div>\n {nextStates.length === 0 ? (\n <p className=\"text-xs text-text-secondary\">\n This brand is archived (terminal state).\n </p>\n ) : (\n <div className=\"flex flex-col gap-2\">\n {nextStates.map((next) => (\n <button\n key={next}\n type=\"button\"\n disabled={transition.isPending}\n onClick={() => transition.mutate({ id: brand.id, status: next })}\n className={cn(\n 'inline-flex items-center justify-center gap-2 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 >\n {transition.isPending && <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />}\n Move to {titleCase(next)}\n </button>\n ))}\n </div>\n )}\n {transition.isError && (\n <p className=\"mt-2 text-xs text-status-error-text\">\n {transitionErrorMessage(transition.error)}\n </p>\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\">Handle</dt>\n <dd className=\"text-text-primary\">@{brand.handle}</dd>\n </div>\n <div className=\"flex items-center justify-between gap-2\">\n <dt className=\"text-text-secondary\">Featured</dt>\n <dd className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={brand.isFeatured}\n aria-label={brand.isFeatured ? 'Unfeature this brand' : 'Feature this brand'}\n disabled={updateBrand.isPending}\n onClick={() =>\n updateBrand.mutate({\n id: brand.id,\n input: { isFeatured: !brand.isFeatured },\n })\n }\n className={cn(\n 'relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] disabled:opacity-60',\n brand.isFeatured ? 'bg-action-primary-bg' : 'bg-bg-sunken'\n )}\n >\n <span\n className={cn(\n 'inline-block h-4 w-4 rounded-full bg-bg-surface shadow transition-transform',\n brand.isFeatured ? 'translate-x-[1.125rem]' : 'translate-x-0.5'\n )}\n />\n </button>\n {updateBrand.isPending && (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin text-text-secondary\" />\n )}\n </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(brand.createdAt, { hour: undefined, minute: undefined })}\n </dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Updated</dt>\n <dd className=\"text-text-primary\">\n {formatDate(brand.updatedAt, { hour: undefined, minute: undefined })}\n </dd>\n </div>\n </dl>\n </GlassCard>\n\n {/* Audit trail — who moved this storefront through its lifecycle, from\n the platform ActivityLog rows the svc's audit plugin writes. */}\n <ActivityTrail resourceType=\"coolandlovely-brand\" resourceId={brand.id} />\n\n {/* Reviews & feedback — moved into the sidebar to match the storefront layout */}\n <Comments entityType=\"CooBrand\" entityId={brand.id} className=\"mt-0\" />\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Brand orders + brand order detail (BOFF-9636)
|
|
3
|
+
* @module coolandlovely/pages/commerce
|
|
4
|
+
*
|
|
5
|
+
* The brand side of CoolAndLovely orders: the paid orders that contain a brand's pieces
|
|
6
|
+
* (`cooBrandOrders`, only that brand's lines), counts per fulfilment state
|
|
7
|
+
* (`cooBrandOrderSummary`), and one order's fulfilment — confirm it, ship it with tracking,
|
|
8
|
+
* mark it delivered (`cooUpdateOrderFulfilment`). Fulfilment only moves forward, and the
|
|
9
|
+
* buyer is notified of every change. A brand can also refund all of its pieces of an order
|
|
10
|
+
* (`cooRefundBrandOrder`, BOFF-9702); refunded pieces are no longer fulfilled.
|
|
11
|
+
*/
|
|
12
|
+
export declare function BrandOrdersPage(): import("react").JSX.Element;
|
|
13
|
+
export declare function BrandOrderDetailPage(): import("react").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=BrandOrdersPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BrandOrdersPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/commerce/BrandOrdersPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA8EH,wBAAgB,eAAe,gCA2H9B;AA6HD,wBAAgB,oBAAoB,gCAgHnC"}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { useCoolAndLovely as e } from "../../context/CoolAndLovelyContext.js";
|
|
2
|
+
import { cn as t } from "../../utils/cn.js";
|
|
3
|
+
import { PageLayout as n } from "../../components/PageLayout.js";
|
|
4
|
+
import { useBrands as r } from "../../hooks/useCoolAndLovelyApi.js";
|
|
5
|
+
import { useTr as i } from "../../hooks/useTr.js";
|
|
6
|
+
import "../../hooks/index.js";
|
|
7
|
+
import { StatusBadge as a } from "../../components/StatusBadge.js";
|
|
8
|
+
import { ErrorView as o, LoadingView as s } from "../../components/StateViews.js";
|
|
9
|
+
import { Thumbnail as c } from "../../components/Thumbnail.js";
|
|
10
|
+
import { formatDate as l, formatPrice as u } from "../../utils/formatters.js";
|
|
11
|
+
import { EmptyState as d } from "../../components/EmptyState.js";
|
|
12
|
+
import { SelectField as f, TextAreaField as p, TextField as m } from "../../components/Field.js";
|
|
13
|
+
import { FulfilmentTimeline as h } from "../../components/FulfilmentTimeline.js";
|
|
14
|
+
import { useBrandOrder as g, useBrandOrderSummary as _, useBrandOrders as v, useUpdateOrderFulfilment as y } from "../../hooks/useBrandOrdersApi.js";
|
|
15
|
+
import { RefundPanel as b } from "../../components/RefundPanel.js";
|
|
16
|
+
import { useEffect as x, useMemo as S, useState as C } from "react";
|
|
17
|
+
import { ArrowLeft as w, CheckCircle2 as T, ChevronRight as E, Loader2 as D, Package as O, PackageCheck as k, Truck as A } from "lucide-react";
|
|
18
|
+
import { useParams as j, useSearchParams as M } from "react-router";
|
|
19
|
+
import { Fragment as N, jsx as P, jsxs as F } from "react/jsx-runtime";
|
|
20
|
+
import { GlassCard as I } from "@burdenoff/fe-libs/ui";
|
|
21
|
+
//#region src/coolandlovely/pages/commerce/BrandOrdersPage.tsx
|
|
22
|
+
var L = [
|
|
23
|
+
{
|
|
24
|
+
value: void 0,
|
|
25
|
+
key: "coolandlovely.brandOrders.filterAll",
|
|
26
|
+
label: "All",
|
|
27
|
+
count: (e) => e.total
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
value: "UNFULFILLED",
|
|
31
|
+
key: "coolandlovely.brandOrders.filterUnfulfilled",
|
|
32
|
+
label: "To confirm",
|
|
33
|
+
count: (e) => e.unfulfilled
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
value: "CONFIRMED",
|
|
37
|
+
key: "coolandlovely.brandOrders.filterConfirmed",
|
|
38
|
+
label: "Confirmed",
|
|
39
|
+
count: (e) => e.confirmed
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
value: "SHIPPED",
|
|
43
|
+
key: "coolandlovely.brandOrders.filterShipped",
|
|
44
|
+
label: "Shipped",
|
|
45
|
+
count: (e) => e.shipped
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
value: "DELIVERED",
|
|
49
|
+
key: "coolandlovely.brandOrders.filterDelivered",
|
|
50
|
+
label: "Delivered",
|
|
51
|
+
count: (e) => e.delivered
|
|
52
|
+
}
|
|
53
|
+
], R = "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 disabled:opacity-50", z = "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";
|
|
54
|
+
function B() {
|
|
55
|
+
let c = i(), { navigateTo: p } = e(), [m, h] = M(), g = r({ pagination: {
|
|
56
|
+
limit: 100,
|
|
57
|
+
offset: 0
|
|
58
|
+
} }), y = S(() => (g.data?.items ?? []).map((e) => ({
|
|
59
|
+
value: e.id,
|
|
60
|
+
label: e.name
|
|
61
|
+
})), [g.data]), b = m.get("brand") ?? y[0]?.value, [w, T] = C(void 0), D = _(b), k = v(b, w), A = c("coolandlovely.brandOrders.title", "Brand orders");
|
|
62
|
+
return x(() => T(void 0), [b]), /* @__PURE__ */ P(n, {
|
|
63
|
+
title: A,
|
|
64
|
+
description: c("coolandlovely.brandOrders.description", "Paid orders for your pieces. Confirm them, ship them with tracking and mark them delivered."),
|
|
65
|
+
children: g.isLoading ? /* @__PURE__ */ P(s, {}) : y.length === 0 ? /* @__PURE__ */ P(d, {
|
|
66
|
+
icon: /* @__PURE__ */ P(O, { className: "h-8 w-8" }),
|
|
67
|
+
title: c("coolandlovely.brandOrders.noBrandsTitle", "No brands yet"),
|
|
68
|
+
description: c("coolandlovely.brandOrders.noBrandsDescription", "Create a brand storefront to start selling pieces.")
|
|
69
|
+
}) : /* @__PURE__ */ F(N, { children: [
|
|
70
|
+
/* @__PURE__ */ P("div", {
|
|
71
|
+
className: "mb-4 max-w-sm",
|
|
72
|
+
children: /* @__PURE__ */ P(f, {
|
|
73
|
+
id: "coo-brand-orders-brand",
|
|
74
|
+
label: c("coolandlovely.brandOrders.brand", "Brand"),
|
|
75
|
+
value: b ?? "",
|
|
76
|
+
onChange: (e) => {
|
|
77
|
+
let t = new URLSearchParams(m);
|
|
78
|
+
t.set("brand", e), h(t, { replace: !0 });
|
|
79
|
+
},
|
|
80
|
+
options: y
|
|
81
|
+
})
|
|
82
|
+
}),
|
|
83
|
+
/* @__PURE__ */ P("div", {
|
|
84
|
+
className: "mb-4 flex flex-wrap gap-2",
|
|
85
|
+
role: "tablist",
|
|
86
|
+
children: L.map((e) => /* @__PURE__ */ F("button", {
|
|
87
|
+
type: "button",
|
|
88
|
+
role: "tab",
|
|
89
|
+
"aria-selected": w === e.value,
|
|
90
|
+
onClick: () => T(e.value),
|
|
91
|
+
className: t("inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-sm font-medium transition-colors", w === e.value ? "border-action-primary-bg bg-action-primary-bg text-action-primary-text" : "border-border-seam text-text-primary hover:bg-bg-sunken"),
|
|
92
|
+
children: [c(e.key, e.label), D.data && /* @__PURE__ */ P("span", {
|
|
93
|
+
className: "tabular-nums opacity-80",
|
|
94
|
+
children: e.count(D.data)
|
|
95
|
+
})]
|
|
96
|
+
}, e.key))
|
|
97
|
+
}),
|
|
98
|
+
k.isLoading ? /* @__PURE__ */ P(s, { label: c("coolandlovely.brandOrders.loading", "Loading orders…") }) : k.isError || !k.data ? /* @__PURE__ */ P(o, {
|
|
99
|
+
message: k.error?.message,
|
|
100
|
+
onRetry: () => void k.refetch()
|
|
101
|
+
}) : k.data.items.length === 0 ? /* @__PURE__ */ P(d, {
|
|
102
|
+
icon: /* @__PURE__ */ P(O, { className: "h-8 w-8" }),
|
|
103
|
+
title: c("coolandlovely.brandOrders.emptyTitle", "No orders here"),
|
|
104
|
+
description: c("coolandlovely.brandOrders.emptyDescription", "Paid orders for this brand’s pieces appear here.")
|
|
105
|
+
}) : /* @__PURE__ */ P("div", {
|
|
106
|
+
className: "space-y-3",
|
|
107
|
+
"data-testid": "brand-orders-list",
|
|
108
|
+
children: k.data.items.map((e) => /* @__PURE__ */ F("button", {
|
|
109
|
+
type: "button",
|
|
110
|
+
onClick: () => p(`/brand-orders/${e.brandId}/${e.id}`),
|
|
111
|
+
className: "flex w-full items-center gap-4 rounded-xl border border-border-seam bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken/50",
|
|
112
|
+
children: [
|
|
113
|
+
/* @__PURE__ */ F("div", {
|
|
114
|
+
className: "min-w-0 flex-1",
|
|
115
|
+
children: [/* @__PURE__ */ P("p", {
|
|
116
|
+
className: "font-mono text-sm font-medium text-text-primary",
|
|
117
|
+
children: e.orderNumber
|
|
118
|
+
}), /* @__PURE__ */ F("p", {
|
|
119
|
+
className: "truncate text-xs text-text-secondary",
|
|
120
|
+
children: [
|
|
121
|
+
l(e.paidAt ?? e.createdAt),
|
|
122
|
+
" · ",
|
|
123
|
+
e.shippingName ?? "—",
|
|
124
|
+
" ·",
|
|
125
|
+
" ",
|
|
126
|
+
c("coolandlovely.orders.pieces", "{{count}} pieces", { count: e.itemCount })
|
|
127
|
+
]
|
|
128
|
+
})]
|
|
129
|
+
}),
|
|
130
|
+
/* @__PURE__ */ P(a, { status: e.fulfilment.refunded ? "REFUNDED" : e.fulfilment.status }),
|
|
131
|
+
/* @__PURE__ */ P("span", {
|
|
132
|
+
className: "w-28 text-right text-sm font-semibold tabular-nums text-text-primary",
|
|
133
|
+
children: u(e.brandSubtotal, e.currency)
|
|
134
|
+
}),
|
|
135
|
+
/* @__PURE__ */ P(E, { className: "h-4 w-4 text-text-secondary" })
|
|
136
|
+
]
|
|
137
|
+
}, e.id))
|
|
138
|
+
})
|
|
139
|
+
] })
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
function V({ order: e }) {
|
|
143
|
+
let n = i(), r = y(), a = e.fulfilment, [o, s] = C(a.carrier ?? ""), [c, l] = C(a.trackingNumber ?? ""), [u, d] = C(a.trackingUrl ?? ""), [f, h] = C(a.note ?? "");
|
|
144
|
+
if (a.status === "DELIVERED") return /* @__PURE__ */ P("p", {
|
|
145
|
+
className: "text-sm text-status-success-text",
|
|
146
|
+
children: n("coolandlovely.fulfilment.complete", "Delivered. Nothing left to do for this order.")
|
|
147
|
+
});
|
|
148
|
+
let g = {
|
|
149
|
+
brandId: e.brandId,
|
|
150
|
+
orderId: e.id,
|
|
151
|
+
carrier: o.trim() || null,
|
|
152
|
+
trackingNumber: c.trim() || null,
|
|
153
|
+
trackingUrl: u.trim() || null,
|
|
154
|
+
note: f.trim() || null
|
|
155
|
+
}, _ = !!g.carrier && !!g.trackingNumber;
|
|
156
|
+
return /* @__PURE__ */ F("div", {
|
|
157
|
+
className: "space-y-3 border-t border-border-seam pt-4",
|
|
158
|
+
children: [
|
|
159
|
+
/* @__PURE__ */ P(m, {
|
|
160
|
+
id: "coo-fulfilment-carrier",
|
|
161
|
+
label: n("coolandlovely.fulfilment.carrier", "Carrier"),
|
|
162
|
+
value: o,
|
|
163
|
+
onChange: s,
|
|
164
|
+
placeholder: "Delhivery"
|
|
165
|
+
}),
|
|
166
|
+
/* @__PURE__ */ P(m, {
|
|
167
|
+
id: "coo-fulfilment-tracking",
|
|
168
|
+
label: n("coolandlovely.fulfilment.trackingNumber", "Tracking number"),
|
|
169
|
+
value: c,
|
|
170
|
+
onChange: l
|
|
171
|
+
}),
|
|
172
|
+
/* @__PURE__ */ P(m, {
|
|
173
|
+
id: "coo-fulfilment-tracking-url",
|
|
174
|
+
type: "url",
|
|
175
|
+
label: n("coolandlovely.fulfilment.trackingUrl", "Tracking link (optional)"),
|
|
176
|
+
value: u,
|
|
177
|
+
onChange: d,
|
|
178
|
+
placeholder: "https://"
|
|
179
|
+
}),
|
|
180
|
+
/* @__PURE__ */ P(p, {
|
|
181
|
+
id: "coo-fulfilment-note",
|
|
182
|
+
label: n("coolandlovely.fulfilment.note", "Note for the buyer (optional)"),
|
|
183
|
+
value: f,
|
|
184
|
+
onChange: h,
|
|
185
|
+
rows: 2
|
|
186
|
+
}),
|
|
187
|
+
r.error && /* @__PURE__ */ P("p", {
|
|
188
|
+
className: "text-sm text-status-error-text",
|
|
189
|
+
children: r.error.message
|
|
190
|
+
}),
|
|
191
|
+
/* @__PURE__ */ F("div", {
|
|
192
|
+
className: "space-y-2",
|
|
193
|
+
children: [
|
|
194
|
+
a.status === "UNFULFILLED" && /* @__PURE__ */ F("button", {
|
|
195
|
+
type: "button",
|
|
196
|
+
disabled: r.isPending,
|
|
197
|
+
onClick: () => r.mutate({
|
|
198
|
+
...g,
|
|
199
|
+
status: "CONFIRMED"
|
|
200
|
+
}),
|
|
201
|
+
className: t(R, "w-full justify-center"),
|
|
202
|
+
children: [/* @__PURE__ */ P(T, { className: "h-4 w-4" }), n("coolandlovely.fulfilment.confirm", "Confirm order")]
|
|
203
|
+
}),
|
|
204
|
+
(a.status === "UNFULFILLED" || a.status === "CONFIRMED") && /* @__PURE__ */ F("button", {
|
|
205
|
+
type: "button",
|
|
206
|
+
disabled: r.isPending || !_,
|
|
207
|
+
onClick: () => r.mutate({
|
|
208
|
+
...g,
|
|
209
|
+
status: "SHIPPED"
|
|
210
|
+
}),
|
|
211
|
+
className: z,
|
|
212
|
+
children: [r.isPending ? /* @__PURE__ */ P(D, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ P(A, { className: "h-4 w-4" }), n("coolandlovely.fulfilment.markShipped", "Mark shipped")]
|
|
213
|
+
}),
|
|
214
|
+
a.status === "SHIPPED" && /* @__PURE__ */ F(N, { children: [/* @__PURE__ */ P("button", {
|
|
215
|
+
type: "button",
|
|
216
|
+
disabled: r.isPending || !_,
|
|
217
|
+
onClick: () => r.mutate({
|
|
218
|
+
...g,
|
|
219
|
+
status: "SHIPPED"
|
|
220
|
+
}),
|
|
221
|
+
className: t(R, "w-full justify-center"),
|
|
222
|
+
children: n("coolandlovely.fulfilment.saveTracking", "Save tracking details")
|
|
223
|
+
}), /* @__PURE__ */ F("button", {
|
|
224
|
+
type: "button",
|
|
225
|
+
disabled: r.isPending,
|
|
226
|
+
onClick: () => r.mutate({
|
|
227
|
+
...g,
|
|
228
|
+
status: "DELIVERED"
|
|
229
|
+
}),
|
|
230
|
+
className: z,
|
|
231
|
+
children: [r.isPending ? /* @__PURE__ */ P(D, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ P(k, { className: "h-4 w-4" }), n("coolandlovely.fulfilment.markDelivered", "Mark delivered")]
|
|
232
|
+
})] }),
|
|
233
|
+
!_ && a.status !== "SHIPPED" && /* @__PURE__ */ P("p", {
|
|
234
|
+
className: "text-xs text-text-secondary",
|
|
235
|
+
children: n("coolandlovely.fulfilment.trackingHint", "Add a carrier and tracking number to mark the order shipped.")
|
|
236
|
+
})
|
|
237
|
+
]
|
|
238
|
+
})
|
|
239
|
+
]
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
function H() {
|
|
243
|
+
let t = i(), { brandId: r, orderId: d } = j(), { navigateTo: f } = e(), p = g(r, d), m = t("coolandlovely.brandOrders.detailTitle", "Order"), _ = () => f(`/brand-orders?brand=${r ?? ""}`);
|
|
244
|
+
if (p.isLoading) return /* @__PURE__ */ P(n, {
|
|
245
|
+
title: m,
|
|
246
|
+
children: /* @__PURE__ */ P(s, {})
|
|
247
|
+
});
|
|
248
|
+
if (p.isError || !p.data) return /* @__PURE__ */ P(n, {
|
|
249
|
+
title: m,
|
|
250
|
+
children: /* @__PURE__ */ P(o, {
|
|
251
|
+
title: t("coolandlovely.orders.notFound", "Order not found"),
|
|
252
|
+
message: p.error?.message,
|
|
253
|
+
onRetry: () => void p.refetch()
|
|
254
|
+
})
|
|
255
|
+
});
|
|
256
|
+
let v = p.data, y = v.fulfilment.refunded || v.refund?.status === "PENDING" || v.refund?.status === "COMPLETED";
|
|
257
|
+
return /* @__PURE__ */ P(n, {
|
|
258
|
+
title: v.orderNumber,
|
|
259
|
+
description: t("coolandlovely.brandOrders.paidOn", "Paid {{date}}", { date: l(v.paidAt ?? v.createdAt) }),
|
|
260
|
+
actions: /* @__PURE__ */ F("button", {
|
|
261
|
+
type: "button",
|
|
262
|
+
onClick: _,
|
|
263
|
+
className: R,
|
|
264
|
+
children: [
|
|
265
|
+
/* @__PURE__ */ P(w, { className: "h-4 w-4" }),
|
|
266
|
+
" ",
|
|
267
|
+
t("coolandlovely.common.back", "Back")
|
|
268
|
+
]
|
|
269
|
+
}),
|
|
270
|
+
children: /* @__PURE__ */ F("div", {
|
|
271
|
+
className: "grid grid-cols-1 gap-6 lg:grid-cols-3",
|
|
272
|
+
children: [/* @__PURE__ */ F("div", {
|
|
273
|
+
className: "space-y-3 lg:col-span-2",
|
|
274
|
+
children: [v.items.map((e) => /* @__PURE__ */ F(I, {
|
|
275
|
+
treatment: "plain",
|
|
276
|
+
className: "flex items-center gap-4 p-4",
|
|
277
|
+
children: [
|
|
278
|
+
/* @__PURE__ */ P(c, {
|
|
279
|
+
icon: /* @__PURE__ */ P(O, { className: "h-5 w-5" }),
|
|
280
|
+
seed: e.styleItemId,
|
|
281
|
+
fileId: e.image?.id,
|
|
282
|
+
alt: e.name,
|
|
283
|
+
className: "h-14 w-14 shrink-0"
|
|
284
|
+
}),
|
|
285
|
+
/* @__PURE__ */ F("div", {
|
|
286
|
+
className: "min-w-0 flex-1",
|
|
287
|
+
children: [/* @__PURE__ */ P("p", {
|
|
288
|
+
className: "truncate text-sm font-medium text-text-primary",
|
|
289
|
+
children: e.name
|
|
290
|
+
}), /* @__PURE__ */ P("p", {
|
|
291
|
+
className: "truncate text-xs text-text-secondary",
|
|
292
|
+
children: [
|
|
293
|
+
e.sku,
|
|
294
|
+
e.size,
|
|
295
|
+
e.colour,
|
|
296
|
+
`× ${e.quantity}`
|
|
297
|
+
].filter(Boolean).join(" · ")
|
|
298
|
+
})]
|
|
299
|
+
}),
|
|
300
|
+
/* @__PURE__ */ P("span", {
|
|
301
|
+
className: "text-sm font-semibold tabular-nums text-text-primary",
|
|
302
|
+
children: u(e.lineTotal, v.currency)
|
|
303
|
+
})
|
|
304
|
+
]
|
|
305
|
+
}, e.id)), /* @__PURE__ */ F(I, {
|
|
306
|
+
treatment: "plain",
|
|
307
|
+
className: "space-y-1 p-4 text-sm",
|
|
308
|
+
children: [
|
|
309
|
+
/* @__PURE__ */ P("p", {
|
|
310
|
+
className: "text-xs font-medium uppercase tracking-wide text-text-secondary",
|
|
311
|
+
children: t("coolandlovely.orders.shipTo", "Ship to")
|
|
312
|
+
}),
|
|
313
|
+
/* @__PURE__ */ P("p", {
|
|
314
|
+
className: "text-text-primary",
|
|
315
|
+
children: v.shippingName
|
|
316
|
+
}),
|
|
317
|
+
/* @__PURE__ */ P("p", {
|
|
318
|
+
className: "whitespace-pre-line text-text-secondary",
|
|
319
|
+
children: v.shippingAddress
|
|
320
|
+
}),
|
|
321
|
+
v.buyerNote && /* @__PURE__ */ P("p", {
|
|
322
|
+
className: "pt-2 text-text-secondary",
|
|
323
|
+
children: t("coolandlovely.brandOrders.buyerNote", "Buyer note: {{note}}", { note: v.buyerNote })
|
|
324
|
+
})
|
|
325
|
+
]
|
|
326
|
+
})]
|
|
327
|
+
}), /* @__PURE__ */ F(I, {
|
|
328
|
+
treatment: "glass",
|
|
329
|
+
className: "h-fit space-y-4 p-6",
|
|
330
|
+
children: [
|
|
331
|
+
/* @__PURE__ */ F("div", {
|
|
332
|
+
className: "flex items-center justify-between",
|
|
333
|
+
children: [/* @__PURE__ */ P("span", {
|
|
334
|
+
className: "text-sm text-text-secondary",
|
|
335
|
+
children: t("coolandlovely.fulfilment.status", "Fulfilment")
|
|
336
|
+
}), /* @__PURE__ */ P("span", {
|
|
337
|
+
"data-testid": "fulfilment-status",
|
|
338
|
+
children: /* @__PURE__ */ P(a, { status: v.fulfilment.refunded ? "REFUNDED" : v.fulfilment.status })
|
|
339
|
+
})]
|
|
340
|
+
}),
|
|
341
|
+
/* @__PURE__ */ F("div", {
|
|
342
|
+
className: "flex justify-between text-sm",
|
|
343
|
+
children: [/* @__PURE__ */ P("span", {
|
|
344
|
+
className: "text-text-secondary",
|
|
345
|
+
children: t("coolandlovely.brandOrders.brandSubtotal", "Your pieces")
|
|
346
|
+
}), /* @__PURE__ */ P("span", {
|
|
347
|
+
className: "font-semibold tabular-nums text-text-primary",
|
|
348
|
+
children: u(v.brandSubtotal, v.currency)
|
|
349
|
+
})]
|
|
350
|
+
}),
|
|
351
|
+
/* @__PURE__ */ P(h, { fulfilment: v.fulfilment }),
|
|
352
|
+
!y && /* @__PURE__ */ P(V, { order: v }, v.fulfilment.updatedAt ?? "new"),
|
|
353
|
+
/* @__PURE__ */ P(b, { order: v })
|
|
354
|
+
]
|
|
355
|
+
})]
|
|
356
|
+
})
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
//#endregion
|
|
360
|
+
export { H as BrandOrderDetailPage, B as BrandOrdersPage };
|
|
361
|
+
|
|
362
|
+
//# sourceMappingURL=BrandOrdersPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BrandOrdersPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/commerce/BrandOrdersPage.tsx"],"sourcesContent":["/**\n * Brand orders + brand order detail (BOFF-9636)\n * @module coolandlovely/pages/commerce\n *\n * The brand side of CoolAndLovely orders: the paid orders that contain a brand's pieces\n * (`cooBrandOrders`, only that brand's lines), counts per fulfilment state\n * (`cooBrandOrderSummary`), and one order's fulfilment — confirm it, ship it with tracking,\n * mark it delivered (`cooUpdateOrderFulfilment`). Fulfilment only moves forward, and the\n * buyer is notified of every change. A brand can also refund all of its pieces of an order\n * (`cooRefundBrandOrder`, BOFF-9702); refunded pieces are no longer fulfilled.\n */\n\nimport { useEffect, useMemo, useState } from 'react';\nimport { useParams, useSearchParams } from 'react-router';\nimport {\n ArrowLeft,\n CheckCircle2,\n ChevronRight,\n Loader2,\n Package,\n PackageCheck,\n Truck,\n} from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\n\nimport { EmptyState } from '../../components/EmptyState';\nimport { FulfilmentTimeline } from '../../components/FulfilmentTimeline';\nimport { SelectField, TextAreaField, TextField } from '../../components/Field';\nimport { PageLayout } from '../../components/PageLayout';\nimport { RefundPanel } from '../../components/RefundPanel';\nimport { ErrorView, LoadingView } from '../../components/StateViews';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useBrands, useTr } from '../../hooks';\nimport {\n useBrandOrder,\n useBrandOrderSummary,\n useBrandOrders,\n useUpdateOrderFulfilment,\n} from '../../hooks/useBrandOrdersApi';\nimport type { CooBrandOrder, CooBrandOrderSummary, CooFulfilmentStatus } from '../../types';\nimport { cn } from '../../utils/cn';\nimport { formatDate, formatPrice } from '../../utils/formatters';\n\nconst FILTERS: Array<{\n value: CooFulfilmentStatus | undefined;\n key: string;\n label: string;\n count: (summary: CooBrandOrderSummary) => number;\n}> = [\n {\n value: undefined,\n key: 'coolandlovely.brandOrders.filterAll',\n label: 'All',\n count: (s) => s.total,\n },\n {\n value: 'UNFULFILLED',\n key: 'coolandlovely.brandOrders.filterUnfulfilled',\n label: 'To confirm',\n count: (s) => s.unfulfilled,\n },\n {\n value: 'CONFIRMED',\n key: 'coolandlovely.brandOrders.filterConfirmed',\n label: 'Confirmed',\n count: (s) => s.confirmed,\n },\n {\n value: 'SHIPPED',\n key: 'coolandlovely.brandOrders.filterShipped',\n label: 'Shipped',\n count: (s) => s.shipped,\n },\n {\n value: 'DELIVERED',\n key: 'coolandlovely.brandOrders.filterDelivered',\n label: 'Delivered',\n count: (s) => s.delivered,\n },\n];\n\nconst secondaryButton =\n '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 disabled:opacity-50';\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\nexport function BrandOrdersPage() {\n const tr = useTr();\n const { navigateTo } = useCoolAndLovely();\n const [searchParams, setSearchParams] = useSearchParams();\n const brands = useBrands({ pagination: { limit: 100, offset: 0 } });\n const brandOptions = useMemo(\n () => (brands.data?.items ?? []).map((brand) => ({ value: brand.id, label: brand.name })),\n [brands.data]\n );\n const brandId = searchParams.get('brand') ?? brandOptions[0]?.value;\n const [status, setStatus] = useState<CooFulfilmentStatus | undefined>(undefined);\n const summary = useBrandOrderSummary(brandId);\n const orders = useBrandOrders(brandId, status);\n const title = tr('coolandlovely.brandOrders.title', 'Brand orders');\n\n useEffect(() => setStatus(undefined), [brandId]);\n\n const selectBrand = (value: string) => {\n const next = new URLSearchParams(searchParams);\n next.set('brand', value);\n setSearchParams(next, { replace: true });\n };\n\n return (\n <PageLayout\n title={title}\n description={tr(\n 'coolandlovely.brandOrders.description',\n 'Paid orders for your pieces. Confirm them, ship them with tracking and mark them delivered.'\n )}\n >\n {brands.isLoading ? (\n <LoadingView />\n ) : brandOptions.length === 0 ? (\n <EmptyState\n icon={<Package className=\"h-8 w-8\" />}\n title={tr('coolandlovely.brandOrders.noBrandsTitle', 'No brands yet')}\n description={tr(\n 'coolandlovely.brandOrders.noBrandsDescription',\n 'Create a brand storefront to start selling pieces.'\n )}\n />\n ) : (\n <>\n <div className=\"mb-4 max-w-sm\">\n <SelectField\n id=\"coo-brand-orders-brand\"\n label={tr('coolandlovely.brandOrders.brand', 'Brand')}\n value={brandId ?? ''}\n onChange={selectBrand}\n options={brandOptions}\n />\n </div>\n <div className=\"mb-4 flex flex-wrap gap-2\" role=\"tablist\">\n {FILTERS.map((filter) => (\n <button\n key={filter.key}\n type=\"button\"\n role=\"tab\"\n aria-selected={status === filter.value}\n onClick={() => setStatus(filter.value)}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-sm font-medium transition-colors',\n status === filter.value\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 >\n {tr(filter.key, filter.label)}\n {summary.data && (\n <span className=\"tabular-nums opacity-80\">{filter.count(summary.data)}</span>\n )}\n </button>\n ))}\n </div>\n {orders.isLoading ? (\n <LoadingView label={tr('coolandlovely.brandOrders.loading', 'Loading orders…')} />\n ) : orders.isError || !orders.data ? (\n <ErrorView message={orders.error?.message} onRetry={() => void orders.refetch()} />\n ) : orders.data.items.length === 0 ? (\n <EmptyState\n icon={<Package className=\"h-8 w-8\" />}\n title={tr('coolandlovely.brandOrders.emptyTitle', 'No orders here')}\n description={tr(\n 'coolandlovely.brandOrders.emptyDescription',\n 'Paid orders for this brand’s pieces appear here.'\n )}\n />\n ) : (\n <div className=\"space-y-3\" data-testid=\"brand-orders-list\">\n {orders.data.items.map((order) => (\n <button\n key={order.id}\n type=\"button\"\n onClick={() => navigateTo(`/brand-orders/${order.brandId}/${order.id}`)}\n className=\"flex w-full items-center gap-4 rounded-xl border border-border-seam bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-mono text-sm font-medium text-text-primary\">\n {order.orderNumber}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">\n {formatDate(order.paidAt ?? order.createdAt)} · {order.shippingName ?? '—'} ·{' '}\n {tr('coolandlovely.orders.pieces', '{{count}} pieces', {\n count: order.itemCount,\n })}\n </p>\n </div>\n <StatusBadge\n status={order.fulfilment.refunded ? 'REFUNDED' : order.fulfilment.status}\n />\n <span className=\"w-28 text-right text-sm font-semibold tabular-nums text-text-primary\">\n {formatPrice(order.brandSubtotal, order.currency)}\n </span>\n <ChevronRight className=\"h-4 w-4 text-text-secondary\" />\n </button>\n ))}\n </div>\n )}\n </>\n )}\n </PageLayout>\n );\n}\n\nfunction FulfilmentForm({ order }: { order: CooBrandOrder }) {\n const tr = useTr();\n const update = useUpdateOrderFulfilment();\n const current = order.fulfilment;\n const [carrier, setCarrier] = useState(current.carrier ?? '');\n const [trackingNumber, setTrackingNumber] = useState(current.trackingNumber ?? '');\n const [trackingUrl, setTrackingUrl] = useState(current.trackingUrl ?? '');\n const [note, setNote] = useState(current.note ?? '');\n\n if (current.status === 'DELIVERED') {\n return (\n <p className=\"text-sm text-status-success-text\">\n {tr('coolandlovely.fulfilment.complete', 'Delivered. Nothing left to do for this order.')}\n </p>\n );\n }\n\n const details = {\n brandId: order.brandId,\n orderId: order.id,\n carrier: carrier.trim() || null,\n trackingNumber: trackingNumber.trim() || null,\n trackingUrl: trackingUrl.trim() || null,\n note: note.trim() || null,\n };\n const canShip = !!details.carrier && !!details.trackingNumber;\n\n return (\n <div className=\"space-y-3 border-t border-border-seam pt-4\">\n <TextField\n id=\"coo-fulfilment-carrier\"\n label={tr('coolandlovely.fulfilment.carrier', 'Carrier')}\n value={carrier}\n onChange={setCarrier}\n placeholder=\"Delhivery\"\n />\n <TextField\n id=\"coo-fulfilment-tracking\"\n label={tr('coolandlovely.fulfilment.trackingNumber', 'Tracking number')}\n value={trackingNumber}\n onChange={setTrackingNumber}\n />\n <TextField\n id=\"coo-fulfilment-tracking-url\"\n type=\"url\"\n label={tr('coolandlovely.fulfilment.trackingUrl', 'Tracking link (optional)')}\n value={trackingUrl}\n onChange={setTrackingUrl}\n placeholder=\"https://\"\n />\n <TextAreaField\n id=\"coo-fulfilment-note\"\n label={tr('coolandlovely.fulfilment.note', 'Note for the buyer (optional)')}\n value={note}\n onChange={setNote}\n rows={2}\n />\n {update.error && <p className=\"text-sm text-status-error-text\">{update.error.message}</p>}\n <div className=\"space-y-2\">\n {current.status === 'UNFULFILLED' && (\n <button\n type=\"button\"\n disabled={update.isPending}\n onClick={() => update.mutate({ ...details, status: 'CONFIRMED' })}\n className={cn(secondaryButton, 'w-full justify-center')}\n >\n <CheckCircle2 className=\"h-4 w-4\" />\n {tr('coolandlovely.fulfilment.confirm', 'Confirm order')}\n </button>\n )}\n {(current.status === 'UNFULFILLED' || current.status === 'CONFIRMED') && (\n <button\n type=\"button\"\n disabled={update.isPending || !canShip}\n onClick={() => update.mutate({ ...details, status: 'SHIPPED' })}\n className={primaryButton}\n >\n {update.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Truck className=\"h-4 w-4\" />\n )}\n {tr('coolandlovely.fulfilment.markShipped', 'Mark shipped')}\n </button>\n )}\n {current.status === 'SHIPPED' && (\n <>\n <button\n type=\"button\"\n disabled={update.isPending || !canShip}\n onClick={() => update.mutate({ ...details, status: 'SHIPPED' })}\n className={cn(secondaryButton, 'w-full justify-center')}\n >\n {tr('coolandlovely.fulfilment.saveTracking', 'Save tracking details')}\n </button>\n <button\n type=\"button\"\n disabled={update.isPending}\n onClick={() => update.mutate({ ...details, status: 'DELIVERED' })}\n className={primaryButton}\n >\n {update.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <PackageCheck className=\"h-4 w-4\" />\n )}\n {tr('coolandlovely.fulfilment.markDelivered', 'Mark delivered')}\n </button>\n </>\n )}\n {!canShip && current.status !== 'SHIPPED' && (\n <p className=\"text-xs text-text-secondary\">\n {tr(\n 'coolandlovely.fulfilment.trackingHint',\n 'Add a carrier and tracking number to mark the order shipped.'\n )}\n </p>\n )}\n </div>\n </div>\n );\n}\n\nexport function BrandOrderDetailPage() {\n const tr = useTr();\n const { brandId, orderId } = useParams<{ brandId: string; orderId: string }>();\n const { navigateTo } = useCoolAndLovely();\n const order = useBrandOrder(brandId, orderId);\n const title = tr('coolandlovely.brandOrders.detailTitle', 'Order');\n const back = () => navigateTo(`/brand-orders?brand=${brandId ?? ''}`);\n\n if (order.isLoading) {\n return (\n <PageLayout title={title}>\n <LoadingView />\n </PageLayout>\n );\n }\n if (order.isError || !order.data) {\n return (\n <PageLayout title={title}>\n <ErrorView\n title={tr('coolandlovely.orders.notFound', 'Order not found')}\n message={order.error?.message}\n onRetry={() => void order.refetch()}\n />\n </PageLayout>\n );\n }\n\n const data = order.data;\n // Pieces the brand refunded, or is refunding, are not shipped.\n const refundBlocksFulfilment =\n data.fulfilment.refunded ||\n data.refund?.status === 'PENDING' ||\n data.refund?.status === 'COMPLETED';\n return (\n <PageLayout\n title={data.orderNumber}\n description={tr('coolandlovely.brandOrders.paidOn', 'Paid {{date}}', {\n date: formatDate(data.paidAt ?? data.createdAt),\n })}\n actions={\n <button type=\"button\" onClick={back} className={secondaryButton}>\n <ArrowLeft className=\"h-4 w-4\" /> {tr('coolandlovely.common.back', 'Back')}\n </button>\n }\n >\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <div className=\"space-y-3 lg:col-span-2\">\n {data.items.map((item) => (\n <GlassCard key={item.id} treatment=\"plain\" className=\"flex items-center gap-4 p-4\">\n <Thumbnail\n icon={<Package className=\"h-5 w-5\" />}\n seed={item.styleItemId}\n fileId={item.image?.id}\n alt={item.name}\n className=\"h-14 w-14 shrink-0\"\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{item.name}</p>\n <p className=\"truncate text-xs text-text-secondary\">\n {[item.sku, item.size, item.colour, `× ${item.quantity}`]\n .filter(Boolean)\n .join(' · ')}\n </p>\n </div>\n <span className=\"text-sm font-semibold tabular-nums text-text-primary\">\n {formatPrice(item.lineTotal, data.currency)}\n </span>\n </GlassCard>\n ))}\n <GlassCard treatment=\"plain\" className=\"space-y-1 p-4 text-sm\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-text-secondary\">\n {tr('coolandlovely.orders.shipTo', 'Ship to')}\n </p>\n <p className=\"text-text-primary\">{data.shippingName}</p>\n <p className=\"whitespace-pre-line text-text-secondary\">{data.shippingAddress}</p>\n {data.buyerNote && (\n <p className=\"pt-2 text-text-secondary\">\n {tr('coolandlovely.brandOrders.buyerNote', 'Buyer note: {{note}}', {\n note: data.buyerNote,\n })}\n </p>\n )}\n </GlassCard>\n </div>\n <GlassCard treatment=\"glass\" className=\"h-fit space-y-4 p-6\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm text-text-secondary\">\n {tr('coolandlovely.fulfilment.status', 'Fulfilment')}\n </span>\n <span data-testid=\"fulfilment-status\">\n <StatusBadge\n status={data.fulfilment.refunded ? 'REFUNDED' : data.fulfilment.status}\n />\n </span>\n </div>\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-secondary\">\n {tr('coolandlovely.brandOrders.brandSubtotal', 'Your pieces')}\n </span>\n <span className=\"font-semibold tabular-nums text-text-primary\">\n {formatPrice(data.brandSubtotal, data.currency)}\n </span>\n </div>\n <FulfilmentTimeline fulfilment={data.fulfilment} />\n {!refundBlocksFulfilment && (\n <FulfilmentForm key={data.fulfilment.updatedAt ?? 'new'} order={data} />\n )}\n <RefundPanel order={data} />\n </GlassCard>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -7,8 +7,8 @@ import { Thumbnail as a } from "../../components/Thumbnail.js";
|
|
|
7
7
|
import { formatPrice as o } from "../../utils/formatters.js";
|
|
8
8
|
import { EmptyState as s } from "../../components/EmptyState.js";
|
|
9
9
|
import { TextAreaField as c, TextField as l } from "../../components/Field.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { useCheckout as u, useMyCart as d, useRemoveCartItem as f, useSyncOrderPayment as p, useUpdateCartItem as m } from "../../hooks/useCommerceApi.js";
|
|
11
|
+
import { PayForOrder as h } from "../../components/PayForOrder.js";
|
|
12
12
|
import { useState as g } from "react";
|
|
13
13
|
import { ArrowLeft as _, Loader2 as v, Minus as y, Plus as b, ShoppingBag as x, Sparkles as S, Trash2 as C } from "lucide-react";
|
|
14
14
|
import { jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
@@ -16,7 +16,7 @@ import { GlassCard as E } from "@burdenoff/fe-libs/ui";
|
|
|
16
16
|
//#region src/coolandlovely/pages/commerce/CartPage.tsx
|
|
17
17
|
var D = 10;
|
|
18
18
|
function O() {
|
|
19
|
-
let O = n(), { navigateTo: k } = e(), A =
|
|
19
|
+
let O = n(), { navigateTo: k } = e(), A = d(), j = m(), M = f(), N = u(), P = p(), [F, I] = g(""), [L, R] = g(""), [z, B] = g(""), [V, H] = g(null), U = O("coolandlovely.cart.title", "Your cart");
|
|
20
20
|
if (A.isLoading) return /* @__PURE__ */ w(t, {
|
|
21
21
|
title: U,
|
|
22
22
|
children: /* @__PURE__ */ w(i, { label: O("coolandlovely.cart.loading", "Loading your cart…") })
|
|
@@ -70,7 +70,7 @@ function O() {
|
|
|
70
70
|
})
|
|
71
71
|
]
|
|
72
72
|
}),
|
|
73
|
-
/* @__PURE__ */ w(
|
|
73
|
+
/* @__PURE__ */ w(h, {
|
|
74
74
|
checkout: V,
|
|
75
75
|
onSettle: async () => {
|
|
76
76
|
await P.mutateAsync(V.order.id).catch(() => void 0), k(`/orders/${V.order.id}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreatorEarningsPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/commerce/CreatorEarningsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"CreatorEarningsPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/commerce/CreatorEarningsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAqBH,wBAAgB,mBAAmB,gCAoMlC"}
|