@burdenoff/microfe-coolandlovely 2026.706.2 → 2026.706.3
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/CoolAndLovelyRoot.js +62 -46
- package/dist/coolandlovely/CoolAndLovelyRoot.js.map +1 -1
- package/dist/coolandlovely/components/AddToLookbookButton.js +22 -22
- package/dist/coolandlovely/components/AddToLookbookButton.js.map +1 -1
- package/dist/coolandlovely/components/BrandCover.js +39 -0
- package/dist/coolandlovely/components/BrandCover.js.map +1 -0
- package/dist/coolandlovely/components/BrandCreatorAvatars.js +57 -0
- package/dist/coolandlovely/components/BrandCreatorAvatars.js.map +1 -0
- package/dist/coolandlovely/components/ColourSwatchRow.js +86 -0
- package/dist/coolandlovely/components/ColourSwatchRow.js.map +1 -0
- package/dist/coolandlovely/components/Comments.js +4 -4
- package/dist/coolandlovely/components/Comments.js.map +1 -1
- package/dist/coolandlovely/components/FileImage.js.map +1 -1
- package/dist/coolandlovely/components/ImageUploadField.js +139 -57
- package/dist/coolandlovely/components/ImageUploadField.js.map +1 -1
- package/dist/coolandlovely/components/LookCard.js +77 -0
- package/dist/coolandlovely/components/LookCard.js.map +1 -0
- package/dist/coolandlovely/components/MetricsCard.js +1 -1
- package/dist/coolandlovely/components/MetricsCard.js.map +1 -1
- package/dist/coolandlovely/components/ShopItemCard.js +45 -0
- package/dist/coolandlovely/components/ShopItemCard.js.map +1 -0
- package/dist/coolandlovely/components/StepTracker.js +35 -0
- package/dist/coolandlovely/components/StepTracker.js.map +1 -0
- package/dist/coolandlovely/components/Thumbnail.js +15 -11
- package/dist/coolandlovely/components/Thumbnail.js.map +1 -1
- package/dist/coolandlovely/components/VisibilityChip.js +32 -0
- package/dist/coolandlovely/components/VisibilityChip.js.map +1 -0
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js +94 -69
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js.map +1 -1
- package/dist/coolandlovely/hooks/useFiles.js +49 -32
- package/dist/coolandlovely/hooks/useFiles.js.map +1 -1
- package/dist/coolandlovely/pages/HomePage.js +112 -133
- package/dist/coolandlovely/pages/HomePage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js +253 -242
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandFormPage.js +116 -112
- package/dist/coolandlovely/pages/brands/BrandFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandsListPage.js +13 -13
- package/dist/coolandlovely/pages/brands/BrandsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js +117 -95
- package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.js +1 -1
- package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.js +50 -43
- package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionDetailPage.js +131 -108
- package/dist/coolandlovely/pages/collections/CollectionDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionFormPage.js +1 -1
- package/dist/coolandlovely/pages/collections/CollectionsListPage.js +59 -56
- package/dist/coolandlovely/pages/collections/CollectionsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/discover/DiscoverPage.js +1 -1
- package/dist/coolandlovely/pages/discover/DiscoverPage.js.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.js +175 -147
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemFormPage.js +1 -1
- package/dist/coolandlovely/pages/items/StyleItemsListPage.js +71 -62
- package/dist/coolandlovely/pages/items/StyleItemsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js +149 -127
- package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js +69 -53
- package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LookDetailPage.js +135 -113
- package/dist/coolandlovely/pages/looks/LookDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LookFormPage.js +122 -110
- package/dist/coolandlovely/pages/looks/LookFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LooksListPage.js +60 -97
- package/dist/coolandlovely/pages/looks/LooksListPage.js.map +1 -1
- package/dist/coolandlovely/pages/profile/StyleProfilePage.js +372 -210
- package/dist/coolandlovely/pages/profile/StyleProfilePage.js.map +1 -1
- package/dist/coolandlovely/pages/trends/TrendsPage.js +1 -1
- package/dist/coolandlovely/pages/trends/TrendsPage.js.map +1 -1
- package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js +130 -94
- package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js +75 -76
- package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrandsListPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/brands/BrandsListPage.tsx"],"sourcesContent":["/**\n * Brands List Page\n * @module coolandlovely/pages/brands\n *\n * Lists brand storefronts (cursor-paginated `cooListBrands`) with status &\n * featured filters. Each card links to the brand detail page.\n */\n\nimport { useState } from 'react';\nimport { Store, Plus, Star, ChevronLeft, ChevronRight } from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { Thumbnail } from '../../components/Thumbnail';\nimport { TagList } from '../../components/TagList';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useBrands } from '../../hooks';\nimport { titleCase } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\nimport type { CooBrandStatus } from '../../types';\n\nconst PAGE_SIZE = 24;\n\nconst STATUS_OPTIONS: Array<{ value: CooBrandStatus | 'ALL'; label: string }> = [\n { value: 'ALL', label: 'All' },\n { value: 'PUBLISHED', label: 'Published' },\n { value: 'DRAFT', label: 'Draft' },\n { value: 'PENDING_REVIEW', label: 'In review' },\n { value: 'SUSPENDED', label: 'Suspended' },\n { value: 'ARCHIVED', label: 'Archived' },\n];\n\nexport function BrandsListPage() {\n const { navigateTo } = useCoolAndLovely();\n const [status, setStatus] = useState<CooBrandStatus | 'ALL'>('ALL');\n const [featuredOnly, setFeaturedOnly] = useState(false);\n const [offset, setOffset] = useState(0);\n\n const query = useBrands({\n status: status === 'ALL' ? undefined : status,\n featured: featuredOnly ? true : undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n\n const brands = query.data?.items ?? [];\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n return (\n <PageLayout\n title=\"Brands\"\n description=\"Storefronts on the platform with a real publish lifecycle\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/brands/new')}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n <Plus className=\"h-4 w-4\" /> New brand\n </button>\n }\n >\n {/* Filters */}\n <div className=\"mb-6 flex flex-wrap items-center gap-2\">\n {STATUS_OPTIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => {\n setStatus(opt.value);\n setOffset(0);\n }}\n className={cn(\n 'rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n status === opt.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {opt.label}\n </button>\n ))}\n <button\n type=\"button\"\n onClick={() => {\n setFeaturedOnly((v) => !v);\n setOffset(0);\n }}\n className={cn(\n 'ml-auto inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n featuredOnly\n ? 'bg-status-warning-bg-subtle text-status-warning-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n <Star className={cn('h-3.5 w-3.5', featuredOnly && 'fill-status-warning-text')} />{' '}\n Featured\n </button>\n </div>\n\n {query.isLoading ? (\n <LoadingView label=\"Loading brands…\" />\n ) : query.isError ? (\n <ErrorView onRetry={() => void query.refetch()} />\n ) : brands.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Store className=\"h-10 w-10\" />}\n title=\"No brands yet\"\n description=\"Launch the first storefront to start building the catalogue.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/brands/new')}\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\"\n >\n <Plus className=\"h-4 w-4\" /> New brand\n </button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {brands.map((brand) => (\n <button\n key={brand.id}\n type=\"button\"\n onClick={() => navigateTo(`/brands/${brand.id}`)}\n className=\"overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left shadow-sm transition-all hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <Thumbnail\n icon={<Store className=\"h-9 w-9\" />}\n seed={brand.id}\n fileId={brand.cover?.id ?? brand.logo?.id}\n alt={brand.name}\n className=\"h-32 w-full\"\n />\n <div className=\"p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-1.5\">\n <h3 className=\"truncate text-base font-semibold text-text-primary\">\n {brand.name}\n </h3>\n {brand.isFeatured && (\n <Star className=\"h-3.5 w-3.5 shrink-0 fill-status-warning-text text-status-warning-text\" />\n )}\n </div>\n <p className=\"truncate text-xs text-text-secondary\">@{brand.handle}</p>\n </div>\n <StatusBadge status={brand.status} />\n </div>\n {brand.tagline && (\n <p className=\"mt-2 line-clamp-2 text-sm text-text-secondary\">{brand.tagline}</p>\n )}\n {brand.aesthetics.length > 0 && (\n <TagList\n tags={brand.aesthetics.map(titleCase)}\n max={4}\n className=\"mt-3\"\n tone=\"accent\"\n />\n )}\n </div>\n </button>\n ))}\n </div>\n\n {/* Pagination */}\n {(offset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-center gap-2\">\n <button\n type=\"button\"\n disabled={offset === 0}\n onClick={() => setOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n <ChevronLeft className=\"h-4 w-4\" /> Previous\n </button>\n <span className=\"text-sm text-text-secondary\">Page {offset / PAGE_SIZE + 1}</span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n Next <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BrandsListPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/brands/BrandsListPage.tsx"],"sourcesContent":["/**\n * Brands List Page\n * @module coolandlovely/pages/brands\n *\n * Lists brand storefronts (cursor-paginated `cooListBrands`) with status &\n * featured filters. Each card links to the brand detail page.\n */\n\nimport { useState } from 'react';\nimport { Store, Plus, Star, ChevronLeft, ChevronRight } from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { BrandCover } from '../../components/BrandCover';\nimport { TagList } from '../../components/TagList';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useBrands } from '../../hooks';\nimport { titleCase } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\nimport type { CooBrandStatus } from '../../types';\n\nconst PAGE_SIZE = 24;\n\nconst STATUS_OPTIONS: Array<{ value: CooBrandStatus | 'ALL'; label: string }> = [\n { value: 'ALL', label: 'All' },\n { value: 'PUBLISHED', label: 'Published' },\n { value: 'DRAFT', label: 'Draft' },\n { value: 'PENDING_REVIEW', label: 'In review' },\n { value: 'SUSPENDED', label: 'Suspended' },\n { value: 'ARCHIVED', label: 'Archived' },\n];\n\nexport function BrandsListPage() {\n const { navigateTo } = useCoolAndLovely();\n const [status, setStatus] = useState<CooBrandStatus | 'ALL'>('ALL');\n const [featuredOnly, setFeaturedOnly] = useState(false);\n const [offset, setOffset] = useState(0);\n\n const query = useBrands({\n status: status === 'ALL' ? undefined : status,\n featured: featuredOnly ? true : undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n\n const brands = query.data?.items ?? [];\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n return (\n <PageLayout\n title=\"Brands\"\n description=\"Storefronts on the platform with a real publish lifecycle\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/brands/new')}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n <Plus className=\"h-4 w-4\" /> New brand\n </button>\n }\n >\n {/* Filters */}\n <div className=\"mb-6 flex flex-wrap items-center gap-2\">\n {STATUS_OPTIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => {\n setStatus(opt.value);\n setOffset(0);\n }}\n className={cn(\n 'rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n status === opt.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {opt.label}\n </button>\n ))}\n <button\n type=\"button\"\n onClick={() => {\n setFeaturedOnly((v) => !v);\n setOffset(0);\n }}\n className={cn(\n 'ml-auto inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n featuredOnly\n ? 'bg-status-warning-bg-subtle text-status-warning-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n <Star className={cn('h-3.5 w-3.5', featuredOnly && 'fill-status-warning-text')} />{' '}\n Featured\n </button>\n </div>\n\n {query.isLoading ? (\n <LoadingView label=\"Loading brands…\" />\n ) : query.isError ? (\n <ErrorView onRetry={() => void query.refetch()} />\n ) : brands.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Store className=\"h-10 w-10\" />}\n title=\"No brands yet\"\n description=\"Launch the first storefront to start building the catalogue.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/brands/new')}\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\"\n >\n <Plus className=\"h-4 w-4\" /> New brand\n </button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {brands.map((brand) => (\n <button\n key={brand.id}\n type=\"button\"\n onClick={() => navigateTo(`/brands/${brand.id}`)}\n className=\"group flex flex-col overflow-hidden rounded-xl border border-border-seam bg-bg-surface text-left shadow-sm transition-all hover:border-accent-foreground/20 hover:shadow-md\"\n >\n <BrandCover\n coverFileId={brand.cover?.id}\n logoFileId={brand.logo?.id}\n name={brand.name}\n seed={brand.id}\n showLogo\n />\n <div className=\"px-4 pb-4 pt-3\">\n <div className=\"flex min-h-[2.5rem] items-start justify-between gap-2 pl-20\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-1.5\">\n <h3 className=\"truncate text-base font-semibold text-text-primary\">\n {brand.name}\n </h3>\n {brand.isFeatured && (\n <Star className=\"h-3.5 w-3.5 shrink-0 fill-status-warning-text text-status-warning-text\" />\n )}\n </div>\n <p className=\"truncate text-xs text-text-secondary\">@{brand.handle}</p>\n </div>\n <StatusBadge status={brand.status} />\n </div>\n {brand.tagline && (\n <p className=\"mt-2 line-clamp-2 text-sm text-text-secondary\">{brand.tagline}</p>\n )}\n {brand.aesthetics.length > 0 && (\n <TagList\n tags={brand.aesthetics.map(titleCase)}\n max={4}\n className=\"mt-3\"\n tone=\"accent\"\n />\n )}\n </div>\n </button>\n ))}\n </div>\n\n {/* Pagination */}\n {(offset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-center gap-2\">\n <button\n type=\"button\"\n disabled={offset === 0}\n onClick={() => setOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n <ChevronLeft className=\"h-4 w-4\" /> Previous\n </button>\n <span className=\"text-sm text-text-secondary\">Page {offset / PAGE_SIZE + 1}</span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken disabled:cursor-not-allowed disabled:opacity-40\"\n >\n Next <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -4,15 +4,18 @@ import { StatusBadge as n } from "../../components/StatusBadge.js";
|
|
|
4
4
|
import { ErrorView as r, LoadingView as i } from "../../components/StateViews.js";
|
|
5
5
|
import { Thumbnail as a } from "../../components/Thumbnail.js";
|
|
6
6
|
import { useCollaboration as o, useTransitionCollaboration as s } from "../../hooks/useCoolAndLovelyApi.js";
|
|
7
|
-
import "../../hooks/index.js";
|
|
8
7
|
import { formatDate as c, formatPrice as l, titleCase as u } from "../../utils/formatters.js";
|
|
8
|
+
import "../../hooks/index.js";
|
|
9
9
|
import { TagList as d } from "../../components/TagList.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
10
|
+
import { ActorName as f } from "../../components/ActorName.js";
|
|
11
|
+
import { BrandCreatorAvatars as p } from "../../components/BrandCreatorAvatars.js";
|
|
12
|
+
import { StepTracker as m } from "../../components/StepTracker.js";
|
|
13
|
+
import { ArrowLeft as h, Loader2 as g, Sparkles as _, Store as v } from "lucide-react";
|
|
14
|
+
import { useParams as y } from "react-router-dom";
|
|
15
|
+
import { jsx as b, jsxs as x } from "react/jsx-runtime";
|
|
16
|
+
import { GlassCard as S } from "@burdenoff/fe-libs/ui";
|
|
14
17
|
//#region src/coolandlovely/pages/collaborations/CollaborationDetailPage.tsx
|
|
15
|
-
var
|
|
18
|
+
var C = {
|
|
16
19
|
PROPOSED: [
|
|
17
20
|
"ACCEPTED",
|
|
18
21
|
"DECLINED",
|
|
@@ -23,97 +26,111 @@ var x = {
|
|
|
23
26
|
PUBLISHED: [],
|
|
24
27
|
DECLINED: [],
|
|
25
28
|
CANCELLED: []
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
}, w = [
|
|
30
|
+
"PROPOSED",
|
|
31
|
+
"ACCEPTED",
|
|
32
|
+
"IN_PROGRESS",
|
|
33
|
+
"PUBLISHED"
|
|
34
|
+
];
|
|
35
|
+
function T() {
|
|
36
|
+
let { collaborationId: T } = y(), { navigateTo: E } = e(), D = o(T), O = s();
|
|
37
|
+
if (D.isLoading) return /* @__PURE__ */ b(t, {
|
|
30
38
|
title: "Collaboration",
|
|
31
|
-
children: /* @__PURE__ */
|
|
39
|
+
children: /* @__PURE__ */ b(i, { label: "Loading collaboration…" })
|
|
32
40
|
});
|
|
33
|
-
if (
|
|
41
|
+
if (D.isError || !D.data) return /* @__PURE__ */ b(t, {
|
|
34
42
|
title: "Collaboration",
|
|
35
|
-
children: /* @__PURE__ */
|
|
43
|
+
children: /* @__PURE__ */ b(r, {
|
|
36
44
|
title: "Collaboration not found",
|
|
37
|
-
onRetry: () => void
|
|
45
|
+
onRetry: () => void D.refetch()
|
|
38
46
|
})
|
|
39
47
|
});
|
|
40
|
-
let
|
|
41
|
-
return /* @__PURE__ */
|
|
42
|
-
title:
|
|
43
|
-
description:
|
|
44
|
-
actions: /* @__PURE__ */
|
|
48
|
+
let k = D.data, A = k.looks ?? [], j = C[k.status], M = w.includes(k.status) ? w : ["PROPOSED", k.status];
|
|
49
|
+
return /* @__PURE__ */ b(t, {
|
|
50
|
+
title: k.title,
|
|
51
|
+
description: k.brand?.name ?? void 0,
|
|
52
|
+
actions: /* @__PURE__ */ x("button", {
|
|
45
53
|
type: "button",
|
|
46
|
-
onClick: () =>
|
|
54
|
+
onClick: () => E("/collaborations"),
|
|
47
55
|
className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken",
|
|
48
|
-
children: [/* @__PURE__ */
|
|
56
|
+
children: [/* @__PURE__ */ b(h, { className: "h-4 w-4" }), " Back"]
|
|
49
57
|
}),
|
|
50
|
-
children: /* @__PURE__ */
|
|
58
|
+
children: /* @__PURE__ */ x("div", {
|
|
51
59
|
className: "grid grid-cols-1 gap-6 lg:grid-cols-3",
|
|
52
|
-
children: [/* @__PURE__ */
|
|
60
|
+
children: [/* @__PURE__ */ x("div", {
|
|
53
61
|
className: "lg:col-span-2",
|
|
54
|
-
children: [/* @__PURE__ */
|
|
62
|
+
children: [/* @__PURE__ */ x(S, {
|
|
55
63
|
treatment: "glass",
|
|
56
64
|
className: "p-6",
|
|
57
65
|
children: [
|
|
58
|
-
/* @__PURE__ */
|
|
66
|
+
/* @__PURE__ */ x("div", {
|
|
59
67
|
className: "flex items-center gap-3",
|
|
60
68
|
children: [
|
|
61
|
-
/* @__PURE__ */
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
69
|
+
/* @__PURE__ */ b(p, {
|
|
70
|
+
brandLogoFileId: k.brand?.logo?.id,
|
|
71
|
+
brandSeed: k.brandId,
|
|
72
|
+
creatorId: k.creatorId,
|
|
73
|
+
className: "shrink-0"
|
|
65
74
|
}),
|
|
66
|
-
/* @__PURE__ */
|
|
75
|
+
/* @__PURE__ */ x("div", {
|
|
67
76
|
className: "min-w-0 flex-1",
|
|
68
|
-
children: [/* @__PURE__ */
|
|
77
|
+
children: [/* @__PURE__ */ b("h2", {
|
|
69
78
|
className: "truncate text-xl font-semibold text-text-primary",
|
|
70
|
-
children:
|
|
71
|
-
}), /* @__PURE__ */
|
|
79
|
+
children: k.title
|
|
80
|
+
}), /* @__PURE__ */ x("p", {
|
|
72
81
|
className: "text-xs text-text-secondary",
|
|
73
|
-
children: [
|
|
82
|
+
children: [
|
|
83
|
+
k.brand?.name ?? "Brand",
|
|
84
|
+
" × ",
|
|
85
|
+
/* @__PURE__ */ b(f, { id: k.creatorId }),
|
|
86
|
+
" ·",
|
|
87
|
+
" ",
|
|
88
|
+
u(k.role),
|
|
89
|
+
" collaboration"
|
|
90
|
+
]
|
|
74
91
|
})]
|
|
75
92
|
}),
|
|
76
|
-
/* @__PURE__ */
|
|
93
|
+
/* @__PURE__ */ b(n, { status: k.status })
|
|
77
94
|
]
|
|
78
95
|
}),
|
|
79
|
-
|
|
96
|
+
k.brief && /* @__PURE__ */ b("p", {
|
|
80
97
|
className: "mt-4 text-sm text-text-secondary",
|
|
81
|
-
children:
|
|
98
|
+
children: k.brief
|
|
82
99
|
}),
|
|
83
|
-
|
|
84
|
-
tags:
|
|
100
|
+
k.tags.length > 0 && /* @__PURE__ */ b(d, {
|
|
101
|
+
tags: k.tags,
|
|
85
102
|
className: "mt-4",
|
|
86
103
|
tone: "accent"
|
|
87
104
|
})
|
|
88
105
|
]
|
|
89
|
-
}), /* @__PURE__ */
|
|
106
|
+
}), /* @__PURE__ */ x("section", {
|
|
90
107
|
className: "mt-6",
|
|
91
|
-
children: [/* @__PURE__ */
|
|
108
|
+
children: [/* @__PURE__ */ x("h3", {
|
|
92
109
|
className: "mb-3 text-lg font-semibold text-text-primary",
|
|
93
110
|
children: [
|
|
94
111
|
"Attributed looks (",
|
|
95
|
-
|
|
112
|
+
A.length,
|
|
96
113
|
")"
|
|
97
114
|
]
|
|
98
|
-
}),
|
|
115
|
+
}), A.length === 0 ? /* @__PURE__ */ b("p", {
|
|
99
116
|
className: "rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary",
|
|
100
117
|
children: "No looks attributed to this collaboration yet."
|
|
101
|
-
}) : /* @__PURE__ */
|
|
118
|
+
}) : /* @__PURE__ */ b("div", {
|
|
102
119
|
className: "grid grid-cols-2 gap-3 sm:grid-cols-3",
|
|
103
|
-
children:
|
|
120
|
+
children: A.map((e) => /* @__PURE__ */ x("button", {
|
|
104
121
|
type: "button",
|
|
105
|
-
onClick: () =>
|
|
122
|
+
onClick: () => E(`/looks/${e.id}`),
|
|
106
123
|
className: "overflow-hidden rounded-lg border border-border-seam bg-bg-surface text-left transition-all hover:border-accent-foreground/20 hover:shadow-md",
|
|
107
|
-
children: [/* @__PURE__ */
|
|
108
|
-
icon: /* @__PURE__ */
|
|
124
|
+
children: [/* @__PURE__ */ b(a, {
|
|
125
|
+
icon: /* @__PURE__ */ b(_, { className: "h-6 w-6" }),
|
|
109
126
|
seed: e.id,
|
|
110
127
|
className: "h-24 w-full"
|
|
111
|
-
}), /* @__PURE__ */
|
|
128
|
+
}), /* @__PURE__ */ x("div", {
|
|
112
129
|
className: "p-3",
|
|
113
|
-
children: [/* @__PURE__ */
|
|
130
|
+
children: [/* @__PURE__ */ b("p", {
|
|
114
131
|
className: "truncate text-sm font-medium text-text-primary",
|
|
115
132
|
children: e.title
|
|
116
|
-
}), /* @__PURE__ */
|
|
133
|
+
}), /* @__PURE__ */ b("p", {
|
|
117
134
|
className: "mt-0.5 text-xs text-text-secondary",
|
|
118
135
|
children: u(e.occasion)
|
|
119
136
|
})]
|
|
@@ -121,100 +138,105 @@ function S() {
|
|
|
121
138
|
}, e.id))
|
|
122
139
|
})]
|
|
123
140
|
})]
|
|
124
|
-
}), /* @__PURE__ */
|
|
141
|
+
}), /* @__PURE__ */ x("div", {
|
|
125
142
|
className: "space-y-4",
|
|
126
143
|
children: [
|
|
127
|
-
/* @__PURE__ */
|
|
144
|
+
/* @__PURE__ */ x(S, {
|
|
128
145
|
treatment: "insight",
|
|
129
146
|
className: "p-5",
|
|
130
147
|
children: [
|
|
131
|
-
/* @__PURE__ */
|
|
148
|
+
/* @__PURE__ */ b("h3", {
|
|
132
149
|
className: "mb-3 text-sm font-semibold text-text-primary",
|
|
133
150
|
children: "Lifecycle"
|
|
134
151
|
}),
|
|
135
|
-
/* @__PURE__ */
|
|
152
|
+
/* @__PURE__ */ b(m, {
|
|
153
|
+
steps: M,
|
|
154
|
+
current: k.status,
|
|
155
|
+
className: "mb-5"
|
|
156
|
+
}),
|
|
157
|
+
/* @__PURE__ */ x("div", {
|
|
136
158
|
className: "mb-3 flex items-center gap-2",
|
|
137
|
-
children: [/* @__PURE__ */
|
|
159
|
+
children: [/* @__PURE__ */ b("span", {
|
|
138
160
|
className: "text-sm text-text-secondary",
|
|
139
161
|
children: "Current:"
|
|
140
|
-
}), /* @__PURE__ */
|
|
162
|
+
}), /* @__PURE__ */ b(n, { status: k.status })]
|
|
141
163
|
}),
|
|
142
|
-
|
|
164
|
+
j.length === 0 ? /* @__PURE__ */ b("p", {
|
|
143
165
|
className: "text-xs text-text-secondary",
|
|
144
166
|
children: "This collaboration is in a terminal state."
|
|
145
|
-
}) : /* @__PURE__ */
|
|
167
|
+
}) : /* @__PURE__ */ b("div", {
|
|
146
168
|
className: "flex flex-col gap-2",
|
|
147
|
-
children:
|
|
169
|
+
children: j.map((e) => /* @__PURE__ */ x("button", {
|
|
148
170
|
type: "button",
|
|
149
|
-
disabled:
|
|
150
|
-
onClick: () =>
|
|
151
|
-
id:
|
|
171
|
+
disabled: O.isPending,
|
|
172
|
+
onClick: () => O.mutate({
|
|
173
|
+
id: k.id,
|
|
152
174
|
status: e
|
|
153
175
|
}),
|
|
154
176
|
className: "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",
|
|
155
177
|
children: [
|
|
156
|
-
|
|
178
|
+
O.isPending && /* @__PURE__ */ b(g, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
157
179
|
"Move to ",
|
|
158
180
|
u(e)
|
|
159
181
|
]
|
|
160
182
|
}, e))
|
|
161
183
|
}),
|
|
162
|
-
|
|
184
|
+
O.isError && /* @__PURE__ */ b("p", {
|
|
163
185
|
className: "mt-2 text-xs text-status-error-text",
|
|
164
|
-
children:
|
|
186
|
+
children: O.error instanceof Error ? O.error.message : "Transition failed"
|
|
165
187
|
})
|
|
166
188
|
]
|
|
167
189
|
}),
|
|
168
|
-
/* @__PURE__ */
|
|
190
|
+
/* @__PURE__ */ x(S, {
|
|
169
191
|
treatment: "plain",
|
|
170
192
|
className: "p-5",
|
|
171
|
-
children: [/* @__PURE__ */
|
|
193
|
+
children: [/* @__PURE__ */ b("h3", {
|
|
172
194
|
className: "mb-3 text-sm font-semibold text-text-primary",
|
|
173
195
|
children: "Terms"
|
|
174
|
-
}), /* @__PURE__ */
|
|
196
|
+
}), /* @__PURE__ */ x("dl", {
|
|
175
197
|
className: "space-y-2 text-sm",
|
|
176
198
|
children: [
|
|
177
|
-
/* @__PURE__ */
|
|
199
|
+
/* @__PURE__ */ x("div", {
|
|
178
200
|
className: "flex justify-between gap-2",
|
|
179
|
-
children: [/* @__PURE__ */
|
|
201
|
+
children: [/* @__PURE__ */ b("dt", {
|
|
180
202
|
className: "text-text-secondary",
|
|
181
203
|
children: "Role"
|
|
182
|
-
}), /* @__PURE__ */
|
|
204
|
+
}), /* @__PURE__ */ b("dd", {
|
|
183
205
|
className: "text-text-primary",
|
|
184
|
-
children: u(
|
|
206
|
+
children: u(k.role)
|
|
185
207
|
})]
|
|
186
208
|
}),
|
|
187
|
-
/* @__PURE__ */
|
|
209
|
+
/* @__PURE__ */ x("div", {
|
|
188
210
|
className: "flex justify-between gap-2",
|
|
189
|
-
children: [/* @__PURE__ */
|
|
211
|
+
children: [/* @__PURE__ */ b("dt", {
|
|
190
212
|
className: "text-text-secondary",
|
|
191
213
|
children: "Compensation"
|
|
192
|
-
}), /* @__PURE__ */
|
|
214
|
+
}), /* @__PURE__ */ b("dd", {
|
|
193
215
|
className: "text-text-primary",
|
|
194
|
-
children: l(
|
|
216
|
+
children: l(k.compensation, k.currency)
|
|
195
217
|
})]
|
|
196
218
|
}),
|
|
197
|
-
/* @__PURE__ */
|
|
219
|
+
/* @__PURE__ */ x("div", {
|
|
198
220
|
className: "flex justify-between gap-2",
|
|
199
|
-
children: [/* @__PURE__ */
|
|
221
|
+
children: [/* @__PURE__ */ b("dt", {
|
|
200
222
|
className: "text-text-secondary",
|
|
201
223
|
children: "Starts"
|
|
202
|
-
}), /* @__PURE__ */
|
|
224
|
+
}), /* @__PURE__ */ b("dd", {
|
|
203
225
|
className: "text-text-primary",
|
|
204
|
-
children:
|
|
226
|
+
children: k.startDate ? c(k.startDate, {
|
|
205
227
|
hour: void 0,
|
|
206
228
|
minute: void 0
|
|
207
229
|
}) : "—"
|
|
208
230
|
})]
|
|
209
231
|
}),
|
|
210
|
-
/* @__PURE__ */
|
|
232
|
+
/* @__PURE__ */ x("div", {
|
|
211
233
|
className: "flex justify-between gap-2",
|
|
212
|
-
children: [/* @__PURE__ */
|
|
234
|
+
children: [/* @__PURE__ */ b("dt", {
|
|
213
235
|
className: "text-text-secondary",
|
|
214
236
|
children: "Ends"
|
|
215
|
-
}), /* @__PURE__ */
|
|
237
|
+
}), /* @__PURE__ */ b("dd", {
|
|
216
238
|
className: "text-text-primary",
|
|
217
|
-
children:
|
|
239
|
+
children: k.endDate ? c(k.endDate, {
|
|
218
240
|
hour: void 0,
|
|
219
241
|
minute: void 0
|
|
220
242
|
}) : "—"
|
|
@@ -223,20 +245,20 @@ function S() {
|
|
|
223
245
|
]
|
|
224
246
|
})]
|
|
225
247
|
}),
|
|
226
|
-
|
|
248
|
+
k.brand && /* @__PURE__ */ x("button", {
|
|
227
249
|
type: "button",
|
|
228
|
-
onClick: () =>
|
|
250
|
+
onClick: () => E(`/brands/${k.brand?.id}`),
|
|
229
251
|
className: "flex w-full items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken/50",
|
|
230
|
-
children: [/* @__PURE__ */
|
|
231
|
-
icon: /* @__PURE__ */ v
|
|
232
|
-
seed:
|
|
252
|
+
children: [/* @__PURE__ */ b(a, {
|
|
253
|
+
icon: /* @__PURE__ */ b(v, { className: "h-5 w-5" }),
|
|
254
|
+
seed: k.brand.id,
|
|
233
255
|
className: "h-10 w-10 shrink-0"
|
|
234
|
-
}), /* @__PURE__ */
|
|
256
|
+
}), /* @__PURE__ */ x("div", {
|
|
235
257
|
className: "min-w-0",
|
|
236
|
-
children: [/* @__PURE__ */
|
|
258
|
+
children: [/* @__PURE__ */ b("p", {
|
|
237
259
|
className: "truncate text-sm font-medium text-text-primary",
|
|
238
|
-
children:
|
|
239
|
-
}), /* @__PURE__ */
|
|
260
|
+
children: k.brand.name
|
|
261
|
+
}), /* @__PURE__ */ b("p", {
|
|
240
262
|
className: "truncate text-xs text-text-secondary",
|
|
241
263
|
children: "View brand"
|
|
242
264
|
})]
|
|
@@ -248,6 +270,6 @@ function S() {
|
|
|
248
270
|
});
|
|
249
271
|
}
|
|
250
272
|
//#endregion
|
|
251
|
-
export {
|
|
273
|
+
export { T as CollaborationDetailPage };
|
|
252
274
|
|
|
253
275
|
//# sourceMappingURL=CollaborationDetailPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollaborationDetailPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/collaborations/CollaborationDetailPage.tsx"],"sourcesContent":["/**\n * Collaboration Detail Page\n * @module coolandlovely/pages/collaborations\n *\n * Single collaboration (`cooCollaboration`) with validated lifecycle\n * transitions (`cooTransitionCollaboration`), its brand and attributed looks.\n */\n\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Loader2, Handshake, Store, Sparkles } 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 { TagList } from '../../components/TagList';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useCollaboration, useTransitionCollaboration } from '../../hooks';\nimport { formatPrice, formatDate, titleCase } from '../../utils/formatters';\nimport type { CooCollaborationStatus } from '../../types';\n\n/** Allowed next states per the svc collaboration state machine (UX guidance;\n * the service is authoritative and rejects illegal jumps). */\nconst NEXT_STATES: Record<CooCollaborationStatus, CooCollaborationStatus[]> = {\n PROPOSED: ['ACCEPTED', 'DECLINED', 'CANCELLED'],\n ACCEPTED: ['IN_PROGRESS', 'CANCELLED'],\n IN_PROGRESS: ['PUBLISHED', 'CANCELLED'],\n PUBLISHED: [],\n DECLINED: [],\n CANCELLED: [],\n};\n\nexport function CollaborationDetailPage() {\n const { collaborationId } = useParams<{ collaborationId: string }>();\n const { navigateTo } = useCoolAndLovely();\n const query = useCollaboration(collaborationId);\n const transition = useTransitionCollaboration();\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Collaboration\">\n <LoadingView label=\"Loading collaboration…\" />\n </PageLayout>\n );\n }\n\n if (query.isError || !query.data) {\n return (\n <PageLayout title=\"Collaboration\">\n <ErrorView title=\"Collaboration not found\" onRetry={() => void query.refetch()} />\n </PageLayout>\n );\n }\n\n const collab = query.data;\n const looks = collab.looks ?? [];\n const nextStates = NEXT_STATES[collab.status];\n\n return (\n <PageLayout\n title={collab.title}\n description={collab.brand?.name ?? undefined}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/collaborations')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n }\n >\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2\">\n <GlassCard treatment=\"glass\" className=\"p-6\">\n <div className=\"flex items-center gap-3\">\n <Thumbnail\n icon={<Handshake className=\"h-6 w-6\" />}\n seed={collab.id}\n className=\"h-12 w-12 shrink-0\"\n />\n <div className=\"min-w-0 flex-1\">\n <h2 className=\"truncate text-xl font-semibold text-text-primary\">{collab.title}</h2>\n <p className=\"text-xs text-text-secondary\">\n {titleCase(collab.role)} collaboration\n </p>\n </div>\n <StatusBadge status={collab.status} />\n </div>\n {collab.brief && <p className=\"mt-4 text-sm text-text-secondary\">{collab.brief}</p>}\n {collab.tags.length > 0 && (\n <TagList tags={collab.tags} className=\"mt-4\" tone=\"accent\" />\n )}\n </GlassCard>\n\n {/* Attributed looks */}\n <section className=\"mt-6\">\n <h3 className=\"mb-3 text-lg font-semibold text-text-primary\">\n Attributed looks ({looks.length})\n </h3>\n {looks.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n No looks attributed to this collaboration yet.\n </p>\n ) : (\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-3\">\n {looks.map((look) => (\n <button\n key={look.id}\n type=\"button\"\n onClick={() => navigateTo(`/looks/${look.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={<Sparkles className=\"h-6 w-6\" />}\n seed={look.id}\n className=\"h-24 w-full\"\n />\n <div className=\"p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{look.title}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {titleCase(look.occasion)}\n </p>\n </div>\n </button>\n ))}\n </div>\n )}\n </section>\n </div>\n\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\">Lifecycle</h3>\n <div className=\"mb-3 flex items-center gap-2\">\n <span className=\"text-sm text-text-secondary\">Current:</span>\n <StatusBadge status={collab.status} />\n </div>\n {nextStates.length === 0 ? (\n <p className=\"text-xs text-text-secondary\">\n This collaboration is in a 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: collab.id, status: next })}\n className=\"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 {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 {transition.error instanceof Error ? transition.error.message : 'Transition failed'}\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\">Terms</h3>\n <dl className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Role</dt>\n <dd className=\"text-text-primary\">{titleCase(collab.role)}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Compensation</dt>\n <dd className=\"text-text-primary\">\n {formatPrice(collab.compensation, collab.currency)}\n </dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Starts</dt>\n <dd className=\"text-text-primary\">\n {collab.startDate\n ? formatDate(collab.startDate, { hour: undefined, minute: undefined })\n : '—'}\n </dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Ends</dt>\n <dd className=\"text-text-primary\">\n {collab.endDate\n ? formatDate(collab.endDate, { hour: undefined, minute: undefined })\n : '—'}\n </dd>\n </div>\n </dl>\n </GlassCard>\n\n {collab.brand && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/brands/${collab.brand?.id}`)}\n className=\"flex w-full items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <Thumbnail\n icon={<Store className=\"h-5 w-5\" />}\n seed={collab.brand.id}\n className=\"h-10 w-10 shrink-0\"\n />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {collab.brand.name}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">View brand</p>\n </div>\n </button>\n )}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CollaborationDetailPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/collaborations/CollaborationDetailPage.tsx"],"sourcesContent":["/**\n * Collaboration Detail Page\n * @module coolandlovely/pages/collaborations\n *\n * Single collaboration (`cooCollaboration`) with validated lifecycle\n * transitions (`cooTransitionCollaboration`), its brand and attributed looks.\n */\n\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Loader2, Store, Sparkles } 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 { BrandCreatorAvatars } from '../../components/BrandCreatorAvatars';\nimport { ActorName } from '../../components/ActorName';\nimport { StepTracker } from '../../components/StepTracker';\nimport { TagList } from '../../components/TagList';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useCollaboration, useTransitionCollaboration } from '../../hooks';\nimport { formatPrice, formatDate, titleCase } from '../../utils/formatters';\nimport type { CooCollaborationStatus } from '../../types';\n\n/** Allowed next states per the svc collaboration state machine (UX guidance;\n * the service is authoritative and rejects illegal jumps). */\nconst NEXT_STATES: Record<CooCollaborationStatus, CooCollaborationStatus[]> = {\n PROPOSED: ['ACCEPTED', 'DECLINED', 'CANCELLED'],\n ACCEPTED: ['IN_PROGRESS', 'CANCELLED'],\n IN_PROGRESS: ['PUBLISHED', 'CANCELLED'],\n PUBLISHED: [],\n DECLINED: [],\n CANCELLED: [],\n};\n\nconst LIFECYCLE_STEPS: CooCollaborationStatus[] = [\n 'PROPOSED',\n 'ACCEPTED',\n 'IN_PROGRESS',\n 'PUBLISHED',\n];\n\nexport function CollaborationDetailPage() {\n const { collaborationId } = useParams<{ collaborationId: string }>();\n const { navigateTo } = useCoolAndLovely();\n const query = useCollaboration(collaborationId);\n const transition = useTransitionCollaboration();\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Collaboration\">\n <LoadingView label=\"Loading collaboration…\" />\n </PageLayout>\n );\n }\n\n if (query.isError || !query.data) {\n return (\n <PageLayout title=\"Collaboration\">\n <ErrorView title=\"Collaboration not found\" onRetry={() => void query.refetch()} />\n </PageLayout>\n );\n }\n\n const collab = query.data;\n const looks = collab.looks ?? [];\n const nextStates = NEXT_STATES[collab.status];\n const trackerSteps = LIFECYCLE_STEPS.includes(collab.status)\n ? LIFECYCLE_STEPS\n : (['PROPOSED', collab.status] as CooCollaborationStatus[]);\n\n return (\n <PageLayout\n title={collab.title}\n description={collab.brand?.name ?? undefined}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/collaborations')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n }\n >\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2\">\n <GlassCard treatment=\"glass\" className=\"p-6\">\n <div className=\"flex items-center gap-3\">\n <BrandCreatorAvatars\n brandLogoFileId={collab.brand?.logo?.id}\n brandSeed={collab.brandId}\n creatorId={collab.creatorId}\n className=\"shrink-0\"\n />\n <div className=\"min-w-0 flex-1\">\n <h2 className=\"truncate text-xl font-semibold text-text-primary\">{collab.title}</h2>\n <p className=\"text-xs text-text-secondary\">\n {collab.brand?.name ?? 'Brand'} × <ActorName id={collab.creatorId} /> ·{' '}\n {titleCase(collab.role)} collaboration\n </p>\n </div>\n <StatusBadge status={collab.status} />\n </div>\n {collab.brief && <p className=\"mt-4 text-sm text-text-secondary\">{collab.brief}</p>}\n {collab.tags.length > 0 && (\n <TagList tags={collab.tags} className=\"mt-4\" tone=\"accent\" />\n )}\n </GlassCard>\n\n {/* Attributed looks */}\n <section className=\"mt-6\">\n <h3 className=\"mb-3 text-lg font-semibold text-text-primary\">\n Attributed looks ({looks.length})\n </h3>\n {looks.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n No looks attributed to this collaboration yet.\n </p>\n ) : (\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-3\">\n {looks.map((look) => (\n <button\n key={look.id}\n type=\"button\"\n onClick={() => navigateTo(`/looks/${look.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={<Sparkles className=\"h-6 w-6\" />}\n seed={look.id}\n className=\"h-24 w-full\"\n />\n <div className=\"p-3\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{look.title}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {titleCase(look.occasion)}\n </p>\n </div>\n </button>\n ))}\n </div>\n )}\n </section>\n </div>\n\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\">Lifecycle</h3>\n <StepTracker steps={trackerSteps} current={collab.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={collab.status} />\n </div>\n {nextStates.length === 0 ? (\n <p className=\"text-xs text-text-secondary\">\n This collaboration is in a 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: collab.id, status: next })}\n className=\"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 {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 {transition.error instanceof Error ? transition.error.message : 'Transition failed'}\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\">Terms</h3>\n <dl className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Role</dt>\n <dd className=\"text-text-primary\">{titleCase(collab.role)}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Compensation</dt>\n <dd className=\"text-text-primary\">\n {formatPrice(collab.compensation, collab.currency)}\n </dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Starts</dt>\n <dd className=\"text-text-primary\">\n {collab.startDate\n ? formatDate(collab.startDate, { hour: undefined, minute: undefined })\n : '—'}\n </dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Ends</dt>\n <dd className=\"text-text-primary\">\n {collab.endDate\n ? formatDate(collab.endDate, { hour: undefined, minute: undefined })\n : '—'}\n </dd>\n </div>\n </dl>\n </GlassCard>\n\n {collab.brand && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/brands/${collab.brand?.id}`)}\n className=\"flex w-full items-center gap-3 rounded-lg border border-border-seam bg-bg-surface p-4 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <Thumbnail\n icon={<Store className=\"h-5 w-5\" />}\n seed={collab.brand.id}\n className=\"h-10 w-10 shrink-0\"\n />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {collab.brand.name}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">View brand</p>\n </div>\n </button>\n )}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA0BA,IAAM,IAAwE;CAC5E,UAAU;EAAC;EAAY;EAAY;EAAY;CAC/C,UAAU,CAAC,eAAe,YAAY;CACtC,aAAa,CAAC,aAAa,YAAY;CACvC,WAAW,EAAE;CACb,UAAU,EAAE;CACZ,WAAW,EAAE;CACd,EAEK,IAA4C;CAChD;CACA;CACA;CACA;CACD;AAED,SAAgB,IAA0B;CACxC,IAAM,EAAE,uBAAoB,GAAwC,EAC9D,EAAE,kBAAe,GAAkB,EACnC,IAAQ,EAAiB,EAAgB,EACzC,IAAa,GAA4B;AAE/C,KAAI,EAAM,UACR,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD,EAAa,OAAM,0BAA2B,CAAA;EACnC,CAAA;AAIjB,KAAI,EAAM,WAAW,CAAC,EAAM,KAC1B,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD;GAAW,OAAM;GAA0B,eAAe,KAAK,EAAM,SAAS;GAAI,CAAA;EACvE,CAAA;CAIjB,IAAM,IAAS,EAAM,MACf,IAAQ,EAAO,SAAS,EAAE,EAC1B,IAAa,EAAY,EAAO,SAChC,IAAe,EAAgB,SAAS,EAAO,OAAO,GACxD,IACC,CAAC,YAAY,EAAO,OAAO;AAEhC,QACE,kBAAC,GAAD;EACE,OAAO,EAAO;EACd,aAAa,EAAO,OAAO,QAAQ,KAAA;EACnC,SACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAW,kBAAkB;GAC5C,WAAU;aAHZ,CAKE,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA,EAAA,QAC1B;;YAGX,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAW,WAAU;KAAQ,WAAU;eAAvC;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,GAAD;SACE,iBAAiB,EAAO,OAAO,MAAM;SACrC,WAAW,EAAO;SAClB,WAAW,EAAO;SAClB,WAAU;SACV,CAAA;QACF,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBAAoD,EAAO;UAAW,CAAA,EACpF,kBAAC,KAAD;UAAG,WAAU;oBAAb;WACG,EAAO,OAAO,QAAQ;WAAQ;WAAG,kBAAC,GAAD,EAAW,IAAI,EAAO,WAAa,CAAA;;WAAG;WACvE,EAAU,EAAO,KAAK;WAAC;WACtB;YACA;;QACN,kBAAC,GAAD,EAAa,QAAQ,EAAO,QAAU,CAAA;QAClC;;MACL,EAAO,SAAS,kBAAC,KAAD;OAAG,WAAU;iBAAoC,EAAO;OAAU,CAAA;MAClF,EAAO,KAAK,SAAS,KACpB,kBAAC,GAAD;OAAS,MAAM,EAAO;OAAM,WAAU;OAAO,MAAK;OAAW,CAAA;MAErD;QAGZ,kBAAC,WAAD;KAAS,WAAU;eAAnB,CACE,kBAAC,MAAD;MAAI,WAAU;gBAAd;OAA6D;OACxC,EAAM;OAAO;OAC7B;SACJ,EAAM,WAAW,IAChB,kBAAC,KAAD;MAAG,WAAU;gBAAqF;MAE9F,CAAA,GAEJ,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAM,KAAK,MACV,kBAAC,UAAD;OAEE,MAAK;OACL,eAAe,EAAW,UAAU,EAAK,KAAK;OAC9C,WAAU;iBAJZ,CAME,kBAAC,GAAD;QACE,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;QACtC,MAAM,EAAK;QACX,WAAU;QACV,CAAA,EACF,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,KAAD;SAAG,WAAU;mBAAkD,EAAK;SAAU,CAAA,EAC9E,kBAAC,KAAD;SAAG,WAAU;mBACV,EAAU,EAAK,SAAS;SACvB,CAAA,CACA;UACC;SAhBF,EAAK,GAgBH,CACT;MACE,CAAA,CAEA;OACN;OAEN,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAW,WAAU;MAAU,WAAU;gBAAzC;OACE,kBAAC,MAAD;QAAI,WAAU;kBAA+C;QAAc,CAAA;OAC3E,kBAAC,GAAD;QAAa,OAAO;QAAc,SAAS,EAAO;QAAQ,WAAU;QAAS,CAAA;OAC7E,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBAA8B;SAAe,CAAA,EAC7D,kBAAC,GAAD,EAAa,QAAQ,EAAO,QAAU,CAAA,CAClC;;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,EAAO;UAAI,QAAQ;UAAM,CAAC;SACjE,WAAU;mBALZ;UAOG,EAAW,aAAa,kBAAC,GAAD,EAAS,WAAU,4BAA6B,CAAA;UAAC;UACjE,EAAU,EAAK;UACjB;WARF,EAQE,CACT;QACE,CAAA;OAEP,EAAW,WACV,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAW,iBAAiB,QAAQ,EAAW,MAAM,UAAU;QAC9D,CAAA;OAEI;;KAEZ,kBAAC,GAAD;MAAW,WAAU;MAAQ,WAAU;gBAAvC,CACE,kBAAC,MAAD;OAAI,WAAU;iBAA+C;OAAU,CAAA,EACvE,kBAAC,MAAD;OAAI,WAAU;iBAAd;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBAAsB;UAAS,CAAA,EAC7C,kBAAC,MAAD;UAAI,WAAU;oBAAqB,EAAU,EAAO,KAAK;UAAM,CAAA,CAC3D;;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBAAsB;UAAiB,CAAA,EACrD,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAY,EAAO,cAAc,EAAO,SAAS;UAC/C,CAAA,CACD;;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBAAsB;UAAW,CAAA,EAC/C,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAO,YACJ,EAAW,EAAO,WAAW;WAAE,MAAM,KAAA;WAAW,QAAQ,KAAA;WAAW,CAAC,GACpE;UACD,CAAA,CACD;;QACN,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBAAsB;UAAS,CAAA,EAC7C,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAO,UACJ,EAAW,EAAO,SAAS;WAAE,MAAM,KAAA;WAAW,QAAQ,KAAA;WAAW,CAAC,GAClE;UACD,CAAA,CACD;;QACH;SACK;;KAEX,EAAO,SACN,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAW,WAAW,EAAO,OAAO,KAAK;MACxD,WAAU;gBAHZ,CAKE,kBAAC,GAAD;OACE,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;OACnC,MAAM,EAAO,MAAM;OACnB,WAAU;OACV,CAAA,EACF,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAO,MAAM;QACZ,CAAA,EACJ,kBAAC,KAAD;QAAG,WAAU;kBAAuC;QAAc,CAAA,CAC9D;SACC;;KAEP;MACF;;EACK,CAAA"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useCoolAndLovely as e } from "../../context/CoolAndLovelyContext.js";
|
|
2
2
|
import { PageLayout as t } from "../../components/PageLayout.js";
|
|
3
3
|
import { useBrands as n, useCreateCollaboration as r } from "../../hooks/useCoolAndLovelyApi.js";
|
|
4
|
-
import "../../hooks/index.js";
|
|
5
4
|
import { parseCsv as i, titleCase as a } from "../../utils/formatters.js";
|
|
5
|
+
import "../../hooks/index.js";
|
|
6
6
|
import { SelectField as o, TextAreaField as s, TextField as c } from "../../components/Field.js";
|
|
7
7
|
import { useMemo as l, useState as u } from "react";
|
|
8
8
|
import { ArrowLeft as d, Handshake as f, Loader2 as p, Save as m } from "lucide-react";
|