@aforoai/storefront-widgets 1.0.4 → 1.0.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.
@@ -6,7 +6,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
6
  // src/vue/index.ts
7
7
 
8
8
  // src/core/version.ts
9
- var VERSION = "1.0.4";
9
+ var VERSION = "1.0.5";
10
10
 
11
11
  // src/core/AforoEmbed.ts
12
12
  var mountedElements = /* @__PURE__ */ new WeakMap();
@@ -526,7 +526,8 @@ var _BridgeClient = class _BridgeClient {
526
526
  throw await this.parseError(resp);
527
527
  }
528
528
  const body = await resp.json();
529
- if (!body.sessionJwt || typeof body.expiresAt !== "number") {
529
+ const data = body?.data ?? body;
530
+ if (!data || !data.sessionJwt || typeof data.expiresAt !== "number") {
530
531
  throw new BridgeClientError(
531
532
  "Malformed bridge exchange response",
532
533
  500,
@@ -535,9 +536,9 @@ var _BridgeClient = class _BridgeClient {
535
536
  );
536
537
  }
537
538
  return {
538
- sessionJwt: body.sessionJwt,
539
- expiresAt: body.expiresAt,
540
- customerId: body.customerId ?? null
539
+ sessionJwt: data.sessionJwt,
540
+ expiresAt: data.expiresAt,
541
+ customerId: data.customerId ?? null
541
542
  };
542
543
  }
543
544
  /**
@@ -623,16 +624,17 @@ var _BridgeClient = class _BridgeClient {
623
624
  try {
624
625
  const body = await resp.json();
625
626
  if (!body || typeof body !== "object") return null;
627
+ const data = body.data ?? body;
626
628
  return {
627
- tenantSlug: body.tenantSlug,
629
+ tenantSlug: data.tenantSlug,
628
630
  branding: {
629
- primaryColor: body.primaryColor ?? null,
630
- secondaryColor: body.secondaryColor ?? null,
631
- logoUrl: body.logoUrl ?? null,
632
- fontFamily: body.fontFamily ?? null
631
+ primaryColor: data.primaryColor ?? null,
632
+ secondaryColor: data.secondaryColor ?? null,
633
+ logoUrl: data.logoUrl ?? null,
634
+ fontFamily: data.fontFamily ?? null
633
635
  },
634
- offerings: Array.isArray(body.offerings) ? body.offerings : [],
635
- embeddableWidget: body.embeddableWidget ?? null
636
+ offerings: Array.isArray(data.offerings) ? data.offerings : [],
637
+ embeddableWidget: data.embeddableWidget ?? null
636
638
  };
637
639
  } catch {
638
640
  return null;
@@ -777,7 +779,8 @@ var _BridgeClient = class _BridgeClient {
777
779
  false
778
780
  );
779
781
  }
780
- if (!body.checkoutUrl || !body.checkoutSessionId || !body.expiresAt) {
782
+ const data = body?.data ?? body ?? {};
783
+ if (!data.checkoutUrl || !data.checkoutSessionId || !data.expiresAt) {
781
784
  throw new BridgeClientError(
782
785
  "Malformed checkout-initiate response (missing required fields)",
783
786
  500,
@@ -786,9 +789,9 @@ var _BridgeClient = class _BridgeClient {
786
789
  );
787
790
  }
788
791
  return {
789
- checkoutUrl: body.checkoutUrl,
790
- checkoutSessionId: body.checkoutSessionId,
791
- expiresAt: body.expiresAt
792
+ checkoutUrl: data.checkoutUrl,
793
+ checkoutSessionId: data.checkoutSessionId,
794
+ expiresAt: data.expiresAt
792
795
  };
793
796
  }
794
797
  /* ────────────────────────────────────────────────────────────────────
@@ -1596,13 +1599,16 @@ var _BridgeClient = class _BridgeClient {
1596
1599
  if (!resp.ok) return emptyPage;
1597
1600
  try {
1598
1601
  const body = await resp.json();
1599
- if (!body || typeof body !== "object") return emptyPage;
1602
+ if (!body || typeof body !== "object") {
1603
+ return emptyPage;
1604
+ }
1605
+ const data = body.data ?? body;
1600
1606
  return {
1601
- content: Array.isArray(body.content) ? body.content : [],
1602
- totalElements: typeof body.totalElements === "number" && Number.isFinite(body.totalElements) ? body.totalElements : 0,
1603
- totalPages: typeof body.totalPages === "number" && Number.isFinite(body.totalPages) ? body.totalPages : 0,
1604
- page: typeof body.page === "number" && Number.isFinite(body.page) ? body.page : filter.page ?? 0,
1605
- size: typeof body.size === "number" && Number.isFinite(body.size) ? body.size : filter.size ?? 10
1607
+ content: Array.isArray(data.content) ? data.content : [],
1608
+ totalElements: typeof data.totalElements === "number" && Number.isFinite(data.totalElements) ? data.totalElements : 0,
1609
+ totalPages: typeof data.totalPages === "number" && Number.isFinite(data.totalPages) ? data.totalPages : 0,
1610
+ page: typeof data.page === "number" && Number.isFinite(data.page) ? data.page : filter.page ?? 0,
1611
+ size: typeof data.size === "number" && Number.isFinite(data.size) ? data.size : filter.size ?? 10
1606
1612
  };
1607
1613
  } catch {
1608
1614
  return emptyPage;
@@ -3106,6 +3112,20 @@ function safeFormatCurrency(priceCents, currency, locale, intlOverride) {
3106
3112
  return `${currency} ${amount.toFixed(2)}`;
3107
3113
  }
3108
3114
  }
3115
+ function resolveDisplayPrice(offering, locale, intlOverride) {
3116
+ const flat = safeFormatCurrency(offering.priceCents, offering.currency, locale, intlOverride);
3117
+ if (flat !== "\u2014") return { text: flat, unitSuffix: null };
3118
+ const perUnitPlan = offering.ratePlans?.find(
3119
+ (rp) => rp.pricingModel === "PER_UNIT" && rp.perUnitPriceCents != null
3120
+ );
3121
+ if (perUnitPlan) {
3122
+ const unitPrice = safeFormatCurrency(perUnitPlan.perUnitPriceCents, offering.currency, locale, intlOverride);
3123
+ if (unitPrice !== "\u2014") {
3124
+ return { text: unitPrice, unitSuffix: perUnitPlan.unitLabel || "unit" };
3125
+ }
3126
+ }
3127
+ return { text: "\u2014", unitSuffix: null };
3128
+ }
3109
3129
  function localizedName(o) {
3110
3130
  return o.localizedDisplayName || o.name || "(unnamed plan)";
3111
3131
  }
@@ -3509,12 +3529,7 @@ function PlanCard({
3509
3529
  onCtaClick,
3510
3530
  intlOverride
3511
3531
  }) {
3512
- const price = safeFormatCurrency(
3513
- offering.priceCents,
3514
- offering.currency,
3515
- locale,
3516
- intlOverride
3517
- );
3532
+ const { text: price, unitSuffix } = resolveDisplayPrice(offering, locale, intlOverride);
3518
3533
  const isContactSales = price === "\u2014";
3519
3534
  const planName = localizedName(offering);
3520
3535
  const description = localizedDescription(offering);
@@ -3535,7 +3550,7 @@ function PlanCard({
3535
3550
  "div",
3536
3551
  {
3537
3552
  role: "group",
3538
- "aria-label": `${planName}, ${price} per ${offering.billingCycle}`,
3553
+ "aria-label": `${planName}, ${price} per ${unitSuffix ?? offering.billingCycle}`,
3539
3554
  className: `aforo-w-pc-card${featured ? " aforo-w-pc-card-featured" : ""}`,
3540
3555
  style: cardStyle2,
3541
3556
  children: [
@@ -3600,14 +3615,14 @@ function PlanCard({
3600
3615
  children: price
3601
3616
  }
3602
3617
  ),
3603
- !isContactSales && offering.billingCycle ? /* @__PURE__ */ jsxs(
3618
+ !isContactSales && (unitSuffix || offering.billingCycle) ? /* @__PURE__ */ jsxs(
3604
3619
  "span",
3605
3620
  {
3606
3621
  className: "aforo-w-pc-cycle",
3607
3622
  style: { fontSize: 13, color: tokens.textMuted },
3608
3623
  children: [
3609
3624
  "/ ",
3610
- humanCycle(offering.billingCycle)
3625
+ unitSuffix ?? humanCycle(offering.billingCycle)
3611
3626
  ]
3612
3627
  }
3613
3628
  ) : null
@@ -3765,6 +3780,7 @@ function TableLayout({
3765
3780
  /* @__PURE__ */ jsx("th", { scope: "col", style: { ...headerCellStyle, color: tokens.textMuted, fontSize: 12 }, children: /* @__PURE__ */ jsx("span", { className: "aforo-w-pc-sr-only", style: srOnlyStyle, children: "Feature" }) }),
3766
3781
  offerings.map((o) => {
3767
3782
  const featured = offeringIsFeatured(o, featuredOverride);
3783
+ const { text: tablePrice, unitSuffix: tableUnitSuffix } = resolveDisplayPrice(o, locale, intlOverride);
3768
3784
  return /* @__PURE__ */ jsx(
3769
3785
  "th",
3770
3786
  {
@@ -3794,13 +3810,20 @@ function TableLayout({
3794
3810
  children: "Most popular"
3795
3811
  }
3796
3812
  ) : null,
3797
- /* @__PURE__ */ jsx("div", { style: { fontSize: 22, fontWeight: 700 }, children: safeFormatCurrency(o.priceCents, o.currency, locale, intlOverride) }),
3813
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: 22, fontWeight: 700 }, children: [
3814
+ tablePrice,
3815
+ tableUnitSuffix ? /* @__PURE__ */ jsxs("span", { style: { fontSize: 12, fontWeight: 400, color: tokens.textMuted }, children: [
3816
+ " ",
3817
+ "/ ",
3818
+ tableUnitSuffix
3819
+ ] }) : null
3820
+ ] }),
3798
3821
  /* @__PURE__ */ jsx(
3799
3822
  "button",
3800
3823
  {
3801
3824
  type: "button",
3802
3825
  onClick: () => onCtaClick(o),
3803
- "aria-label": `${ctaLabel(o, ctaTextProp, safeFormatCurrency(o.priceCents, o.currency, locale, intlOverride) === "\u2014")} for ${localizedName(o)}`,
3826
+ "aria-label": `${ctaLabel(o, ctaTextProp, tablePrice === "\u2014")} for ${localizedName(o)}`,
3804
3827
  style: {
3805
3828
  inlineSize: "100%",
3806
3829
  padding: "8px 12px",
@@ -3813,7 +3836,7 @@ function TableLayout({
3813
3836
  cursor: "pointer",
3814
3837
  fontFamily: tokens.fontFamily
3815
3838
  },
3816
- children: ctaLabel(o, ctaTextProp, safeFormatCurrency(o.priceCents, o.currency, locale, intlOverride) === "\u2014")
3839
+ children: ctaLabel(o, ctaTextProp, tablePrice === "\u2014")
3817
3840
  }
3818
3841
  )
3819
3842
  ] })