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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orionplace-svelte",
3
- "version": "0.7.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.key === 'placed' && inputs.order.time_submited?.date}
405
+ {#if step.date}
406
406
  <span class={['op-orders-step-note']}>
407
- {inputs.order.time_submited.date}
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 ? actionLabels.value.saved : '';
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
- return actions.preorderId.value
110
- ? actionCopy.value.preorderSaved
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
- export function orderSteps(order: OrderShipmentCounters): OrderStep[] {
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
- { key: 'placed', state: 'done', current: false, count: 1, total: 1 },
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,