@burdenoff/microfe-coolandlovely 2026.1024.3 → 2026.1026.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/coolandlovely/CoolAndLovelyRoutes.d.ts.map +1 -1
- package/dist/coolandlovely/CoolAndLovelyRoutes.js +20 -12
- package/dist/coolandlovely/CoolAndLovelyRoutes.js.map +1 -1
- package/dist/coolandlovely/components/FulfilmentTimeline.d.ts +7 -0
- package/dist/coolandlovely/components/FulfilmentTimeline.d.ts.map +1 -0
- package/dist/coolandlovely/components/FulfilmentTimeline.js +77 -0
- package/dist/coolandlovely/components/FulfilmentTimeline.js.map +1 -0
- package/dist/coolandlovely/components/StatusBadge.d.ts.map +1 -1
- package/dist/coolandlovely/components/StatusBadge.js +9 -1
- package/dist/coolandlovely/components/StatusBadge.js.map +1 -1
- package/dist/coolandlovely/hooks/useBrandOrdersApi.d.ts +7 -0
- package/dist/coolandlovely/hooks/useBrandOrdersApi.d.ts.map +1 -0
- package/dist/coolandlovely/hooks/useBrandOrdersApi.js +92 -0
- package/dist/coolandlovely/hooks/useBrandOrdersApi.js.map +1 -0
- package/dist/coolandlovely/hooks/useCommerceApi.d.ts +2 -0
- package/dist/coolandlovely/hooks/useCommerceApi.d.ts.map +1 -1
- package/dist/coolandlovely/hooks/useCommerceApi.js +26 -22
- package/dist/coolandlovely/hooks/useCommerceApi.js.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandDetailPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js +157 -148
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/commerce/BrandOrdersPage.d.ts +13 -0
- package/dist/coolandlovely/pages/commerce/BrandOrdersPage.d.ts.map +1 -0
- package/dist/coolandlovely/pages/commerce/BrandOrdersPage.js +360 -0
- package/dist/coolandlovely/pages/commerce/BrandOrdersPage.js.map +1 -0
- package/dist/coolandlovely/pages/commerce/CartPage.js +4 -4
- package/dist/coolandlovely/pages/commerce/OrdersPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/commerce/OrdersPage.js +122 -101
- package/dist/coolandlovely/pages/commerce/OrdersPage.js.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemFormPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemFormPage.js +130 -104
- package/dist/coolandlovely/pages/items/StyleItemFormPage.js.map +1 -1
- package/dist/coolandlovely/types/commerce.d.ts +61 -0
- package/dist/coolandlovely/types/commerce.d.ts.map +1 -1
- package/dist/coolandlovely/types/index.d.ts +2 -0
- package/dist/coolandlovely/types/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -14,7 +14,20 @@ import { useParams as w, useSearchParams as T } from "react-router";
|
|
|
14
14
|
import { jsx as E, jsxs as D } from "react/jsx-runtime";
|
|
15
15
|
import { GlassCard as O } from "@burdenoff/fe-libs/ui";
|
|
16
16
|
//#region src/coolandlovely/pages/items/StyleItemFormPage.tsx
|
|
17
|
-
var k =
|
|
17
|
+
var k = [
|
|
18
|
+
{
|
|
19
|
+
value: "DRAFT",
|
|
20
|
+
label: "Draft (not on sale)"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
value: "ACTIVE",
|
|
24
|
+
label: "On sale"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
value: "OUT_OF_STOCK",
|
|
28
|
+
label: "Out of stock"
|
|
29
|
+
}
|
|
30
|
+
], A = {
|
|
18
31
|
brandId: "",
|
|
19
32
|
collectionId: "",
|
|
20
33
|
name: "",
|
|
@@ -27,21 +40,22 @@ var k = {
|
|
|
27
40
|
sizes: "",
|
|
28
41
|
materials: "",
|
|
29
42
|
tags: "",
|
|
30
|
-
imageFileId: ""
|
|
43
|
+
imageFileId: "",
|
|
44
|
+
status: "DRAFT"
|
|
31
45
|
};
|
|
32
|
-
function
|
|
33
|
-
let { itemId:
|
|
46
|
+
function j() {
|
|
47
|
+
let { itemId: j } = w(), [M] = T(), N = !!j, { navigateTo: P } = e(), F = a(N ? j : void 0), I = n({ pagination: {
|
|
34
48
|
limit: 100,
|
|
35
49
|
offset: 0
|
|
36
|
-
} }),
|
|
37
|
-
...
|
|
38
|
-
brandId:
|
|
39
|
-
collectionId:
|
|
40
|
-
})), [
|
|
50
|
+
} }), L = i(), R = o(), [z, B] = y(() => ({
|
|
51
|
+
...A,
|
|
52
|
+
brandId: M.get("brandId") ?? "",
|
|
53
|
+
collectionId: M.get("collectionId") ?? ""
|
|
54
|
+
})), [V, H] = y({}), U = r(z.brandId ? { brandId: z.brandId } : {});
|
|
41
55
|
_(() => {
|
|
42
|
-
if (
|
|
43
|
-
let e =
|
|
44
|
-
|
|
56
|
+
if (N && F.data) {
|
|
57
|
+
let e = F.data;
|
|
58
|
+
B({
|
|
45
59
|
brandId: e.brandId,
|
|
46
60
|
collectionId: e.collectionId ?? "",
|
|
47
61
|
name: e.name,
|
|
@@ -54,79 +68,81 @@ function A() {
|
|
|
54
68
|
sizes: e.sizes.join(", "),
|
|
55
69
|
materials: e.materials.join(", "),
|
|
56
70
|
tags: e.tags.join(", "),
|
|
57
|
-
imageFileId: e.image?.id ?? ""
|
|
71
|
+
imageFileId: e.image?.id ?? "",
|
|
72
|
+
status: e.status
|
|
58
73
|
});
|
|
59
74
|
}
|
|
60
|
-
}, [
|
|
61
|
-
let
|
|
75
|
+
}, [N, F.data]);
|
|
76
|
+
let W = (e, t) => B((n) => ({
|
|
62
77
|
...n,
|
|
63
78
|
[e]: t
|
|
64
|
-
})),
|
|
79
|
+
})), G = N ? R : L, K = v(() => (I.data?.items ?? []).map((e) => ({
|
|
65
80
|
value: e.id,
|
|
66
81
|
label: e.name
|
|
67
|
-
})), [
|
|
82
|
+
})), [I.data]), q = v(() => (U.data ?? []).map((e) => ({
|
|
68
83
|
value: e.id,
|
|
69
84
|
label: e.name
|
|
70
|
-
})), [
|
|
85
|
+
})), [U.data]), J = f.map((e) => ({
|
|
71
86
|
value: e,
|
|
72
87
|
label: d(e)
|
|
73
|
-
})),
|
|
88
|
+
})), Y = () => {
|
|
74
89
|
let e = {};
|
|
75
|
-
return
|
|
90
|
+
return z.name.trim() || (e.name = "Name is required"), !N && !z.brandId && (e.brandId = "Brand is required"), z.price && Number.isNaN(Number(z.price)) && (e.price = "Price must be a number"), H(e), Object.keys(e).length === 0;
|
|
76
91
|
};
|
|
77
|
-
return
|
|
92
|
+
return N && F.isLoading ? /* @__PURE__ */ E(t, {
|
|
78
93
|
title: "Edit item",
|
|
79
94
|
children: /* @__PURE__ */ E(l, { label: "Loading item…" })
|
|
80
|
-
}) :
|
|
95
|
+
}) : N && (F.isError || !F.data) ? /* @__PURE__ */ E(t, {
|
|
81
96
|
title: "Edit item",
|
|
82
97
|
children: /* @__PURE__ */ E(c, {
|
|
83
98
|
title: "Item not found",
|
|
84
|
-
onRetry: () => void
|
|
99
|
+
onRetry: () => void F.refetch()
|
|
85
100
|
})
|
|
86
101
|
}) : /* @__PURE__ */ E(t, {
|
|
87
|
-
title:
|
|
88
|
-
description:
|
|
102
|
+
title: N ? "Edit item" : "New style item",
|
|
103
|
+
description: N ? "Update this catalogue piece" : "List a new shoppable piece",
|
|
89
104
|
actions: /* @__PURE__ */ D("button", {
|
|
90
105
|
type: "button",
|
|
91
|
-
onClick: () => N
|
|
106
|
+
onClick: () => P(N && j ? `/items/${j}` : "/items"),
|
|
92
107
|
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",
|
|
93
108
|
children: [/* @__PURE__ */ E(b, { className: "h-4 w-4" }), " Cancel"]
|
|
94
109
|
}),
|
|
95
110
|
children: /* @__PURE__ */ E("form", {
|
|
96
111
|
onSubmit: (e) => {
|
|
97
|
-
if (e.preventDefault(), !
|
|
98
|
-
let t =
|
|
99
|
-
|
|
100
|
-
id:
|
|
112
|
+
if (e.preventDefault(), !Y()) return;
|
|
113
|
+
let t = z.price.trim() ? Number(z.price) : void 0;
|
|
114
|
+
N && j ? R.mutate({
|
|
115
|
+
id: j,
|
|
101
116
|
input: {
|
|
102
|
-
name:
|
|
103
|
-
description:
|
|
104
|
-
category:
|
|
105
|
-
collectionId:
|
|
106
|
-
sku:
|
|
117
|
+
name: z.name.trim(),
|
|
118
|
+
description: z.description.trim() || void 0,
|
|
119
|
+
category: z.category,
|
|
120
|
+
collectionId: z.collectionId || void 0,
|
|
121
|
+
sku: z.sku.trim() || void 0,
|
|
107
122
|
price: t,
|
|
108
|
-
currency:
|
|
109
|
-
colours: u(
|
|
110
|
-
sizes: u(
|
|
111
|
-
materials: u(
|
|
112
|
-
tags: u(
|
|
113
|
-
imageFileId:
|
|
123
|
+
currency: z.currency.trim() || void 0,
|
|
124
|
+
colours: u(z.colours),
|
|
125
|
+
sizes: u(z.sizes),
|
|
126
|
+
materials: u(z.materials),
|
|
127
|
+
tags: u(z.tags),
|
|
128
|
+
imageFileId: z.imageFileId || void 0,
|
|
129
|
+
status: z.status === "RETIRED" ? void 0 : z.status
|
|
114
130
|
}
|
|
115
|
-
}, { onSuccess: () =>
|
|
116
|
-
brandId:
|
|
117
|
-
name:
|
|
118
|
-
description:
|
|
119
|
-
category:
|
|
120
|
-
collectionId:
|
|
121
|
-
sku:
|
|
131
|
+
}, { onSuccess: () => P(`/items/${j}`) }) : L.mutate({
|
|
132
|
+
brandId: z.brandId,
|
|
133
|
+
name: z.name.trim(),
|
|
134
|
+
description: z.description.trim() || void 0,
|
|
135
|
+
category: z.category,
|
|
136
|
+
collectionId: z.collectionId || void 0,
|
|
137
|
+
sku: z.sku.trim() || void 0,
|
|
122
138
|
price: t,
|
|
123
|
-
currency:
|
|
124
|
-
colours: u(
|
|
125
|
-
sizes: u(
|
|
126
|
-
materials: u(
|
|
127
|
-
tags: u(
|
|
128
|
-
imageFileId:
|
|
129
|
-
}, { onSuccess: (e) =>
|
|
139
|
+
currency: z.currency.trim() || void 0,
|
|
140
|
+
colours: u(z.colours),
|
|
141
|
+
sizes: u(z.sizes),
|
|
142
|
+
materials: u(z.materials),
|
|
143
|
+
tags: u(z.tags),
|
|
144
|
+
imageFileId: z.imageFileId || void 0
|
|
145
|
+
}, { onSuccess: (e) => P(`/items/${e.id}`) });
|
|
130
146
|
},
|
|
131
147
|
className: "mx-auto max-w-2xl",
|
|
132
148
|
children: /* @__PURE__ */ D(O, {
|
|
@@ -146,48 +162,58 @@ function A() {
|
|
|
146
162
|
children: "A piece belongs to a brand and optionally a collection."
|
|
147
163
|
})] })]
|
|
148
164
|
}),
|
|
149
|
-
!
|
|
165
|
+
!N && /* @__PURE__ */ E(p, {
|
|
150
166
|
id: "brandId",
|
|
151
167
|
label: "Brand",
|
|
152
|
-
value:
|
|
153
|
-
onChange: (e) =>
|
|
154
|
-
options:
|
|
168
|
+
value: z.brandId,
|
|
169
|
+
onChange: (e) => W("brandId", e),
|
|
170
|
+
options: K,
|
|
155
171
|
required: !0,
|
|
156
|
-
placeholder:
|
|
157
|
-
error:
|
|
172
|
+
placeholder: I.isLoading ? "Loading brands…" : "Select a brand",
|
|
173
|
+
error: V.brandId,
|
|
158
174
|
className: "mb-4"
|
|
159
175
|
}),
|
|
160
176
|
/* @__PURE__ */ D("div", {
|
|
161
177
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
|
|
162
|
-
children: [
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
178
|
+
children: [
|
|
179
|
+
/* @__PURE__ */ E(h, {
|
|
180
|
+
id: "name",
|
|
181
|
+
label: "Name",
|
|
182
|
+
value: z.name,
|
|
183
|
+
onChange: (e) => W("name", e),
|
|
184
|
+
placeholder: "Silk slip dress",
|
|
185
|
+
required: !0,
|
|
186
|
+
error: V.name
|
|
187
|
+
}),
|
|
188
|
+
/* @__PURE__ */ E(p, {
|
|
189
|
+
id: "category",
|
|
190
|
+
label: "Category",
|
|
191
|
+
value: z.category,
|
|
192
|
+
onChange: (e) => W("category", e),
|
|
193
|
+
options: J
|
|
194
|
+
}),
|
|
195
|
+
N && z.status !== "RETIRED" && /* @__PURE__ */ E(p, {
|
|
196
|
+
id: "status",
|
|
197
|
+
label: "Sale status",
|
|
198
|
+
value: z.status,
|
|
199
|
+
onChange: (e) => W("status", e),
|
|
200
|
+
options: k
|
|
201
|
+
})
|
|
202
|
+
]
|
|
177
203
|
}),
|
|
178
204
|
/* @__PURE__ */ E(m, {
|
|
179
205
|
id: "description",
|
|
180
206
|
label: "Description",
|
|
181
|
-
value:
|
|
182
|
-
onChange: (e) =>
|
|
207
|
+
value: z.description,
|
|
208
|
+
onChange: (e) => W("description", e),
|
|
183
209
|
placeholder: "Describe the piece…",
|
|
184
210
|
rows: 3,
|
|
185
211
|
className: "mt-4"
|
|
186
212
|
}),
|
|
187
213
|
/* @__PURE__ */ E(g, {
|
|
188
214
|
label: "Product photo",
|
|
189
|
-
value:
|
|
190
|
-
onChange: (e) =>
|
|
215
|
+
value: z.imageFileId,
|
|
216
|
+
onChange: (e) => W("imageFileId", e),
|
|
191
217
|
folder: s.items,
|
|
192
218
|
hint: "Shown across the catalogue and item page",
|
|
193
219
|
className: "mt-4"
|
|
@@ -199,23 +225,23 @@ function A() {
|
|
|
199
225
|
id: "price",
|
|
200
226
|
label: "Price",
|
|
201
227
|
type: "number",
|
|
202
|
-
value:
|
|
203
|
-
onChange: (e) =>
|
|
228
|
+
value: z.price,
|
|
229
|
+
onChange: (e) => W("price", e),
|
|
204
230
|
placeholder: "0.00",
|
|
205
|
-
error:
|
|
231
|
+
error: V.price
|
|
206
232
|
}),
|
|
207
233
|
/* @__PURE__ */ E(h, {
|
|
208
234
|
id: "currency",
|
|
209
235
|
label: "Currency",
|
|
210
|
-
value:
|
|
211
|
-
onChange: (e) =>
|
|
236
|
+
value: z.currency,
|
|
237
|
+
onChange: (e) => W("currency", e),
|
|
212
238
|
placeholder: "USD"
|
|
213
239
|
}),
|
|
214
240
|
/* @__PURE__ */ E(h, {
|
|
215
241
|
id: "sku",
|
|
216
242
|
label: "SKU",
|
|
217
|
-
value:
|
|
218
|
-
onChange: (e) =>
|
|
243
|
+
value: z.sku,
|
|
244
|
+
onChange: (e) => W("sku", e),
|
|
219
245
|
placeholder: "ABC-123"
|
|
220
246
|
})
|
|
221
247
|
]
|
|
@@ -223,10 +249,10 @@ function A() {
|
|
|
223
249
|
/* @__PURE__ */ E(p, {
|
|
224
250
|
id: "collectionId",
|
|
225
251
|
label: "Collection (optional)",
|
|
226
|
-
value:
|
|
227
|
-
onChange: (e) =>
|
|
228
|
-
options:
|
|
229
|
-
placeholder:
|
|
252
|
+
value: z.collectionId,
|
|
253
|
+
onChange: (e) => W("collectionId", e),
|
|
254
|
+
options: q,
|
|
255
|
+
placeholder: z.brandId ? U.isLoading ? "Loading collections…" : "No collection" : "Select a brand first",
|
|
230
256
|
className: "mt-4"
|
|
231
257
|
}),
|
|
232
258
|
/* @__PURE__ */ D("div", {
|
|
@@ -235,48 +261,48 @@ function A() {
|
|
|
235
261
|
/* @__PURE__ */ E(h, {
|
|
236
262
|
id: "colours",
|
|
237
263
|
label: "Colours",
|
|
238
|
-
value:
|
|
239
|
-
onChange: (e) =>
|
|
264
|
+
value: z.colours,
|
|
265
|
+
onChange: (e) => W("colours", e),
|
|
240
266
|
placeholder: "black, ivory",
|
|
241
267
|
hint: "Comma-separated"
|
|
242
268
|
}),
|
|
243
269
|
/* @__PURE__ */ E(h, {
|
|
244
270
|
id: "sizes",
|
|
245
271
|
label: "Sizes",
|
|
246
|
-
value:
|
|
247
|
-
onChange: (e) =>
|
|
272
|
+
value: z.sizes,
|
|
273
|
+
onChange: (e) => W("sizes", e),
|
|
248
274
|
placeholder: "XS, S, M, L",
|
|
249
275
|
hint: "Comma-separated"
|
|
250
276
|
}),
|
|
251
277
|
/* @__PURE__ */ E(h, {
|
|
252
278
|
id: "materials",
|
|
253
279
|
label: "Materials",
|
|
254
|
-
value:
|
|
255
|
-
onChange: (e) =>
|
|
280
|
+
value: z.materials,
|
|
281
|
+
onChange: (e) => W("materials", e),
|
|
256
282
|
placeholder: "silk, cotton",
|
|
257
283
|
hint: "Comma-separated"
|
|
258
284
|
}),
|
|
259
285
|
/* @__PURE__ */ E(h, {
|
|
260
286
|
id: "tags",
|
|
261
287
|
label: "Tags",
|
|
262
|
-
value:
|
|
263
|
-
onChange: (e) =>
|
|
288
|
+
value: z.tags,
|
|
289
|
+
onChange: (e) => W("tags", e),
|
|
264
290
|
placeholder: "summer, party",
|
|
265
291
|
hint: "Comma-separated"
|
|
266
292
|
})
|
|
267
293
|
]
|
|
268
294
|
}),
|
|
269
|
-
|
|
295
|
+
G.isError && /* @__PURE__ */ E("p", {
|
|
270
296
|
className: "mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
|
|
271
|
-
children:
|
|
297
|
+
children: G.error instanceof Error ? G.error.message : "Something went wrong"
|
|
272
298
|
}),
|
|
273
299
|
/* @__PURE__ */ E("div", {
|
|
274
300
|
className: "mt-6 flex justify-end gap-2",
|
|
275
301
|
children: /* @__PURE__ */ D("button", {
|
|
276
302
|
type: "submit",
|
|
277
|
-
disabled:
|
|
303
|
+
disabled: G.isPending,
|
|
278
304
|
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",
|
|
279
|
-
children: [
|
|
305
|
+
children: [G.isPending ? /* @__PURE__ */ E(x, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ E(S, { className: "h-4 w-4" }), N ? "Save changes" : "Create item"]
|
|
280
306
|
})
|
|
281
307
|
})
|
|
282
308
|
]
|
|
@@ -285,6 +311,6 @@ function A() {
|
|
|
285
311
|
});
|
|
286
312
|
}
|
|
287
313
|
//#endregion
|
|
288
|
-
export {
|
|
314
|
+
export { j as StyleItemFormPage };
|
|
289
315
|
|
|
290
316
|
//# sourceMappingURL=StyleItemFormPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StyleItemFormPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/items/StyleItemFormPage.tsx"],"sourcesContent":["/**\n * Style Item Create / Edit Page\n * @module coolandlovely/pages/items\n *\n * Drives `cooCreateStyleItem` (new) and `cooUpdateStyleItem` (edit).\n * Brand selection is required on create (and locked on edit). The collection\n * select is scoped to the chosen brand.\n */\n\nimport { useEffect, useMemo, useState } from 'react';\nimport { useParams, useSearchParams } from 'react-router';\nimport { ArrowLeft, Loader2, Save, Shirt } 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 { ImageUploadField } from '../../components/ImageUploadField';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport {\n useStyleItem,\n useCreateStyleItem,\n useUpdateStyleItem,\n useBrands,\n useCollections,\n} from '../../hooks';\nimport { COO_FILE_FOLDERS } from '../../hooks/useFiles';\nimport { STYLE_CATEGORIES } from '../../utils/icons';\nimport { parseCsv, titleCase } from '../../utils/formatters';\nimport type { CooStyleCategory } from '../../types';\n\ninterface FormState {\n brandId: string;\n collectionId: string;\n name: string;\n description: string;\n category: CooStyleCategory;\n sku: string;\n price: string;\n currency: string;\n colours: string;\n sizes: string;\n materials: string;\n tags: string;\n imageFileId: string;\n}\n\nconst EMPTY: FormState = {\n brandId: '',\n collectionId: '',\n name: '',\n description: '',\n category: 'OTHER',\n sku: '',\n price: '',\n currency: 'USD',\n colours: '',\n sizes: '',\n materials: '',\n tags: '',\n imageFileId: '',\n};\n\nexport function StyleItemFormPage() {\n const { itemId } = useParams<{ itemId: string }>();\n const [searchParams] = useSearchParams();\n const isEdit = Boolean(itemId);\n const { navigateTo } = useCoolAndLovely();\n\n const existing = useStyleItem(isEdit ? itemId : undefined);\n const brands = useBrands({ pagination: { limit: 100, offset: 0 } });\n const createItem = useCreateStyleItem();\n const updateItem = useUpdateStyleItem();\n\n const [form, setForm] = useState<FormState>(() => ({\n ...EMPTY,\n brandId: searchParams.get('brandId') ?? '',\n collectionId: searchParams.get('collectionId') ?? '',\n }));\n const [errors, setErrors] = useState<Partial<Record<keyof FormState, string>>>({});\n\n // Collections scoped to the selected brand (for the optional collection select)\n const collections = useCollections(form.brandId ? { brandId: form.brandId } : {});\n\n useEffect(() => {\n if (isEdit && existing.data) {\n const it = existing.data;\n setForm({\n brandId: it.brandId,\n collectionId: it.collectionId ?? '',\n name: it.name,\n description: it.description ?? '',\n category: it.category,\n sku: it.sku ?? '',\n price: String(it.price),\n currency: it.currency,\n colours: it.colours.join(', '),\n sizes: it.sizes.join(', '),\n materials: it.materials.join(', '),\n tags: it.tags.join(', '),\n imageFileId: it.image?.id ?? '',\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 ? updateItem : createItem;\n\n const brandOptions = useMemo(\n () => (brands.data?.items ?? []).map((b) => ({ value: b.id, label: b.name })),\n [brands.data]\n );\n const collectionOptions = useMemo(\n () => (collections.data ?? []).map((c) => ({ value: c.id, label: c.name })),\n [collections.data]\n );\n const categoryOptions = STYLE_CATEGORIES.map((c) => ({ value: c, label: titleCase(c) }));\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 if (form.price && Number.isNaN(Number(form.price))) next.price = 'Price must be a number';\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 const priceNum = form.price.trim() ? Number(form.price) : undefined;\n\n if (isEdit && itemId) {\n updateItem.mutate(\n {\n id: itemId,\n input: {\n name: form.name.trim(),\n description: form.description.trim() || undefined,\n category: form.category,\n collectionId: form.collectionId || undefined,\n sku: form.sku.trim() || undefined,\n price: priceNum,\n currency: form.currency.trim() || undefined,\n colours: parseCsv(form.colours),\n sizes: parseCsv(form.sizes),\n materials: parseCsv(form.materials),\n tags: parseCsv(form.tags),\n imageFileId: form.imageFileId || undefined,\n },\n },\n { onSuccess: () => navigateTo(`/items/${itemId}`) }\n );\n } else {\n createItem.mutate(\n {\n brandId: form.brandId,\n name: form.name.trim(),\n description: form.description.trim() || undefined,\n category: form.category,\n collectionId: form.collectionId || undefined,\n sku: form.sku.trim() || undefined,\n price: priceNum,\n currency: form.currency.trim() || undefined,\n colours: parseCsv(form.colours),\n sizes: parseCsv(form.sizes),\n materials: parseCsv(form.materials),\n tags: parseCsv(form.tags),\n imageFileId: form.imageFileId || undefined,\n },\n { onSuccess: (item) => navigateTo(`/items/${item.id}`) }\n );\n }\n };\n\n if (isEdit && existing.isLoading) {\n return (\n <PageLayout title=\"Edit item\">\n <LoadingView label=\"Loading item…\" />\n </PageLayout>\n );\n }\n\n if (isEdit && (existing.isError || !existing.data)) {\n return (\n <PageLayout title=\"Edit item\">\n <ErrorView title=\"Item not found\" onRetry={() => void existing.refetch()} />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={isEdit ? 'Edit item' : 'New style item'}\n description={isEdit ? 'Update this catalogue piece' : 'List a new shoppable piece'}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo(isEdit && itemId ? `/items/${itemId}` : '/items')}\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-[var(--color-accent-soft)] text-text-primary\">\n <Shirt className=\"h-5 w-5\" />\n </div>\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">Item details</h2>\n <p className=\"text-xs text-text-secondary\">\n A piece belongs to a brand and optionally a collection.\n </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=\"Silk slip dress\"\n required\n error={errors.name}\n />\n <SelectField\n id=\"category\"\n label=\"Category\"\n value={form.category}\n onChange={(v) => setField('category', v as CooStyleCategory)}\n options={categoryOptions}\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 piece…\"\n rows={3}\n className=\"mt-4\"\n />\n\n <ImageUploadField\n label=\"Product photo\"\n value={form.imageFileId}\n onChange={(id) => setField('imageFileId', id)}\n folder={COO_FILE_FOLDERS.items}\n hint=\"Shown across the catalogue and item page\"\n className=\"mt-4\"\n />\n\n <div className=\"mt-4 grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <TextField\n id=\"price\"\n label=\"Price\"\n type=\"number\"\n value={form.price}\n onChange={(v) => setField('price', v)}\n placeholder=\"0.00\"\n error={errors.price}\n />\n <TextField\n id=\"currency\"\n label=\"Currency\"\n value={form.currency}\n onChange={(v) => setField('currency', v)}\n placeholder=\"USD\"\n />\n <TextField\n id=\"sku\"\n label=\"SKU\"\n value={form.sku}\n onChange={(v) => setField('sku', v)}\n placeholder=\"ABC-123\"\n />\n </div>\n\n <SelectField\n id=\"collectionId\"\n label=\"Collection (optional)\"\n value={form.collectionId}\n onChange={(v) => setField('collectionId', v)}\n options={collectionOptions}\n placeholder={\n !form.brandId\n ? 'Select a brand first'\n : collections.isLoading\n ? 'Loading collections…'\n : 'No collection'\n }\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=\"colours\"\n label=\"Colours\"\n value={form.colours}\n onChange={(v) => setField('colours', v)}\n placeholder=\"black, ivory\"\n hint=\"Comma-separated\"\n />\n <TextField\n id=\"sizes\"\n label=\"Sizes\"\n value={form.sizes}\n onChange={(v) => setField('sizes', v)}\n placeholder=\"XS, S, M, L\"\n hint=\"Comma-separated\"\n />\n <TextField\n id=\"materials\"\n label=\"Materials\"\n value={form.materials}\n onChange={(v) => setField('materials', v)}\n placeholder=\"silk, cotton\"\n hint=\"Comma-separated\"\n />\n <TextField\n id=\"tags\"\n label=\"Tags\"\n value={form.tags}\n onChange={(v) => setField('tags', v)}\n placeholder=\"summer, party\"\n hint=\"Comma-separated\"\n />\n </div>\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 item'}\n </button>\n </div>\n </GlassCard>\n </form>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"StyleItemFormPage.js","names":[],"sources":["../../../../src/coolandlovely/pages/items/StyleItemFormPage.tsx"],"sourcesContent":["/**\n * Style Item Create / Edit Page\n * @module coolandlovely/pages/items\n *\n * Drives `cooCreateStyleItem` (new) and `cooUpdateStyleItem` (edit).\n * Brand selection is required on create (and locked on edit). The collection\n * select is scoped to the chosen brand.\n */\n\nimport { useEffect, useMemo, useState } from 'react';\nimport { useParams, useSearchParams } from 'react-router';\nimport { ArrowLeft, Loader2, Save, Shirt } 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 { ImageUploadField } from '../../components/ImageUploadField';\nimport { useCoolAndLovely } from '../../context/CoolAndLovelyContext';\nimport {\n useStyleItem,\n useCreateStyleItem,\n useUpdateStyleItem,\n useBrands,\n useCollections,\n} from '../../hooks';\nimport { COO_FILE_FOLDERS } from '../../hooks/useFiles';\nimport { STYLE_CATEGORIES } from '../../utils/icons';\nimport { parseCsv, titleCase } from '../../utils/formatters';\nimport type { CooStyleCategory, CooStyleItemStatus } from '../../types';\n\ninterface FormState {\n brandId: string;\n collectionId: string;\n name: string;\n description: string;\n category: CooStyleCategory;\n sku: string;\n price: string;\n currency: string;\n colours: string;\n sizes: string;\n materials: string;\n tags: string;\n imageFileId: string;\n /** Sale status (edit only). RETIRED is archive-only and never offered here. */\n status: CooStyleItemStatus;\n}\n\n/** Sale statuses a brand can set; checkout only sells ACTIVE pieces (BOFF-3370). */\nconst SALE_STATUS_OPTIONS: Array<{ value: CooStyleItemStatus; label: string }> = [\n { value: 'DRAFT', label: 'Draft (not on sale)' },\n { value: 'ACTIVE', label: 'On sale' },\n { value: 'OUT_OF_STOCK', label: 'Out of stock' },\n];\n\nconst EMPTY: FormState = {\n brandId: '',\n collectionId: '',\n name: '',\n description: '',\n category: 'OTHER',\n sku: '',\n price: '',\n currency: 'USD',\n colours: '',\n sizes: '',\n materials: '',\n tags: '',\n imageFileId: '',\n status: 'DRAFT',\n};\n\nexport function StyleItemFormPage() {\n const { itemId } = useParams<{ itemId: string }>();\n const [searchParams] = useSearchParams();\n const isEdit = Boolean(itemId);\n const { navigateTo } = useCoolAndLovely();\n\n const existing = useStyleItem(isEdit ? itemId : undefined);\n const brands = useBrands({ pagination: { limit: 100, offset: 0 } });\n const createItem = useCreateStyleItem();\n const updateItem = useUpdateStyleItem();\n\n const [form, setForm] = useState<FormState>(() => ({\n ...EMPTY,\n brandId: searchParams.get('brandId') ?? '',\n collectionId: searchParams.get('collectionId') ?? '',\n }));\n const [errors, setErrors] = useState<Partial<Record<keyof FormState, string>>>({});\n\n // Collections scoped to the selected brand (for the optional collection select)\n const collections = useCollections(form.brandId ? { brandId: form.brandId } : {});\n\n useEffect(() => {\n if (isEdit && existing.data) {\n const it = existing.data;\n setForm({\n brandId: it.brandId,\n collectionId: it.collectionId ?? '',\n name: it.name,\n description: it.description ?? '',\n category: it.category,\n sku: it.sku ?? '',\n price: String(it.price),\n currency: it.currency,\n colours: it.colours.join(', '),\n sizes: it.sizes.join(', '),\n materials: it.materials.join(', '),\n tags: it.tags.join(', '),\n imageFileId: it.image?.id ?? '',\n status: it.status,\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 ? updateItem : createItem;\n\n const brandOptions = useMemo(\n () => (brands.data?.items ?? []).map((b) => ({ value: b.id, label: b.name })),\n [brands.data]\n );\n const collectionOptions = useMemo(\n () => (collections.data ?? []).map((c) => ({ value: c.id, label: c.name })),\n [collections.data]\n );\n const categoryOptions = STYLE_CATEGORIES.map((c) => ({ value: c, label: titleCase(c) }));\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 if (form.price && Number.isNaN(Number(form.price))) next.price = 'Price must be a number';\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 const priceNum = form.price.trim() ? Number(form.price) : undefined;\n\n if (isEdit && itemId) {\n updateItem.mutate(\n {\n id: itemId,\n input: {\n name: form.name.trim(),\n description: form.description.trim() || undefined,\n category: form.category,\n collectionId: form.collectionId || undefined,\n sku: form.sku.trim() || undefined,\n price: priceNum,\n currency: form.currency.trim() || undefined,\n colours: parseCsv(form.colours),\n sizes: parseCsv(form.sizes),\n materials: parseCsv(form.materials),\n tags: parseCsv(form.tags),\n imageFileId: form.imageFileId || undefined,\n // A retired piece keeps its terminal status; only live statuses are sent.\n status: form.status === 'RETIRED' ? undefined : form.status,\n },\n },\n { onSuccess: () => navigateTo(`/items/${itemId}`) }\n );\n } else {\n createItem.mutate(\n {\n brandId: form.brandId,\n name: form.name.trim(),\n description: form.description.trim() || undefined,\n category: form.category,\n collectionId: form.collectionId || undefined,\n sku: form.sku.trim() || undefined,\n price: priceNum,\n currency: form.currency.trim() || undefined,\n colours: parseCsv(form.colours),\n sizes: parseCsv(form.sizes),\n materials: parseCsv(form.materials),\n tags: parseCsv(form.tags),\n imageFileId: form.imageFileId || undefined,\n },\n { onSuccess: (item) => navigateTo(`/items/${item.id}`) }\n );\n }\n };\n\n if (isEdit && existing.isLoading) {\n return (\n <PageLayout title=\"Edit item\">\n <LoadingView label=\"Loading item…\" />\n </PageLayout>\n );\n }\n\n if (isEdit && (existing.isError || !existing.data)) {\n return (\n <PageLayout title=\"Edit item\">\n <ErrorView title=\"Item not found\" onRetry={() => void existing.refetch()} />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title={isEdit ? 'Edit item' : 'New style item'}\n description={isEdit ? 'Update this catalogue piece' : 'List a new shoppable piece'}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo(isEdit && itemId ? `/items/${itemId}` : '/items')}\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-[var(--color-accent-soft)] text-text-primary\">\n <Shirt className=\"h-5 w-5\" />\n </div>\n <div>\n <h2 className=\"text-base font-semibold text-text-primary\">Item details</h2>\n <p className=\"text-xs text-text-secondary\">\n A piece belongs to a brand and optionally a collection.\n </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=\"Silk slip dress\"\n required\n error={errors.name}\n />\n <SelectField\n id=\"category\"\n label=\"Category\"\n value={form.category}\n onChange={(v) => setField('category', v as CooStyleCategory)}\n options={categoryOptions}\n />\n {isEdit && form.status !== 'RETIRED' && (\n <SelectField\n id=\"status\"\n label=\"Sale status\"\n value={form.status}\n onChange={(v) => setField('status', v as CooStyleItemStatus)}\n options={SALE_STATUS_OPTIONS}\n />\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 piece…\"\n rows={3}\n className=\"mt-4\"\n />\n\n <ImageUploadField\n label=\"Product photo\"\n value={form.imageFileId}\n onChange={(id) => setField('imageFileId', id)}\n folder={COO_FILE_FOLDERS.items}\n hint=\"Shown across the catalogue and item page\"\n className=\"mt-4\"\n />\n\n <div className=\"mt-4 grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <TextField\n id=\"price\"\n label=\"Price\"\n type=\"number\"\n value={form.price}\n onChange={(v) => setField('price', v)}\n placeholder=\"0.00\"\n error={errors.price}\n />\n <TextField\n id=\"currency\"\n label=\"Currency\"\n value={form.currency}\n onChange={(v) => setField('currency', v)}\n placeholder=\"USD\"\n />\n <TextField\n id=\"sku\"\n label=\"SKU\"\n value={form.sku}\n onChange={(v) => setField('sku', v)}\n placeholder=\"ABC-123\"\n />\n </div>\n\n <SelectField\n id=\"collectionId\"\n label=\"Collection (optional)\"\n value={form.collectionId}\n onChange={(v) => setField('collectionId', v)}\n options={collectionOptions}\n placeholder={\n !form.brandId\n ? 'Select a brand first'\n : collections.isLoading\n ? 'Loading collections…'\n : 'No collection'\n }\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=\"colours\"\n label=\"Colours\"\n value={form.colours}\n onChange={(v) => setField('colours', v)}\n placeholder=\"black, ivory\"\n hint=\"Comma-separated\"\n />\n <TextField\n id=\"sizes\"\n label=\"Sizes\"\n value={form.sizes}\n onChange={(v) => setField('sizes', v)}\n placeholder=\"XS, S, M, L\"\n hint=\"Comma-separated\"\n />\n <TextField\n id=\"materials\"\n label=\"Materials\"\n value={form.materials}\n onChange={(v) => setField('materials', v)}\n placeholder=\"silk, cotton\"\n hint=\"Comma-separated\"\n />\n <TextField\n id=\"tags\"\n label=\"Tags\"\n value={form.tags}\n onChange={(v) => setField('tags', v)}\n placeholder=\"summer, party\"\n hint=\"Comma-separated\"\n />\n </div>\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 item'}\n </button>\n </div>\n </GlassCard>\n </form>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -2,6 +2,23 @@ import { CooFileRef, CooStyleItem } from './index';
|
|
|
2
2
|
|
|
3
3
|
export type CooOrderStatus = 'PENDING_PAYMENT' | 'PAID' | 'CANCELLED';
|
|
4
4
|
export type CooEarningSyncStatus = 'PENDING' | 'SYNCED' | 'FAILED';
|
|
5
|
+
/** Brand-side fulfilment (BOFF-9636): forward-only, one per brand in an order. */
|
|
6
|
+
export type CooFulfilmentStatus = 'UNFULFILLED' | 'CONFIRMED' | 'SHIPPED' | 'DELIVERED';
|
|
7
|
+
export interface CooOrderFulfilment {
|
|
8
|
+
id: string | null;
|
|
9
|
+
orderId: string;
|
|
10
|
+
brandId: string;
|
|
11
|
+
brandName: string | null;
|
|
12
|
+
status: CooFulfilmentStatus;
|
|
13
|
+
carrier: string | null;
|
|
14
|
+
trackingNumber: string | null;
|
|
15
|
+
trackingUrl: string | null;
|
|
16
|
+
note: string | null;
|
|
17
|
+
confirmedAt: string | null;
|
|
18
|
+
shippedAt: string | null;
|
|
19
|
+
deliveredAt: string | null;
|
|
20
|
+
updatedAt: string | null;
|
|
21
|
+
}
|
|
5
22
|
export interface CooCartItem {
|
|
6
23
|
id: string;
|
|
7
24
|
styleItemId: string;
|
|
@@ -61,6 +78,50 @@ export interface CooOrder {
|
|
|
61
78
|
createdAt: string;
|
|
62
79
|
updatedAt: string;
|
|
63
80
|
items: CooOrderItem[];
|
|
81
|
+
/** Present on the order detail query only. */
|
|
82
|
+
fulfilments?: CooOrderFulfilment[];
|
|
83
|
+
fulfilmentStatus?: CooFulfilmentStatus;
|
|
84
|
+
}
|
|
85
|
+
/** A paid order as one brand sees it: only that brand's lines and fulfilment. */
|
|
86
|
+
export interface CooBrandOrder {
|
|
87
|
+
id: string;
|
|
88
|
+
orderNumber: string;
|
|
89
|
+
status: CooOrderStatus;
|
|
90
|
+
brandId: string;
|
|
91
|
+
currency: string;
|
|
92
|
+
brandSubtotal: number;
|
|
93
|
+
itemCount: number;
|
|
94
|
+
shippingName: string | null;
|
|
95
|
+
shippingAddress: string | null;
|
|
96
|
+
buyerNote: string | null;
|
|
97
|
+
paidAt: string | null;
|
|
98
|
+
createdAt: string;
|
|
99
|
+
items: CooOrderItem[];
|
|
100
|
+
fulfilment: CooOrderFulfilment;
|
|
101
|
+
}
|
|
102
|
+
export interface CooBrandOrderConnection {
|
|
103
|
+
items: CooBrandOrder[];
|
|
104
|
+
pageInfo: {
|
|
105
|
+
cursor: string | null;
|
|
106
|
+
hasMore: boolean;
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export interface CooBrandOrderSummary {
|
|
110
|
+
brandId: string;
|
|
111
|
+
unfulfilled: number;
|
|
112
|
+
confirmed: number;
|
|
113
|
+
shipped: number;
|
|
114
|
+
delivered: number;
|
|
115
|
+
total: number;
|
|
116
|
+
}
|
|
117
|
+
export interface CooUpdateOrderFulfilmentInput {
|
|
118
|
+
brandId: string;
|
|
119
|
+
orderId: string;
|
|
120
|
+
status: Exclude<CooFulfilmentStatus, 'UNFULFILLED'>;
|
|
121
|
+
carrier?: string | null;
|
|
122
|
+
trackingNumber?: string | null;
|
|
123
|
+
trackingUrl?: string | null;
|
|
124
|
+
note?: string | null;
|
|
64
125
|
}
|
|
65
126
|
export interface CooOrderConnection {
|
|
66
127
|
items: CooOrder[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commerce.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/types/commerce.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAExD,MAAM,MAAM,cAAc,GAAG,iBAAiB,GAAG,MAAM,GAAG,WAAW,CAAC;AACtE,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"commerce.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/types/commerce.ts"],"names":[],"mappings":"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"}
|
|
@@ -388,6 +388,8 @@ export interface CooUpdateStyleItemInput {
|
|
|
388
388
|
tags?: string[];
|
|
389
389
|
imageFileId?: string;
|
|
390
390
|
isFeatured?: boolean;
|
|
391
|
+
/** Sale status (DRAFT / ACTIVE / OUT_OF_STOCK); RETIRED is archive-only. */
|
|
392
|
+
status?: CooStyleItemStatus;
|
|
391
393
|
}
|
|
392
394
|
export interface CooLookItemInput {
|
|
393
395
|
styleItemId: string;
|