orionplace-svelte 0.7.7 → 0.7.8
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/package.json +1 -1
- package/templates/src/lib/components/orionplace/orders/OrderDetails.svelte +2 -2
- package/templates/src/lib/components/orionplace/products/StorefrontProduct.svelte +3 -1
- package/templates/src/lib/layouts/StorefrontLayout.svelte +2 -3
- package/templates/src/lib/utils/orionplace/orderPresentation.ts +45 -2
- package/templates/src/lib/utils/orionplace/productActionLabels.ts +21 -0
- package/templates/src/lib/utils/orionplace/productActions.svelte.ts +27 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "orionplace-svelte",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.8",
|
|
4
4
|
"description": "SvelteKit 2 storefront for your Orionplace marketplace: setup CLI, server API gateway, typed store and ready-made catalog, cart, checkout and account components in English, Russian and Spanish, plus an Android app build.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -402,9 +402,9 @@
|
|
|
402
402
|
</span>
|
|
403
403
|
{/if}
|
|
404
404
|
|
|
405
|
-
{#if step.
|
|
405
|
+
{#if step.date}
|
|
406
406
|
<span class={['op-orders-step-note']}>
|
|
407
|
-
{
|
|
407
|
+
{step.date}
|
|
408
408
|
</span>
|
|
409
409
|
{:else if stepCount(step.count, step.total)}
|
|
410
410
|
<span class={['op-orders-step-note']}>
|
|
@@ -218,7 +218,9 @@
|
|
|
218
218
|
actionLabels.value.failed
|
|
219
219
|
);
|
|
220
220
|
}
|
|
221
|
-
return actions.success.value
|
|
221
|
+
return actions.success.value
|
|
222
|
+
? actionLabels.value[actions.done.value ?? 'saved']
|
|
223
|
+
: '';
|
|
222
224
|
});
|
|
223
225
|
const previewStatus = computed(() => {
|
|
224
226
|
if (!inputs.previewKey || !product.value) {
|
|
@@ -106,9 +106,8 @@
|
|
|
106
106
|
if (!actions.success.value) {
|
|
107
107
|
return '';
|
|
108
108
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
: actionCopy.value.saved;
|
|
109
|
+
// The notice names what the action did («Added to the cart.»).
|
|
110
|
+
return actionCopy.value[actions.done.value ?? 'saved'];
|
|
112
111
|
});
|
|
113
112
|
// Header selection messages stay neutral.
|
|
114
113
|
const actionTone = computed(() => {
|
|
@@ -59,6 +59,8 @@ export interface OrderStep {
|
|
|
59
59
|
current: boolean;
|
|
60
60
|
count: number;
|
|
61
61
|
total: number;
|
|
62
|
+
/** The date the step was reached ('' until then); see orderStepDate. */
|
|
63
|
+
date?: string;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
export type OrderShipmentStateKey =
|
|
@@ -228,7 +230,39 @@ export function orderCanCancel(
|
|
|
228
230
|
}
|
|
229
231
|
|
|
230
232
|
// Canceled and returned orders have no delivery progress to show.
|
|
231
|
-
|
|
233
|
+
// The date a step was reached: the order's own date for Placed; for Shipped
|
|
234
|
+
// and Delivered, once every shipment got there, the latest of their sent
|
|
235
|
+
// (or delivery) dates; '' while a shipment has not reached the step.
|
|
236
|
+
export function orderStepDate(
|
|
237
|
+
order: OrderShipmentCounters & Partial<Pick<IOrder, 'time_submited'>>,
|
|
238
|
+
key: OrderStepKey,
|
|
239
|
+
): string {
|
|
240
|
+
if (key === 'placed') {
|
|
241
|
+
return order.time_submited?.date ?? '';
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const shipments = order.delivery_froms ?? [];
|
|
245
|
+
const reached = shipments.map((shipment) =>
|
|
246
|
+
key === 'shipped'
|
|
247
|
+
? shipment.dates?.sent || shipment.dates?.delivery_date_real
|
|
248
|
+
: shipment.dates?.delivery_date_real,
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
if (!reached.length || reached.some((date) => !date?.date)) {
|
|
252
|
+
return '';
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// The latest is the one the fewest minutes ago (any date format).
|
|
256
|
+
const latest = reached.reduce((best, date) =>
|
|
257
|
+
Number(date?.minutes_ago ?? 0) < Number(best?.minutes_ago ?? 0) ? date : best,
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
return latest?.date ?? '';
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export function orderSteps(
|
|
264
|
+
order: OrderShipmentCounters & Partial<Pick<IOrder, 'time_submited'>>,
|
|
265
|
+
): OrderStep[] {
|
|
232
266
|
const { total, sent, delivered } = orderShipmentProgress(order);
|
|
233
267
|
|
|
234
268
|
if (
|
|
@@ -239,13 +273,21 @@ export function orderSteps(order: OrderShipmentCounters): OrderStep[] {
|
|
|
239
273
|
}
|
|
240
274
|
|
|
241
275
|
const steps = [
|
|
242
|
-
{
|
|
276
|
+
{
|
|
277
|
+
key: 'placed',
|
|
278
|
+
state: 'done',
|
|
279
|
+
current: false,
|
|
280
|
+
count: 1,
|
|
281
|
+
total: 1,
|
|
282
|
+
date: orderStepDate(order, 'placed'),
|
|
283
|
+
},
|
|
243
284
|
{
|
|
244
285
|
key: 'shipped',
|
|
245
286
|
state: stepState(sent, total),
|
|
246
287
|
current: false,
|
|
247
288
|
count: sent,
|
|
248
289
|
total,
|
|
290
|
+
date: orderStepDate(order, 'shipped'),
|
|
249
291
|
},
|
|
250
292
|
{
|
|
251
293
|
key: 'delivered',
|
|
@@ -253,6 +295,7 @@ export function orderSteps(order: OrderShipmentCounters): OrderStep[] {
|
|
|
253
295
|
current: false,
|
|
254
296
|
count: delivered,
|
|
255
297
|
total,
|
|
298
|
+
date: orderStepDate(order, 'delivered'),
|
|
256
299
|
},
|
|
257
300
|
] satisfies OrderStep[];
|
|
258
301
|
|
|
@@ -4,6 +4,13 @@ const labels = {
|
|
|
4
4
|
en: {
|
|
5
5
|
pending: 'Updating product…',
|
|
6
6
|
saved: 'Product updated.',
|
|
7
|
+
cartAdded: 'Added to the cart.',
|
|
8
|
+
cartUpdated: 'Cart quantity updated.',
|
|
9
|
+
cartRemoved: 'Removed from the cart.',
|
|
10
|
+
favoriteAdded: 'Saved to favorites.',
|
|
11
|
+
favoriteRemoved: 'Removed from favorites.',
|
|
12
|
+
subscribed: 'We will let you know when it is back in stock.',
|
|
13
|
+
unsubscribed: 'Availability notification turned off.',
|
|
7
14
|
failed: 'The request failed. Your confirmed product data is unchanged.',
|
|
8
15
|
unavailable: 'This action is unavailable.',
|
|
9
16
|
login: 'Sign in to save favorites or availability notifications.',
|
|
@@ -31,6 +38,13 @@ const labels = {
|
|
|
31
38
|
ru: {
|
|
32
39
|
pending: 'Обновляем товар…',
|
|
33
40
|
saved: 'Товар обновлён.',
|
|
41
|
+
cartAdded: 'Товар добавлен в корзину.',
|
|
42
|
+
cartUpdated: 'Количество в корзине изменено.',
|
|
43
|
+
cartRemoved: 'Товар удалён из корзины.',
|
|
44
|
+
favoriteAdded: 'Товар добавлен в избранное.',
|
|
45
|
+
favoriteRemoved: 'Товар удалён из избранного.',
|
|
46
|
+
subscribed: 'Сообщим, когда товар появится в наличии.',
|
|
47
|
+
unsubscribed: 'Уведомление о наличии отключено.',
|
|
34
48
|
failed: 'Запрос не выполнен. Подтверждённые данные товара сохранены.',
|
|
35
49
|
unavailable: 'Это действие недоступно.',
|
|
36
50
|
login: 'Войдите, чтобы сохранять избранное и уведомления о наличии.',
|
|
@@ -56,6 +70,13 @@ const labels = {
|
|
|
56
70
|
es: {
|
|
57
71
|
pending: 'Actualizando el producto…',
|
|
58
72
|
saved: 'Producto actualizado.',
|
|
73
|
+
cartAdded: 'Añadido al carrito.',
|
|
74
|
+
cartUpdated: 'Cantidad del carrito actualizada.',
|
|
75
|
+
cartRemoved: 'Eliminado del carrito.',
|
|
76
|
+
favoriteAdded: 'Guardado en favoritos.',
|
|
77
|
+
favoriteRemoved: 'Eliminado de favoritos.',
|
|
78
|
+
subscribed: 'Te avisaremos cuando vuelva a estar disponible.',
|
|
79
|
+
unsubscribed: 'Aviso de disponibilidad desactivado.',
|
|
59
80
|
failed: 'La solicitud ha fallado. Los datos confirmados del producto no han cambiado.',
|
|
60
81
|
unavailable: 'Esta acción no está disponible.',
|
|
61
82
|
login: 'Inicia sesión para guardar favoritos o avisos de disponibilidad.',
|
|
@@ -140,6 +140,18 @@ export function applyProductActionPatch(
|
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
// What a finished action did, so the notice can say it («Added to the
|
|
144
|
+
// cart.» rather than «Product updated.»); a key of productActionLabels.
|
|
145
|
+
export type ProductActionDone =
|
|
146
|
+
| 'cartAdded'
|
|
147
|
+
| 'cartUpdated'
|
|
148
|
+
| 'cartRemoved'
|
|
149
|
+
| 'favoriteAdded'
|
|
150
|
+
| 'favoriteRemoved'
|
|
151
|
+
| 'subscribed'
|
|
152
|
+
| 'unsubscribed'
|
|
153
|
+
| 'preorderSaved';
|
|
154
|
+
|
|
143
155
|
export function createProductActions(options: {
|
|
144
156
|
request: ProductActionRequest;
|
|
145
157
|
authenticated: () => boolean;
|
|
@@ -164,6 +176,7 @@ export function createProductActions(options: {
|
|
|
164
176
|
}>();
|
|
165
177
|
const success = ref(false);
|
|
166
178
|
const preorderId = ref<number>();
|
|
179
|
+
const done = ref<ProductActionDone>();
|
|
167
180
|
const needsRefresh = ref(false);
|
|
168
181
|
let refreshTarget: { store: ProductActionStore; id: number } | undefined;
|
|
169
182
|
|
|
@@ -482,6 +495,7 @@ export function createProductActions(options: {
|
|
|
482
495
|
|
|
483
496
|
error.value = undefined;
|
|
484
497
|
success.value = false;
|
|
498
|
+
done.value = undefined;
|
|
485
499
|
preorderId.value = undefined;
|
|
486
500
|
|
|
487
501
|
try {
|
|
@@ -511,16 +525,28 @@ export function createProductActions(options: {
|
|
|
511
525
|
|
|
512
526
|
pending.value = true;
|
|
513
527
|
|
|
528
|
+
let finished: ProductActionDone | undefined;
|
|
529
|
+
|
|
514
530
|
if (action === 'toggleFavorite') {
|
|
515
531
|
await changeFavorite(store, selection);
|
|
532
|
+
finished = selection.selected ? 'favoriteAdded' : 'favoriteRemoved';
|
|
516
533
|
} else if (action === 'add' || action === 'remove') {
|
|
534
|
+
// Adding a product already in the cart sets its new quantity.
|
|
535
|
+
const inCart = Boolean(product.cart_counts?.cart_id);
|
|
536
|
+
|
|
517
537
|
await changeCart(store, action, selection, product);
|
|
538
|
+
finished = action === 'remove'
|
|
539
|
+
? 'cartRemoved'
|
|
540
|
+
: inCart ? 'cartUpdated' : 'cartAdded';
|
|
518
541
|
} else if (action === 'subscribe' || action === 'unsubscribe') {
|
|
519
542
|
await changeSubscription(store, action, id);
|
|
543
|
+
finished = action === 'subscribe' ? 'subscribed' : 'unsubscribed';
|
|
520
544
|
} else if (action === 'preorder') {
|
|
521
545
|
await createPreorder(selection, availability.canPreorder);
|
|
546
|
+
finished = 'preorderSaved';
|
|
522
547
|
}
|
|
523
548
|
|
|
549
|
+
done.value = finished;
|
|
524
550
|
success.value = true;
|
|
525
551
|
return true;
|
|
526
552
|
} catch (reason) {
|
|
@@ -540,6 +566,7 @@ export function createProductActions(options: {
|
|
|
540
566
|
pending,
|
|
541
567
|
error,
|
|
542
568
|
success,
|
|
569
|
+
done,
|
|
543
570
|
preorderId,
|
|
544
571
|
needsRefresh,
|
|
545
572
|
retryRefresh,
|