@nok-integration/storefront-react 0.20.14 → 0.20.16

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/index.d.ts CHANGED
@@ -282,8 +282,8 @@ export declare interface CartLineItemProps {
282
282
  * should send it here too — the pair is what keeps the two surfaces agreeing.
283
283
  *
284
284
  * The market belongs on the validated shopping session rather than on the query string,
285
- * and moves there when that contract exists. This is the interim source,
286
- * not the intended one.
285
+ * and moves there when that contract exists. This is the interim source, not the intended
286
+ * one.
287
287
  */
288
288
  declare const CartMarketQuery: z.ZodObject<{
289
289
  country: z.ZodOptional<z.ZodString>;
@@ -3272,26 +3272,26 @@ declare const CreateReturnRequest: z.ZodObject<{
3272
3272
  items: z.ZodArray<z.ZodObject<{
3273
3273
  line_ref: z.ZodString;
3274
3274
  qty: z.ZodNumber;
3275
- reason: z.ZodEnum<["too_large", "too_small", "arrived_too_late", "item_damaged", "not_as_described", "changed_my_mind"]>;
3275
+ reason: z.ZodEnum<["too_large", "too_small", "arrived_too_late", "item_damaged", "not_as_described"]>;
3276
3276
  }, "strip", z.ZodTypeAny, {
3277
3277
  qty: number;
3278
- reason: "too_small" | "changed_my_mind" | "too_large" | "arrived_too_late" | "item_damaged" | "not_as_described";
3278
+ reason: "too_small" | "too_large" | "arrived_too_late" | "item_damaged" | "not_as_described";
3279
3279
  line_ref: string;
3280
3280
  }, {
3281
3281
  qty: number;
3282
- reason: "too_small" | "changed_my_mind" | "too_large" | "arrived_too_late" | "item_damaged" | "not_as_described";
3282
+ reason: "too_small" | "too_large" | "arrived_too_late" | "item_damaged" | "not_as_described";
3283
3283
  line_ref: string;
3284
3284
  }>, "many">;
3285
3285
  }, "strict", z.ZodTypeAny, {
3286
3286
  items: {
3287
3287
  qty: number;
3288
- reason: "too_small" | "changed_my_mind" | "too_large" | "arrived_too_late" | "item_damaged" | "not_as_described";
3288
+ reason: "too_small" | "too_large" | "arrived_too_late" | "item_damaged" | "not_as_described";
3289
3289
  line_ref: string;
3290
3290
  }[];
3291
3291
  }, {
3292
3292
  items: {
3293
3293
  qty: number;
3294
- reason: "too_small" | "changed_my_mind" | "too_large" | "arrived_too_late" | "item_damaged" | "not_as_described";
3294
+ reason: "too_small" | "too_large" | "arrived_too_late" | "item_damaged" | "not_as_described";
3295
3295
  line_ref: string;
3296
3296
  }[];
3297
3297
  }>;
@@ -3518,8 +3518,20 @@ export declare function ExploreList({ title, links }: {
3518
3518
  links: ExploreLink[];
3519
3519
  }): JSX.Element;
3520
3520
 
3521
- /** Why an item is coming back, from Figma's `Reason for return` sheet. */
3522
- declare const FanReturnReason: z.ZodEnum<["too_large", "too_small", "arrived_too_late", "item_damaged", "not_as_described", "changed_my_mind"]>;
3521
+ /**
3522
+ * Why an item is coming back — what a fan may CHOOSE, from Figma's `Reason for return`
3523
+ * sheet, less one.
3524
+ *
3525
+ * **`changed_my_mind` was withdrawn on DAZN's instruction**, and this is a documented
3526
+ * departure from the frame rather than a drift from it. It stays available on
3527
+ * the CANCEL sheet, where it is the commonest honest answer; on a return it is the one
3528
+ * reason that says nothing a warehouse or a buyer can act on.
3529
+ *
3530
+ * Narrowing what a fan may send is the whole point, so this is the enum the request
3531
+ * validates against. Reading a return already recorded is a different question — see
3532
+ * {@link RecordedReturnReason}.
3533
+ */
3534
+ declare const FanReturnReason: z.ZodEnum<["too_large", "too_small", "arrived_too_late", "item_damaged", "not_as_described"]>;
3523
3535
 
3524
3536
  declare type FanReturnReason = z.infer<typeof FanReturnReason>;
3525
3537
 
@@ -5276,6 +5288,12 @@ export declare function resolveSku(variants: ProductVariant[], size: string | nu
5276
5288
  * Ordered by how often a fan picks them rather than alphabetically, which is the design's
5277
5289
  * choice and not ours to re-sort: the two sizing reasons lead because sizing is what most
5278
5290
  * clothing returns are about.
5291
+ *
5292
+ * **Five, not the frame's six.** `changed_my_mind` was withdrawn on DAZN's instruction —
5293
+ * a documented departure, not a drift. It stays on the CANCEL sheet, where it
5294
+ * is the commonest honest answer; on a return it is the one reason that tells neither the
5295
+ * warehouse nor the buyer anything they can act on. Returns already reported under it are
5296
+ * unaffected and still read — the contract keeps it as a recorded value.
5279
5297
  */
5280
5298
  export declare const RETURN_REASONS: readonly ReasonOption<FanReturnReason>[];
5281
5299
 
@@ -5539,14 +5557,14 @@ export declare interface ReturnLabelViewProps {
5539
5557
  declare const ReturnRequestItem: z.ZodObject<{
5540
5558
  line_ref: z.ZodString;
5541
5559
  qty: z.ZodNumber;
5542
- reason: z.ZodEnum<["too_large", "too_small", "arrived_too_late", "item_damaged", "not_as_described", "changed_my_mind"]>;
5560
+ reason: z.ZodEnum<["too_large", "too_small", "arrived_too_late", "item_damaged", "not_as_described"]>;
5543
5561
  }, "strip", z.ZodTypeAny, {
5544
5562
  qty: number;
5545
- reason: "too_small" | "changed_my_mind" | "too_large" | "arrived_too_late" | "item_damaged" | "not_as_described";
5563
+ reason: "too_small" | "too_large" | "arrived_too_late" | "item_damaged" | "not_as_described";
5546
5564
  line_ref: string;
5547
5565
  }, {
5548
5566
  qty: number;
5549
- reason: "too_small" | "changed_my_mind" | "too_large" | "arrived_too_late" | "item_damaged" | "not_as_described";
5567
+ reason: "too_small" | "too_large" | "arrived_too_late" | "item_damaged" | "not_as_described";
5550
5568
  line_ref: string;
5551
5569
  }>;
5552
5570
 
package/dist/index.mjs CHANGED
@@ -4695,7 +4695,7 @@ function requireOrderTracking() {
4695
4695
  Object.defineProperty(exports, "__esModule", {
4696
4696
  value: true
4697
4697
  });
4698
- exports.ReturnDetail = exports.ReturnItem = exports.ReturnProgressEntry = exports.CreateReturnRequest = exports.ReturnRequestItem = exports.FanReturnReason = exports.RequestCancellationRequest = exports.FanCancelReason = exports.OrderDetail = exports.ReturnSummary = exports.OrderList = exports.ReturnSummaryItem = exports.OrderSummaryItem = exports.ReturnOutcome = exports.ReturnStatus = exports.OrderItem = exports.OrderTracking = exports.OrderProgressEntry = exports.OrderProgressStep = void 0;
4698
+ exports.ReturnDetail = exports.ReturnItem = exports.ReturnProgressEntry = exports.CreateReturnRequest = exports.ReturnRequestItem = exports.RecordedReturnReason = exports.FanReturnReason = exports.RequestCancellationRequest = exports.FanCancelReason = exports.OrderDetail = exports.ReturnSummary = exports.OrderList = exports.ReturnSummaryItem = exports.OrderSummaryItem = exports.ReturnOutcome = exports.ReturnStatus = exports.OrderItem = exports.OrderTracking = exports.OrderProgressEntry = exports.OrderProgressStep = void 0;
4699
4699
  const zod_1 = requireZod();
4700
4700
  const money_1 = requireMoney();
4701
4701
  const ids_1 = requireIds();
@@ -4786,7 +4786,8 @@ function requireOrderTracking() {
4786
4786
  exports.RequestCancellationRequest = zod_1.z.object({
4787
4787
  reason: exports.FanCancelReason
4788
4788
  }).strict();
4789
- exports.FanReturnReason = zod_1.z.enum(["too_large", "too_small", "arrived_too_late", "item_damaged", "not_as_described", "changed_my_mind"]);
4789
+ exports.FanReturnReason = zod_1.z.enum(["too_large", "too_small", "arrived_too_late", "item_damaged", "not_as_described"]);
4790
+ exports.RecordedReturnReason = zod_1.z.enum([...exports.FanReturnReason.options, "changed_my_mind"]);
4790
4791
  exports.ReturnRequestItem = zod_1.z.object({
4791
4792
  line_ref: zod_1.z.string().min(1),
4792
4793
  qty: zod_1.z.number().int().positive(),
@@ -4805,7 +4806,7 @@ function requireOrderTracking() {
4805
4806
  line_ref: zod_1.z.string().min(1),
4806
4807
  sku: common_1.Sku,
4807
4808
  qty: zod_1.z.number().int().positive(),
4808
- reason: exports.FanReturnReason,
4809
+ reason: exports.RecordedReturnReason,
4809
4810
  unit_price: money_1.Money,
4810
4811
  compare_at_unit_price: money_1.Money.optional(),
4811
4812
  title: zod_1.z.string().optional(),
@@ -5728,7 +5729,7 @@ const neutral$2 = "_neutral_1bagf_12";
5728
5729
  const success$1 = "_success_1bagf_17";
5729
5730
  const critical$2 = "_critical_1bagf_22";
5730
5731
  const promo = "_promo_1bagf_27";
5731
- const styles$R = {
5732
+ const styles$S = {
5732
5733
  badge: badge$5,
5733
5734
  neutral: neutral$2,
5734
5735
  success: success$1,
@@ -5737,39 +5738,42 @@ const styles$R = {
5737
5738
  };
5738
5739
  function Badge({ tone = "neutral", children }) {
5739
5740
  return jsx("span", {
5740
- className: [styles$R.badge, styles$R[tone]].join(" "),
5741
+ className: [styles$S.badge, styles$S[tone]].join(" "),
5741
5742
  children
5742
5743
  });
5743
5744
  }
5744
- const button$1 = "_button_17pvl_1";
5745
- const fullWidth = "_fullWidth_17pvl_25";
5746
- const primary = "_primary_17pvl_29";
5747
- const secondary = "_secondary_17pvl_34";
5748
- const ghost = "_ghost_17pvl_40";
5749
- const spinner = "_spinner_17pvl_83";
5750
- const spin = "_spin_17pvl_83";
5751
- const styles$Q = {
5745
+ const button$1 = "_button_ci424_1";
5746
+ const fullWidth = "_fullWidth_ci424_25";
5747
+ const primary = "_primary_ci424_29";
5748
+ const secondary = "_secondary_ci424_34";
5749
+ const ghost = "_ghost_ci424_40";
5750
+ const styles$R = {
5752
5751
  button: button$1,
5753
5752
  fullWidth,
5754
5753
  primary,
5755
5754
  secondary,
5756
- ghost,
5757
- spinner,
5758
- spin
5755
+ ghost
5756
+ };
5757
+ const spinner = "_spinner_1rueh_5";
5758
+ const styles$Q = {
5759
+ spinner
5759
5760
  };
5761
+ function Spinner({ className }) {
5762
+ return jsx("span", {
5763
+ className: [styles$Q.spinner, className ?? ""].filter(Boolean).join(" "),
5764
+ "aria-hidden": "true"
5765
+ });
5766
+ }
5760
5767
  const Button = forwardRef(function Button2({ variant = "primary", loading = false, fullWidth: fullWidth2 = false, disabled: disabled2, children, className, type = "button", ...rest }, ref) {
5761
5768
  const isDisabled = disabled2 || loading;
5762
5769
  return jsxs("button", {
5763
5770
  ref,
5764
5771
  type,
5765
- className: [styles$Q.button, styles$Q[variant], fullWidth2 ? styles$Q.fullWidth : "", className ?? ""].filter(Boolean).join(" "),
5772
+ className: [styles$R.button, styles$R[variant], fullWidth2 ? styles$R.fullWidth : "", className ?? ""].filter(Boolean).join(" "),
5766
5773
  disabled: isDisabled,
5767
5774
  "aria-busy": loading || void 0,
5768
5775
  ...rest,
5769
- children: [loading && jsx("span", {
5770
- className: styles$Q.spinner,
5771
- "aria-hidden": "true"
5772
- }), jsx("span", {
5776
+ children: [loading && jsx(Spinner, {}), jsx("span", {
5773
5777
  children
5774
5778
  })]
5775
5779
  });
@@ -6160,10 +6164,22 @@ const ES = {
6160
6164
  "Your items will show up here once you've added to your cart.": "Sus artículos aparecerán aquí cuando los añada a la cesta.",
6161
6165
  "Complete your DAZN sign-up to check out. Your cart is saved.": "Complete su registro en DAZN para finalizar la compra. Su cesta está guardada.",
6162
6166
  "Your orders will show up here once you've shopped.": "Sus pedidos aparecerán aquí cuando haya comprado.",
6167
+ "Your return label is not ready yet. Try again in a moment.": "Tu etiqueta de devolución todavía no está lista. Vuelve a intentarlo dentro de un momento.",
6163
6168
  "We'll let you know": "Le avisaremos",
6164
6169
  "{0} — as soon as it is back": "{0} — en cuanto vuelva a estar disponible",
6165
6170
  "Size {0}": "Talla {0}",
6166
- "On the way": "En camino"
6171
+ "On the way": "En camino",
6172
+ "Adding to cart": "Añadiendo a la cesta",
6173
+ "Go to cart": "Ir a la cesta",
6174
+ "Track your return": "Seguir tu devolución",
6175
+ "Track return {0}": "Seguir la devolución {0}",
6176
+ "Return requested": "Devolución solicitada",
6177
+ "Package received": "Paquete recibido",
6178
+ "Return complete": "Devolución completada",
6179
+ Less: "Menos",
6180
+ more: "más",
6181
+ "Close reasons": "Cerrar motivos",
6182
+ Select: "Seleccionar"
6167
6183
  };
6168
6184
  const CATALOGUES = {
6169
6185
  es: ES
@@ -7572,9 +7588,6 @@ const RETURN_REASONS = [{
7572
7588
  }, {
7573
7589
  value: "not_as_described",
7574
7590
  label: "Item doesn't match description"
7575
- }, {
7576
- value: "changed_my_mind",
7577
- label: "Changed my mind"
7578
7591
  }];
7579
7592
  const REASON_LABEL = new Map(RETURN_REASONS.map((r) => [r.value, r.label]));
7580
7593
  function unitsLeft(item2) {
@@ -7735,8 +7748,61 @@ const styles$A = {
7735
7748
  download,
7736
7749
  note: note$1
7737
7750
  };
7751
+ const PREPARE_TIMEOUT_MS = 6e4;
7752
+ function useLabelDownload(labelUrl) {
7753
+ const [preparing, setPreparing] = useState(false);
7754
+ const [unavailable, setUnavailable] = useState(false);
7755
+ const [ready, setReady] = useState(false);
7756
+ const live = useRef(true);
7757
+ useEffect(() => {
7758
+ live.current = true;
7759
+ return () => {
7760
+ live.current = false;
7761
+ };
7762
+ }, []);
7763
+ const onDownload = useCallback((event) => {
7764
+ if (!labelUrl || ready) return;
7765
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0) {
7766
+ return;
7767
+ }
7768
+ event.preventDefault();
7769
+ if (preparing) return;
7770
+ setUnavailable(false);
7771
+ setPreparing(true);
7772
+ const until = Date.now() + PREPARE_TIMEOUT_MS;
7773
+ void (async () => {
7774
+ for (; ; ) {
7775
+ let ok = false;
7776
+ try {
7777
+ ok = (await fetch(labelUrl, {
7778
+ method: "HEAD"
7779
+ })).ok;
7780
+ } catch {
7781
+ }
7782
+ if (!live.current) return;
7783
+ if (ok) {
7784
+ setPreparing(false);
7785
+ setReady(true);
7786
+ window.location.href = labelUrl;
7787
+ return;
7788
+ }
7789
+ if (Date.now() >= until) break;
7790
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
7791
+ if (!live.current) return;
7792
+ }
7793
+ setPreparing(false);
7794
+ setUnavailable(true);
7795
+ })();
7796
+ }, [labelUrl, preparing, ready]);
7797
+ return {
7798
+ preparing,
7799
+ unavailable,
7800
+ onDownload
7801
+ };
7802
+ }
7738
7803
  function ReturnLabelView({ ret, onDone }) {
7739
7804
  const t = useT();
7805
+ const { preparing, unavailable, onDownload } = useLabelDownload(ret.label_url);
7740
7806
  return jsxs("div", {
7741
7807
  className: styles$A.page,
7742
7808
  children: [jsxs("div", {
@@ -7777,10 +7843,17 @@ function ReturnLabelView({ ret, onDone }) {
7777
7843
  href: ret.label_url,
7778
7844
  target: "_blank",
7779
7845
  rel: "noopener noreferrer",
7780
- children: [t("Download return label"), jsx("span", {
7846
+ onClick: onDownload,
7847
+ "aria-busy": preparing || void 0,
7848
+ "aria-disabled": preparing || void 0,
7849
+ children: [preparing && jsx(Spinner, {}), t("Download return label"), jsx("span", {
7781
7850
  className: "visually-hidden",
7782
7851
  children: ` ${t("(opens in a new tab)")}`
7783
7852
  })]
7853
+ }), unavailable && jsx("p", {
7854
+ className: styles$A.note,
7855
+ role: "status",
7856
+ children: t("Your return label is not ready yet. Try again in a moment.")
7784
7857
  }), ret.label_email && jsxs("p", {
7785
7858
  className: styles$A.note,
7786
7859
  children: [t("You’ll receive a shipping label PDF to your email as well."), jsx("br", {}), ret.label_email]
@@ -8139,7 +8212,7 @@ function OrderTrackingContent({ orderRef, locale: localeProp, onStartReturn, onO
8139
8212
  useEffect(() => {
8140
8213
  void load();
8141
8214
  }, [load]);
8142
- const cancelled = order?.status === "cancelled";
8215
+ const cancelled = state === "ready" && order?.status === "cancelled";
8143
8216
  const cancelledPage = useRef(null);
8144
8217
  useBrowserLayoutEffect(() => {
8145
8218
  if (!cancelled) return;
@@ -8773,6 +8846,7 @@ function ReturnCard({ ret, locale, onOpen }) {
8773
8846
  });
8774
8847
  }
8775
8848
  function ReturnThumbnails({ ret }) {
8849
+ const t = useT();
8776
8850
  const images = ret.images ?? [];
8777
8851
  const hidden = ret.item_count - TILES + 1;
8778
8852
  const overflow = images.length >= TILES && hidden > 1 ? hidden : 0;
@@ -8804,7 +8878,7 @@ function ReturnThumbnails({ ret }) {
8804
8878
  children: ["+", overflow]
8805
8879
  }), jsx("span", {
8806
8880
  className: "visually-hidden",
8807
- children: `and ${overflow} more items`
8881
+ children: t("and {0} more items", overflow)
8808
8882
  })]
8809
8883
  })]
8810
8884
  }, `${src}-${i}`);
@@ -8812,6 +8886,7 @@ function ReturnThumbnails({ ret }) {
8812
8886
  });
8813
8887
  }
8814
8888
  function OrderCard({ order, locale, onOpen }) {
8889
+ const t = useT();
8815
8890
  const body3 = jsxs(Fragment, {
8816
8891
  children: [jsxs("div", {
8817
8892
  className: styles$v.head,
@@ -8819,7 +8894,7 @@ function OrderCard({ order, locale, onOpen }) {
8819
8894
  className: styles$v.heading,
8820
8895
  children: [jsx("span", {
8821
8896
  className: styles$v.title,
8822
- children: `Order #${shortRef(order.order_ref)}`
8897
+ children: t("Order #{0}", shortRef(order.order_ref))
8823
8898
  }), jsx("span", {
8824
8899
  className: styles$v.date,
8825
8900
  children: formatPlaced(order.placed_at, locale)
@@ -8850,6 +8925,7 @@ function OrderCard({ order, locale, onOpen }) {
8850
8925
  });
8851
8926
  }
8852
8927
  function Thumbnails({ order }) {
8928
+ const t = useT();
8853
8929
  const images = order.images ?? (order.image ? [order.image] : []);
8854
8930
  const hidden = order.item_count - TILES + 1;
8855
8931
  const overflow = images.length >= TILES && hidden > 1 ? hidden : 0;
@@ -8881,7 +8957,7 @@ function Thumbnails({ order }) {
8881
8957
  children: ["+", overflow]
8882
8958
  }), jsx("span", {
8883
8959
  className: "visually-hidden",
8884
- children: `and ${overflow} more items`
8960
+ children: t("and {0} more items", overflow)
8885
8961
  })]
8886
8962
  })]
8887
8963
  }, `${src}-${i}`);
@@ -10469,7 +10545,7 @@ function ColorSelector({ colours, selected: selected2, onSelect }) {
10469
10545
  }), lowStock2 && jsx("span", {
10470
10546
  className: styles$f.stockBadge,
10471
10547
  "aria-hidden": "true",
10472
- children: `${c.remaining} left`
10548
+ children: t("{0} left", c.remaining)
10473
10549
  })]
10474
10550
  }, c.value);
10475
10551
  })
@@ -10594,7 +10670,7 @@ function ProductDetails({ description: description2 }) {
10594
10670
  className: styles$d.toggle,
10595
10671
  "aria-expanded": expanded,
10596
10672
  onClick: () => setExpanded((v) => !v),
10597
- children: expanded ? "Less" : "more"
10673
+ children: expanded ? t("Less") : t("more")
10598
10674
  }) : null]
10599
10675
  });
10600
10676
  }
@@ -4695,7 +4695,7 @@ function requireOrderTracking() {
4695
4695
  Object.defineProperty(exports, "__esModule", {
4696
4696
  value: true
4697
4697
  });
4698
- exports.ReturnDetail = exports.ReturnItem = exports.ReturnProgressEntry = exports.CreateReturnRequest = exports.ReturnRequestItem = exports.FanReturnReason = exports.RequestCancellationRequest = exports.FanCancelReason = exports.OrderDetail = exports.ReturnSummary = exports.OrderList = exports.ReturnSummaryItem = exports.OrderSummaryItem = exports.ReturnOutcome = exports.ReturnStatus = exports.OrderItem = exports.OrderTracking = exports.OrderProgressEntry = exports.OrderProgressStep = void 0;
4698
+ exports.ReturnDetail = exports.ReturnItem = exports.ReturnProgressEntry = exports.CreateReturnRequest = exports.ReturnRequestItem = exports.RecordedReturnReason = exports.FanReturnReason = exports.RequestCancellationRequest = exports.FanCancelReason = exports.OrderDetail = exports.ReturnSummary = exports.OrderList = exports.ReturnSummaryItem = exports.OrderSummaryItem = exports.ReturnOutcome = exports.ReturnStatus = exports.OrderItem = exports.OrderTracking = exports.OrderProgressEntry = exports.OrderProgressStep = void 0;
4699
4699
  const zod_1 = requireZod();
4700
4700
  const money_1 = requireMoney();
4701
4701
  const ids_1 = requireIds();
@@ -4786,7 +4786,8 @@ function requireOrderTracking() {
4786
4786
  exports.RequestCancellationRequest = zod_1.z.object({
4787
4787
  reason: exports.FanCancelReason
4788
4788
  }).strict();
4789
- exports.FanReturnReason = zod_1.z.enum(["too_large", "too_small", "arrived_too_late", "item_damaged", "not_as_described", "changed_my_mind"]);
4789
+ exports.FanReturnReason = zod_1.z.enum(["too_large", "too_small", "arrived_too_late", "item_damaged", "not_as_described"]);
4790
+ exports.RecordedReturnReason = zod_1.z.enum([...exports.FanReturnReason.options, "changed_my_mind"]);
4790
4791
  exports.ReturnRequestItem = zod_1.z.object({
4791
4792
  line_ref: zod_1.z.string().min(1),
4792
4793
  qty: zod_1.z.number().int().positive(),
@@ -4805,7 +4806,7 @@ function requireOrderTracking() {
4805
4806
  line_ref: zod_1.z.string().min(1),
4806
4807
  sku: common_1.Sku,
4807
4808
  qty: zod_1.z.number().int().positive(),
4808
- reason: exports.FanReturnReason,
4809
+ reason: exports.RecordedReturnReason,
4809
4810
  unit_price: money_1.Money,
4810
4811
  compare_at_unit_price: money_1.Money.optional(),
4811
4812
  title: zod_1.z.string().optional(),
@@ -5728,7 +5729,7 @@ const neutral$2 = "_neutral_1bagf_12";
5728
5729
  const success$1 = "_success_1bagf_17";
5729
5730
  const critical$2 = "_critical_1bagf_22";
5730
5731
  const promo = "_promo_1bagf_27";
5731
- const styles$R = {
5732
+ const styles$S = {
5732
5733
  badge: badge$5,
5733
5734
  neutral: neutral$2,
5734
5735
  success: success$1,
@@ -5737,39 +5738,42 @@ const styles$R = {
5737
5738
  };
5738
5739
  function Badge({ tone = "neutral", children }) {
5739
5740
  return jsx("span", {
5740
- className: [styles$R.badge, styles$R[tone]].join(" "),
5741
+ className: [styles$S.badge, styles$S[tone]].join(" "),
5741
5742
  children
5742
5743
  });
5743
5744
  }
5744
- const button$1 = "_button_17pvl_1";
5745
- const fullWidth = "_fullWidth_17pvl_25";
5746
- const primary = "_primary_17pvl_29";
5747
- const secondary = "_secondary_17pvl_34";
5748
- const ghost = "_ghost_17pvl_40";
5749
- const spinner = "_spinner_17pvl_83";
5750
- const spin = "_spin_17pvl_83";
5751
- const styles$Q = {
5745
+ const button$1 = "_button_ci424_1";
5746
+ const fullWidth = "_fullWidth_ci424_25";
5747
+ const primary = "_primary_ci424_29";
5748
+ const secondary = "_secondary_ci424_34";
5749
+ const ghost = "_ghost_ci424_40";
5750
+ const styles$R = {
5752
5751
  button: button$1,
5753
5752
  fullWidth,
5754
5753
  primary,
5755
5754
  secondary,
5756
- ghost,
5757
- spinner,
5758
- spin
5755
+ ghost
5756
+ };
5757
+ const spinner = "_spinner_1rueh_5";
5758
+ const styles$Q = {
5759
+ spinner
5759
5760
  };
5761
+ function Spinner({ className }) {
5762
+ return jsx("span", {
5763
+ className: [styles$Q.spinner, className ?? ""].filter(Boolean).join(" "),
5764
+ "aria-hidden": "true"
5765
+ });
5766
+ }
5760
5767
  const Button = forwardRef(function Button2({ variant = "primary", loading = false, fullWidth: fullWidth2 = false, disabled: disabled2, children, className, type = "button", ...rest }, ref) {
5761
5768
  const isDisabled = disabled2 || loading;
5762
5769
  return jsxs("button", {
5763
5770
  ref,
5764
5771
  type,
5765
- className: [styles$Q.button, styles$Q[variant], fullWidth2 ? styles$Q.fullWidth : "", className ?? ""].filter(Boolean).join(" "),
5772
+ className: [styles$R.button, styles$R[variant], fullWidth2 ? styles$R.fullWidth : "", className ?? ""].filter(Boolean).join(" "),
5766
5773
  disabled: isDisabled,
5767
5774
  "aria-busy": loading || void 0,
5768
5775
  ...rest,
5769
- children: [loading && jsx("span", {
5770
- className: styles$Q.spinner,
5771
- "aria-hidden": "true"
5772
- }), jsx("span", {
5776
+ children: [loading && jsx(Spinner, {}), jsx("span", {
5773
5777
  children
5774
5778
  })]
5775
5779
  });
@@ -6160,10 +6164,22 @@ const ES = {
6160
6164
  "Your items will show up here once you've added to your cart.": "Sus artículos aparecerán aquí cuando los añada a la cesta.",
6161
6165
  "Complete your DAZN sign-up to check out. Your cart is saved.": "Complete su registro en DAZN para finalizar la compra. Su cesta está guardada.",
6162
6166
  "Your orders will show up here once you've shopped.": "Sus pedidos aparecerán aquí cuando haya comprado.",
6167
+ "Your return label is not ready yet. Try again in a moment.": "Tu etiqueta de devolución todavía no está lista. Vuelve a intentarlo dentro de un momento.",
6163
6168
  "We'll let you know": "Le avisaremos",
6164
6169
  "{0} — as soon as it is back": "{0} — en cuanto vuelva a estar disponible",
6165
6170
  "Size {0}": "Talla {0}",
6166
- "On the way": "En camino"
6171
+ "On the way": "En camino",
6172
+ "Adding to cart": "Añadiendo a la cesta",
6173
+ "Go to cart": "Ir a la cesta",
6174
+ "Track your return": "Seguir tu devolución",
6175
+ "Track return {0}": "Seguir la devolución {0}",
6176
+ "Return requested": "Devolución solicitada",
6177
+ "Package received": "Paquete recibido",
6178
+ "Return complete": "Devolución completada",
6179
+ Less: "Menos",
6180
+ more: "más",
6181
+ "Close reasons": "Cerrar motivos",
6182
+ Select: "Seleccionar"
6167
6183
  };
6168
6184
  const CATALOGUES = {
6169
6185
  es: ES
@@ -7572,9 +7588,6 @@ const RETURN_REASONS = [{
7572
7588
  }, {
7573
7589
  value: "not_as_described",
7574
7590
  label: "Item doesn't match description"
7575
- }, {
7576
- value: "changed_my_mind",
7577
- label: "Changed my mind"
7578
7591
  }];
7579
7592
  const REASON_LABEL = new Map(RETURN_REASONS.map((r) => [r.value, r.label]));
7580
7593
  function unitsLeft(item2) {
@@ -7735,8 +7748,61 @@ const styles$A = {
7735
7748
  download,
7736
7749
  note: note$1
7737
7750
  };
7751
+ const PREPARE_TIMEOUT_MS = 6e4;
7752
+ function useLabelDownload(labelUrl) {
7753
+ const [preparing, setPreparing] = useState(false);
7754
+ const [unavailable, setUnavailable] = useState(false);
7755
+ const [ready, setReady] = useState(false);
7756
+ const live = useRef(true);
7757
+ useEffect(() => {
7758
+ live.current = true;
7759
+ return () => {
7760
+ live.current = false;
7761
+ };
7762
+ }, []);
7763
+ const onDownload = useCallback((event) => {
7764
+ if (!labelUrl || ready) return;
7765
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0) {
7766
+ return;
7767
+ }
7768
+ event.preventDefault();
7769
+ if (preparing) return;
7770
+ setUnavailable(false);
7771
+ setPreparing(true);
7772
+ const until = Date.now() + PREPARE_TIMEOUT_MS;
7773
+ void (async () => {
7774
+ for (; ; ) {
7775
+ let ok = false;
7776
+ try {
7777
+ ok = (await fetch(labelUrl, {
7778
+ method: "HEAD"
7779
+ })).ok;
7780
+ } catch {
7781
+ }
7782
+ if (!live.current) return;
7783
+ if (ok) {
7784
+ setPreparing(false);
7785
+ setReady(true);
7786
+ window.location.href = labelUrl;
7787
+ return;
7788
+ }
7789
+ if (Date.now() >= until) break;
7790
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
7791
+ if (!live.current) return;
7792
+ }
7793
+ setPreparing(false);
7794
+ setUnavailable(true);
7795
+ })();
7796
+ }, [labelUrl, preparing, ready]);
7797
+ return {
7798
+ preparing,
7799
+ unavailable,
7800
+ onDownload
7801
+ };
7802
+ }
7738
7803
  function ReturnLabelView({ ret, onDone }) {
7739
7804
  const t = useT();
7805
+ const { preparing, unavailable, onDownload } = useLabelDownload(ret.label_url);
7740
7806
  return jsxs("div", {
7741
7807
  className: styles$A.page,
7742
7808
  children: [jsxs("div", {
@@ -7777,10 +7843,17 @@ function ReturnLabelView({ ret, onDone }) {
7777
7843
  href: ret.label_url,
7778
7844
  target: "_blank",
7779
7845
  rel: "noopener noreferrer",
7780
- children: [t("Download return label"), jsx("span", {
7846
+ onClick: onDownload,
7847
+ "aria-busy": preparing || void 0,
7848
+ "aria-disabled": preparing || void 0,
7849
+ children: [preparing && jsx(Spinner, {}), t("Download return label"), jsx("span", {
7781
7850
  className: "visually-hidden",
7782
7851
  children: ` ${t("(opens in a new tab)")}`
7783
7852
  })]
7853
+ }), unavailable && jsx("p", {
7854
+ className: styles$A.note,
7855
+ role: "status",
7856
+ children: t("Your return label is not ready yet. Try again in a moment.")
7784
7857
  }), ret.label_email && jsxs("p", {
7785
7858
  className: styles$A.note,
7786
7859
  children: [t("You’ll receive a shipping label PDF to your email as well."), jsx("br", {}), ret.label_email]
@@ -8139,7 +8212,7 @@ function OrderTrackingContent({ orderRef, locale: localeProp, onStartReturn, onO
8139
8212
  useEffect(() => {
8140
8213
  void load();
8141
8214
  }, [load]);
8142
- const cancelled = order?.status === "cancelled";
8215
+ const cancelled = state === "ready" && order?.status === "cancelled";
8143
8216
  const cancelledPage = useRef(null);
8144
8217
  useBrowserLayoutEffect(() => {
8145
8218
  if (!cancelled) return;
@@ -8773,6 +8846,7 @@ function ReturnCard({ ret, locale, onOpen }) {
8773
8846
  });
8774
8847
  }
8775
8848
  function ReturnThumbnails({ ret }) {
8849
+ const t = useT();
8776
8850
  const images = ret.images ?? [];
8777
8851
  const hidden = ret.item_count - TILES + 1;
8778
8852
  const overflow = images.length >= TILES && hidden > 1 ? hidden : 0;
@@ -8804,7 +8878,7 @@ function ReturnThumbnails({ ret }) {
8804
8878
  children: ["+", overflow]
8805
8879
  }), jsx("span", {
8806
8880
  className: "visually-hidden",
8807
- children: `and ${overflow} more items`
8881
+ children: t("and {0} more items", overflow)
8808
8882
  })]
8809
8883
  })]
8810
8884
  }, `${src}-${i}`);
@@ -8812,6 +8886,7 @@ function ReturnThumbnails({ ret }) {
8812
8886
  });
8813
8887
  }
8814
8888
  function OrderCard({ order, locale, onOpen }) {
8889
+ const t = useT();
8815
8890
  const body3 = jsxs(Fragment, {
8816
8891
  children: [jsxs("div", {
8817
8892
  className: styles$v.head,
@@ -8819,7 +8894,7 @@ function OrderCard({ order, locale, onOpen }) {
8819
8894
  className: styles$v.heading,
8820
8895
  children: [jsx("span", {
8821
8896
  className: styles$v.title,
8822
- children: `Order #${shortRef(order.order_ref)}`
8897
+ children: t("Order #{0}", shortRef(order.order_ref))
8823
8898
  }), jsx("span", {
8824
8899
  className: styles$v.date,
8825
8900
  children: formatPlaced(order.placed_at, locale)
@@ -8850,6 +8925,7 @@ function OrderCard({ order, locale, onOpen }) {
8850
8925
  });
8851
8926
  }
8852
8927
  function Thumbnails({ order }) {
8928
+ const t = useT();
8853
8929
  const images = order.images ?? (order.image ? [order.image] : []);
8854
8930
  const hidden = order.item_count - TILES + 1;
8855
8931
  const overflow = images.length >= TILES && hidden > 1 ? hidden : 0;
@@ -8881,7 +8957,7 @@ function Thumbnails({ order }) {
8881
8957
  children: ["+", overflow]
8882
8958
  }), jsx("span", {
8883
8959
  className: "visually-hidden",
8884
- children: `and ${overflow} more items`
8960
+ children: t("and {0} more items", overflow)
8885
8961
  })]
8886
8962
  })]
8887
8963
  }, `${src}-${i}`);
@@ -10469,7 +10545,7 @@ function ColorSelector({ colours, selected: selected2, onSelect }) {
10469
10545
  }), lowStock2 && jsx("span", {
10470
10546
  className: styles$f.stockBadge,
10471
10547
  "aria-hidden": "true",
10472
- children: `${c.remaining} left`
10548
+ children: t("{0} left", c.remaining)
10473
10549
  })]
10474
10550
  }, c.value);
10475
10551
  })
@@ -10594,7 +10670,7 @@ function ProductDetails({ description: description2 }) {
10594
10670
  className: styles$d.toggle,
10595
10671
  "aria-expanded": expanded,
10596
10672
  onClick: () => setExpanded((v) => !v),
10597
- children: expanded ? "Less" : "more"
10673
+ children: expanded ? t("Less") : t("more")
10598
10674
  }) : null]
10599
10675
  });
10600
10676
  }
@@ -133,7 +133,7 @@
133
133
  background: var(--color-surface-max);
134
134
  color: var(--color-text-strong);
135
135
  }
136
- ._button_17pvl_1 {
136
+ ._button_ci424_1 {
137
137
  display: inline-flex;
138
138
  align-items: center;
139
139
  justify-content: center;
@@ -151,52 +151,57 @@
151
151
  transition: background-color 120ms ease, opacity 120ms ease;
152
152
  -webkit-tap-highlight-color: transparent;
153
153
  }
154
- ._fullWidth_17pvl_25 {
154
+ ._fullWidth_ci424_25 {
155
155
  width: 100%;
156
156
  }
157
- ._primary_17pvl_29 {
157
+ ._primary_ci424_29 {
158
158
  background: var(--color-surface-max);
159
159
  color: var(--color-text-strong);
160
160
  }
161
- ._secondary_17pvl_34 {
161
+ ._secondary_ci424_34 {
162
162
  background: transparent;
163
163
  color: var(--color-text-default);
164
164
  border-color: var(--color-border-default);
165
165
  }
166
- ._ghost_17pvl_40 {
166
+ ._ghost_ci424_40 {
167
167
  background: transparent;
168
168
  color: var(--color-text-default);
169
169
  border-color: transparent;
170
170
  }
171
- ._button_17pvl_1:disabled {
171
+ ._button_ci424_1:disabled {
172
172
  cursor: not-allowed;
173
173
  }
174
- ._primary_17pvl_29:disabled {
174
+ ._primary_ci424_29:disabled {
175
175
  background: var(--color-surface-bold);
176
176
  color: var(--color-text-disabled);
177
177
  }
178
- ._secondary_17pvl_34:disabled,
179
- ._ghost_17pvl_40:disabled {
178
+ ._secondary_ci424_34:disabled,
179
+ ._ghost_ci424_40:disabled {
180
180
  opacity: 0.5;
181
181
  }
182
- ._button_17pvl_1:focus-visible {
182
+ ._button_ci424_1:focus-visible {
183
183
  outline: 2px solid var(--color-surface-max);
184
184
  outline-offset: 2px;
185
185
  }
186
- ._spinner_17pvl_83 {
186
+ ._spinner_1rueh_5 {
187
187
  width: 20px;
188
188
  height: 20px;
189
189
  margin: 2px;
190
190
  border-radius: var(--radius-full);
191
191
  border: 2px solid currentColor;
192
192
  border-top-color: transparent;
193
- animation: _spin_17pvl_83 700ms linear infinite;
193
+ animation: _spin_1rueh_5 700ms linear infinite;
194
194
  }
195
- @keyframes _spin_17pvl_83 {
195
+ @keyframes _spin_1rueh_5 {
196
196
  to {
197
197
  transform: rotate(360deg);
198
198
  }
199
199
  }
200
+ @media (prefers-reduced-motion: reduce) {
201
+ ._spinner_1rueh_5 {
202
+ animation-duration: 2400ms;
203
+ }
204
+ }
200
205
  ._skeleton_1nxz7_1 {
201
206
  display: block;
202
207
  background:
package/dist/styles.css CHANGED
@@ -133,7 +133,7 @@
133
133
  background: var(--color-surface-max);
134
134
  color: var(--color-text-strong);
135
135
  }
136
- ._button_17pvl_1 {
136
+ ._button_ci424_1 {
137
137
  display: inline-flex;
138
138
  align-items: center;
139
139
  justify-content: center;
@@ -151,52 +151,57 @@
151
151
  transition: background-color 120ms ease, opacity 120ms ease;
152
152
  -webkit-tap-highlight-color: transparent;
153
153
  }
154
- ._fullWidth_17pvl_25 {
154
+ ._fullWidth_ci424_25 {
155
155
  width: 100%;
156
156
  }
157
- ._primary_17pvl_29 {
157
+ ._primary_ci424_29 {
158
158
  background: var(--color-surface-max);
159
159
  color: var(--color-text-strong);
160
160
  }
161
- ._secondary_17pvl_34 {
161
+ ._secondary_ci424_34 {
162
162
  background: transparent;
163
163
  color: var(--color-text-default);
164
164
  border-color: var(--color-border-default);
165
165
  }
166
- ._ghost_17pvl_40 {
166
+ ._ghost_ci424_40 {
167
167
  background: transparent;
168
168
  color: var(--color-text-default);
169
169
  border-color: transparent;
170
170
  }
171
- ._button_17pvl_1:disabled {
171
+ ._button_ci424_1:disabled {
172
172
  cursor: not-allowed;
173
173
  }
174
- ._primary_17pvl_29:disabled {
174
+ ._primary_ci424_29:disabled {
175
175
  background: var(--color-surface-bold);
176
176
  color: var(--color-text-disabled);
177
177
  }
178
- ._secondary_17pvl_34:disabled,
179
- ._ghost_17pvl_40:disabled {
178
+ ._secondary_ci424_34:disabled,
179
+ ._ghost_ci424_40:disabled {
180
180
  opacity: 0.5;
181
181
  }
182
- ._button_17pvl_1:focus-visible {
182
+ ._button_ci424_1:focus-visible {
183
183
  outline: 2px solid var(--color-surface-max);
184
184
  outline-offset: 2px;
185
185
  }
186
- ._spinner_17pvl_83 {
186
+ ._spinner_1rueh_5 {
187
187
  width: 20px;
188
188
  height: 20px;
189
189
  margin: 2px;
190
190
  border-radius: var(--radius-full);
191
191
  border: 2px solid currentColor;
192
192
  border-top-color: transparent;
193
- animation: _spin_17pvl_83 700ms linear infinite;
193
+ animation: _spin_1rueh_5 700ms linear infinite;
194
194
  }
195
- @keyframes _spin_17pvl_83 {
195
+ @keyframes _spin_1rueh_5 {
196
196
  to {
197
197
  transform: rotate(360deg);
198
198
  }
199
199
  }
200
+ @media (prefers-reduced-motion: reduce) {
201
+ ._spinner_1rueh_5 {
202
+ animation-duration: 2400ms;
203
+ }
204
+ }
200
205
  ._skeleton_1nxz7_1 {
201
206
  display: block;
202
207
  background:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nok-integration/storefront-react",
3
- "version": "0.20.14",
3
+ "version": "0.20.16",
4
4
  "description": "Mountable React storefront components: catalogue, product detail and cart, mounted directly into a host DOM tree. No iframe.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",