@nok-integration/storefront-react 0.29.11 → 0.29.12

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
@@ -5289,7 +5289,7 @@ declare class ProductCache {
5289
5289
  * the size error). Add-to-cart calls the engine through the session so a 401 silently
5290
5290
  * re-handshakes.
5291
5291
  */
5292
- export declare function ProductDetail({ product, inventory, recommendations, claim, breadcrumb, help, }: ProductDetailProps): JSX.Element;
5292
+ export declare function ProductDetail({ product, inventory, recommendations, claim, breadcrumb, help, initialVariantSku, }: ProductDetailProps): JSX.Element;
5293
5293
 
5294
5294
  export declare interface ProductDetailProps {
5295
5295
  product: Product;
@@ -5303,6 +5303,7 @@ export declare interface ProductDetailProps {
5303
5303
  claim?: (sku: string) => Promise<void>;
5304
5304
  breadcrumb?: ReactNode;
5305
5305
  help?: ReactNode;
5306
+ initialVariantSku?: string;
5306
5307
  }
5307
5308
 
5308
5309
  /**
package/dist/index.mjs CHANGED
@@ -5692,6 +5692,72 @@ function withAuthorization(init, token) {
5692
5692
  headers
5693
5693
  };
5694
5694
  }
5695
+ const KEY = "dazn-shop.set-aside";
5696
+ const KEPT_FOR = 30 * 24 * 60 * 60 * 1e3;
5697
+ function read() {
5698
+ try {
5699
+ const raw = localStorage.getItem(KEY);
5700
+ if (!raw) return null;
5701
+ const value2 = JSON.parse(raw);
5702
+ if (!Array.isArray(value2.lines) || typeof value2.at !== "number") return null;
5703
+ if (Date.now() - value2.at > KEPT_FOR) {
5704
+ localStorage.removeItem(KEY);
5705
+ return null;
5706
+ }
5707
+ const lines2 = value2.lines.filter((l) => !!l && typeof l.sku === "string" && Number.isInteger(l.qty) && l.qty > 0);
5708
+ return {
5709
+ lines: lines2,
5710
+ armed: value2.armed === true,
5711
+ at: value2.at
5712
+ };
5713
+ } catch {
5714
+ return null;
5715
+ }
5716
+ }
5717
+ function write(value2) {
5718
+ try {
5719
+ if (value2) localStorage.setItem(KEY, JSON.stringify(value2));
5720
+ else localStorage.removeItem(KEY);
5721
+ } catch {
5722
+ return;
5723
+ }
5724
+ }
5725
+ function setAside(lines2) {
5726
+ if (lines2.length === 0 || read()) return;
5727
+ write({
5728
+ lines: lines2,
5729
+ armed: false,
5730
+ at: Date.now()
5731
+ });
5732
+ }
5733
+ function armSetAside() {
5734
+ const stored2 = read();
5735
+ if (stored2) write({
5736
+ ...stored2,
5737
+ armed: true
5738
+ });
5739
+ }
5740
+ let restoring = false;
5741
+ async function restoreSetAside(cart2, writer, query, { force = false } = {}) {
5742
+ const stored2 = read();
5743
+ if (!stored2 || restoring) return cart2;
5744
+ if (!force && (!stored2.armed || cart2.vip)) return cart2;
5745
+ restoring = true;
5746
+ write(null);
5747
+ let latest = cart2;
5748
+ try {
5749
+ for (const line2 of stored2.lines) {
5750
+ if (latest.items.some((i) => i.sku === line2.sku)) continue;
5751
+ latest = await writer.addItem({
5752
+ sku: line2.sku,
5753
+ qty: line2.qty
5754
+ }, query).catch(() => latest);
5755
+ }
5756
+ } finally {
5757
+ restoring = false;
5758
+ }
5759
+ return latest;
5760
+ }
5695
5761
  const ScreenTitleContext = createContext({
5696
5762
  title: void 0,
5697
5763
  trailing: "default",
@@ -5885,24 +5951,24 @@ function DaznShopProvider({ children, ...config }) {
5885
5951
  carts.set(cart2);
5886
5952
  return cart2;
5887
5953
  };
5888
- const read = (fn) => (...args) => {
5954
+ const read2 = (fn) => (...args) => {
5889
5955
  const before = carts.revision;
5890
5956
  return fn(...args).then((cart2) => carts.revision === before ? remember2(cart2) : cart2);
5891
5957
  };
5892
- const write = (fn) => (...args) => fn(...args).then(remember2);
5958
+ const write2 = (fn) => (...args) => fn(...args).then(remember2);
5893
5959
  return {
5894
5960
  ...client2,
5895
5961
  cart: {
5896
5962
  ...client2.cart,
5897
- create: read(client2.cart.create),
5898
- get: read(client2.cart.get),
5899
- addItem: write(client2.cart.addItem),
5900
- updateItem: write(client2.cart.updateItem),
5901
- removeItem: write(client2.cart.removeItem)
5963
+ create: read2(client2.cart.create),
5964
+ get: (...args) => read2(client2.cart.get)(...args).then((cart2) => restoreSetAside(cart2, client2.cart, args[0]).then((latest) => latest === cart2 ? cart2 : remember2(latest))),
5965
+ addItem: write2(client2.cart.addItem),
5966
+ updateItem: write2(client2.cart.updateItem),
5967
+ removeItem: write2(client2.cart.removeItem)
5902
5968
  },
5903
5969
  vip: {
5904
5970
  ...client2.vip,
5905
- addToCart: write(client2.vip.addToCart)
5971
+ addToCart: write2(client2.vip.addToCart)
5906
5972
  }
5907
5973
  };
5908
5974
  }, [client2, carts]);
@@ -12234,7 +12300,7 @@ const styles$e = {
12234
12300
  cta: cta$3,
12235
12301
  shop
12236
12302
  };
12237
- function ProductDetail({ product, inventory: inventory2, recommendations = [], claim, breadcrumb: breadcrumb2, help: help2 }) {
12303
+ function ProductDetail({ product, inventory: inventory2, recommendations = [], claim, breadcrumb: breadcrumb2, help: help2, initialVariantSku }) {
12238
12304
  const t = useT();
12239
12305
  const toast2 = useToast();
12240
12306
  const { api, emit } = useShop();
@@ -12266,11 +12332,12 @@ function ProductDetail({ product, inventory: inventory2, recommendations = [], c
12266
12332
  const hasSizes = useMemo(() => sizeOptions(variants).length > 0, [variants]);
12267
12333
  const hasColours = baseColours.length > 0;
12268
12334
  const structured = hasSizes || hasColours;
12269
- const [selectedSize, setSelectedSize] = useState(null);
12270
- const [selectedColour, setSelectedColour] = useState(hasColours ? baseColours.find((c) => c.available)?.value ?? baseColours[0].value : null);
12335
+ const preselected = initialVariantSku ? variants.find((v) => v.sku === initialVariantSku) : void 0;
12336
+ const [selectedSize, setSelectedSize] = useState(preselected?.attributes.size ?? null);
12337
+ const [selectedColour, setSelectedColour] = useState(preselected?.attributes.colour ?? preselected?.attributes.color ?? (hasColours ? baseColours.find((c) => c.available)?.value ?? baseColours[0].value : null));
12271
12338
  const sizes2 = useMemo(() => sizeOptions(variants, selectedColour), [variants, selectedColour]);
12272
12339
  const colours = useMemo(() => colourOptions(variants, selectedSize), [variants, selectedSize]);
12273
- const [genericSku, setGenericSku] = useState(null);
12340
+ const [genericSku, setGenericSku] = useState(preselected && !structured ? preselected.sku : null);
12274
12341
  const [busy, setBusy] = useState(null);
12275
12342
  const [sizeError, setSizeError] = useState(false);
12276
12343
  const [reminded, setReminded] = useState([]);
@@ -13323,9 +13390,12 @@ function ProductView({ sku, initialData, showRecommendations = true, onNotFound
13323
13390
  if (product) {
13324
13391
  return jsx(ProductDetail, {
13325
13392
  product,
13393
+ ...sku === product.sku ? {} : {
13394
+ initialVariantSku: sku
13395
+ },
13326
13396
  inventory: inventory2,
13327
13397
  recommendations
13328
- }, product.sku);
13398
+ }, sku === product.sku ? product.sku : `${product.sku}:${sku}`);
13329
13399
  }
13330
13400
  if (loading) return jsx(ScreenSkeleton, {
13331
13401
  tone: "light"
@@ -15137,8 +15207,12 @@ function ActiveLanding({ token, invite, screen: screen2 }) {
15137
15207
  }
15138
15208
  try {
15139
15209
  const current2 = await api.cart.get().catch(() => null);
15140
- if (current2?.vip?.invite_ref === invite.invite_ref) {
15141
- for (const line2 of current2.items) await api.cart.removeItem(line2.sku);
15210
+ if (current2 && current2.items.length > 0) {
15211
+ if (!current2.vip) setAside(current2.items.map((line2) => ({
15212
+ sku: line2.sku,
15213
+ qty: line2.qty
15214
+ })));
15215
+ for (const line2 of current2.items) await api.cart.removeItem(line2.sku).catch(() => null);
15142
15216
  }
15143
15217
  const target = locatorOf(token);
15144
15218
  if (!target) throw new Error("invalid invite link");
@@ -15147,6 +15221,7 @@ function ActiveLanding({ token, invite, screen: screen2 }) {
15147
15221
  sku: variantSku,
15148
15222
  qty: 1
15149
15223
  });
15224
+ armSetAside();
15150
15225
  emit({
15151
15226
  type: "cart_updated",
15152
15227
  itemCount: cart2.items.reduce((n, i) => n + i.qty, 0),
@@ -15161,6 +15236,10 @@ function ActiveLanding({ token, invite, screen: screen2 }) {
15161
15236
  window.location.assign(checkout_url);
15162
15237
  } catch (err) {
15163
15238
  const code = codeOf(err);
15239
+ const now = await api.cart.get().catch(() => null);
15240
+ if (now && !now.vip) await restoreSetAside(now, api.cart, void 0, {
15241
+ force: true
15242
+ });
15164
15243
  if (code === "unauthorized") {
15165
15244
  emit({
15166
15245
  type: "session_required",
@@ -15323,7 +15402,7 @@ function useDocumentSnap(ref, enabled = true) {
15323
15402
  };
15324
15403
  let at = TOP;
15325
15404
  let returning = false;
15326
- let restoring = false;
15405
+ let restoring2 = false;
15327
15406
  let holding = false;
15328
15407
  const settle = () => {
15329
15408
  returning = false;
@@ -15340,13 +15419,13 @@ function useDocumentSnap(ref, enabled = true) {
15340
15419
  release();
15341
15420
  const back = returnOffset(here());
15342
15421
  returning = back !== null;
15343
- restoring = returning;
15422
+ restoring2 = returning;
15344
15423
  at = back ?? TOP;
15345
15424
  holding = true;
15346
15425
  if (frame2 !== null && typeof window.cancelAnimationFrame === "function") {
15347
15426
  window.cancelAnimationFrame(frame2);
15348
15427
  }
15349
- if (restoring) snapOn();
15428
+ if (restoring2) snapOn();
15350
15429
  else snapOff();
15351
15430
  top2();
15352
15431
  frame2 = typeof window.requestAnimationFrame === "function" ? window.requestAnimationFrame(() => {
@@ -15354,7 +15433,7 @@ function useDocumentSnap(ref, enabled = true) {
15354
15433
  snapOn();
15355
15434
  }) : null;
15356
15435
  release = anchorTop(() => {
15357
- if (snapping && !restoring) {
15436
+ if (snapping && !restoring2) {
15358
15437
  const layout = layoutOf();
15359
15438
  if (layout !== snappedLayout) {
15360
15439
  snappedLayout = layout;
@@ -16333,17 +16412,17 @@ function useScrolledUnder(enabled) {
16333
16412
  const [scrolled2, setScrolled] = useState(false);
16334
16413
  useEffect(() => {
16335
16414
  if (!enabled) return;
16336
- const read = (event) => {
16415
+ const read2 = (event) => {
16337
16416
  const target = event?.target;
16338
16417
  const top2 = target && target !== document && target instanceof HTMLElement ? target.scrollTop : window.scrollY || document.documentElement.scrollTop;
16339
16418
  setScrolled(top2 > 0);
16340
16419
  };
16341
- read();
16342
- document.addEventListener("scroll", read, {
16420
+ read2();
16421
+ document.addEventListener("scroll", read2, {
16343
16422
  capture: true,
16344
16423
  passive: true
16345
16424
  });
16346
- return () => document.removeEventListener("scroll", read, {
16425
+ return () => document.removeEventListener("scroll", read2, {
16347
16426
  capture: true
16348
16427
  });
16349
16428
  }, [enabled]);
@@ -5692,6 +5692,72 @@ function withAuthorization(init, token) {
5692
5692
  headers
5693
5693
  };
5694
5694
  }
5695
+ const KEY = "dazn-shop.set-aside";
5696
+ const KEPT_FOR = 30 * 24 * 60 * 60 * 1e3;
5697
+ function read() {
5698
+ try {
5699
+ const raw = localStorage.getItem(KEY);
5700
+ if (!raw) return null;
5701
+ const value2 = JSON.parse(raw);
5702
+ if (!Array.isArray(value2.lines) || typeof value2.at !== "number") return null;
5703
+ if (Date.now() - value2.at > KEPT_FOR) {
5704
+ localStorage.removeItem(KEY);
5705
+ return null;
5706
+ }
5707
+ const lines2 = value2.lines.filter((l) => !!l && typeof l.sku === "string" && Number.isInteger(l.qty) && l.qty > 0);
5708
+ return {
5709
+ lines: lines2,
5710
+ armed: value2.armed === true,
5711
+ at: value2.at
5712
+ };
5713
+ } catch {
5714
+ return null;
5715
+ }
5716
+ }
5717
+ function write(value2) {
5718
+ try {
5719
+ if (value2) localStorage.setItem(KEY, JSON.stringify(value2));
5720
+ else localStorage.removeItem(KEY);
5721
+ } catch {
5722
+ return;
5723
+ }
5724
+ }
5725
+ function setAside(lines2) {
5726
+ if (lines2.length === 0 || read()) return;
5727
+ write({
5728
+ lines: lines2,
5729
+ armed: false,
5730
+ at: Date.now()
5731
+ });
5732
+ }
5733
+ function armSetAside() {
5734
+ const stored2 = read();
5735
+ if (stored2) write({
5736
+ ...stored2,
5737
+ armed: true
5738
+ });
5739
+ }
5740
+ let restoring = false;
5741
+ async function restoreSetAside(cart2, writer, query, { force = false } = {}) {
5742
+ const stored2 = read();
5743
+ if (!stored2 || restoring) return cart2;
5744
+ if (!force && (!stored2.armed || cart2.vip)) return cart2;
5745
+ restoring = true;
5746
+ write(null);
5747
+ let latest = cart2;
5748
+ try {
5749
+ for (const line2 of stored2.lines) {
5750
+ if (latest.items.some((i) => i.sku === line2.sku)) continue;
5751
+ latest = await writer.addItem({
5752
+ sku: line2.sku,
5753
+ qty: line2.qty
5754
+ }, query).catch(() => latest);
5755
+ }
5756
+ } finally {
5757
+ restoring = false;
5758
+ }
5759
+ return latest;
5760
+ }
5695
5761
  const ScreenTitleContext = createContext({
5696
5762
  title: void 0,
5697
5763
  trailing: "default",
@@ -5885,24 +5951,24 @@ function DaznShopProvider({ children, ...config }) {
5885
5951
  carts.set(cart2);
5886
5952
  return cart2;
5887
5953
  };
5888
- const read = (fn) => (...args) => {
5954
+ const read2 = (fn) => (...args) => {
5889
5955
  const before = carts.revision;
5890
5956
  return fn(...args).then((cart2) => carts.revision === before ? remember2(cart2) : cart2);
5891
5957
  };
5892
- const write = (fn) => (...args) => fn(...args).then(remember2);
5958
+ const write2 = (fn) => (...args) => fn(...args).then(remember2);
5893
5959
  return {
5894
5960
  ...client2,
5895
5961
  cart: {
5896
5962
  ...client2.cart,
5897
- create: read(client2.cart.create),
5898
- get: read(client2.cart.get),
5899
- addItem: write(client2.cart.addItem),
5900
- updateItem: write(client2.cart.updateItem),
5901
- removeItem: write(client2.cart.removeItem)
5963
+ create: read2(client2.cart.create),
5964
+ get: (...args) => read2(client2.cart.get)(...args).then((cart2) => restoreSetAside(cart2, client2.cart, args[0]).then((latest) => latest === cart2 ? cart2 : remember2(latest))),
5965
+ addItem: write2(client2.cart.addItem),
5966
+ updateItem: write2(client2.cart.updateItem),
5967
+ removeItem: write2(client2.cart.removeItem)
5902
5968
  },
5903
5969
  vip: {
5904
5970
  ...client2.vip,
5905
- addToCart: write(client2.vip.addToCart)
5971
+ addToCart: write2(client2.vip.addToCart)
5906
5972
  }
5907
5973
  };
5908
5974
  }, [client2, carts]);
@@ -12234,7 +12300,7 @@ const styles$e = {
12234
12300
  cta: cta$3,
12235
12301
  shop
12236
12302
  };
12237
- function ProductDetail({ product, inventory: inventory2, recommendations = [], claim, breadcrumb: breadcrumb2, help: help2 }) {
12303
+ function ProductDetail({ product, inventory: inventory2, recommendations = [], claim, breadcrumb: breadcrumb2, help: help2, initialVariantSku }) {
12238
12304
  const t = useT();
12239
12305
  const toast2 = useToast();
12240
12306
  const { api, emit } = useShop();
@@ -12266,11 +12332,12 @@ function ProductDetail({ product, inventory: inventory2, recommendations = [], c
12266
12332
  const hasSizes = useMemo(() => sizeOptions(variants).length > 0, [variants]);
12267
12333
  const hasColours = baseColours.length > 0;
12268
12334
  const structured = hasSizes || hasColours;
12269
- const [selectedSize, setSelectedSize] = useState(null);
12270
- const [selectedColour, setSelectedColour] = useState(hasColours ? baseColours.find((c) => c.available)?.value ?? baseColours[0].value : null);
12335
+ const preselected = initialVariantSku ? variants.find((v) => v.sku === initialVariantSku) : void 0;
12336
+ const [selectedSize, setSelectedSize] = useState(preselected?.attributes.size ?? null);
12337
+ const [selectedColour, setSelectedColour] = useState(preselected?.attributes.colour ?? preselected?.attributes.color ?? (hasColours ? baseColours.find((c) => c.available)?.value ?? baseColours[0].value : null));
12271
12338
  const sizes2 = useMemo(() => sizeOptions(variants, selectedColour), [variants, selectedColour]);
12272
12339
  const colours = useMemo(() => colourOptions(variants, selectedSize), [variants, selectedSize]);
12273
- const [genericSku, setGenericSku] = useState(null);
12340
+ const [genericSku, setGenericSku] = useState(preselected && !structured ? preselected.sku : null);
12274
12341
  const [busy, setBusy] = useState(null);
12275
12342
  const [sizeError, setSizeError] = useState(false);
12276
12343
  const [reminded, setReminded] = useState([]);
@@ -13323,9 +13390,12 @@ function ProductView({ sku, initialData, showRecommendations = true, onNotFound
13323
13390
  if (product) {
13324
13391
  return jsx(ProductDetail, {
13325
13392
  product,
13393
+ ...sku === product.sku ? {} : {
13394
+ initialVariantSku: sku
13395
+ },
13326
13396
  inventory: inventory2,
13327
13397
  recommendations
13328
- }, product.sku);
13398
+ }, sku === product.sku ? product.sku : `${product.sku}:${sku}`);
13329
13399
  }
13330
13400
  if (loading) return jsx(ScreenSkeleton, {
13331
13401
  tone: "light"
@@ -15137,8 +15207,12 @@ function ActiveLanding({ token, invite, screen: screen2 }) {
15137
15207
  }
15138
15208
  try {
15139
15209
  const current2 = await api.cart.get().catch(() => null);
15140
- if (current2?.vip?.invite_ref === invite.invite_ref) {
15141
- for (const line2 of current2.items) await api.cart.removeItem(line2.sku);
15210
+ if (current2 && current2.items.length > 0) {
15211
+ if (!current2.vip) setAside(current2.items.map((line2) => ({
15212
+ sku: line2.sku,
15213
+ qty: line2.qty
15214
+ })));
15215
+ for (const line2 of current2.items) await api.cart.removeItem(line2.sku).catch(() => null);
15142
15216
  }
15143
15217
  const target = locatorOf(token);
15144
15218
  if (!target) throw new Error("invalid invite link");
@@ -15147,6 +15221,7 @@ function ActiveLanding({ token, invite, screen: screen2 }) {
15147
15221
  sku: variantSku,
15148
15222
  qty: 1
15149
15223
  });
15224
+ armSetAside();
15150
15225
  emit({
15151
15226
  type: "cart_updated",
15152
15227
  itemCount: cart2.items.reduce((n, i) => n + i.qty, 0),
@@ -15161,6 +15236,10 @@ function ActiveLanding({ token, invite, screen: screen2 }) {
15161
15236
  window.location.assign(checkout_url);
15162
15237
  } catch (err) {
15163
15238
  const code = codeOf(err);
15239
+ const now = await api.cart.get().catch(() => null);
15240
+ if (now && !now.vip) await restoreSetAside(now, api.cart, void 0, {
15241
+ force: true
15242
+ });
15164
15243
  if (code === "unauthorized") {
15165
15244
  emit({
15166
15245
  type: "session_required",
@@ -15323,7 +15402,7 @@ function useDocumentSnap(ref, enabled = true) {
15323
15402
  };
15324
15403
  let at = TOP;
15325
15404
  let returning = false;
15326
- let restoring = false;
15405
+ let restoring2 = false;
15327
15406
  let holding = false;
15328
15407
  const settle = () => {
15329
15408
  returning = false;
@@ -15340,13 +15419,13 @@ function useDocumentSnap(ref, enabled = true) {
15340
15419
  release();
15341
15420
  const back = returnOffset(here());
15342
15421
  returning = back !== null;
15343
- restoring = returning;
15422
+ restoring2 = returning;
15344
15423
  at = back ?? TOP;
15345
15424
  holding = true;
15346
15425
  if (frame2 !== null && typeof window.cancelAnimationFrame === "function") {
15347
15426
  window.cancelAnimationFrame(frame2);
15348
15427
  }
15349
- if (restoring) snapOn();
15428
+ if (restoring2) snapOn();
15350
15429
  else snapOff();
15351
15430
  top2();
15352
15431
  frame2 = typeof window.requestAnimationFrame === "function" ? window.requestAnimationFrame(() => {
@@ -15354,7 +15433,7 @@ function useDocumentSnap(ref, enabled = true) {
15354
15433
  snapOn();
15355
15434
  }) : null;
15356
15435
  release = anchorTop(() => {
15357
- if (snapping && !restoring) {
15436
+ if (snapping && !restoring2) {
15358
15437
  const layout = layoutOf();
15359
15438
  if (layout !== snappedLayout) {
15360
15439
  snappedLayout = layout;
@@ -16333,17 +16412,17 @@ function useScrolledUnder(enabled) {
16333
16412
  const [scrolled2, setScrolled] = useState(false);
16334
16413
  useEffect(() => {
16335
16414
  if (!enabled) return;
16336
- const read = (event) => {
16415
+ const read2 = (event) => {
16337
16416
  const target = event?.target;
16338
16417
  const top2 = target && target !== document && target instanceof HTMLElement ? target.scrollTop : window.scrollY || document.documentElement.scrollTop;
16339
16418
  setScrolled(top2 > 0);
16340
16419
  };
16341
- read();
16342
- document.addEventListener("scroll", read, {
16420
+ read2();
16421
+ document.addEventListener("scroll", read2, {
16343
16422
  capture: true,
16344
16423
  passive: true
16345
16424
  });
16346
- return () => document.removeEventListener("scroll", read, {
16425
+ return () => document.removeEventListener("scroll", read2, {
16347
16426
  capture: true
16348
16427
  });
16349
16428
  }, [enabled]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nok-integration/storefront-react",
3
- "version": "0.29.11",
3
+ "version": "0.29.12",
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",