@schematichq/schematic-components 2.16.2 → 2.17.1

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/README.md CHANGED
@@ -48,24 +48,34 @@ selection stage.
48
48
  initializeWithPlan('plan_VBXv4bHjSf3');
49
49
  ```
50
50
 
51
- Passing a config object allows pre-selecting Add-ons as well as hiding
52
- specific stages.
51
+ Passing a config object allows pre-selecting Add-ons and pay-in-advance
52
+ quantities, as well as hiding specific stages.
53
53
 
54
54
  ```ts
55
55
  const config = {
56
56
  planId: 'plan_VBXv4bHjSf3', // pre-select a Plan
57
57
  addOnIds: ['plan_AWv7bPjSx2'], // pre-select 1 or more Add-ons
58
58
  period: 'month', // pre-select 'month' or 'year' for the billing period (optional)
59
+ payInAdvanceQuantities: { // pre-fill pay-in-advance quantities, keyed by feature id (optional)
60
+ feat_seats: 3,
61
+ },
59
62
  skipped: {
60
63
  planStage: true, // if true, skip Plan selection
61
- addOnStage: true // if true, skip Add-on selection
62
- }
63
- hideSkipped: true // if true, hide skipped stages from breadcrumb navigation
64
+ addOnStage: true, // if true, skip Add-on selection
65
+ usageStage: true, // if true, skip the pay-in-advance Quantity stage
66
+ addOnUsageStage: true, // if true, skip the add-on Quantity stage
67
+ },
68
+ hideSkipped: true, // if true, hide skipped stages from breadcrumb navigation
64
69
  };
65
70
 
66
71
  initializeWithPlan(config);
67
72
  ```
68
73
 
74
+ `payInAdvanceQuantities` only applies to entitlements with pay-in-advance
75
+ pricing; entries for other (or unknown) features are ignored. Combine it with
76
+ `skipped.usageStage` / `skipped.addOnUsageStage` to send the customer straight to
77
+ the final checkout step with the quantities already set.
78
+
69
79
  The Plans and Add-ons available to the checkout flows must be live in your
70
80
  Schematic account [Catalog configuration](https://docs.schematichq.com/catalog/overview).
71
81
 
@@ -1866,6 +1866,7 @@ __export(index_exports, {
1866
1866
  UnsubscribeButton: () => UnsubscribeButton,
1867
1867
  UpcomingBill: () => UpcomingBill,
1868
1868
  Viewport: () => Viewport,
1869
+ applyPrefilledQuantities: () => applyPrefilledQuantities,
1869
1870
  cardBoxShadow: () => cardBoxShadow,
1870
1871
  createActiveUsageBasedEntitlementsReducer: () => createActiveUsageBasedEntitlementsReducer,
1871
1872
  defaultSettings: () => defaultSettings,
@@ -8291,6 +8292,7 @@ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
8291
8292
  }
8292
8293
  return {
8293
8294
  allocation: json["allocation"] == null ? void 0 : json["allocation"],
8295
+ consumptionRate: json["consumption_rate"] == null ? void 0 : json["consumption_rate"],
8294
8296
  creditId: json["credit_id"] == null ? void 0 : json["credit_id"],
8295
8297
  creditRemaining: json["credit_remaining"] == null ? void 0 : json["credit_remaining"],
8296
8298
  creditReserved: json["credit_reserved"] == null ? void 0 : json["credit_reserved"],
@@ -8298,6 +8300,7 @@ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
8298
8300
  creditTotal: json["credit_total"] == null ? void 0 : json["credit_total"],
8299
8301
  creditUsed: json["credit_used"] == null ? void 0 : json["credit_used"],
8300
8302
  eventName: json["event_name"] == null ? void 0 : json["event_name"],
8303
+ eventSubtype: json["event_subtype"] == null ? void 0 : json["event_subtype"],
8301
8304
  featureId: json["feature_id"],
8302
8305
  featureKey: json["feature_key"],
8303
8306
  metricPeriod: json["metric_period"] == null ? void 0 : MetricPeriodFromJSON(json["metric_period"]),
@@ -13313,18 +13316,26 @@ var reducer = (state, action) => {
13313
13316
  let bypassPlanSelection;
13314
13317
  let bypassAddOnSelection;
13315
13318
  let bypassCreditsSelection;
13319
+ let bypassUsageSelection;
13320
+ let bypassAddOnUsageSelection;
13316
13321
  if (config.skipped !== void 0) {
13317
13322
  bypassPlanSelection = config.skipped.planStage ?? false;
13318
13323
  bypassAddOnSelection = config.skipped.addOnStage ?? false;
13319
13324
  bypassCreditsSelection = config.skipped.creditStage ?? false;
13325
+ bypassUsageSelection = config.skipped.usageStage ?? false;
13326
+ bypassAddOnUsageSelection = config.skipped.addOnUsageStage ?? false;
13320
13327
  } else if (isStringFormat) {
13321
13328
  bypassPlanSelection = true;
13322
13329
  bypassAddOnSelection = false;
13323
13330
  bypassCreditsSelection = false;
13331
+ bypassUsageSelection = false;
13332
+ bypassAddOnUsageSelection = false;
13324
13333
  } else {
13325
13334
  bypassPlanSelection = false;
13326
13335
  bypassAddOnSelection = false;
13327
13336
  bypassCreditsSelection = false;
13337
+ bypassUsageSelection = false;
13338
+ bypassAddOnUsageSelection = false;
13328
13339
  }
13329
13340
  return {
13330
13341
  ...state,
@@ -13335,7 +13346,12 @@ var reducer = (state, action) => {
13335
13346
  bypassPlanSelection,
13336
13347
  bypassAddOnSelection,
13337
13348
  bypassCreditsSelection,
13349
+ bypassUsageSelection,
13350
+ bypassAddOnUsageSelection,
13338
13351
  ...config.addOnIds && { addOnIds: config.addOnIds },
13352
+ ...config.payInAdvanceQuantities && {
13353
+ payInAdvanceQuantities: config.payInAdvanceQuantities
13354
+ },
13339
13355
  ...config.currency && {
13340
13356
  selectedCurrency: config.currency.toUpperCase()
13341
13357
  },
@@ -13371,7 +13387,7 @@ var reducer = (state, action) => {
13371
13387
  // src/context/EmbedProvider.tsx
13372
13388
  var import_jsx_runtime3 = require("react/jsx-runtime");
13373
13389
  var getCustomHeaders = (sessionId) => ({
13374
- "X-Schematic-Components-Version": "2.16.2",
13390
+ "X-Schematic-Components-Version": "2.17.1",
13375
13391
  "X-Schematic-Session-ID": sessionId
13376
13392
  });
13377
13393
  var normalizeCurrencyFilter = (filter2) => {
@@ -17241,6 +17257,18 @@ var createActiveUsageBasedEntitlementsReducer = (entitlements, period) => (acc,
17241
17257
  }
17242
17258
  return acc;
17243
17259
  };
17260
+ var applyPrefilledQuantities = (entitlements, prefill) => {
17261
+ if (!prefill) {
17262
+ return entitlements;
17263
+ }
17264
+ return entitlements.map((entitlement) => {
17265
+ const prefilled = prefill[entitlement.featureId];
17266
+ if (entitlement.priceBehavior === EntitlementPriceBehavior.PayInAdvance && typeof prefilled === "number") {
17267
+ return { ...entitlement, quantity: Math.max(0, Math.floor(prefilled)) };
17268
+ }
17269
+ return entitlement;
17270
+ });
17271
+ };
17244
17272
  var CheckoutDialog = ({ top }) => {
17245
17273
  const { t: t3 } = useTranslation();
17246
17274
  const {
@@ -17474,9 +17502,12 @@ var CheckoutDialog = ({ top }) => {
17474
17502
  effectiveCurrency
17475
17503
  ]);
17476
17504
  const [usageBasedEntitlements, setUsageBasedEntitlements] = (0, import_react36.useState)(
17477
- () => (selectedPlan?.entitlements || []).reduce(
17478
- createActiveUsageBasedEntitlementsReducer(featureUsage, planPeriod),
17479
- []
17505
+ () => applyPrefilledQuantities(
17506
+ (selectedPlan?.entitlements || []).reduce(
17507
+ createActiveUsageBasedEntitlementsReducer(featureUsage, planPeriod),
17508
+ []
17509
+ ),
17510
+ checkoutState?.payInAdvanceQuantities
17480
17511
  )
17481
17512
  );
17482
17513
  const [addOnUsageBasedEntitlements, setAddOnUsageBasedEntitlements] = (0, import_react36.useState)(() => {
@@ -17515,7 +17546,10 @@ var CheckoutDialog = ({ top }) => {
17515
17546
  allEntitlements.push(bypassEnt);
17516
17547
  }
17517
17548
  }
17518
- return allEntitlements;
17549
+ return applyPrefilledQuantities(
17550
+ allEntitlements,
17551
+ checkoutState?.payInAdvanceQuantities
17552
+ );
17519
17553
  });
17520
17554
  const payInAdvanceEntitlements = (0, import_react36.useMemo)(
17521
17555
  () => usageBasedEntitlements.filter(
@@ -17651,7 +17685,7 @@ var CheckoutDialog = ({ top }) => {
17651
17685
  hasInitialPaymentMethod
17652
17686
  ]);
17653
17687
  const [isBypassLoading, setIsBypassLoading] = (0, import_react36.useState)(
17654
- () => checkoutState?.bypassPlanSelection || checkoutState?.bypassAddOnSelection || checkoutState?.bypassCreditsSelection
17688
+ () => checkoutState?.bypassPlanSelection || checkoutState?.bypassAddOnSelection || checkoutState?.bypassCreditsSelection || checkoutState?.bypassUsageSelection || checkoutState?.bypassAddOnUsageSelection
17655
17689
  );
17656
17690
  const [checkoutStage, setCheckoutStage] = (0, import_react36.useState)(() => {
17657
17691
  if (checkoutState?.addOnId) {
@@ -17671,7 +17705,7 @@ var CheckoutDialog = ({ top }) => {
17671
17705
  const effectiveCheckoutStage = (0, import_react36.useMemo)(() => {
17672
17706
  if (isBypassLoading) return checkoutStage;
17673
17707
  let id = checkoutStage;
17674
- while (id === "plan" && checkoutState?.bypassPlanSelection || id === "addons" && checkoutState?.bypassAddOnSelection || id === "credits" && checkoutState?.bypassCreditsSelection) {
17708
+ while (id === "plan" && checkoutState?.bypassPlanSelection || id === "usage" && checkoutState?.bypassUsageSelection || id === "addons" && checkoutState?.bypassAddOnSelection || id === "addonsUsage" && checkoutState?.bypassAddOnUsageSelection || id === "credits" && checkoutState?.bypassCreditsSelection) {
17675
17709
  const idx = checkoutStages.findIndex((s) => s.id === id);
17676
17710
  const next2 = checkoutStages[idx + 1];
17677
17711
  if (!next2) break;
@@ -17896,9 +17930,12 @@ var CheckoutDialog = ({ top }) => {
17896
17930
  (updates) => {
17897
17931
  const plan = updates.plan;
17898
17932
  const period = showPeriodToggle ? updates.period || planPeriod : plan.monthlyPrice ? BillingProductPriceInterval.Month : plan.quarterlyPrice ? "quarter" : plan.yearlyPrice ? BillingProductPriceInterval.Year : BillingProductPriceInterval.Month;
17899
- const updatedUsageBasedEntitlements = (plan.entitlements ?? []).reduce(
17900
- createActiveUsageBasedEntitlementsReducer(featureUsage, period),
17901
- []
17933
+ const updatedUsageBasedEntitlements = applyPrefilledQuantities(
17934
+ (plan.entitlements ?? []).reduce(
17935
+ createActiveUsageBasedEntitlementsReducer(featureUsage, period),
17936
+ []
17937
+ ),
17938
+ checkoutState?.payInAdvanceQuantities
17902
17939
  );
17903
17940
  if (period !== planPeriod || plan.id !== selectedPlan?.id) {
17904
17941
  setUsageBasedEntitlements((prev2) => {
@@ -17948,7 +17985,8 @@ var CheckoutDialog = ({ top }) => {
17948
17985
  featureUsage,
17949
17986
  shouldTrial,
17950
17987
  willTrialWithoutPaymentMethod,
17951
- handlePreviewCheckout
17988
+ handlePreviewCheckout,
17989
+ checkoutState?.payInAdvanceQuantities
17952
17990
  ]
17953
17991
  );
17954
17992
  const changePlanPeriod = (0, import_react36.useCallback)(
@@ -18176,9 +18214,15 @@ var CheckoutDialog = ({ top }) => {
18176
18214
  if (stage.id === "plan" && checkoutState.bypassPlanSelection) {
18177
18215
  return false;
18178
18216
  }
18217
+ if (stage.id === "usage" && checkoutState.bypassUsageSelection) {
18218
+ return false;
18219
+ }
18179
18220
  if (stage.id === "addons" && checkoutState.bypassAddOnSelection) {
18180
18221
  return false;
18181
18222
  }
18223
+ if (stage.id === "addonsUsage" && checkoutState.bypassAddOnUsageSelection) {
18224
+ return false;
18225
+ }
18182
18226
  if (stage.id === "credits" && checkoutState.bypassCreditsSelection) {
18183
18227
  return false;
18184
18228
  }
@@ -18190,9 +18234,15 @@ var CheckoutDialog = ({ top }) => {
18190
18234
  if (stage.id === "plan" && checkoutState?.bypassPlanSelection) {
18191
18235
  return false;
18192
18236
  }
18237
+ if (stage.id === "usage" && checkoutState?.bypassUsageSelection) {
18238
+ return false;
18239
+ }
18193
18240
  if (stage.id === "addons" && checkoutState?.bypassAddOnSelection) {
18194
18241
  return false;
18195
18242
  }
18243
+ if (stage.id === "addonsUsage" && checkoutState?.bypassAddOnUsageSelection) {
18244
+ return false;
18245
+ }
18196
18246
  if (stage.id === "credits" && checkoutState?.bypassCreditsSelection) {
18197
18247
  return false;
18198
18248
  }
@@ -18201,7 +18251,9 @@ var CheckoutDialog = ({ top }) => {
18201
18251
  }, [
18202
18252
  checkoutStages,
18203
18253
  checkoutState?.bypassPlanSelection,
18254
+ checkoutState?.bypassUsageSelection,
18204
18255
  checkoutState?.bypassAddOnSelection,
18256
+ checkoutState?.bypassAddOnUsageSelection,
18205
18257
  checkoutState?.bypassCreditsSelection
18206
18258
  ]);
18207
18259
  const shouldShowBypassOverlay = isBypassLoading;
@@ -18935,6 +18987,8 @@ var PaymentForm = ({ onConfirm, financeData }) => {
18935
18987
  const [isPaymentComplete, setIsPaymentComplete] = (0, import_react39.useState)(false);
18936
18988
  const [isPaymentReady, setIsPaymentReady] = (0, import_react39.useState)(false);
18937
18989
  const [loadError, setLoadError] = (0, import_react39.useState)();
18990
+ const [isEmailValid, setIsEmailValid] = (0, import_react39.useState)(() => !collectEmail);
18991
+ const emailInputRef = (0, import_react39.useRef)(null);
18938
18992
  const [isAddressComplete, setIsAddressComplete] = (0, import_react39.useState)(
18939
18993
  () => !shouldCollectAddress
18940
18994
  );
@@ -18947,6 +19001,11 @@ var PaymentForm = ({ onConfirm, financeData }) => {
18947
19001
  setEmail(billing.email);
18948
19002
  }
18949
19003
  }, [billing?.email]);
19004
+ (0, import_react39.useEffect)(() => {
19005
+ setIsEmailValid(
19006
+ !collectEmail || (emailInputRef.current?.checkValidity() ?? false)
19007
+ );
19008
+ }, [email, collectEmail, stripe]);
18950
19009
  const handleSubmit = async (event) => {
18951
19010
  event.preventDefault();
18952
19011
  if (!stripe || !elements) {
@@ -19046,11 +19105,13 @@ var PaymentForm = ({ onConfirm, financeData }) => {
19046
19105
  /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19047
19106
  Input2,
19048
19107
  {
19108
+ ref: emailInputRef,
19049
19109
  id: "email",
19050
- type: "text",
19110
+ type: "email",
19051
19111
  value: email,
19052
19112
  autoComplete: "email",
19053
19113
  placeholder: "Enter email address",
19114
+ required: true,
19054
19115
  onChange: (e2) => {
19055
19116
  userEditedEmailRef.current = true;
19056
19117
  setEmail(e2.target.value);
@@ -19081,7 +19142,7 @@ var PaymentForm = ({ onConfirm, financeData }) => {
19081
19142
  Button,
19082
19143
  {
19083
19144
  id: "submit",
19084
- disabled: isLoading || !stripe || !elements || isConfirmed || !isPaymentComplete || !isAddressComplete,
19145
+ disabled: isLoading || !stripe || !elements || isConfirmed || !isPaymentComplete || !isAddressComplete || !isEmailValid,
19085
19146
  style: { flexShrink: 0 },
19086
19147
  $color: "primary",
19087
19148
  $isLoading: isLoading,
@@ -22682,6 +22743,18 @@ var getPaymentMethodData = ({
22682
22743
  iconTitle: billingName || billingEmail || "Amazon Pay account",
22683
22744
  label: billingName || billingEmail || "Amazon Pay account"
22684
22745
  },
22746
+ apple_pay: {
22747
+ iconName: "applepay",
22748
+ iconTitle: "Apple Pay",
22749
+ label: cardLast4 ? "Apple Pay ending in" : "Apple Pay",
22750
+ paymentLast4: cardLast4
22751
+ },
22752
+ google_pay: {
22753
+ iconName: "google",
22754
+ iconTitle: "Google Pay",
22755
+ label: cardLast4 ? "Google Pay ending in" : "Google Pay",
22756
+ paymentLast4: cardLast4
22757
+ },
22685
22758
  cashapp: {
22686
22759
  iconName: "cashapp",
22687
22760
  iconTitle: accountName || billingEmail || "CashApp account",
@@ -26,6 +26,8 @@ declare interface AddOnsProps {
26
26
  currency?: string;
27
27
  }
28
28
 
29
+ export declare const applyPrefilledQuantities: (entitlements: UsageBasedEntitlement[], prefill?: Record<string, number>) => UsageBasedEntitlement[];
30
+
29
31
  export declare const AutoTopup: ({ planCreditGrants, autoTopupConfigs, updateAutoTopupConfig, }: AutoTopupProps) => JSX.Element;
30
32
 
31
33
  declare type AutoTopupConfig = Pick<CompanyPlanCreditGrantView, "companyAutoTopupEnabled" | "companyAutoTopupThresholdCredits" | "companyAutoTopupAmount">;
@@ -2901,6 +2903,19 @@ export declare interface BypassConfig {
2901
2903
  * currency is locked (the selector is already hidden in those cases).
2902
2904
  */
2903
2905
  showCurrencySelector?: boolean;
2906
+ /**
2907
+ * Pre-fill pay-in-advance quantities, keyed by feature id.
2908
+ *
2909
+ * Only applies to entitlements whose price behavior is pay-in-advance; entries
2910
+ * for other features (or unknown feature ids) are ignored. Values are clamped
2911
+ * to whole numbers >= 0. Combine with `skipped.usageStage` /
2912
+ * `skipped.addOnUsageStage` to land the customer directly on the checkout step
2913
+ * with the quantities already set.
2914
+ *
2915
+ * @example
2916
+ * { planId: "plan_abc", payInAdvanceQuantities: { feat_seats: 3 } }
2917
+ */
2918
+ payInAdvanceQuantities?: Record<string, number>;
2904
2919
  }
2905
2920
 
2906
2921
  export declare const Card: ForwardRefExoticComponent<CardProps & RefAttributes<HTMLDivElement | null>>;
@@ -3399,6 +3414,20 @@ export declare interface CheckoutStageSkipConfig {
3399
3414
  * - undefined: Defaults to false (show stage)
3400
3415
  */
3401
3416
  creditStage?: boolean;
3417
+ /**
3418
+ * Skip the pay-in-advance quantity stage for the plan.
3419
+ * - true: Skip directly to next stage (uses prefilled or current quantities)
3420
+ * - false: Show quantity stage (user can review/change quantities)
3421
+ * - undefined: Defaults to false (show stage)
3422
+ */
3423
+ usageStage?: boolean;
3424
+ /**
3425
+ * Skip the pay-in-advance quantity stage for add-ons.
3426
+ * - true: Skip directly to next stage (uses prefilled or current quantities)
3427
+ * - false: Show add-on quantity stage (user can review/change quantities)
3428
+ * - undefined: Defaults to false (show stage)
3429
+ */
3430
+ addOnUsageStage?: boolean;
3402
3431
  }
3403
3432
 
3404
3433
  export declare type CheckoutState = {
@@ -3411,11 +3440,14 @@ export declare type CheckoutState = {
3411
3440
  bypassPlanSelection?: boolean;
3412
3441
  bypassAddOnSelection?: boolean;
3413
3442
  bypassCreditsSelection?: boolean;
3443
+ bypassUsageSelection?: boolean;
3444
+ bypassAddOnUsageSelection?: boolean;
3414
3445
  addOnIds?: string[];
3415
3446
  hideSkippedStages?: boolean;
3416
3447
  selectedCurrency?: string;
3417
3448
  showCurrencySelector?: boolean;
3418
3449
  startTrialIfAvailable?: boolean;
3450
+ payInAdvanceQuantities?: Record<string, number>;
3419
3451
  };
3420
3452
 
3421
3453
  /**
@@ -6949,6 +6981,12 @@ declare interface FeatureEntitlement {
6949
6981
  * @memberof FeatureEntitlement
6950
6982
  */
6951
6983
  allocation?: number | null;
6984
+ /**
6985
+ * If the company has a credit-based entitlement for this feature, the credit cost per unit of usage
6986
+ * @type {number}
6987
+ * @memberof FeatureEntitlement
6988
+ */
6989
+ consumptionRate?: number | null;
6952
6990
  /**
6953
6991
  * If the company has a credit-based entitlement for this feature, the ID of the credit
6954
6992
  * @type {string}
@@ -6991,6 +7029,12 @@ declare interface FeatureEntitlement {
6991
7029
  * @memberof FeatureEntitlement
6992
7030
  */
6993
7031
  eventName?: string | null;
7032
+ /**
7033
+ * For event-based or credit-metered feature entitlements, the event subtype whose usage is tracked
7034
+ * @type {string}
7035
+ * @memberof FeatureEntitlement
7036
+ */
7037
+ eventSubtype?: string | null;
6994
7038
  /**
6995
7039
  * The ID of the feature
6996
7040
  * @type {string}
@@ -8202,6 +8202,7 @@ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
8202
8202
  }
8203
8203
  return {
8204
8204
  allocation: json["allocation"] == null ? void 0 : json["allocation"],
8205
+ consumptionRate: json["consumption_rate"] == null ? void 0 : json["consumption_rate"],
8205
8206
  creditId: json["credit_id"] == null ? void 0 : json["credit_id"],
8206
8207
  creditRemaining: json["credit_remaining"] == null ? void 0 : json["credit_remaining"],
8207
8208
  creditReserved: json["credit_reserved"] == null ? void 0 : json["credit_reserved"],
@@ -8209,6 +8210,7 @@ function FeatureEntitlementFromJSONTyped(json, ignoreDiscriminator) {
8209
8210
  creditTotal: json["credit_total"] == null ? void 0 : json["credit_total"],
8210
8211
  creditUsed: json["credit_used"] == null ? void 0 : json["credit_used"],
8211
8212
  eventName: json["event_name"] == null ? void 0 : json["event_name"],
8213
+ eventSubtype: json["event_subtype"] == null ? void 0 : json["event_subtype"],
8212
8214
  featureId: json["feature_id"],
8213
8215
  featureKey: json["feature_key"],
8214
8216
  metricPeriod: json["metric_period"] == null ? void 0 : MetricPeriodFromJSON(json["metric_period"]),
@@ -13224,18 +13226,26 @@ var reducer = (state, action) => {
13224
13226
  let bypassPlanSelection;
13225
13227
  let bypassAddOnSelection;
13226
13228
  let bypassCreditsSelection;
13229
+ let bypassUsageSelection;
13230
+ let bypassAddOnUsageSelection;
13227
13231
  if (config.skipped !== void 0) {
13228
13232
  bypassPlanSelection = config.skipped.planStage ?? false;
13229
13233
  bypassAddOnSelection = config.skipped.addOnStage ?? false;
13230
13234
  bypassCreditsSelection = config.skipped.creditStage ?? false;
13235
+ bypassUsageSelection = config.skipped.usageStage ?? false;
13236
+ bypassAddOnUsageSelection = config.skipped.addOnUsageStage ?? false;
13231
13237
  } else if (isStringFormat) {
13232
13238
  bypassPlanSelection = true;
13233
13239
  bypassAddOnSelection = false;
13234
13240
  bypassCreditsSelection = false;
13241
+ bypassUsageSelection = false;
13242
+ bypassAddOnUsageSelection = false;
13235
13243
  } else {
13236
13244
  bypassPlanSelection = false;
13237
13245
  bypassAddOnSelection = false;
13238
13246
  bypassCreditsSelection = false;
13247
+ bypassUsageSelection = false;
13248
+ bypassAddOnUsageSelection = false;
13239
13249
  }
13240
13250
  return {
13241
13251
  ...state,
@@ -13246,7 +13256,12 @@ var reducer = (state, action) => {
13246
13256
  bypassPlanSelection,
13247
13257
  bypassAddOnSelection,
13248
13258
  bypassCreditsSelection,
13259
+ bypassUsageSelection,
13260
+ bypassAddOnUsageSelection,
13249
13261
  ...config.addOnIds && { addOnIds: config.addOnIds },
13262
+ ...config.payInAdvanceQuantities && {
13263
+ payInAdvanceQuantities: config.payInAdvanceQuantities
13264
+ },
13250
13265
  ...config.currency && {
13251
13266
  selectedCurrency: config.currency.toUpperCase()
13252
13267
  },
@@ -13282,7 +13297,7 @@ var reducer = (state, action) => {
13282
13297
  // src/context/EmbedProvider.tsx
13283
13298
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
13284
13299
  var getCustomHeaders = (sessionId) => ({
13285
- "X-Schematic-Components-Version": "2.16.2",
13300
+ "X-Schematic-Components-Version": "2.17.1",
13286
13301
  "X-Schematic-Session-ID": sessionId
13287
13302
  });
13288
13303
  var normalizeCurrencyFilter = (filter2) => {
@@ -17171,6 +17186,18 @@ var createActiveUsageBasedEntitlementsReducer = (entitlements, period) => (acc,
17171
17186
  }
17172
17187
  return acc;
17173
17188
  };
17189
+ var applyPrefilledQuantities = (entitlements, prefill) => {
17190
+ if (!prefill) {
17191
+ return entitlements;
17192
+ }
17193
+ return entitlements.map((entitlement) => {
17194
+ const prefilled = prefill[entitlement.featureId];
17195
+ if (entitlement.priceBehavior === EntitlementPriceBehavior.PayInAdvance && typeof prefilled === "number") {
17196
+ return { ...entitlement, quantity: Math.max(0, Math.floor(prefilled)) };
17197
+ }
17198
+ return entitlement;
17199
+ });
17200
+ };
17174
17201
  var CheckoutDialog = ({ top }) => {
17175
17202
  const { t: t3 } = useTranslation();
17176
17203
  const {
@@ -17404,9 +17431,12 @@ var CheckoutDialog = ({ top }) => {
17404
17431
  effectiveCurrency
17405
17432
  ]);
17406
17433
  const [usageBasedEntitlements, setUsageBasedEntitlements] = useState8(
17407
- () => (selectedPlan?.entitlements || []).reduce(
17408
- createActiveUsageBasedEntitlementsReducer(featureUsage, planPeriod),
17409
- []
17434
+ () => applyPrefilledQuantities(
17435
+ (selectedPlan?.entitlements || []).reduce(
17436
+ createActiveUsageBasedEntitlementsReducer(featureUsage, planPeriod),
17437
+ []
17438
+ ),
17439
+ checkoutState?.payInAdvanceQuantities
17410
17440
  )
17411
17441
  );
17412
17442
  const [addOnUsageBasedEntitlements, setAddOnUsageBasedEntitlements] = useState8(() => {
@@ -17445,7 +17475,10 @@ var CheckoutDialog = ({ top }) => {
17445
17475
  allEntitlements.push(bypassEnt);
17446
17476
  }
17447
17477
  }
17448
- return allEntitlements;
17478
+ return applyPrefilledQuantities(
17479
+ allEntitlements,
17480
+ checkoutState?.payInAdvanceQuantities
17481
+ );
17449
17482
  });
17450
17483
  const payInAdvanceEntitlements = useMemo12(
17451
17484
  () => usageBasedEntitlements.filter(
@@ -17581,7 +17614,7 @@ var CheckoutDialog = ({ top }) => {
17581
17614
  hasInitialPaymentMethod
17582
17615
  ]);
17583
17616
  const [isBypassLoading, setIsBypassLoading] = useState8(
17584
- () => checkoutState?.bypassPlanSelection || checkoutState?.bypassAddOnSelection || checkoutState?.bypassCreditsSelection
17617
+ () => checkoutState?.bypassPlanSelection || checkoutState?.bypassAddOnSelection || checkoutState?.bypassCreditsSelection || checkoutState?.bypassUsageSelection || checkoutState?.bypassAddOnUsageSelection
17585
17618
  );
17586
17619
  const [checkoutStage, setCheckoutStage] = useState8(() => {
17587
17620
  if (checkoutState?.addOnId) {
@@ -17601,7 +17634,7 @@ var CheckoutDialog = ({ top }) => {
17601
17634
  const effectiveCheckoutStage = useMemo12(() => {
17602
17635
  if (isBypassLoading) return checkoutStage;
17603
17636
  let id = checkoutStage;
17604
- while (id === "plan" && checkoutState?.bypassPlanSelection || id === "addons" && checkoutState?.bypassAddOnSelection || id === "credits" && checkoutState?.bypassCreditsSelection) {
17637
+ while (id === "plan" && checkoutState?.bypassPlanSelection || id === "usage" && checkoutState?.bypassUsageSelection || id === "addons" && checkoutState?.bypassAddOnSelection || id === "addonsUsage" && checkoutState?.bypassAddOnUsageSelection || id === "credits" && checkoutState?.bypassCreditsSelection) {
17605
17638
  const idx = checkoutStages.findIndex((s) => s.id === id);
17606
17639
  const next2 = checkoutStages[idx + 1];
17607
17640
  if (!next2) break;
@@ -17826,9 +17859,12 @@ var CheckoutDialog = ({ top }) => {
17826
17859
  (updates) => {
17827
17860
  const plan = updates.plan;
17828
17861
  const period = showPeriodToggle ? updates.period || planPeriod : plan.monthlyPrice ? BillingProductPriceInterval.Month : plan.quarterlyPrice ? "quarter" : plan.yearlyPrice ? BillingProductPriceInterval.Year : BillingProductPriceInterval.Month;
17829
- const updatedUsageBasedEntitlements = (plan.entitlements ?? []).reduce(
17830
- createActiveUsageBasedEntitlementsReducer(featureUsage, period),
17831
- []
17862
+ const updatedUsageBasedEntitlements = applyPrefilledQuantities(
17863
+ (plan.entitlements ?? []).reduce(
17864
+ createActiveUsageBasedEntitlementsReducer(featureUsage, period),
17865
+ []
17866
+ ),
17867
+ checkoutState?.payInAdvanceQuantities
17832
17868
  );
17833
17869
  if (period !== planPeriod || plan.id !== selectedPlan?.id) {
17834
17870
  setUsageBasedEntitlements((prev2) => {
@@ -17878,7 +17914,8 @@ var CheckoutDialog = ({ top }) => {
17878
17914
  featureUsage,
17879
17915
  shouldTrial,
17880
17916
  willTrialWithoutPaymentMethod,
17881
- handlePreviewCheckout
17917
+ handlePreviewCheckout,
17918
+ checkoutState?.payInAdvanceQuantities
17882
17919
  ]
17883
17920
  );
17884
17921
  const changePlanPeriod = useCallback7(
@@ -18106,9 +18143,15 @@ var CheckoutDialog = ({ top }) => {
18106
18143
  if (stage.id === "plan" && checkoutState.bypassPlanSelection) {
18107
18144
  return false;
18108
18145
  }
18146
+ if (stage.id === "usage" && checkoutState.bypassUsageSelection) {
18147
+ return false;
18148
+ }
18109
18149
  if (stage.id === "addons" && checkoutState.bypassAddOnSelection) {
18110
18150
  return false;
18111
18151
  }
18152
+ if (stage.id === "addonsUsage" && checkoutState.bypassAddOnUsageSelection) {
18153
+ return false;
18154
+ }
18112
18155
  if (stage.id === "credits" && checkoutState.bypassCreditsSelection) {
18113
18156
  return false;
18114
18157
  }
@@ -18120,9 +18163,15 @@ var CheckoutDialog = ({ top }) => {
18120
18163
  if (stage.id === "plan" && checkoutState?.bypassPlanSelection) {
18121
18164
  return false;
18122
18165
  }
18166
+ if (stage.id === "usage" && checkoutState?.bypassUsageSelection) {
18167
+ return false;
18168
+ }
18123
18169
  if (stage.id === "addons" && checkoutState?.bypassAddOnSelection) {
18124
18170
  return false;
18125
18171
  }
18172
+ if (stage.id === "addonsUsage" && checkoutState?.bypassAddOnUsageSelection) {
18173
+ return false;
18174
+ }
18126
18175
  if (stage.id === "credits" && checkoutState?.bypassCreditsSelection) {
18127
18176
  return false;
18128
18177
  }
@@ -18131,7 +18180,9 @@ var CheckoutDialog = ({ top }) => {
18131
18180
  }, [
18132
18181
  checkoutStages,
18133
18182
  checkoutState?.bypassPlanSelection,
18183
+ checkoutState?.bypassUsageSelection,
18134
18184
  checkoutState?.bypassAddOnSelection,
18185
+ checkoutState?.bypassAddOnUsageSelection,
18135
18186
  checkoutState?.bypassCreditsSelection
18136
18187
  ]);
18137
18188
  const shouldShowBypassOverlay = isBypassLoading;
@@ -18870,6 +18921,8 @@ var PaymentForm = ({ onConfirm, financeData }) => {
18870
18921
  const [isPaymentComplete, setIsPaymentComplete] = useState11(false);
18871
18922
  const [isPaymentReady, setIsPaymentReady] = useState11(false);
18872
18923
  const [loadError, setLoadError] = useState11();
18924
+ const [isEmailValid, setIsEmailValid] = useState11(() => !collectEmail);
18925
+ const emailInputRef = useRef8(null);
18873
18926
  const [isAddressComplete, setIsAddressComplete] = useState11(
18874
18927
  () => !shouldCollectAddress
18875
18928
  );
@@ -18882,6 +18935,11 @@ var PaymentForm = ({ onConfirm, financeData }) => {
18882
18935
  setEmail(billing.email);
18883
18936
  }
18884
18937
  }, [billing?.email]);
18938
+ useEffect5(() => {
18939
+ setIsEmailValid(
18940
+ !collectEmail || (emailInputRef.current?.checkValidity() ?? false)
18941
+ );
18942
+ }, [email, collectEmail, stripe]);
18885
18943
  const handleSubmit = async (event) => {
18886
18944
  event.preventDefault();
18887
18945
  if (!stripe || !elements) {
@@ -18981,11 +19039,13 @@ var PaymentForm = ({ onConfirm, financeData }) => {
18981
19039
  /* @__PURE__ */ jsx33(
18982
19040
  Input2,
18983
19041
  {
19042
+ ref: emailInputRef,
18984
19043
  id: "email",
18985
- type: "text",
19044
+ type: "email",
18986
19045
  value: email,
18987
19046
  autoComplete: "email",
18988
19047
  placeholder: "Enter email address",
19048
+ required: true,
18989
19049
  onChange: (e2) => {
18990
19050
  userEditedEmailRef.current = true;
18991
19051
  setEmail(e2.target.value);
@@ -19016,7 +19076,7 @@ var PaymentForm = ({ onConfirm, financeData }) => {
19016
19076
  Button,
19017
19077
  {
19018
19078
  id: "submit",
19019
- disabled: isLoading || !stripe || !elements || isConfirmed || !isPaymentComplete || !isAddressComplete,
19079
+ disabled: isLoading || !stripe || !elements || isConfirmed || !isPaymentComplete || !isAddressComplete || !isEmailValid,
19020
19080
  style: { flexShrink: 0 },
19021
19081
  $color: "primary",
19022
19082
  $isLoading: isLoading,
@@ -22624,6 +22684,18 @@ var getPaymentMethodData = ({
22624
22684
  iconTitle: billingName || billingEmail || "Amazon Pay account",
22625
22685
  label: billingName || billingEmail || "Amazon Pay account"
22626
22686
  },
22687
+ apple_pay: {
22688
+ iconName: "applepay",
22689
+ iconTitle: "Apple Pay",
22690
+ label: cardLast4 ? "Apple Pay ending in" : "Apple Pay",
22691
+ paymentLast4: cardLast4
22692
+ },
22693
+ google_pay: {
22694
+ iconName: "google",
22695
+ iconTitle: "Google Pay",
22696
+ label: cardLast4 ? "Google Pay ending in" : "Google Pay",
22697
+ paymentLast4: cardLast4
22698
+ },
22627
22699
  cashapp: {
22628
22700
  iconName: "cashapp",
22629
22701
  iconTitle: accountName || billingEmail || "CashApp account",
@@ -29979,6 +30051,7 @@ export {
29979
30051
  UnsubscribeButton,
29980
30052
  UpcomingBill,
29981
30053
  Viewport,
30054
+ applyPrefilledQuantities,
29982
30055
  cardBoxShadow,
29983
30056
  createActiveUsageBasedEntitlementsReducer,
29984
30057
  defaultSettings,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@schematichq/schematic-components",
3
- "version": "2.16.2",
3
+ "version": "2.17.1",
4
4
  "main": "dist/schematic-components.cjs.js",
5
5
  "module": "dist/schematic-components.esm.js",
6
6
  "types": "dist/schematic-components.d.ts",
@@ -40,16 +40,16 @@
40
40
  "pako": "^2.1.0",
41
41
  "react-i18next": "16.1.6",
42
42
  "styled-components": "^6.4.2",
43
- "uuid": "^14.0.0"
43
+ "uuid": "^14.0.1"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@eslint/js": "^10.0.1",
47
47
  "@eslint/json": "^2.0.0",
48
48
  "@eslint/markdown": "^8.0.2",
49
49
  "@microsoft/api-extractor": "^7.58.9",
50
- "@openapitools/openapi-generator-cli": "^2.38.0",
50
+ "@openapitools/openapi-generator-cli": "^2.39.0",
51
51
  "@stripe/react-stripe-js": "^6.6.0",
52
- "@swc/core": "^1.15.41",
52
+ "@swc/core": "^1.15.43",
53
53
  "@testing-library/dom": "^10.4.1",
54
54
  "@testing-library/jest-dom": "^6.9.1",
55
55
  "@testing-library/react": "^16.3.2",
@@ -64,15 +64,15 @@
64
64
  "eslint-plugin-import-x": "^4.16.2",
65
65
  "eslint-plugin-react": "^7.37.5",
66
66
  "eslint-plugin-react-hooks": "^7.1.1",
67
- "globals": "^17.6.0",
68
- "happy-dom": "^20.10.5",
67
+ "globals": "^17.7.0",
68
+ "happy-dom": "^20.10.6",
69
69
  "jsdom": "^29.1.1",
70
70
  "msw": "^2.14.6",
71
71
  "prettier": "^3.8.4",
72
72
  "react": "^19.2.7",
73
73
  "react-dom": "^19.2.7",
74
74
  "typescript": "^6.0.3",
75
- "typescript-eslint": "^8.61.1",
75
+ "typescript-eslint": "^8.62.0",
76
76
  "vitest": "^4.1.9"
77
77
  },
78
78
  "peerDependencies": {