@nok-integration/storefront-react 0.29.3 → 0.29.5

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
@@ -23,15 +23,15 @@ declare type AddCartItemRequest = z.infer<typeof AddCartItemRequest>;
23
23
 
24
24
  /** The `error` member — a machine `code`, a human `message`, and optional `details`. */
25
25
  declare const ApiErrorBody: z.ZodObject<{
26
- code: z.ZodEnum<["invalid_request", "unauthorized", "out_of_stock", "cart_locked", "sku_not_found", "category_not_found", "amount_mismatch", "duplicate_order", "order_not_found", "order_not_cancellable", "cart_not_found", "support_ticket_not_found", "vip_invite_not_found", "vip_cart_conflict", "vip_invite_mismatch", "size_chart_not_found", "forbidden", "invalid_transition", "rate_limited", "server_error"]>;
26
+ code: z.ZodEnum<["invalid_request", "unauthorized", "out_of_stock", "cart_locked", "sku_not_found", "category_not_found", "amount_mismatch", "duplicate_order", "order_not_found", "order_not_cancellable", "cart_not_found", "support_ticket_not_found", "vip_invite_not_found", "vip_cart_conflict", "vip_invite_mismatch", "vip_hero_missing", "size_chart_not_found", "forbidden", "invalid_transition", "rate_limited", "server_error"]>;
27
27
  message: z.ZodString;
28
28
  details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
29
29
  }, "strip", z.ZodTypeAny, {
30
- code: "invalid_request" | "unauthorized" | "out_of_stock" | "cart_locked" | "sku_not_found" | "category_not_found" | "amount_mismatch" | "duplicate_order" | "order_not_found" | "order_not_cancellable" | "cart_not_found" | "support_ticket_not_found" | "vip_invite_not_found" | "vip_cart_conflict" | "vip_invite_mismatch" | "size_chart_not_found" | "forbidden" | "invalid_transition" | "rate_limited" | "server_error";
30
+ code: "invalid_request" | "unauthorized" | "out_of_stock" | "cart_locked" | "sku_not_found" | "category_not_found" | "amount_mismatch" | "duplicate_order" | "order_not_found" | "order_not_cancellable" | "cart_not_found" | "support_ticket_not_found" | "vip_invite_not_found" | "vip_cart_conflict" | "vip_invite_mismatch" | "vip_hero_missing" | "size_chart_not_found" | "forbidden" | "invalid_transition" | "rate_limited" | "server_error";
31
31
  message: string;
32
32
  details?: Record<string, unknown> | undefined;
33
33
  }, {
34
- code: "invalid_request" | "unauthorized" | "out_of_stock" | "cart_locked" | "sku_not_found" | "category_not_found" | "amount_mismatch" | "duplicate_order" | "order_not_found" | "order_not_cancellable" | "cart_not_found" | "support_ticket_not_found" | "vip_invite_not_found" | "vip_cart_conflict" | "vip_invite_mismatch" | "size_chart_not_found" | "forbidden" | "invalid_transition" | "rate_limited" | "server_error";
34
+ code: "invalid_request" | "unauthorized" | "out_of_stock" | "cart_locked" | "sku_not_found" | "category_not_found" | "amount_mismatch" | "duplicate_order" | "order_not_found" | "order_not_cancellable" | "cart_not_found" | "support_ticket_not_found" | "vip_invite_not_found" | "vip_cart_conflict" | "vip_invite_mismatch" | "vip_hero_missing" | "size_chart_not_found" | "forbidden" | "invalid_transition" | "rate_limited" | "server_error";
35
35
  message: string;
36
36
  details?: Record<string, unknown> | undefined;
37
37
  }>;
@@ -3760,7 +3760,7 @@ export declare interface EmptyStateProps {
3760
3760
  * | rate_limited | 429 | too many requests |
3761
3761
  * | server_error | 500 | unexpected error (safe to retry idempotent) |
3762
3762
  */
3763
- declare const ErrorCode: z.ZodEnum<["invalid_request", "unauthorized", "out_of_stock", "cart_locked", "sku_not_found", "category_not_found", "amount_mismatch", "duplicate_order", "order_not_found", "order_not_cancellable", "cart_not_found", "support_ticket_not_found", "vip_invite_not_found", "vip_cart_conflict", "vip_invite_mismatch", "size_chart_not_found", "forbidden", "invalid_transition", "rate_limited", "server_error"]>;
3763
+ declare const ErrorCode: z.ZodEnum<["invalid_request", "unauthorized", "out_of_stock", "cart_locked", "sku_not_found", "category_not_found", "amount_mismatch", "duplicate_order", "order_not_found", "order_not_cancellable", "cart_not_found", "support_ticket_not_found", "vip_invite_not_found", "vip_cart_conflict", "vip_invite_mismatch", "vip_hero_missing", "size_chart_not_found", "forbidden", "invalid_transition", "rate_limited", "server_error"]>;
3764
3764
 
3765
3765
  declare type ErrorCode = z.infer<typeof ErrorCode>;
3766
3766
 
@@ -3783,7 +3783,7 @@ declare type ErrorCode = z.infer<typeof ErrorCode>;
3783
3783
  * | rate_limited | 429 | too many requests |
3784
3784
  * | server_error | 500 | unexpected error (safe to retry idempotent) |
3785
3785
  */
3786
- declare const ErrorCode_2: z.ZodEnum<["invalid_request", "unauthorized", "out_of_stock", "cart_locked", "sku_not_found", "category_not_found", "amount_mismatch", "duplicate_order", "order_not_found", "order_not_cancellable", "cart_not_found", "support_ticket_not_found", "vip_invite_not_found", "vip_cart_conflict", "vip_invite_mismatch", "size_chart_not_found", "forbidden", "invalid_transition", "rate_limited", "server_error"]>;
3786
+ declare const ErrorCode_2: z.ZodEnum<["invalid_request", "unauthorized", "out_of_stock", "cart_locked", "sku_not_found", "category_not_found", "amount_mismatch", "duplicate_order", "order_not_found", "order_not_cancellable", "cart_not_found", "support_ticket_not_found", "vip_invite_not_found", "vip_cart_conflict", "vip_invite_mismatch", "vip_hero_missing", "size_chart_not_found", "forbidden", "invalid_transition", "rate_limited", "server_error"]>;
3787
3787
 
3788
3788
  declare type ErrorCode_2 = z.infer<typeof ErrorCode_2>;
3789
3789
 
@@ -7225,7 +7225,7 @@ declare const VipInviteView: z.ZodDiscriminatedUnion<"state", [z.ZodObject<{
7225
7225
 
7226
7226
  declare type VipInviteView = z.infer<typeof VipInviteView>;
7227
7227
 
7228
- export declare function VipLandingView({ token, onUnavailable }: VipLandingViewProps): JSX.Element;
7228
+ export declare function VipLandingView({ token, onUnavailable, screen }: VipLandingViewProps): JSX.Element;
7229
7229
 
7230
7230
  export declare interface VipLandingViewProps {
7231
7231
  /**
@@ -7235,6 +7235,11 @@ export declare interface VipLandingViewProps {
7235
7235
  token: string;
7236
7236
  /** Replaces the built-in screen for an invite that cannot be claimed. */
7237
7237
  onUnavailable?: (state: VipInviteUnavailableState) => ReactNode;
7238
+ /**
7239
+ * Which screen of the invite this URL is. `hero` is `/vip/<token>`, `product` is
7240
+ * `/vip/<token>/product`. Defaults to `hero`.
7241
+ */
7242
+ screen?: 'hero' | 'product';
7238
7243
  }
7239
7244
 
7240
7245
  /** "Why shop with us" reassurance tiles. */
package/dist/index.mjs CHANGED
@@ -4993,7 +4993,7 @@ function requireErrors$1() {
4993
4993
  });
4994
4994
  exports.ErrorResponse = exports.ApiErrorBody = exports.ERROR_CODE_STATUS = exports.ErrorCode = void 0;
4995
4995
  const zod_1 = requireZod();
4996
- exports.ErrorCode = zod_1.z.enum(["invalid_request", "unauthorized", "out_of_stock", "cart_locked", "sku_not_found", "category_not_found", "amount_mismatch", "duplicate_order", "order_not_found", "order_not_cancellable", "cart_not_found", "support_ticket_not_found", "vip_invite_not_found", "vip_cart_conflict", "vip_invite_mismatch", "size_chart_not_found", "forbidden", "invalid_transition", "rate_limited", "server_error"]);
4996
+ exports.ErrorCode = zod_1.z.enum(["invalid_request", "unauthorized", "out_of_stock", "cart_locked", "sku_not_found", "category_not_found", "amount_mismatch", "duplicate_order", "order_not_found", "order_not_cancellable", "cart_not_found", "support_ticket_not_found", "vip_invite_not_found", "vip_cart_conflict", "vip_invite_mismatch", "vip_hero_missing", "size_chart_not_found", "forbidden", "invalid_transition", "rate_limited", "server_error"]);
4997
4997
  exports.ERROR_CODE_STATUS = {
4998
4998
  invalid_request: 400,
4999
4999
  unauthorized: 401,
@@ -5010,6 +5010,7 @@ function requireErrors$1() {
5010
5010
  vip_invite_not_found: 404,
5011
5011
  vip_cart_conflict: 409,
5012
5012
  vip_invite_mismatch: 409,
5013
+ vip_hero_missing: 422,
5013
5014
  size_chart_not_found: 404,
5014
5015
  forbidden: 403,
5015
5016
  invalid_transition: 409,
@@ -6252,15 +6253,15 @@ const ShopSurface = forwardRef(function ShopSurface2({ tone, fill: fill2 = false
6252
6253
  children
6253
6254
  });
6254
6255
  });
6255
- const root$7 = "_root_ney0g_1";
6256
- const inner = "_inner_ney0g_6";
6257
- const media$5 = "_media_ney0g_20";
6258
- const lines$2 = "_lines_ney0g_32";
6259
- const lineWide = "_lineWide_ney0g_41";
6260
- const lineMid = "_lineMid_ney0g_45";
6261
- const lineNarrow = "_lineNarrow_ney0g_49";
6262
- const row$9 = "_row_ney0g_53";
6263
- const action$2 = "_action_ney0g_57";
6256
+ const root$7 = "_root_l5418_1";
6257
+ const inner = "_inner_l5418_6";
6258
+ const media$5 = "_media_l5418_20";
6259
+ const lines$2 = "_lines_l5418_32";
6260
+ const lineWide = "_lineWide_l5418_41";
6261
+ const lineMid = "_lineMid_l5418_45";
6262
+ const lineNarrow = "_lineNarrow_l5418_49";
6263
+ const row$9 = "_row_l5418_53";
6264
+ const action$2 = "_action_l5418_57";
6264
6265
  const styles$T = {
6265
6266
  root: root$7,
6266
6267
  inner,
@@ -6600,6 +6601,7 @@ function ScreenSkeleton({ tone, shape = "media" }) {
6600
6601
  tone,
6601
6602
  fill: true,
6602
6603
  className: styles$T.root,
6604
+ "data-shop-layout": "wide",
6603
6605
  children: jsx("div", {
6604
6606
  className: styles$T.inner,
6605
6607
  role: "status",
@@ -8082,9 +8084,9 @@ function ReturnItemsView({ order, onSubmit, busy = false }) {
8082
8084
  const t = useT();
8083
8085
  const wide2 = useDesktopLayout();
8084
8086
  useOrderNav([t("My orders"), t("Order #{0}", shortRef$1(order.order_ref))], t("Return items"));
8085
- const layout = wide2 ? {
8087
+ const layout = {
8086
8088
  "data-shop-layout": "wide"
8087
- } : {};
8089
+ };
8088
8090
  const pageClass = [styles$H.page, wide2 ? styles$H.wide : ""].join(" ");
8089
8091
  const returnable = useMemo(() => order.items.filter((i) => unitsLeft(i) > 0), [order.items]);
8090
8092
  const selected2 = Object.entries(chosen).filter(([, reason2]) => reason2 !== void 0);
@@ -8308,9 +8310,7 @@ function ReturnLabelView({ ret, onDone }) {
8308
8310
  useOrderNav([t("My orders"), t("Order #{0}", shortRef$1(ret.order_ref))], t("Return items"));
8309
8311
  return jsx("div", {
8310
8312
  className: [styles$G.page, wide2 ? styles$G.wide : ""].join(" "),
8311
- ...wide2 ? {
8312
- "data-shop-layout": "wide"
8313
- } : {},
8313
+ "data-shop-layout": "wide",
8314
8314
  children: jsxs("div", {
8315
8315
  className: styles$G.main,
8316
8316
  children: [jsxs("div", {
@@ -8456,9 +8456,7 @@ function ReturnTrackingView({ ret, locale: localeProp }) {
8456
8456
  fill: true,
8457
8457
  children: jsxs("div", {
8458
8458
  className: [styles$F.page, wide2 ? styles$F.wide : ""].join(" "),
8459
- ...wide2 ? {
8460
- "data-shop-layout": "wide"
8461
- } : {},
8459
+ "data-shop-layout": "wide",
8462
8460
  children: [jsxs("section", {
8463
8461
  className: styles$F.widget,
8464
8462
  "aria-labelledby": "return-title",
@@ -9206,9 +9204,7 @@ function OrderTrackingContent({ orderRef, locale: localeProp, onStartReturn, onO
9206
9204
  return jsxs("div", {
9207
9205
  className: [styles$D.page, wide2 ? styles$D.wide : "", wide2 && order.vip ? styles$D.vip : ""].join(" "),
9208
9206
  ref: cancelledPage,
9209
- ...wide2 ? {
9210
- "data-shop-layout": "wide"
9211
- } : {},
9207
+ "data-shop-layout": "wide",
9212
9208
  children: [jsxs("div", {
9213
9209
  className: styles$D.cancelledMain,
9214
9210
  children: [jsxs("div", {
@@ -9252,9 +9248,7 @@ function OrderTrackingContent({ orderRef, locale: localeProp, onStartReturn, onO
9252
9248
  }
9253
9249
  return jsxs("div", {
9254
9250
  className: [styles$D.page, wide2 ? styles$D.wide : ""].join(" "),
9255
- ...wide2 ? {
9256
- "data-shop-layout": "wide"
9257
- } : {},
9251
+ "data-shop-layout": "wide",
9258
9252
  children: [jsxs("section", {
9259
9253
  className: styles$D.widget,
9260
9254
  "aria-label": t("Delivery status"),
@@ -9474,9 +9468,7 @@ function OrderConfirmationContent({ orderRef, locale: localeProp, onDone }) {
9474
9468
  }
9475
9469
  return jsxs("div", {
9476
9470
  className: [styles$C.page, wide2 ? styles$C.wide : ""].join(" "),
9477
- ...wide2 ? {
9478
- "data-shop-layout": "wide"
9479
- } : {},
9471
+ "data-shop-layout": "wide",
9480
9472
  children: [jsxs("section", {
9481
9473
  className: styles$C.confirmed,
9482
9474
  "aria-label": t("Order confirmation"),
@@ -14142,7 +14134,7 @@ function requireErrors() {
14142
14134
  });
14143
14135
  exports.ErrorResponse = exports.ApiErrorBody = exports.ERROR_CODE_STATUS = exports.ErrorCode = void 0;
14144
14136
  const zod_1 = requireZod();
14145
- exports.ErrorCode = zod_1.z.enum(["invalid_request", "unauthorized", "out_of_stock", "cart_locked", "sku_not_found", "category_not_found", "amount_mismatch", "duplicate_order", "order_not_found", "order_not_cancellable", "cart_not_found", "support_ticket_not_found", "vip_invite_not_found", "vip_cart_conflict", "vip_invite_mismatch", "size_chart_not_found", "forbidden", "invalid_transition", "rate_limited", "server_error"]);
14137
+ exports.ErrorCode = zod_1.z.enum(["invalid_request", "unauthorized", "out_of_stock", "cart_locked", "sku_not_found", "category_not_found", "amount_mismatch", "duplicate_order", "order_not_found", "order_not_cancellable", "cart_not_found", "support_ticket_not_found", "vip_invite_not_found", "vip_cart_conflict", "vip_invite_mismatch", "vip_hero_missing", "size_chart_not_found", "forbidden", "invalid_transition", "rate_limited", "server_error"]);
14146
14138
  exports.ERROR_CODE_STATUS = {
14147
14139
  invalid_request: 400,
14148
14140
  unauthorized: 401,
@@ -14159,6 +14151,7 @@ function requireErrors() {
14159
14151
  vip_invite_not_found: 404,
14160
14152
  vip_cart_conflict: 409,
14161
14153
  vip_invite_mismatch: 409,
14154
+ vip_hero_missing: 422,
14162
14155
  size_chart_not_found: 404,
14163
14156
  forbidden: 403,
14164
14157
  invalid_transition: 409,
@@ -14902,7 +14895,7 @@ function locatorOf(segment) {
14902
14895
  return null;
14903
14896
  }
14904
14897
  const INVALID_LINK = /* @__PURE__ */ new Set(["invalid_request", "vip_invite_not_found", "vip_invite_mismatch"]);
14905
- function VipLandingView({ token, onUnavailable }) {
14898
+ function VipLandingView({ token, onUnavailable, screen: screen2 = "hero" }) {
14906
14899
  const t = useT();
14907
14900
  const { api, emit } = useShop();
14908
14901
  const locator = locatorOf(token);
@@ -14982,18 +14975,43 @@ function VipLandingView({ token, onUnavailable }) {
14982
14975
  }
14983
14976
  return jsx(ActiveLanding, {
14984
14977
  token,
14985
- invite
14978
+ invite,
14979
+ screen: screen2
14986
14980
  });
14987
14981
  }
14988
- function ActiveLanding({ token, invite }) {
14982
+ function plainFirstLine(description2) {
14983
+ if (!description2) return null;
14984
+ const line2 = description2.replace(/<[^>]*>/g, " ").split(/\n+/).map((l) => l.replace(/\s+/g, " ").trim()).find((l) => l.length > 0);
14985
+ if (!line2) return null;
14986
+ const sentence = /^.*?[.!?](?=\s|$)/.exec(line2);
14987
+ return sentence ? sentence[0] : line2;
14988
+ }
14989
+ function heroFromProduct(product, ctaLabel) {
14990
+ const image2 = product.media[0] ?? null;
14991
+ return {
14992
+ image: image2,
14993
+ desktop_image: image2,
14994
+ headline: product.title,
14995
+ body: plainFirstLine(product.description),
14996
+ cta_label: ctaLabel
14997
+ };
14998
+ }
14999
+ function ActiveLanding({ token, invite, screen: screen2 }) {
14989
15000
  const t = useT();
14990
15001
  const toast2 = useToast();
14991
15002
  const { api, emit } = useShop();
14992
- const product = useInPlaceScreen("vipProduct");
15003
+ const navigate = useNavigate();
14993
15004
  const sku = invite.items[0]?.product_sku ?? "";
14994
15005
  const loaded = useProduct(sku, {
14995
15006
  showRecommendations: false
14996
15007
  });
15008
+ const productPath = `/vip/${token}/product`;
15009
+ const heroPath = `/vip/${token}`;
15010
+ const go = useCallback((to) => {
15011
+ if (navigate) navigate(to);
15012
+ else window.location.assign(to);
15013
+ }, [navigate]);
15014
+ const fallback = useMemo(() => loaded.product ? heroFromProduct(loaded.product, t("See more")) : null, [loaded.product, t]);
14997
15015
  const claim = useCallback(async (variantSku) => {
14998
15016
  try {
14999
15017
  const current2 = await api.cart.get().catch(() => null);
@@ -15036,23 +15054,21 @@ function ActiveLanding({ token, invite }) {
15036
15054
  toast2.show(t(treatmentFor(code).body), "critical");
15037
15055
  }
15038
15056
  }, [api, emit, invite.invite_ref, t, toast2, token]);
15039
- if (invite.hero && product.value === null) {
15040
- return jsx(VipHero, {
15041
- hero: invite.hero,
15042
- onContinue: () => product.open("1")
15057
+ if (screen2 === "hero") {
15058
+ const hero2 = invite.hero ?? fallback;
15059
+ if (hero2) return jsx(VipHero, {
15060
+ hero: hero2,
15061
+ onContinue: () => go(productPath)
15043
15062
  });
15044
- }
15045
- if (loaded.product) {
15063
+ } else if (loaded.product) {
15046
15064
  return jsx(ProductDetail, {
15047
15065
  product: loaded.product,
15048
15066
  inventory: loaded.inventory,
15049
15067
  claim,
15050
- ...invite.hero ? {
15051
- breadcrumb: jsx(VipBreadcrumb, {
15052
- title: loaded.product.title,
15053
- onHome: product.close
15054
- })
15055
- } : {}
15068
+ breadcrumb: jsx(VipBreadcrumb, {
15069
+ title: loaded.product.title,
15070
+ onHome: () => go(heroPath)
15071
+ })
15056
15072
  }, loaded.product.sku);
15057
15073
  }
15058
15074
  if (loaded.loading) return jsx(ScreenSkeleton, {
@@ -4993,7 +4993,7 @@ function requireErrors$1() {
4993
4993
  });
4994
4994
  exports.ErrorResponse = exports.ApiErrorBody = exports.ERROR_CODE_STATUS = exports.ErrorCode = void 0;
4995
4995
  const zod_1 = requireZod();
4996
- exports.ErrorCode = zod_1.z.enum(["invalid_request", "unauthorized", "out_of_stock", "cart_locked", "sku_not_found", "category_not_found", "amount_mismatch", "duplicate_order", "order_not_found", "order_not_cancellable", "cart_not_found", "support_ticket_not_found", "vip_invite_not_found", "vip_cart_conflict", "vip_invite_mismatch", "size_chart_not_found", "forbidden", "invalid_transition", "rate_limited", "server_error"]);
4996
+ exports.ErrorCode = zod_1.z.enum(["invalid_request", "unauthorized", "out_of_stock", "cart_locked", "sku_not_found", "category_not_found", "amount_mismatch", "duplicate_order", "order_not_found", "order_not_cancellable", "cart_not_found", "support_ticket_not_found", "vip_invite_not_found", "vip_cart_conflict", "vip_invite_mismatch", "vip_hero_missing", "size_chart_not_found", "forbidden", "invalid_transition", "rate_limited", "server_error"]);
4997
4997
  exports.ERROR_CODE_STATUS = {
4998
4998
  invalid_request: 400,
4999
4999
  unauthorized: 401,
@@ -5010,6 +5010,7 @@ function requireErrors$1() {
5010
5010
  vip_invite_not_found: 404,
5011
5011
  vip_cart_conflict: 409,
5012
5012
  vip_invite_mismatch: 409,
5013
+ vip_hero_missing: 422,
5013
5014
  size_chart_not_found: 404,
5014
5015
  forbidden: 403,
5015
5016
  invalid_transition: 409,
@@ -6252,15 +6253,15 @@ const ShopSurface = forwardRef(function ShopSurface2({ tone, fill: fill2 = false
6252
6253
  children
6253
6254
  });
6254
6255
  });
6255
- const root$7 = "_root_ney0g_1";
6256
- const inner = "_inner_ney0g_6";
6257
- const media$5 = "_media_ney0g_20";
6258
- const lines$2 = "_lines_ney0g_32";
6259
- const lineWide = "_lineWide_ney0g_41";
6260
- const lineMid = "_lineMid_ney0g_45";
6261
- const lineNarrow = "_lineNarrow_ney0g_49";
6262
- const row$9 = "_row_ney0g_53";
6263
- const action$2 = "_action_ney0g_57";
6256
+ const root$7 = "_root_l5418_1";
6257
+ const inner = "_inner_l5418_6";
6258
+ const media$5 = "_media_l5418_20";
6259
+ const lines$2 = "_lines_l5418_32";
6260
+ const lineWide = "_lineWide_l5418_41";
6261
+ const lineMid = "_lineMid_l5418_45";
6262
+ const lineNarrow = "_lineNarrow_l5418_49";
6263
+ const row$9 = "_row_l5418_53";
6264
+ const action$2 = "_action_l5418_57";
6264
6265
  const styles$T = {
6265
6266
  root: root$7,
6266
6267
  inner,
@@ -6600,6 +6601,7 @@ function ScreenSkeleton({ tone, shape = "media" }) {
6600
6601
  tone,
6601
6602
  fill: true,
6602
6603
  className: styles$T.root,
6604
+ "data-shop-layout": "wide",
6603
6605
  children: jsx("div", {
6604
6606
  className: styles$T.inner,
6605
6607
  role: "status",
@@ -8082,9 +8084,9 @@ function ReturnItemsView({ order, onSubmit, busy = false }) {
8082
8084
  const t = useT();
8083
8085
  const wide2 = useDesktopLayout();
8084
8086
  useOrderNav([t("My orders"), t("Order #{0}", shortRef$1(order.order_ref))], t("Return items"));
8085
- const layout = wide2 ? {
8087
+ const layout = {
8086
8088
  "data-shop-layout": "wide"
8087
- } : {};
8089
+ };
8088
8090
  const pageClass = [styles$H.page, wide2 ? styles$H.wide : ""].join(" ");
8089
8091
  const returnable = useMemo(() => order.items.filter((i) => unitsLeft(i) > 0), [order.items]);
8090
8092
  const selected2 = Object.entries(chosen).filter(([, reason2]) => reason2 !== void 0);
@@ -8308,9 +8310,7 @@ function ReturnLabelView({ ret, onDone }) {
8308
8310
  useOrderNav([t("My orders"), t("Order #{0}", shortRef$1(ret.order_ref))], t("Return items"));
8309
8311
  return jsx("div", {
8310
8312
  className: [styles$G.page, wide2 ? styles$G.wide : ""].join(" "),
8311
- ...wide2 ? {
8312
- "data-shop-layout": "wide"
8313
- } : {},
8313
+ "data-shop-layout": "wide",
8314
8314
  children: jsxs("div", {
8315
8315
  className: styles$G.main,
8316
8316
  children: [jsxs("div", {
@@ -8456,9 +8456,7 @@ function ReturnTrackingView({ ret, locale: localeProp }) {
8456
8456
  fill: true,
8457
8457
  children: jsxs("div", {
8458
8458
  className: [styles$F.page, wide2 ? styles$F.wide : ""].join(" "),
8459
- ...wide2 ? {
8460
- "data-shop-layout": "wide"
8461
- } : {},
8459
+ "data-shop-layout": "wide",
8462
8460
  children: [jsxs("section", {
8463
8461
  className: styles$F.widget,
8464
8462
  "aria-labelledby": "return-title",
@@ -9206,9 +9204,7 @@ function OrderTrackingContent({ orderRef, locale: localeProp, onStartReturn, onO
9206
9204
  return jsxs("div", {
9207
9205
  className: [styles$D.page, wide2 ? styles$D.wide : "", wide2 && order.vip ? styles$D.vip : ""].join(" "),
9208
9206
  ref: cancelledPage,
9209
- ...wide2 ? {
9210
- "data-shop-layout": "wide"
9211
- } : {},
9207
+ "data-shop-layout": "wide",
9212
9208
  children: [jsxs("div", {
9213
9209
  className: styles$D.cancelledMain,
9214
9210
  children: [jsxs("div", {
@@ -9252,9 +9248,7 @@ function OrderTrackingContent({ orderRef, locale: localeProp, onStartReturn, onO
9252
9248
  }
9253
9249
  return jsxs("div", {
9254
9250
  className: [styles$D.page, wide2 ? styles$D.wide : ""].join(" "),
9255
- ...wide2 ? {
9256
- "data-shop-layout": "wide"
9257
- } : {},
9251
+ "data-shop-layout": "wide",
9258
9252
  children: [jsxs("section", {
9259
9253
  className: styles$D.widget,
9260
9254
  "aria-label": t("Delivery status"),
@@ -9474,9 +9468,7 @@ function OrderConfirmationContent({ orderRef, locale: localeProp, onDone }) {
9474
9468
  }
9475
9469
  return jsxs("div", {
9476
9470
  className: [styles$C.page, wide2 ? styles$C.wide : ""].join(" "),
9477
- ...wide2 ? {
9478
- "data-shop-layout": "wide"
9479
- } : {},
9471
+ "data-shop-layout": "wide",
9480
9472
  children: [jsxs("section", {
9481
9473
  className: styles$C.confirmed,
9482
9474
  "aria-label": t("Order confirmation"),
@@ -14142,7 +14134,7 @@ function requireErrors() {
14142
14134
  });
14143
14135
  exports.ErrorResponse = exports.ApiErrorBody = exports.ERROR_CODE_STATUS = exports.ErrorCode = void 0;
14144
14136
  const zod_1 = requireZod();
14145
- exports.ErrorCode = zod_1.z.enum(["invalid_request", "unauthorized", "out_of_stock", "cart_locked", "sku_not_found", "category_not_found", "amount_mismatch", "duplicate_order", "order_not_found", "order_not_cancellable", "cart_not_found", "support_ticket_not_found", "vip_invite_not_found", "vip_cart_conflict", "vip_invite_mismatch", "size_chart_not_found", "forbidden", "invalid_transition", "rate_limited", "server_error"]);
14137
+ exports.ErrorCode = zod_1.z.enum(["invalid_request", "unauthorized", "out_of_stock", "cart_locked", "sku_not_found", "category_not_found", "amount_mismatch", "duplicate_order", "order_not_found", "order_not_cancellable", "cart_not_found", "support_ticket_not_found", "vip_invite_not_found", "vip_cart_conflict", "vip_invite_mismatch", "vip_hero_missing", "size_chart_not_found", "forbidden", "invalid_transition", "rate_limited", "server_error"]);
14146
14138
  exports.ERROR_CODE_STATUS = {
14147
14139
  invalid_request: 400,
14148
14140
  unauthorized: 401,
@@ -14159,6 +14151,7 @@ function requireErrors() {
14159
14151
  vip_invite_not_found: 404,
14160
14152
  vip_cart_conflict: 409,
14161
14153
  vip_invite_mismatch: 409,
14154
+ vip_hero_missing: 422,
14162
14155
  size_chart_not_found: 404,
14163
14156
  forbidden: 403,
14164
14157
  invalid_transition: 409,
@@ -14902,7 +14895,7 @@ function locatorOf(segment) {
14902
14895
  return null;
14903
14896
  }
14904
14897
  const INVALID_LINK = /* @__PURE__ */ new Set(["invalid_request", "vip_invite_not_found", "vip_invite_mismatch"]);
14905
- function VipLandingView({ token, onUnavailable }) {
14898
+ function VipLandingView({ token, onUnavailable, screen: screen2 = "hero" }) {
14906
14899
  const t = useT();
14907
14900
  const { api, emit } = useShop();
14908
14901
  const locator = locatorOf(token);
@@ -14982,18 +14975,43 @@ function VipLandingView({ token, onUnavailable }) {
14982
14975
  }
14983
14976
  return jsx(ActiveLanding, {
14984
14977
  token,
14985
- invite
14978
+ invite,
14979
+ screen: screen2
14986
14980
  });
14987
14981
  }
14988
- function ActiveLanding({ token, invite }) {
14982
+ function plainFirstLine(description2) {
14983
+ if (!description2) return null;
14984
+ const line2 = description2.replace(/<[^>]*>/g, " ").split(/\n+/).map((l) => l.replace(/\s+/g, " ").trim()).find((l) => l.length > 0);
14985
+ if (!line2) return null;
14986
+ const sentence = /^.*?[.!?](?=\s|$)/.exec(line2);
14987
+ return sentence ? sentence[0] : line2;
14988
+ }
14989
+ function heroFromProduct(product, ctaLabel) {
14990
+ const image2 = product.media[0] ?? null;
14991
+ return {
14992
+ image: image2,
14993
+ desktop_image: image2,
14994
+ headline: product.title,
14995
+ body: plainFirstLine(product.description),
14996
+ cta_label: ctaLabel
14997
+ };
14998
+ }
14999
+ function ActiveLanding({ token, invite, screen: screen2 }) {
14989
15000
  const t = useT();
14990
15001
  const toast2 = useToast();
14991
15002
  const { api, emit } = useShop();
14992
- const product = useInPlaceScreen("vipProduct");
15003
+ const navigate = useNavigate();
14993
15004
  const sku = invite.items[0]?.product_sku ?? "";
14994
15005
  const loaded = useProduct(sku, {
14995
15006
  showRecommendations: false
14996
15007
  });
15008
+ const productPath = `/vip/${token}/product`;
15009
+ const heroPath = `/vip/${token}`;
15010
+ const go = useCallback((to) => {
15011
+ if (navigate) navigate(to);
15012
+ else window.location.assign(to);
15013
+ }, [navigate]);
15014
+ const fallback = useMemo(() => loaded.product ? heroFromProduct(loaded.product, t("See more")) : null, [loaded.product, t]);
14997
15015
  const claim = useCallback(async (variantSku) => {
14998
15016
  try {
14999
15017
  const current2 = await api.cart.get().catch(() => null);
@@ -15036,23 +15054,21 @@ function ActiveLanding({ token, invite }) {
15036
15054
  toast2.show(t(treatmentFor(code).body), "critical");
15037
15055
  }
15038
15056
  }, [api, emit, invite.invite_ref, t, toast2, token]);
15039
- if (invite.hero && product.value === null) {
15040
- return jsx(VipHero, {
15041
- hero: invite.hero,
15042
- onContinue: () => product.open("1")
15057
+ if (screen2 === "hero") {
15058
+ const hero2 = invite.hero ?? fallback;
15059
+ if (hero2) return jsx(VipHero, {
15060
+ hero: hero2,
15061
+ onContinue: () => go(productPath)
15043
15062
  });
15044
- }
15045
- if (loaded.product) {
15063
+ } else if (loaded.product) {
15046
15064
  return jsx(ProductDetail, {
15047
15065
  product: loaded.product,
15048
15066
  inventory: loaded.inventory,
15049
15067
  claim,
15050
- ...invite.hero ? {
15051
- breadcrumb: jsx(VipBreadcrumb, {
15052
- title: loaded.product.title,
15053
- onHome: product.close
15054
- })
15055
- } : {}
15068
+ breadcrumb: jsx(VipBreadcrumb, {
15069
+ title: loaded.product.title,
15070
+ onHome: () => go(heroPath)
15071
+ })
15056
15072
  }, loaded.product.sku);
15057
15073
  }
15058
15074
  if (loaded.loading) return jsx(ScreenSkeleton, {
@@ -279,43 +279,56 @@
279
279
  scroll-behavior: auto !important;
280
280
  }
281
281
  }
282
- ._root_ney0g_1 {
282
+ ._root_l5418_1 {
283
283
  display: flex;
284
284
  flex-direction: column;
285
285
  }
286
- ._inner_ney0g_6 {
286
+ ._inner_l5418_6 {
287
287
  display: flex;
288
288
  flex-direction: column;
289
289
  gap: var(--space-16);
290
290
  padding-bottom: var(--space-24);
291
291
  }
292
- ._media_ney0g_20 {
292
+ ._media_l5418_20 {
293
293
  width: 100%;
294
294
  min-height: 320px;
295
295
  aspect-ratio: 4 / 5;
296
296
  border-radius: 0;
297
297
  }
298
- ._lines_ney0g_32 {
298
+ ._lines_l5418_32 {
299
299
  display: flex;
300
300
  flex-direction: column;
301
301
  gap: var(--space-12);
302
302
  padding: 0 var(--space-16);
303
303
  }
304
- ._lineWide_ney0g_41 {
304
+ ._lineWide_l5418_41 {
305
305
  width: 70%;
306
306
  }
307
- ._lineMid_ney0g_45 {
307
+ ._lineMid_l5418_45 {
308
308
  width: 45%;
309
309
  }
310
- ._lineNarrow_ney0g_49 {
310
+ ._lineNarrow_l5418_49 {
311
311
  width: 88%;
312
312
  }
313
- ._row_ney0g_53 {
313
+ ._row_l5418_53 {
314
314
  width: 100%;
315
315
  }
316
- ._action_ney0g_57 {
316
+ ._action_l5418_57 {
317
317
  margin: var(--space-8) var(--space-16) 0;
318
318
  }
319
+ @media (min-width: 1200px) {
320
+ ._media_l5418_20 {
321
+ min-height: 0;
322
+ aspect-ratio: auto;
323
+ height: calc(100vh - var(--shop-chrome-top, 0px) - 64px);
324
+ }
325
+ ._lines_l5418_32,
326
+ ._action_l5418_57 {
327
+ width: min(1088px, 100%);
328
+ margin-inline: auto;
329
+ padding: 0;
330
+ }
331
+ }
319
332
  ._root_ryf3q_6 {
320
333
  display: flex;
321
334
  flex-direction: column;
package/dist/styles.css CHANGED
@@ -279,43 +279,56 @@
279
279
  scroll-behavior: auto !important;
280
280
  }
281
281
  }
282
- ._root_ney0g_1 {
282
+ ._root_l5418_1 {
283
283
  display: flex;
284
284
  flex-direction: column;
285
285
  }
286
- ._inner_ney0g_6 {
286
+ ._inner_l5418_6 {
287
287
  display: flex;
288
288
  flex-direction: column;
289
289
  gap: var(--space-16);
290
290
  padding-bottom: var(--space-24);
291
291
  }
292
- ._media_ney0g_20 {
292
+ ._media_l5418_20 {
293
293
  width: 100%;
294
294
  min-height: 320px;
295
295
  aspect-ratio: 4 / 5;
296
296
  border-radius: 0;
297
297
  }
298
- ._lines_ney0g_32 {
298
+ ._lines_l5418_32 {
299
299
  display: flex;
300
300
  flex-direction: column;
301
301
  gap: var(--space-12);
302
302
  padding: 0 var(--space-16);
303
303
  }
304
- ._lineWide_ney0g_41 {
304
+ ._lineWide_l5418_41 {
305
305
  width: 70%;
306
306
  }
307
- ._lineMid_ney0g_45 {
307
+ ._lineMid_l5418_45 {
308
308
  width: 45%;
309
309
  }
310
- ._lineNarrow_ney0g_49 {
310
+ ._lineNarrow_l5418_49 {
311
311
  width: 88%;
312
312
  }
313
- ._row_ney0g_53 {
313
+ ._row_l5418_53 {
314
314
  width: 100%;
315
315
  }
316
- ._action_ney0g_57 {
316
+ ._action_l5418_57 {
317
317
  margin: var(--space-8) var(--space-16) 0;
318
318
  }
319
+ @media (min-width: 1200px) {
320
+ ._media_l5418_20 {
321
+ min-height: 0;
322
+ aspect-ratio: auto;
323
+ height: calc(100vh - var(--shop-chrome-top, 0px) - 64px);
324
+ }
325
+ ._lines_l5418_32,
326
+ ._action_l5418_57 {
327
+ width: min(1088px, 100%);
328
+ margin-inline: auto;
329
+ padding: 0;
330
+ }
331
+ }
319
332
  ._root_ryf3q_6 {
320
333
  display: flex;
321
334
  flex-direction: column;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nok-integration/storefront-react",
3
- "version": "0.29.3",
3
+ "version": "0.29.5",
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",