@bunnyapp/components 1.8.0-beta.4 → 1.8.0-beta.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/cjs/index.js CHANGED
@@ -1283,7 +1283,7 @@ const DEFAULT_CONFIG = {
1283
1283
  };
1284
1284
 
1285
1285
  // This will be replaced at build time by rollup-plugin-replace
1286
- const PACKAGE_VERSION = '1.8.0-beta.3';
1286
+ const PACKAGE_VERSION = '1.8.0-beta.4';
1287
1287
  const createRequestHeaders = (token) => {
1288
1288
  const headers = createClientDevHeaders({ token });
1289
1289
  // Add the components version header
@@ -22955,15 +22955,15 @@ function QuotesWrapper() {
22955
22955
  return (jsxRuntime.jsx(TransactionsDisplay, { transactions: quotesAsTransactions, onSearchValueChanged: setSearch, search: search }));
22956
22956
  }
22957
22957
 
22958
- const shouldShowCouponEditor_QuoteFragment = t(`
22959
- fragment shouldShowCouponEditor_QuoteFragment on Quote {
22958
+ const canApplyCoupons_QuoteFragment = t(`
22959
+ fragment canApplyCoupons_QuoteFragment on Quote {
22960
22960
  id
22961
22961
  kind
22962
22962
  amountDue
22963
22963
  }
22964
22964
  `, []);
22965
- const shouldShowCouponEditor_SubscriptionFragment = t(`
22966
- fragment shouldShowCouponEditor_SubscriptionFragment on Subscription {
22965
+ const canApplyCoupons_SubscriptionFragment = t(`
22966
+ fragment canApplyCoupons_SubscriptionFragment on Subscription {
22967
22967
  id
22968
22968
  state
22969
22969
  charges {
@@ -22971,10 +22971,10 @@ const shouldShowCouponEditor_SubscriptionFragment = t(`
22971
22971
  }
22972
22972
  }
22973
22973
  `, []);
22974
- function shouldShowCouponEditor(maskedQuote, activeCouponsExist, maskedUpgradingSubscription) {
22974
+ function canApplyCoupons(maskedQuote, activeCouponsExist, maskedUpgradingSubscription) {
22975
22975
  var _a, _b;
22976
- const quote = readFragment(shouldShowCouponEditor_QuoteFragment, maskedQuote);
22977
- const upgradingSubscription = readFragment(shouldShowCouponEditor_SubscriptionFragment, maskedUpgradingSubscription);
22976
+ const quote = readFragment(canApplyCoupons_QuoteFragment, maskedQuote);
22977
+ const upgradingSubscription = readFragment(canApplyCoupons_SubscriptionFragment, maskedUpgradingSubscription);
22978
22978
  const upgradingFromTrial = ((_a = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL') ||
22979
22979
  ((_b = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) ===
22980
22980
  t.scalar('SubscriptionState', 'TRIAL_EXPIRED');
@@ -22992,7 +22992,10 @@ function shouldShowCouponEditor(maskedQuote, activeCouponsExist, maskedUpgrading
22992
22992
  return false;
22993
22993
  }
22994
22994
  if (quoteKindIsValid) {
22995
- return activeCouponsExist && (upgradingFromTrial || upgradingFromFree() || signingUpForNewSubscription);
22995
+ const result = activeCouponsExist &&
22996
+ (upgradingFromTrial || upgradingFromFree() || signingUpForNewSubscription);
22997
+ console.log('returning result', result);
22998
+ return result;
22996
22999
  }
22997
23000
  return false;
22998
23001
  }
@@ -23004,6 +23007,27 @@ function CouponEditor({ className, onAddCoupon, isAddingCoupon, couponCode, setC
23004
23007
  return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-flex-col bunny-gap-2 ${className}`, children: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2", children: [jsxRuntime.jsx(antd.Input, { value: couponCode, onChange: e => setCouponCode(e.target.value), placeholder: "Coupon code", disabled: isAddingCoupon, size: "small" }), jsxRuntime.jsx(antd.Button, { loading: isAddingCoupon, type: "primary", onClick: handleAddCoupon, disabled: couponCode.length === 0, children: "Apply" })] }) }));
23005
23008
  }
23006
23009
 
23010
+ t(`
23011
+ fragment sortQuoteChangeCharges_QuoteChargeFragment on QuoteCharge {
23012
+ kind
23013
+ }
23014
+ `, []);
23015
+ /**
23016
+ * Sorts quote change charges so that coupon charges appear at the end of the list.
23017
+ * Uses a generic type so the full charge shape is preserved.
23018
+ */
23019
+ function sortQuoteChangeCharges(charges) {
23020
+ return [...charges].sort((chargeA, chargeB) => {
23021
+ const aIsCoupon = chargeA.kind === 'COUPON';
23022
+ const bIsCoupon = chargeB.kind === 'COUPON';
23023
+ if (aIsCoupon && !bIsCoupon)
23024
+ return 1;
23025
+ if (!aIsCoupon && bIsCoupon)
23026
+ return -1;
23027
+ return 0;
23028
+ });
23029
+ }
23030
+
23007
23031
  const { Text: Text$r } = antd.Typography;
23008
23032
  const CheckoutSummary_PriceListFragment = t(`
23009
23033
  fragment CheckoutSummary_PriceListFragment on PriceList {
@@ -23033,14 +23057,14 @@ const CheckoutSummary_QuoteFragment = t(`
23033
23057
  currencyId
23034
23058
  }
23035
23059
  }
23036
- ...shouldShowCouponEditor_QuoteFragment
23060
+ ...canApplyCoupons_QuoteFragment
23037
23061
  }
23038
- `, [shouldShowCouponEditor_QuoteFragment]);
23062
+ `, [canApplyCoupons_QuoteFragment]);
23039
23063
  function CheckoutSummary({ quote: maskedQuote, className, onAddCoupon, onRemoveCoupon, isRemovingCoupon, priceList: maskedPriceList, isAddingCoupon, couponCode, setCouponCode, activeCouponsExist, }) {
23040
23064
  var _a, _b;
23041
23065
  const priceList = readFragment(CheckoutSummary_PriceListFragment, maskedPriceList);
23042
23066
  const quote = readFragment(CheckoutSummary_QuoteFragment, maskedQuote);
23043
- return (jsxRuntime.jsxs("div", { className: `${className} bunny-space-y-4`, children: [jsxRuntime.jsxs(Text$r, { children: [jsxRuntime.jsxs("div", { className: "bunny-text-lg bunny-font-medium bunny-mb-4", children: ["Checkout summary - ", (_a = priceList === null || priceList === void 0 ? void 0 : priceList.product) === null || _a === void 0 ? void 0 : _a.name, " ", priceList === null || priceList === void 0 ? void 0 : priceList.name] }), jsxRuntime.jsx("div", { className: "bunny-space-y-4", children: (_b = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _b === void 0 ? void 0 : _b.map(quoteChange => quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.charges.map(charge => {
23067
+ return (jsxRuntime.jsxs("div", { className: `${className} bunny-space-y-4`, children: [jsxRuntime.jsxs(Text$r, { children: [jsxRuntime.jsxs("div", { className: "bunny-text-lg bunny-font-medium bunny-mb-4", children: ["Checkout summary - ", (_a = priceList === null || priceList === void 0 ? void 0 : priceList.product) === null || _a === void 0 ? void 0 : _a.name, " ", priceList === null || priceList === void 0 ? void 0 : priceList.name] }), jsxRuntime.jsx("div", { className: "bunny-space-y-4", children: (_b = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _b === void 0 ? void 0 : _b.map(quoteChange => sortQuoteChangeCharges(quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.charges).map(charge => {
23044
23068
  var _a;
23045
23069
  const multiplier = charge.kind === 'COUPON' ? -1 : 1;
23046
23070
  return (jsxRuntime.jsxs("div", { className: "bunny-grid bunny-grid-cols-3 bunny-gap-4 bunny-items-center", children: [jsxRuntime.jsx("div", { className: "bunny-col-span-1", children: charge.name }), jsxRuntime.jsx("div", { className: "bunny-col-span-1 bunny-text-center", children: ((_a = charge.coupon) === null || _a === void 0 ? void 0 : _a.couponCode) ? (jsxRuntime.jsx("button", { onClick: () => {
@@ -23053,7 +23077,7 @@ function CheckoutSummary({ quote: maskedQuote, className, onAddCoupon, onRemoveC
23053
23077
  }
23054
23078
  onRemoveCoupon((_b = charge.coupon) === null || _b === void 0 ? void 0 : _b.couponCode);
23055
23079
  }, className: "bunny-text-orange-500 hover:bunny-text-orange-400 bunny-cursor-pointer bunny-bg-transparent bunny-border-none", children: "Remove" })) : (jsxRuntime.jsx("div", { children: charge.quantity })) }), jsxRuntime.jsx("div", { className: "bunny-col-span-1 bunny-text-right", children: formatCurrency(multiplier * (charge.subtotal || 0), charge.currencyId) })] }, charge.id));
23056
- })) }), jsxRuntime.jsx(CheckoutSummaryDivider, {}), jsxRuntime.jsxs("div", { className: "bunny-space-y-4", children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsxRuntime.jsx("div", { children: "Subtotal" }), jsxRuntime.jsx("div", { children: formatCurrency(quote.subtotal, quote.currencyId) })] }), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsxRuntime.jsx("div", { children: "Taxes" }), jsxRuntime.jsx("div", { children: formatCurrency(quote.taxAmount, quote.currencyId) })] })] }), jsxRuntime.jsx(CheckoutSummaryDivider, {}), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsxRuntime.jsx("div", { children: "Total" }), jsxRuntime.jsx("div", { children: formatCurrency(quote.amountDue, quote.currencyId) })] })] }), shouldShowCouponEditor(quote, activeCouponsExist) && (jsxRuntime.jsx(CouponEditor, { className: "bunny-w-full", onAddCoupon: onAddCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode }))] }));
23080
+ })) }), jsxRuntime.jsx(CheckoutSummaryDivider, {}), jsxRuntime.jsxs("div", { className: "bunny-space-y-4", children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsxRuntime.jsx("div", { children: "Subtotal" }), jsxRuntime.jsx("div", { children: formatCurrency(quote.subtotal, quote.currencyId) })] }), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsxRuntime.jsx("div", { children: "Taxes" }), jsxRuntime.jsx("div", { children: formatCurrency(quote.taxAmount, quote.currencyId) })] })] }), jsxRuntime.jsx(CheckoutSummaryDivider, {}), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsxRuntime.jsx("div", { children: "Total" }), jsxRuntime.jsx("div", { children: formatCurrency(quote.amountDue, quote.currencyId) })] })] }), canApplyCoupons(quote, activeCouponsExist) && (jsxRuntime.jsx(CouponEditor, { className: "bunny-w-full", onAddCoupon: onAddCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode }))] }));
23057
23081
  }
23058
23082
  const CheckoutSummaryDivider = () => {
23059
23083
  return (jsxRuntime.jsx("div", { className: "bunny-my-2", children: jsxRuntime.jsx(antd.Divider, { className: "m-0" }) }));
@@ -23104,10 +23128,36 @@ function InitialSignupForm({ className, onSubmit, submitting, defaultValues, })
23104
23128
  } }) }) }) }), jsxRuntime.jsx(antd.Form.Item, { children: jsxRuntime.jsx(antd.Button, { type: "primary", onClick: handleSubmit, loading: submitting, className: "bunny-w-full", children: "Proceed to payment" }) })] }) }));
23105
23129
  }
23106
23130
 
23131
+ const useApplyDefaultCoupon_QuoteFragment = t(`
23132
+ fragment useApplyDefaultCoupon_QuoteFragment on Quote {
23133
+ ...canApplyCoupons_QuoteFragment
23134
+ }
23135
+ `, [canApplyCoupons_QuoteFragment]);
23136
+ /**
23137
+ * Applies a default coupon code once when quoteChangeId is available.
23138
+ * Uses a ref to ensure coupon code is only applied once.
23139
+ */
23140
+ function useApplyDefaultCoupon({ couponCode, quoteChangeId, quote: maskedQuote, activeCouponsExist, addCoupon, }) {
23141
+ const defaultCouponAppliedRef = react.useRef(undefined);
23142
+ // Derived state
23143
+ const quote = readFragment(useApplyDefaultCoupon_QuoteFragment, maskedQuote);
23144
+ const canApplyCouponsResult = canApplyCoupons(quote, activeCouponsExist);
23145
+ react.useEffect(() => {
23146
+ if (couponCode &&
23147
+ quoteChangeId &&
23148
+ defaultCouponAppliedRef.current !== couponCode &&
23149
+ canApplyCouponsResult) {
23150
+ addCoupon(couponCode);
23151
+ defaultCouponAppliedRef.current = couponCode;
23152
+ }
23153
+ }, [couponCode, quoteChangeId, addCoupon, canApplyCouponsResult]);
23154
+ }
23155
+
23107
23156
  const Signup_QuoteFragment = t(`
23108
23157
  fragment Signup_QuoteFragment on Quote {
23109
23158
  ...CheckoutSummary_QuoteFragment
23110
23159
  ...PaymentForms_QuoteFragment
23160
+ ...useApplyDefaultCoupon_QuoteFragment
23111
23161
  id
23112
23162
  currencyId
23113
23163
  amountDue
@@ -23115,7 +23165,7 @@ const Signup_QuoteFragment = t(`
23115
23165
  id
23116
23166
  }
23117
23167
  }
23118
- `, [CheckoutSummary_QuoteFragment, PaymentForms_QuoteFragment]);
23168
+ `, [CheckoutSummary_QuoteFragment, PaymentForms_QuoteFragment, useApplyDefaultCoupon_QuoteFragment]);
23119
23169
 
23120
23170
  const query$6 = t(`
23121
23171
  query quote($id: ID) {
@@ -23571,7 +23621,6 @@ function Signup({ companyName, priceListCode, returnUrl, couponCode, className,
23571
23621
  const [portalSessionToken, setPortalSessionToken] = react.useState(undefined);
23572
23622
  const token = portalSessionToken || tokenFromContexts;
23573
23623
  const [purchaseSucceeded, setPurchaseSucceeded] = react.useState(false);
23574
- const defaultCouponAppliedRef = react.useRef(undefined);
23575
23624
  const [couponEditorCouponCode, setCouponEditorCouponCode] = react.useState('');
23576
23625
  // Read fragment
23577
23626
  const initialQuoteId = (_a = readFragment(Signup_QuoteFragment, initialQuote)) === null || _a === void 0 ? void 0 : _a.id;
@@ -23688,13 +23737,7 @@ function Signup({ companyName, priceListCode, returnUrl, couponCode, className,
23688
23737
  handleRecalculateTaxes(quote === null || quote === void 0 ? void 0 : quote.id);
23689
23738
  },
23690
23739
  });
23691
- // Handle default coupon application
23692
- react.useEffect(() => {
23693
- if (couponCode && quoteChangeId && defaultCouponAppliedRef.current !== couponCode) {
23694
- addCoupon(couponCode);
23695
- defaultCouponAppliedRef.current = couponCode;
23696
- }
23697
- }, [couponCode, quoteChangeId]);
23740
+ useApplyDefaultCoupon({ couponCode, quoteChangeId, addCoupon, activeCouponsExist, quote });
23698
23741
  async function handleSubmit(formData) {
23699
23742
  if (selfServiceBuyEnabled === false) {
23700
23743
  handleShowSelfServiceBuyWarning();
@@ -23924,22 +23967,22 @@ const QuoteCheckout_QuoteFragment = t(`
23924
23967
  }
23925
23968
  }
23926
23969
  ...QuoteFields_QuoteFragment
23927
- ...shouldShowCouponEditor_QuoteFragment
23970
+ ...canApplyCoupons_QuoteFragment
23928
23971
  ...PaymentForm_QuoteFragment
23929
23972
  ...getQuoteAmountDue_QuoteFragment
23930
23973
  }
23931
23974
  `, [
23932
23975
  QuoteFields_QuoteFragment,
23933
- shouldShowCouponEditor_QuoteFragment,
23976
+ canApplyCoupons_QuoteFragment,
23934
23977
  PaymentForm_QuoteFragment,
23935
23978
  getQuoteAmountDue_QuoteFragment,
23936
23979
  ]);
23937
23980
  const QuoteCheckout_SubscriptionFragment = t(`
23938
23981
  fragment QuoteCheckout_SubscriptionFragment on Subscription {
23939
23982
  id
23940
- ...shouldShowCouponEditor_SubscriptionFragment
23983
+ ...canApplyCoupons_SubscriptionFragment
23941
23984
  }
23942
- `, [shouldShowCouponEditor_SubscriptionFragment]);
23985
+ `, [canApplyCoupons_SubscriptionFragment]);
23943
23986
  const showSuccessNotification = useSuccessNotification();
23944
23987
  const QuoteCheckout = ({ account, onSuccess, onFail, quote: maskedQuote, taxationRequiredAccountFields, isUpdatingQuote, onRecalculateTaxes, isRecalculatingTaxes, }) => {
23945
23988
  var _a, _b, _c, _d, _e;
@@ -24025,7 +24068,7 @@ const QuoteCheckout = ({ account, onSuccess, onFail, quote: maskedQuote, taxatio
24025
24068
  if (taxationRequiredAccountFields)
24026
24069
  return (jsxRuntime.jsx(PaymentFormWrapper, { setMaxHeight: false, children: jsxRuntime.jsx(TaxationForm, { account: account, accountId: quote.accountId }) }));
24027
24070
  return (jsxRuntime.jsx(PaymentFormWrapper, { setMaxHeight: false, children: paymentRequired ? (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2 bunny-w-full", children: [jsxRuntime.jsx(PaymentForm, { onPaymentSuccess: onSuccess, quote: quote, onSavePaymentMethod: (paymentMethod) => onPaymentMethodSaved === null || onPaymentMethodSaved === void 0 ? void 0 : onPaymentMethodSaved(paymentMethod.savedPaymentMethodResponse.paymentMethodId), onPaymentMethodRemoved: (paymentMethod) => onPaymentMethodRemoved === null || onPaymentMethodRemoved === void 0 ? void 0 : onPaymentMethodRemoved(paymentMethod.id), disablePayButton: isFinalizingQuote }), isFinalizingQuote && jsxRuntime.jsx(QuoteLoadingIndicator, {}), (couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.length) === 0 ? (jsxRuntime.jsx(jsxRuntime.Fragment, { children: upgradingSubscription &&
24028
- shouldShowCouponEditor(quote, activeCouponsExist, upgradingSubscription) && (jsxRuntime.jsx(CouponEditor, { className: "bunny-px-4 bunny-pt-1", onAddCoupon: addCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode })) })) : (jsxRuntime.jsx(antd.Button, { type: "link", loading: isRemovingCoupon, onClick: () => {
24071
+ canApplyCoupons(quote, activeCouponsExist, upgradingSubscription) && (jsxRuntime.jsx(CouponEditor, { className: "bunny-px-4 bunny-pt-1", onAddCoupon: addCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode })) })) : (jsxRuntime.jsx(antd.Button, { type: "link", loading: isRemovingCoupon, onClick: () => {
24029
24072
  couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.forEach(couponCharge => {
24030
24073
  var _a;
24031
24074
  const couponCode = (_a = couponCharge === null || couponCharge === void 0 ? void 0 : couponCharge.coupon) === null || _a === void 0 ? void 0 : _a.couponCode;
@@ -72,7 +72,7 @@ export declare const QuoteCheckout_QuoteFragment: import("gql.tada").TadaDocumen
72
72
  }[];
73
73
  kind: "SUBSCRIBE" | "UPDATE" | "RENEW" | "REINSTATE" | "UNSUBSCRIBE" | "ADJUSTMENT" | "COUPON" | "DISCOUNT" | "CREDIT" | "PRICE_UPDATE" | "QUANTITY_UPDATE" | "FREE_PERIOD_DISCOUNT" | "ACTIVATE";
74
74
  [$tada.fragmentRefs]: {
75
- shouldShowCouponEditor_QuoteFragment: "Quote";
75
+ canApplyCoupons_QuoteFragment: "Quote";
76
76
  } & {
77
77
  PaymentForm_QuoteFragment: "Quote";
78
78
  } & {
@@ -86,7 +86,7 @@ export declare const QuoteCheckout_QuoteFragment: import("gql.tada").TadaDocumen
86
86
  export declare const QuoteCheckout_SubscriptionFragment: import("gql.tada").TadaDocumentNode<{
87
87
  id: string;
88
88
  [$tada.fragmentRefs]: {
89
- shouldShowCouponEditor_SubscriptionFragment: "Subscription";
89
+ canApplyCoupons_SubscriptionFragment: "Subscription";
90
90
  };
91
91
  }, {}, {
92
92
  fragment: "QuoteCheckout_SubscriptionFragment";
@@ -29,7 +29,7 @@ export declare const CheckoutSummary_QuoteFragment: import("gql.tada").TadaDocum
29
29
  }[];
30
30
  }[] | null;
31
31
  [$tada.fragmentRefs]: {
32
- shouldShowCouponEditor_QuoteFragment: "Quote";
32
+ canApplyCoupons_QuoteFragment: "Quote";
33
33
  };
34
34
  }, {}, {
35
35
  fragment: "CheckoutSummary_QuoteFragment";
@@ -0,0 +1,14 @@
1
+ import { ResultOf } from 'gql.tada';
2
+ declare const sortQuoteChangeCharges_QuoteChargeFragment: import("gql.tada").TadaDocumentNode<{
3
+ kind: "SUBSCRIBE" | "UPDATE" | "RENEW" | "REINSTATE" | "UNSUBSCRIBE" | "ADJUSTMENT" | "COUPON" | "DISCOUNT" | "CREDIT" | "PRICE_UPDATE" | "QUANTITY_UPDATE" | "FREE_PERIOD_DISCOUNT" | "ACTIVATE" | null;
4
+ }, {}, {
5
+ fragment: "sortQuoteChangeCharges_QuoteChargeFragment";
6
+ on: "QuoteCharge";
7
+ masked: true;
8
+ }>;
9
+ /**
10
+ * Sorts quote change charges so that coupon charges appear at the end of the list.
11
+ * Uses a generic type so the full charge shape is preserved.
12
+ */
13
+ export declare function sortQuoteChangeCharges<T extends ResultOf<typeof sortQuoteChangeCharges_QuoteChargeFragment>>(charges: T[]): T[];
14
+ export {};
@@ -3,6 +3,8 @@ export declare const Signup_QuoteFragment: import("gql.tada").TadaDocumentNode<{
3
3
  CheckoutSummary_QuoteFragment: "Quote";
4
4
  } & {
5
5
  PaymentForms_QuoteFragment: "Quote";
6
+ } & {
7
+ useApplyDefaultCoupon_QuoteFragment: "Quote";
6
8
  };
7
9
  id: string | null;
8
10
  currencyId: string;
@@ -0,0 +1,21 @@
1
+ import { FragmentOf } from 'gql.tada';
2
+ export declare const useApplyDefaultCoupon_QuoteFragment: import("gql.tada").TadaDocumentNode<{
3
+ [$tada.fragmentRefs]: {
4
+ canApplyCoupons_QuoteFragment: "Quote";
5
+ };
6
+ }, {}, {
7
+ fragment: "useApplyDefaultCoupon_QuoteFragment";
8
+ on: "Quote";
9
+ masked: true;
10
+ }>;
11
+ /**
12
+ * Applies a default coupon code once when quoteChangeId is available.
13
+ * Uses a ref to ensure coupon code is only applied once.
14
+ */
15
+ export default function useApplyDefaultCoupon({ couponCode, quoteChangeId, quote: maskedQuote, activeCouponsExist, addCoupon, }: {
16
+ couponCode: string | undefined;
17
+ quoteChangeId: string | undefined;
18
+ quote: FragmentOf<typeof useApplyDefaultCoupon_QuoteFragment> | undefined | null;
19
+ activeCouponsExist: boolean;
20
+ addCoupon: (code: string) => void;
21
+ }): void;
@@ -1,22 +1,22 @@
1
1
  import { FragmentOf } from 'gql.tada';
2
- export declare const shouldShowCouponEditor_QuoteFragment: import("gql.tada").TadaDocumentNode<{
2
+ export declare const canApplyCoupons_QuoteFragment: import("gql.tada").TadaDocumentNode<{
3
3
  id: string | null;
4
4
  kind: "SUBSCRIBE" | "UPDATE" | "RENEW" | "REINSTATE" | "UNSUBSCRIBE" | "ADJUSTMENT" | "COUPON" | "DISCOUNT" | "CREDIT" | "PRICE_UPDATE" | "QUANTITY_UPDATE" | "FREE_PERIOD_DISCOUNT" | "ACTIVATE";
5
5
  amountDue: number | null;
6
6
  }, {}, {
7
- fragment: "shouldShowCouponEditor_QuoteFragment";
7
+ fragment: "canApplyCoupons_QuoteFragment";
8
8
  on: "Quote";
9
9
  masked: true;
10
10
  }>;
11
- export declare const shouldShowCouponEditor_SubscriptionFragment: import("gql.tada").TadaDocumentNode<{
11
+ export declare const canApplyCoupons_SubscriptionFragment: import("gql.tada").TadaDocumentNode<{
12
12
  id: string;
13
13
  state: "ACTIVE" | "TRIAL" | "CANCELED" | "EXPIRED" | "TRIAL_EXPIRED" | "PENDING";
14
14
  charges: {
15
15
  discountedPrice: string | null;
16
16
  }[] | null;
17
17
  }, {}, {
18
- fragment: "shouldShowCouponEditor_SubscriptionFragment";
18
+ fragment: "canApplyCoupons_SubscriptionFragment";
19
19
  on: "Subscription";
20
20
  masked: true;
21
21
  }>;
22
- export declare function shouldShowCouponEditor(maskedQuote: FragmentOf<typeof shouldShowCouponEditor_QuoteFragment>, activeCouponsExist: boolean, maskedUpgradingSubscription?: FragmentOf<typeof shouldShowCouponEditor_SubscriptionFragment>): boolean;
22
+ export declare function canApplyCoupons(maskedQuote: FragmentOf<typeof canApplyCoupons_QuoteFragment> | undefined | null, activeCouponsExist: boolean, maskedUpgradingSubscription?: FragmentOf<typeof canApplyCoupons_SubscriptionFragment>): boolean;
package/dist/esm/index.js CHANGED
@@ -1281,7 +1281,7 @@ const DEFAULT_CONFIG = {
1281
1281
  };
1282
1282
 
1283
1283
  // This will be replaced at build time by rollup-plugin-replace
1284
- const PACKAGE_VERSION = '1.8.0-beta.3';
1284
+ const PACKAGE_VERSION = '1.8.0-beta.4';
1285
1285
  const createRequestHeaders = (token) => {
1286
1286
  const headers = createClientDevHeaders({ token });
1287
1287
  // Add the components version header
@@ -22953,15 +22953,15 @@ function QuotesWrapper() {
22953
22953
  return (jsx(TransactionsDisplay, { transactions: quotesAsTransactions, onSearchValueChanged: setSearch, search: search }));
22954
22954
  }
22955
22955
 
22956
- const shouldShowCouponEditor_QuoteFragment = t(`
22957
- fragment shouldShowCouponEditor_QuoteFragment on Quote {
22956
+ const canApplyCoupons_QuoteFragment = t(`
22957
+ fragment canApplyCoupons_QuoteFragment on Quote {
22958
22958
  id
22959
22959
  kind
22960
22960
  amountDue
22961
22961
  }
22962
22962
  `, []);
22963
- const shouldShowCouponEditor_SubscriptionFragment = t(`
22964
- fragment shouldShowCouponEditor_SubscriptionFragment on Subscription {
22963
+ const canApplyCoupons_SubscriptionFragment = t(`
22964
+ fragment canApplyCoupons_SubscriptionFragment on Subscription {
22965
22965
  id
22966
22966
  state
22967
22967
  charges {
@@ -22969,10 +22969,10 @@ const shouldShowCouponEditor_SubscriptionFragment = t(`
22969
22969
  }
22970
22970
  }
22971
22971
  `, []);
22972
- function shouldShowCouponEditor(maskedQuote, activeCouponsExist, maskedUpgradingSubscription) {
22972
+ function canApplyCoupons(maskedQuote, activeCouponsExist, maskedUpgradingSubscription) {
22973
22973
  var _a, _b;
22974
- const quote = readFragment(shouldShowCouponEditor_QuoteFragment, maskedQuote);
22975
- const upgradingSubscription = readFragment(shouldShowCouponEditor_SubscriptionFragment, maskedUpgradingSubscription);
22974
+ const quote = readFragment(canApplyCoupons_QuoteFragment, maskedQuote);
22975
+ const upgradingSubscription = readFragment(canApplyCoupons_SubscriptionFragment, maskedUpgradingSubscription);
22976
22976
  const upgradingFromTrial = ((_a = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL') ||
22977
22977
  ((_b = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) ===
22978
22978
  t.scalar('SubscriptionState', 'TRIAL_EXPIRED');
@@ -22990,7 +22990,10 @@ function shouldShowCouponEditor(maskedQuote, activeCouponsExist, maskedUpgrading
22990
22990
  return false;
22991
22991
  }
22992
22992
  if (quoteKindIsValid) {
22993
- return activeCouponsExist && (upgradingFromTrial || upgradingFromFree() || signingUpForNewSubscription);
22993
+ const result = activeCouponsExist &&
22994
+ (upgradingFromTrial || upgradingFromFree() || signingUpForNewSubscription);
22995
+ console.log('returning result', result);
22996
+ return result;
22994
22997
  }
22995
22998
  return false;
22996
22999
  }
@@ -23002,6 +23005,27 @@ function CouponEditor({ className, onAddCoupon, isAddingCoupon, couponCode, setC
23002
23005
  return (jsx("div", { className: `bunny-flex bunny-flex-col bunny-gap-2 ${className}`, children: jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2", children: [jsx(Input, { value: couponCode, onChange: e => setCouponCode(e.target.value), placeholder: "Coupon code", disabled: isAddingCoupon, size: "small" }), jsx(Button, { loading: isAddingCoupon, type: "primary", onClick: handleAddCoupon, disabled: couponCode.length === 0, children: "Apply" })] }) }));
23003
23006
  }
23004
23007
 
23008
+ t(`
23009
+ fragment sortQuoteChangeCharges_QuoteChargeFragment on QuoteCharge {
23010
+ kind
23011
+ }
23012
+ `, []);
23013
+ /**
23014
+ * Sorts quote change charges so that coupon charges appear at the end of the list.
23015
+ * Uses a generic type so the full charge shape is preserved.
23016
+ */
23017
+ function sortQuoteChangeCharges(charges) {
23018
+ return [...charges].sort((chargeA, chargeB) => {
23019
+ const aIsCoupon = chargeA.kind === 'COUPON';
23020
+ const bIsCoupon = chargeB.kind === 'COUPON';
23021
+ if (aIsCoupon && !bIsCoupon)
23022
+ return 1;
23023
+ if (!aIsCoupon && bIsCoupon)
23024
+ return -1;
23025
+ return 0;
23026
+ });
23027
+ }
23028
+
23005
23029
  const { Text: Text$r } = Typography;
23006
23030
  const CheckoutSummary_PriceListFragment = t(`
23007
23031
  fragment CheckoutSummary_PriceListFragment on PriceList {
@@ -23031,14 +23055,14 @@ const CheckoutSummary_QuoteFragment = t(`
23031
23055
  currencyId
23032
23056
  }
23033
23057
  }
23034
- ...shouldShowCouponEditor_QuoteFragment
23058
+ ...canApplyCoupons_QuoteFragment
23035
23059
  }
23036
- `, [shouldShowCouponEditor_QuoteFragment]);
23060
+ `, [canApplyCoupons_QuoteFragment]);
23037
23061
  function CheckoutSummary({ quote: maskedQuote, className, onAddCoupon, onRemoveCoupon, isRemovingCoupon, priceList: maskedPriceList, isAddingCoupon, couponCode, setCouponCode, activeCouponsExist, }) {
23038
23062
  var _a, _b;
23039
23063
  const priceList = readFragment(CheckoutSummary_PriceListFragment, maskedPriceList);
23040
23064
  const quote = readFragment(CheckoutSummary_QuoteFragment, maskedQuote);
23041
- return (jsxs("div", { className: `${className} bunny-space-y-4`, children: [jsxs(Text$r, { children: [jsxs("div", { className: "bunny-text-lg bunny-font-medium bunny-mb-4", children: ["Checkout summary - ", (_a = priceList === null || priceList === void 0 ? void 0 : priceList.product) === null || _a === void 0 ? void 0 : _a.name, " ", priceList === null || priceList === void 0 ? void 0 : priceList.name] }), jsx("div", { className: "bunny-space-y-4", children: (_b = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _b === void 0 ? void 0 : _b.map(quoteChange => quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.charges.map(charge => {
23065
+ return (jsxs("div", { className: `${className} bunny-space-y-4`, children: [jsxs(Text$r, { children: [jsxs("div", { className: "bunny-text-lg bunny-font-medium bunny-mb-4", children: ["Checkout summary - ", (_a = priceList === null || priceList === void 0 ? void 0 : priceList.product) === null || _a === void 0 ? void 0 : _a.name, " ", priceList === null || priceList === void 0 ? void 0 : priceList.name] }), jsx("div", { className: "bunny-space-y-4", children: (_b = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _b === void 0 ? void 0 : _b.map(quoteChange => sortQuoteChangeCharges(quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.charges).map(charge => {
23042
23066
  var _a;
23043
23067
  const multiplier = charge.kind === 'COUPON' ? -1 : 1;
23044
23068
  return (jsxs("div", { className: "bunny-grid bunny-grid-cols-3 bunny-gap-4 bunny-items-center", children: [jsx("div", { className: "bunny-col-span-1", children: charge.name }), jsx("div", { className: "bunny-col-span-1 bunny-text-center", children: ((_a = charge.coupon) === null || _a === void 0 ? void 0 : _a.couponCode) ? (jsx("button", { onClick: () => {
@@ -23051,7 +23075,7 @@ function CheckoutSummary({ quote: maskedQuote, className, onAddCoupon, onRemoveC
23051
23075
  }
23052
23076
  onRemoveCoupon((_b = charge.coupon) === null || _b === void 0 ? void 0 : _b.couponCode);
23053
23077
  }, className: "bunny-text-orange-500 hover:bunny-text-orange-400 bunny-cursor-pointer bunny-bg-transparent bunny-border-none", children: "Remove" })) : (jsx("div", { children: charge.quantity })) }), jsx("div", { className: "bunny-col-span-1 bunny-text-right", children: formatCurrency(multiplier * (charge.subtotal || 0), charge.currencyId) })] }, charge.id));
23054
- })) }), jsx(CheckoutSummaryDivider, {}), jsxs("div", { className: "bunny-space-y-4", children: [jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsx("div", { children: "Subtotal" }), jsx("div", { children: formatCurrency(quote.subtotal, quote.currencyId) })] }), jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsx("div", { children: "Taxes" }), jsx("div", { children: formatCurrency(quote.taxAmount, quote.currencyId) })] })] }), jsx(CheckoutSummaryDivider, {}), jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsx("div", { children: "Total" }), jsx("div", { children: formatCurrency(quote.amountDue, quote.currencyId) })] })] }), shouldShowCouponEditor(quote, activeCouponsExist) && (jsx(CouponEditor, { className: "bunny-w-full", onAddCoupon: onAddCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode }))] }));
23078
+ })) }), jsx(CheckoutSummaryDivider, {}), jsxs("div", { className: "bunny-space-y-4", children: [jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsx("div", { children: "Subtotal" }), jsx("div", { children: formatCurrency(quote.subtotal, quote.currencyId) })] }), jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsx("div", { children: "Taxes" }), jsx("div", { children: formatCurrency(quote.taxAmount, quote.currencyId) })] })] }), jsx(CheckoutSummaryDivider, {}), jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsx("div", { children: "Total" }), jsx("div", { children: formatCurrency(quote.amountDue, quote.currencyId) })] })] }), canApplyCoupons(quote, activeCouponsExist) && (jsx(CouponEditor, { className: "bunny-w-full", onAddCoupon: onAddCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode }))] }));
23055
23079
  }
23056
23080
  const CheckoutSummaryDivider = () => {
23057
23081
  return (jsx("div", { className: "bunny-my-2", children: jsx(Divider, { className: "m-0" }) }));
@@ -23102,10 +23126,36 @@ function InitialSignupForm({ className, onSubmit, submitting, defaultValues, })
23102
23126
  } }) }) }) }), jsx(Form.Item, { children: jsx(Button, { type: "primary", onClick: handleSubmit, loading: submitting, className: "bunny-w-full", children: "Proceed to payment" }) })] }) }));
23103
23127
  }
23104
23128
 
23129
+ const useApplyDefaultCoupon_QuoteFragment = t(`
23130
+ fragment useApplyDefaultCoupon_QuoteFragment on Quote {
23131
+ ...canApplyCoupons_QuoteFragment
23132
+ }
23133
+ `, [canApplyCoupons_QuoteFragment]);
23134
+ /**
23135
+ * Applies a default coupon code once when quoteChangeId is available.
23136
+ * Uses a ref to ensure coupon code is only applied once.
23137
+ */
23138
+ function useApplyDefaultCoupon({ couponCode, quoteChangeId, quote: maskedQuote, activeCouponsExist, addCoupon, }) {
23139
+ const defaultCouponAppliedRef = useRef(undefined);
23140
+ // Derived state
23141
+ const quote = readFragment(useApplyDefaultCoupon_QuoteFragment, maskedQuote);
23142
+ const canApplyCouponsResult = canApplyCoupons(quote, activeCouponsExist);
23143
+ useEffect(() => {
23144
+ if (couponCode &&
23145
+ quoteChangeId &&
23146
+ defaultCouponAppliedRef.current !== couponCode &&
23147
+ canApplyCouponsResult) {
23148
+ addCoupon(couponCode);
23149
+ defaultCouponAppliedRef.current = couponCode;
23150
+ }
23151
+ }, [couponCode, quoteChangeId, addCoupon, canApplyCouponsResult]);
23152
+ }
23153
+
23105
23154
  const Signup_QuoteFragment = t(`
23106
23155
  fragment Signup_QuoteFragment on Quote {
23107
23156
  ...CheckoutSummary_QuoteFragment
23108
23157
  ...PaymentForms_QuoteFragment
23158
+ ...useApplyDefaultCoupon_QuoteFragment
23109
23159
  id
23110
23160
  currencyId
23111
23161
  amountDue
@@ -23113,7 +23163,7 @@ const Signup_QuoteFragment = t(`
23113
23163
  id
23114
23164
  }
23115
23165
  }
23116
- `, [CheckoutSummary_QuoteFragment, PaymentForms_QuoteFragment]);
23166
+ `, [CheckoutSummary_QuoteFragment, PaymentForms_QuoteFragment, useApplyDefaultCoupon_QuoteFragment]);
23117
23167
 
23118
23168
  const query$6 = t(`
23119
23169
  query quote($id: ID) {
@@ -23569,7 +23619,6 @@ function Signup({ companyName, priceListCode, returnUrl, couponCode, className,
23569
23619
  const [portalSessionToken, setPortalSessionToken] = useState(undefined);
23570
23620
  const token = portalSessionToken || tokenFromContexts;
23571
23621
  const [purchaseSucceeded, setPurchaseSucceeded] = useState(false);
23572
- const defaultCouponAppliedRef = useRef(undefined);
23573
23622
  const [couponEditorCouponCode, setCouponEditorCouponCode] = useState('');
23574
23623
  // Read fragment
23575
23624
  const initialQuoteId = (_a = readFragment(Signup_QuoteFragment, initialQuote)) === null || _a === void 0 ? void 0 : _a.id;
@@ -23686,13 +23735,7 @@ function Signup({ companyName, priceListCode, returnUrl, couponCode, className,
23686
23735
  handleRecalculateTaxes(quote === null || quote === void 0 ? void 0 : quote.id);
23687
23736
  },
23688
23737
  });
23689
- // Handle default coupon application
23690
- useEffect(() => {
23691
- if (couponCode && quoteChangeId && defaultCouponAppliedRef.current !== couponCode) {
23692
- addCoupon(couponCode);
23693
- defaultCouponAppliedRef.current = couponCode;
23694
- }
23695
- }, [couponCode, quoteChangeId]);
23738
+ useApplyDefaultCoupon({ couponCode, quoteChangeId, addCoupon, activeCouponsExist, quote });
23696
23739
  async function handleSubmit(formData) {
23697
23740
  if (selfServiceBuyEnabled === false) {
23698
23741
  handleShowSelfServiceBuyWarning();
@@ -23922,22 +23965,22 @@ const QuoteCheckout_QuoteFragment = t(`
23922
23965
  }
23923
23966
  }
23924
23967
  ...QuoteFields_QuoteFragment
23925
- ...shouldShowCouponEditor_QuoteFragment
23968
+ ...canApplyCoupons_QuoteFragment
23926
23969
  ...PaymentForm_QuoteFragment
23927
23970
  ...getQuoteAmountDue_QuoteFragment
23928
23971
  }
23929
23972
  `, [
23930
23973
  QuoteFields_QuoteFragment,
23931
- shouldShowCouponEditor_QuoteFragment,
23974
+ canApplyCoupons_QuoteFragment,
23932
23975
  PaymentForm_QuoteFragment,
23933
23976
  getQuoteAmountDue_QuoteFragment,
23934
23977
  ]);
23935
23978
  const QuoteCheckout_SubscriptionFragment = t(`
23936
23979
  fragment QuoteCheckout_SubscriptionFragment on Subscription {
23937
23980
  id
23938
- ...shouldShowCouponEditor_SubscriptionFragment
23981
+ ...canApplyCoupons_SubscriptionFragment
23939
23982
  }
23940
- `, [shouldShowCouponEditor_SubscriptionFragment]);
23983
+ `, [canApplyCoupons_SubscriptionFragment]);
23941
23984
  const showSuccessNotification = useSuccessNotification();
23942
23985
  const QuoteCheckout = ({ account, onSuccess, onFail, quote: maskedQuote, taxationRequiredAccountFields, isUpdatingQuote, onRecalculateTaxes, isRecalculatingTaxes, }) => {
23943
23986
  var _a, _b, _c, _d, _e;
@@ -24023,7 +24066,7 @@ const QuoteCheckout = ({ account, onSuccess, onFail, quote: maskedQuote, taxatio
24023
24066
  if (taxationRequiredAccountFields)
24024
24067
  return (jsx(PaymentFormWrapper, { setMaxHeight: false, children: jsx(TaxationForm, { account: account, accountId: quote.accountId }) }));
24025
24068
  return (jsx(PaymentFormWrapper, { setMaxHeight: false, children: paymentRequired ? (jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2 bunny-w-full", children: [jsx(PaymentForm, { onPaymentSuccess: onSuccess, quote: quote, onSavePaymentMethod: (paymentMethod) => onPaymentMethodSaved === null || onPaymentMethodSaved === void 0 ? void 0 : onPaymentMethodSaved(paymentMethod.savedPaymentMethodResponse.paymentMethodId), onPaymentMethodRemoved: (paymentMethod) => onPaymentMethodRemoved === null || onPaymentMethodRemoved === void 0 ? void 0 : onPaymentMethodRemoved(paymentMethod.id), disablePayButton: isFinalizingQuote }), isFinalizingQuote && jsx(QuoteLoadingIndicator, {}), (couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.length) === 0 ? (jsx(Fragment, { children: upgradingSubscription &&
24026
- shouldShowCouponEditor(quote, activeCouponsExist, upgradingSubscription) && (jsx(CouponEditor, { className: "bunny-px-4 bunny-pt-1", onAddCoupon: addCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode })) })) : (jsx(Button, { type: "link", loading: isRemovingCoupon, onClick: () => {
24069
+ canApplyCoupons(quote, activeCouponsExist, upgradingSubscription) && (jsx(CouponEditor, { className: "bunny-px-4 bunny-pt-1", onAddCoupon: addCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode })) })) : (jsx(Button, { type: "link", loading: isRemovingCoupon, onClick: () => {
24027
24070
  couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.forEach(couponCharge => {
24028
24071
  var _a;
24029
24072
  const couponCode = (_a = couponCharge === null || couponCharge === void 0 ? void 0 : couponCharge.coupon) === null || _a === void 0 ? void 0 : _a.couponCode;
@@ -72,7 +72,7 @@ export declare const QuoteCheckout_QuoteFragment: import("gql.tada").TadaDocumen
72
72
  }[];
73
73
  kind: "SUBSCRIBE" | "UPDATE" | "RENEW" | "REINSTATE" | "UNSUBSCRIBE" | "ADJUSTMENT" | "COUPON" | "DISCOUNT" | "CREDIT" | "PRICE_UPDATE" | "QUANTITY_UPDATE" | "FREE_PERIOD_DISCOUNT" | "ACTIVATE";
74
74
  [$tada.fragmentRefs]: {
75
- shouldShowCouponEditor_QuoteFragment: "Quote";
75
+ canApplyCoupons_QuoteFragment: "Quote";
76
76
  } & {
77
77
  PaymentForm_QuoteFragment: "Quote";
78
78
  } & {
@@ -86,7 +86,7 @@ export declare const QuoteCheckout_QuoteFragment: import("gql.tada").TadaDocumen
86
86
  export declare const QuoteCheckout_SubscriptionFragment: import("gql.tada").TadaDocumentNode<{
87
87
  id: string;
88
88
  [$tada.fragmentRefs]: {
89
- shouldShowCouponEditor_SubscriptionFragment: "Subscription";
89
+ canApplyCoupons_SubscriptionFragment: "Subscription";
90
90
  };
91
91
  }, {}, {
92
92
  fragment: "QuoteCheckout_SubscriptionFragment";
@@ -29,7 +29,7 @@ export declare const CheckoutSummary_QuoteFragment: import("gql.tada").TadaDocum
29
29
  }[];
30
30
  }[] | null;
31
31
  [$tada.fragmentRefs]: {
32
- shouldShowCouponEditor_QuoteFragment: "Quote";
32
+ canApplyCoupons_QuoteFragment: "Quote";
33
33
  };
34
34
  }, {}, {
35
35
  fragment: "CheckoutSummary_QuoteFragment";
@@ -0,0 +1,14 @@
1
+ import { ResultOf } from 'gql.tada';
2
+ declare const sortQuoteChangeCharges_QuoteChargeFragment: import("gql.tada").TadaDocumentNode<{
3
+ kind: "SUBSCRIBE" | "UPDATE" | "RENEW" | "REINSTATE" | "UNSUBSCRIBE" | "ADJUSTMENT" | "COUPON" | "DISCOUNT" | "CREDIT" | "PRICE_UPDATE" | "QUANTITY_UPDATE" | "FREE_PERIOD_DISCOUNT" | "ACTIVATE" | null;
4
+ }, {}, {
5
+ fragment: "sortQuoteChangeCharges_QuoteChargeFragment";
6
+ on: "QuoteCharge";
7
+ masked: true;
8
+ }>;
9
+ /**
10
+ * Sorts quote change charges so that coupon charges appear at the end of the list.
11
+ * Uses a generic type so the full charge shape is preserved.
12
+ */
13
+ export declare function sortQuoteChangeCharges<T extends ResultOf<typeof sortQuoteChangeCharges_QuoteChargeFragment>>(charges: T[]): T[];
14
+ export {};
@@ -3,6 +3,8 @@ export declare const Signup_QuoteFragment: import("gql.tada").TadaDocumentNode<{
3
3
  CheckoutSummary_QuoteFragment: "Quote";
4
4
  } & {
5
5
  PaymentForms_QuoteFragment: "Quote";
6
+ } & {
7
+ useApplyDefaultCoupon_QuoteFragment: "Quote";
6
8
  };
7
9
  id: string | null;
8
10
  currencyId: string;
@@ -0,0 +1,21 @@
1
+ import { FragmentOf } from 'gql.tada';
2
+ export declare const useApplyDefaultCoupon_QuoteFragment: import("gql.tada").TadaDocumentNode<{
3
+ [$tada.fragmentRefs]: {
4
+ canApplyCoupons_QuoteFragment: "Quote";
5
+ };
6
+ }, {}, {
7
+ fragment: "useApplyDefaultCoupon_QuoteFragment";
8
+ on: "Quote";
9
+ masked: true;
10
+ }>;
11
+ /**
12
+ * Applies a default coupon code once when quoteChangeId is available.
13
+ * Uses a ref to ensure coupon code is only applied once.
14
+ */
15
+ export default function useApplyDefaultCoupon({ couponCode, quoteChangeId, quote: maskedQuote, activeCouponsExist, addCoupon, }: {
16
+ couponCode: string | undefined;
17
+ quoteChangeId: string | undefined;
18
+ quote: FragmentOf<typeof useApplyDefaultCoupon_QuoteFragment> | undefined | null;
19
+ activeCouponsExist: boolean;
20
+ addCoupon: (code: string) => void;
21
+ }): void;
@@ -1,22 +1,22 @@
1
1
  import { FragmentOf } from 'gql.tada';
2
- export declare const shouldShowCouponEditor_QuoteFragment: import("gql.tada").TadaDocumentNode<{
2
+ export declare const canApplyCoupons_QuoteFragment: import("gql.tada").TadaDocumentNode<{
3
3
  id: string | null;
4
4
  kind: "SUBSCRIBE" | "UPDATE" | "RENEW" | "REINSTATE" | "UNSUBSCRIBE" | "ADJUSTMENT" | "COUPON" | "DISCOUNT" | "CREDIT" | "PRICE_UPDATE" | "QUANTITY_UPDATE" | "FREE_PERIOD_DISCOUNT" | "ACTIVATE";
5
5
  amountDue: number | null;
6
6
  }, {}, {
7
- fragment: "shouldShowCouponEditor_QuoteFragment";
7
+ fragment: "canApplyCoupons_QuoteFragment";
8
8
  on: "Quote";
9
9
  masked: true;
10
10
  }>;
11
- export declare const shouldShowCouponEditor_SubscriptionFragment: import("gql.tada").TadaDocumentNode<{
11
+ export declare const canApplyCoupons_SubscriptionFragment: import("gql.tada").TadaDocumentNode<{
12
12
  id: string;
13
13
  state: "ACTIVE" | "TRIAL" | "CANCELED" | "EXPIRED" | "TRIAL_EXPIRED" | "PENDING";
14
14
  charges: {
15
15
  discountedPrice: string | null;
16
16
  }[] | null;
17
17
  }, {}, {
18
- fragment: "shouldShowCouponEditor_SubscriptionFragment";
18
+ fragment: "canApplyCoupons_SubscriptionFragment";
19
19
  on: "Subscription";
20
20
  masked: true;
21
21
  }>;
22
- export declare function shouldShowCouponEditor(maskedQuote: FragmentOf<typeof shouldShowCouponEditor_QuoteFragment>, activeCouponsExist: boolean, maskedUpgradingSubscription?: FragmentOf<typeof shouldShowCouponEditor_SubscriptionFragment>): boolean;
22
+ export declare function canApplyCoupons(maskedQuote: FragmentOf<typeof canApplyCoupons_QuoteFragment> | undefined | null, activeCouponsExist: boolean, maskedUpgradingSubscription?: FragmentOf<typeof canApplyCoupons_SubscriptionFragment>): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bunnyapp/components",
3
- "version": "1.8.0-beta.4",
3
+ "version": "1.8.0-beta.5",
4
4
  "description": "Components from the Bunny portal to embed Bunny UI functionality into your application.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",