@burdenoff/microfe-coolandlovely 2026.706.1 → 2026.706.2

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 (66) hide show
  1. package/dist/coolandlovely/CoolAndLovelyRoutes.js +14 -6
  2. package/dist/coolandlovely/CoolAndLovelyRoutes.js.map +1 -1
  3. package/dist/coolandlovely/components/ActorName.js +29 -0
  4. package/dist/coolandlovely/components/ActorName.js.map +1 -0
  5. package/dist/coolandlovely/components/AddToLookbookButton.js +81 -0
  6. package/dist/coolandlovely/components/AddToLookbookButton.js.map +1 -0
  7. package/dist/coolandlovely/components/Comments.js +109 -0
  8. package/dist/coolandlovely/components/Comments.js.map +1 -0
  9. package/dist/coolandlovely/components/Field.js +22 -2
  10. package/dist/coolandlovely/components/Field.js.map +1 -1
  11. package/dist/coolandlovely/components/FileImage.js +17 -0
  12. package/dist/coolandlovely/components/FileImage.js.map +1 -0
  13. package/dist/coolandlovely/components/FollowButton.js +24 -0
  14. package/dist/coolandlovely/components/FollowButton.js.map +1 -0
  15. package/dist/coolandlovely/components/ImageUploadField.js +71 -0
  16. package/dist/coolandlovely/components/ImageUploadField.js.map +1 -0
  17. package/dist/coolandlovely/components/Thumbnail.js +20 -13
  18. package/dist/coolandlovely/components/Thumbnail.js.map +1 -1
  19. package/dist/coolandlovely/hooks/index.js +2 -0
  20. package/dist/coolandlovely/hooks/useComments.js +68 -0
  21. package/dist/coolandlovely/hooks/useComments.js.map +1 -0
  22. package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js +74 -4
  23. package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js.map +1 -1
  24. package/dist/coolandlovely/hooks/useFiles.js +94 -0
  25. package/dist/coolandlovely/hooks/useFiles.js.map +1 -0
  26. package/dist/coolandlovely/pages/HomePage.js +105 -87
  27. package/dist/coolandlovely/pages/HomePage.js.map +1 -1
  28. package/dist/coolandlovely/pages/brands/BrandDetailPage.js +144 -122
  29. package/dist/coolandlovely/pages/brands/BrandDetailPage.js.map +1 -1
  30. package/dist/coolandlovely/pages/brands/BrandFormPage.js +128 -90
  31. package/dist/coolandlovely/pages/brands/BrandFormPage.js.map +1 -1
  32. package/dist/coolandlovely/pages/brands/BrandsListPage.js +2 -0
  33. package/dist/coolandlovely/pages/brands/BrandsListPage.js.map +1 -1
  34. package/dist/coolandlovely/pages/collections/CollectionDetailPage.js +5 -1
  35. package/dist/coolandlovely/pages/collections/CollectionDetailPage.js.map +1 -1
  36. package/dist/coolandlovely/pages/collections/CollectionFormPage.js +117 -102
  37. package/dist/coolandlovely/pages/collections/CollectionFormPage.js.map +1 -1
  38. package/dist/coolandlovely/pages/collections/CollectionsListPage.js +2 -0
  39. package/dist/coolandlovely/pages/collections/CollectionsListPage.js.map +1 -1
  40. package/dist/coolandlovely/pages/discover/DiscoverPage.js +223 -0
  41. package/dist/coolandlovely/pages/discover/DiscoverPage.js.map +1 -0
  42. package/dist/coolandlovely/pages/items/StyleItemDetailPage.js +99 -95
  43. package/dist/coolandlovely/pages/items/StyleItemDetailPage.js.map +1 -1
  44. package/dist/coolandlovely/pages/items/StyleItemFormPage.js +144 -130
  45. package/dist/coolandlovely/pages/items/StyleItemFormPage.js.map +1 -1
  46. package/dist/coolandlovely/pages/items/StyleItemsListPage.js +2 -0
  47. package/dist/coolandlovely/pages/items/StyleItemsListPage.js.map +1 -1
  48. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js +190 -99
  49. package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js.map +1 -1
  50. package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js +81 -68
  51. package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js.map +1 -1
  52. package/dist/coolandlovely/pages/looks/LookDetailPage.js +195 -155
  53. package/dist/coolandlovely/pages/looks/LookDetailPage.js.map +1 -1
  54. package/dist/coolandlovely/pages/looks/LookFormPage.js +127 -88
  55. package/dist/coolandlovely/pages/looks/LookFormPage.js.map +1 -1
  56. package/dist/coolandlovely/pages/looks/LooksListPage.js +2 -0
  57. package/dist/coolandlovely/pages/looks/LooksListPage.js.map +1 -1
  58. package/dist/coolandlovely/pages/profile/StyleProfilePage.js +169 -101
  59. package/dist/coolandlovely/pages/profile/StyleProfilePage.js.map +1 -1
  60. package/dist/coolandlovely/pages/trends/TrendsPage.js +249 -0
  61. package/dist/coolandlovely/pages/trends/TrendsPage.js.map +1 -0
  62. package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js +88 -76
  63. package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js.map +1 -1
  64. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js +2 -0
  65. package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js.map +1 -1
  66. package/package.json +1 -1
@@ -1,21 +1,23 @@
1
1
  import { PageLayout as e } from "../../components/PageLayout.js";
2
2
  import { StatusBadge as t } from "../../components/StatusBadge.js";
3
3
  import { ErrorView as n, LoadingView as r } from "../../components/StateViews.js";
4
- import { useMyStyleProfile as i, useUpsertStyleProfile as a } from "../../hooks/useCoolAndLovelyApi.js";
4
+ import { useMyFollowing as i, useMyStyleProfile as a, useUpsertStyleProfile as o } from "../../hooks/useCoolAndLovelyApi.js";
5
5
  import "../../hooks/index.js";
6
- import { parseCsv as o, titleCase as s } from "../../utils/formatters.js";
7
- import { TagList as c } from "../../components/TagList.js";
8
- import { SelectField as l, TextAreaField as u, TextField as d } from "../../components/Field.js";
9
- import { useEffect as f, useState as p } from "react";
10
- import { Loader2 as m, Pencil as h, Save as g, UserCircle as _, X as v } from "lucide-react";
11
- import { jsx as y, jsxs as b } from "react/jsx-runtime";
12
- import { GlassCard as x } from "@burdenoff/fe-libs/ui";
6
+ import { parseCsv as s, titleCase as c } from "../../utils/formatters.js";
7
+ import { TagList as l } from "../../components/TagList.js";
8
+ import { ActorName as u } from "../../components/ActorName.js";
9
+ import { SelectField as d, TextAreaField as f, TextField as p } from "../../components/Field.js";
10
+ import { FollowButton as m } from "../../components/FollowButton.js";
11
+ import { useEffect as h, useState as g } from "react";
12
+ import { Loader2 as _, Pencil as v, Save as y, UserCircle as b, Users as x, X as S } from "lucide-react";
13
+ import { jsx as C, jsxs as w } from "react/jsx-runtime";
14
+ import { GlassCard as T } from "@burdenoff/fe-libs/ui";
13
15
  //#region src/coolandlovely/pages/profile/StyleProfilePage.tsx
14
- var S = [
16
+ var E = [
15
17
  "PUBLIC",
16
18
  "FOLLOWERS",
17
19
  "PRIVATE"
18
- ], C = {
20
+ ], D = {
19
21
  displayName: "",
20
22
  bio: "",
21
23
  visibility: "PRIVATE",
@@ -23,194 +25,260 @@ var S = [
23
25
  palette: "",
24
26
  favouriteBrands: ""
25
27
  };
26
- function w() {
27
- let w = i(), T = a(), [E, D] = p(!1), [O, k] = p(C), A = w.data, j = !!A;
28
- f(() => {
29
- A && k({
30
- displayName: A.displayName ?? "",
31
- bio: A.bio ?? "",
32
- visibility: A.visibility,
33
- stylePreferences: A.stylePreferences.join(", "),
34
- palette: A.palette.join(", "),
35
- favouriteBrands: A.favouriteBrands.join(", ")
28
+ function O() {
29
+ let O = a(), k = o(), A = i(), [j, M] = g(!1), [N, P] = g(D), F = O.data, I = !!F, L = A.data ?? [];
30
+ h(() => {
31
+ F && P({
32
+ displayName: F.displayName ?? "",
33
+ bio: F.bio ?? "",
34
+ visibility: F.visibility,
35
+ stylePreferences: F.stylePreferences.join(", "),
36
+ palette: F.palette.join(", "),
37
+ favouriteBrands: F.favouriteBrands.join(", ")
36
38
  });
37
- }, [A]), f(() => {
38
- !w.isLoading && !j && D(!0);
39
- }, [w.isLoading, j]);
40
- let M = (e, t) => k((n) => ({
39
+ }, [F]), h(() => {
40
+ !O.isLoading && !I && M(!0);
41
+ }, [O.isLoading, I]);
42
+ let R = (e, t) => P((n) => ({
41
43
  ...n,
42
44
  [e]: t
43
- })), N = S.map((e) => ({
45
+ })), z = E.map((e) => ({
44
46
  value: e,
45
- label: s(e)
47
+ label: c(e)
46
48
  }));
47
- return w.isLoading ? /* @__PURE__ */ y(e, {
49
+ return O.isLoading ? /* @__PURE__ */ C(e, {
48
50
  title: "Style Profile",
49
- children: /* @__PURE__ */ y(r, { label: "Loading your style profile…" })
50
- }) : w.isError ? /* @__PURE__ */ y(e, {
51
+ children: /* @__PURE__ */ C(r, { label: "Loading your style profile…" })
52
+ }) : O.isError ? /* @__PURE__ */ C(e, {
51
53
  title: "Style Profile",
52
- children: /* @__PURE__ */ y(n, { onRetry: () => void w.refetch() })
53
- }) : !E && A ? /* @__PURE__ */ y(e, {
54
+ children: /* @__PURE__ */ C(n, { onRetry: () => void O.refetch() })
55
+ }) : !j && F ? /* @__PURE__ */ C(e, {
54
56
  title: "Style Profile",
55
57
  description: "Your taste, palette and sizing — the spine of personalised discovery",
56
- actions: /* @__PURE__ */ b("button", {
58
+ actions: /* @__PURE__ */ w("button", {
57
59
  type: "button",
58
- onClick: () => D(!0),
60
+ onClick: () => M(!0),
59
61
  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",
60
- children: [/* @__PURE__ */ y(h, { className: "h-4 w-4" }), " Edit"]
62
+ children: [/* @__PURE__ */ C(v, { className: "h-4 w-4" }), " Edit"]
61
63
  }),
62
- children: /* @__PURE__ */ y("div", {
64
+ children: /* @__PURE__ */ w("div", {
63
65
  className: "mx-auto max-w-2xl",
64
- children: /* @__PURE__ */ b(x, {
66
+ children: [/* @__PURE__ */ w(T, {
65
67
  treatment: "glass",
66
68
  className: "p-6",
67
69
  children: [
68
- /* @__PURE__ */ b("div", {
70
+ /* @__PURE__ */ w("div", {
69
71
  className: "flex items-center gap-4",
70
- children: [/* @__PURE__ */ y("div", {
72
+ children: [/* @__PURE__ */ C("div", {
71
73
  className: "flex h-14 w-14 items-center justify-center rounded-full bg-accent-purple-subtle text-text-primary",
72
- children: /* @__PURE__ */ y(_, { className: "h-7 w-7" })
73
- }), /* @__PURE__ */ b("div", {
74
+ children: /* @__PURE__ */ C(b, { className: "h-7 w-7" })
75
+ }), /* @__PURE__ */ w("div", {
74
76
  className: "min-w-0 flex-1",
75
- children: [/* @__PURE__ */ y("h2", {
77
+ children: [/* @__PURE__ */ C("h2", {
76
78
  className: "truncate text-xl font-semibold text-text-primary",
77
- children: A.displayName || "Your style profile"
78
- }), /* @__PURE__ */ y(t, {
79
- status: A.visibility,
79
+ children: F.displayName || "Your style profile"
80
+ }), /* @__PURE__ */ C(t, {
81
+ status: F.visibility,
80
82
  className: "mt-1"
81
83
  })]
82
84
  })]
83
85
  }),
84
- A.bio && /* @__PURE__ */ y("p", {
86
+ F.bio && /* @__PURE__ */ C("p", {
85
87
  className: "mt-4 text-sm text-text-secondary",
86
- children: A.bio
88
+ children: F.bio
87
89
  }),
88
- /* @__PURE__ */ b("div", {
90
+ /* @__PURE__ */ w("div", {
91
+ className: "mt-4 flex items-center gap-6",
92
+ children: [/* @__PURE__ */ w("span", {
93
+ className: "text-sm text-text-secondary",
94
+ children: [
95
+ /* @__PURE__ */ C("span", {
96
+ className: "font-semibold text-text-primary tabular-nums",
97
+ children: F.followerCount ?? 0
98
+ }),
99
+ " ",
100
+ F.followerCount === 1 ? "follower" : "followers"
101
+ ]
102
+ }), /* @__PURE__ */ w("span", {
103
+ className: "text-sm text-text-secondary",
104
+ children: [
105
+ /* @__PURE__ */ C("span", {
106
+ className: "font-semibold text-text-primary tabular-nums",
107
+ children: F.followingCount ?? 0
108
+ }),
109
+ " ",
110
+ "following"
111
+ ]
112
+ })]
113
+ }),
114
+ /* @__PURE__ */ w("div", {
89
115
  className: "mt-6 space-y-4",
90
116
  children: [
91
- /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
117
+ /* @__PURE__ */ w("div", { children: [/* @__PURE__ */ C("p", {
92
118
  className: "mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary",
93
119
  children: "Style preferences"
94
- }), A.stylePreferences.length ? /* @__PURE__ */ y(c, {
95
- tags: A.stylePreferences,
120
+ }), F.stylePreferences.length ? /* @__PURE__ */ C(l, {
121
+ tags: F.stylePreferences,
96
122
  tone: "accent",
97
123
  max: 20
98
- }) : /* @__PURE__ */ y("p", {
124
+ }) : /* @__PURE__ */ C("p", {
99
125
  className: "text-sm text-text-secondary",
100
126
  children: "—"
101
127
  })] }),
102
- /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
128
+ /* @__PURE__ */ w("div", { children: [/* @__PURE__ */ C("p", {
103
129
  className: "mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary",
104
130
  children: "Palette"
105
- }), A.palette.length ? /* @__PURE__ */ y(c, {
106
- tags: A.palette,
131
+ }), F.palette.length ? /* @__PURE__ */ C(l, {
132
+ tags: F.palette,
107
133
  max: 20
108
- }) : /* @__PURE__ */ y("p", {
134
+ }) : /* @__PURE__ */ C("p", {
109
135
  className: "text-sm text-text-secondary",
110
136
  children: "—"
111
137
  })] }),
112
- /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
138
+ /* @__PURE__ */ w("div", { children: [/* @__PURE__ */ C("p", {
113
139
  className: "mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary",
114
140
  children: "Favourite brands"
115
- }), A.favouriteBrands.length ? /* @__PURE__ */ y(c, {
116
- tags: A.favouriteBrands,
141
+ }), F.favouriteBrands.length ? /* @__PURE__ */ C(l, {
142
+ tags: F.favouriteBrands,
117
143
  max: 20
118
- }) : /* @__PURE__ */ y("p", {
144
+ }) : /* @__PURE__ */ C("p", {
119
145
  className: "text-sm text-text-secondary",
120
146
  children: "—"
121
147
  })] })
122
148
  ]
123
149
  })
124
150
  ]
125
- })
151
+ }), /* @__PURE__ */ w("section", {
152
+ className: "mt-6",
153
+ children: [/* @__PURE__ */ w("h3", {
154
+ className: "mb-3 flex items-center gap-2 text-lg font-semibold text-text-primary",
155
+ children: [
156
+ /* @__PURE__ */ C(x, { className: "h-5 w-5" }),
157
+ " People you follow (",
158
+ L.length,
159
+ ")"
160
+ ]
161
+ }), A.isLoading ? /* @__PURE__ */ w("div", {
162
+ className: "flex items-center gap-2 rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary",
163
+ children: [/* @__PURE__ */ C(_, { className: "h-4 w-4 animate-spin" }), " Loading…"]
164
+ }) : L.length === 0 ? /* @__PURE__ */ C("p", {
165
+ className: "rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary",
166
+ children: "You are not following anyone yet. Follow creators from their looks to see their latest in Discover."
167
+ }) : /* @__PURE__ */ C("ul", {
168
+ className: "divide-y divide-border-seam rounded-lg border border-border-seam bg-bg-surface",
169
+ children: L.map((e) => /* @__PURE__ */ w("li", {
170
+ className: "flex items-center gap-3 px-4 py-3",
171
+ children: [
172
+ /* @__PURE__ */ C("div", {
173
+ className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-accent-purple-subtle text-text-primary",
174
+ children: /* @__PURE__ */ C(b, { className: "h-5 w-5" })
175
+ }),
176
+ /* @__PURE__ */ w("div", {
177
+ className: "min-w-0 flex-1",
178
+ children: [/* @__PURE__ */ C("p", {
179
+ className: "truncate text-sm font-medium text-text-primary",
180
+ children: e.displayName || /* @__PURE__ */ C(u, { id: e.ownerId })
181
+ }), e.bio && /* @__PURE__ */ C("p", {
182
+ className: "truncate text-xs text-text-secondary",
183
+ children: e.bio
184
+ })]
185
+ }),
186
+ /* @__PURE__ */ C(m, {
187
+ followeeId: e.ownerId,
188
+ size: "sm"
189
+ })
190
+ ]
191
+ }, e.id))
192
+ })]
193
+ })]
126
194
  })
127
- }) : /* @__PURE__ */ y(e, {
128
- title: j ? "Edit style profile" : "Create your style profile",
195
+ }) : /* @__PURE__ */ C(e, {
196
+ title: I ? "Edit style profile" : "Create your style profile",
129
197
  description: "This powers your personalised discovery feed",
130
- actions: j ? /* @__PURE__ */ b("button", {
198
+ actions: I ? /* @__PURE__ */ w("button", {
131
199
  type: "button",
132
- onClick: () => D(!1),
200
+ onClick: () => M(!1),
133
201
  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",
134
- children: [/* @__PURE__ */ y(v, { className: "h-4 w-4" }), " Cancel"]
202
+ children: [/* @__PURE__ */ C(S, { className: "h-4 w-4" }), " Cancel"]
135
203
  }) : void 0,
136
- children: /* @__PURE__ */ y("form", {
204
+ children: /* @__PURE__ */ C("form", {
137
205
  onSubmit: (e) => {
138
- e.preventDefault(), T.mutate({
139
- displayName: O.displayName.trim() || void 0,
140
- bio: O.bio.trim() || void 0,
141
- visibility: O.visibility,
142
- stylePreferences: o(O.stylePreferences),
143
- palette: o(O.palette),
144
- favouriteBrands: o(O.favouriteBrands)
145
- }, { onSuccess: () => D(!1) });
206
+ e.preventDefault(), k.mutate({
207
+ displayName: N.displayName.trim() || void 0,
208
+ bio: N.bio.trim() || void 0,
209
+ visibility: N.visibility,
210
+ stylePreferences: s(N.stylePreferences),
211
+ palette: s(N.palette),
212
+ favouriteBrands: s(N.favouriteBrands)
213
+ }, { onSuccess: () => M(!1) });
146
214
  },
147
215
  className: "mx-auto max-w-2xl",
148
- children: /* @__PURE__ */ b(x, {
216
+ children: /* @__PURE__ */ w(T, {
149
217
  treatment: "plain",
150
218
  className: "p-6",
151
219
  children: [
152
- /* @__PURE__ */ y(d, {
220
+ /* @__PURE__ */ C(p, {
153
221
  id: "displayName",
154
222
  label: "Display name",
155
- value: O.displayName,
156
- onChange: (e) => M("displayName", e),
223
+ value: N.displayName,
224
+ onChange: (e) => R("displayName", e),
157
225
  placeholder: "How you want to appear"
158
226
  }),
159
- /* @__PURE__ */ y(u, {
227
+ /* @__PURE__ */ C(f, {
160
228
  id: "bio",
161
229
  label: "Bio",
162
- value: O.bio,
163
- onChange: (e) => M("bio", e),
230
+ value: N.bio,
231
+ onChange: (e) => R("bio", e),
164
232
  placeholder: "A sentence about your style…",
165
233
  rows: 3,
166
234
  className: "mt-4"
167
235
  }),
168
- /* @__PURE__ */ y(l, {
236
+ /* @__PURE__ */ C(d, {
169
237
  id: "visibility",
170
238
  label: "Visibility",
171
- value: O.visibility,
172
- onChange: (e) => M("visibility", e),
173
- options: N,
239
+ value: N.visibility,
240
+ onChange: (e) => R("visibility", e),
241
+ options: z,
174
242
  className: "mt-4"
175
243
  }),
176
- /* @__PURE__ */ y(d, {
244
+ /* @__PURE__ */ C(p, {
177
245
  id: "stylePreferences",
178
246
  label: "Style preferences",
179
- value: O.stylePreferences,
180
- onChange: (e) => M("stylePreferences", e),
247
+ value: N.stylePreferences,
248
+ onChange: (e) => R("stylePreferences", e),
181
249
  placeholder: "minimal, tailored, vintage",
182
250
  hint: "Comma-separated",
183
251
  className: "mt-4"
184
252
  }),
185
- /* @__PURE__ */ y(d, {
253
+ /* @__PURE__ */ C(p, {
186
254
  id: "palette",
187
255
  label: "Palette",
188
- value: O.palette,
189
- onChange: (e) => M("palette", e),
256
+ value: N.palette,
257
+ onChange: (e) => R("palette", e),
190
258
  placeholder: "neutrals, navy, rust",
191
259
  hint: "Comma-separated",
192
260
  className: "mt-4"
193
261
  }),
194
- /* @__PURE__ */ y(d, {
262
+ /* @__PURE__ */ C(p, {
195
263
  id: "favouriteBrands",
196
264
  label: "Favourite brands",
197
- value: O.favouriteBrands,
198
- onChange: (e) => M("favouriteBrands", e),
265
+ value: N.favouriteBrands,
266
+ onChange: (e) => R("favouriteBrands", e),
199
267
  placeholder: "Aurora Atelier, …",
200
268
  hint: "Comma-separated",
201
269
  className: "mt-4"
202
270
  }),
203
- T.isError && /* @__PURE__ */ y("p", {
271
+ k.isError && /* @__PURE__ */ C("p", {
204
272
  className: "mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
205
- children: T.error instanceof Error ? T.error.message : "Something went wrong"
273
+ children: k.error instanceof Error ? k.error.message : "Something went wrong"
206
274
  }),
207
- /* @__PURE__ */ y("div", {
275
+ /* @__PURE__ */ C("div", {
208
276
  className: "mt-6 flex justify-end gap-2",
209
- children: /* @__PURE__ */ b("button", {
277
+ children: /* @__PURE__ */ w("button", {
210
278
  type: "submit",
211
- disabled: T.isPending,
279
+ disabled: k.isPending,
212
280
  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",
213
- children: [T.isPending ? /* @__PURE__ */ y(m, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ y(g, { className: "h-4 w-4" }), j ? "Save changes" : "Create profile"]
281
+ children: [k.isPending ? /* @__PURE__ */ C(_, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ C(y, { className: "h-4 w-4" }), I ? "Save changes" : "Create profile"]
214
282
  })
215
283
  })
216
284
  ]
@@ -219,6 +287,6 @@ function w() {
219
287
  });
220
288
  }
221
289
  //#endregion
222
- export { w as StyleProfilePage };
290
+ export { O as StyleProfilePage };
223
291
 
224
292
  //# sourceMappingURL=StyleProfilePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"StyleProfilePage.js","names":[],"sources":["../../../../src/coolandlovely/pages/profile/StyleProfilePage.tsx"],"sourcesContent":["/**\n * Style Profile Page (self-scoped)\n * @module coolandlovely/pages/profile\n *\n * Views and edits the calling shopper's style profile (`cooMyStyleProfile` +\n * `cooUpsertStyleProfile`). One profile per workspace per shopper.\n */\n\nimport { useEffect, useState } from 'react';\nimport { Loader2, Save, UserCircle, Pencil, X } 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 { TagList } from '../../components/TagList';\nimport { TextField, TextAreaField, SelectField } from '../../components/Field';\nimport { useMyStyleProfile, useUpsertStyleProfile } from '../../hooks';\nimport { parseCsv, titleCase } from '../../utils/formatters';\nimport type { CooVisibility } from '../../types';\n\nconst VISIBILITIES: CooVisibility[] = ['PUBLIC', 'FOLLOWERS', 'PRIVATE'];\n\ninterface FormState {\n displayName: string;\n bio: string;\n visibility: CooVisibility;\n stylePreferences: string;\n palette: string;\n favouriteBrands: string;\n}\n\nconst EMPTY: FormState = {\n displayName: '',\n bio: '',\n visibility: 'PRIVATE',\n stylePreferences: '',\n palette: '',\n favouriteBrands: '',\n};\n\nexport function StyleProfilePage() {\n const query = useMyStyleProfile();\n const upsert = useUpsertStyleProfile();\n\n const [editing, setEditing] = useState(false);\n const [form, setForm] = useState<FormState>(EMPTY);\n\n const profile = query.data;\n const hasProfile = Boolean(profile);\n\n useEffect(() => {\n if (profile) {\n setForm({\n displayName: profile.displayName ?? '',\n bio: profile.bio ?? '',\n visibility: profile.visibility,\n stylePreferences: profile.stylePreferences.join(', '),\n palette: profile.palette.join(', '),\n favouriteBrands: profile.favouriteBrands.join(', '),\n });\n }\n }, [profile]);\n\n // If there is no profile yet, drop straight into edit mode.\n useEffect(() => {\n if (!query.isLoading && !hasProfile) {\n setEditing(true);\n }\n }, [query.isLoading, hasProfile]);\n\n const setField = <K extends keyof FormState>(key: K, value: FormState[K]) =>\n setForm((f) => ({ ...f, [key]: value }));\n\n const visibilityOptions = VISIBILITIES.map((v) => ({ value: v, label: titleCase(v) }));\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n upsert.mutate(\n {\n displayName: form.displayName.trim() || undefined,\n bio: form.bio.trim() || undefined,\n visibility: form.visibility,\n stylePreferences: parseCsv(form.stylePreferences),\n palette: parseCsv(form.palette),\n favouriteBrands: parseCsv(form.favouriteBrands),\n },\n { onSuccess: () => setEditing(false) }\n );\n };\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Style Profile\">\n <LoadingView label=\"Loading your style profile…\" />\n </PageLayout>\n );\n }\n\n if (query.isError) {\n return (\n <PageLayout title=\"Style Profile\">\n <ErrorView onRetry={() => void query.refetch()} />\n </PageLayout>\n );\n }\n\n // ----- View mode -----\n if (!editing && profile) {\n return (\n <PageLayout\n title=\"Style Profile\"\n description=\"Your taste, palette and sizing — the spine of personalised discovery\"\n actions={\n <button\n type=\"button\"\n onClick={() => setEditing(true)}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n <Pencil className=\"h-4 w-4\" /> Edit\n </button>\n }\n >\n <div className=\"mx-auto max-w-2xl\">\n <GlassCard treatment=\"glass\" className=\"p-6\">\n <div className=\"flex items-center gap-4\">\n <div className=\"flex h-14 w-14 items-center justify-center rounded-full bg-accent-purple-subtle text-text-primary\">\n <UserCircle className=\"h-7 w-7\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <h2 className=\"truncate text-xl font-semibold text-text-primary\">\n {profile.displayName || 'Your style profile'}\n </h2>\n <StatusBadge status={profile.visibility} className=\"mt-1\" />\n </div>\n </div>\n {profile.bio && <p className=\"mt-4 text-sm text-text-secondary\">{profile.bio}</p>}\n\n <div className=\"mt-6 space-y-4\">\n <div>\n <p className=\"mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Style preferences\n </p>\n {profile.stylePreferences.length ? (\n <TagList tags={profile.stylePreferences} tone=\"accent\" max={20} />\n ) : (\n <p className=\"text-sm text-text-secondary\">—</p>\n )}\n </div>\n <div>\n <p className=\"mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Palette\n </p>\n {profile.palette.length ? (\n <TagList tags={profile.palette} max={20} />\n ) : (\n <p className=\"text-sm text-text-secondary\">—</p>\n )}\n </div>\n <div>\n <p className=\"mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Favourite brands\n </p>\n {profile.favouriteBrands.length ? (\n <TagList tags={profile.favouriteBrands} max={20} />\n ) : (\n <p className=\"text-sm text-text-secondary\">—</p>\n )}\n </div>\n </div>\n </GlassCard>\n </div>\n </PageLayout>\n );\n }\n\n // ----- Edit / create mode -----\n return (\n <PageLayout\n title={hasProfile ? 'Edit style profile' : 'Create your style profile'}\n description=\"This powers your personalised discovery feed\"\n actions={\n hasProfile ? (\n <button\n type=\"button\"\n onClick={() => setEditing(false)}\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 <X className=\"h-4 w-4\" /> Cancel\n </button>\n ) : undefined\n }\n >\n <form onSubmit={handleSubmit} className=\"mx-auto max-w-2xl\">\n <GlassCard treatment=\"plain\" className=\"p-6\">\n <TextField\n id=\"displayName\"\n label=\"Display name\"\n value={form.displayName}\n onChange={(v) => setField('displayName', v)}\n placeholder=\"How you want to appear\"\n />\n <TextAreaField\n id=\"bio\"\n label=\"Bio\"\n value={form.bio}\n onChange={(v) => setField('bio', v)}\n placeholder=\"A sentence about your style…\"\n rows={3}\n className=\"mt-4\"\n />\n <SelectField\n id=\"visibility\"\n label=\"Visibility\"\n value={form.visibility}\n onChange={(v) => setField('visibility', v as CooVisibility)}\n options={visibilityOptions}\n className=\"mt-4\"\n />\n <TextField\n id=\"stylePreferences\"\n label=\"Style preferences\"\n value={form.stylePreferences}\n onChange={(v) => setField('stylePreferences', v)}\n placeholder=\"minimal, tailored, vintage\"\n hint=\"Comma-separated\"\n className=\"mt-4\"\n />\n <TextField\n id=\"palette\"\n label=\"Palette\"\n value={form.palette}\n onChange={(v) => setField('palette', v)}\n placeholder=\"neutrals, navy, rust\"\n hint=\"Comma-separated\"\n className=\"mt-4\"\n />\n <TextField\n id=\"favouriteBrands\"\n label=\"Favourite brands\"\n value={form.favouriteBrands}\n onChange={(v) => setField('favouriteBrands', v)}\n placeholder=\"Aurora Atelier, …\"\n hint=\"Comma-separated\"\n className=\"mt-4\"\n />\n\n {upsert.isError && (\n <p className=\"mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {upsert.error instanceof Error ? upsert.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={upsert.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 {upsert.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Save className=\"h-4 w-4\" />\n )}\n {hasProfile ? 'Save changes' : 'Create profile'}\n </button>\n </div>\n </GlassCard>\n </form>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"StyleProfilePage.js","names":[],"sources":["../../../../src/coolandlovely/pages/profile/StyleProfilePage.tsx"],"sourcesContent":["/**\n * Style Profile Page (self-scoped)\n * @module coolandlovely/pages/profile\n *\n * Views and edits the calling shopper's style profile (`cooMyStyleProfile` +\n * `cooUpsertStyleProfile`). One profile per workspace per shopper.\n */\n\nimport { useEffect, useState } from 'react';\nimport { Loader2, Save, UserCircle, Pencil, X, Users } 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 { TagList } from '../../components/TagList';\nimport { TextField, TextAreaField, SelectField } from '../../components/Field';\nimport { ActorName } from '../../components/ActorName';\nimport { FollowButton } from '../../components/FollowButton';\nimport { useMyStyleProfile, useUpsertStyleProfile, useMyFollowing } from '../../hooks';\nimport { parseCsv, titleCase } from '../../utils/formatters';\nimport type { CooVisibility } from '../../types';\n\nconst VISIBILITIES: CooVisibility[] = ['PUBLIC', 'FOLLOWERS', 'PRIVATE'];\n\ninterface FormState {\n displayName: string;\n bio: string;\n visibility: CooVisibility;\n stylePreferences: string;\n palette: string;\n favouriteBrands: string;\n}\n\nconst EMPTY: FormState = {\n displayName: '',\n bio: '',\n visibility: 'PRIVATE',\n stylePreferences: '',\n palette: '',\n favouriteBrands: '',\n};\n\nexport function StyleProfilePage() {\n const query = useMyStyleProfile();\n const upsert = useUpsertStyleProfile();\n const following = useMyFollowing();\n\n const [editing, setEditing] = useState(false);\n const [form, setForm] = useState<FormState>(EMPTY);\n\n const profile = query.data;\n const hasProfile = Boolean(profile);\n const followingList = following.data ?? [];\n\n useEffect(() => {\n if (profile) {\n setForm({\n displayName: profile.displayName ?? '',\n bio: profile.bio ?? '',\n visibility: profile.visibility,\n stylePreferences: profile.stylePreferences.join(', '),\n palette: profile.palette.join(', '),\n favouriteBrands: profile.favouriteBrands.join(', '),\n });\n }\n }, [profile]);\n\n // If there is no profile yet, drop straight into edit mode.\n useEffect(() => {\n if (!query.isLoading && !hasProfile) {\n setEditing(true);\n }\n }, [query.isLoading, hasProfile]);\n\n const setField = <K extends keyof FormState>(key: K, value: FormState[K]) =>\n setForm((f) => ({ ...f, [key]: value }));\n\n const visibilityOptions = VISIBILITIES.map((v) => ({ value: v, label: titleCase(v) }));\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n upsert.mutate(\n {\n displayName: form.displayName.trim() || undefined,\n bio: form.bio.trim() || undefined,\n visibility: form.visibility,\n stylePreferences: parseCsv(form.stylePreferences),\n palette: parseCsv(form.palette),\n favouriteBrands: parseCsv(form.favouriteBrands),\n },\n { onSuccess: () => setEditing(false) }\n );\n };\n\n if (query.isLoading) {\n return (\n <PageLayout title=\"Style Profile\">\n <LoadingView label=\"Loading your style profile…\" />\n </PageLayout>\n );\n }\n\n if (query.isError) {\n return (\n <PageLayout title=\"Style Profile\">\n <ErrorView onRetry={() => void query.refetch()} />\n </PageLayout>\n );\n }\n\n // ----- View mode -----\n if (!editing && profile) {\n return (\n <PageLayout\n title=\"Style Profile\"\n description=\"Your taste, palette and sizing — the spine of personalised discovery\"\n actions={\n <button\n type=\"button\"\n onClick={() => setEditing(true)}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n <Pencil className=\"h-4 w-4\" /> Edit\n </button>\n }\n >\n <div className=\"mx-auto max-w-2xl\">\n <GlassCard treatment=\"glass\" className=\"p-6\">\n <div className=\"flex items-center gap-4\">\n <div className=\"flex h-14 w-14 items-center justify-center rounded-full bg-accent-purple-subtle text-text-primary\">\n <UserCircle className=\"h-7 w-7\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <h2 className=\"truncate text-xl font-semibold text-text-primary\">\n {profile.displayName || 'Your style profile'}\n </h2>\n <StatusBadge status={profile.visibility} className=\"mt-1\" />\n </div>\n </div>\n {profile.bio && <p className=\"mt-4 text-sm text-text-secondary\">{profile.bio}</p>}\n\n <div className=\"mt-4 flex items-center gap-6\">\n <span className=\"text-sm text-text-secondary\">\n <span className=\"font-semibold text-text-primary tabular-nums\">\n {profile.followerCount ?? 0}\n </span>{' '}\n {profile.followerCount === 1 ? 'follower' : 'followers'}\n </span>\n <span className=\"text-sm text-text-secondary\">\n <span className=\"font-semibold text-text-primary tabular-nums\">\n {profile.followingCount ?? 0}\n </span>{' '}\n following\n </span>\n </div>\n\n <div className=\"mt-6 space-y-4\">\n <div>\n <p className=\"mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Style preferences\n </p>\n {profile.stylePreferences.length ? (\n <TagList tags={profile.stylePreferences} tone=\"accent\" max={20} />\n ) : (\n <p className=\"text-sm text-text-secondary\">—</p>\n )}\n </div>\n <div>\n <p className=\"mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Palette\n </p>\n {profile.palette.length ? (\n <TagList tags={profile.palette} max={20} />\n ) : (\n <p className=\"text-sm text-text-secondary\">—</p>\n )}\n </div>\n <div>\n <p className=\"mb-1.5 text-xs font-medium uppercase tracking-wide text-text-secondary\">\n Favourite brands\n </p>\n {profile.favouriteBrands.length ? (\n <TagList tags={profile.favouriteBrands} max={20} />\n ) : (\n <p className=\"text-sm text-text-secondary\">—</p>\n )}\n </div>\n </div>\n </GlassCard>\n\n <section className=\"mt-6\">\n <h3 className=\"mb-3 flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Users className=\"h-5 w-5\" /> People you follow ({followingList.length})\n </h3>\n {following.isLoading ? (\n <div className=\"flex items-center gap-2 rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n <Loader2 className=\"h-4 w-4 animate-spin\" /> Loading…\n </div>\n ) : followingList.length === 0 ? (\n <p className=\"rounded-lg border border-border-seam bg-bg-surface p-4 text-sm text-text-secondary\">\n You are not following anyone yet. Follow creators from their looks to see their\n latest in Discover.\n </p>\n ) : (\n <ul className=\"divide-y divide-border-seam rounded-lg border border-border-seam bg-bg-surface\">\n {followingList.map((p) => (\n <li key={p.id} className=\"flex items-center gap-3 px-4 py-3\">\n <div className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-accent-purple-subtle text-text-primary\">\n <UserCircle className=\"h-5 w-5\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {p.displayName || <ActorName id={p.ownerId} />}\n </p>\n {p.bio && <p className=\"truncate text-xs text-text-secondary\">{p.bio}</p>}\n </div>\n <FollowButton followeeId={p.ownerId} size=\"sm\" />\n </li>\n ))}\n </ul>\n )}\n </section>\n </div>\n </PageLayout>\n );\n }\n\n // ----- Edit / create mode -----\n return (\n <PageLayout\n title={hasProfile ? 'Edit style profile' : 'Create your style profile'}\n description=\"This powers your personalised discovery feed\"\n actions={\n hasProfile ? (\n <button\n type=\"button\"\n onClick={() => setEditing(false)}\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 <X className=\"h-4 w-4\" /> Cancel\n </button>\n ) : undefined\n }\n >\n <form onSubmit={handleSubmit} className=\"mx-auto max-w-2xl\">\n <GlassCard treatment=\"plain\" className=\"p-6\">\n <TextField\n id=\"displayName\"\n label=\"Display name\"\n value={form.displayName}\n onChange={(v) => setField('displayName', v)}\n placeholder=\"How you want to appear\"\n />\n <TextAreaField\n id=\"bio\"\n label=\"Bio\"\n value={form.bio}\n onChange={(v) => setField('bio', v)}\n placeholder=\"A sentence about your style…\"\n rows={3}\n className=\"mt-4\"\n />\n <SelectField\n id=\"visibility\"\n label=\"Visibility\"\n value={form.visibility}\n onChange={(v) => setField('visibility', v as CooVisibility)}\n options={visibilityOptions}\n className=\"mt-4\"\n />\n <TextField\n id=\"stylePreferences\"\n label=\"Style preferences\"\n value={form.stylePreferences}\n onChange={(v) => setField('stylePreferences', v)}\n placeholder=\"minimal, tailored, vintage\"\n hint=\"Comma-separated\"\n className=\"mt-4\"\n />\n <TextField\n id=\"palette\"\n label=\"Palette\"\n value={form.palette}\n onChange={(v) => setField('palette', v)}\n placeholder=\"neutrals, navy, rust\"\n hint=\"Comma-separated\"\n className=\"mt-4\"\n />\n <TextField\n id=\"favouriteBrands\"\n label=\"Favourite brands\"\n value={form.favouriteBrands}\n onChange={(v) => setField('favouriteBrands', v)}\n placeholder=\"Aurora Atelier, …\"\n hint=\"Comma-separated\"\n className=\"mt-4\"\n />\n\n {upsert.isError && (\n <p className=\"mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {upsert.error instanceof Error ? upsert.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={upsert.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 {upsert.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Save className=\"h-4 w-4\" />\n )}\n {hasProfile ? 'Save changes' : 'Create profile'}\n </button>\n </div>\n </GlassCard>\n </form>\n </PageLayout>\n );\n}\n"],"mappings":"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"}