@akinon/pz-theme 2.0.65-beta.0 → 2.0.65-rc.0
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/CHANGELOG.md +31 -7
- package/package.json +4 -4
- package/src/blocks/order-detail-block.tsx +124 -600
- package/src/blocks/order-list-block.tsx +101 -477
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import React
|
|
3
|
+
import React from 'react';
|
|
4
4
|
import NextLink from 'next/link';
|
|
5
5
|
import { useSession } from 'next-auth/react';
|
|
6
6
|
import { useGetOrdersQuery } from '@akinon/next/data/client/account';
|
|
@@ -11,10 +11,6 @@ import { hasItemTemplate, ItemTemplateList } from './item-template';
|
|
|
11
11
|
import { readToggle } from './product-block-utils';
|
|
12
12
|
import { BlockRendererProps } from './block-renderer-registry';
|
|
13
13
|
|
|
14
|
-
interface OrderItemLike {
|
|
15
|
-
product?: { image?: string; name?: string } | null;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
14
|
interface OrderLike {
|
|
19
15
|
id?: number;
|
|
20
16
|
number?: string;
|
|
@@ -22,15 +18,9 @@ interface OrderLike {
|
|
|
22
18
|
created_date?: string;
|
|
23
19
|
status?: { value?: string; label?: string };
|
|
24
20
|
currency?: { value?: string; label?: string };
|
|
25
|
-
orderitem_set?:
|
|
21
|
+
orderitem_set?: unknown[];
|
|
26
22
|
}
|
|
27
23
|
|
|
28
|
-
const readCount = (value: unknown, fallback: number): number => {
|
|
29
|
-
const numeric = Math.round(Number(value));
|
|
30
|
-
|
|
31
|
-
return Number.isFinite(numeric) && numeric >= 0 ? numeric : fallback;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
24
|
/** Newest/oldest first without mutating the array RTK Query handed us. */
|
|
35
25
|
const sortOrders = (orders: OrderLike[], sort: string): OrderLike[] => {
|
|
36
26
|
if (sort !== 'newest' && sort !== 'oldest') return orders;
|
|
@@ -52,11 +42,8 @@ const sortOrders = (orders: OrderLike[], sort: string): OrderLike[] => {
|
|
|
52
42
|
* rows are shown, which fields the row carries, where a row links to and the
|
|
53
43
|
* styling.
|
|
54
44
|
* Properties: limit, orderHrefBase, sort, showDate, showStatus, showAmount,
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* showPagination, perPage, emptyLabel.
|
|
58
|
-
* Parts: title, list, item, images, image-overflow, link, date, total,
|
|
59
|
-
* detail-link, status, pagination, empty.
|
|
45
|
+
* emptyLabel.
|
|
46
|
+
* Parts: list, item, link, date, total, status, empty.
|
|
60
47
|
*/
|
|
61
48
|
const OrderListBlock = ({
|
|
62
49
|
block,
|
|
@@ -96,108 +83,23 @@ const OrderListBlock = ({
|
|
|
96
83
|
currentBreakpoint,
|
|
97
84
|
true
|
|
98
85
|
);
|
|
99
|
-
const showItemImages = readToggle(
|
|
100
|
-
block.properties?.showItemImages,
|
|
101
|
-
currentBreakpoint,
|
|
102
|
-
true
|
|
103
|
-
);
|
|
104
|
-
const imageWidth = readCount(
|
|
105
|
-
getResponsiveValue(block.properties?.imageWidth, currentBreakpoint, 64),
|
|
106
|
-
64
|
|
107
|
-
);
|
|
108
|
-
const imageHeight = readCount(
|
|
109
|
-
getResponsiveValue(block.properties?.imageHeight, currentBreakpoint, 96),
|
|
110
|
-
96
|
|
111
|
-
);
|
|
112
|
-
const imageGap = readCount(
|
|
113
|
-
getResponsiveValue(block.properties?.imageGap, currentBreakpoint, 8),
|
|
114
|
-
8
|
|
115
|
-
);
|
|
116
|
-
const imageAlignRaw = String(
|
|
117
|
-
getResponsiveValue(block.properties?.imageAlign, currentBreakpoint, 'left')
|
|
118
|
-
);
|
|
119
|
-
const imageJustify =
|
|
120
|
-
imageAlignRaw === 'center'
|
|
121
|
-
? 'center'
|
|
122
|
-
: imageAlignRaw === 'right'
|
|
123
|
-
? 'flex-end'
|
|
124
|
-
: 'flex-start';
|
|
125
|
-
const maxImages = Math.max(
|
|
126
|
-
1,
|
|
127
|
-
readCount(
|
|
128
|
-
getResponsiveValue(block.properties?.maxImages, currentBreakpoint, 3),
|
|
129
|
-
3
|
|
130
|
-
)
|
|
131
|
-
);
|
|
132
86
|
const emptyLabel = String(
|
|
133
87
|
getResponsiveValue(block.properties?.emptyLabel, currentBreakpoint, '')
|
|
134
88
|
);
|
|
135
|
-
// Empty keeps the built-in row exactly as it always rendered — a brand
|
|
136
|
-
// opts into labels and a standalone detail link by setting these.
|
|
137
|
-
const numberLabel = String(
|
|
138
|
-
getResponsiveValue(block.properties?.numberLabel, currentBreakpoint, '')
|
|
139
|
-
);
|
|
140
|
-
const dateLabel = String(
|
|
141
|
-
getResponsiveValue(block.properties?.dateLabel, currentBreakpoint, '')
|
|
142
|
-
);
|
|
143
|
-
const totalLabel = String(
|
|
144
|
-
getResponsiveValue(block.properties?.totalLabel, currentBreakpoint, '')
|
|
145
|
-
);
|
|
146
|
-
const detailLinkLabel = String(
|
|
147
|
-
getResponsiveValue(block.properties?.detailLinkLabel, currentBreakpoint, '')
|
|
148
|
-
);
|
|
149
|
-
const showTitle = readToggle(
|
|
150
|
-
block.properties?.showTitle,
|
|
151
|
-
currentBreakpoint,
|
|
152
|
-
false
|
|
153
|
-
);
|
|
154
|
-
const title = String(
|
|
155
|
-
getResponsiveValue(block.properties?.title, currentBreakpoint, '')
|
|
156
|
-
);
|
|
157
|
-
const showPagination = readToggle(
|
|
158
|
-
block.properties?.showPagination,
|
|
159
|
-
currentBreakpoint,
|
|
160
|
-
false
|
|
161
|
-
);
|
|
162
|
-
const perPage = Math.max(
|
|
163
|
-
1,
|
|
164
|
-
readCount(
|
|
165
|
-
getResponsiveValue(block.properties?.perPage, currentBreakpoint, 10),
|
|
166
|
-
10
|
|
167
|
-
)
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
const isMobile = currentBreakpoint === 'mobile';
|
|
171
89
|
|
|
172
90
|
const { locale, currency: localeCurrency } = useLocalization();
|
|
173
91
|
const { status } = useSession();
|
|
174
92
|
const isAuthenticated = status === 'authenticated';
|
|
175
93
|
|
|
176
|
-
// Paged mode reads perPage/currentPage from the server; unpaged mode keeps
|
|
177
|
-
// the original single fetch capped by `limit`.
|
|
178
|
-
const [currentPage, setCurrentPage] = useState(1);
|
|
179
|
-
|
|
180
|
-
// A brand switching pageSize (or sort) mid-session should not strand the
|
|
181
|
-
// shopper on a page number that no longer exists.
|
|
182
|
-
useEffect(() => {
|
|
183
|
-
setCurrentPage(1);
|
|
184
|
-
}, [perPage, sort, showPagination]);
|
|
185
|
-
|
|
186
|
-
const effectiveLimit = showPagination ? perPage : limit;
|
|
187
|
-
|
|
188
94
|
// Guests have no orders endpoint; skipping avoids a guaranteed 403 on every
|
|
189
95
|
// page that hosts this block.
|
|
190
96
|
const { data, isLoading } = useGetOrdersQuery(
|
|
191
|
-
{ limit
|
|
97
|
+
{ limit, page: 1 },
|
|
192
98
|
{ skip: !isAuthenticated }
|
|
193
99
|
);
|
|
194
100
|
|
|
195
101
|
const orders: OrderLike[] =
|
|
196
102
|
(data as { results?: OrderLike[] } | undefined)?.results ?? [];
|
|
197
|
-
const totalCount = (data as { count?: number } | undefined)?.count ?? 0;
|
|
198
|
-
const totalPages = showPagination
|
|
199
|
-
? Math.max(1, Math.ceil(totalCount / perPage))
|
|
200
|
-
: 1;
|
|
201
103
|
|
|
202
104
|
// Navigating inside the designer iframe would drop the author out of the
|
|
203
105
|
// page they are editing, so the order links are inert there.
|
|
@@ -206,11 +108,9 @@ const OrderListBlock = ({
|
|
|
206
108
|
};
|
|
207
109
|
|
|
208
110
|
const hrefFor = (order: OrderLike) =>
|
|
209
|
-
order.id
|
|
210
|
-
? `${orderHrefBase.replace(/\/$/, '')}/${order.id}`
|
|
211
|
-
: orderHrefBase;
|
|
111
|
+
order.id ? `${orderHrefBase.replace(/\/$/, '')}/${order.id}` : orderHrefBase;
|
|
212
112
|
|
|
213
|
-
const visibleOrders = sortOrders(orders, sort).slice(0,
|
|
113
|
+
const visibleOrders = sortOrders(orders, sort).slice(0, limit);
|
|
214
114
|
|
|
215
115
|
const rows = visibleOrders.map((order, index) => ({
|
|
216
116
|
id: order.id ?? '',
|
|
@@ -233,15 +133,6 @@ const OrderListBlock = ({
|
|
|
233
133
|
itemCount: Array.isArray(order.orderitem_set)
|
|
234
134
|
? order.orderitem_set.length
|
|
235
135
|
: 0,
|
|
236
|
-
images: (Array.isArray(order.orderitem_set) ? order.orderitem_set : [])
|
|
237
|
-
.slice(0, maxImages)
|
|
238
|
-
.map((item) => item?.product?.image || '')
|
|
239
|
-
.filter(Boolean),
|
|
240
|
-
imageOverflowCount: Math.max(
|
|
241
|
-
0,
|
|
242
|
-
(Array.isArray(order.orderitem_set) ? order.orderitem_set.length : 0) -
|
|
243
|
-
maxImages
|
|
244
|
-
),
|
|
245
136
|
url: hrefFor(order),
|
|
246
137
|
href: hrefFor(order)
|
|
247
138
|
}));
|
|
@@ -260,390 +151,123 @@ const OrderListBlock = ({
|
|
|
260
151
|
/>
|
|
261
152
|
) : null;
|
|
262
153
|
|
|
263
|
-
const titleNode =
|
|
264
|
-
showTitle && title ? (
|
|
265
|
-
<div
|
|
266
|
-
data-order-list-title=""
|
|
267
|
-
{...partAttrs('title')}
|
|
268
|
-
style={{
|
|
269
|
-
width: '100%',
|
|
270
|
-
fontSize: '16px',
|
|
271
|
-
fontWeight: 600,
|
|
272
|
-
marginBottom: '16px'
|
|
273
|
-
}}
|
|
274
|
-
>
|
|
275
|
-
{title}
|
|
276
|
-
</div>
|
|
277
|
-
) : null;
|
|
278
|
-
|
|
279
154
|
if (orders.length === 0 && !customRows) {
|
|
280
155
|
if (isDesigner) {
|
|
281
156
|
return (
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
? 'Recent orders (loading)'
|
|
292
|
-
: emptyLabel || 'Recent orders (no orders)'}
|
|
293
|
-
</div>
|
|
294
|
-
</>
|
|
157
|
+
<div
|
|
158
|
+
data-order-list=""
|
|
159
|
+
data-order-list-state="empty"
|
|
160
|
+
{...partAttrs('empty', { empty: true })}
|
|
161
|
+
>
|
|
162
|
+
{isLoading
|
|
163
|
+
? 'Recent orders (loading)'
|
|
164
|
+
: emptyLabel || 'Recent orders (no orders)'}
|
|
165
|
+
</div>
|
|
295
166
|
);
|
|
296
167
|
}
|
|
297
168
|
|
|
298
169
|
// The shopper-facing empty copy is only honest once the account query has
|
|
299
170
|
// resolved; before that (and without a message) the block stays absent,
|
|
300
171
|
// which is what every published composition renders today.
|
|
301
|
-
if (!isAuthenticated || isLoading || !emptyLabel) return
|
|
172
|
+
if (!isAuthenticated || isLoading || !emptyLabel) return null;
|
|
302
173
|
|
|
303
174
|
return (
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
>
|
|
312
|
-
{emptyLabel}
|
|
313
|
-
</div>
|
|
314
|
-
</>
|
|
175
|
+
<div
|
|
176
|
+
data-order-list=""
|
|
177
|
+
data-order-list-state="empty"
|
|
178
|
+
{...partAttrs('empty', { empty: true })}
|
|
179
|
+
>
|
|
180
|
+
{emptyLabel}
|
|
181
|
+
</div>
|
|
315
182
|
);
|
|
316
183
|
}
|
|
317
184
|
|
|
318
185
|
return (
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
) => (
|
|
357
|
-
<React.Fragment>
|
|
358
|
-
{label && (
|
|
359
|
-
<span style={{ fontWeight: 600, whiteSpace: 'nowrap' }}>
|
|
360
|
-
{label}
|
|
361
|
-
</span>
|
|
362
|
-
)}
|
|
363
|
-
<span
|
|
364
|
-
{...{ [dataAttr]: '' }}
|
|
365
|
-
{...partAttrs(partName)}
|
|
366
|
-
// No default text color: the Order Number/Date/Total style
|
|
367
|
-
// groups already expose one, and an inline default would
|
|
368
|
-
// sit in front of that panel value rather than behind it.
|
|
369
|
-
// A template asking for a muted value colour sets it as a
|
|
370
|
-
// `link|date|total/color` style, not a code default.
|
|
371
|
-
style={{
|
|
372
|
-
gridColumn: label ? 'auto' : '1 / span 2',
|
|
373
|
-
// An order number is one long unbroken digit string —
|
|
374
|
-
// without this it can't wrap at all, so shrinking the
|
|
375
|
-
// column (above) just pushes it past the row's edge.
|
|
376
|
-
overflowWrap: 'anywhere'
|
|
377
|
-
}}
|
|
186
|
+
<ul
|
|
187
|
+
data-order-list=""
|
|
188
|
+
{...partAttrs('list')}
|
|
189
|
+
style={{
|
|
190
|
+
display: 'flex',
|
|
191
|
+
flexDirection: 'column',
|
|
192
|
+
gap: 'var(--order-list-gap, 12px)',
|
|
193
|
+
listStyle: 'none',
|
|
194
|
+
margin: 0,
|
|
195
|
+
padding: 0
|
|
196
|
+
}}
|
|
197
|
+
>
|
|
198
|
+
{customRows ??
|
|
199
|
+
visibleOrders.map((order, index) => {
|
|
200
|
+
const href = hrefFor(order);
|
|
201
|
+
|
|
202
|
+
return (
|
|
203
|
+
<li
|
|
204
|
+
key={order.id ?? order.number ?? index}
|
|
205
|
+
data-order-list-item=""
|
|
206
|
+
{...partAttrs('item')}
|
|
207
|
+
style={{
|
|
208
|
+
display: 'flex',
|
|
209
|
+
alignItems: 'center',
|
|
210
|
+
justifyContent: 'space-between',
|
|
211
|
+
gap: '12px',
|
|
212
|
+
padding: '12px 0',
|
|
213
|
+
borderBottom: '1px solid var(--order-list-border, #e5e7eb)'
|
|
214
|
+
}}
|
|
215
|
+
>
|
|
216
|
+
<div style={{ minWidth: 0 }}>
|
|
217
|
+
<NextLink
|
|
218
|
+
href={isDesigner ? '#' : href}
|
|
219
|
+
onClick={guard}
|
|
220
|
+
data-order-list-number=""
|
|
221
|
+
{...partAttrs('link')}
|
|
222
|
+
style={{ color: 'inherit', textDecoration: 'none' }}
|
|
378
223
|
>
|
|
379
|
-
{
|
|
380
|
-
</
|
|
381
|
-
|
|
382
|
-
|
|
224
|
+
{order.number || `#${order.id ?? ''}`}
|
|
225
|
+
</NextLink>
|
|
226
|
+
{showDate && (
|
|
227
|
+
<div
|
|
228
|
+
data-order-list-date=""
|
|
229
|
+
{...partAttrs('date')}
|
|
230
|
+
style={{ opacity: 0.8, marginTop: '2px' }}
|
|
231
|
+
>
|
|
232
|
+
{formatDate(order.created_date, locale)}
|
|
233
|
+
</div>
|
|
234
|
+
)}
|
|
235
|
+
</div>
|
|
383
236
|
|
|
384
|
-
|
|
385
|
-
<li
|
|
386
|
-
key={order.id ?? order.number ?? index}
|
|
387
|
-
data-order-list-item=""
|
|
388
|
-
{...partAttrs('item')}
|
|
237
|
+
<div
|
|
389
238
|
style={{
|
|
390
239
|
display: 'flex',
|
|
391
|
-
flexDirection:
|
|
392
|
-
alignItems:
|
|
393
|
-
gap: isMobile ? '16px' : '24px',
|
|
394
|
-
padding: '20px 0',
|
|
395
|
-
borderBottom: '1px solid var(--order-list-border, #e5e7eb)'
|
|
240
|
+
flexDirection: 'column',
|
|
241
|
+
alignItems: 'flex-end'
|
|
396
242
|
}}
|
|
397
243
|
>
|
|
398
|
-
{
|
|
399
|
-
<
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
gap: `${imageGap}px`,
|
|
408
|
-
listStyle: 'none',
|
|
409
|
-
margin: 0,
|
|
410
|
-
padding: 0,
|
|
411
|
-
minWidth: 0,
|
|
412
|
-
// Grow/shrink together with the info half (below), not
|
|
413
|
-
// a rigid 50% — a host narrower than the full page (a
|
|
414
|
-
// dashboard widget next to a sidebar, say) needs both
|
|
415
|
-
// halves to give way instead of overflowing on top of
|
|
416
|
-
// each other.
|
|
417
|
-
flex: isMobile ? '0 0 auto' : '1 1 50%',
|
|
418
|
-
width: isMobile ? '100%' : undefined
|
|
419
|
-
}}
|
|
420
|
-
>
|
|
421
|
-
{images.map((src, imageIndex) => (
|
|
422
|
-
// Plain img: order thumbnails come from arbitrary commerce
|
|
423
|
-
// CDNs that the brand next.config may not allow. The
|
|
424
|
-
// Product Images style group targets each thumbnail
|
|
425
|
-
// (not this wrapper), so its box controls land on an
|
|
426
|
-
// element they actually make sense on.
|
|
427
|
-
// eslint-disable-next-line @next/next/no-img-element
|
|
428
|
-
<img
|
|
429
|
-
key={imageIndex}
|
|
430
|
-
{...partAttrs('images')}
|
|
431
|
-
src={src}
|
|
432
|
-
alt=""
|
|
433
|
-
width={imageWidth}
|
|
434
|
-
height={imageHeight}
|
|
435
|
-
style={{
|
|
436
|
-
objectFit: 'cover',
|
|
437
|
-
display: 'block',
|
|
438
|
-
flex: '0 0 auto'
|
|
439
|
-
}}
|
|
440
|
-
/>
|
|
441
|
-
))}
|
|
442
|
-
{imageOverflowCount > 0 && (
|
|
443
|
-
<li
|
|
444
|
-
data-order-list-image-overflow=""
|
|
445
|
-
{...partAttrs('image-overflow')}
|
|
446
|
-
style={{
|
|
447
|
-
display: 'flex',
|
|
448
|
-
alignItems: 'center',
|
|
449
|
-
justifyContent: 'center',
|
|
450
|
-
flex: '0 0 auto'
|
|
451
|
-
}}
|
|
452
|
-
>
|
|
453
|
-
+{imageOverflowCount}
|
|
454
|
-
</li>
|
|
455
|
-
)}
|
|
456
|
-
</ul>
|
|
244
|
+
{showAmount && (
|
|
245
|
+
<span data-order-list-amount="" {...partAttrs('total')}>
|
|
246
|
+
{/* The order carries the currency it was placed in; the
|
|
247
|
+
storefront currency is only the fallback. */}
|
|
248
|
+
{formatMoney(order.amount, {
|
|
249
|
+
locale,
|
|
250
|
+
currency: order.currency?.value || localeCurrency
|
|
251
|
+
})}
|
|
252
|
+
</span>
|
|
457
253
|
)}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
alignItems: isMobile ? 'stretch' : 'flex-start',
|
|
467
|
-
justifyContent: isMobile ? 'flex-start' : 'space-between',
|
|
468
|
-
// A safety net for the row/status column below, on top
|
|
469
|
-
// of the shrinking above: if there still isn't room once
|
|
470
|
-
// both halves have given up all their slack, this drops
|
|
471
|
-
// the status pill to its own line instead of it landing
|
|
472
|
-
// on top of the order number.
|
|
473
|
-
flexWrap: 'wrap',
|
|
474
|
-
gap: isMobile ? '10px' : '24px',
|
|
475
|
-
flex: isMobile ? '1 1 auto' : '1 1 50%',
|
|
476
|
-
minWidth: 0,
|
|
477
|
-
width: isMobile ? '100%' : undefined
|
|
478
|
-
}}
|
|
479
|
-
>
|
|
480
|
-
<div
|
|
481
|
-
style={{
|
|
482
|
-
minWidth: 0,
|
|
483
|
-
// The value column: 'auto' alone has no minimum-width
|
|
484
|
-
// floor, so a long unbroken value (a 16-digit order
|
|
485
|
-
// number, say) refuses to shrink and pushes the grid
|
|
486
|
-
// itself past the row's edge instead of wrapping.
|
|
487
|
-
display: 'grid',
|
|
488
|
-
gridTemplateColumns: 'auto minmax(0, auto)',
|
|
489
|
-
columnGap: '10px',
|
|
490
|
-
rowGap: '10px',
|
|
491
|
-
justifyContent: 'start'
|
|
492
|
-
}}
|
|
254
|
+
{showStatus && order.status?.label && (
|
|
255
|
+
<span
|
|
256
|
+
data-order-list-status=""
|
|
257
|
+
// The raw status code is published so scoped custom CSS can
|
|
258
|
+
// paint one status differently from the rest.
|
|
259
|
+
data-order-status-value={order.status.value}
|
|
260
|
+
{...partAttrs('status')}
|
|
261
|
+
style={{ opacity: 0.8 }}
|
|
493
262
|
>
|
|
494
|
-
{
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
style={{ textDecoration: 'none' }}
|
|
503
|
-
>
|
|
504
|
-
{order.number || `#${order.id ?? ''}`}
|
|
505
|
-
</NextLink>
|
|
506
|
-
),
|
|
507
|
-
'link',
|
|
508
|
-
'data-order-list-number'
|
|
509
|
-
)}
|
|
510
|
-
{showDate &&
|
|
511
|
-
gridPair(
|
|
512
|
-
dateLabel,
|
|
513
|
-
formatDate(order.created_date, locale),
|
|
514
|
-
'date',
|
|
515
|
-
'data-order-list-date'
|
|
516
|
-
)}
|
|
517
|
-
{showAmount &&
|
|
518
|
-
totalLabel &&
|
|
519
|
-
gridPair(
|
|
520
|
-
totalLabel,
|
|
521
|
-
formatMoney(order.amount, {
|
|
522
|
-
locale,
|
|
523
|
-
currency: order.currency?.value || localeCurrency
|
|
524
|
-
}),
|
|
525
|
-
'total',
|
|
526
|
-
'data-order-list-total-inline'
|
|
527
|
-
)}
|
|
528
|
-
</div>
|
|
529
|
-
|
|
530
|
-
{detailLinkLabel && (
|
|
531
|
-
<NextLink
|
|
532
|
-
href={isDesigner ? '#' : href}
|
|
533
|
-
onClick={guard}
|
|
534
|
-
data-order-list-detail-link=""
|
|
535
|
-
{...partAttrs('detail-link')}
|
|
536
|
-
// No inline colour: the Order Detail Link style group
|
|
537
|
-
// owns that (an inline default would block it, same as
|
|
538
|
-
// the value spans above).
|
|
539
|
-
style={{
|
|
540
|
-
flex: '0 0 auto',
|
|
541
|
-
whiteSpace: 'nowrap',
|
|
542
|
-
textDecoration: 'none'
|
|
543
|
-
}}
|
|
544
|
-
>
|
|
545
|
-
→ {detailLinkLabel}
|
|
546
|
-
</NextLink>
|
|
547
|
-
)}
|
|
548
|
-
|
|
549
|
-
<div
|
|
550
|
-
style={{
|
|
551
|
-
display: 'flex',
|
|
552
|
-
flexDirection: 'column',
|
|
553
|
-
alignItems: isMobile ? 'flex-start' : 'flex-end',
|
|
554
|
-
gap: '6px',
|
|
555
|
-
flex: '0 0 auto',
|
|
556
|
-
marginLeft: !isMobile && !detailLinkLabel ? 'auto' : 0
|
|
557
|
-
}}
|
|
558
|
-
>
|
|
559
|
-
{showAmount && !totalLabel && (
|
|
560
|
-
<span data-order-list-amount="" {...partAttrs('total')}>
|
|
561
|
-
{/* The order carries the currency it was placed in; the
|
|
562
|
-
storefront currency is only the fallback. */}
|
|
563
|
-
{formatMoney(order.amount, {
|
|
564
|
-
locale,
|
|
565
|
-
currency: order.currency?.value || localeCurrency
|
|
566
|
-
})}
|
|
567
|
-
</span>
|
|
568
|
-
)}
|
|
569
|
-
{showStatus && order.status?.label && (
|
|
570
|
-
<span
|
|
571
|
-
data-order-list-status=""
|
|
572
|
-
// The raw status code is published so scoped custom CSS can
|
|
573
|
-
// paint one status differently from the rest.
|
|
574
|
-
data-order-status-value={order.status.value}
|
|
575
|
-
{...partAttrs('status')}
|
|
576
|
-
// No background/padding/radius here: the Status Pill
|
|
577
|
-
// style group already exposes exactly those (and an
|
|
578
|
-
// inline default would sit in front of a panel value,
|
|
579
|
-
// not behind it — a designer could never turn it off).
|
|
580
|
-
// A pill look is a template's `status/*` styles, not a
|
|
581
|
-
// code default.
|
|
582
|
-
style={{ display: 'inline-block', fontSize: '12px' }}
|
|
583
|
-
>
|
|
584
|
-
{order.status.label}
|
|
585
|
-
</span>
|
|
586
|
-
)}
|
|
587
|
-
</div>
|
|
588
|
-
</div>
|
|
589
|
-
</li>
|
|
590
|
-
);
|
|
591
|
-
})}
|
|
592
|
-
</ul>
|
|
593
|
-
{showPagination && totalPages > 1 && (
|
|
594
|
-
<nav
|
|
595
|
-
data-order-list-pagination=""
|
|
596
|
-
{...partAttrs('pagination')}
|
|
597
|
-
style={{
|
|
598
|
-
display: 'flex',
|
|
599
|
-
alignItems: 'center',
|
|
600
|
-
justifyContent: 'center',
|
|
601
|
-
gap: '16px',
|
|
602
|
-
marginTop: 'var(--order-list-pagination-margin, 16px)'
|
|
603
|
-
}}
|
|
604
|
-
>
|
|
605
|
-
<button
|
|
606
|
-
type="button"
|
|
607
|
-
data-order-list-pagination-prev=""
|
|
608
|
-
disabled={currentPage <= 1}
|
|
609
|
-
onClick={() => setCurrentPage((page) => Math.max(1, page - 1))}
|
|
610
|
-
style={{
|
|
611
|
-
background: 'none',
|
|
612
|
-
border: 'none',
|
|
613
|
-
cursor: currentPage <= 1 ? 'default' : 'pointer',
|
|
614
|
-
opacity: currentPage <= 1 ? 0.4 : 1,
|
|
615
|
-
padding: 0,
|
|
616
|
-
font: 'inherit',
|
|
617
|
-
color: 'inherit'
|
|
618
|
-
}}
|
|
619
|
-
>
|
|
620
|
-
‹
|
|
621
|
-
</button>
|
|
622
|
-
<span data-order-list-pagination-status="">
|
|
623
|
-
{currentPage} / {totalPages}
|
|
624
|
-
</span>
|
|
625
|
-
<button
|
|
626
|
-
type="button"
|
|
627
|
-
data-order-list-pagination-next=""
|
|
628
|
-
disabled={currentPage >= totalPages}
|
|
629
|
-
onClick={() =>
|
|
630
|
-
setCurrentPage((page) => Math.min(totalPages, page + 1))
|
|
631
|
-
}
|
|
632
|
-
style={{
|
|
633
|
-
background: 'none',
|
|
634
|
-
border: 'none',
|
|
635
|
-
cursor: currentPage >= totalPages ? 'default' : 'pointer',
|
|
636
|
-
opacity: currentPage >= totalPages ? 0.4 : 1,
|
|
637
|
-
padding: 0,
|
|
638
|
-
font: 'inherit',
|
|
639
|
-
color: 'inherit'
|
|
640
|
-
}}
|
|
641
|
-
>
|
|
642
|
-
›
|
|
643
|
-
</button>
|
|
644
|
-
</nav>
|
|
645
|
-
)}
|
|
646
|
-
</>
|
|
263
|
+
{order.status.label}
|
|
264
|
+
</span>
|
|
265
|
+
)}
|
|
266
|
+
</div>
|
|
267
|
+
</li>
|
|
268
|
+
);
|
|
269
|
+
})}
|
|
270
|
+
</ul>
|
|
647
271
|
);
|
|
648
272
|
};
|
|
649
273
|
|