@burdenoff/microfe-coolandlovely 2026.1024.4 → 2026.1026.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.
Files changed (32) hide show
  1. package/dist/coolandlovely/CoolAndLovelyRoutes.d.ts.map +1 -1
  2. package/dist/coolandlovely/CoolAndLovelyRoutes.js +20 -12
  3. package/dist/coolandlovely/CoolAndLovelyRoutes.js.map +1 -1
  4. package/dist/coolandlovely/components/FulfilmentTimeline.d.ts +7 -0
  5. package/dist/coolandlovely/components/FulfilmentTimeline.d.ts.map +1 -0
  6. package/dist/coolandlovely/components/FulfilmentTimeline.js +77 -0
  7. package/dist/coolandlovely/components/FulfilmentTimeline.js.map +1 -0
  8. package/dist/coolandlovely/components/StatusBadge.d.ts.map +1 -1
  9. package/dist/coolandlovely/components/StatusBadge.js +9 -1
  10. package/dist/coolandlovely/components/StatusBadge.js.map +1 -1
  11. package/dist/coolandlovely/hooks/useBrandOrdersApi.d.ts +7 -0
  12. package/dist/coolandlovely/hooks/useBrandOrdersApi.d.ts.map +1 -0
  13. package/dist/coolandlovely/hooks/useBrandOrdersApi.js +92 -0
  14. package/dist/coolandlovely/hooks/useBrandOrdersApi.js.map +1 -0
  15. package/dist/coolandlovely/hooks/useCommerceApi.d.ts +2 -0
  16. package/dist/coolandlovely/hooks/useCommerceApi.d.ts.map +1 -1
  17. package/dist/coolandlovely/hooks/useCommerceApi.js +26 -22
  18. package/dist/coolandlovely/hooks/useCommerceApi.js.map +1 -1
  19. package/dist/coolandlovely/pages/brands/BrandDetailPage.d.ts.map +1 -1
  20. package/dist/coolandlovely/pages/brands/BrandDetailPage.js +157 -148
  21. package/dist/coolandlovely/pages/brands/BrandDetailPage.js.map +1 -1
  22. package/dist/coolandlovely/pages/commerce/BrandOrdersPage.d.ts +13 -0
  23. package/dist/coolandlovely/pages/commerce/BrandOrdersPage.d.ts.map +1 -0
  24. package/dist/coolandlovely/pages/commerce/BrandOrdersPage.js +360 -0
  25. package/dist/coolandlovely/pages/commerce/BrandOrdersPage.js.map +1 -0
  26. package/dist/coolandlovely/pages/commerce/CartPage.js +4 -4
  27. package/dist/coolandlovely/pages/commerce/OrdersPage.d.ts.map +1 -1
  28. package/dist/coolandlovely/pages/commerce/OrdersPage.js +122 -101
  29. package/dist/coolandlovely/pages/commerce/OrdersPage.js.map +1 -1
  30. package/dist/coolandlovely/types/commerce.d.ts +61 -0
  31. package/dist/coolandlovely/types/commerce.d.ts.map +1 -1
  32. 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":"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"}
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,13 @@
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.
10
+ */
11
+ export declare function BrandOrdersPage(): import("react").JSX.Element;
12
+ export declare function BrandOrderDetailPage(): import("react").JSX.Element;
13
+ //# 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;;;;;;;;;GASG;AA6EH,wBAAgB,eAAe,gCAyH9B;AA6HD,wBAAgB,oBAAoB,gCAsGnC"}
@@ -0,0 +1,360 @@
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 { useEffect as b, useMemo as x, useState as S } from "react";
16
+ import { ArrowLeft as C, CheckCircle2 as w, ChevronRight as T, Loader2 as E, Package as D, PackageCheck as O, Truck as k } from "lucide-react";
17
+ import { useParams as A, useSearchParams as j } from "react-router";
18
+ import { Fragment as M, jsx as N, jsxs as P } from "react/jsx-runtime";
19
+ import { GlassCard as F } from "@burdenoff/fe-libs/ui";
20
+ //#region src/coolandlovely/pages/commerce/BrandOrdersPage.tsx
21
+ var I = [
22
+ {
23
+ value: void 0,
24
+ key: "coolandlovely.brandOrders.filterAll",
25
+ label: "All",
26
+ count: (e) => e.total
27
+ },
28
+ {
29
+ value: "UNFULFILLED",
30
+ key: "coolandlovely.brandOrders.filterUnfulfilled",
31
+ label: "To confirm",
32
+ count: (e) => e.unfulfilled
33
+ },
34
+ {
35
+ value: "CONFIRMED",
36
+ key: "coolandlovely.brandOrders.filterConfirmed",
37
+ label: "Confirmed",
38
+ count: (e) => e.confirmed
39
+ },
40
+ {
41
+ value: "SHIPPED",
42
+ key: "coolandlovely.brandOrders.filterShipped",
43
+ label: "Shipped",
44
+ count: (e) => e.shipped
45
+ },
46
+ {
47
+ value: "DELIVERED",
48
+ key: "coolandlovely.brandOrders.filterDelivered",
49
+ label: "Delivered",
50
+ count: (e) => e.delivered
51
+ }
52
+ ], L = "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", R = "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";
53
+ function z() {
54
+ let c = i(), { navigateTo: p } = e(), [m, h] = j(), g = r({ pagination: {
55
+ limit: 100,
56
+ offset: 0
57
+ } }), y = x(() => (g.data?.items ?? []).map((e) => ({
58
+ value: e.id,
59
+ label: e.name
60
+ })), [g.data]), C = m.get("brand") ?? y[0]?.value, [w, E] = S(void 0), O = _(C), k = v(C, w), A = c("coolandlovely.brandOrders.title", "Brand orders");
61
+ return b(() => E(void 0), [C]), /* @__PURE__ */ N(n, {
62
+ title: A,
63
+ description: c("coolandlovely.brandOrders.description", "Paid orders for your pieces. Confirm them, ship them with tracking and mark them delivered."),
64
+ children: g.isLoading ? /* @__PURE__ */ N(s, {}) : y.length === 0 ? /* @__PURE__ */ N(d, {
65
+ icon: /* @__PURE__ */ N(D, { className: "h-8 w-8" }),
66
+ title: c("coolandlovely.brandOrders.noBrandsTitle", "No brands yet"),
67
+ description: c("coolandlovely.brandOrders.noBrandsDescription", "Create a brand storefront to start selling pieces.")
68
+ }) : /* @__PURE__ */ P(M, { children: [
69
+ /* @__PURE__ */ N("div", {
70
+ className: "mb-4 max-w-sm",
71
+ children: /* @__PURE__ */ N(f, {
72
+ id: "coo-brand-orders-brand",
73
+ label: c("coolandlovely.brandOrders.brand", "Brand"),
74
+ value: C ?? "",
75
+ onChange: (e) => {
76
+ let t = new URLSearchParams(m);
77
+ t.set("brand", e), h(t, { replace: !0 });
78
+ },
79
+ options: y
80
+ })
81
+ }),
82
+ /* @__PURE__ */ N("div", {
83
+ className: "mb-4 flex flex-wrap gap-2",
84
+ role: "tablist",
85
+ children: I.map((e) => /* @__PURE__ */ P("button", {
86
+ type: "button",
87
+ role: "tab",
88
+ "aria-selected": w === e.value,
89
+ onClick: () => E(e.value),
90
+ 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"),
91
+ children: [c(e.key, e.label), O.data && /* @__PURE__ */ N("span", {
92
+ className: "tabular-nums opacity-80",
93
+ children: e.count(O.data)
94
+ })]
95
+ }, e.key))
96
+ }),
97
+ k.isLoading ? /* @__PURE__ */ N(s, { label: c("coolandlovely.brandOrders.loading", "Loading orders…") }) : k.isError || !k.data ? /* @__PURE__ */ N(o, {
98
+ message: k.error?.message,
99
+ onRetry: () => void k.refetch()
100
+ }) : k.data.items.length === 0 ? /* @__PURE__ */ N(d, {
101
+ icon: /* @__PURE__ */ N(D, { className: "h-8 w-8" }),
102
+ title: c("coolandlovely.brandOrders.emptyTitle", "No orders here"),
103
+ description: c("coolandlovely.brandOrders.emptyDescription", "Paid orders for this brand’s pieces appear here.")
104
+ }) : /* @__PURE__ */ N("div", {
105
+ className: "space-y-3",
106
+ "data-testid": "brand-orders-list",
107
+ children: k.data.items.map((e) => /* @__PURE__ */ P("button", {
108
+ type: "button",
109
+ onClick: () => p(`/brand-orders/${e.brandId}/${e.id}`),
110
+ 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",
111
+ children: [
112
+ /* @__PURE__ */ P("div", {
113
+ className: "min-w-0 flex-1",
114
+ children: [/* @__PURE__ */ N("p", {
115
+ className: "font-mono text-sm font-medium text-text-primary",
116
+ children: e.orderNumber
117
+ }), /* @__PURE__ */ P("p", {
118
+ className: "truncate text-xs text-text-secondary",
119
+ children: [
120
+ l(e.paidAt ?? e.createdAt),
121
+ " · ",
122
+ e.shippingName ?? "—",
123
+ " ·",
124
+ " ",
125
+ c("coolandlovely.orders.pieces", "{{count}} pieces", { count: e.itemCount })
126
+ ]
127
+ })]
128
+ }),
129
+ /* @__PURE__ */ N(a, { status: e.fulfilment.status }),
130
+ /* @__PURE__ */ N("span", {
131
+ className: "w-28 text-right text-sm font-semibold tabular-nums text-text-primary",
132
+ children: u(e.brandSubtotal, e.currency)
133
+ }),
134
+ /* @__PURE__ */ N(T, { className: "h-4 w-4 text-text-secondary" })
135
+ ]
136
+ }, e.id))
137
+ })
138
+ ] })
139
+ });
140
+ }
141
+ function B({ order: e }) {
142
+ let n = i(), r = y(), a = e.fulfilment, [o, s] = S(a.carrier ?? ""), [c, l] = S(a.trackingNumber ?? ""), [u, d] = S(a.trackingUrl ?? ""), [f, h] = S(a.note ?? "");
143
+ if (a.status === "DELIVERED") return /* @__PURE__ */ N("p", {
144
+ className: "text-sm text-status-success-text",
145
+ children: n("coolandlovely.fulfilment.complete", "Delivered. Nothing left to do for this order.")
146
+ });
147
+ let g = {
148
+ brandId: e.brandId,
149
+ orderId: e.id,
150
+ carrier: o.trim() || null,
151
+ trackingNumber: c.trim() || null,
152
+ trackingUrl: u.trim() || null,
153
+ note: f.trim() || null
154
+ }, _ = !!g.carrier && !!g.trackingNumber;
155
+ return /* @__PURE__ */ P("div", {
156
+ className: "space-y-3 border-t border-border-seam pt-4",
157
+ children: [
158
+ /* @__PURE__ */ N(m, {
159
+ id: "coo-fulfilment-carrier",
160
+ label: n("coolandlovely.fulfilment.carrier", "Carrier"),
161
+ value: o,
162
+ onChange: s,
163
+ placeholder: "Delhivery"
164
+ }),
165
+ /* @__PURE__ */ N(m, {
166
+ id: "coo-fulfilment-tracking",
167
+ label: n("coolandlovely.fulfilment.trackingNumber", "Tracking number"),
168
+ value: c,
169
+ onChange: l
170
+ }),
171
+ /* @__PURE__ */ N(m, {
172
+ id: "coo-fulfilment-tracking-url",
173
+ type: "url",
174
+ label: n("coolandlovely.fulfilment.trackingUrl", "Tracking link (optional)"),
175
+ value: u,
176
+ onChange: d,
177
+ placeholder: "https://"
178
+ }),
179
+ /* @__PURE__ */ N(p, {
180
+ id: "coo-fulfilment-note",
181
+ label: n("coolandlovely.fulfilment.note", "Note for the buyer (optional)"),
182
+ value: f,
183
+ onChange: h,
184
+ rows: 2
185
+ }),
186
+ r.error && /* @__PURE__ */ N("p", {
187
+ className: "text-sm text-status-error-text",
188
+ children: r.error.message
189
+ }),
190
+ /* @__PURE__ */ P("div", {
191
+ className: "space-y-2",
192
+ children: [
193
+ a.status === "UNFULFILLED" && /* @__PURE__ */ P("button", {
194
+ type: "button",
195
+ disabled: r.isPending,
196
+ onClick: () => r.mutate({
197
+ ...g,
198
+ status: "CONFIRMED"
199
+ }),
200
+ className: t(L, "w-full justify-center"),
201
+ children: [/* @__PURE__ */ N(w, { className: "h-4 w-4" }), n("coolandlovely.fulfilment.confirm", "Confirm order")]
202
+ }),
203
+ (a.status === "UNFULFILLED" || a.status === "CONFIRMED") && /* @__PURE__ */ P("button", {
204
+ type: "button",
205
+ disabled: r.isPending || !_,
206
+ onClick: () => r.mutate({
207
+ ...g,
208
+ status: "SHIPPED"
209
+ }),
210
+ className: R,
211
+ children: [r.isPending ? /* @__PURE__ */ N(E, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ N(k, { className: "h-4 w-4" }), n("coolandlovely.fulfilment.markShipped", "Mark shipped")]
212
+ }),
213
+ a.status === "SHIPPED" && /* @__PURE__ */ P(M, { children: [/* @__PURE__ */ N("button", {
214
+ type: "button",
215
+ disabled: r.isPending || !_,
216
+ onClick: () => r.mutate({
217
+ ...g,
218
+ status: "SHIPPED"
219
+ }),
220
+ className: t(L, "w-full justify-center"),
221
+ children: n("coolandlovely.fulfilment.saveTracking", "Save tracking details")
222
+ }), /* @__PURE__ */ P("button", {
223
+ type: "button",
224
+ disabled: r.isPending,
225
+ onClick: () => r.mutate({
226
+ ...g,
227
+ status: "DELIVERED"
228
+ }),
229
+ className: R,
230
+ children: [r.isPending ? /* @__PURE__ */ N(E, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ N(O, { className: "h-4 w-4" }), n("coolandlovely.fulfilment.markDelivered", "Mark delivered")]
231
+ })] }),
232
+ !_ && a.status !== "SHIPPED" && /* @__PURE__ */ N("p", {
233
+ className: "text-xs text-text-secondary",
234
+ children: n("coolandlovely.fulfilment.trackingHint", "Add a carrier and tracking number to mark the order shipped.")
235
+ })
236
+ ]
237
+ })
238
+ ]
239
+ });
240
+ }
241
+ function V() {
242
+ let t = i(), { brandId: r, orderId: d } = A(), { navigateTo: f } = e(), p = g(r, d), m = t("coolandlovely.brandOrders.detailTitle", "Order"), _ = () => f(`/brand-orders?brand=${r ?? ""}`);
243
+ if (p.isLoading) return /* @__PURE__ */ N(n, {
244
+ title: m,
245
+ children: /* @__PURE__ */ N(s, {})
246
+ });
247
+ if (p.isError || !p.data) return /* @__PURE__ */ N(n, {
248
+ title: m,
249
+ children: /* @__PURE__ */ N(o, {
250
+ title: t("coolandlovely.orders.notFound", "Order not found"),
251
+ message: p.error?.message,
252
+ onRetry: () => void p.refetch()
253
+ })
254
+ });
255
+ let v = p.data;
256
+ return /* @__PURE__ */ N(n, {
257
+ title: v.orderNumber,
258
+ description: t("coolandlovely.brandOrders.paidOn", "Paid {{date}}", { date: l(v.paidAt ?? v.createdAt) }),
259
+ actions: /* @__PURE__ */ P("button", {
260
+ type: "button",
261
+ onClick: _,
262
+ className: L,
263
+ children: [
264
+ /* @__PURE__ */ N(C, { className: "h-4 w-4" }),
265
+ " ",
266
+ t("coolandlovely.common.back", "Back")
267
+ ]
268
+ }),
269
+ children: /* @__PURE__ */ P("div", {
270
+ className: "grid grid-cols-1 gap-6 lg:grid-cols-3",
271
+ children: [/* @__PURE__ */ P("div", {
272
+ className: "space-y-3 lg:col-span-2",
273
+ children: [v.items.map((e) => /* @__PURE__ */ P(F, {
274
+ treatment: "plain",
275
+ className: "flex items-center gap-4 p-4",
276
+ children: [
277
+ /* @__PURE__ */ N(c, {
278
+ icon: /* @__PURE__ */ N(D, { className: "h-5 w-5" }),
279
+ seed: e.styleItemId,
280
+ fileId: e.image?.id,
281
+ alt: e.name,
282
+ className: "h-14 w-14 shrink-0"
283
+ }),
284
+ /* @__PURE__ */ P("div", {
285
+ className: "min-w-0 flex-1",
286
+ children: [/* @__PURE__ */ N("p", {
287
+ className: "truncate text-sm font-medium text-text-primary",
288
+ children: e.name
289
+ }), /* @__PURE__ */ N("p", {
290
+ className: "truncate text-xs text-text-secondary",
291
+ children: [
292
+ e.sku,
293
+ e.size,
294
+ e.colour,
295
+ `× ${e.quantity}`
296
+ ].filter(Boolean).join(" · ")
297
+ })]
298
+ }),
299
+ /* @__PURE__ */ N("span", {
300
+ className: "text-sm font-semibold tabular-nums text-text-primary",
301
+ children: u(e.lineTotal, v.currency)
302
+ })
303
+ ]
304
+ }, e.id)), /* @__PURE__ */ P(F, {
305
+ treatment: "plain",
306
+ className: "space-y-1 p-4 text-sm",
307
+ children: [
308
+ /* @__PURE__ */ N("p", {
309
+ className: "text-xs font-medium uppercase tracking-wide text-text-secondary",
310
+ children: t("coolandlovely.orders.shipTo", "Ship to")
311
+ }),
312
+ /* @__PURE__ */ N("p", {
313
+ className: "text-text-primary",
314
+ children: v.shippingName
315
+ }),
316
+ /* @__PURE__ */ N("p", {
317
+ className: "whitespace-pre-line text-text-secondary",
318
+ children: v.shippingAddress
319
+ }),
320
+ v.buyerNote && /* @__PURE__ */ N("p", {
321
+ className: "pt-2 text-text-secondary",
322
+ children: t("coolandlovely.brandOrders.buyerNote", "Buyer note: {{note}}", { note: v.buyerNote })
323
+ })
324
+ ]
325
+ })]
326
+ }), /* @__PURE__ */ P(F, {
327
+ treatment: "glass",
328
+ className: "h-fit space-y-4 p-6",
329
+ children: [
330
+ /* @__PURE__ */ P("div", {
331
+ className: "flex items-center justify-between",
332
+ children: [/* @__PURE__ */ N("span", {
333
+ className: "text-sm text-text-secondary",
334
+ children: t("coolandlovely.fulfilment.status", "Fulfilment")
335
+ }), /* @__PURE__ */ N("span", {
336
+ "data-testid": "fulfilment-status",
337
+ children: /* @__PURE__ */ N(a, { status: v.fulfilment.status })
338
+ })]
339
+ }),
340
+ /* @__PURE__ */ P("div", {
341
+ className: "flex justify-between text-sm",
342
+ children: [/* @__PURE__ */ N("span", {
343
+ className: "text-text-secondary",
344
+ children: t("coolandlovely.brandOrders.brandSubtotal", "Your pieces")
345
+ }), /* @__PURE__ */ N("span", {
346
+ className: "font-semibold tabular-nums text-text-primary",
347
+ children: u(v.brandSubtotal, v.currency)
348
+ })]
349
+ }),
350
+ /* @__PURE__ */ N(h, { fulfilment: v.fulfilment }),
351
+ /* @__PURE__ */ N(B, { order: v }, v.fulfilment.updatedAt ?? "new")
352
+ ]
353
+ })]
354
+ })
355
+ });
356
+ }
357
+ //#endregion
358
+ export { V as BrandOrderDetailPage, z as BrandOrdersPage };
359
+
360
+ //# 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.\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 { 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 status={order.fulfilment.status} />\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 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 status={data.fulfilment.status} />\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 <FulfilmentForm key={data.fulfilment.updatedAt ?? 'new'} 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 { PayForOrder as u } from "../../components/PayForOrder.js";
11
- import { useCheckout as d, useMyCart as f, useRemoveCartItem as p, useSyncOrderPayment as m, useUpdateCartItem as h } from "../../hooks/useCommerceApi.js";
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 = f(), j = h(), M = p(), N = d(), P = m(), [F, I] = g(""), [L, R] = g(""), [z, B] = g(""), [V, H] = g(null), U = O("coolandlovely.cart.title", "Your cart");
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(u, {
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":"OrdersPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/commerce/OrdersPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAgDH,wBAAgB,UAAU,gCAwEzB;AAED,wBAAgB,eAAe,gCAgL9B"}
1
+ {"version":3,"file":"OrdersPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/commerce/OrdersPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAiDH,wBAAgB,UAAU,gCAwEzB;AAED,wBAAgB,eAAe,gCA2M9B"}