@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.
- package/dist/coolandlovely/CoolAndLovelyRoutes.js +14 -6
- package/dist/coolandlovely/CoolAndLovelyRoutes.js.map +1 -1
- package/dist/coolandlovely/components/ActorName.js +29 -0
- package/dist/coolandlovely/components/ActorName.js.map +1 -0
- package/dist/coolandlovely/components/AddToLookbookButton.js +81 -0
- package/dist/coolandlovely/components/AddToLookbookButton.js.map +1 -0
- package/dist/coolandlovely/components/Comments.js +109 -0
- package/dist/coolandlovely/components/Comments.js.map +1 -0
- package/dist/coolandlovely/components/Field.js +22 -2
- package/dist/coolandlovely/components/Field.js.map +1 -1
- package/dist/coolandlovely/components/FileImage.js +17 -0
- package/dist/coolandlovely/components/FileImage.js.map +1 -0
- package/dist/coolandlovely/components/FollowButton.js +24 -0
- package/dist/coolandlovely/components/FollowButton.js.map +1 -0
- package/dist/coolandlovely/components/ImageUploadField.js +71 -0
- package/dist/coolandlovely/components/ImageUploadField.js.map +1 -0
- package/dist/coolandlovely/components/Thumbnail.js +20 -13
- package/dist/coolandlovely/components/Thumbnail.js.map +1 -1
- package/dist/coolandlovely/hooks/index.js +2 -0
- package/dist/coolandlovely/hooks/useComments.js +68 -0
- package/dist/coolandlovely/hooks/useComments.js.map +1 -0
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js +74 -4
- package/dist/coolandlovely/hooks/useCoolAndLovelyApi.js.map +1 -1
- package/dist/coolandlovely/hooks/useFiles.js +94 -0
- package/dist/coolandlovely/hooks/useFiles.js.map +1 -0
- package/dist/coolandlovely/pages/HomePage.js +105 -87
- package/dist/coolandlovely/pages/HomePage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js +144 -122
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandFormPage.js +128 -90
- package/dist/coolandlovely/pages/brands/BrandFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandsListPage.js +2 -0
- package/dist/coolandlovely/pages/brands/BrandsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionDetailPage.js +5 -1
- package/dist/coolandlovely/pages/collections/CollectionDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionFormPage.js +117 -102
- package/dist/coolandlovely/pages/collections/CollectionFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionsListPage.js +2 -0
- package/dist/coolandlovely/pages/collections/CollectionsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/discover/DiscoverPage.js +223 -0
- package/dist/coolandlovely/pages/discover/DiscoverPage.js.map +1 -0
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.js +99 -95
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemFormPage.js +144 -130
- package/dist/coolandlovely/pages/items/StyleItemFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemsListPage.js +2 -0
- package/dist/coolandlovely/pages/items/StyleItemsListPage.js.map +1 -1
- package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js +190 -99
- package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js +81 -68
- package/dist/coolandlovely/pages/lookbooks/LookbooksListPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LookDetailPage.js +195 -155
- package/dist/coolandlovely/pages/looks/LookDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LookFormPage.js +127 -88
- package/dist/coolandlovely/pages/looks/LookFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LooksListPage.js +2 -0
- package/dist/coolandlovely/pages/looks/LooksListPage.js.map +1 -1
- package/dist/coolandlovely/pages/profile/StyleProfilePage.js +169 -101
- package/dist/coolandlovely/pages/profile/StyleProfilePage.js.map +1 -1
- package/dist/coolandlovely/pages/trends/TrendsPage.js +249 -0
- package/dist/coolandlovely/pages/trends/TrendsPage.js.map +1 -0
- package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js +88 -76
- package/dist/coolandlovely/pages/wardrobe/WardrobeFormPage.js.map +1 -1
- package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js +2 -0
- package/dist/coolandlovely/pages/wardrobe/WardrobeListPage.js.map +1 -1
- 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 {
|
|
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
|
|
7
|
-
import { TagList as
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
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
|
|
16
|
+
var E = [
|
|
15
17
|
"PUBLIC",
|
|
16
18
|
"FOLLOWERS",
|
|
17
19
|
"PRIVATE"
|
|
18
|
-
],
|
|
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
|
|
27
|
-
let
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
displayName:
|
|
31
|
-
bio:
|
|
32
|
-
visibility:
|
|
33
|
-
stylePreferences:
|
|
34
|
-
palette:
|
|
35
|
-
favouriteBrands:
|
|
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
|
-
}, [
|
|
38
|
-
!
|
|
39
|
-
}, [
|
|
40
|
-
let
|
|
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
|
-
})),
|
|
45
|
+
})), z = E.map((e) => ({
|
|
44
46
|
value: e,
|
|
45
|
-
label:
|
|
47
|
+
label: c(e)
|
|
46
48
|
}));
|
|
47
|
-
return
|
|
49
|
+
return O.isLoading ? /* @__PURE__ */ C(e, {
|
|
48
50
|
title: "Style Profile",
|
|
49
|
-
children: /* @__PURE__ */
|
|
50
|
-
}) :
|
|
51
|
+
children: /* @__PURE__ */ C(r, { label: "Loading your style profile…" })
|
|
52
|
+
}) : O.isError ? /* @__PURE__ */ C(e, {
|
|
51
53
|
title: "Style Profile",
|
|
52
|
-
children: /* @__PURE__ */
|
|
53
|
-
}) : !
|
|
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__ */
|
|
58
|
+
actions: /* @__PURE__ */ w("button", {
|
|
57
59
|
type: "button",
|
|
58
|
-
onClick: () =>
|
|
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__ */
|
|
62
|
+
children: [/* @__PURE__ */ C(v, { className: "h-4 w-4" }), " Edit"]
|
|
61
63
|
}),
|
|
62
|
-
children: /* @__PURE__ */
|
|
64
|
+
children: /* @__PURE__ */ w("div", {
|
|
63
65
|
className: "mx-auto max-w-2xl",
|
|
64
|
-
children: /* @__PURE__ */
|
|
66
|
+
children: [/* @__PURE__ */ w(T, {
|
|
65
67
|
treatment: "glass",
|
|
66
68
|
className: "p-6",
|
|
67
69
|
children: [
|
|
68
|
-
/* @__PURE__ */
|
|
70
|
+
/* @__PURE__ */ w("div", {
|
|
69
71
|
className: "flex items-center gap-4",
|
|
70
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
73
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
77
|
+
children: [/* @__PURE__ */ C("h2", {
|
|
76
78
|
className: "truncate text-xl font-semibold text-text-primary",
|
|
77
|
-
children:
|
|
78
|
-
}), /* @__PURE__ */
|
|
79
|
-
status:
|
|
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
|
-
|
|
86
|
+
F.bio && /* @__PURE__ */ C("p", {
|
|
85
87
|
className: "mt-4 text-sm text-text-secondary",
|
|
86
|
-
children:
|
|
88
|
+
children: F.bio
|
|
87
89
|
}),
|
|
88
|
-
/* @__PURE__ */
|
|
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__ */
|
|
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
|
-
}),
|
|
95
|
-
tags:
|
|
120
|
+
}), F.stylePreferences.length ? /* @__PURE__ */ C(l, {
|
|
121
|
+
tags: F.stylePreferences,
|
|
96
122
|
tone: "accent",
|
|
97
123
|
max: 20
|
|
98
|
-
}) : /* @__PURE__ */
|
|
124
|
+
}) : /* @__PURE__ */ C("p", {
|
|
99
125
|
className: "text-sm text-text-secondary",
|
|
100
126
|
children: "—"
|
|
101
127
|
})] }),
|
|
102
|
-
/* @__PURE__ */
|
|
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
|
-
}),
|
|
106
|
-
tags:
|
|
131
|
+
}), F.palette.length ? /* @__PURE__ */ C(l, {
|
|
132
|
+
tags: F.palette,
|
|
107
133
|
max: 20
|
|
108
|
-
}) : /* @__PURE__ */
|
|
134
|
+
}) : /* @__PURE__ */ C("p", {
|
|
109
135
|
className: "text-sm text-text-secondary",
|
|
110
136
|
children: "—"
|
|
111
137
|
})] }),
|
|
112
|
-
/* @__PURE__ */
|
|
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
|
-
}),
|
|
116
|
-
tags:
|
|
141
|
+
}), F.favouriteBrands.length ? /* @__PURE__ */ C(l, {
|
|
142
|
+
tags: F.favouriteBrands,
|
|
117
143
|
max: 20
|
|
118
|
-
}) : /* @__PURE__ */
|
|
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__ */
|
|
128
|
-
title:
|
|
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:
|
|
198
|
+
actions: I ? /* @__PURE__ */ w("button", {
|
|
131
199
|
type: "button",
|
|
132
|
-
onClick: () =>
|
|
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__ */
|
|
202
|
+
children: [/* @__PURE__ */ C(S, { className: "h-4 w-4" }), " Cancel"]
|
|
135
203
|
}) : void 0,
|
|
136
|
-
children: /* @__PURE__ */
|
|
204
|
+
children: /* @__PURE__ */ C("form", {
|
|
137
205
|
onSubmit: (e) => {
|
|
138
|
-
e.preventDefault(),
|
|
139
|
-
displayName:
|
|
140
|
-
bio:
|
|
141
|
-
visibility:
|
|
142
|
-
stylePreferences:
|
|
143
|
-
palette:
|
|
144
|
-
favouriteBrands:
|
|
145
|
-
}, { onSuccess: () =>
|
|
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__ */
|
|
216
|
+
children: /* @__PURE__ */ w(T, {
|
|
149
217
|
treatment: "plain",
|
|
150
218
|
className: "p-6",
|
|
151
219
|
children: [
|
|
152
|
-
/* @__PURE__ */
|
|
220
|
+
/* @__PURE__ */ C(p, {
|
|
153
221
|
id: "displayName",
|
|
154
222
|
label: "Display name",
|
|
155
|
-
value:
|
|
156
|
-
onChange: (e) =>
|
|
223
|
+
value: N.displayName,
|
|
224
|
+
onChange: (e) => R("displayName", e),
|
|
157
225
|
placeholder: "How you want to appear"
|
|
158
226
|
}),
|
|
159
|
-
/* @__PURE__ */
|
|
227
|
+
/* @__PURE__ */ C(f, {
|
|
160
228
|
id: "bio",
|
|
161
229
|
label: "Bio",
|
|
162
|
-
value:
|
|
163
|
-
onChange: (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__ */
|
|
236
|
+
/* @__PURE__ */ C(d, {
|
|
169
237
|
id: "visibility",
|
|
170
238
|
label: "Visibility",
|
|
171
|
-
value:
|
|
172
|
-
onChange: (e) =>
|
|
173
|
-
options:
|
|
239
|
+
value: N.visibility,
|
|
240
|
+
onChange: (e) => R("visibility", e),
|
|
241
|
+
options: z,
|
|
174
242
|
className: "mt-4"
|
|
175
243
|
}),
|
|
176
|
-
/* @__PURE__ */
|
|
244
|
+
/* @__PURE__ */ C(p, {
|
|
177
245
|
id: "stylePreferences",
|
|
178
246
|
label: "Style preferences",
|
|
179
|
-
value:
|
|
180
|
-
onChange: (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__ */
|
|
253
|
+
/* @__PURE__ */ C(p, {
|
|
186
254
|
id: "palette",
|
|
187
255
|
label: "Palette",
|
|
188
|
-
value:
|
|
189
|
-
onChange: (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__ */
|
|
262
|
+
/* @__PURE__ */ C(p, {
|
|
195
263
|
id: "favouriteBrands",
|
|
196
264
|
label: "Favourite brands",
|
|
197
|
-
value:
|
|
198
|
-
onChange: (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
|
-
|
|
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:
|
|
273
|
+
children: k.error instanceof Error ? k.error.message : "Something went wrong"
|
|
206
274
|
}),
|
|
207
|
-
/* @__PURE__ */
|
|
275
|
+
/* @__PURE__ */ C("div", {
|
|
208
276
|
className: "mt-6 flex justify-end gap-2",
|
|
209
|
-
children: /* @__PURE__ */
|
|
277
|
+
children: /* @__PURE__ */ w("button", {
|
|
210
278
|
type: "submit",
|
|
211
|
-
disabled:
|
|
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: [
|
|
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 {
|
|
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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"}
|