@burdenoff/microfe-coolandlovely 2026.625.2 → 2026.628.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 (165) hide show
  1. package/dist/coolandlovely/CoolAndLovelyRoot.js +66 -122
  2. package/dist/coolandlovely/CoolAndLovelyRoot.js.map +1 -1
  3. package/dist/coolandlovely/CoolAndLovelyRoutes.js +87 -175
  4. package/dist/coolandlovely/CoolAndLovelyRoutes.js.map +1 -1
  5. package/dist/coolandlovely/components/Field.js +81 -0
  6. package/dist/coolandlovely/components/Field.js.map +1 -0
  7. package/dist/coolandlovely/components/StateViews.js +34 -0
  8. package/dist/coolandlovely/components/StateViews.js.map +1 -0
  9. package/dist/coolandlovely/components/StatusBadge.js +25 -22
  10. package/dist/coolandlovely/components/StatusBadge.js.map +1 -1
  11. package/dist/coolandlovely/components/TagList.js +21 -0
  12. package/dist/coolandlovely/components/TagList.js.map +1 -0
  13. package/dist/coolandlovely/components/Thumbnail.js +29 -0
  14. package/dist/coolandlovely/components/Thumbnail.js.map +1 -0
  15. package/dist/coolandlovely/context/CoolAndLovelyContext.js +10 -10
  16. package/dist/coolandlovely/context/CoolAndLovelyContext.js.map +1 -1
  17. package/dist/coolandlovely/hooks/index.js +1 -0
  18. package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js +462 -169
  19. package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js.map +1 -1
  20. package/dist/coolandlovely/pages/HomePage.js +251 -845
  21. package/dist/coolandlovely/pages/HomePage.js.map +1 -1
  22. package/dist/coolandlovely/pages/brands/BrandDetailPage.js +319 -0
  23. package/dist/coolandlovely/pages/brands/BrandDetailPage.js.map +1 -0
  24. package/dist/coolandlovely/pages/brands/BrandFormPage.js +190 -0
  25. package/dist/coolandlovely/pages/brands/BrandFormPage.js.map +1 -0
  26. package/dist/coolandlovely/pages/brands/BrandsListPage.js +158 -0
  27. package/dist/coolandlovely/pages/brands/BrandsListPage.js.map +1 -0
  28. package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js +253 -0
  29. package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js.map +1 -0
  30. package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.js +206 -0
  31. package/dist/coolandlovely/pages/collaborations/CollaborationFormPage.js.map +1 -0
  32. package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.js +129 -0
  33. package/dist/coolandlovely/pages/collaborations/CollaborationsListPage.js.map +1 -0
  34. package/dist/coolandlovely/pages/collections/CollectionDetailPage.js +217 -0
  35. package/dist/coolandlovely/pages/collections/CollectionDetailPage.js.map +1 -0
  36. package/dist/coolandlovely/pages/collections/CollectionFormPage.js +217 -0
  37. package/dist/coolandlovely/pages/collections/CollectionFormPage.js.map +1 -0
  38. package/dist/coolandlovely/pages/collections/CollectionsListPage.js +122 -0
  39. package/dist/coolandlovely/pages/collections/CollectionsListPage.js.map +1 -0
  40. package/dist/coolandlovely/pages/items/StyleItemDetailPage.js +230 -0
  41. package/dist/coolandlovely/pages/items/StyleItemDetailPage.js.map +1 -0
  42. package/dist/coolandlovely/pages/items/StyleItemFormPage.js +276 -0
  43. package/dist/coolandlovely/pages/items/StyleItemFormPage.js.map +1 -0
  44. package/dist/coolandlovely/pages/items/StyleItemsListPage.js +170 -0
  45. package/dist/coolandlovely/pages/items/StyleItemsListPage.js.map +1 -0
  46. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js +124 -0
  47. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js.map +1 -0
  48. package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js +156 -0
  49. package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js.map +1 -0
  50. package/dist/coolandlovely/pages/looks/LookDetailPage.js +238 -0
  51. package/dist/coolandlovely/pages/looks/LookDetailPage.js.map +1 -0
  52. package/dist/coolandlovely/pages/looks/LookFormPage.js +209 -0
  53. package/dist/coolandlovely/pages/looks/LookFormPage.js.map +1 -0
  54. package/dist/coolandlovely/pages/looks/LooksListPage.js +181 -0
  55. package/dist/coolandlovely/pages/looks/LooksListPage.js.map +1 -0
  56. package/dist/coolandlovely/pages/profile/StyleProfilePage.js +224 -0
  57. package/dist/coolandlovely/pages/profile/StyleProfilePage.js.map +1 -0
  58. package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js +173 -0
  59. package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js.map +1 -0
  60. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js +172 -0
  61. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js.map +1 -0
  62. package/dist/coolandlovely/store/coolandlovelyStore.js +2 -6
  63. package/dist/coolandlovely/store/coolandlovelyStore.js.map +1 -1
  64. package/dist/coolandlovely/utils/formatters.js +31 -23
  65. package/dist/coolandlovely/utils/formatters.js.map +1 -1
  66. package/dist/coolandlovely/utils/icons.js +34 -0
  67. package/dist/coolandlovely/utils/icons.js.map +1 -0
  68. package/dist/index.js +4 -4
  69. package/package.json +1 -1
  70. package/dist/coolandlovely/components/InvestmentCard.js +0 -98
  71. package/dist/coolandlovely/components/InvestmentCard.js.map +0 -1
  72. package/dist/coolandlovely/components/RatingDisplay.js +0 -35
  73. package/dist/coolandlovely/components/RatingDisplay.js.map +0 -1
  74. package/dist/coolandlovely/mocks/data.js +0 -1517
  75. package/dist/coolandlovely/mocks/data.js.map +0 -1
  76. package/dist/coolandlovely/mocks/users.js +0 -34
  77. package/dist/coolandlovely/mocks/users.js.map +0 -1
  78. package/dist/coolandlovely/pages/admin/AdminAnalyticsPage.js +0 -651
  79. package/dist/coolandlovely/pages/admin/AdminAnalyticsPage.js.map +0 -1
  80. package/dist/coolandlovely/pages/admin/AdminDashboard.js +0 -673
  81. package/dist/coolandlovely/pages/admin/AdminDashboard.js.map +0 -1
  82. package/dist/coolandlovely/pages/admin/AdminFinancialPage.js +0 -427
  83. package/dist/coolandlovely/pages/admin/AdminFinancialPage.js.map +0 -1
  84. package/dist/coolandlovely/pages/admin/AdminOrdersPage.js +0 -665
  85. package/dist/coolandlovely/pages/admin/AdminOrdersPage.js.map +0 -1
  86. package/dist/coolandlovely/pages/admin/AdminProfilePage.js +0 -264
  87. package/dist/coolandlovely/pages/admin/AdminProfilePage.js.map +0 -1
  88. package/dist/coolandlovely/pages/admin/AdminSettingsPage.js +0 -654
  89. package/dist/coolandlovely/pages/admin/AdminSettingsPage.js.map +0 -1
  90. package/dist/coolandlovely/pages/admin/CartManagementPage.js +0 -874
  91. package/dist/coolandlovely/pages/admin/CartManagementPage.js.map +0 -1
  92. package/dist/coolandlovely/pages/admin/UserManagementPage.js +0 -898
  93. package/dist/coolandlovely/pages/admin/UserManagementPage.js.map +0 -1
  94. package/dist/coolandlovely/pages/cart-owner/AnalyticsDashboard.js +0 -842
  95. package/dist/coolandlovely/pages/cart-owner/AnalyticsDashboard.js.map +0 -1
  96. package/dist/coolandlovely/pages/cart-owner/BusinessSettingsPage.js +0 -705
  97. package/dist/coolandlovely/pages/cart-owner/BusinessSettingsPage.js.map +0 -1
  98. package/dist/coolandlovely/pages/cart-owner/CartOwnerDashboard.js +0 -802
  99. package/dist/coolandlovely/pages/cart-owner/CartOwnerDashboard.js.map +0 -1
  100. package/dist/coolandlovely/pages/cart-owner/CartOwnerProfilePage.js +0 -891
  101. package/dist/coolandlovely/pages/cart-owner/CartOwnerProfilePage.js.map +0 -1
  102. package/dist/coolandlovely/pages/cart-owner/CartServiceConfigPage.js +0 -639
  103. package/dist/coolandlovely/pages/cart-owner/CartServiceConfigPage.js.map +0 -1
  104. package/dist/coolandlovely/pages/cart-owner/InventoryManagementPage.js +0 -914
  105. package/dist/coolandlovely/pages/cart-owner/InventoryManagementPage.js.map +0 -1
  106. package/dist/coolandlovely/pages/cart-owner/OrderManagementPage.js +0 -882
  107. package/dist/coolandlovely/pages/cart-owner/OrderManagementPage.js.map +0 -1
  108. package/dist/coolandlovely/pages/cart-owner/StaffManagementPage.js +0 -831
  109. package/dist/coolandlovely/pages/cart-owner/StaffManagementPage.js.map +0 -1
  110. package/dist/coolandlovely/pages/common/HelpSupportPage.js +0 -1325
  111. package/dist/coolandlovely/pages/common/HelpSupportPage.js.map +0 -1
  112. package/dist/coolandlovely/pages/common/NotificationCenterPage.js +0 -671
  113. package/dist/coolandlovely/pages/common/NotificationCenterPage.js.map +0 -1
  114. package/dist/coolandlovely/pages/common/SettingsPage.js +0 -973
  115. package/dist/coolandlovely/pages/common/SettingsPage.js.map +0 -1
  116. package/dist/coolandlovely/pages/customer/BookingDetailsPage.js +0 -630
  117. package/dist/coolandlovely/pages/customer/BookingDetailsPage.js.map +0 -1
  118. package/dist/coolandlovely/pages/customer/CartDetailPage.js +0 -623
  119. package/dist/coolandlovely/pages/customer/CartDetailPage.js.map +0 -1
  120. package/dist/coolandlovely/pages/customer/CartDiscoveryPage.js +0 -558
  121. package/dist/coolandlovely/pages/customer/CartDiscoveryPage.js.map +0 -1
  122. package/dist/coolandlovely/pages/customer/CheckoutPage.js +0 -529
  123. package/dist/coolandlovely/pages/customer/CheckoutPage.js.map +0 -1
  124. package/dist/coolandlovely/pages/customer/CustomerDashboard.js +0 -538
  125. package/dist/coolandlovely/pages/customer/CustomerDashboard.js.map +0 -1
  126. package/dist/coolandlovely/pages/customer/CustomerProfilePage.js +0 -658
  127. package/dist/coolandlovely/pages/customer/CustomerProfilePage.js.map +0 -1
  128. package/dist/coolandlovely/pages/customer/DirectServiceBookingPage.js +0 -632
  129. package/dist/coolandlovely/pages/customer/DirectServiceBookingPage.js.map +0 -1
  130. package/dist/coolandlovely/pages/customer/FavoritesPage.js +0 -487
  131. package/dist/coolandlovely/pages/customer/FavoritesPage.js.map +0 -1
  132. package/dist/coolandlovely/pages/customer/OrderHistoryPage.js +0 -447
  133. package/dist/coolandlovely/pages/customer/OrderHistoryPage.js.map +0 -1
  134. package/dist/coolandlovely/pages/customer/OrderTrackingPage.js +0 -425
  135. package/dist/coolandlovely/pages/customer/OrderTrackingPage.js.map +0 -1
  136. package/dist/coolandlovely/pages/customer/PaymentMethodsPage.js +0 -494
  137. package/dist/coolandlovely/pages/customer/PaymentMethodsPage.js.map +0 -1
  138. package/dist/coolandlovely/pages/customer/ReviewsPage.js +0 -616
  139. package/dist/coolandlovely/pages/customer/ReviewsPage.js.map +0 -1
  140. package/dist/coolandlovely/pages/customer/SavedAddressesPage.js +0 -449
  141. package/dist/coolandlovely/pages/customer/SavedAddressesPage.js.map +0 -1
  142. package/dist/coolandlovely/pages/investor/InvestmentDetailsPage.js +0 -887
  143. package/dist/coolandlovely/pages/investor/InvestmentDetailsPage.js.map +0 -1
  144. package/dist/coolandlovely/pages/investor/InvestmentOpportunitiesPage.js +0 -945
  145. package/dist/coolandlovely/pages/investor/InvestmentOpportunitiesPage.js.map +0 -1
  146. package/dist/coolandlovely/pages/investor/InvestorAnalyticsPage.js +0 -687
  147. package/dist/coolandlovely/pages/investor/InvestorAnalyticsPage.js.map +0 -1
  148. package/dist/coolandlovely/pages/investor/InvestorDashboard.js +0 -455
  149. package/dist/coolandlovely/pages/investor/InvestorDashboard.js.map +0 -1
  150. package/dist/coolandlovely/pages/investor/InvestorInvestmentsPage.js +0 -405
  151. package/dist/coolandlovely/pages/investor/InvestorInvestmentsPage.js.map +0 -1
  152. package/dist/coolandlovely/pages/investor/InvestorPortfolioPage.js +0 -602
  153. package/dist/coolandlovely/pages/investor/InvestorPortfolioPage.js.map +0 -1
  154. package/dist/coolandlovely/pages/investor/InvestorProfilePage.js +0 -1070
  155. package/dist/coolandlovely/pages/investor/InvestorProfilePage.js.map +0 -1
  156. package/dist/coolandlovely/pages/worker/TaskDetailsPage.js +0 -533
  157. package/dist/coolandlovely/pages/worker/TaskDetailsPage.js.map +0 -1
  158. package/dist/coolandlovely/pages/worker/WorkerDashboard.js +0 -671
  159. package/dist/coolandlovely/pages/worker/WorkerDashboard.js.map +0 -1
  160. package/dist/coolandlovely/pages/worker/WorkerOrdersPage.js +0 -680
  161. package/dist/coolandlovely/pages/worker/WorkerOrdersPage.js.map +0 -1
  162. package/dist/coolandlovely/pages/worker/WorkerProfilePage.js +0 -692
  163. package/dist/coolandlovely/pages/worker/WorkerProfilePage.js.map +0 -1
  164. package/dist/coolandlovely/pages/worker/WorkerSchedulePage.js +0 -583
  165. package/dist/coolandlovely/pages/worker/WorkerSchedulePage.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CollectionDetailPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/collections/CollectionDetailPage.tsx"],"sourcesContent":["/**\n * Collection Detail Page\n * @module coolandlovely/pages/collections\n *\n * Single collection (`cooCollection`) with publish (`cooPublishCollection`),\n * edit, its brand link and member items.\n */\n\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Pencil, Rocket, Loader2, Shapes, Store, 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 { TagList } from '../../components/TagList';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useCollection, usePublishCollection } from '../../hooks';\nimport { categoryIcon } from '../../utils/icons';\nimport { formatPrice, formatDate, titleCase } from '../../utils/formatters';\n\nexport function CollectionDetailPage() {\n const { collectionId } = useParams<{ collectionId: string }>();\n const { navigateTo } = useCoolAndLovely();\n const query = useCollection(collectionId);\n const publish = usePublishCollection();\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Collection\">\n <LoadingView label=\"Loading collection…\" />\n </PageLayout>\n );\n }\n\n if (query.isError || !query.data) {\n return (\n <PageLayout title=\"Collection\">\n <ErrorView title=\"Collection not found\" onRetry={() => void query.refetch()} />\n </PageLayout>\n );\n }\n\n const collection = query.data;\n const items = collection.items ?? [];\n const canPublish = collection.status === 'DRAFT' || collection.status === 'SCHEDULED';\n\n return (\n <PageLayout\n title={collection.name}\n description={collection.brand?.name ?? undefined}\n actions={\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/collections')}\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 <button\n type=\"button\"\n onClick={() => navigateTo(`/collections/${collection.id}/edit`)}\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 <Pencil className=\"h-4 w-4\" /> Edit\n </button>\n {canPublish && (\n <button\n type=\"button\"\n disabled={publish.isPending}\n onClick={() => publish.mutate(collection.id)}\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 disabled:opacity-50\"\n >\n {publish.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Rocket className=\"h-4 w-4\" />\n )}\n Publish\n </button>\n )}\n </div>\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=\"overflow-hidden p-0\">\n <Thumbnail icon={<Shapes className=\"h-12 w-12\" />} seed={collection.id} className=\"h-40 w-full\" />\n <div className=\"p-6\">\n <div className=\"flex items-center gap-2\">\n <h2 className=\"text-xl font-semibold text-text-primary\">{collection.name}</h2>\n <StatusBadge status={collection.status} className=\"ml-auto\" />\n </div>\n {collection.description && (\n <p className=\"mt-3 text-sm text-text-secondary\">{collection.description}</p>\n )}\n {collection.tags.length > 0 && <TagList tags={collection.tags} className=\"mt-4\" />}\n </div>\n </GlassCard>\n\n <section className=\"mt-6\">\n <h3 className=\"mb-3 text-lg font-semibold text-text-primary\">\n 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 in this collection 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 icon={categoryIcon(item.category, 24)} seed={item.id} className=\"h-24 w-full\" />\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 <button\n type=\"button\"\n onClick={() => navigateTo(`/items/new?brandId=${collection.brandId}&collectionId=${collection.id}`)}\n className=\"mt-3 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 <Plus className=\"h-4 w-4\" /> Add item to this collection\n </button>\n </section>\n </div>\n\n <div className=\"space-y-4\">\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\">Season</dt>\n <dd className=\"text-text-primary\">{titleCase(collection.season)}</dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Publish at</dt>\n <dd className=\"text-text-primary\">\n {collection.publishAt\n ? formatDate(collection.publishAt, { hour: undefined, minute: undefined })\n : '—'}\n </dd>\n </div>\n <div className=\"flex justify-between gap-2\">\n <dt className=\"text-text-secondary\">Ends at</dt>\n <dd className=\"text-text-primary\">\n {collection.endAt\n ? formatDate(collection.endAt, { hour: undefined, minute: undefined })\n : '—'}\n </dd>\n </div>\n </dl>\n </GlassCard>\n\n {collection.brand && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/brands/${collection.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 icon={<Store className=\"h-5 w-5\" />} seed={collection.brand.id} className=\"h-10 w-10 shrink-0\" />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{collection.brand.name}</p>\n <p className=\"truncate text-xs text-text-secondary\">View brand</p>\n </div>\n </button>\n )}\n\n {publish.isError && (\n <p className=\"rounded-lg bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text\">\n {publish.error instanceof Error ? publish.error.message : 'Publish failed'}\n </p>\n )}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,217 @@
1
+ import { useCoolAndLovely as e } from "../../context/CoolAndLovelyContext.js";
2
+ import { PageLayout as t } from "../../components/PageLayout.js";
3
+ import { ErrorView as n, LoadingView as r } from "../../components/StateViews.js";
4
+ import { useBrands as i, useCollection as a, useCreateCollection as o, useUpdateCollection as s } from "../../hooks/useCoolAndLovelyApi.js";
5
+ import "../../hooks/index.js";
6
+ import { parseCsv as c, titleCase as l } from "../../utils/formatters.js";
7
+ import { SelectField as u, TextAreaField as d, TextField as f } from "../../components/Field.js";
8
+ import { useEffect as p, useMemo as m, useState as h } from "react";
9
+ import { ArrowLeft as g, Loader2 as _, Save as v, Shapes as y } from "lucide-react";
10
+ import { useParams as b, useSearchParams as x } from "react-router-dom";
11
+ import { jsx as S, jsxs as C } from "react/jsx-runtime";
12
+ import { GlassCard as w } from "@burdenoff/fe-libs/ui";
13
+ //#region src/coolandlovely/pages/collections/CollectionFormPage.tsx
14
+ var T = [
15
+ "SPRING",
16
+ "SUMMER",
17
+ "AUTUMN",
18
+ "WINTER",
19
+ "RESORT",
20
+ "ALL_SEASON"
21
+ ], E = {
22
+ brandId: "",
23
+ name: "",
24
+ description: "",
25
+ season: "ALL_SEASON",
26
+ tags: "",
27
+ publishAt: "",
28
+ endAt: ""
29
+ };
30
+ function D(e) {
31
+ if (!e) return;
32
+ let t = new Date(e);
33
+ return Number.isNaN(t.getTime()) ? void 0 : t.toISOString();
34
+ }
35
+ function O(e) {
36
+ if (!e) return "";
37
+ let t = new Date(e);
38
+ return Number.isNaN(t.getTime()) ? "" : t.toISOString().slice(0, 10);
39
+ }
40
+ function k() {
41
+ let { collectionId: k } = b(), [A] = x(), j = !!k, { navigateTo: M } = e(), N = a(j ? k : void 0), P = i({ pagination: {
42
+ limit: 100,
43
+ offset: 0
44
+ } }), F = o(), I = s(), [L, R] = h(() => ({
45
+ ...E,
46
+ brandId: A.get("brandId") ?? ""
47
+ })), [z, B] = h({});
48
+ p(() => {
49
+ if (j && N.data) {
50
+ let e = N.data;
51
+ R({
52
+ brandId: e.brandId,
53
+ name: e.name,
54
+ description: e.description ?? "",
55
+ season: e.season,
56
+ tags: e.tags.join(", "),
57
+ publishAt: O(e.publishAt),
58
+ endAt: O(e.endAt)
59
+ });
60
+ }
61
+ }, [j, N.data]);
62
+ let V = (e, t) => R((n) => ({
63
+ ...n,
64
+ [e]: t
65
+ })), H = j ? I : F, U = m(() => (P.data?.items ?? []).map((e) => ({
66
+ value: e.id,
67
+ label: e.name
68
+ })), [P.data]), W = T.map((e) => ({
69
+ value: e,
70
+ label: l(e)
71
+ })), G = () => {
72
+ let e = {};
73
+ return L.name.trim() || (e.name = "Name is required"), !j && !L.brandId && (e.brandId = "Brand is required"), B(e), Object.keys(e).length === 0;
74
+ };
75
+ return j && N.isLoading ? /* @__PURE__ */ S(t, {
76
+ title: "Edit collection",
77
+ children: /* @__PURE__ */ S(r, { label: "Loading collection…" })
78
+ }) : j && (N.isError || !N.data) ? /* @__PURE__ */ S(t, {
79
+ title: "Edit collection",
80
+ children: /* @__PURE__ */ S(n, {
81
+ title: "Collection not found",
82
+ onRetry: () => void N.refetch()
83
+ })
84
+ }) : /* @__PURE__ */ S(t, {
85
+ title: j ? "Edit collection" : "New collection",
86
+ description: j ? "Update this seasonal drop" : "Group pieces into a seasonal drop",
87
+ actions: /* @__PURE__ */ C("button", {
88
+ type: "button",
89
+ onClick: () => M(j && k ? `/collections/${k}` : "/collections"),
90
+ 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",
91
+ children: [/* @__PURE__ */ S(g, { className: "h-4 w-4" }), " Cancel"]
92
+ }),
93
+ children: /* @__PURE__ */ S("form", {
94
+ onSubmit: (e) => {
95
+ e.preventDefault(), G() && (j && k ? I.mutate({
96
+ id: k,
97
+ input: {
98
+ name: L.name.trim(),
99
+ description: L.description.trim() || void 0,
100
+ season: L.season,
101
+ tags: c(L.tags),
102
+ publishAt: D(L.publishAt),
103
+ endAt: D(L.endAt)
104
+ }
105
+ }, { onSuccess: () => M(`/collections/${k}`) }) : F.mutate({
106
+ brandId: L.brandId,
107
+ name: L.name.trim(),
108
+ description: L.description.trim() || void 0,
109
+ season: L.season,
110
+ tags: c(L.tags),
111
+ publishAt: D(L.publishAt),
112
+ endAt: D(L.endAt)
113
+ }, { onSuccess: (e) => M(`/collections/${e.id}`) }));
114
+ },
115
+ className: "mx-auto max-w-2xl",
116
+ children: /* @__PURE__ */ C(w, {
117
+ treatment: "plain",
118
+ className: "p-6",
119
+ children: [
120
+ /* @__PURE__ */ C("div", {
121
+ className: "mb-6 flex items-center gap-3",
122
+ children: [/* @__PURE__ */ S("div", {
123
+ className: "flex h-11 w-11 items-center justify-center rounded-lg bg-accent-blue-subtle text-accent-blue",
124
+ children: /* @__PURE__ */ S(y, { className: "h-5 w-5" })
125
+ }), /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("h2", {
126
+ className: "text-base font-semibold text-text-primary",
127
+ children: "Collection details"
128
+ }), /* @__PURE__ */ S("p", {
129
+ className: "text-xs text-text-secondary",
130
+ children: "A collection belongs to one brand."
131
+ })] })]
132
+ }),
133
+ !j && /* @__PURE__ */ S(u, {
134
+ id: "brandId",
135
+ label: "Brand",
136
+ value: L.brandId,
137
+ onChange: (e) => V("brandId", e),
138
+ options: U,
139
+ required: !0,
140
+ placeholder: P.isLoading ? "Loading brands…" : "Select a brand",
141
+ error: z.brandId,
142
+ className: "mb-4"
143
+ }),
144
+ /* @__PURE__ */ C("div", {
145
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
146
+ children: [/* @__PURE__ */ S(f, {
147
+ id: "name",
148
+ label: "Name",
149
+ value: L.name,
150
+ onChange: (e) => V("name", e),
151
+ placeholder: "Spring Awakening",
152
+ required: !0,
153
+ error: z.name
154
+ }), /* @__PURE__ */ S(u, {
155
+ id: "season",
156
+ label: "Season",
157
+ value: L.season,
158
+ onChange: (e) => V("season", e),
159
+ options: W
160
+ })]
161
+ }),
162
+ /* @__PURE__ */ S(d, {
163
+ id: "description",
164
+ label: "Description",
165
+ value: L.description,
166
+ onChange: (e) => V("description", e),
167
+ placeholder: "Describe the drop…",
168
+ rows: 3,
169
+ className: "mt-4"
170
+ }),
171
+ /* @__PURE__ */ C("div", {
172
+ className: "mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2",
173
+ children: [/* @__PURE__ */ S(f, {
174
+ id: "publishAt",
175
+ label: "Publish date",
176
+ type: "date",
177
+ value: L.publishAt,
178
+ onChange: (e) => V("publishAt", e)
179
+ }), /* @__PURE__ */ S(f, {
180
+ id: "endAt",
181
+ label: "End date",
182
+ type: "date",
183
+ value: L.endAt,
184
+ onChange: (e) => V("endAt", e)
185
+ })]
186
+ }),
187
+ /* @__PURE__ */ S(f, {
188
+ id: "tags",
189
+ label: "Tags",
190
+ value: L.tags,
191
+ onChange: (e) => V("tags", e),
192
+ placeholder: "pastel, floral",
193
+ hint: "Comma-separated",
194
+ className: "mt-4"
195
+ }),
196
+ H.isError && /* @__PURE__ */ S("p", {
197
+ className: "mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
198
+ children: H.error instanceof Error ? H.error.message : "Something went wrong"
199
+ }),
200
+ /* @__PURE__ */ S("div", {
201
+ className: "mt-6 flex justify-end gap-2",
202
+ children: /* @__PURE__ */ C("button", {
203
+ type: "submit",
204
+ disabled: H.isPending,
205
+ className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-5 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-50",
206
+ children: [H.isPending ? /* @__PURE__ */ S(_, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ S(v, { className: "h-4 w-4" }), j ? "Save changes" : "Create collection"]
207
+ })
208
+ })
209
+ ]
210
+ })
211
+ })
212
+ });
213
+ }
214
+ //#endregion
215
+ export { k as CollectionFormPage };
216
+
217
+ //# sourceMappingURL=CollectionFormPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CollectionFormPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/collections/CollectionFormPage.tsx"],"sourcesContent":["/**\n * Collection Create / Edit Page\n * @module coolandlovely/pages/collections\n *\n * Drives `cooCreateCollection` (new) and `cooUpdateCollection` (edit).\n * Brand selection is required on create and locked on edit.\n */\n\nimport { useEffect, useMemo, useState } from 'react';\nimport { useParams, useSearchParams } from 'react-router-dom';\nimport { ArrowLeft, Loader2, Save, Shapes } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { LoadingView, ErrorView } from '../../components/StateViews';\nimport { TextField, TextAreaField, SelectField } from '../../components/Field';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport { useCollection, useCreateCollection, useUpdateCollection, useBrands } from '../../hooks';\nimport { parseCsv, titleCase } from '../../utils/formatters';\nimport type { CooSeason } from '../../types';\n\nconst SEASONS: CooSeason[] = ['SPRING', 'SUMMER', 'AUTUMN', 'WINTER', 'RESORT', 'ALL_SEASON'];\n\ninterface FormState {\n brandId: string;\n name: string;\n description: string;\n season: CooSeason;\n tags: string;\n publishAt: string;\n endAt: string;\n}\n\nconst EMPTY: FormState = {\n brandId: '',\n name: '',\n description: '',\n season: 'ALL_SEASON',\n tags: '',\n publishAt: '',\n endAt: '',\n};\n\n/** ISO timestamp <input type=date> values use yyyy-mm-dd; convert to ISO. */\nfunction toIso(date: string): string | undefined {\n if (!date) return undefined;\n const d = new Date(date);\n return Number.isNaN(d.getTime()) ? undefined : d.toISOString();\n}\n\nfunction toDateInput(iso: string | null): string {\n if (!iso) return '';\n const d = new Date(iso);\n return Number.isNaN(d.getTime()) ? '' : d.toISOString().slice(0, 10);\n}\n\nexport function CollectionFormPage() {\n const { collectionId } = useParams<{ collectionId: string }>();\n const [searchParams] = useSearchParams();\n const isEdit = Boolean(collectionId);\n const { navigateTo } = useCoolAndLovely();\n\n const existing = useCollection(isEdit ? collectionId : undefined);\n const brands = useBrands({ pagination: { limit: 100, offset: 0 } });\n const createCollection = useCreateCollection();\n const updateCollection = useUpdateCollection();\n\n const [form, setForm] = useState<FormState>(() => ({\n ...EMPTY,\n brandId: searchParams.get('brandId') ?? '',\n }));\n const [errors, setErrors] = useState<Partial<Record<keyof FormState, string>>>({});\n\n useEffect(() => {\n if (isEdit && existing.data) {\n const c = existing.data;\n setForm({\n brandId: c.brandId,\n name: c.name,\n description: c.description ?? '',\n season: c.season,\n tags: c.tags.join(', '),\n publishAt: toDateInput(c.publishAt),\n endAt: toDateInput(c.endAt),\n });\n }\n }, [isEdit, existing.data]);\n\n const setField = <K extends keyof FormState>(key: K, value: FormState[K]) =>\n setForm((f) => ({ ...f, [key]: value }));\n\n const mutation = isEdit ? updateCollection : createCollection;\n\n const brandOptions = useMemo(\n () => (brands.data?.items ?? []).map((b) => ({ value: b.id, label: b.name })),\n [brands.data]\n );\n const seasonOptions = SEASONS.map((s) => ({ value: s, label: titleCase(s) }));\n\n const validate = (): boolean => {\n const next: Partial<Record<keyof FormState, string>> = {};\n if (!form.name.trim()) next.name = 'Name is required';\n if (!isEdit && !form.brandId) next.brandId = 'Brand is required';\n setErrors(next);\n return Object.keys(next).length === 0;\n };\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n if (!validate()) return;\n\n if (isEdit && collectionId) {\n updateCollection.mutate(\n {\n id: collectionId,\n input: {\n name: form.name.trim(),\n description: form.description.trim() || undefined,\n season: form.season,\n tags: parseCsv(form.tags),\n publishAt: toIso(form.publishAt),\n endAt: toIso(form.endAt),\n },\n },\n { onSuccess: () => navigateTo(`/collections/${collectionId}`) }\n );\n } else {\n createCollection.mutate(\n {\n brandId: form.brandId,\n name: form.name.trim(),\n description: form.description.trim() || undefined,\n season: form.season,\n tags: parseCsv(form.tags),\n publishAt: toIso(form.publishAt),\n endAt: toIso(form.endAt),\n },\n { onSuccess: (c) => navigateTo(`/collections/${c.id}`) }\n );\n }\n };\n\n if (isEdit && existing.isLoading) {\n return (\n <PageLayout title=\"Edit collection\">\n <LoadingView label=\"Loading collection…\" />\n </PageLayout>\n );\n }\n\n if (isEdit && (existing.isError || !existing.data)) {\n return (\n <PageLayout title=\"Edit collection\">\n <ErrorView title=\"Collection not found\" onRetry={() => void existing.refetch()} />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={isEdit ? 'Edit collection' : 'New collection'}\n description={isEdit ? 'Update this seasonal drop' : 'Group pieces into a seasonal drop'}\n actions={\n <button\n type=\"button\"\n onClick={() =>\n navigateTo(isEdit && collectionId ? `/collections/${collectionId}` : '/collections')\n }\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\" /> Cancel\n </button>\n }\n >\n <form onSubmit={handleSubmit} className=\"mx-auto max-w-2xl\">\n <GlassCard treatment=\"plain\" className=\"p-6\">\n <div className=\"mb-6 flex items-center gap-3\">\n <div className=\"flex h-11 w-11 items-center justify-center rounded-lg bg-accent-blue-subtle text-accent-blue\">\n <Shapes className=\"h-5 w-5\" />\n </div>\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">Collection details</h2>\n <p className=\"text-xs text-text-secondary\">A collection belongs to one brand.</p>\n </div>\n </div>\n\n {!isEdit && (\n <SelectField\n id=\"brandId\"\n label=\"Brand\"\n value={form.brandId}\n onChange={(v) => setField('brandId', v)}\n options={brandOptions}\n required\n placeholder={brands.isLoading ? 'Loading brands…' : 'Select a brand'}\n error={errors.brandId}\n className=\"mb-4\"\n />\n )}\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <TextField\n id=\"name\"\n label=\"Name\"\n value={form.name}\n onChange={(v) => setField('name', v)}\n placeholder=\"Spring Awakening\"\n required\n error={errors.name}\n />\n <SelectField\n id=\"season\"\n label=\"Season\"\n value={form.season}\n onChange={(v) => setField('season', v as CooSeason)}\n options={seasonOptions}\n />\n </div>\n\n <TextAreaField\n id=\"description\"\n label=\"Description\"\n value={form.description}\n onChange={(v) => setField('description', v)}\n placeholder=\"Describe the drop…\"\n rows={3}\n className=\"mt-4\"\n />\n\n <div className=\"mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <TextField\n id=\"publishAt\"\n label=\"Publish date\"\n type=\"date\"\n value={form.publishAt}\n onChange={(v) => setField('publishAt', v)}\n />\n <TextField\n id=\"endAt\"\n label=\"End date\"\n type=\"date\"\n value={form.endAt}\n onChange={(v) => setField('endAt', v)}\n />\n </div>\n\n <TextField\n id=\"tags\"\n label=\"Tags\"\n value={form.tags}\n onChange={(v) => setField('tags', v)}\n placeholder=\"pastel, floral\"\n hint=\"Comma-separated\"\n className=\"mt-4\"\n />\n\n {mutation.isError && (\n <p className=\"mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {mutation.error instanceof Error ? mutation.error.message : 'Something went wrong'}\n </p>\n )}\n\n <div className=\"mt-6 flex justify-end gap-2\">\n <button\n type=\"submit\"\n disabled={mutation.isPending}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-5 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-50\"\n >\n {mutation.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Save className=\"h-4 w-4\" />\n )}\n {isEdit ? 'Save changes' : 'Create collection'}\n </button>\n </div>\n </GlassCard>\n </form>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,122 @@
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 { StatusBadge as r } from "../../components/StatusBadge.js";
5
+ import { ErrorView as i, LoadingView as a } from "../../components/StateViews.js";
6
+ import { Thumbnail as o } from "../../components/Thumbnail.js";
7
+ import { useCollections as s } from "../../hooks/useCoolAndLovelyApi.js";
8
+ import "../../hooks/index.js";
9
+ import { formatDate as c, titleCase as l } from "../../utils/formatters.js";
10
+ import { TagList as u } from "../../components/TagList.js";
11
+ import { EmptyState as d } from "../../components/EmptyState.js";
12
+ import { useState as f } from "react";
13
+ import { Plus as p, Shapes as m } from "lucide-react";
14
+ import { jsx as h, jsxs as g } from "react/jsx-runtime";
15
+ //#region src/coolandlovely/pages/collections/CollectionsListPage.tsx
16
+ var _ = [
17
+ {
18
+ value: "ALL",
19
+ label: "All"
20
+ },
21
+ {
22
+ value: "LIVE",
23
+ label: "Live"
24
+ },
25
+ {
26
+ value: "SCHEDULED",
27
+ label: "Scheduled"
28
+ },
29
+ {
30
+ value: "DRAFT",
31
+ label: "Draft"
32
+ },
33
+ {
34
+ value: "ENDED",
35
+ label: "Ended"
36
+ },
37
+ {
38
+ value: "ARCHIVED",
39
+ label: "Archived"
40
+ }
41
+ ];
42
+ function v() {
43
+ let { navigateTo: v } = e(), [y, b] = f("ALL"), x = s({ status: y === "ALL" ? void 0 : y }), S = x.data ?? [];
44
+ return /* @__PURE__ */ g(n, {
45
+ title: "Collections",
46
+ description: "Seasonal drops and curated edits grouped by brand",
47
+ actions: /* @__PURE__ */ g("button", {
48
+ type: "button",
49
+ onClick: () => v("/collections/new"),
50
+ 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",
51
+ children: [/* @__PURE__ */ h(p, { className: "h-4 w-4" }), " New collection"]
52
+ }),
53
+ children: [/* @__PURE__ */ h("div", {
54
+ className: "mb-6 flex flex-wrap items-center gap-2",
55
+ children: _.map((e) => /* @__PURE__ */ h("button", {
56
+ type: "button",
57
+ onClick: () => b(e.value),
58
+ className: t("rounded-full px-3 py-1.5 text-sm font-medium transition-colors", y === e.value ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
59
+ children: e.label
60
+ }, e.value))
61
+ }), x.isLoading ? /* @__PURE__ */ h(a, { label: "Loading collections…" }) : x.isError ? /* @__PURE__ */ h(i, { onRetry: () => void x.refetch() }) : S.length === 0 ? /* @__PURE__ */ h(d, {
62
+ illustration: "empty-data",
63
+ icon: /* @__PURE__ */ h(m, { className: "h-10 w-10" }),
64
+ title: "No collections yet",
65
+ description: "Group pieces into a seasonal drop to start a collection.",
66
+ action: /* @__PURE__ */ g("button", {
67
+ type: "button",
68
+ onClick: () => v("/collections/new"),
69
+ 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",
70
+ children: [/* @__PURE__ */ h(p, { className: "h-4 w-4" }), " New collection"]
71
+ })
72
+ }) : /* @__PURE__ */ h("div", {
73
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
74
+ children: S.map((e) => /* @__PURE__ */ g("button", {
75
+ type: "button",
76
+ onClick: () => v(`/collections/${e.id}`),
77
+ 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",
78
+ children: [/* @__PURE__ */ h(o, {
79
+ icon: /* @__PURE__ */ h(m, { className: "h-9 w-9" }),
80
+ seed: e.id,
81
+ className: "h-28 w-full"
82
+ }), /* @__PURE__ */ g("div", {
83
+ className: "p-4",
84
+ children: [
85
+ /* @__PURE__ */ g("div", {
86
+ className: "flex items-start justify-between gap-2",
87
+ children: [/* @__PURE__ */ g("div", {
88
+ className: "min-w-0",
89
+ children: [/* @__PURE__ */ h("h3", {
90
+ className: "truncate text-base font-semibold text-text-primary",
91
+ children: e.name
92
+ }), e.brand?.name && /* @__PURE__ */ h("p", {
93
+ className: "truncate text-xs text-text-secondary",
94
+ children: e.brand.name
95
+ })]
96
+ }), /* @__PURE__ */ h(r, { status: e.status })]
97
+ }),
98
+ /* @__PURE__ */ g("div", {
99
+ className: "mt-2 flex items-center gap-2 text-xs text-text-secondary",
100
+ children: [/* @__PURE__ */ h("span", {
101
+ className: "rounded-full bg-bg-sunken px-2 py-0.5",
102
+ children: l(e.season)
103
+ }), e.publishAt && /* @__PURE__ */ g("span", { children: ["Publishes ", c(e.publishAt, {
104
+ hour: void 0,
105
+ minute: void 0
106
+ })] })]
107
+ }),
108
+ e.tags.length > 0 && /* @__PURE__ */ h(u, {
109
+ tags: e.tags,
110
+ max: 4,
111
+ className: "mt-3"
112
+ })
113
+ ]
114
+ })]
115
+ }, e.id))
116
+ })]
117
+ });
118
+ }
119
+ //#endregion
120
+ export { v as CollectionsListPage };
121
+
122
+ //# sourceMappingURL=CollectionsListPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CollectionsListPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/collections/CollectionsListPage.tsx"],"sourcesContent":["/**\n * Collections List Page\n * @module coolandlovely/pages/collections\n *\n * Lists seasonal collections (`cooListCollections`) with status filter.\n */\n\nimport { useState } from 'react';\nimport { Plus, Shapes } 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 { useCollections } from '../../hooks';\nimport { titleCase, formatDate } from '../../utils/formatters';\nimport { cn } from '../../utils/cn';\nimport type { CooCollectionStatus } from '../../types';\n\nconst STATUS_OPTIONS: Array<{ value: CooCollectionStatus | 'ALL'; label: string }> = [\n { value: 'ALL', label: 'All' },\n { value: 'LIVE', label: 'Live' },\n { value: 'SCHEDULED', label: 'Scheduled' },\n { value: 'DRAFT', label: 'Draft' },\n { value: 'ENDED', label: 'Ended' },\n { value: 'ARCHIVED', label: 'Archived' },\n];\n\nexport function CollectionsListPage() {\n const { navigateTo } = useCoolAndLovely();\n const [status, setStatus] = useState<CooCollectionStatus | 'ALL'>('ALL');\n\n const query = useCollections({ status: status === 'ALL' ? undefined : status });\n const collections = query.data ?? [];\n\n return (\n <PageLayout\n title=\"Collections\"\n description=\"Seasonal drops and curated edits grouped by brand\"\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/collections/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 collection\n </button>\n }\n >\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={() => setStatus(opt.value)}\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 </div>\n\n {query.isLoading ? (\n <LoadingView label=\"Loading collections…\" />\n ) : query.isError ? (\n <ErrorView onRetry={() => void query.refetch()} />\n ) : collections.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Shapes className=\"h-10 w-10\" />}\n title=\"No collections yet\"\n description=\"Group pieces into a seasonal drop to start a collection.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/collections/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 collection\n </button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {collections.map((c) => (\n <button\n key={c.id}\n type=\"button\"\n onClick={() => navigateTo(`/collections/${c.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 icon={<Shapes className=\"h-9 w-9\" />} seed={c.id} className=\"h-28 w-full\" />\n <div className=\"p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-base font-semibold text-text-primary\">{c.name}</h3>\n {c.brand?.name && (\n <p className=\"truncate text-xs text-text-secondary\">{c.brand.name}</p>\n )}\n </div>\n <StatusBadge status={c.status} />\n </div>\n <div className=\"mt-2 flex items-center gap-2 text-xs text-text-secondary\">\n <span className=\"rounded-full bg-bg-sunken px-2 py-0.5\">{titleCase(c.season)}</span>\n {c.publishAt && <span>Publishes {formatDate(c.publishAt, { hour: undefined, minute: undefined })}</span>}\n </div>\n {c.tags.length > 0 && <TagList tags={c.tags} max={4} className=\"mt-3\" />}\n </div>\n </button>\n ))}\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AAqBA,IAAM,IAA+E;CACnF;EAAE,OAAO;EAAO,OAAO;EAAO;CAC9B;EAAE,OAAO;EAAQ,OAAO;EAAQ;CAChC;EAAE,OAAO;EAAa,OAAO;EAAa;CAC1C;EAAE,OAAO;EAAS,OAAO;EAAS;CAClC;EAAE,OAAO;EAAS,OAAO;EAAS;CAClC;EAAE,OAAO;EAAY,OAAO;EAAY;CACzC;AAED,SAAgB,IAAsB;CACpC,IAAM,EAAE,kBAAe,GAAkB,EACnC,CAAC,GAAQ,KAAa,EAAsC,MAAM,EAElE,IAAQ,EAAe,EAAE,QAAQ,MAAW,QAAQ,KAAA,IAAY,GAAQ,CAAC,EACzE,IAAc,EAAM,QAAQ,EAAE;AAEpC,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAW,mBAAmB;GAC7C,WAAU;aAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,kBACrB;;YAVb,CAaE,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAe,KAAK,MACnB,kBAAC,UAAD;IAEE,MAAK;IACL,eAAe,EAAU,EAAI,MAAM;IACnC,WAAW,EACT,kEACA,MAAW,EAAI,QACX,kDACA,2DACL;cAEA,EAAI;IACE,EAXF,EAAI,MAWF,CACT;GACE,CAAA,EAEL,EAAM,YACL,kBAAC,GAAD,EAAa,OAAM,wBAAyB,CAAA,GAC1C,EAAM,UACR,kBAAC,GAAD,EAAW,eAAe,KAAK,EAAM,SAAS,EAAI,CAAA,GAChD,EAAY,WAAW,IACzB,kBAAC,GAAD;GACE,cAAa;GACb,MAAM,kBAAC,GAAD,EAAQ,WAAU,aAAc,CAAA;GACtC,OAAM;GACN,aAAY;GACZ,QACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,mBAAmB;IAC7C,WAAU;cAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,kBACrB;;GAEX,CAAA,GAEF,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAY,KAAK,MAChB,kBAAC,UAAD;IAEE,MAAK;IACL,eAAe,EAAW,gBAAgB,EAAE,KAAK;IACjD,WAAU;cAJZ,CAME,kBAAC,GAAD;KAAW,MAAM,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;KAAE,MAAM,EAAE;KAAI,WAAU;KAAgB,CAAA,EACvF,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,MAAD;SAAI,WAAU;mBAAsD,EAAE;SAAU,CAAA,EAC/E,EAAE,OAAO,QACR,kBAAC,KAAD;SAAG,WAAU;mBAAwC,EAAE,MAAM;SAAS,CAAA,CAEpE;WACN,kBAAC,GAAD,EAAa,QAAQ,EAAE,QAAU,CAAA,CAC7B;;MACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAyC,EAAU,EAAE,OAAO;QAAQ,CAAA,EACnF,EAAE,aAAa,kBAAC,QAAD,EAAA,UAAA,CAAM,cAAW,EAAW,EAAE,WAAW;QAAE,MAAM,KAAA;QAAW,QAAQ,KAAA;QAAW,CAAC,CAAQ,EAAA,CAAA,CACpG;;MACL,EAAE,KAAK,SAAS,KAAK,kBAAC,GAAD;OAAS,MAAM,EAAE;OAAM,KAAK;OAAG,WAAU;OAAS,CAAA;MACpE;OACC;MAtBF,EAAE,GAsBA,CACT;GACE,CAAA,CAEG"}
@@ -0,0 +1,230 @@
1
+ import { useCoolAndLovely as e } from "../../context/CoolAndLovelyContext.js";
2
+ import { PageLayout as t } from "../../components/PageLayout.js";
3
+ import { StatusBadge as n } from "../../components/StatusBadge.js";
4
+ import { ErrorView as r, LoadingView as i } from "../../components/StateViews.js";
5
+ import { Thumbnail as a } from "../../components/Thumbnail.js";
6
+ import { useArchiveStyleItem as o, useStyleItem as s } from "../../hooks/useCoolAndLovelyApi.js";
7
+ import "../../hooks/index.js";
8
+ import { formatDate as c, formatPrice as l, titleCase as u } from "../../utils/formatters.js";
9
+ import { TagList as d } from "../../components/TagList.js";
10
+ import { categoryIcon as f } from "../../utils/icons.js";
11
+ import { Archive as p, ArrowLeft as m, Loader2 as h, Pencil as g, Shapes as _, Store as v } from "lucide-react";
12
+ import { useParams as y } from "react-router-dom";
13
+ import { jsx as b, jsxs as x } from "react/jsx-runtime";
14
+ import { GlassCard as S } from "@burdenoff/fe-libs/ui";
15
+ //#region src/coolandlovely/pages/items/StyleItemDetailPage.tsx
16
+ function C() {
17
+ let { itemId: C } = y(), { navigateTo: w } = e(), T = s(C), E = o();
18
+ if (T.isLoading) return /* @__PURE__ */ b(t, {
19
+ title: "Style item",
20
+ children: /* @__PURE__ */ b(i, { label: "Loading item…" })
21
+ });
22
+ if (T.isError || !T.data) return /* @__PURE__ */ b(t, {
23
+ title: "Style item",
24
+ children: /* @__PURE__ */ b(r, {
25
+ title: "Item not found",
26
+ onRetry: () => void T.refetch()
27
+ })
28
+ });
29
+ let D = T.data, O = D.status === "RETIRED";
30
+ return /* @__PURE__ */ b(t, {
31
+ title: D.name,
32
+ description: D.brand?.name ?? void 0,
33
+ actions: /* @__PURE__ */ x("div", {
34
+ className: "flex items-center gap-2",
35
+ children: [
36
+ /* @__PURE__ */ x("button", {
37
+ type: "button",
38
+ onClick: () => w("/items"),
39
+ 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",
40
+ children: [/* @__PURE__ */ b(m, { className: "h-4 w-4" }), " Back"]
41
+ }),
42
+ /* @__PURE__ */ x("button", {
43
+ type: "button",
44
+ onClick: () => w(`/items/${D.id}/edit`),
45
+ 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",
46
+ children: [/* @__PURE__ */ b(g, { className: "h-4 w-4" }), " Edit"]
47
+ }),
48
+ !O && /* @__PURE__ */ x("button", {
49
+ type: "button",
50
+ disabled: E.isPending,
51
+ onClick: () => E.mutate(D.id, { onSuccess: () => w("/items") }),
52
+ className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-50",
53
+ children: [E.isPending ? /* @__PURE__ */ b(h, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ b(p, { className: "h-4 w-4" }), "Archive"]
54
+ })
55
+ ]
56
+ }),
57
+ children: /* @__PURE__ */ x("div", {
58
+ className: "grid grid-cols-1 gap-6 lg:grid-cols-3",
59
+ children: [/* @__PURE__ */ b("div", {
60
+ className: "lg:col-span-2",
61
+ children: /* @__PURE__ */ x(S, {
62
+ treatment: "glass",
63
+ className: "overflow-hidden p-0",
64
+ children: [/* @__PURE__ */ b(a, {
65
+ icon: f(D.category, 40),
66
+ seed: D.id,
67
+ className: "h-52 w-full"
68
+ }), /* @__PURE__ */ x("div", {
69
+ className: "p-6",
70
+ children: [
71
+ /* @__PURE__ */ x("div", {
72
+ className: "flex items-center gap-2",
73
+ children: [/* @__PURE__ */ b("h2", {
74
+ className: "text-xl font-semibold text-text-primary",
75
+ children: D.name
76
+ }), /* @__PURE__ */ b(n, {
77
+ status: D.status,
78
+ className: "ml-auto"
79
+ })]
80
+ }),
81
+ /* @__PURE__ */ b("p", {
82
+ className: "mt-1 text-2xl font-bold text-text-primary tabular-nums",
83
+ children: l(D.price, D.currency)
84
+ }),
85
+ D.description && /* @__PURE__ */ b("p", {
86
+ className: "mt-3 text-sm text-text-secondary",
87
+ children: D.description
88
+ }),
89
+ /* @__PURE__ */ x("div", {
90
+ className: "mt-5 grid grid-cols-1 gap-4 sm:grid-cols-2",
91
+ children: [
92
+ D.colours.length > 0 && /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ b("p", {
93
+ className: "mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary",
94
+ children: "Colours"
95
+ }), /* @__PURE__ */ b(d, {
96
+ tags: D.colours,
97
+ max: 10
98
+ })] }),
99
+ D.sizes.length > 0 && /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ b("p", {
100
+ className: "mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary",
101
+ children: "Sizes"
102
+ }), /* @__PURE__ */ b(d, {
103
+ tags: D.sizes,
104
+ max: 10
105
+ })] }),
106
+ D.materials.length > 0 && /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ b("p", {
107
+ className: "mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary",
108
+ children: "Materials"
109
+ }), /* @__PURE__ */ b(d, {
110
+ tags: D.materials,
111
+ max: 10
112
+ })] }),
113
+ D.tags.length > 0 && /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ b("p", {
114
+ className: "mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary",
115
+ children: "Tags"
116
+ }), /* @__PURE__ */ b(d, {
117
+ tags: D.tags,
118
+ max: 10,
119
+ tone: "accent"
120
+ })] })
121
+ ]
122
+ })
123
+ ]
124
+ })]
125
+ })
126
+ }), /* @__PURE__ */ x("div", {
127
+ className: "space-y-4",
128
+ children: [
129
+ /* @__PURE__ */ x(S, {
130
+ treatment: "plain",
131
+ className: "p-5",
132
+ children: [/* @__PURE__ */ b("h3", {
133
+ className: "mb-3 text-sm font-semibold text-text-primary",
134
+ children: "Details"
135
+ }), /* @__PURE__ */ x("dl", {
136
+ className: "space-y-2 text-sm",
137
+ children: [
138
+ /* @__PURE__ */ x("div", {
139
+ className: "flex justify-between gap-2",
140
+ children: [/* @__PURE__ */ b("dt", {
141
+ className: "text-text-secondary",
142
+ children: "Category"
143
+ }), /* @__PURE__ */ b("dd", {
144
+ className: "text-text-primary",
145
+ children: u(D.category)
146
+ })]
147
+ }),
148
+ /* @__PURE__ */ x("div", {
149
+ className: "flex justify-between gap-2",
150
+ children: [/* @__PURE__ */ b("dt", {
151
+ className: "text-text-secondary",
152
+ children: "SKU"
153
+ }), /* @__PURE__ */ b("dd", {
154
+ className: "text-text-primary",
155
+ children: D.sku ?? "—"
156
+ })]
157
+ }),
158
+ /* @__PURE__ */ x("div", {
159
+ className: "flex justify-between gap-2",
160
+ children: [/* @__PURE__ */ b("dt", {
161
+ className: "text-text-secondary",
162
+ children: "Currency"
163
+ }), /* @__PURE__ */ b("dd", {
164
+ className: "text-text-primary",
165
+ children: D.currency
166
+ })]
167
+ }),
168
+ /* @__PURE__ */ x("div", {
169
+ className: "flex justify-between gap-2",
170
+ children: [/* @__PURE__ */ b("dt", {
171
+ className: "text-text-secondary",
172
+ children: "Created"
173
+ }), /* @__PURE__ */ b("dd", {
174
+ className: "text-text-primary",
175
+ children: c(D.createdAt, {
176
+ hour: void 0,
177
+ minute: void 0
178
+ })
179
+ })]
180
+ })
181
+ ]
182
+ })]
183
+ }),
184
+ D.brand && /* @__PURE__ */ x("button", {
185
+ type: "button",
186
+ onClick: () => w(`/brands/${D.brand?.id}`),
187
+ 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",
188
+ children: [/* @__PURE__ */ b(a, {
189
+ icon: /* @__PURE__ */ b(v, { className: "h-5 w-5" }),
190
+ seed: D.brand.id,
191
+ className: "h-10 w-10 shrink-0"
192
+ }), /* @__PURE__ */ x("div", {
193
+ className: "min-w-0",
194
+ children: [/* @__PURE__ */ b("p", {
195
+ className: "truncate text-sm font-medium text-text-primary",
196
+ children: D.brand.name
197
+ }), /* @__PURE__ */ b("p", {
198
+ className: "truncate text-xs text-text-secondary",
199
+ children: "View brand"
200
+ })]
201
+ })]
202
+ }),
203
+ D.collection && /* @__PURE__ */ x("button", {
204
+ type: "button",
205
+ onClick: () => w(`/collections/${D.collection?.id}`),
206
+ 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",
207
+ children: [/* @__PURE__ */ b(a, {
208
+ icon: /* @__PURE__ */ b(_, { className: "h-5 w-5" }),
209
+ seed: D.collection.id,
210
+ className: "h-10 w-10 shrink-0"
211
+ }), /* @__PURE__ */ x("div", {
212
+ className: "min-w-0",
213
+ children: [/* @__PURE__ */ b("p", {
214
+ className: "truncate text-sm font-medium text-text-primary",
215
+ children: D.collection.name
216
+ }), /* @__PURE__ */ b("p", {
217
+ className: "truncate text-xs text-text-secondary",
218
+ children: "View collection"
219
+ })]
220
+ })]
221
+ })
222
+ ]
223
+ })]
224
+ })
225
+ });
226
+ }
227
+ //#endregion
228
+ export { C as StyleItemDetailPage };
229
+
230
+ //# sourceMappingURL=StyleItemDetailPage.js.map