@nok-integration/storefront-react 0.20.15 → 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,6 +6164,7 @@ 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}",
@@ -7583,9 +7588,6 @@ const RETURN_REASONS = [{
7583
7588
  }, {
7584
7589
  value: "not_as_described",
7585
7590
  label: "Item doesn't match description"
7586
- }, {
7587
- value: "changed_my_mind",
7588
- label: "Changed my mind"
7589
7591
  }];
7590
7592
  const REASON_LABEL = new Map(RETURN_REASONS.map((r) => [r.value, r.label]));
7591
7593
  function unitsLeft(item2) {
@@ -7746,8 +7748,61 @@ const styles$A = {
7746
7748
  download,
7747
7749
  note: note$1
7748
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
+ }
7749
7803
  function ReturnLabelView({ ret, onDone }) {
7750
7804
  const t = useT();
7805
+ const { preparing, unavailable, onDownload } = useLabelDownload(ret.label_url);
7751
7806
  return jsxs("div", {
7752
7807
  className: styles$A.page,
7753
7808
  children: [jsxs("div", {
@@ -7788,10 +7843,17 @@ function ReturnLabelView({ ret, onDone }) {
7788
7843
  href: ret.label_url,
7789
7844
  target: "_blank",
7790
7845
  rel: "noopener noreferrer",
7791
- 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", {
7792
7850
  className: "visually-hidden",
7793
7851
  children: ` ${t("(opens in a new tab)")}`
7794
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.")
7795
7857
  }), ret.label_email && jsxs("p", {
7796
7858
  className: styles$A.note,
7797
7859
  children: [t("You’ll receive a shipping label PDF to your email as well."), jsx("br", {}), ret.label_email]
@@ -8150,7 +8212,7 @@ function OrderTrackingContent({ orderRef, locale: localeProp, onStartReturn, onO
8150
8212
  useEffect(() => {
8151
8213
  void load();
8152
8214
  }, [load]);
8153
- const cancelled = order?.status === "cancelled";
8215
+ const cancelled = state === "ready" && order?.status === "cancelled";
8154
8216
  const cancelledPage = useRef(null);
8155
8217
  useBrowserLayoutEffect(() => {
8156
8218
  if (!cancelled) return;
@@ -8784,6 +8846,7 @@ function ReturnCard({ ret, locale, onOpen }) {
8784
8846
  });
8785
8847
  }
8786
8848
  function ReturnThumbnails({ ret }) {
8849
+ const t = useT();
8787
8850
  const images = ret.images ?? [];
8788
8851
  const hidden = ret.item_count - TILES + 1;
8789
8852
  const overflow = images.length >= TILES && hidden > 1 ? hidden : 0;
@@ -8815,7 +8878,7 @@ function ReturnThumbnails({ ret }) {
8815
8878
  children: ["+", overflow]
8816
8879
  }), jsx("span", {
8817
8880
  className: "visually-hidden",
8818
- children: `and ${overflow} more items`
8881
+ children: t("and {0} more items", overflow)
8819
8882
  })]
8820
8883
  })]
8821
8884
  }, `${src}-${i}`);
@@ -8823,6 +8886,7 @@ function ReturnThumbnails({ ret }) {
8823
8886
  });
8824
8887
  }
8825
8888
  function OrderCard({ order, locale, onOpen }) {
8889
+ const t = useT();
8826
8890
  const body3 = jsxs(Fragment, {
8827
8891
  children: [jsxs("div", {
8828
8892
  className: styles$v.head,
@@ -8830,7 +8894,7 @@ function OrderCard({ order, locale, onOpen }) {
8830
8894
  className: styles$v.heading,
8831
8895
  children: [jsx("span", {
8832
8896
  className: styles$v.title,
8833
- children: `Order #${shortRef(order.order_ref)}`
8897
+ children: t("Order #{0}", shortRef(order.order_ref))
8834
8898
  }), jsx("span", {
8835
8899
  className: styles$v.date,
8836
8900
  children: formatPlaced(order.placed_at, locale)
@@ -8861,6 +8925,7 @@ function OrderCard({ order, locale, onOpen }) {
8861
8925
  });
8862
8926
  }
8863
8927
  function Thumbnails({ order }) {
8928
+ const t = useT();
8864
8929
  const images = order.images ?? (order.image ? [order.image] : []);
8865
8930
  const hidden = order.item_count - TILES + 1;
8866
8931
  const overflow = images.length >= TILES && hidden > 1 ? hidden : 0;
@@ -8892,7 +8957,7 @@ function Thumbnails({ order }) {
8892
8957
  children: ["+", overflow]
8893
8958
  }), jsx("span", {
8894
8959
  className: "visually-hidden",
8895
- children: `and ${overflow} more items`
8960
+ children: t("and {0} more items", overflow)
8896
8961
  })]
8897
8962
  })]
8898
8963
  }, `${src}-${i}`);
@@ -10480,7 +10545,7 @@ function ColorSelector({ colours, selected: selected2, onSelect }) {
10480
10545
  }), lowStock2 && jsx("span", {
10481
10546
  className: styles$f.stockBadge,
10482
10547
  "aria-hidden": "true",
10483
- children: `${c.remaining} left`
10548
+ children: t("{0} left", c.remaining)
10484
10549
  })]
10485
10550
  }, c.value);
10486
10551
  })
@@ -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,6 +6164,7 @@ 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}",
@@ -7583,9 +7588,6 @@ const RETURN_REASONS = [{
7583
7588
  }, {
7584
7589
  value: "not_as_described",
7585
7590
  label: "Item doesn't match description"
7586
- }, {
7587
- value: "changed_my_mind",
7588
- label: "Changed my mind"
7589
7591
  }];
7590
7592
  const REASON_LABEL = new Map(RETURN_REASONS.map((r) => [r.value, r.label]));
7591
7593
  function unitsLeft(item2) {
@@ -7746,8 +7748,61 @@ const styles$A = {
7746
7748
  download,
7747
7749
  note: note$1
7748
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
+ }
7749
7803
  function ReturnLabelView({ ret, onDone }) {
7750
7804
  const t = useT();
7805
+ const { preparing, unavailable, onDownload } = useLabelDownload(ret.label_url);
7751
7806
  return jsxs("div", {
7752
7807
  className: styles$A.page,
7753
7808
  children: [jsxs("div", {
@@ -7788,10 +7843,17 @@ function ReturnLabelView({ ret, onDone }) {
7788
7843
  href: ret.label_url,
7789
7844
  target: "_blank",
7790
7845
  rel: "noopener noreferrer",
7791
- 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", {
7792
7850
  className: "visually-hidden",
7793
7851
  children: ` ${t("(opens in a new tab)")}`
7794
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.")
7795
7857
  }), ret.label_email && jsxs("p", {
7796
7858
  className: styles$A.note,
7797
7859
  children: [t("You’ll receive a shipping label PDF to your email as well."), jsx("br", {}), ret.label_email]
@@ -8150,7 +8212,7 @@ function OrderTrackingContent({ orderRef, locale: localeProp, onStartReturn, onO
8150
8212
  useEffect(() => {
8151
8213
  void load();
8152
8214
  }, [load]);
8153
- const cancelled = order?.status === "cancelled";
8215
+ const cancelled = state === "ready" && order?.status === "cancelled";
8154
8216
  const cancelledPage = useRef(null);
8155
8217
  useBrowserLayoutEffect(() => {
8156
8218
  if (!cancelled) return;
@@ -8784,6 +8846,7 @@ function ReturnCard({ ret, locale, onOpen }) {
8784
8846
  });
8785
8847
  }
8786
8848
  function ReturnThumbnails({ ret }) {
8849
+ const t = useT();
8787
8850
  const images = ret.images ?? [];
8788
8851
  const hidden = ret.item_count - TILES + 1;
8789
8852
  const overflow = images.length >= TILES && hidden > 1 ? hidden : 0;
@@ -8815,7 +8878,7 @@ function ReturnThumbnails({ ret }) {
8815
8878
  children: ["+", overflow]
8816
8879
  }), jsx("span", {
8817
8880
  className: "visually-hidden",
8818
- children: `and ${overflow} more items`
8881
+ children: t("and {0} more items", overflow)
8819
8882
  })]
8820
8883
  })]
8821
8884
  }, `${src}-${i}`);
@@ -8823,6 +8886,7 @@ function ReturnThumbnails({ ret }) {
8823
8886
  });
8824
8887
  }
8825
8888
  function OrderCard({ order, locale, onOpen }) {
8889
+ const t = useT();
8826
8890
  const body3 = jsxs(Fragment, {
8827
8891
  children: [jsxs("div", {
8828
8892
  className: styles$v.head,
@@ -8830,7 +8894,7 @@ function OrderCard({ order, locale, onOpen }) {
8830
8894
  className: styles$v.heading,
8831
8895
  children: [jsx("span", {
8832
8896
  className: styles$v.title,
8833
- children: `Order #${shortRef(order.order_ref)}`
8897
+ children: t("Order #{0}", shortRef(order.order_ref))
8834
8898
  }), jsx("span", {
8835
8899
  className: styles$v.date,
8836
8900
  children: formatPlaced(order.placed_at, locale)
@@ -8861,6 +8925,7 @@ function OrderCard({ order, locale, onOpen }) {
8861
8925
  });
8862
8926
  }
8863
8927
  function Thumbnails({ order }) {
8928
+ const t = useT();
8864
8929
  const images = order.images ?? (order.image ? [order.image] : []);
8865
8930
  const hidden = order.item_count - TILES + 1;
8866
8931
  const overflow = images.length >= TILES && hidden > 1 ? hidden : 0;
@@ -8892,7 +8957,7 @@ function Thumbnails({ order }) {
8892
8957
  children: ["+", overflow]
8893
8958
  }), jsx("span", {
8894
8959
  className: "visually-hidden",
8895
- children: `and ${overflow} more items`
8960
+ children: t("and {0} more items", overflow)
8896
8961
  })]
8897
8962
  })]
8898
8963
  }, `${src}-${i}`);
@@ -10480,7 +10545,7 @@ function ColorSelector({ colours, selected: selected2, onSelect }) {
10480
10545
  }), lowStock2 && jsx("span", {
10481
10546
  className: styles$f.stockBadge,
10482
10547
  "aria-hidden": "true",
10483
- children: `${c.remaining} left`
10548
+ children: t("{0} left", c.remaining)
10484
10549
  })]
10485
10550
  }, c.value);
10486
10551
  })
@@ -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.15",
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",