@bunnyapp/components 1.7.0-beta.32 → 1.7.0-beta.34

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.
Files changed (31) hide show
  1. package/dist/cjs/index.js +1621 -1663
  2. package/dist/cjs/types/src/components/Signup/CheckoutSummary.d.ts +29 -3
  3. package/dist/cjs/types/src/components/Signup/PaymentForms.d.ts +1 -1
  4. package/dist/cjs/types/src/components/Signup/PriceListDisplay.d.ts +2 -0
  5. package/dist/cjs/types/src/components/Signup/fragments/Signup_PriceListFragment.d.ts +1 -0
  6. package/dist/cjs/types/src/components/Signup/fragments/Signup_QuoteFragment.d.ts +17 -0
  7. package/dist/cjs/types/src/components/Signup/mutations/accountSignup.d.ts +58 -0
  8. package/dist/cjs/types/src/components/Signup/mutations/quoteAccountSignup.d.ts +31 -0
  9. package/dist/cjs/types/src/{graphql → components/Signup}/mutations/quoteRecalculateTaxes.d.ts +5 -1
  10. package/dist/cjs/types/src/components/Signup/queries/getQuote.d.ts +10 -0
  11. package/dist/cjs/types/src/components/Subscriptions/Upgrade/PlanPicker/checkoutBar/CheckoutPrice.d.ts +8 -3
  12. package/dist/cjs/types/src/utils/couponUtils.d.ts +2 -1
  13. package/dist/esm/index.js +1623 -1665
  14. package/dist/esm/types/src/components/Signup/CheckoutSummary.d.ts +29 -3
  15. package/dist/esm/types/src/components/Signup/PaymentForms.d.ts +1 -1
  16. package/dist/esm/types/src/components/Signup/PriceListDisplay.d.ts +2 -0
  17. package/dist/esm/types/src/components/Signup/fragments/Signup_PriceListFragment.d.ts +1 -0
  18. package/dist/esm/types/src/components/Signup/fragments/Signup_QuoteFragment.d.ts +17 -0
  19. package/dist/esm/types/src/components/Signup/mutations/accountSignup.d.ts +58 -0
  20. package/dist/esm/types/src/components/Signup/mutations/quoteAccountSignup.d.ts +31 -0
  21. package/dist/esm/types/src/{graphql → components/Signup}/mutations/quoteRecalculateTaxes.d.ts +5 -1
  22. package/dist/esm/types/src/components/Signup/queries/getQuote.d.ts +10 -0
  23. package/dist/esm/types/src/components/Subscriptions/Upgrade/PlanPicker/checkoutBar/CheckoutPrice.d.ts +8 -3
  24. package/dist/esm/types/src/utils/couponUtils.d.ts +2 -1
  25. package/package.json +2 -2
  26. package/dist/cjs/types/src/graphql/mutations/accountSignup.d.ts +0 -11
  27. package/dist/cjs/types/src/graphql/mutations/quoteAccountSignup.d.ts +0 -15
  28. package/dist/cjs/types/src/graphql/queries/getQuote.d.ts +0 -36
  29. package/dist/esm/types/src/graphql/mutations/accountSignup.d.ts +0 -11
  30. package/dist/esm/types/src/graphql/mutations/quoteAccountSignup.d.ts +0 -15
  31. package/dist/esm/types/src/graphql/queries/getQuote.d.ts +0 -36
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.7.0-beta.31';
1286
+ const PACKAGE_VERSION = '1.7.0-beta.33';
1287
1287
  const createRequestHeaders = (token) => {
1288
1288
  const headers = createClientDevHeaders({ token });
1289
1289
  // Add the components version header
@@ -1333,7 +1333,7 @@ const createClientDevHeaders = ({ token, componentsVersion, additionalHeaders, }
1333
1333
  return headers;
1334
1334
  };
1335
1335
 
1336
- const MUTATION$7 = `
1336
+ const MUTATION$5 = `
1337
1337
  query FormattedInvoice($id: ID) {
1338
1338
  formattedInvoice(id: $id) {
1339
1339
  amount
@@ -1401,7 +1401,7 @@ query FormattedInvoice($id: ID) {
1401
1401
  const getFormattedInvoice = async ({ id, token, apiHost, }) => {
1402
1402
  const vars = { id };
1403
1403
  const response = await gqlRequest({
1404
- query: MUTATION$7,
1404
+ query: MUTATION$5,
1405
1405
  token,
1406
1406
  vars,
1407
1407
  apiHost,
@@ -2248,7 +2248,7 @@ function readFragment(...r) {
2248
2248
 
2249
2249
  var t = initGraphQLTada();
2250
2250
 
2251
- const query$9 = t(`
2251
+ const query$a = t(`
2252
2252
  query entityBranding {
2253
2253
  entityBranding {
2254
2254
  accentColor
@@ -2258,13 +2258,17 @@ const query$9 = t(`
2258
2258
  }
2259
2259
  `);
2260
2260
  const getBranding = async ({ token, apiHost }) => {
2261
- return await execute(query$9, { apiHost, token }, {});
2261
+ return await execute(query$a, { apiHost, token }, {});
2262
2262
  };
2263
2263
 
2264
2264
  const BunnyContext = react.createContext({});
2265
2265
  // Every component shares similar props and functionality, which this wrapper handles.
2266
2266
  function BunnyProvider({ children, darkMode = false, queryClient, apiHost, token, onTokenExpired, onUserUnavailable, onInvalidOrMissingAuthorization, suppressUserUnavailableErrorNotification = false, configProviderProps, }) {
2267
- return (jsxRuntime.jsx(BunnyProviderCallbacksProvider, { value: { onUserUnavailable, onInvalidOrMissingAuthorization, suppressUserUnavailableErrorNotification }, children: jsxRuntime.jsx(BunnyProviderContent, { darkMode: darkMode, queryClient: queryClient, apiHost: apiHost, token: token, onTokenExpired: onTokenExpired, configProviderProps: configProviderProps, children: children }) }));
2267
+ return (jsxRuntime.jsx(BunnyProviderCallbacksProvider, { value: {
2268
+ onUserUnavailable,
2269
+ onInvalidOrMissingAuthorization,
2270
+ suppressUserUnavailableErrorNotification,
2271
+ }, children: jsxRuntime.jsx(BunnyProviderContent, { darkMode: darkMode, queryClient: queryClient, apiHost: apiHost, token: token, onTokenExpired: onTokenExpired, configProviderProps: configProviderProps, children: children }) }));
2268
2272
  }
2269
2273
  function BunnyProviderContent({ children, darkMode = false, queryClient, apiHost, token, onTokenExpired, configProviderProps, }) {
2270
2274
  const createQueryClient = useCreateQueryClient();
@@ -19832,7 +19836,7 @@ const PaymentForm_PaymentMethodsFragment = t(`
19832
19836
  }
19833
19837
  `, [MiniCreditCard_PaymentMethodFragment]);
19834
19838
 
19835
- const query$8 = t(`
19839
+ const query$9 = t(`
19836
19840
  query PaymentMethods($accountId: ID) {
19837
19841
  paymentMethods(accountId: $accountId) {
19838
19842
  nodes {
@@ -19861,7 +19865,7 @@ const query$8 = t(`
19861
19865
  `, [PaymentForm_PaymentMethodsFragment]);
19862
19866
  const getPaymentMethods = async ({ apiHost, token, accountId, }) => {
19863
19867
  var _a, _b, _c;
19864
- const response = await execute(query$8, { apiHost, token }, { accountId });
19868
+ const response = await execute(query$9, { apiHost, token }, { accountId });
19865
19869
  // Filter out null values that are technically possible due to api schema
19866
19870
  return (_c = (_b = (_a = response === null || response === void 0 ? void 0 : response.paymentMethods) === null || _a === void 0 ? void 0 : _a.nodes) === null || _b === void 0 ? void 0 : _b.filter(paymentMethod => paymentMethod !== null)) !== null && _c !== void 0 ? _c : [];
19867
19871
  };
@@ -19886,7 +19890,7 @@ const usePaymentMethod = ({ accountId, enabled = true, }) => {
19886
19890
  };
19887
19891
  };
19888
19892
 
19889
- const mutation$e = t(`
19893
+ const mutation$g = t(`
19890
19894
  query PaymentPlugins($accountId: ID) {
19891
19895
  paymentPlugins(accountId: $accountId) {
19892
19896
  enabled
@@ -19914,7 +19918,7 @@ const mutation$e = t(`
19914
19918
  // }[];
19915
19919
  // };
19916
19920
  const getPaymentPlugins = async ({ apiHost, token, accountId, }) => {
19917
- const response = await execute(mutation$e, { apiHost, token }, { accountId });
19921
+ const response = await execute(mutation$g, { apiHost, token }, { accountId });
19918
19922
  return response === null || response === void 0 ? void 0 : response.paymentPlugins;
19919
19923
  };
19920
19924
  const usePaymentPlugins = (accountId) => {
@@ -20133,7 +20137,7 @@ function useSave$1({ onSaveSuccess, onSaveError, accountId, }) {
20133
20137
  return { save, isSaving };
20134
20138
  }
20135
20139
 
20136
- const MUTATION$6 = `
20140
+ const MUTATION$4 = `
20137
20141
  mutation checkout(
20138
20142
  $invoiceId: ID,
20139
20143
  $quoteId: ID,
@@ -20182,7 +20186,7 @@ const checkout = async ({ quoteId, invoiceId, paymentMethodId, paymentMethodData
20182
20186
  };
20183
20187
  }
20184
20188
  const response = await gqlRequest({
20185
- query: MUTATION$6,
20189
+ query: MUTATION$4,
20186
20190
  token,
20187
20191
  vars: mutationVars,
20188
20192
  apiHost: apiHost,
@@ -21183,7 +21187,7 @@ const useAutoSetDefaultPaymentMethod = ({ handleSetDefault, setDefaultPaymentMet
21183
21187
  ]);
21184
21188
  };
21185
21189
 
21186
- const query$7 = t(`
21190
+ const query$8 = t(`
21187
21191
  query GetCurrentUserData {
21188
21192
  company {
21189
21193
  name
@@ -21206,7 +21210,7 @@ const query$7 = t(`
21206
21210
  `);
21207
21211
  const getCurrentUserData = async ({ token, apiHost }) => {
21208
21212
  var _a, _b, _c, _d, _e, _f, _g, _h;
21209
- const response = await execute(query$7, { apiHost, token }, {});
21213
+ const response = await execute(query$8, { apiHost, token }, {});
21210
21214
  return {
21211
21215
  authObjectName: (_a = response === null || response === void 0 ? void 0 : response.currentUser) === null || _a === void 0 ? void 0 : _a.authObjectName,
21212
21216
  account: (_b = response === null || response === void 0 ? void 0 : response.currentUser) === null || _b === void 0 ? void 0 : _b.account,
@@ -21973,7 +21977,7 @@ const StyledModal$2 = (props) => {
21973
21977
  return jsxRuntime.jsx(ModalOverrideBrandStylings, { closable: false, ...props });
21974
21978
  };
21975
21979
 
21976
- const query$6 = t(`
21980
+ const query$7 = t(`
21977
21981
  query formattedQuote($id: ID) {
21978
21982
  formattedQuote(id: $id) {
21979
21983
  quote {
@@ -22124,7 +22128,7 @@ const query$6 = t(`
22124
22128
  QuoteButtons_FormattedQuoteFragment,
22125
22129
  ]);
22126
22130
  const getFormattedQuote = async ({ token, apiHost, id, }) => {
22127
- const response = await execute(query$6, { apiHost, token }, { id });
22131
+ const response = await execute(query$7, { apiHost, token }, { id });
22128
22132
  return response === null || response === void 0 ? void 0 : response.formattedQuote;
22129
22133
  };
22130
22134
 
@@ -22938,6 +22942,110 @@ function QuotesWrapper() {
22938
22942
  return (jsxRuntime.jsx(TransactionsDisplay, { transactions: quotesAsTransactions, onSearchValueChanged: setSearch, search: search }));
22939
22943
  }
22940
22944
 
22945
+ const shouldShowCouponEditor_QuoteFragment = t(`
22946
+ fragment shouldShowCouponEditor_QuoteFragment on Quote {
22947
+ id
22948
+ kind
22949
+ amountDue
22950
+ }
22951
+ `, []);
22952
+ const shouldShowCouponEditor_SubscriptionFragment = t(`
22953
+ fragment shouldShowCouponEditor_SubscriptionFragment on Subscription {
22954
+ id
22955
+ state
22956
+ charges {
22957
+ discountedPrice
22958
+ }
22959
+ }
22960
+ `, []);
22961
+ function shouldShowCouponEditor(maskedQuote, activeCouponsExist, maskedUpgradingSubscription) {
22962
+ var _a, _b;
22963
+ const quote = readFragment(shouldShowCouponEditor_QuoteFragment, maskedQuote);
22964
+ const upgradingSubscription = readFragment(shouldShowCouponEditor_SubscriptionFragment, maskedUpgradingSubscription);
22965
+ const upgradingFromTrial = ((_a = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL') ||
22966
+ ((_b = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) ===
22967
+ t.scalar('SubscriptionState', 'TRIAL_EXPIRED');
22968
+ const signingUpForNewSubscription = upgradingSubscription === undefined;
22969
+ function upgradingFromFree() {
22970
+ var _a;
22971
+ const totalPrice = (_a = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.charges) === null || _a === void 0 ? void 0 : _a.reduce((acc, charge) => acc + Number((charge === null || charge === void 0 ? void 0 : charge.discountedPrice) || 0), 0);
22972
+ return totalPrice === 0;
22973
+ }
22974
+ const quoteKindIsValid = (quote === null || quote === void 0 ? void 0 : quote.kind) === t.scalar('QuoteChangeKind', 'SUBSCRIBE') ||
22975
+ (quote === null || quote === void 0 ? void 0 : quote.kind) === t.scalar('QuoteChangeKind', 'ADJUSTMENT') ||
22976
+ (quote === null || quote === void 0 ? void 0 : quote.kind) === t.scalar('QuoteChangeKind', 'ACTIVATE');
22977
+ // if amount due is 0 do not show coupon editor
22978
+ if ((quote === null || quote === void 0 ? void 0 : quote.amountDue) == 0) {
22979
+ return false;
22980
+ }
22981
+ if (quoteKindIsValid) {
22982
+ return activeCouponsExist && (upgradingFromTrial || upgradingFromFree() || signingUpForNewSubscription);
22983
+ }
22984
+ return false;
22985
+ }
22986
+
22987
+ function CouponEditor({ className, onAddCoupon, isAddingCoupon, couponCode, setCouponCode, }) {
22988
+ async function handleAddCoupon() {
22989
+ onAddCoupon(couponCode);
22990
+ }
22991
+ 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" })] }) }));
22992
+ }
22993
+
22994
+ const { Text: Text$q } = antd.Typography;
22995
+ const CheckoutSummary_PriceListFragment = t(`
22996
+ fragment CheckoutSummary_PriceListFragment on PriceList {
22997
+ product {
22998
+ name
22999
+ }
23000
+ name
23001
+ }
23002
+ `);
23003
+ const CheckoutSummary_QuoteFragment = t(`
23004
+ fragment CheckoutSummary_QuoteFragment on Quote {
23005
+ id
23006
+ amountDue
23007
+ subtotal
23008
+ taxAmount
23009
+ currencyId
23010
+ quoteChanges {
23011
+ charges {
23012
+ id
23013
+ kind
23014
+ name
23015
+ coupon {
23016
+ couponCode
23017
+ }
23018
+ quantity
23019
+ subtotal
23020
+ currencyId
23021
+ }
23022
+ }
23023
+ ...shouldShowCouponEditor_QuoteFragment
23024
+ }
23025
+ `, [shouldShowCouponEditor_QuoteFragment]);
23026
+ function CheckoutSummary({ quote: maskedQuote, className, onAddCoupon, onRemoveCoupon, isRemovingCoupon, priceList: maskedPriceList, isAddingCoupon, couponCode, setCouponCode, activeCouponsExist, }) {
23027
+ var _a, _b;
23028
+ const priceList = readFragment(CheckoutSummary_PriceListFragment, maskedPriceList);
23029
+ const quote = readFragment(CheckoutSummary_QuoteFragment, maskedQuote);
23030
+ return (jsxRuntime.jsxs("div", { className: `${className} bunny-space-y-4`, children: [jsxRuntime.jsxs(Text$q, { 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 => {
23031
+ var _a;
23032
+ const multiplier = charge.kind === 'COUPON' ? -1 : 1;
23033
+ 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: () => {
23034
+ var _a, _b;
23035
+ if (isRemovingCoupon) {
23036
+ return;
23037
+ }
23038
+ if (!((_a = charge.coupon) === null || _a === void 0 ? void 0 : _a.couponCode)) {
23039
+ throw new Error('Coupon code not found');
23040
+ }
23041
+ onRemoveCoupon((_b = charge.coupon) === null || _b === void 0 ? void 0 : _b.couponCode);
23042
+ }, 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));
23043
+ })) }), 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 }))] }));
23044
+ }
23045
+ const CheckoutSummaryDivider = () => {
23046
+ return (jsxRuntime.jsx("div", { className: "bunny-my-2", children: jsxRuntime.jsx(antd.Divider, { className: "m-0" }) }));
23047
+ };
23048
+
22941
23049
  const { Title: Title$1 } = antd.Typography;
22942
23050
  const PaymentForms_QuoteFragment = t(`
22943
23051
  fragment PaymentForms_QuoteFragment on Quote {
@@ -22983,404 +23091,77 @@ function InitialSignupForm({ className, onSubmit, submitting, defaultValues, })
22983
23091
  } }) }) }) }), jsxRuntime.jsx(antd.Form.Item, { children: jsxRuntime.jsx(antd.Button, { type: "primary", onClick: handleSubmit, loading: submitting, className: "bunny-w-full", children: "Proceed to payment" }) })] }) }));
22984
23092
  }
22985
23093
 
22986
- const QuoteContext = react.createContext({});
22987
-
22988
- const [SubscriptionPropsProvider, useSubscriptionProps] = createValueContext();
22989
-
22990
- var ChargeType;
22991
- (function (ChargeType) {
22992
- ChargeType["USAGE"] = "USAGE";
22993
- ChargeType["ONE_TIME"] = "ONE_TIME";
22994
- ChargeType["RECURRING"] = "RECURRING";
22995
- })(ChargeType || (ChargeType = {}));
22996
- var ChargeType$1 = ChargeType;
22997
-
22998
- const canSubscriptionUpgradeFromTrial_SubscriptionFragment = t(`
22999
- fragment canSubscriptionUpgradeFromTrial_SubscriptionFragment on Subscription {
23000
- state
23001
- plan {
23002
- selfServiceBuy
23094
+ const Signup_QuoteFragment = t(`
23095
+ fragment Signup_QuoteFragment on Quote {
23096
+ ...CheckoutSummary_QuoteFragment
23097
+ ...PaymentForms_QuoteFragment
23098
+ id
23099
+ currencyId
23100
+ amountDue
23101
+ quoteChanges {
23102
+ id
23003
23103
  }
23004
23104
  }
23005
- `);
23006
- const canSubscriptionUpgradeFromTrial = (maskedSubscription) => {
23007
- var _a, _b;
23008
- const subscription = readFragment(canSubscriptionUpgradeFromTrial_SubscriptionFragment, maskedSubscription);
23009
- return ((((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL') &&
23010
- ((_b = subscription.plan) === null || _b === void 0 ? void 0 : _b.selfServiceBuy)) ||
23011
- false);
23012
- };
23105
+ `, [CheckoutSummary_QuoteFragment, PaymentForms_QuoteFragment]);
23013
23106
 
23014
- const canSubscriptionUpgradeFromTrialExpired_SubscriptionFragment = t(`
23015
- fragment canSubscriptionUpgradeFromTrialExpired_SubscriptionFragment on Subscription {
23016
- state
23017
- plan {
23018
- selfServiceBuy
23107
+ const query$6 = t(`
23108
+ query quote($id: ID) {
23109
+ quote(id: $id) {
23110
+ ...Signup_QuoteFragment
23019
23111
  }
23020
23112
  }
23021
- `);
23022
- const canSubscriptionUpgradeFromTrialExpired = (maskedSubscription) => {
23023
- var _a, _b;
23024
- const subscription = readFragment(canSubscriptionUpgradeFromTrialExpired_SubscriptionFragment, maskedSubscription);
23025
- return ((((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED') &&
23026
- ((_b = subscription.plan) === null || _b === void 0 ? void 0 : _b.selfServiceBuy)) ||
23027
- false);
23113
+ `, [Signup_QuoteFragment]);
23114
+ const getQuote$1 = async ({ id, token, apiHost, }) => {
23115
+ const response = await execute(query$6, { apiHost, token }, { id });
23116
+ return response === null || response === void 0 ? void 0 : response.quote;
23028
23117
  };
23029
23118
 
23030
- const graphql = initGraphQLTada();
23031
-
23032
- const periodMonthsConverter = (period) => {
23033
- if (period === 0)
23034
- return graphql.scalar('BillingPeriod', 'ONCE');
23035
- else if (period === 1)
23036
- return graphql.scalar('BillingPeriod', 'MONTHLY');
23037
- else if (period === 3)
23038
- return graphql.scalar('BillingPeriod', 'QUARTERLY');
23039
- else if (period === 6)
23040
- return graphql.scalar('BillingPeriod', 'SEMI_ANNUAL');
23041
- else if (period === 12)
23042
- return graphql.scalar('BillingPeriod', 'ANNUAL');
23043
- else
23044
- return null;
23045
- };
23046
- const billingPeriodConverter = (period) => {
23047
- if (period === graphql.scalar('BillingPeriod', 'ONCE'))
23048
- return 0;
23049
- else if (period === graphql.scalar('BillingPeriod', 'MONTHLY'))
23050
- return 1;
23051
- else if (period === graphql.scalar('BillingPeriod', 'QUARTERLY'))
23052
- return 3;
23053
- else if (period === graphql.scalar('BillingPeriod', 'SEMI_ANNUAL'))
23054
- return 6;
23055
- else
23056
- return 12;
23119
+ const useHasTaxPlugin = ({ apiHost, token }) => {
23120
+ const { data: plugins } = usePlugins({
23121
+ apiHost,
23122
+ token,
23123
+ });
23124
+ return Boolean(plugins === null || plugins === void 0 ? void 0 : plugins.some((plugin) => plugin.type === 'taxation'));
23057
23125
  };
23058
23126
 
23059
- function getAddonsForBillingPeriod(billingPeriod, addonPlans) {
23060
- const flattenedPriceLists = addonPlans.flatMap(addonPlan => addonPlan.priceLists);
23061
- return flattenedPriceLists.filter(priceList => priceList.periodMonths === billingPeriodConverter(billingPeriod));
23062
- }
23063
-
23064
- const hasUnpurchasedAddonPriceLists_PlanFragment = t(`
23065
- fragment hasUnpurchasedAddonPriceLists_PlanFragment on Plan {
23066
- priceLists {
23127
+ const MUTATION$3 = `mutation quoteChangeAddCoupon($couponCode: String!, $quoteChangeId: ID!) {
23128
+ quoteChangeAddCoupon(couponCode: $couponCode, quoteChangeId: $quoteChangeId) {
23129
+ quoteChange {
23067
23130
  id
23068
- isVisible
23069
- periodMonths
23131
+ charges {
23132
+ id
23133
+ amount
23134
+ couponId
23135
+ }
23070
23136
  }
23071
23137
  }
23072
- `);
23073
- function hasUnpurchasedAddonPriceLists(maskedPriceListAddonPlans, currentSubscription, billingPeriod) {
23074
- // Read fragments
23075
- const priceListAddonPlans = maskedPriceListAddonPlans.map(maskedAddonPlan => readFragment(hasUnpurchasedAddonPriceLists_PlanFragment, maskedAddonPlan));
23076
- const addonPriceLists = getAddonsForBillingPeriod(billingPeriod, priceListAddonPlans).filter(priceList => priceList.isVisible);
23077
- const unpurchasedAddonPriceLists = addonPriceLists === null || addonPriceLists === void 0 ? void 0 : addonPriceLists.filter(addonPriceList => {
23078
- var _a;
23079
- return !((_a = currentSubscription === null || currentSubscription === void 0 ? void 0 : currentSubscription.addonSubscriptions) === null || _a === void 0 ? void 0 : _a.some(addonSubscription => addonSubscription.priceList.id === addonPriceList.id));
23138
+ }`;
23139
+ const quoteChangeAddCoupon = async ({ quoteChangeId, couponCode, token, apiHost, }) => {
23140
+ var _a;
23141
+ const vars = { couponCode, quoteChangeId };
23142
+ const response = await gqlRequest({
23143
+ query: MUTATION$3,
23144
+ token,
23145
+ vars,
23146
+ apiHost,
23080
23147
  });
23081
- return unpurchasedAddonPriceLists.length > 0;
23082
- }
23083
-
23084
- var QuoteChangeKind;
23085
- (function (QuoteChangeKind) {
23086
- QuoteChangeKind["ADJUSTMENT"] = "ADJUSTMENT";
23087
- QuoteChangeKind["COUPON"] = "COUPON";
23088
- QuoteChangeKind["CREDIT"] = "CREDIT";
23089
- QuoteChangeKind["DISCOUNT"] = "DISCOUNT";
23090
- QuoteChangeKind["FREE_PERIOD_DISCOUNT"] = "FREE_PERIOD_DISCOUNT";
23091
- QuoteChangeKind["PRICE_UPDATE"] = "PRICE_UPDATE";
23092
- QuoteChangeKind["QUANTITY_UPDATE"] = "QUANTITY_UPDATE";
23093
- QuoteChangeKind["REINSTATE"] = "REINSTATE";
23094
- QuoteChangeKind["RENEW"] = "RENEW";
23095
- QuoteChangeKind["SUBSCRIBE"] = "SUBSCRIBE";
23096
- QuoteChangeKind["UNSUBSCRIBE"] = "UNSUBSCRIBE";
23097
- QuoteChangeKind["UPDATE"] = "UPDATE";
23098
- QuoteChangeKind["ACTIVATE"] = "ACTIVATE";
23099
- })(QuoteChangeKind || (QuoteChangeKind = {}));
23100
- var QuoteChangeKind$1 = QuoteChangeKind;
23148
+ const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteAddCoupon) === null || _a === void 0 ? void 0 : _a.errors;
23149
+ if (errors)
23150
+ throw errors;
23151
+ return response.quote;
23152
+ };
23101
23153
 
23102
- function hasUnpurchasedFeatureAddons(priceList, currentSubscription) {
23103
- const featureAddons = priceList.charges.filter(charge => charge.featureAddon);
23104
- const purchasedFeatureAddons = currentSubscription === null || currentSubscription === void 0 ? void 0 : currentSubscription.charges.filter(charge => { var _a; return (_a = charge.priceListCharge) === null || _a === void 0 ? void 0 : _a.featureAddon; });
23105
- const unpurchasedFeatureAddons = featureAddons.filter(charge => !(purchasedFeatureAddons === null || purchasedFeatureAddons === void 0 ? void 0 : purchasedFeatureAddons.some(purchasedCharge => { var _a; return ((_a = purchasedCharge.priceListCharge) === null || _a === void 0 ? void 0 : _a.id) === charge.id; })));
23106
- return unpurchasedFeatureAddons.length > 0;
23107
- }
23108
- function findQuoteChangeForFeatureAddon(quote) {
23109
- return quote === null || quote === void 0 ? void 0 : quote.quoteChanges.find(qc => qc.kind === QuoteChangeKind$1.UPDATE ||
23110
- qc.kind === QuoteChangeKind$1.SUBSCRIBE ||
23111
- qc.kind === QuoteChangeKind$1.ACTIVATE);
23112
- }
23113
- function featureAddonInQuote(selectedPriceList, priceListCharge, quote) {
23114
- var _a, _b, _c;
23115
- const quoteChange = (_a = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _a === void 0 ? void 0 : _a.find(qc => { var _a; return ((_a = qc === null || qc === void 0 ? void 0 : qc.priceList) === null || _a === void 0 ? void 0 : _a.id) === selectedPriceList.id; });
23116
- if (!quoteChange)
23117
- return false;
23118
- return (_c = (_b = quoteChange.charges) === null || _b === void 0 ? void 0 : _b.some(c => { var _a; return ((_a = c.priceListCharge) === null || _a === void 0 ? void 0 : _a.id) === priceListCharge.id; })) !== null && _c !== void 0 ? _c : false;
23119
- }
23120
- // ID Cucumber will use to find the feature addon switch
23121
- function featureAddonSwitchTestId(addonName) {
23122
- const name = addonName.toLowerCase().replace(/ /g, '-');
23123
- return `feature-addon-switch-${name}`;
23124
- }
23125
-
23126
- const removeHTMLTagsRegex = /<br>(?=(?:\s*<[^>]*>)*$)|(<br>)|<[^>]*>/gi;
23127
- // Description is a string that can contain HTML tags. We want to remove all HTML tags except <br> tags.
23128
- const createPlanDescription = (planDescription) => {
23129
- return (planDescription || '').replace(removeHTMLTagsRegex, (_, y) => (y ? ' & ' : ''));
23130
- };
23131
- const getActivePlanPriceData = (priceList, selectedPriceList) => {
23132
- if (!priceList) {
23133
- return;
23134
- }
23135
- // If a period option is selected, return the charge that matches the selected period option
23136
- let activeBillingPLCharge;
23137
- // Default to first price list charge
23138
- let lowestPLCharge;
23139
- // Find the lowest price list charge with a billing period that matches the selected period option
23140
- if (priceList.id === (selectedPriceList === null || selectedPriceList === void 0 ? void 0 : selectedPriceList.id)) {
23141
- activeBillingPLCharge = priceList.charges[0];
23142
- }
23143
- for (let j = 0; j < priceList.charges.length; j++) {
23144
- const charge = priceList.charges[j];
23145
- if (charge.chargeType === ChargeType$1.USAGE || charge.featureAddon === true)
23146
- continue;
23147
- if (activeBillingPLCharge) {
23148
- // If we already found a charge with the same billing period check if this charge is lower
23149
- if (charge.basePrice < activeBillingPLCharge.basePrice &&
23150
- charge.billingPeriod === (activeBillingPLCharge === null || activeBillingPLCharge === void 0 ? void 0 : activeBillingPLCharge.billingPeriod)) {
23151
- activeBillingPLCharge = charge;
23152
- }
23153
- }
23154
- // If a period option is selected, only return the charge if it matches the selected period option
23155
- else if (selectedPriceList &&
23156
- charge.billingPeriod === periodMonthsConverter(selectedPriceList.periodMonths)) {
23157
- activeBillingPLCharge = charge;
23158
- }
23159
- // Otherwise, return the lowest price list charge
23160
- else if (charge.basePrice < ((lowestPLCharge === null || lowestPLCharge === void 0 ? void 0 : lowestPLCharge.basePrice) || -1)) {
23161
- lowestPLCharge = charge;
23162
- }
23163
- }
23164
- return {
23165
- activeCharge: activeBillingPLCharge || lowestPLCharge,
23166
- };
23167
- };
23168
- const showErrorNotification$3 = useErrorNotification();
23169
- const isPriceListDisabled = ({ priceList, upgradingSubscription, }) => {
23170
- const priceListAddonPlans = priceList === null || priceList === void 0 ? void 0 : priceList.plan.addonPlans;
23171
- if (!priceListAddonPlans) {
23172
- showErrorNotification$3('Price list addon plans are undefined');
23173
- return false;
23174
- }
23175
- const canPurchaseFeatureAddons = hasUnpurchasedFeatureAddons(priceList, upgradingSubscription);
23176
- const canPurchasePlanAddons = hasUnpurchasedAddonPriceLists(priceListAddonPlans, upgradingSubscription, periodMonthsConverter(priceList.periodMonths));
23177
- const existingSubscriptionInTrial = upgradingSubscription && canSubscriptionUpgradeFromTrial(upgradingSubscription); // TODO: set type properly later
23178
- const existingSubscriptionInTrialExpired = upgradingSubscription && canSubscriptionUpgradeFromTrialExpired(upgradingSubscription); // TODO: set type properly later
23179
- const isUpgradingSubscriptionPriceList = (upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.id) === priceList.id;
23180
- // When should priceList be disabled?
23181
- // if upgradingSubscription?.priceList.id === priceList.id
23182
- // AND the upgradingSubscription is not in trial
23183
- // AND cannot purchase feature addons
23184
- // AND cannot purchase add-on plans
23185
- // AND selfServiceBuy is false
23186
- // if upgradingSubscription?.priceList.id != priceList.id
23187
- // AND upgradingSubscription is expired trial
23188
- // AND priceList is not deprecated
23189
- if (isUpgradingSubscriptionPriceList) {
23190
- return (!existingSubscriptionInTrial &&
23191
- !existingSubscriptionInTrialExpired &&
23192
- !canPurchaseFeatureAddons &&
23193
- !canPurchasePlanAddons);
23194
- }
23195
- else if (priceList === null || priceList === void 0 ? void 0 : priceList.deprecated) {
23196
- return true;
23197
- }
23198
- else {
23199
- return false;
23200
- }
23201
- };
23202
-
23203
- const CheckoutButton = ({ disabled, onClickCheckout, loading, tooltipText, }) => {
23204
- const isMobile = useIsMobile();
23205
- const TooltipWrapper = ({ children }) => {
23206
- if (tooltipText) {
23207
- return jsxRuntime.jsx(antd.Tooltip, { title: tooltipText, children: children });
23208
- }
23209
- return jsxRuntime.jsx("div", { children: children });
23210
- };
23211
- return (jsxRuntime.jsx(TooltipWrapper, { children: jsxRuntime.jsx(antd.Button, { className: isMobile ? 'w-full' : '', disabled: disabled, onClick: onClickCheckout, size: isMobile ? 'large' : 'middle', type: "primary", loading: loading, children: "Proceed to checkout" }) }));
23212
- };
23213
-
23214
- const CheckoutPrice_QuoteFragment = t(`
23215
- fragment CheckoutPrice_QuoteFragment on Quote {
23216
- periodAmount
23217
- amountDue
23218
- }
23219
- `);
23220
- const CheckoutPrice = ({ isUsage, quote: maskedQuote, selectedPriceList, }) => {
23221
- var _a;
23222
- // Read fragments
23223
- const quote = readFragment(CheckoutPrice_QuoteFragment, maskedQuote);
23224
- // Hooks
23225
- const isMobile = useIsMobile();
23226
- // amountDue might not be available, so we use periodAmount as a fallback
23227
- const displayAmount = (_a = quote === null || quote === void 0 ? void 0 : quote.amountDue) !== null && _a !== void 0 ? _a : quote === null || quote === void 0 ? void 0 : quote.periodAmount;
23228
- if (!isUsage && (!selectedPriceList || displayAmount === undefined))
23229
- return null;
23230
- const convertedPeriodMonths = periodMonthsConverter(selectedPriceList.periodMonths);
23231
- const periodLabel = convertedPeriodMonths ? PERIOD_LABELS[convertedPeriodMonths] : 'undefined';
23232
- return (jsxRuntime.jsx("div", { className: `bunny-font-medium ${isMobile ? 'bunny-text-2xl' : ''}`, children: isUsage
23233
- ? 'Usage based pricing'
23234
- : selectedPriceList && displayAmount !== undefined
23235
- ? `${formatCurrency(displayAmount, selectedPriceList === null || selectedPriceList === void 0 ? void 0 : selectedPriceList.currencyId, undefined)} / ${periodLabel}`
23236
- : '' }));
23237
- };
23238
-
23239
- const { Text: Text$q } = antd.Typography;
23240
- const CheckoutBarSummarySection_QuoteFragment = t(`
23241
- fragment CheckoutBarSummarySection_QuoteFragment on Quote {
23242
- quoteChanges {
23243
- charges {
23244
- id
23245
- }
23246
- }
23247
- ...CheckoutPrice_QuoteFragment
23248
- }
23249
- `, [CheckoutPrice_QuoteFragment]);
23250
- const CheckoutBarSummarySection = ({ selectedPriceList, onClickCheckout, }) => {
23251
- var _a, _b;
23252
- // Context
23253
- const { quote: maskedQuote, isQuotePending, isUpdatingQuote } = react.useContext(QuoteContext);
23254
- const quote = readFragment(CheckoutBarSummarySection_QuoteFragment, maskedQuote);
23255
- const { isInPreviewMode } = useSubscriptionProps();
23256
- // Hooks
23257
- const { paymentPlugins } = usePaymentPlugins(undefined);
23258
- const isMobile = useIsMobile();
23259
- const hasPaymentPlugins = Boolean(paymentPlugins === null || paymentPlugins === void 0 ? void 0 : paymentPlugins.length);
23260
- const quoteHasCharges = Boolean((_a = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _a === void 0 ? void 0 : _a.some(qc => qc.charges.length > 0));
23261
- const checkoutButtonDisabled = Boolean(!selectedPriceList || !quoteHasCharges || !hasPaymentPlugins || isInPreviewMode);
23262
- const activeCharge = (_b = getActivePlanPriceData(selectedPriceList, selectedPriceList)) === null || _b === void 0 ? void 0 : _b.activeCharge;
23263
- const isUsage = (activeCharge === null || activeCharge === void 0 ? void 0 : activeCharge.chargeType) === ChargeType$1.USAGE;
23264
- return (jsxRuntime.jsxs(Text$q, { className: `bunny-flex bunny-items-center bunny-gap-4 ${isMobile ? 'bunny-flex-col' : ''}`, children: [quote && (jsxRuntime.jsxs("div", { className: `bunny-flex ${isMobile ? 'items-center justify-between w-full' : 'flex-col'}`, children: [jsxRuntime.jsx("div", { className: "bunny-text-slate-500 bunny-font-medium bunny-text-right", style: { fontSize: '11px' }, children: "TOTAL" }), jsxRuntime.jsx(CheckoutPrice, { isUsage: isUsage, quote: quote, selectedPriceList: selectedPriceList })] })), jsxRuntime.jsx(CheckoutButton, { disabled: checkoutButtonDisabled, onClickCheckout: onClickCheckout, loading: isQuotePending || isUpdatingQuote, tooltipText: isInPreviewMode
23265
- ? 'Checkout is disabled in preview mode'
23266
- : !hasPaymentPlugins
23267
- ? 'Cannot checkout. No valid payment plugins found. Please contact your administrator.'
23268
- : undefined })] }));
23269
- };
23270
-
23271
- const accountQuery = (id) => `
23272
- query account {
23273
- account(id: ${id}) {
23274
- billingCountry
23275
- billingState
23276
- billingStreet
23277
- billingCity
23278
- billingZip
23279
- }
23280
- }`;
23281
- const getAccount$1 = async ({ id, apiHost, token, }) => {
23282
- const response = await gqlRequest({
23283
- query: accountQuery(id),
23284
- token,
23285
- apiHost,
23286
- });
23287
- return response === null || response === void 0 ? void 0 : response.account;
23288
- };
23289
-
23290
- const MUTATION$5 = `{
23291
- currentUser {
23292
- taxationRequiredAccountFields
23293
- }
23294
- }`;
23295
- const getTaxationRequiredAccountFields = async ({ apiHost, token, }) => {
23296
- var _a, _b;
23297
- const response = await gqlRequest({
23298
- query: MUTATION$5,
23299
- token,
23300
- apiHost: apiHost,
23301
- });
23302
- return ((_b = (_a = response === null || response === void 0 ? void 0 : response.currentUser) === null || _a === void 0 ? void 0 : _a.taxationRequiredAccountFields) === null || _b === void 0 ? void 0 : _b.length) > 0
23303
- ? response.currentUser.taxationRequiredAccountFields
23304
- : null;
23305
- };
23306
-
23307
- const useHasTaxPlugin = ({ apiHost, token }) => {
23308
- const { data: plugins } = usePlugins({
23309
- apiHost,
23310
- token,
23311
- });
23312
- return Boolean(plugins === null || plugins === void 0 ? void 0 : plugins.some((plugin) => plugin.type === 'taxation'));
23313
- };
23314
-
23315
- const BunnyFooterIcon = ({ color }) => {
23316
- return (jsxRuntime.jsxs("svg", { width: "45", height: "15", viewBox: "0 0 39 13", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsxRuntime.jsxs("g", { clipPath: "url(#clip0_6_851)", children: [jsxRuntime.jsx("path", { className: "bunny-icon-path", d: "M14.5898 7.19708C14.5898 9.35053 13.0926 10.325 11.2495 10.325C9.39955 10.325 7.90234 9.35001 7.90234 7.18967V3.26221H10.1125V7.00052C10.1125 7.87719 10.5855 8.27725 11.2495 8.27725C11.9061 8.27725 12.3865 7.87719 12.3865 7.00052V3.26221H14.5898V7.19708Z", fill: color }), jsxRuntime.jsx("path", { className: "bunny-icon-path", d: "M31.8943 12.9625H29.4793L31.8523 8.62816L28.9355 3.26221H31.4708L33.0457 6.35524L34.5924 3.26221H37.0075L31.8943 12.9625Z", fill: color }), jsxRuntime.jsx("path", { className: "bunny-icon-path", d: "M15.1602 5.96827C15.1602 3.8148 16.6574 2.84033 18.5005 2.84033C20.3504 2.84033 21.8476 3.81533 21.8476 5.97568V10.1473H19.6374V6.16483C19.6374 5.28815 19.1645 4.8881 18.5005 4.8881C17.8439 4.8881 17.3634 5.28815 17.3634 6.16483V10.1473H15.1602V5.96827Z", fill: color }), jsxRuntime.jsx("path", { className: "bunny-icon-path", d: "M22.4316 5.96827C22.4316 3.8148 23.9289 2.84033 25.7719 2.84033C27.6219 2.84033 29.1191 3.81533 29.1191 5.97568V10.1473H26.9089V6.16483C26.9089 5.28815 26.4359 4.8881 25.7719 4.8881C25.1154 4.8881 24.6349 5.28815 24.6349 6.16483V10.1473H22.4316V5.96827Z", fill: color }), jsxRuntime.jsx("path", { className: "bunny-icon-path", d: "M7.40511 6.68957C7.40511 8.7236 6.02815 10.3227 4.17816 10.3227C3.23907 10.3227 2.61071 9.94378 2.19358 9.40371V10.1404H0.0605469V0.0405273H2.26381V3.91939C2.68041 3.42158 3.28802 3.07069 4.17763 3.07069C6.02759 3.07069 7.40511 4.66981 7.40511 6.68957ZM2.17229 6.69642C2.17229 7.60802 2.77937 8.2744 3.64823 8.2744C4.53783 8.2744 5.13107 7.59372 5.13107 6.69642C5.13107 5.79912 4.53783 5.11844 3.64823 5.11844C2.77937 5.11844 2.17229 5.78482 2.17229 6.69642Z", fill: color }), jsxRuntime.jsx("path", { className: "bunny-icon-path", d: "M38.966 8.94801C38.966 9.76181 38.2668 10.4631 37.4618 10.4631C36.6499 10.4631 35.9434 9.76181 35.9434 8.94801C35.9434 8.14846 36.6494 7.46094 37.4618 7.46094C38.2668 7.46094 38.966 8.14846 38.966 8.94801Z", fill: color })] }), jsxRuntime.jsx("defs", { children: jsxRuntime.jsx("clipPath", { id: "clip0_6_851", children: jsxRuntime.jsx("rect", { width: "39", height: "13", fill: "white" }) }) })] }));
23317
- };
23318
-
23319
- const { Text: Text$p } = antd.Typography;
23320
- const Footer = ({ className }) => {
23321
- const token = useToken();
23322
- const { currentUser } = useCurrentUserData(token);
23323
- const { privacyUrl, termsUrl } = currentUser;
23324
- const isMobile = useIsMobile();
23325
- return (jsxRuntime.jsxs("div", { className: `bunny-flex bunny-items-center bunny-justify-between bunny-shrink-0 ${isMobile ? 'bunny-flex-col bunny-gap-2' : ''} ${className}`, children: [(termsUrl || privacyUrl) && (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-3", children: [termsUrl && (jsxRuntime.jsx(StyedLink, { className: "bunny-text-xs bunny-text-slate-400", href: termsUrl, rel: "noopener noreferrer", target: "_blank", type: "text", children: "Terms" })), privacyUrl && (jsxRuntime.jsx(StyedLink, { className: "bunny-text-xs bunny-text-slate-400", href: privacyUrl, rel: "noopener noreferrer", target: "_blank", type: "text", children: "Privacy" }))] })), jsxRuntime.jsx(BunnyMarketingLink, {})] }));
23326
- };
23327
- const BunnyMarketingLink = () => {
23328
- const [isHovered, setIsHovered] = react.useState(false);
23329
- const isMobile = useIsMobile();
23330
- return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-items-end bunny-justify-end ${isMobile ? '' : 'grow'}`, children: jsxRuntime.jsx(StyledBunnyLink, { className: "bunny-flex bunny-items-end bunny-justify-end bunny-text-slate-400", href: "https://bunny.com/", rel: "noopener noreferrer", target: "_blank", children: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center", onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: [jsxRuntime.jsx(Text$p, { className: "bunny-text-slate-400", children: "Powered by\u00A0" }), jsxRuntime.jsx("div", { style: { paddingTop: '5px' }, children: jsxRuntime.jsx(BunnyFooterIcon, { color: isHovered ? PRIMARY_COLOR : SLATE_400 }) })] }) }) }));
23331
- };
23332
- const StyedLink = styled.a `
23333
- color: ${SLATE_400};
23334
- transition: color 0.3s;
23335
- &:hover {
23336
- color: ${SLATE_500};
23337
- }
23338
- text-decoration: none;
23339
- `;
23340
- const StyledBunnyLink = styled(StyedLink) `
23341
- &:hover {
23342
- color: ${PRIMARY_COLOR} !important;
23343
- }
23344
- `;
23345
-
23346
- const MUTATION$4 = `mutation quoteChangeAddCoupon($couponCode: String!, $quoteChangeId: ID!) {
23347
- quoteChangeAddCoupon(couponCode: $couponCode, quoteChangeId: $quoteChangeId) {
23348
- quoteChange {
23349
- id
23350
- charges {
23351
- id
23352
- amount
23353
- couponId
23354
- }
23355
- }
23356
- }
23357
- }`;
23358
- const quoteChangeAddCoupon = async ({ quoteChangeId, couponCode, token, apiHost, }) => {
23359
- var _a;
23360
- const vars = { couponCode, quoteChangeId };
23361
- const response = await gqlRequest({
23362
- query: MUTATION$4,
23363
- token,
23364
- vars,
23365
- apiHost,
23366
- });
23367
- const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteAddCoupon) === null || _a === void 0 ? void 0 : _a.errors;
23368
- if (errors)
23369
- throw errors;
23370
- return response.quote;
23371
- };
23372
-
23373
- const MUTATION$3 = `mutation quoteChangeRemoveCoupon($quoteChangeId: ID!, $couponCode: String!) {
23374
- quoteChangeRemoveCoupon(quoteChangeId: $quoteChangeId, couponCode: $couponCode) {
23375
- errors
23376
- }
23154
+ const MUTATION$2 = `mutation quoteChangeRemoveCoupon($quoteChangeId: ID!, $couponCode: String!) {
23155
+ quoteChangeRemoveCoupon(quoteChangeId: $quoteChangeId, couponCode: $couponCode) {
23156
+ errors
23157
+ }
23377
23158
  }
23378
23159
  `;
23379
23160
  const quoteChangeRemoveCoupon = async ({ quoteChangeId, couponCode, token, apiHost, }) => {
23380
23161
  var _a;
23381
23162
  const vars = { couponCode, quoteChangeId };
23382
23163
  const response = await gqlRequest({
23383
- query: MUTATION$3,
23164
+ query: MUTATION$2,
23384
23165
  token,
23385
23166
  vars,
23386
23167
  apiHost,
@@ -23408,7 +23189,7 @@ const getCoupons = async ({ token, apiHost, filter, }) => {
23408
23189
  return response === null || response === void 0 ? void 0 : response.coupons;
23409
23190
  };
23410
23191
 
23411
- const showErrorNotification$2 = useErrorNotification();
23192
+ const showErrorNotification$3 = useErrorNotification();
23412
23193
  const useUpdateCoupons = ({ apiHost, token, quoteChangeId, onCouponAdded, onCouponRemoved, }) => {
23413
23194
  const { data: coupons } = reactQuery.useQuery({
23414
23195
  queryKey: ['coupons', token],
@@ -23434,7 +23215,7 @@ const useUpdateCoupons = ({ apiHost, token, quoteChangeId, onCouponAdded, onCoup
23434
23215
  },
23435
23216
  onError: (error) => {
23436
23217
  var _a, _b;
23437
- showErrorNotification$2((_b = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.errors[0]) === null || _b === void 0 ? void 0 : _b.message, 'Error adding coupon');
23218
+ showErrorNotification$3((_b = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.errors[0]) === null || _b === void 0 ? void 0 : _b.message, 'Error adding coupon');
23438
23219
  },
23439
23220
  });
23440
23221
  const { mutate: removeCoupon, isPending: isRemovingCoupon } = reactQuery.useMutation({
@@ -23454,7 +23235,7 @@ const useUpdateCoupons = ({ apiHost, token, quoteChangeId, onCouponAdded, onCoup
23454
23235
  },
23455
23236
  onError: (error) => {
23456
23237
  var _a, _b;
23457
- showErrorNotification$2((_b = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.errors[0]) === null || _b === void 0 ? void 0 : _b.message, 'Error removing coupon');
23238
+ showErrorNotification$3((_b = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.errors[0]) === null || _b === void 0 ? void 0 : _b.message, 'Error removing coupon');
23458
23239
  },
23459
23240
  });
23460
23241
  return {
@@ -23466,1090 +23247,384 @@ const useUpdateCoupons = ({ apiHost, token, quoteChangeId, onCouponAdded, onCoup
23466
23247
  };
23467
23248
  };
23468
23249
 
23469
- const shouldShowCouponEditor_QuoteFragment = t(`
23470
- fragment shouldShowCouponEditor_QuoteFragment on Quote {
23471
- id
23472
- kind
23473
- }
23474
- `, []);
23475
- const shouldShowCouponEditor_SubscriptionFragment = t(`
23476
- fragment shouldShowCouponEditor_SubscriptionFragment on Subscription {
23477
- id
23478
- state
23479
- charges {
23480
- discountedPrice
23250
+ const BunnyFooterIcon = ({ color }) => {
23251
+ return (jsxRuntime.jsxs("svg", { width: "45", height: "15", viewBox: "0 0 39 13", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsxRuntime.jsxs("g", { clipPath: "url(#clip0_6_851)", children: [jsxRuntime.jsx("path", { className: "bunny-icon-path", d: "M14.5898 7.19708C14.5898 9.35053 13.0926 10.325 11.2495 10.325C9.39955 10.325 7.90234 9.35001 7.90234 7.18967V3.26221H10.1125V7.00052C10.1125 7.87719 10.5855 8.27725 11.2495 8.27725C11.9061 8.27725 12.3865 7.87719 12.3865 7.00052V3.26221H14.5898V7.19708Z", fill: color }), jsxRuntime.jsx("path", { className: "bunny-icon-path", d: "M31.8943 12.9625H29.4793L31.8523 8.62816L28.9355 3.26221H31.4708L33.0457 6.35524L34.5924 3.26221H37.0075L31.8943 12.9625Z", fill: color }), jsxRuntime.jsx("path", { className: "bunny-icon-path", d: "M15.1602 5.96827C15.1602 3.8148 16.6574 2.84033 18.5005 2.84033C20.3504 2.84033 21.8476 3.81533 21.8476 5.97568V10.1473H19.6374V6.16483C19.6374 5.28815 19.1645 4.8881 18.5005 4.8881C17.8439 4.8881 17.3634 5.28815 17.3634 6.16483V10.1473H15.1602V5.96827Z", fill: color }), jsxRuntime.jsx("path", { className: "bunny-icon-path", d: "M22.4316 5.96827C22.4316 3.8148 23.9289 2.84033 25.7719 2.84033C27.6219 2.84033 29.1191 3.81533 29.1191 5.97568V10.1473H26.9089V6.16483C26.9089 5.28815 26.4359 4.8881 25.7719 4.8881C25.1154 4.8881 24.6349 5.28815 24.6349 6.16483V10.1473H22.4316V5.96827Z", fill: color }), jsxRuntime.jsx("path", { className: "bunny-icon-path", d: "M7.40511 6.68957C7.40511 8.7236 6.02815 10.3227 4.17816 10.3227C3.23907 10.3227 2.61071 9.94378 2.19358 9.40371V10.1404H0.0605469V0.0405273H2.26381V3.91939C2.68041 3.42158 3.28802 3.07069 4.17763 3.07069C6.02759 3.07069 7.40511 4.66981 7.40511 6.68957ZM2.17229 6.69642C2.17229 7.60802 2.77937 8.2744 3.64823 8.2744C4.53783 8.2744 5.13107 7.59372 5.13107 6.69642C5.13107 5.79912 4.53783 5.11844 3.64823 5.11844C2.77937 5.11844 2.17229 5.78482 2.17229 6.69642Z", fill: color }), jsxRuntime.jsx("path", { className: "bunny-icon-path", d: "M38.966 8.94801C38.966 9.76181 38.2668 10.4631 37.4618 10.4631C36.6499 10.4631 35.9434 9.76181 35.9434 8.94801C35.9434 8.14846 36.6494 7.46094 37.4618 7.46094C38.2668 7.46094 38.966 8.14846 38.966 8.94801Z", fill: color })] }), jsxRuntime.jsx("defs", { children: jsxRuntime.jsx("clipPath", { id: "clip0_6_851", children: jsxRuntime.jsx("rect", { width: "39", height: "13", fill: "white" }) }) })] }));
23252
+ };
23253
+
23254
+ const { Text: Text$p } = antd.Typography;
23255
+ const Footer = ({ className }) => {
23256
+ const token = useToken();
23257
+ const { currentUser } = useCurrentUserData(token);
23258
+ const { privacyUrl, termsUrl } = currentUser;
23259
+ const isMobile = useIsMobile();
23260
+ return (jsxRuntime.jsxs("div", { className: `bunny-flex bunny-items-center bunny-justify-between bunny-shrink-0 ${isMobile ? 'bunny-flex-col bunny-gap-2' : ''} ${className}`, children: [(termsUrl || privacyUrl) && (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-3", children: [termsUrl && (jsxRuntime.jsx(StyedLink, { className: "bunny-text-xs bunny-text-slate-400", href: termsUrl, rel: "noopener noreferrer", target: "_blank", type: "text", children: "Terms" })), privacyUrl && (jsxRuntime.jsx(StyedLink, { className: "bunny-text-xs bunny-text-slate-400", href: privacyUrl, rel: "noopener noreferrer", target: "_blank", type: "text", children: "Privacy" }))] })), jsxRuntime.jsx(BunnyMarketingLink, {})] }));
23261
+ };
23262
+ const BunnyMarketingLink = () => {
23263
+ const [isHovered, setIsHovered] = react.useState(false);
23264
+ const isMobile = useIsMobile();
23265
+ return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-items-end bunny-justify-end ${isMobile ? '' : 'grow'}`, children: jsxRuntime.jsx(StyledBunnyLink, { className: "bunny-flex bunny-items-end bunny-justify-end bunny-text-slate-400", href: "https://bunny.com/", rel: "noopener noreferrer", target: "_blank", children: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center", onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: [jsxRuntime.jsx(Text$p, { className: "bunny-text-slate-400", children: "Powered by\u00A0" }), jsxRuntime.jsx("div", { style: { paddingTop: '5px' }, children: jsxRuntime.jsx(BunnyFooterIcon, { color: isHovered ? PRIMARY_COLOR : SLATE_400 }) })] }) }) }));
23266
+ };
23267
+ const StyedLink = styled.a `
23268
+ color: ${SLATE_400};
23269
+ transition: color 0.3s;
23270
+ &:hover {
23271
+ color: ${SLATE_500};
23272
+ }
23273
+ text-decoration: none;
23274
+ `;
23275
+ const StyledBunnyLink = styled(StyedLink) `
23276
+ &:hover {
23277
+ color: ${PRIMARY_COLOR} !important;
23278
+ }
23279
+ `;
23280
+
23281
+ const SelfServiceBuyWarning_PriceListFragment = t(`
23282
+ fragment SelfServiceBuyWarning_PriceListFragment on PriceList {
23283
+ plan {
23284
+ selfServiceBuy
23481
23285
  }
23482
23286
  }
23483
- `, []);
23484
- function shouldShowCouponEditor(maskedQuote, activeCouponsExist, maskedUpgradingSubscription) {
23485
- var _a, _b;
23486
- const quote = readFragment(shouldShowCouponEditor_QuoteFragment, maskedQuote);
23487
- const upgradingSubscription = readFragment(shouldShowCouponEditor_SubscriptionFragment, maskedUpgradingSubscription);
23488
- const upgradingFromTrial = ((_a = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL') ||
23489
- ((_b = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) ===
23490
- t.scalar('SubscriptionState', 'TRIAL_EXPIRED');
23491
- function upgradingFromFree() {
23287
+ `);
23288
+ function SelfServiceBuyWarning({ priceList: maskedPriceList, onShowSelfServiceBuyWarning, }) {
23289
+ const priceList = readFragment(SelfServiceBuyWarning_PriceListFragment, maskedPriceList);
23290
+ const hasShownRef = react.useRef(false);
23291
+ // Only show the warning when component is first mounted
23292
+ react.useEffect(() => {
23492
23293
  var _a;
23493
- const totalPrice = (_a = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.charges) === null || _a === void 0 ? void 0 : _a.reduce((acc, charge) => acc + Number((charge === null || charge === void 0 ? void 0 : charge.discountedPrice) || 0), 0);
23494
- return totalPrice === 0;
23495
- }
23496
- const quoteKindIsValid = (quote === null || quote === void 0 ? void 0 : quote.kind) === t.scalar('QuoteChangeKind', 'SUBSCRIBE') ||
23497
- (quote === null || quote === void 0 ? void 0 : quote.kind) === t.scalar('QuoteChangeKind', 'ADJUSTMENT') ||
23498
- (quote === null || quote === void 0 ? void 0 : quote.kind) === t.scalar('QuoteChangeKind', 'ACTIVATE');
23499
- if (quoteKindIsValid) {
23500
- return activeCouponsExist && (upgradingFromTrial || upgradingFromFree());
23501
- }
23502
- return false;
23294
+ if (!priceList || hasShownRef.current)
23295
+ return;
23296
+ if (((_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.selfServiceBuy) === false) {
23297
+ hasShownRef.current = true;
23298
+ onShowSelfServiceBuyWarning();
23299
+ }
23300
+ }, [priceList, onShowSelfServiceBuyWarning]);
23301
+ return null;
23503
23302
  }
23504
23303
 
23505
- function CouponEditor({ className, onAddCoupon, isAddingCoupon, couponCode, setCouponCode, }) {
23506
- async function handleAddCoupon() {
23507
- onAddCoupon(couponCode);
23304
+ const TAG_COLORS = {
23305
+ ACTIVE: 'green',
23306
+ TRIAL: 'blue',
23307
+ CANCELED: 'red',
23308
+ EXPIRED: 'gray',
23309
+ TRIAL_EXPIRED: 'red',
23310
+ PENDING: 'yellow',
23311
+ };
23312
+
23313
+ const { Text: Text$o } = antd.Typography;
23314
+ const PriceListDisplay_PriceListFragment = t(`
23315
+ fragment PriceListDisplay_PriceListFragment on PriceList {
23316
+ product {
23317
+ name
23318
+ }
23319
+ name
23320
+ basePrice
23321
+ currencyId
23322
+ trialAllowed
23323
+ trialLengthDays
23508
23324
  }
23509
- 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" })] }) }));
23325
+ `);
23326
+ function PriceListDisplay({ priceList: maskedPriceList }) {
23327
+ var _a, _b;
23328
+ const priceList = readFragment(PriceListDisplay_PriceListFragment, maskedPriceList);
23329
+ if (!priceList)
23330
+ return null;
23331
+ return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-4", children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-0", children: [jsxRuntime.jsxs(Text$o, { className: "bunny-text-slate-500 bunny-font-bold bunny-text-lg", children: [(_a = priceList.product) === null || _a === void 0 ? void 0 : _a.name, " ", priceList.name] }), jsxRuntime.jsxs(Text$o, { className: "bunny-font-bold bunny-text-xl", children: [formatCurrency(priceList.basePrice, priceList.currencyId), " / month"] })] }), priceList.trialAllowed ? (jsxRuntime.jsx("div", { className: "bunny-flex", children: jsxRuntime.jsx(CustomizedTag, { color: TAG_COLORS["TRIAL"], children: `${(_b = priceList.trialLengthDays) !== null && _b !== void 0 ? _b : 'N/A'} day trial` }) })) : null] }));
23510
23332
  }
23511
23333
 
23512
- const QuoteFields_QuoteFragment = t(`
23513
- fragment QuoteFields_QuoteFragment on Quote @_unmask {
23514
- accountId
23515
- amount
23516
- amountDue
23517
- smallUnitAmountDue
23518
- currencyId
23519
- id
23520
- payableId
23521
- periodAmount
23522
- subtotal
23523
- taxAmount
23524
- startDate
23525
- formattedQuote {
23526
- html
23334
+ const Signup_PriceListFragment = t(`
23335
+ fragment Signup_PriceListFragment on PriceList {
23336
+ ...CheckoutSummary_PriceListFragment
23337
+ ...PriceListDisplay_PriceListFragment
23338
+ ...SelfServiceBuyWarning_PriceListFragment
23339
+ plan {
23340
+ selfServiceBuy
23527
23341
  }
23528
- amountsByPeriod {
23342
+ trialAllowed
23343
+ }
23344
+ `, [
23345
+ CheckoutSummary_PriceListFragment,
23346
+ PriceListDisplay_PriceListFragment,
23347
+ SelfServiceBuyWarning_PriceListFragment,
23348
+ ]);
23349
+
23350
+ const graphql = initGraphQLTada();
23351
+
23352
+ const mutation$f = graphql(`
23353
+ mutation AccountSignup (
23354
+ $pluginId: String!,
23355
+ $paymentMethodId: String,
23356
+ $priceListCode: String!,
23357
+ $accountId: ID!,
23358
+ $quoteId: ID!,
23359
+ ) {
23360
+ accountSignup(
23361
+ pluginId: $pluginId,
23362
+ paymentMethodId: $paymentMethodId,
23363
+ priceListCode: $priceListCode,
23364
+ accountId: $accountId,
23365
+ quoteId: $quoteId,
23366
+ ) {
23367
+ errors
23368
+ quote {
23369
+ accountId
23529
23370
  amount
23530
- startDate
23531
- }
23532
- kind
23533
- quoteChanges {
23371
+ amountDue
23372
+ applicationDate
23373
+ applied
23374
+ backdatedPeriods
23375
+ backdatedQuote
23376
+ billingDay
23377
+ contactId
23378
+ createdAt
23379
+ credits
23534
23380
  currencyId
23381
+ dealId
23382
+ discount
23383
+ discountValue
23384
+ endDate
23385
+ evergreen
23386
+ expiresAt
23535
23387
  id
23388
+ invoiceImmediately
23389
+ invoiceImmediatelyAvailable
23390
+ invoiceUntil
23391
+ isPendingApprovalRequest
23536
23392
  kind
23537
- charges {
23538
- subtotal
23539
- amountsByPeriod {
23540
- amount
23541
- startDate
23542
- }
23543
- amount
23544
- billingPeriod
23545
- currencyId
23546
- feature {
23547
- unitName
23548
- }
23549
- id
23550
- name
23551
- priceListCharge {
23552
- id
23553
- }
23554
- priceList {
23555
- id
23556
- }
23557
- coupon {
23558
- couponCode
23559
- }
23560
- quantity
23561
- kind
23562
- }
23563
- priceList {
23564
- id
23565
- plan {
23566
- name
23567
- }
23568
- product {
23569
- name
23570
- }
23571
- }
23393
+ message
23394
+ name
23395
+ netPaymentDays
23396
+ notes
23397
+ number
23398
+ ownerId
23399
+ payableId
23400
+ periodAmount
23401
+ poNumber
23402
+ requiresApproval
23403
+ smallUnitAmountDue
23404
+ splitInvoice
23405
+ startDate
23406
+ state
23407
+ subtotal
23408
+ taxAmount
23409
+ taxCode
23410
+ updatedAt
23411
+ uuid
23572
23412
  }
23573
23413
  }
23574
- `);
23575
-
23576
- const [UpgradingSubscriptionProvider, useUpgradingSubscription] = createValueContext();
23577
-
23578
- const MUTATION$2 = `
23579
- mutation accountUpdate(
23580
- $id: ID!,
23581
- $attributes: AccountAttributes!) {
23582
- accountUpdate(
23583
- id: $id,
23584
- attributes: $attributes
23585
- ) {
23586
- account {
23587
- id
23588
- billingCountry
23589
- billingState
23590
- billingStreet
23591
- billingCity
23592
- billingZip
23593
- name
23594
- }
23595
- errors
23596
- }
23597
- }
23598
- `;
23599
- const accountUpdate$1 = async ({ accountId, attributes, token, apiHost, }) => {
23414
+ }`);
23415
+ const accountSignup = async ({ token, apiHost, accountId, quoteId, paymentToken, paymentMethodId, pluginId, priceListCode, }) => {
23600
23416
  var _a;
23601
- const vars = { id: accountId, attributes };
23602
- const response = await gqlRequest({
23603
- query: MUTATION$2,
23604
- token,
23605
- vars,
23606
- apiHost,
23417
+ const response = await execute(mutation$f, { apiHost, token }, {
23418
+ accountId,
23419
+ quoteId,
23420
+ paymentToken,
23421
+ pluginId,
23422
+ paymentMethodId,
23423
+ priceListCode,
23607
23424
  });
23608
- const errors = (_a = response === null || response === void 0 ? void 0 : response.accountUpdate) === null || _a === void 0 ? void 0 : _a.errors;
23425
+ const errors = (_a = response === null || response === void 0 ? void 0 : response.accountSignup) === null || _a === void 0 ? void 0 : _a.errors;
23609
23426
  if (errors)
23610
23427
  throw errors;
23611
- return response.accountUpdate;
23428
+ return response === null || response === void 0 ? void 0 : response.accountSignup;
23612
23429
  };
23613
23430
 
23614
- const COUNTRIES_REQUIRING_STATE = ['US', 'CA'];
23615
- const TaxationForm = ({ account, accountId }) => {
23616
- // Hooks
23617
- const queryClient = reactQuery.useQueryClient();
23618
- const { apiHost } = react.useContext(BunnyContext);
23619
- const token = useToken();
23620
- const [form] = antd.Form.useForm();
23621
- // Mutations
23622
- const { mutate: updateAccount, isPending: isUpdatingAccount } = reactQuery.useMutation({
23623
- mutationFn: async (changedFormData) => {
23624
- const account = await accountUpdate$1({
23625
- accountId,
23626
- attributes: changedFormData,
23627
- token,
23628
- apiHost,
23629
- });
23630
- return account;
23631
- },
23632
- onSuccess: () => {
23633
- queryClient.invalidateQueries({
23634
- queryKey: ['getTaxationRequiredAccountFields', token],
23635
- });
23636
- },
23431
+ const mutation$e = t(`
23432
+ mutation QuoteAccountSignup (
23433
+ $accountName: String!,
23434
+ $billingContact: ContactAttributes!,
23435
+ $priceListCode: String!,
23436
+ $billingDetails: BillingDetailsAttributes
23437
+ $trial: Boolean,
23438
+ ) {
23439
+ quoteAccountSignup(
23440
+ priceListCode: $priceListCode,
23441
+ accountName: $accountName,
23442
+ billingContact: $billingContact,
23443
+ billingDetails: $billingDetails,
23444
+ trial: $trial,
23445
+ ) {
23446
+ account {
23447
+ id
23448
+ }
23449
+ quote {
23450
+ ...Signup_QuoteFragment
23451
+ id
23452
+ }
23453
+ tenant {
23454
+ code
23455
+ }
23456
+ portalSessionToken
23457
+ errors
23458
+ }
23459
+ }`, [Signup_QuoteFragment]);
23460
+ const quoteAccountSignup = async ({ token, apiHost, priceListCode, accountName, billingContact, billingDetails, trial, }) => {
23461
+ var _a;
23462
+ const response = await execute(mutation$e, { apiHost, token }, {
23463
+ priceListCode,
23464
+ accountName,
23465
+ billingContact,
23466
+ billingDetails,
23467
+ trial,
23637
23468
  });
23638
- return (jsxRuntime.jsxs(antd.Form, { className: "bunny-flex bunny-flex-col bunny-gap-4", form: form, initialValues: account, layout: "vertical", onFinish: updateAccount, children: [jsxRuntime.jsx(antd.Form.Item, { label: "Billing street", name: "billingStreet", children: jsxRuntime.jsx(antd.Input, { placeholder: "Street" }) }), jsxRuntime.jsx(antd.Form.Item, { label: "Billing city", name: "billingCity", children: jsxRuntime.jsx(antd.Input, { placeholder: "City" }) }), jsxRuntime.jsx(FormBillingState, {}), jsxRuntime.jsx(antd.Form.Item, { label: "Billing country", name: "billingCountry", rules: [{ required: true }], children: jsxRuntime.jsx(antd.Select, { options: COUNTRY_LIST, placeholder: "Select a country", showSearch: true, filterOption: (input, option) => {
23639
- var _a, _b;
23640
- return ((_a = option === null || option === void 0 ? void 0 : option.label) !== null && _a !== void 0 ? _a : '').toLowerCase().includes(input.toLowerCase()) ||
23641
- ((_b = option === null || option === void 0 ? void 0 : option.value) !== null && _b !== void 0 ? _b : '').toLowerCase().includes(input.toLowerCase());
23642
- } }) }), jsxRuntime.jsx(antd.Form.Item, { label: "Billing zip", name: "billingZip", children: jsxRuntime.jsx(antd.Input, { placeholder: "Zip" }) }), jsxRuntime.jsx(antd.Form.Item, { children: jsxRuntime.jsx(antd.Button, { className: "bunny-w-full", disabled: isUpdatingAccount, htmlType: "submit", type: "primary", children: "Submit" }) })] }));
23643
- };
23644
- const FormBillingState = () => {
23645
- const billingCountry = antd.Form.useWatch('billingCountry');
23646
- const billingStateRequired = COUNTRIES_REQUIRING_STATE.includes(billingCountry);
23647
- return (jsxRuntime.jsx(antd.Form.Item, { label: "Billing state", name: "billingState", rules: [{ required: billingStateRequired }], children: jsxRuntime.jsx(antd.Input, { placeholder: "State" }) }));
23469
+ const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteAccountSignup) === null || _a === void 0 ? void 0 : _a.errors;
23470
+ if (errors)
23471
+ throw errors;
23472
+ return response === null || response === void 0 ? void 0 : response.quoteAccountSignup;
23648
23473
  };
23649
23474
 
23650
- const [OnPaymentMethodSavedProvider, useOnPaymentMethodSaved] = createValueContext();
23651
- // This provider is used in all components that may save a payment method
23652
-
23653
- const [OnPaymentMethodRemovedProvider, useOnPaymentMethodRemoved] = createValueContext();
23654
- // This provider is used in all components that may remove a payment method
23655
-
23656
- const { Text: Text$o } = antd.Typography;
23657
- // HACK: I have imported QuoteFields_QuoteFragment here as a hack to ensure I have all of the quote data needed for
23658
- // the eventual children of this component.
23659
- // Solution: Eventually all children of this component should be using query fragments to avoid this
23660
- const QuoteCheckout_QuoteFragment = t(`
23661
- fragment QuoteCheckout_QuoteFragment on Quote {
23662
- id
23663
- accountId
23664
- amountDue
23665
- amount
23666
- quoteChanges {
23667
- id
23668
- charges {
23669
- kind
23670
- coupon {
23671
- couponCode
23672
- }
23673
- }
23475
+ const mutation$d = t(`
23476
+ mutation QuoteRecalculateTaxes($id: ID!) {
23477
+ quoteRecalculateTaxes(id: $id) {
23478
+ quote {
23479
+ ...Signup_QuoteFragment
23674
23480
  }
23675
- ...QuoteFields_QuoteFragment
23676
- ...shouldShowCouponEditor_QuoteFragment
23677
- ...PaymentForm_QuoteFragment
23678
- ...getQuoteAmountDue_QuoteFragment
23481
+ errors
23679
23482
  }
23680
- `, [
23681
- QuoteFields_QuoteFragment,
23682
- shouldShowCouponEditor_QuoteFragment,
23683
- PaymentForm_QuoteFragment,
23684
- getQuoteAmountDue_QuoteFragment,
23685
- ]);
23686
- const QuoteCheckout_SubscriptionFragment = t(`
23687
- fragment QuoteCheckout_SubscriptionFragment on Subscription {
23688
- id
23689
- ...shouldShowCouponEditor_SubscriptionFragment
23483
+ }
23484
+ `, [Signup_QuoteFragment]);
23485
+ const quoteRecalculateTaxes$2 = async ({ quoteId, apiHost, token, }) => {
23486
+ var _a;
23487
+ const response = await execute(mutation$d, { apiHost, token }, { id: quoteId });
23488
+ return (_a = response.quoteRecalculateTaxes) === null || _a === void 0 ? void 0 : _a.quote;
23489
+ };
23490
+
23491
+ const { Title, Text: Text$n } = antd.Typography;
23492
+ function PaymentSuccessDisplay({ amountPaid, className, companyName, returnUrl, style, currencyId, }) {
23493
+ return (jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-items-center bunny-justify-center bunny-h-full ${className}`, style: style, children: [jsxRuntime.jsx(icons.CheckCircleFilled, { style: { fontSize: '48px', color: 'rgb(52 211 153)' } }), jsxRuntime.jsxs(Title, { level: 3, className: "bunny-mt-2 bunny-m-0", children: ["Payment of ", formatCurrency(amountPaid, currencyId), " successful"] }), returnUrl && (jsxRuntime.jsxs(Text$n, { className: "bunny-text-slate-500 bunny-cursor-pointer bunny-underline", onClick: () => (window.location.href = returnUrl), children: ["Back to ", companyName] }))] }));
23494
+ }
23495
+
23496
+ const query$5 = t(`
23497
+ query PriceList($code: String!) {
23498
+ priceList (code: $code) {
23499
+ ...Signup_PriceListFragment
23690
23500
  }
23691
- `, [shouldShowCouponEditor_SubscriptionFragment]);
23501
+ }
23502
+ `, [Signup_PriceListFragment]);
23503
+ const getPriceList = async ({ token, code, apiHost, }) => {
23504
+ const response = await execute(query$5, { apiHost, token }, { code });
23505
+ return response === null || response === void 0 ? void 0 : response.priceList;
23506
+ };
23507
+
23508
+ const showErrorNotification$2 = useErrorNotification();
23692
23509
  const showSuccessNotification$1 = useSuccessNotification();
23693
- const QuoteCheckout = ({ account, onSuccess, onFail, quote: maskedQuote, taxationRequiredAccountFields, onRecalculateTaxes, }) => {
23694
- var _a, _b, _c, _d, _e;
23695
- const maskedUpgradingSubscription = useUpgradingSubscription();
23696
- // Read fragments
23697
- const quote = readFragment(QuoteCheckout_QuoteFragment, maskedQuote);
23698
- const upgradingSubscription = readFragment(QuoteCheckout_SubscriptionFragment, maskedUpgradingSubscription);
23699
- // Context
23700
- const onPaymentMethodSaved = useOnPaymentMethodSaved();
23701
- const onPaymentMethodRemoved = useOnPaymentMethodRemoved();
23510
+ const showInfoNotification$2 = useInfoNotification();
23511
+ function Signup({ companyName, priceListCode, returnUrl, couponCode, className, shadow = 'shadow-md', style, defaultFirstName, defaultLastName, defaultEmail, defaultCompanyName, defaultBillingCountry, }) {
23512
+ var _a, _b, _c, _d, _e, _f;
23513
+ // Hooks
23702
23514
  const { apiHost } = react.useContext(BunnyContext);
23703
- const token = useToken();
23515
+ const tokenFromContexts = useToken();
23704
23516
  const isMobile = useIsMobile();
23705
- const [isSaving, setIsSaving] = react.useState(false);
23706
- const paymentRequired = getQuoteAmountDue(quote) > 0;
23517
+ const { topNavImageUrl } = useBrand();
23518
+ const defaultValues = react.useMemo(() => ({
23519
+ firstName: defaultFirstName,
23520
+ lastName: defaultLastName,
23521
+ email: defaultEmail,
23522
+ accountName: defaultCompanyName,
23523
+ billingCountry: defaultBillingCountry,
23524
+ }), [defaultFirstName, defaultLastName, defaultEmail, defaultCompanyName, defaultBillingCountry]);
23707
23525
  const queryClient = reactQuery.useQueryClient();
23708
- const [couponCode, setCouponCode] = react.useState('');
23709
- const { addCoupon, removeCoupon, isAddingCoupon, isRemovingCoupon, activeCouponsExist } = useUpdateCoupons({
23526
+ const [initialQuote, setInitialQuote] = react.useState(undefined);
23527
+ const [accountId, setAccountId] = react.useState(undefined);
23528
+ const [portalSessionToken, setPortalSessionToken] = react.useState(undefined);
23529
+ const token = portalSessionToken || tokenFromContexts;
23530
+ const [purchaseSucceeded, setPurchaseSucceeded] = react.useState(false);
23531
+ const defaultCouponAppliedRef = react.useRef(undefined);
23532
+ const [couponEditorCouponCode, setCouponEditorCouponCode] = react.useState('');
23533
+ // Read fragment
23534
+ const initialQuoteId = (_a = readFragment(Signup_QuoteFragment, initialQuote)) === null || _a === void 0 ? void 0 : _a.id;
23535
+ const hasTaxPlugin = useHasTaxPlugin({
23710
23536
  apiHost,
23711
23537
  token,
23712
- quoteChangeId: (_d = (_c = (_a = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _a === void 0 ? void 0 : _a[((_b = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _b === void 0 ? void 0 : _b.length) - 1]) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : undefined,
23713
- onCouponAdded: () => {
23714
- if (!(quote === null || quote === void 0 ? void 0 : quote.id))
23715
- throw new Error('Quote ID is required');
23538
+ });
23539
+ const { mutate: recalculateTaxesMutation } = reactQuery.useMutation({
23540
+ mutationFn: (quoteId) => {
23541
+ return quoteRecalculateTaxes$2({ token, apiHost, quoteId });
23542
+ },
23543
+ onError: (error) => {
23544
+ if (!error[0].message.includes('Ensure that you have a taxation plugin')) {
23545
+ showErrorNotification$2(error.message);
23546
+ }
23547
+ },
23548
+ onSuccess: (quote) => {
23549
+ queryClient.setQueryData(['quote', initialQuoteId], quote);
23716
23550
  queryClient.invalidateQueries({
23717
- queryKey: QueryKeyFactory.createObjectKey({
23718
- id: quote === null || quote === void 0 ? void 0 : quote.id,
23719
- objectName: 'editingQuote',
23720
- token,
23721
- }),
23551
+ queryKey: ['quote', initialQuoteId],
23722
23552
  });
23723
- showSuccessNotification$1('Coupon applied');
23724
- onRecalculateTaxes();
23725
- setCouponCode('');
23726
23553
  },
23727
- onCouponRemoved: () => {
23728
- if (!(quote === null || quote === void 0 ? void 0 : quote.id))
23729
- throw new Error('Quote ID is required');
23554
+ });
23555
+ const { mutate: quoteAccountSignupMutate, isPending: isSigningUp } = reactQuery.useMutation({
23556
+ mutationFn: (formData) => {
23557
+ var _a;
23558
+ return quoteAccountSignup({
23559
+ token,
23560
+ apiHost,
23561
+ priceListCode,
23562
+ accountName: formData.accountName,
23563
+ billingContact: {
23564
+ firstName: formData.firstName,
23565
+ lastName: formData.lastName,
23566
+ email: formData.email,
23567
+ },
23568
+ billingDetails: {
23569
+ billingCountry: formData.billingCountry,
23570
+ // TODO: add these billing details back for Avalara and AFC taxation plugins.
23571
+ // billingState: formData.billingState,
23572
+ // billingCity: formData.billingCity,
23573
+ // billingZip: formData.billingZip,
23574
+ // billingStreet: formData.billingStreet,
23575
+ // taxNumber: formData.taxNumber,
23576
+ },
23577
+ trial: (_a = priceList === null || priceList === void 0 ? void 0 : priceList.trialAllowed) !== null && _a !== void 0 ? _a : false,
23578
+ });
23579
+ },
23580
+ onSuccess: (data) => {
23581
+ var _a, _b;
23582
+ setAccountId((_a = data === null || data === void 0 ? void 0 : data.account) === null || _a === void 0 ? void 0 : _a.id);
23583
+ if (!(data === null || data === void 0 ? void 0 : data.portalSessionToken)) {
23584
+ throw new Error('Portal session token is required');
23585
+ }
23586
+ setPortalSessionToken(data === null || data === void 0 ? void 0 : data.portalSessionToken);
23587
+ // We must invalidate the accountPaymentMethodsKey query in order to clear payment methods from the provided api token,
23588
+ // to instead use paymentMethods from portalSessionToken.
23730
23589
  queryClient.invalidateQueries({
23731
- queryKey: QueryKeyFactory.createObjectKey({
23732
- id: quote === null || quote === void 0 ? void 0 : quote.id,
23733
- objectName: 'editingQuote',
23590
+ queryKey: QueryKeyFactory.accountPaymentMethodsKey({
23591
+ accountId,
23734
23592
  token,
23735
23593
  }),
23736
23594
  });
23737
- showSuccessNotification$1('Coupon removed');
23738
- onRecalculateTaxes();
23595
+ setInitialQuote(data === null || data === void 0 ? void 0 : data.quote);
23596
+ handleRecalculateTaxes((_b = data === null || data === void 0 ? void 0 : data.quote) === null || _b === void 0 ? void 0 : _b.id);
23597
+ },
23598
+ onError: (error) => {
23599
+ const errorMessage = error.response.errors[0].message;
23600
+ if (errorMessage.includes("Address couldn't be validated")) {
23601
+ showErrorNotification$2('Please enter a valid billing address');
23602
+ }
23603
+ else {
23604
+ showErrorNotification$2(errorMessage);
23605
+ }
23739
23606
  },
23740
23607
  });
23741
- const couponsOnQuote = (_e = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _e === void 0 ? void 0 : _e.flatMap(quoteChange => { var _a; return (_a = quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.charges) === null || _a === void 0 ? void 0 : _a.filter(charge => charge.kind === 'COUPON'); });
23742
- const checkoutMutation = reactQuery.useMutation({
23743
- mutationFn: async () => {
23744
- if (!(quote === null || quote === void 0 ? void 0 : quote.id))
23608
+ // Queries
23609
+ const { data: maskedPriceList, isLoading: isLoadingPriceList } = reactQuery.useQuery({
23610
+ queryKey: ['priceList', priceListCode],
23611
+ queryFn: () => getPriceList({ token, apiHost, code: priceListCode }),
23612
+ });
23613
+ const { data, isLoading: isLoadingQuote } = reactQuery.useQuery({
23614
+ queryKey: ['quote', initialQuoteId],
23615
+ queryFn: () => {
23616
+ if (!initialQuoteId) {
23745
23617
  throw new Error('Quote ID is required');
23746
- if (paymentRequired)
23747
- throw new Error('Payment is required');
23748
- return await checkout({ quoteId: quote.id, token, apiHost });
23618
+ }
23619
+ return getQuote$1({ token, apiHost, id: initialQuoteId });
23749
23620
  },
23750
- onSuccess,
23751
- onError: onFail,
23752
- });
23753
- async function handleCheckoutNoPayment() {
23754
- setIsSaving(true);
23755
- checkoutMutation.mutate();
23756
- setIsSaving(false);
23757
- }
23758
- if (taxationRequiredAccountFields)
23759
- return (jsxRuntime.jsx(PaymentFormWrapper, { setMaxHeight: false, children: jsxRuntime.jsx(TaxationForm, { account: account, accountId: quote.accountId }) }));
23760
- 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) }), (couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.length) === 0 ? (jsxRuntime.jsx(jsxRuntime.Fragment, { children: upgradingSubscription &&
23761
- 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: () => {
23762
- couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.forEach(couponCharge => {
23763
- var _a;
23764
- const couponCode = (_a = couponCharge === null || couponCharge === void 0 ? void 0 : couponCharge.coupon) === null || _a === void 0 ? void 0 : _a.couponCode;
23765
- if (couponCode) {
23766
- removeCoupon(couponCode);
23767
- }
23768
- });
23769
- }, children: "Remove coupon(s)" }))] })) : (jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-2 bunny-px-4 ${isMobile ? 'bunny-shadow-padding-x' : ''}`, children: [jsxRuntime.jsx(antd.Button, { onClick: handleCheckoutNoPayment, type: "primary", children: isSaving ? 'Processing...' : 'Complete order' }), jsxRuntime.jsx(Text$o, { className: "bunny-text-xs bunny-text-slate-500", children: "No payment is required" })] })) }));
23770
- };
23771
- const PaymentFormWrapper = ({ children, setMaxHeight, className, }) => {
23772
- const isMobile = useIsMobile();
23773
- return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-w-full bunny-flex-col bunny-gap-6 ${isMobile ? 'bunny-shadow-padding-xb' : ''} ${className}`, style: {
23774
- ...(isMobile
23775
- ? setMaxHeight
23776
- ? { maxHeight: '60vh' }
23777
- : {}
23778
- : {
23779
- width: '100%',
23780
- maxWidth: '400px',
23781
- }),
23782
- }, children: children }));
23783
- };
23784
-
23785
- const Checkout_QuoteFragment = t(`
23786
- fragment Checkout_QuoteFragment on Quote {
23787
- id
23788
- accountId
23789
- formattedQuote {
23790
- html
23791
- }
23792
- ...QuoteCheckout_QuoteFragment
23793
- }
23794
- `, [QuoteCheckout_QuoteFragment]);
23795
- const Checkout = ({ onCancel, onSuccess, onFail, onRecalculateTaxes, invoice, open, quote: maskedQuote, isUpdatingQuote, }) => {
23796
- var _a, _b, _c, _d, _e;
23797
- const { apiHost } = react.useContext(BunnyContext);
23798
- const isMobile = useIsMobile();
23799
- const token = useToken();
23800
- // Context
23801
- const onPaymentMethodSaved = useOnPaymentMethodSaved();
23802
- const onPaymentMethodRemoved = useOnPaymentMethodRemoved();
23803
- // Read fragments
23804
- const quote = readFragment(Checkout_QuoteFragment, maskedQuote);
23805
- const hasTaxPlugin = useHasTaxPlugin({
23806
- apiHost,
23807
- token,
23808
- });
23809
- // Queries
23810
- const { data: taxationRequiredAccountFields, isLoading: isLoadingTaxationRequiredAccountFields } = reactQuery.useQuery({
23811
- queryKey: ['getTaxationRequiredAccountFields', token],
23812
- queryFn: () => getTaxationRequiredAccountFields({ apiHost, token }),
23813
- enabled: Boolean(quote),
23814
- staleTime: 0,
23815
- });
23816
- const { data: account, isLoading: isLoadingAccount } = reactQuery.useQuery({
23817
- queryKey: ['account', quote === null || quote === void 0 ? void 0 : quote.accountId],
23818
- queryFn: () => (quote === null || quote === void 0 ? void 0 : quote.accountId) && getAccount$1({ id: quote.accountId, apiHost, token }),
23819
- enabled: Boolean(quote === null || quote === void 0 ? void 0 : quote.accountId) && ((taxationRequiredAccountFields === null || taxationRequiredAccountFields === void 0 ? void 0 : taxationRequiredAccountFields.length) || 0) > 0,
23820
- });
23821
- // Use onRecalculateTaxes callback because parents need to define recalculateTaxes to get and set the right quote data they need
23822
- async function recalculateTaxes() {
23823
- if (quote) {
23824
- if (!quote.id)
23825
- throw new Error('Quote ID is required');
23826
- onRecalculateTaxes(quote.id);
23827
- }
23828
- return {};
23829
- }
23830
- const recalculateTaxesEnabled = Boolean(quote) &&
23831
- open &&
23832
- hasTaxPlugin &&
23833
- !taxationRequiredAccountFields &&
23834
- !isLoadingTaxationRequiredAccountFields &&
23835
- !isUpdatingQuote;
23836
- reactQuery.useQuery({
23837
- queryKey: QueryKeyFactory.createQuoteTaxCalculateKey({
23838
- id: (_a = quote === null || quote === void 0 ? void 0 : quote.id) !== null && _a !== void 0 ? _a : undefined,
23839
- token,
23840
- }),
23841
- queryFn: recalculateTaxes,
23842
- // Recalculate taxes if the quote is open, has a tax plugin, and the taxation required account fields are not required
23843
- enabled: recalculateTaxesEnabled,
23844
- staleTime: 0,
23845
- });
23846
- if (!open || isLoadingTaxationRequiredAccountFields || isLoadingAccount)
23847
- return null;
23848
- return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-flex-col bunny-fixed bunny-top-0 bunny-left-0 bunny-right-0 bunny-bottom-0 bunny-bg-slate-50
23849
- bunny-overflow-auto bunny-height-full`, style: {
23850
- zIndex: 1001,
23851
- }, children: jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-grow bunny-pt-4 ${isMobile ? 'bunny-pb-4' : 'bunny-pb-8'} bunny-content-container`, children: [jsxRuntime.jsx("div", { className: "bunny-flex bunny-justify-end bunny-w-full bunny-pr-4", children: jsxRuntime.jsx(icons.CloseOutlined, { className: "bunny-text-base bunny-shadow-padding-xb", onClick: onCancel }) }), jsxRuntime.jsxs("div", { className: `bunny-flex bunny-justify-end bunny-pt-4 bunny-gap-4 ${isMobile ? 'bunny-flex-col' : 'bunny-shadow-padding-xb'}`, children: [((invoice === null || invoice === void 0 ? void 0 : invoice.html) || ((_b = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _b === void 0 ? void 0 : _b.html)) && (jsxRuntime.jsx(InvoiceQuoteView, { html: invoice ? invoice.html : (_d = (_c = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _c === void 0 ? void 0 : _c.html) !== null && _d !== void 0 ? _d : '' })), !isMobile && ((invoice === null || invoice === void 0 ? void 0 : invoice.html) || ((_e = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _e === void 0 ? void 0 : _e.html)) && (jsxRuntime.jsx(antd.Divider, { className: "bunny-h-full", type: "vertical" })), invoice ? (jsxRuntime.jsx("div", { className: "bunny-w-full bunny-pt-12", children: jsxRuntime.jsx(PaymentForm, { onPaymentSuccess: onSuccess, invoice: invoice, 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) }) })) : quote ? (jsxRuntime.jsx(QuoteCheckout, { account: account, onFail: error => {
23852
- onFail(error);
23853
- }, onSuccess: onSuccess, quote: quote, taxationRequiredAccountFields: taxationRequiredAccountFields, token: token, onRecalculateTaxes: async () => {
23854
- if (recalculateTaxesEnabled) {
23855
- await recalculateTaxes();
23856
- }
23857
- } })) : (jsxRuntime.jsx(PaymentForm, { onPaymentSuccess: onSuccess, 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) }))] }), jsxRuntime.jsx(Footer, { className: "bunny-px-12" })] }) }));
23858
- };
23859
-
23860
- function canEditChargeQuantity(charge) {
23861
- if (!charge)
23862
- return false;
23863
- if (charge.chargeType === graphql.scalar('ChargeType', 'USAGE'))
23864
- return false;
23865
- if (charge.pricingModel === graphql.scalar('PricingModel', 'FLAT'))
23866
- return false;
23867
- return true;
23868
- }
23869
-
23870
- const { Text: Text$n } = antd.Typography;
23871
- const CheckoutBarInput = ({ disabled, priceListCharge, quantity, onQuantityChanged, }) => {
23872
- var _a;
23873
- const [isTooltipOpen, setIsTooltipOpen] = react.useState(false);
23874
- const isMobile = useIsMobile();
23875
- react.useEffect(() => {
23876
- setTimeout(() => {
23877
- setIsTooltipOpen(true);
23878
- }, 1000);
23879
- setTimeout(() => {
23880
- setIsTooltipOpen(false);
23881
- }, 6000);
23882
- }, []);
23883
- return (jsxRuntime.jsxs(Text$n, { className: `bunny-flex bunny-items-center bunny-gap-2 ${isMobile ? 'bunny-justify-between' : ''}`, children: [jsxRuntime.jsx(QuantityLabel, { activeCharge: priceListCharge }), jsxRuntime.jsx(antd.Tooltip, { onOpenChange: setIsTooltipOpen, open: isTooltipOpen, title: "Change quantity here", styles: {
23884
- body: {
23885
- paddingTop: '0.75rem',
23886
- paddingBottom: '0.75rem',
23887
- },
23888
- }, children: jsxRuntime.jsx(antd.Input, { id: `${(_a = priceListCharge.name) === null || _a === void 0 ? void 0 : _a.toLowerCase().replace(/ /g, '-')}-quantity-input`, className: isMobile ? 'text-right' : '', disabled: disabled, onChange: e => {
23889
- onQuantityChanged(Number(e.target.value));
23890
- }, min: priceListCharge === null || priceListCharge === void 0 ? void 0 : priceListCharge.quantityMin, max: priceListCharge === null || priceListCharge === void 0 ? void 0 : priceListCharge.quantityMax, style: { minWidth: '120px' }, type: "number", value: quantity, required: true }) })] }));
23891
- };
23892
- const QuantityLabel = ({ activeCharge }) => {
23893
- const chargeName = activeCharge.name;
23894
- return (jsxRuntime.jsx(Text$n, { className: "bunny-text-slate-500 bunny-font-medium bunny-text-nowrap", style: { fontSize: '11px' }, children: chargeName.toUpperCase() }));
23895
- };
23896
-
23897
- const PlanPickerCheckoutBar_QuoteFragment = t(`
23898
- fragment PlanPickerCheckoutBar_QuoteFragment on Quote {
23899
- ...Checkout_QuoteFragment
23900
- quoteChanges {
23901
- priceList {
23902
- id
23903
- }
23904
- charges {
23905
- priceListCharge {
23906
- id
23907
- }
23908
- }
23909
- }
23910
- }
23911
- `, [Checkout_QuoteFragment]);
23912
- const PlanPickerCheckoutBar = ({ selectedPriceList, handlePortalErrors, onCheckoutSuccess, }) => {
23913
- // Context
23914
- const { shadow } = useSubscriptionProps();
23915
- const { quote: maskedQuote, onChangeQuantity, getFeatureQuantity, onRecalculateTaxes, isFeatureAddonsLoading, isUpdatingQuote, } = react.useContext(QuoteContext);
23916
- // Read fragments
23917
- const quote = readFragment(PlanPickerCheckoutBar_QuoteFragment, maskedQuote);
23918
- // Local state
23919
- const [payModalVisible, setPayModalVisible] = react.useState(false);
23920
- // Hooks
23921
- const token = useToken();
23922
- const showSuccessNotification = useSuccessNotification();
23923
- const queryClient = reactQuery.useQueryClient();
23924
- const isMobile = useIsMobile();
23925
- const handleCheckoutSuccess = () => {
23926
- queryClient.refetchQueries({
23927
- queryKey: QueryKeyFactory.createTableKey({
23928
- pluralType: 'subscriptions',
23929
- token,
23930
- }),
23931
- });
23932
- queryClient.invalidateQueries({
23933
- queryKey: QueryKeyFactory.createTableKey({
23934
- pluralType: 'upgradeSubscriptions',
23935
- token,
23936
- }),
23937
- });
23938
- queryClient.invalidateQueries({
23939
- queryKey: QueryKeyFactory.createTableKey({
23940
- pluralType: 'hasActiveSubscriptions',
23941
- token,
23942
- }),
23943
- });
23944
- queryClient.invalidateQueries({
23945
- queryKey: QueryKeyFactory.transactionsKey({ token }),
23946
- });
23947
- setPayModalVisible(false);
23948
- showSuccessNotification('Your subscription has been created', 'Checkout successful');
23949
- onCheckoutSuccess();
23950
- };
23951
- return (jsxRuntime.jsxs("div", { className: `bunny-flex ${isMobile ? 'bunny-flex-col bunny-gap-4' : 'bunny-flex-row'} bunny-my-4 bunny-p-4 bunny-justify-between bunny-bg-white bunny-rounded-md ${shadow ? `shadow-${shadow}` : ''}`, children: [jsxRuntime.jsx("div", { className: `${isMobile ? 'bunny-flex bunny-flex-col' : 'bunny-flex'} bunny-gap-4`, children: selectedPriceList === null || selectedPriceList === void 0 ? void 0 : selectedPriceList.charges.map((charge, index) => {
23952
- var _a, _b, _c, _d;
23953
- if (!canEditChargeQuantity({
23954
- chargeType: (_a = charge.chargeType) !== null && _a !== void 0 ? _a : null,
23955
- pricingModel: (_b = charge.pricingModel) !== null && _b !== void 0 ? _b : null,
23956
- }))
23957
- return null;
23958
- if (!((_c = charge.feature) === null || _c === void 0 ? void 0 : _c.id))
23959
- throw new Error('Charge feature is undefined');
23960
- const isFeatureAddon = charge.featureAddon;
23961
- const quantity = getFeatureQuantity((_d = charge.feature) === null || _d === void 0 ? void 0 : _d.id, charge.id);
23962
- const maybeIsChargeLoading = isFeatureAddon && isFeatureAddonsLoading;
23963
- if (!quantity)
23964
- return null;
23965
- // if charge is a feature addon, and a corresponding quote charge is not found in quote, return null
23966
- if (isFeatureAddon && !featureAddonInQuote(selectedPriceList, charge, quote)) {
23967
- return null;
23968
- }
23969
- const isDisabled = !quote || maybeIsChargeLoading || !selectedPriceList || !charge.selfServiceQuantity;
23970
- return (jsxRuntime.jsx(CheckoutBarInput, { disabled: isDisabled, priceListCharge: charge, quantity: quantity, onQuantityChanged: quantity => {
23971
- onChangeQuantity(charge.id, quantity);
23972
- } }, index));
23973
- }) }), jsxRuntime.jsx(CheckoutBarSummarySection, { onClickCheckout: () => setPayModalVisible(true), selectedPriceList: selectedPriceList }), jsxRuntime.jsx(Checkout, { onCancel: () => setPayModalVisible(false), onFail: error => handlePortalErrors === null || handlePortalErrors === void 0 ? void 0 : handlePortalErrors(error), onSuccess: handleCheckoutSuccess, onRecalculateTaxes: onRecalculateTaxes, open: payModalVisible, quote: quote, token: token, isUpdatingQuote: isUpdatingQuote })] }));
23974
- };
23975
-
23976
- const useQuoteUpdateFeatureAddon_QuoteFragment = t(`
23977
- fragment useQuoteUpdateFeatureAddon_QuoteFragment on Quote {
23978
- id
23979
- startDate
23980
- }
23981
- `);
23982
-
23983
- const FeatureAddonRow_QuoteFragment = t(`
23984
- fragment FeatureAddonRow_QuoteFragment on Quote {
23985
- ...useQuoteUpdateFeatureAddon_QuoteFragment
23986
- }
23987
- `, [useQuoteUpdateFeatureAddon_QuoteFragment]);
23988
-
23989
- const useToggleAddonPlan_QuoteFragment = t(`
23990
- fragment useToggleAddonPlan_QuoteFragment on Quote {
23991
- quoteChanges {
23992
- priceList {
23993
- id
23994
- }
23995
- id
23996
- }
23997
- id
23998
- }
23999
- `);
24000
-
24001
- const AddonPlanRow_QuoteFragment = t(`
24002
- fragment AddonPlanRow_QuoteFragment on Quote {
24003
- ...useToggleAddonPlan_QuoteFragment
24004
- }
24005
- `, [useToggleAddonPlan_QuoteFragment]);
24006
-
24007
- /**
24008
- * Central quote fragment for QuoteProvider context.
24009
- *
24010
- * This fragment aggregates all child component fragments to ensure the QuoteProvider
24011
- * fetches all required quote data upfront. When a component needs specific quote fields,
24012
- * add its fragment here to maintain type safety and avoid over-fetching.
24013
- *
24014
- * Pattern: Fragment Composition
24015
- * - Components define their data needs via fragments
24016
- * - Provider composes these fragments into a single query
24017
- * - Type safety ensures all required fields are fetched
24018
- */
24019
- const QuoteContext_QuoteFragment = t(`
24020
- fragment QuoteContext_QuoteFragment on Quote {
24021
- id
24022
- currencyId
24023
- amountDue
24024
- startDate
24025
- quoteChanges {
24026
- id
24027
- kind
24028
- priceList {
24029
- id
24030
- }
24031
- charges {
24032
- priceListCharge {
24033
- id
24034
- chargeType
24035
- pricingModel
24036
- quantityMin
24037
- quantityMax
24038
- selfServiceQuantity
24039
- }
24040
- feature {
24041
- id
24042
- }
24043
- quantity
24044
- id
24045
- }
24046
- }
24047
- ...PlanPickerCheckoutBar_QuoteFragment
24048
- ...CheckoutBarSummarySection_QuoteFragment
24049
- ...AddonPlanRow_QuoteFragment
24050
- ...FeatureAddonRow_QuoteFragment
24051
- ...PaymentForms_QuoteFragment
24052
- }
24053
- `, [
24054
- PlanPickerCheckoutBar_QuoteFragment,
24055
- CheckoutBarSummarySection_QuoteFragment,
24056
- AddonPlanRow_QuoteFragment,
24057
- FeatureAddonRow_QuoteFragment,
24058
- PaymentForms_QuoteFragment,
24059
- ]);
24060
-
24061
- const FormattedQuoteField_QuoteFragment = t(`
24062
- fragment FormattedQuoteField_QuoteFragment on Quote {
24063
- formattedQuote {
24064
- html
24065
- }
24066
- }
24067
- `);
24068
- const query$5 = t(`
24069
- query quote($id: ID, $removeFormattedQuoteField: Boolean!) {
24070
- quote(id: $id) {
24071
- ...QuoteContext_QuoteFragment
24072
- ...FormattedQuoteField_QuoteFragment @include(if: $removeFormattedQuoteField)
24073
- }
24074
- }
24075
- `, [QuoteContext_QuoteFragment, FormattedQuoteField_QuoteFragment]);
24076
- const getQuote$1 = async ({ id, token, apiHost, removeFormattedQuoteField = false, }) => {
24077
- const response = await execute(query$5, { apiHost, token }, { id, removeFormattedQuoteField });
24078
- return response === null || response === void 0 ? void 0 : response.quote;
24079
- };
24080
-
24081
- const MUTATION$1 = () => `
24082
- mutation AccountSignup (
24083
- $pluginId: String!,
24084
- $paymentMethodId: String,
24085
- $priceListCode: String!,
24086
- $accountId: ID!,
24087
- $quoteId: ID!,
24088
- ) {
24089
- accountSignup(
24090
- pluginId: $pluginId,
24091
- paymentMethodId: $paymentMethodId,
24092
- priceListCode: $priceListCode,
24093
- accountId: $accountId,
24094
- quoteId: $quoteId,
24095
- ) {
24096
- errors
24097
- quote {
24098
- accountId
24099
- amount
24100
- amountDue
24101
- applicationDate
24102
- applied
24103
- backdatedPeriods
24104
- backdatedQuote
24105
- billingDay
24106
- contactId
24107
- createdAt
24108
- credits
24109
- currencyId
24110
- dealId
24111
- discount
24112
- discountValue
24113
- endDate
24114
- evergreen
24115
- expiresAt
24116
- id
24117
- invoiceImmediately
24118
- invoiceImmediatelyAvailable
24119
- invoiceUntil
24120
- isPendingApprovalRequest
24121
- kind
24122
- message
24123
- name
24124
- netPaymentDays
24125
- notes
24126
- number
24127
- ownerId
24128
- payableId
24129
- periodAmount
24130
- poNumber
24131
- requiresApproval
24132
- smallUnitAmountDue
24133
- splitInvoice
24134
- startDate
24135
- state
24136
- subtotal
24137
- taxAmount
24138
- taxCode
24139
- updatedAt
24140
- uuid
24141
- }
24142
- }
24143
- }`;
24144
- const accountSignup = async ({ token, apiHost, accountId, quoteId, paymentToken, paymentMethodId, pluginId, priceListCode, }) => {
24145
- var _a;
24146
- const vars = {
24147
- accountId,
24148
- quoteId,
24149
- paymentToken,
24150
- pluginId,
24151
- paymentMethodId,
24152
- priceListCode,
24153
- };
24154
- const response = await gqlRequest({
24155
- query: MUTATION$1(),
24156
- token,
24157
- vars,
24158
- apiHost,
24159
- });
24160
- const errors = (_a = response === null || response === void 0 ? void 0 : response.accountSignup) === null || _a === void 0 ? void 0 : _a.errors;
24161
- if (errors)
24162
- throw errors;
24163
- return response === null || response === void 0 ? void 0 : response.accountSignup;
24164
- };
24165
-
24166
- const MUTATION = () => `
24167
- mutation QuoteAccountSignup (
24168
- $accountName: String!,
24169
- $billingContact: ContactAttributes!,
24170
- $priceListCode: String!,
24171
- $billingDetails: BillingDetailsAttributes
24172
- ) {
24173
- quoteAccountSignup(
24174
- priceListCode: $priceListCode,
24175
- accountName: $accountName,
24176
- billingContact: $billingContact,
24177
- billingDetails: $billingDetails
24178
- ) {
24179
- account {
24180
- id
24181
- }
24182
- quote {
24183
- accountId
24184
- amount
24185
- amountDue
24186
- applicationDate
24187
- applied
24188
- backdatedPeriods
24189
- backdatedQuote
24190
- billingDay
24191
- contactId
24192
- createdAt
24193
- credits
24194
- currencyId
24195
- dealId
24196
- discount
24197
- discountValue
24198
- endDate
24199
- evergreen
24200
- expiresAt
24201
- id
24202
- invoiceImmediately
24203
- invoiceImmediatelyAvailable
24204
- invoiceUntil
24205
- isPendingApprovalRequest
24206
- kind
24207
- message
24208
- name
24209
- netPaymentDays
24210
- notes
24211
- number
24212
- ownerId
24213
- payableId
24214
- periodAmount
24215
- poNumber
24216
- requiresApproval
24217
- smallUnitAmountDue
24218
- splitInvoice
24219
- startDate
24220
- state
24221
- subtotal
24222
- taxAmount
24223
- taxCode
24224
- updatedAt
24225
- uuid
24226
- }
24227
- tenant {
24228
- code
24229
- }
24230
- portalSessionToken
24231
- errors
24232
- }
24233
- }`;
24234
- const quoteAccountSignup = async ({ token, apiHost, priceListCode, accountName, billingContact, billingDetails, }) => {
24235
- var _a;
24236
- const vars = {
24237
- priceListCode,
24238
- accountName,
24239
- billingContact,
24240
- billingDetails,
24241
- };
24242
- const response = await gqlRequest({
24243
- query: MUTATION(),
24244
- token,
24245
- vars,
24246
- apiHost,
24247
- });
24248
- const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteAccountSignup) === null || _a === void 0 ? void 0 : _a.errors;
24249
- if (errors)
24250
- throw errors;
24251
- return response === null || response === void 0 ? void 0 : response.quoteAccountSignup;
24252
- };
24253
-
24254
- const QUOTE_RECALCULATE_TAXES = `
24255
- mutation QuoteRecalculateTaxes($id: ID!) {
24256
- quoteRecalculateTaxes(id: $id) {
24257
- quote {
24258
- accountId
24259
- amount
24260
- amountDue
24261
- smallUnitAmountDue
24262
- currencyId
24263
- formattedQuote {
24264
- html
24265
- }
24266
- id
24267
- payableId
24268
- periodAmount
24269
- subtotal
24270
- taxAmount
24271
- amountsByPeriod {
24272
- amount
24273
- startDate
24274
- }
24275
- kind
24276
- quoteChanges {
24277
- currencyId
24278
- id
24279
- kind
24280
- charges {
24281
- subtotal
24282
- amountsByPeriod {
24283
- amount
24284
- startDate
24285
- }
24286
- amount
24287
- billingPeriod
24288
- currencyId
24289
- feature {
24290
- unitName
24291
- }
24292
- id
24293
- name
24294
- priceListCharge {
24295
- id
24296
- }
24297
- priceList {
24298
- id
24299
- }
24300
- coupon {
24301
- couponCode
24302
- }
24303
- quantity
24304
- kind
24305
- }
24306
- priceList {
24307
- id
24308
- plan {
24309
- name
24310
- }
24311
- product {
24312
- name
24313
- }
24314
- }
24315
- }
24316
- }
24317
- errors
24318
- }
24319
- }
24320
- `;
24321
- const quoteRecalculateTaxes$2 = async ({ quoteId, apiHost, token, }) => {
24322
- var _a, _b;
24323
- const vars = { id: quoteId };
24324
- const response = await gqlRequest({
24325
- query: QUOTE_RECALCULATE_TAXES,
24326
- token,
24327
- vars,
24328
- apiHost,
24329
- });
24330
- const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteRecalculateTaxes) === null || _a === void 0 ? void 0 : _a.errors;
24331
- if (errors)
24332
- throw errors;
24333
- return (_b = response.quoteRecalculateTaxes) === null || _b === void 0 ? void 0 : _b.quote;
24334
- };
24335
-
24336
- const { Text: Text$m } = antd.Typography;
24337
- const CheckoutSummary_PriceListFragment = t(`
24338
- fragment CheckoutSummary_PriceListFragment on PriceList {
24339
- product {
24340
- name
24341
- }
24342
- name
24343
- }
24344
- `);
24345
- function CheckoutSummary({ quote, className, onAddCoupon, onRemoveCoupon, isRemovingCoupon, priceList: maskedPriceList, isAddingCoupon, couponCode, setCouponCode, activeCouponsExist, }) {
24346
- var _a;
24347
- const priceList = readFragment(CheckoutSummary_PriceListFragment, maskedPriceList);
24348
- return (jsxRuntime.jsxs("div", { className: `${className} bunny-space-y-4`, children: [jsxRuntime.jsxs(Text$m, { 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: quote === null || quote === void 0 ? void 0 : quote.quoteChanges.map(quoteChange => quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.charges.map(charge => {
24349
- var _a;
24350
- const multiplier = charge.kind === 'COUPON' ? -1 : 1;
24351
- 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: () => {
24352
- var _a, _b;
24353
- if (isRemovingCoupon) {
24354
- return;
24355
- }
24356
- if (!((_a = charge.coupon) === null || _a === void 0 ? void 0 : _a.couponCode)) {
24357
- throw new Error('Coupon code not found');
24358
- }
24359
- onRemoveCoupon((_b = charge.coupon) === null || _b === void 0 ? void 0 : _b.couponCode);
24360
- }, 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));
24361
- })) }), 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) })] })] }), activeCouponsExist && (jsxRuntime.jsx(CouponEditor, { className: "bunny-w-full", onAddCoupon: onAddCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode }))] }));
24362
- }
24363
- const CheckoutSummaryDivider = () => {
24364
- return (jsxRuntime.jsx("div", { className: "bunny-my-2", children: jsxRuntime.jsx(antd.Divider, { className: "m-0" }) }));
24365
- };
24366
-
24367
- const SelfServiceBuyWarning_PriceListFragment = t(`
24368
- fragment SelfServiceBuyWarning_PriceListFragment on PriceList {
24369
- plan {
24370
- selfServiceBuy
24371
- }
24372
- }
24373
- `);
24374
- function SelfServiceBuyWarning({ priceList: maskedPriceList, onShowSelfServiceBuyWarning, }) {
24375
- const priceList = readFragment(SelfServiceBuyWarning_PriceListFragment, maskedPriceList);
24376
- const hasShownRef = react.useRef(false);
24377
- // Only show the warning when component is first mounted
24378
- react.useEffect(() => {
24379
- var _a;
24380
- if (!priceList || hasShownRef.current)
24381
- return;
24382
- if (((_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.selfServiceBuy) === false) {
24383
- hasShownRef.current = true;
24384
- onShowSelfServiceBuyWarning();
24385
- }
24386
- }, [priceList, onShowSelfServiceBuyWarning]);
24387
- return null;
24388
- }
24389
-
24390
- const { Text: Text$l } = antd.Typography;
24391
- const PriceListDisplay_PriceListFragment = t(`
24392
- fragment PriceListDisplay_PriceListFragment on PriceList {
24393
- product {
24394
- name
24395
- }
24396
- name
24397
- basePrice
24398
- currencyId
24399
- }
24400
- `);
24401
- function PriceListDisplay({ priceList: maskedPriceList }) {
24402
- var _a;
24403
- const priceList = readFragment(PriceListDisplay_PriceListFragment, maskedPriceList);
24404
- if (!priceList)
24405
- return null;
24406
- return (jsxRuntime.jsx("div", { className: "bunny-flex bunny-flex-col bunny-space-y-8", children: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2", children: [jsxRuntime.jsxs(Text$l, { className: "bunny-text-slate-500 bunny-font-bold bunny-text-lg", children: [(_a = priceList.product) === null || _a === void 0 ? void 0 : _a.name, " ", priceList.name] }), jsxRuntime.jsxs(Text$l, { className: "bunny-font-bold bunny-text-xl", children: [formatCurrency(priceList.basePrice, priceList.currencyId), " / month"] })] }) }));
24407
- }
24408
-
24409
- const Signup_PriceListFragment = t(`
24410
- fragment Signup_PriceListFragment on PriceList {
24411
- ...CheckoutSummary_PriceListFragment
24412
- ...PriceListDisplay_PriceListFragment
24413
- ...SelfServiceBuyWarning_PriceListFragment
24414
- plan {
24415
- selfServiceBuy
24416
- }
24417
- }
24418
- `, [
24419
- CheckoutSummary_PriceListFragment,
24420
- PriceListDisplay_PriceListFragment,
24421
- SelfServiceBuyWarning_PriceListFragment,
24422
- ]);
24423
-
24424
- const { Title, Text: Text$k } = antd.Typography;
24425
- function PaymentSuccessDisplay({ amountPaid, className, companyName, returnUrl, style, currencyId, }) {
24426
- return (jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-items-center bunny-justify-center bunny-h-full ${className}`, style: style, children: [jsxRuntime.jsx(icons.CheckCircleFilled, { style: { fontSize: '48px', color: 'rgb(52 211 153)' } }), jsxRuntime.jsxs(Title, { level: 3, className: "bunny-mt-2 bunny-m-0", children: ["Payment of ", formatCurrency(amountPaid, currencyId), " successful"] }), returnUrl && (jsxRuntime.jsxs(Text$k, { className: "bunny-text-slate-500 bunny-cursor-pointer bunny-underline", onClick: () => (window.location.href = returnUrl), children: ["Back to ", companyName] }))] }));
24427
- }
24428
-
24429
- const mutation$d = t(`
24430
- query PriceList($code: String!) {
24431
- priceList (code: $code) {
24432
- ...Signup_PriceListFragment
24433
- }
24434
- }
24435
- `, [Signup_PriceListFragment]);
24436
- const getPriceList = async ({ token, code, apiHost, }) => {
24437
- const response = await execute(mutation$d, { apiHost, token }, { code });
24438
- return response === null || response === void 0 ? void 0 : response.priceList;
24439
- };
24440
-
24441
- const showErrorNotification$1 = useErrorNotification();
24442
- const showSuccessNotification = useSuccessNotification();
24443
- const showInfoNotification$2 = useInfoNotification();
24444
- function Signup({ companyName, priceListCode, returnUrl, couponCode, className, shadow = 'shadow-md', style, defaultFirstName, defaultLastName, defaultEmail, defaultCompanyName, defaultBillingCountry, }) {
24445
- var _a, _b, _c, _d, _e;
24446
- // Hooks
24447
- const { apiHost } = react.useContext(BunnyContext);
24448
- const tokenFromContexts = useToken();
24449
- const isMobile = useIsMobile();
24450
- const { topNavImageUrl } = useBrand();
24451
- const defaultValues = react.useMemo(() => ({
24452
- firstName: defaultFirstName,
24453
- lastName: defaultLastName,
24454
- email: defaultEmail,
24455
- accountName: defaultCompanyName,
24456
- billingCountry: defaultBillingCountry,
24457
- }), [defaultFirstName, defaultLastName, defaultEmail, defaultCompanyName, defaultBillingCountry]);
24458
- const queryClient = reactQuery.useQueryClient();
24459
- const [initialQuote, setInitialQuote] = react.useState(undefined);
24460
- const [accountId, setAccountId] = react.useState(undefined);
24461
- const [portalSessionToken, setPortalSessionToken] = react.useState(undefined);
24462
- const token = portalSessionToken || tokenFromContexts;
24463
- const [purchaseSucceeded, setPurchaseSucceeded] = react.useState(false);
24464
- const defaultCouponAppliedRef = react.useRef(undefined);
24465
- const [couponEditorCouponCode, setCouponEditorCouponCode] = react.useState('');
24466
- const hasTaxPlugin = useHasTaxPlugin({
24467
- apiHost,
24468
- token,
24469
- });
24470
- const { mutate: recalculateTaxesMutation } = reactQuery.useMutation({
24471
- mutationFn: (quoteId) => {
24472
- return quoteRecalculateTaxes$2({ token, apiHost, quoteId });
24473
- },
24474
- onError: (error) => {
24475
- if (!error[0].message.includes('Ensure that you have a taxation plugin')) {
24476
- showErrorNotification$1(error.message);
24477
- }
24478
- },
24479
- onSuccess: (quote) => {
24480
- queryClient.setQueryData(['quote', initialQuote === null || initialQuote === void 0 ? void 0 : initialQuote.id], quote);
24481
- queryClient.invalidateQueries({
24482
- queryKey: ['quote', initialQuote === null || initialQuote === void 0 ? void 0 : initialQuote.id],
24483
- });
24484
- },
24485
- });
24486
- const { mutate: quoteAccountSignupMutate, isPending: isSigningUp } = reactQuery.useMutation({
24487
- mutationFn: (formData) => {
24488
- return quoteAccountSignup({
24489
- token,
24490
- apiHost,
24491
- priceListCode,
24492
- accountName: formData.accountName,
24493
- billingContact: {
24494
- firstName: formData.firstName,
24495
- lastName: formData.lastName,
24496
- email: formData.email,
24497
- },
24498
- billingDetails: {
24499
- billingCountry: formData.billingCountry,
24500
- // TODO: add these billing details back for Avalara and AFC taxation plugins.
24501
- // billingState: formData.billingState,
24502
- // billingCity: formData.billingCity,
24503
- // billingZip: formData.billingZip,
24504
- // billingStreet: formData.billingStreet,
24505
- // taxNumber: formData.taxNumber,
24506
- },
24507
- });
24508
- },
24509
- onSuccess: (data) => {
24510
- setAccountId(data.account.id);
24511
- setPortalSessionToken(data.portalSessionToken);
24512
- // We must invalidate the accountPaymentMethodsKey query in order to clear payment methods from the provided api token,
24513
- // to instead use paymentMethods from portalSessionToken.
24514
- queryClient.invalidateQueries({
24515
- queryKey: QueryKeyFactory.accountPaymentMethodsKey({
24516
- accountId,
24517
- token,
24518
- }),
24519
- });
24520
- setInitialQuote(data.quote);
24521
- handleRecalculateTaxes(data.quote.id);
24522
- },
24523
- onError: (error) => {
24524
- const errorMessage = error.response.errors[0].message;
24525
- if (errorMessage.includes("Address couldn't be validated")) {
24526
- showErrorNotification$1('Please enter a valid billing address');
24527
- }
24528
- else {
24529
- showErrorNotification$1(errorMessage);
24530
- }
24531
- },
24532
- });
24533
- // Queries
24534
- const { data: maskedPriceList, isLoading: isLoadingPriceList } = reactQuery.useQuery({
24535
- queryKey: ['priceList', priceListCode],
24536
- queryFn: () => getPriceList({ token, apiHost, code: priceListCode }),
24537
- });
24538
- const { data, isLoading: isLoadingQuote } = reactQuery.useQuery({
24539
- queryKey: ['quote', initialQuote === null || initialQuote === void 0 ? void 0 : initialQuote.id],
24540
- queryFn: () => {
24541
- if (!(initialQuote === null || initialQuote === void 0 ? void 0 : initialQuote.id)) {
24542
- throw new Error('Quote ID is required');
24543
- }
24544
- return getQuote$1({ token, apiHost, id: initialQuote === null || initialQuote === void 0 ? void 0 : initialQuote.id });
24545
- },
24546
- enabled: !!(initialQuote === null || initialQuote === void 0 ? void 0 : initialQuote.id),
23621
+ enabled: !!initialQuoteId,
24547
23622
  });
24548
23623
  const priceList = readFragment(Signup_PriceListFragment, maskedPriceList);
24549
- const quote = readFragment(QuoteContext_QuoteFragment, data || initialQuote);
24550
- const quoteChangeId = (_d = (_c = (_a = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _a === void 0 ? void 0 : _a[((_b = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _b === void 0 ? void 0 : _b.length) - 1]) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : undefined;
23624
+ const quote = readFragment(Signup_QuoteFragment, data || initialQuote);
23625
+ const quoteChangeId = (_e = (_d = (_b = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _b === void 0 ? void 0 : _b[((_c = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _c === void 0 ? void 0 : _c.length) - 1]) === null || _d === void 0 ? void 0 : _d.id) !== null && _e !== void 0 ? _e : undefined;
24551
23626
  // Derived state
24552
- const selfServiceBuyEnabled = (_e = priceList === null || priceList === void 0 ? void 0 : priceList.plan) === null || _e === void 0 ? void 0 : _e.selfServiceBuy;
23627
+ const selfServiceBuyEnabled = (_f = priceList === null || priceList === void 0 ? void 0 : priceList.plan) === null || _f === void 0 ? void 0 : _f.selfServiceBuy;
24553
23628
  const { addCoupon, removeCoupon, isAddingCoupon, isRemovingCoupon, activeCouponsExist } = useUpdateCoupons({
24554
23629
  apiHost,
24555
23630
  token,
@@ -24558,7 +23633,7 @@ function Signup({ companyName, priceListCode, returnUrl, couponCode, className,
24558
23633
  queryClient.invalidateQueries({
24559
23634
  queryKey: ['quote', quote === null || quote === void 0 ? void 0 : quote.id],
24560
23635
  });
24561
- showSuccessNotification('Coupon applied');
23636
+ showSuccessNotification$1('Coupon applied');
24562
23637
  handleRecalculateTaxes(quote === null || quote === void 0 ? void 0 : quote.id);
24563
23638
  setCouponEditorCouponCode('');
24564
23639
  },
@@ -24566,7 +23641,7 @@ function Signup({ companyName, priceListCode, returnUrl, couponCode, className,
24566
23641
  queryClient.invalidateQueries({
24567
23642
  queryKey: ['quote', quote === null || quote === void 0 ? void 0 : quote.id],
24568
23643
  });
24569
- showSuccessNotification('Coupon removed');
23644
+ showSuccessNotification$1('Coupon removed');
24570
23645
  handleRecalculateTaxes(quote === null || quote === void 0 ? void 0 : quote.id);
24571
23646
  },
24572
23647
  });
@@ -24588,17 +23663,19 @@ function Signup({ companyName, priceListCode, returnUrl, couponCode, className,
24588
23663
  setPurchaseSucceeded(true);
24589
23664
  }
24590
23665
  async function accountSignupFunction(pluginId, paymentMethodId) {
24591
- var _a;
24592
23666
  if (!portalSessionToken) {
24593
23667
  throw new Error('Portal session token is required');
24594
23668
  }
24595
23669
  if (!accountId) {
24596
23670
  throw new Error('Account ID is required');
24597
23671
  }
23672
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
23673
+ throw new Error('Quote ID is required');
23674
+ }
24598
23675
  return await accountSignup({
24599
23676
  token: portalSessionToken,
24600
23677
  apiHost,
24601
- quoteId: (_a = quote === null || quote === void 0 ? void 0 : quote.id) !== null && _a !== void 0 ? _a : undefined,
23678
+ quoteId: quote === null || quote === void 0 ? void 0 : quote.id,
24602
23679
  paymentMethodId,
24603
23680
  pluginId,
24604
23681
  priceListCode: priceListCode,
@@ -24611,7 +23688,7 @@ function Signup({ companyName, priceListCode, returnUrl, couponCode, className,
24611
23688
  return;
24612
23689
  }
24613
23690
  if (!quoteId) {
24614
- showErrorNotification$1('No quote ID found to recalculate taxes');
23691
+ showErrorNotification$2('No quote ID found to recalculate taxes');
24615
23692
  return;
24616
23693
  }
24617
23694
  recalculateTaxesMutation(quoteId);
@@ -24622,7 +23699,7 @@ function Signup({ companyName, priceListCode, returnUrl, couponCode, className,
24622
23699
  if (purchaseSucceeded) {
24623
23700
  return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: (quote === null || quote === void 0 ? void 0 : quote.currencyId) !== undefined ? (jsxRuntime.jsx("div", { className: "bunny-w-screen bunny-absolute bunny-top-0 bunny-left-0 bunny-flex bunny-items-start bunny-pt-[25vh]", children: jsxRuntime.jsx(PaymentSuccessDisplay, { amountPaid: (quote === null || quote === void 0 ? void 0 : quote.amountDue) || 0, className: "bunny-w-full", companyName: companyName, returnUrl: returnUrl, currencyId: quote === null || quote === void 0 ? void 0 : quote.currencyId }) })) : (jsxRuntime.jsx("div", { children: "No currency ID found from Quote" })) }));
24624
23701
  }
24625
- return (jsxRuntime.jsxs("div", { className: `bunny-flex ${isMobile ? 'bunny-flex-col' : 'bunny-flex-row'} bunny-h-screen bunny-w-screen bunny-absolute bunny-top-0 bunny-left-0 ${shadow} ${className}`, style: style, children: [jsxRuntime.jsx(SelfServiceBuyWarning, { priceList: priceList, onShowSelfServiceBuyWarning: handleShowSelfServiceBuyWarning }), jsxRuntime.jsx("div", { className: `bunny-flex bunny-items-center bunny-flex-col ${isMobile ? 'bunny-w-full bunny-h-1/2' : 'bunny-w-1/2 bunny-h-full'} bunny-justify-center`, children: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-items-start bunny-justify-between bunny-w-3/5 bunny-h-full bunny-gap-4 bunny-my-24", children: [jsxRuntime.jsx("div", { children: topNavImageUrl.length > 0 && (jsxRuntime.jsx("img", { alt: "Logo", src: topNavImageUrl, style: { width: 'auto', height: '28px' } })) }), data ? (jsxRuntime.jsx(CheckoutSummary, { quote: data, className: "bunny-h-full bunny-w-full", onAddCoupon: addCoupon, onRemoveCoupon: removeCoupon, isRemovingCoupon: isRemovingCoupon, priceList: priceList, isAddingCoupon: isAddingCoupon, couponCode: couponEditorCouponCode, setCouponCode: setCouponEditorCouponCode, activeCouponsExist: activeCouponsExist })) : (jsxRuntime.jsx("div", { className: "bunny-h-full", children: isLoadingPriceList ? (jsxRuntime.jsx(antd.Skeleton, { active: true })) : (jsxRuntime.jsx(PriceListDisplay, { priceList: priceList })) })), jsxRuntime.jsx(Footer, {})] }) }), jsxRuntime.jsx("div", { className: `bunny-flex bunny-flex-col ${isMobile ? 'bunny-w-full bunny-h-1/2 bunny-overflow-auto' : 'bunny-w-1/2 bunny-h-full'} bunny-items-center`, style: {
23702
+ return (jsxRuntime.jsxs("div", { className: `bunny-flex ${isMobile ? 'bunny-flex-col' : 'bunny-flex-row'} bunny-h-screen bunny-w-screen bunny-absolute bunny-top-0 bunny-left-0 ${shadow} ${className}`, style: style, children: [jsxRuntime.jsx(SelfServiceBuyWarning, { priceList: priceList, onShowSelfServiceBuyWarning: handleShowSelfServiceBuyWarning }), jsxRuntime.jsx("div", { className: `bunny-flex bunny-items-center bunny-flex-col ${isMobile ? 'bunny-w-full bunny-h-1/2' : 'bunny-w-1/2 bunny-h-full'} bunny-justify-center`, children: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-items-start bunny-justify-between bunny-w-3/5 bunny-h-full bunny-gap-4 bunny-my-24", children: [jsxRuntime.jsx("div", { children: topNavImageUrl.length > 0 && (jsxRuntime.jsx("img", { alt: "Logo", src: topNavImageUrl, style: { width: 'auto', height: '28px' } })) }), quote ? (jsxRuntime.jsx(CheckoutSummary, { quote: quote, className: "bunny-h-full bunny-w-full", onAddCoupon: addCoupon, onRemoveCoupon: removeCoupon, isRemovingCoupon: isRemovingCoupon, priceList: priceList, isAddingCoupon: isAddingCoupon, couponCode: couponEditorCouponCode, setCouponCode: setCouponEditorCouponCode, activeCouponsExist: activeCouponsExist })) : (jsxRuntime.jsx("div", { className: "bunny-h-full", children: isLoadingPriceList ? (jsxRuntime.jsx(antd.Skeleton, { active: true })) : (jsxRuntime.jsx(PriceListDisplay, { priceList: priceList })) })), jsxRuntime.jsx(Footer, {})] }) }), jsxRuntime.jsx("div", { className: `bunny-flex bunny-flex-col ${isMobile ? 'bunny-w-full bunny-h-1/2 bunny-overflow-auto' : 'bunny-w-1/2 bunny-h-full'} bunny-items-center`, style: {
24626
23703
  boxShadow: '-5px 0 20px 0 rgba(0, 0, 0, 0.05)',
24627
23704
  }, children: isLoadingPriceList ? (jsxRuntime.jsx(antd.Skeleton, { active: true, className: `bunny-flex bunny-flex-col bunny-w-3/5 bunny-mt-24` })) : (jsxRuntime.jsx("div", { className: `bunny-flex bunny-flex-col bunny-w-3/5 bunny-mt-24`, children: jsxRuntime.jsx(PaymentForms, { quote: quote, handlePaymentSuccess: handlePaymentSuccess, handleSubmit: handleSubmit, proceedingToPayment: isSigningUp || isLoadingQuote, accountId: accountId, overrideToken: portalSessionToken, customCheckoutFunction: accountSignupFunction, defaultValues: defaultValues }) })) })] }));
24628
23705
  }
@@ -24631,8 +23708,283 @@ const [ChangeUpgradingSubscriptionProvider, useChangeUpgradingSubscription] = cr
24631
23708
 
24632
23709
  const [SubscriptionCancelProvider, useSubscriptionCancel] = createValueContext();
24633
23710
 
23711
+ const [SubscriptionPropsProvider, useSubscriptionProps] = createValueContext();
23712
+
23713
+ const [UpgradingSubscriptionProvider, useUpgradingSubscription] = createValueContext();
23714
+
24634
23715
  const [UpgradingSubscriptionIdProvider, useUpgradingSubscriptionId] = createStateContext(initialValue => react.useState(initialValue));
24635
23716
 
23717
+ const QuoteFields_QuoteFragment = t(`
23718
+ fragment QuoteFields_QuoteFragment on Quote @_unmask {
23719
+ accountId
23720
+ amount
23721
+ amountDue
23722
+ smallUnitAmountDue
23723
+ currencyId
23724
+ id
23725
+ payableId
23726
+ periodAmount
23727
+ subtotal
23728
+ taxAmount
23729
+ startDate
23730
+ formattedQuote {
23731
+ html
23732
+ }
23733
+ amountsByPeriod {
23734
+ amount
23735
+ startDate
23736
+ }
23737
+ kind
23738
+ quoteChanges {
23739
+ currencyId
23740
+ id
23741
+ kind
23742
+ charges {
23743
+ subtotal
23744
+ amountsByPeriod {
23745
+ amount
23746
+ startDate
23747
+ }
23748
+ amount
23749
+ billingPeriod
23750
+ currencyId
23751
+ feature {
23752
+ unitName
23753
+ }
23754
+ id
23755
+ name
23756
+ priceListCharge {
23757
+ id
23758
+ }
23759
+ priceList {
23760
+ id
23761
+ }
23762
+ coupon {
23763
+ couponCode
23764
+ }
23765
+ quantity
23766
+ kind
23767
+ }
23768
+ priceList {
23769
+ id
23770
+ plan {
23771
+ name
23772
+ }
23773
+ product {
23774
+ name
23775
+ }
23776
+ }
23777
+ }
23778
+ }
23779
+ `);
23780
+
23781
+ const MUTATION$1 = `
23782
+ mutation accountUpdate(
23783
+ $id: ID!,
23784
+ $attributes: AccountAttributes!) {
23785
+ accountUpdate(
23786
+ id: $id,
23787
+ attributes: $attributes
23788
+ ) {
23789
+ account {
23790
+ id
23791
+ billingCountry
23792
+ billingState
23793
+ billingStreet
23794
+ billingCity
23795
+ billingZip
23796
+ name
23797
+ }
23798
+ errors
23799
+ }
23800
+ }
23801
+ `;
23802
+ const accountUpdate$1 = async ({ accountId, attributes, token, apiHost, }) => {
23803
+ var _a;
23804
+ const vars = { id: accountId, attributes };
23805
+ const response = await gqlRequest({
23806
+ query: MUTATION$1,
23807
+ token,
23808
+ vars,
23809
+ apiHost,
23810
+ });
23811
+ const errors = (_a = response === null || response === void 0 ? void 0 : response.accountUpdate) === null || _a === void 0 ? void 0 : _a.errors;
23812
+ if (errors)
23813
+ throw errors;
23814
+ return response.accountUpdate;
23815
+ };
23816
+
23817
+ const COUNTRIES_REQUIRING_STATE = ['US', 'CA'];
23818
+ const TaxationForm = ({ account, accountId }) => {
23819
+ // Hooks
23820
+ const queryClient = reactQuery.useQueryClient();
23821
+ const { apiHost } = react.useContext(BunnyContext);
23822
+ const token = useToken();
23823
+ const [form] = antd.Form.useForm();
23824
+ // Mutations
23825
+ const { mutate: updateAccount, isPending: isUpdatingAccount } = reactQuery.useMutation({
23826
+ mutationFn: async (changedFormData) => {
23827
+ const account = await accountUpdate$1({
23828
+ accountId,
23829
+ attributes: changedFormData,
23830
+ token,
23831
+ apiHost,
23832
+ });
23833
+ return account;
23834
+ },
23835
+ onSuccess: () => {
23836
+ queryClient.invalidateQueries({
23837
+ queryKey: ['getTaxationRequiredAccountFields', token],
23838
+ });
23839
+ },
23840
+ });
23841
+ return (jsxRuntime.jsxs(antd.Form, { className: "bunny-flex bunny-flex-col bunny-gap-4", form: form, initialValues: account, layout: "vertical", onFinish: updateAccount, children: [jsxRuntime.jsx(antd.Form.Item, { label: "Billing street", name: "billingStreet", children: jsxRuntime.jsx(antd.Input, { placeholder: "Street" }) }), jsxRuntime.jsx(antd.Form.Item, { label: "Billing city", name: "billingCity", children: jsxRuntime.jsx(antd.Input, { placeholder: "City" }) }), jsxRuntime.jsx(FormBillingState, {}), jsxRuntime.jsx(antd.Form.Item, { label: "Billing country", name: "billingCountry", rules: [{ required: true }], children: jsxRuntime.jsx(antd.Select, { options: COUNTRY_LIST, placeholder: "Select a country", showSearch: true, filterOption: (input, option) => {
23842
+ var _a, _b;
23843
+ return ((_a = option === null || option === void 0 ? void 0 : option.label) !== null && _a !== void 0 ? _a : '').toLowerCase().includes(input.toLowerCase()) ||
23844
+ ((_b = option === null || option === void 0 ? void 0 : option.value) !== null && _b !== void 0 ? _b : '').toLowerCase().includes(input.toLowerCase());
23845
+ } }) }), jsxRuntime.jsx(antd.Form.Item, { label: "Billing zip", name: "billingZip", children: jsxRuntime.jsx(antd.Input, { placeholder: "Zip" }) }), jsxRuntime.jsx(antd.Form.Item, { children: jsxRuntime.jsx(antd.Button, { className: "bunny-w-full", disabled: isUpdatingAccount, htmlType: "submit", type: "primary", children: "Submit" }) })] }));
23846
+ };
23847
+ const FormBillingState = () => {
23848
+ const billingCountry = antd.Form.useWatch('billingCountry');
23849
+ const billingStateRequired = COUNTRIES_REQUIRING_STATE.includes(billingCountry);
23850
+ return (jsxRuntime.jsx(antd.Form.Item, { label: "Billing state", name: "billingState", rules: [{ required: billingStateRequired }], children: jsxRuntime.jsx(antd.Input, { placeholder: "State" }) }));
23851
+ };
23852
+
23853
+ const [OnPaymentMethodSavedProvider, useOnPaymentMethodSaved] = createValueContext();
23854
+ // This provider is used in all components that may save a payment method
23855
+
23856
+ const [OnPaymentMethodRemovedProvider, useOnPaymentMethodRemoved] = createValueContext();
23857
+ // This provider is used in all components that may remove a payment method
23858
+
23859
+ const { Text: Text$m } = antd.Typography;
23860
+ // HACK: I have imported QuoteFields_QuoteFragment here as a hack to ensure I have all of the quote data needed for
23861
+ // the eventual children of this component.
23862
+ // Solution: Eventually all children of this component should be using query fragments to avoid this
23863
+ const QuoteCheckout_QuoteFragment = t(`
23864
+ fragment QuoteCheckout_QuoteFragment on Quote {
23865
+ id
23866
+ accountId
23867
+ amountDue
23868
+ amount
23869
+ quoteChanges {
23870
+ id
23871
+ charges {
23872
+ kind
23873
+ coupon {
23874
+ couponCode
23875
+ }
23876
+ }
23877
+ }
23878
+ ...QuoteFields_QuoteFragment
23879
+ ...shouldShowCouponEditor_QuoteFragment
23880
+ ...PaymentForm_QuoteFragment
23881
+ ...getQuoteAmountDue_QuoteFragment
23882
+ }
23883
+ `, [
23884
+ QuoteFields_QuoteFragment,
23885
+ shouldShowCouponEditor_QuoteFragment,
23886
+ PaymentForm_QuoteFragment,
23887
+ getQuoteAmountDue_QuoteFragment,
23888
+ ]);
23889
+ const QuoteCheckout_SubscriptionFragment = t(`
23890
+ fragment QuoteCheckout_SubscriptionFragment on Subscription {
23891
+ id
23892
+ ...shouldShowCouponEditor_SubscriptionFragment
23893
+ }
23894
+ `, [shouldShowCouponEditor_SubscriptionFragment]);
23895
+ const showSuccessNotification = useSuccessNotification();
23896
+ const QuoteCheckout = ({ account, onSuccess, onFail, quote: maskedQuote, taxationRequiredAccountFields, onRecalculateTaxes, }) => {
23897
+ var _a, _b, _c, _d, _e;
23898
+ const maskedUpgradingSubscription = useUpgradingSubscription();
23899
+ // Read fragments
23900
+ const quote = readFragment(QuoteCheckout_QuoteFragment, maskedQuote);
23901
+ const upgradingSubscription = readFragment(QuoteCheckout_SubscriptionFragment, maskedUpgradingSubscription);
23902
+ // Context
23903
+ const onPaymentMethodSaved = useOnPaymentMethodSaved();
23904
+ const onPaymentMethodRemoved = useOnPaymentMethodRemoved();
23905
+ const { apiHost } = react.useContext(BunnyContext);
23906
+ const token = useToken();
23907
+ const isMobile = useIsMobile();
23908
+ const [isSaving, setIsSaving] = react.useState(false);
23909
+ const paymentRequired = getQuoteAmountDue(quote) > 0;
23910
+ const queryClient = reactQuery.useQueryClient();
23911
+ const [couponCode, setCouponCode] = react.useState('');
23912
+ const { addCoupon, removeCoupon, isAddingCoupon, isRemovingCoupon, activeCouponsExist } = useUpdateCoupons({
23913
+ apiHost,
23914
+ token,
23915
+ quoteChangeId: (_d = (_c = (_a = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _a === void 0 ? void 0 : _a[((_b = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _b === void 0 ? void 0 : _b.length) - 1]) === null || _c === void 0 ? void 0 : _c.id) !== null && _d !== void 0 ? _d : undefined,
23916
+ onCouponAdded: () => {
23917
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id))
23918
+ throw new Error('Quote ID is required');
23919
+ queryClient.invalidateQueries({
23920
+ queryKey: QueryKeyFactory.createObjectKey({
23921
+ id: quote === null || quote === void 0 ? void 0 : quote.id,
23922
+ objectName: 'editingQuote',
23923
+ token,
23924
+ }),
23925
+ });
23926
+ showSuccessNotification('Coupon applied');
23927
+ onRecalculateTaxes();
23928
+ setCouponCode('');
23929
+ },
23930
+ onCouponRemoved: () => {
23931
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id))
23932
+ throw new Error('Quote ID is required');
23933
+ queryClient.invalidateQueries({
23934
+ queryKey: QueryKeyFactory.createObjectKey({
23935
+ id: quote === null || quote === void 0 ? void 0 : quote.id,
23936
+ objectName: 'editingQuote',
23937
+ token,
23938
+ }),
23939
+ });
23940
+ showSuccessNotification('Coupon removed');
23941
+ onRecalculateTaxes();
23942
+ },
23943
+ });
23944
+ const couponsOnQuote = (_e = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _e === void 0 ? void 0 : _e.flatMap(quoteChange => { var _a; return (_a = quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.charges) === null || _a === void 0 ? void 0 : _a.filter(charge => charge.kind === 'COUPON'); });
23945
+ const checkoutMutation = reactQuery.useMutation({
23946
+ mutationFn: async () => {
23947
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id))
23948
+ throw new Error('Quote ID is required');
23949
+ if (paymentRequired)
23950
+ throw new Error('Payment is required');
23951
+ return await checkout({ quoteId: quote.id, token, apiHost });
23952
+ },
23953
+ onSuccess,
23954
+ onError: onFail,
23955
+ });
23956
+ async function handleCheckoutNoPayment() {
23957
+ setIsSaving(true);
23958
+ checkoutMutation.mutate();
23959
+ setIsSaving(false);
23960
+ }
23961
+ if (taxationRequiredAccountFields)
23962
+ return (jsxRuntime.jsx(PaymentFormWrapper, { setMaxHeight: false, children: jsxRuntime.jsx(TaxationForm, { account: account, accountId: quote.accountId }) }));
23963
+ 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) }), (couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.length) === 0 ? (jsxRuntime.jsx(jsxRuntime.Fragment, { children: upgradingSubscription &&
23964
+ 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: () => {
23965
+ couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.forEach(couponCharge => {
23966
+ var _a;
23967
+ const couponCode = (_a = couponCharge === null || couponCharge === void 0 ? void 0 : couponCharge.coupon) === null || _a === void 0 ? void 0 : _a.couponCode;
23968
+ if (couponCode) {
23969
+ removeCoupon(couponCode);
23970
+ }
23971
+ });
23972
+ }, children: "Remove coupon(s)" }))] })) : (jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-2 bunny-px-4 ${isMobile ? 'bunny-shadow-padding-x' : ''}`, children: [jsxRuntime.jsx(antd.Button, { onClick: handleCheckoutNoPayment, type: "primary", children: isSaving ? 'Processing...' : 'Complete order' }), jsxRuntime.jsx(Text$m, { className: "bunny-text-xs bunny-text-slate-500", children: "No payment is required" })] })) }));
23973
+ };
23974
+ const PaymentFormWrapper = ({ children, setMaxHeight, className, }) => {
23975
+ const isMobile = useIsMobile();
23976
+ return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-w-full bunny-flex-col bunny-gap-6 ${isMobile ? 'bunny-shadow-padding-xb' : ''} ${className}`, style: {
23977
+ ...(isMobile
23978
+ ? setMaxHeight
23979
+ ? { maxHeight: '60vh' }
23980
+ : {}
23981
+ : {
23982
+ width: '100%',
23983
+ maxWidth: '400px',
23984
+ }),
23985
+ }, children: children }));
23986
+ };
23987
+
24636
23988
  const findParentSubscription_SubscriptionFragment = t(`
24637
23989
  fragment findParentSubscription_SubscriptionFragment on Subscription {
24638
23990
  id
@@ -24706,15 +24058,6 @@ const Card = ({ children, className, style, }) => {
24706
24058
  }, children: children }));
24707
24059
  };
24708
24060
 
24709
- const TAG_COLORS = {
24710
- ACTIVE: 'green',
24711
- TRIAL: 'blue',
24712
- CANCELED: 'red',
24713
- EXPIRED: 'gray',
24714
- TRIAL_EXPIRED: 'red',
24715
- PENDING: 'yellow',
24716
- };
24717
-
24718
24061
  const isSubscriptionNotActive = (subscriptionState) => {
24719
24062
  return ((subscriptionState === null || subscriptionState === void 0 ? void 0 : subscriptionState.toUpperCase()) === t.scalar('SubscriptionState', 'EXPIRED') ||
24720
24063
  (subscriptionState === null || subscriptionState === void 0 ? void 0 : subscriptionState.toUpperCase()) === t.scalar('SubscriptionState', 'CANCELED') ||
@@ -25088,7 +24431,7 @@ function SubscriptionStatusText({ subscription: maskedSubscription, }) {
25088
24431
  return `Ends on ${formatDate(endDate || trialEndDate)}`;
25089
24432
  }
25090
24433
 
25091
- const { Text: Text$j } = antd.Typography;
24434
+ const { Text: Text$l } = antd.Typography;
25092
24435
  const SubscriptionStatusAndActions_SubscriptionFragment = t(`
25093
24436
  fragment SubscriptionStatusAndActions_SubscriptionFragment on Subscription {
25094
24437
  id
@@ -25126,11 +24469,11 @@ function SubscriptionStatusAndActions({ subscription: maskedSubscription, }) {
25126
24469
  const cardActionsVisible = !isMobile;
25127
24470
  const showStatusSkeleton = arePriceListChangeOptionsLoading && cardActionsVisible;
25128
24471
  const showActionsSkeleton = arePriceListChangeOptionsLoading && !priceListChangeOptions;
25129
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [showStatusSkeleton ? (jsxRuntime.jsx(antd.Skeleton.Input, { active: true, size: "small", style: { width: 180 } })) : (jsxRuntime.jsx(Text$j, { className: "bunny-grow", children: jsxRuntime.jsx(SubscriptionStatusText, { subscription: subscription }) })), cardActionsVisible &&
24472
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [showStatusSkeleton ? (jsxRuntime.jsx(antd.Skeleton.Input, { active: true, size: "small", style: { width: 180 } })) : (jsxRuntime.jsx(Text$l, { className: "bunny-grow", children: jsxRuntime.jsx(SubscriptionStatusText, { subscription: subscription }) })), cardActionsVisible &&
25130
24473
  (showActionsSkeleton ? (jsxRuntime.jsx(antd.Skeleton.Button, { active: true, size: "default", style: { width: 100 } })) : (jsxRuntime.jsx(SubscriptionCardActions, { priceListChangeOptions: priceListChangeOptions, subscription: subscription, isPaymentMethodLoading: isPaymentMethodLoading })))] }));
25131
24474
  }
25132
24475
 
25133
- const { Text: Text$i } = antd.Typography;
24476
+ const { Text: Text$k } = antd.Typography;
25134
24477
  const SubscriptionCardHeader_SubscriptionFragment = t(`
25135
24478
  fragment SubscriptionCardHeader_SubscriptionFragment on Subscription {
25136
24479
  id
@@ -25168,10 +24511,10 @@ const SubscriptionCardHeader = ({ subscription: maskedSubscription, }) => {
25168
24511
  const isTrial = isSubscriptionTrial(subscription.state);
25169
24512
  return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center bunny-justify-between", style: {
25170
24513
  backgroundColor: darkMode ? 'var(--row-background-dark)' : '',
25171
- }, children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2", children: [((_a = subscription === null || subscription === void 0 ? void 0 : subscription.product) === null || _a === void 0 ? void 0 : _a.name) && (jsxRuntime.jsx(Text$i, { style: {
24514
+ }, children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2", children: [((_a = subscription === null || subscription === void 0 ? void 0 : subscription.product) === null || _a === void 0 ? void 0 : _a.name) && (jsxRuntime.jsx(Text$k, { style: {
25172
24515
  color: brandColor,
25173
24516
  ...subscriptionProductNameStyle,
25174
- }, children: subscription.product.name })), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-grow bunny-items-center bunny-gap-2", children: [((_b = subscription === null || subscription === void 0 ? void 0 : subscription.plan) === null || _b === void 0 ? void 0 : _b.name) && (jsxRuntime.jsx(Text$i, { className: "bunny-text-sm", children: subscription.plan.name })), jsxRuntime.jsxs(CustomizedTag, { color: TAG_COLORS[(_c = subscription.state) === null || _c === void 0 ? void 0 : _c.toUpperCase()], children: [lodashExports.capitalize(subscription.state.toLowerCase().replace(/_/g, ' ')), isTrial ? ` (${trialDaysLeft !== null && trialDaysLeft !== void 0 ? trialDaysLeft : 'N/A'} days left)` : ''] }), ((_d = subscription.priceList) === null || _d === void 0 ? void 0 : _d.deprecated) && (jsxRuntime.jsx(CustomizedTag, { color: LEGACY_SUBSCRIPTION_COLOR, children: "Legacy" }))] })] }), jsxRuntime.jsx("div", { className: "bunny-flex bunny-items-center bunny-gap-6", children: jsxRuntime.jsx(SubscriptionStatusAndActions, { subscription: subscription }) })] }));
24517
+ }, children: subscription.product.name })), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-grow bunny-items-center bunny-gap-2", children: [((_b = subscription === null || subscription === void 0 ? void 0 : subscription.plan) === null || _b === void 0 ? void 0 : _b.name) && (jsxRuntime.jsx(Text$k, { className: "bunny-text-sm", children: subscription.plan.name })), jsxRuntime.jsxs(CustomizedTag, { color: TAG_COLORS[(_c = subscription.state) === null || _c === void 0 ? void 0 : _c.toUpperCase()], children: [lodashExports.capitalize(subscription.state.toLowerCase().replace(/_/g, ' ')), isTrial ? ` (${trialDaysLeft !== null && trialDaysLeft !== void 0 ? trialDaysLeft : 'N/A'} days left)` : ''] }), ((_d = subscription.priceList) === null || _d === void 0 ? void 0 : _d.deprecated) && (jsxRuntime.jsx(CustomizedTag, { color: LEGACY_SUBSCRIPTION_COLOR, children: "Legacy" }))] })] }), jsxRuntime.jsx("div", { className: "bunny-flex bunny-items-center bunny-gap-6", children: jsxRuntime.jsx(SubscriptionStatusAndActions, { subscription: subscription }) })] }));
25175
24518
  };
25176
24519
 
25177
24520
  const filterSubscriptionCharges_SubscriptionChargeFragment = t(`
@@ -25224,11 +24567,37 @@ function sortSubscriptionCharges(charges) {
25224
24567
  return orderedCharges;
25225
24568
  }
25226
24569
 
25227
- const { Text: Text$h } = antd.Typography;
24570
+ const { Text: Text$j } = antd.Typography;
25228
24571
  const SubscriptionCardColumnHeaders = ({ columns, }) => {
25229
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: columns.map((subscriptionColumn, index) => (jsxRuntime.jsx(Text$h, { className: `bunny-text-slate-400 ${subscriptionColumn.className}`, children: subscriptionColumn.title }, index))) }));
24572
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: columns.map((subscriptionColumn, index) => (jsxRuntime.jsx(Text$j, { className: `bunny-text-slate-400 ${subscriptionColumn.className}`, children: subscriptionColumn.title }, index))) }));
25230
24573
  };
25231
24574
 
24575
+ var ChargeType;
24576
+ (function (ChargeType) {
24577
+ ChargeType["USAGE"] = "USAGE";
24578
+ ChargeType["ONE_TIME"] = "ONE_TIME";
24579
+ ChargeType["RECURRING"] = "RECURRING";
24580
+ })(ChargeType || (ChargeType = {}));
24581
+ var ChargeType$1 = ChargeType;
24582
+
24583
+ var QuoteChangeKind;
24584
+ (function (QuoteChangeKind) {
24585
+ QuoteChangeKind["ADJUSTMENT"] = "ADJUSTMENT";
24586
+ QuoteChangeKind["COUPON"] = "COUPON";
24587
+ QuoteChangeKind["CREDIT"] = "CREDIT";
24588
+ QuoteChangeKind["DISCOUNT"] = "DISCOUNT";
24589
+ QuoteChangeKind["FREE_PERIOD_DISCOUNT"] = "FREE_PERIOD_DISCOUNT";
24590
+ QuoteChangeKind["PRICE_UPDATE"] = "PRICE_UPDATE";
24591
+ QuoteChangeKind["QUANTITY_UPDATE"] = "QUANTITY_UPDATE";
24592
+ QuoteChangeKind["REINSTATE"] = "REINSTATE";
24593
+ QuoteChangeKind["RENEW"] = "RENEW";
24594
+ QuoteChangeKind["SUBSCRIBE"] = "SUBSCRIBE";
24595
+ QuoteChangeKind["UNSUBSCRIBE"] = "UNSUBSCRIBE";
24596
+ QuoteChangeKind["UPDATE"] = "UPDATE";
24597
+ QuoteChangeKind["ACTIVATE"] = "ACTIVATE";
24598
+ })(QuoteChangeKind || (QuoteChangeKind = {}));
24599
+ var QuoteChangeKind$1 = QuoteChangeKind;
24600
+
25232
24601
  var utc$2 = {exports: {}};
25233
24602
 
25234
24603
  var utc$1 = utc$2.exports;
@@ -25516,7 +24885,7 @@ const TieredDisplayDropdown = ({ pricingModel, charge: maskedCharge, currencyId,
25516
24885
  const nextRecord = priceTiers === null || priceTiers === void 0 ? void 0 : priceTiers[index + 1];
25517
24886
  const starts = record.starts;
25518
24887
  const ends = (nextRecord === null || nextRecord === void 0 ? void 0 : nextRecord.starts) ? nextRecord.starts - 1 : '+';
25519
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [formatNumber(starts, 0), typeof ends === 'number' ? formatNumber(ends, 0) : '+'] }));
24888
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [formatNumber(starts, 0), typeof ends === 'number' ? ' - ' : '', typeof ends === 'number' ? formatNumber(ends, 0) : '+'] }));
25520
24889
  },
25521
24890
  },
25522
24891
  {
@@ -25614,9 +24983,9 @@ const SubscriptionChargeUnitPrice = ({ charge: maskedCharge, currencyId, }) => {
25614
24983
  return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: hasPriceTiers(charge) ? (jsxRuntime.jsx(TieredDisplayDropdown, { pricingModel: charge.pricingModel, charge: charge, currencyId: currencyId, priceDecimals: (_c = charge.priceDecimals) !== null && _c !== void 0 ? _c : 0, truncatedText: `${charge.kind === 'PRICE_UPDATE' ? 'new ' : ''}${getApplicablePriceTier(charge, currencyId, (_d = charge.priceDecimals) !== null && _d !== void 0 ? _d : 0)}` })) : isChargeDiscount ? (`-${price}`) : (price) }));
25615
24984
  };
25616
24985
 
25617
- const { Text: Text$g } = antd.Typography;
24986
+ const { Text: Text$i } = antd.Typography;
25618
24987
  const SubscriptionsListCell = ({ children, className, gridColumn, right, style, }) => {
25619
- return (jsxRuntime.jsx(Text$g, { className: `bunny-flex bunny-items-center bunny-text-sm bunny-whitespace-nowrap ${className}`, style: {
24988
+ return (jsxRuntime.jsx(Text$i, { className: `bunny-flex bunny-items-center bunny-text-sm bunny-whitespace-nowrap ${className}`, style: {
25620
24989
  gridColumn,
25621
24990
  textAlign: right ? "right" : "left",
25622
24991
  justifyContent: right ? "flex-end" : "flex-start",
@@ -25788,9 +25157,9 @@ function AddonSubscriptionsCards({ subscriptions: maskedSubscriptions, subscript
25788
25157
  }) }));
25789
25158
  }
25790
25159
 
25791
- const { Text: Text$f } = antd.Typography;
25160
+ const { Text: Text$h } = antd.Typography;
25792
25161
  const SubscriptionCardCellMobile = ({ children, className, style, }) => {
25793
- return (jsxRuntime.jsx(Text$f, { className: className, style: style, children: children }));
25162
+ return (jsxRuntime.jsx(Text$h, { className: className, style: style, children: children }));
25794
25163
  };
25795
25164
 
25796
25165
  const SubscriptionCardMobile_SubscriptionFragment = t(`
@@ -25896,6 +25265,38 @@ const SubscriptionsList = ({ showInactive, subscriptions: maskedSubscriptions, }
25896
25265
  }) }));
25897
25266
  };
25898
25267
 
25268
+ const canSubscriptionUpgradeFromTrial_SubscriptionFragment = t(`
25269
+ fragment canSubscriptionUpgradeFromTrial_SubscriptionFragment on Subscription {
25270
+ state
25271
+ plan {
25272
+ selfServiceBuy
25273
+ }
25274
+ }
25275
+ `);
25276
+ const canSubscriptionUpgradeFromTrial = (maskedSubscription) => {
25277
+ var _a, _b;
25278
+ const subscription = readFragment(canSubscriptionUpgradeFromTrial_SubscriptionFragment, maskedSubscription);
25279
+ return ((((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL') &&
25280
+ ((_b = subscription.plan) === null || _b === void 0 ? void 0 : _b.selfServiceBuy)) ||
25281
+ false);
25282
+ };
25283
+
25284
+ const canSubscriptionUpgradeFromTrialExpired_SubscriptionFragment = t(`
25285
+ fragment canSubscriptionUpgradeFromTrialExpired_SubscriptionFragment on Subscription {
25286
+ state
25287
+ plan {
25288
+ selfServiceBuy
25289
+ }
25290
+ }
25291
+ `);
25292
+ const canSubscriptionUpgradeFromTrialExpired = (maskedSubscription) => {
25293
+ var _a, _b;
25294
+ const subscription = readFragment(canSubscriptionUpgradeFromTrialExpired_SubscriptionFragment, maskedSubscription);
25295
+ return ((((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED') &&
25296
+ ((_b = subscription.plan) === null || _b === void 0 ? void 0 : _b.selfServiceBuy)) ||
25297
+ false);
25298
+ };
25299
+
25899
25300
  const PriceListCardButton_PriceListFragment = t(`
25900
25301
  fragment PriceListCardButton_PriceListFragment on PriceList {
25901
25302
  id
@@ -25946,16 +25347,50 @@ const PriceListCardButton = ({ disableSelectCurrentPlan, isPriceListCurrentSubsc
25946
25347
  return (jsxRuntime.jsx("div", { className: "bunny-flex bunny-flex-col bunny-grow bunny-w-full bunny-gap-3", children: jsxRuntime.jsx(antd.Button, { className: "bunny-w-full", disabled: disableSelectCurrentPlan, type: isSelected ? 'primary' : 'default', children: createButtonText() }) }));
25947
25348
  };
25948
25349
 
25350
+ const periodMonthsConverter = (period) => {
25351
+ if (period === 0)
25352
+ return graphql.scalar('BillingPeriod', 'ONCE');
25353
+ else if (period === 1)
25354
+ return graphql.scalar('BillingPeriod', 'MONTHLY');
25355
+ else if (period === 3)
25356
+ return graphql.scalar('BillingPeriod', 'QUARTERLY');
25357
+ else if (period === 6)
25358
+ return graphql.scalar('BillingPeriod', 'SEMI_ANNUAL');
25359
+ else if (period === 12)
25360
+ return graphql.scalar('BillingPeriod', 'ANNUAL');
25361
+ else
25362
+ return null;
25363
+ };
25364
+ const billingPeriodConverter = (period) => {
25365
+ if (period === graphql.scalar('BillingPeriod', 'ONCE'))
25366
+ return 0;
25367
+ else if (period === graphql.scalar('BillingPeriod', 'MONTHLY'))
25368
+ return 1;
25369
+ else if (period === graphql.scalar('BillingPeriod', 'QUARTERLY'))
25370
+ return 3;
25371
+ else if (period === graphql.scalar('BillingPeriod', 'SEMI_ANNUAL'))
25372
+ return 6;
25373
+ else
25374
+ return 12;
25375
+ };
25376
+
25377
+ const QuoteContext = react.createContext({});
25378
+
25949
25379
  const BillingPeriodSelector = ({ availableBillingPeriods, onChangeBillingPeriod, products, selectedBillingPeriod, selectedProduct, onChangeProduct, }) => {
25950
25380
  const { secondaryColor, brandColor } = useBrand();
25951
25381
  const isMobile = useIsMobile();
25382
+ const { isInPreviewMode } = useSubscriptionProps();
25952
25383
  if (!availableBillingPeriods || (availableBillingPeriods === null || availableBillingPeriods === void 0 ? void 0 : availableBillingPeriods.length) < 2)
25953
25384
  return null;
25954
25385
  return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-8", children: [(products === null || products === void 0 ? void 0 : products.length) && products.length > 1 && (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2", children: [jsxRuntime.jsx("div", { className: "bunny-font-medium bunny-text-xs", style: {
25955
25386
  color: secondaryColor,
25956
25387
  }, children: "Select product" }), jsxRuntime.jsx(ProductRadioStyled, { brandColor: brandColor, children: jsxRuntime.jsx(antd.Radio.Group, { onChange: e => {
25388
+ if (isInPreviewMode)
25389
+ return;
25957
25390
  onChangeProduct(products === null || products === void 0 ? void 0 : products.find(product => product.id === e.target.value));
25958
25391
  }, value: selectedProduct === null || selectedProduct === void 0 ? void 0 : selectedProduct.id, buttonStyle: "solid", children: jsxRuntime.jsx(antd.Space, { className: "bunny-gap-2", children: products === null || products === void 0 ? void 0 : products.map(product => (jsxRuntime.jsx(antd.Radio.Button, { value: product.id, children: product.name }, product.id))) }) }) })] })), jsxRuntime.jsx("div", { className: "bunny-flex bunny-flex-col bunny-w-full bunny-gap-2", children: jsxRuntime.jsx(StyledRadioGroup, { className: "bunny-w-full", "$isMobile": isMobile, children: jsxRuntime.jsx(antd.Radio.Group, { onChange: e => {
25392
+ if (isInPreviewMode)
25393
+ return;
25959
25394
  onChangeBillingPeriod(e.target.value);
25960
25395
  }, value: selectedBillingPeriod, size: "small", buttonStyle: "solid", children: availableBillingPeriods === null || availableBillingPeriods === void 0 ? void 0 : availableBillingPeriods.map((periodMonth, index) => {
25961
25396
  return (jsxRuntime.jsx(antd.Radio.Button, { value: periodMonthsConverter(periodMonth), children: periodMonthsConverter(periodMonth) }, index));
@@ -25990,14 +25425,140 @@ const StyledRadioGroup = styled.div `
25990
25425
  > span {
25991
25426
  font-size: 11px !important;
25992
25427
  }
25993
- }
25994
- .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-checked) {
25995
- background: transparent !important;
25996
- }
25997
- .ant-radio-button-wrapper::before {
25998
- display: none !important;
25999
- }
26000
- `;
25428
+ }
25429
+ .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-checked) {
25430
+ background: transparent !important;
25431
+ }
25432
+ .ant-radio-button-wrapper::before {
25433
+ display: none !important;
25434
+ }
25435
+ `;
25436
+
25437
+ function getAddonsForBillingPeriod(billingPeriod, addonPlans) {
25438
+ const flattenedPriceLists = addonPlans.flatMap(addonPlan => addonPlan.priceLists);
25439
+ return flattenedPriceLists.filter(priceList => priceList.periodMonths === billingPeriodConverter(billingPeriod));
25440
+ }
25441
+
25442
+ const hasUnpurchasedAddonPriceLists_PlanFragment = t(`
25443
+ fragment hasUnpurchasedAddonPriceLists_PlanFragment on Plan {
25444
+ priceLists {
25445
+ id
25446
+ isVisible
25447
+ periodMonths
25448
+ }
25449
+ }
25450
+ `);
25451
+ function hasUnpurchasedAddonPriceLists(maskedPriceListAddonPlans, currentSubscription, billingPeriod) {
25452
+ // Read fragments
25453
+ const priceListAddonPlans = maskedPriceListAddonPlans.map(maskedAddonPlan => readFragment(hasUnpurchasedAddonPriceLists_PlanFragment, maskedAddonPlan));
25454
+ const addonPriceLists = getAddonsForBillingPeriod(billingPeriod, priceListAddonPlans).filter(priceList => priceList.isVisible);
25455
+ const unpurchasedAddonPriceLists = addonPriceLists === null || addonPriceLists === void 0 ? void 0 : addonPriceLists.filter(addonPriceList => {
25456
+ var _a;
25457
+ return !((_a = currentSubscription === null || currentSubscription === void 0 ? void 0 : currentSubscription.addonSubscriptions) === null || _a === void 0 ? void 0 : _a.some(addonSubscription => addonSubscription.priceList.id === addonPriceList.id));
25458
+ });
25459
+ return unpurchasedAddonPriceLists.length > 0;
25460
+ }
25461
+
25462
+ function hasUnpurchasedFeatureAddons(priceList, currentSubscription) {
25463
+ const featureAddons = priceList.charges.filter(charge => charge.featureAddon);
25464
+ const purchasedFeatureAddons = currentSubscription === null || currentSubscription === void 0 ? void 0 : currentSubscription.charges.filter(charge => { var _a; return (_a = charge.priceListCharge) === null || _a === void 0 ? void 0 : _a.featureAddon; });
25465
+ const unpurchasedFeatureAddons = featureAddons.filter(charge => !(purchasedFeatureAddons === null || purchasedFeatureAddons === void 0 ? void 0 : purchasedFeatureAddons.some(purchasedCharge => { var _a; return ((_a = purchasedCharge.priceListCharge) === null || _a === void 0 ? void 0 : _a.id) === charge.id; })));
25466
+ return unpurchasedFeatureAddons.length > 0;
25467
+ }
25468
+ function findQuoteChangeForFeatureAddon(quote) {
25469
+ return quote === null || quote === void 0 ? void 0 : quote.quoteChanges.find(qc => qc.kind === QuoteChangeKind$1.UPDATE ||
25470
+ qc.kind === QuoteChangeKind$1.SUBSCRIBE ||
25471
+ qc.kind === QuoteChangeKind$1.ACTIVATE);
25472
+ }
25473
+ function featureAddonInQuote(selectedPriceList, priceListCharge, quote) {
25474
+ var _a, _b, _c;
25475
+ const quoteChange = (_a = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _a === void 0 ? void 0 : _a.find(qc => { var _a; return ((_a = qc === null || qc === void 0 ? void 0 : qc.priceList) === null || _a === void 0 ? void 0 : _a.id) === selectedPriceList.id; });
25476
+ if (!quoteChange)
25477
+ return false;
25478
+ return (_c = (_b = quoteChange.charges) === null || _b === void 0 ? void 0 : _b.some(c => { var _a; return ((_a = c.priceListCharge) === null || _a === void 0 ? void 0 : _a.id) === priceListCharge.id; })) !== null && _c !== void 0 ? _c : false;
25479
+ }
25480
+ // ID Cucumber will use to find the feature addon switch
25481
+ function featureAddonSwitchTestId(addonName) {
25482
+ const name = addonName.toLowerCase().replace(/ /g, '-');
25483
+ return `feature-addon-switch-${name}`;
25484
+ }
25485
+
25486
+ const removeHTMLTagsRegex = /<br>(?=(?:\s*<[^>]*>)*$)|(<br>)|<[^>]*>/gi;
25487
+ // Description is a string that can contain HTML tags. We want to remove all HTML tags except <br> tags.
25488
+ const createPlanDescription = (planDescription) => {
25489
+ return (planDescription || '').replace(removeHTMLTagsRegex, (_, y) => (y ? ' & ' : ''));
25490
+ };
25491
+ const getActivePlanPriceData = (priceList, selectedPriceList) => {
25492
+ if (!priceList) {
25493
+ return;
25494
+ }
25495
+ // If a period option is selected, return the charge that matches the selected period option
25496
+ let activeBillingPLCharge;
25497
+ // Default to first price list charge
25498
+ let lowestPLCharge;
25499
+ // Find the lowest price list charge with a billing period that matches the selected period option
25500
+ if (priceList.id === (selectedPriceList === null || selectedPriceList === void 0 ? void 0 : selectedPriceList.id)) {
25501
+ activeBillingPLCharge = priceList.charges[0];
25502
+ }
25503
+ for (let j = 0; j < priceList.charges.length; j++) {
25504
+ const charge = priceList.charges[j];
25505
+ if (charge.chargeType === ChargeType$1.USAGE || charge.featureAddon === true)
25506
+ continue;
25507
+ if (activeBillingPLCharge) {
25508
+ // If we already found a charge with the same billing period check if this charge is lower
25509
+ if (charge.basePrice < activeBillingPLCharge.basePrice &&
25510
+ charge.billingPeriod === (activeBillingPLCharge === null || activeBillingPLCharge === void 0 ? void 0 : activeBillingPLCharge.billingPeriod)) {
25511
+ activeBillingPLCharge = charge;
25512
+ }
25513
+ }
25514
+ // If a period option is selected, only return the charge if it matches the selected period option
25515
+ else if (selectedPriceList &&
25516
+ charge.billingPeriod === periodMonthsConverter(selectedPriceList.periodMonths)) {
25517
+ activeBillingPLCharge = charge;
25518
+ }
25519
+ // Otherwise, return the lowest price list charge
25520
+ else if (charge.basePrice < ((lowestPLCharge === null || lowestPLCharge === void 0 ? void 0 : lowestPLCharge.basePrice) || -1)) {
25521
+ lowestPLCharge = charge;
25522
+ }
25523
+ }
25524
+ return {
25525
+ activeCharge: activeBillingPLCharge || lowestPLCharge,
25526
+ };
25527
+ };
25528
+ const showErrorNotification$1 = useErrorNotification();
25529
+ const isPriceListDisabled = ({ priceList, upgradingSubscription, }) => {
25530
+ const priceListAddonPlans = priceList === null || priceList === void 0 ? void 0 : priceList.plan.addonPlans;
25531
+ if (!priceListAddonPlans) {
25532
+ showErrorNotification$1('Price list addon plans are undefined');
25533
+ return false;
25534
+ }
25535
+ const canPurchaseFeatureAddons = hasUnpurchasedFeatureAddons(priceList, upgradingSubscription);
25536
+ const canPurchasePlanAddons = hasUnpurchasedAddonPriceLists(priceListAddonPlans, upgradingSubscription, periodMonthsConverter(priceList.periodMonths));
25537
+ const existingSubscriptionInTrial = upgradingSubscription && canSubscriptionUpgradeFromTrial(upgradingSubscription); // TODO: set type properly later
25538
+ const existingSubscriptionInTrialExpired = upgradingSubscription && canSubscriptionUpgradeFromTrialExpired(upgradingSubscription); // TODO: set type properly later
25539
+ const isUpgradingSubscriptionPriceList = (upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.id) === priceList.id;
25540
+ // When should priceList be disabled?
25541
+ // if upgradingSubscription?.priceList.id === priceList.id
25542
+ // AND the upgradingSubscription is not in trial
25543
+ // AND cannot purchase feature addons
25544
+ // AND cannot purchase add-on plans
25545
+ // AND selfServiceBuy is false
25546
+ // if upgradingSubscription?.priceList.id != priceList.id
25547
+ // AND upgradingSubscription is expired trial
25548
+ // AND priceList is not deprecated
25549
+ if (isUpgradingSubscriptionPriceList) {
25550
+ return (!existingSubscriptionInTrial &&
25551
+ !existingSubscriptionInTrialExpired &&
25552
+ !canPurchaseFeatureAddons &&
25553
+ !canPurchasePlanAddons);
25554
+ }
25555
+ else if (priceList === null || priceList === void 0 ? void 0 : priceList.deprecated) {
25556
+ return true;
25557
+ }
25558
+ else {
25559
+ return false;
25560
+ }
25561
+ };
26001
25562
 
26002
25563
  const NextPriceListButton = ({ availablePriceLists, priceListStart, setPriceListStart, numberOfPlansToDisplay, }) => {
26003
25564
  return (jsxRuntime.jsxs("div", { className: "bunny-absolute bunny-flex bunny-gap-1", style: { top: '12px', right: '8px' }, children: [priceListStart > 0 && (jsxRuntime.jsx("div", { className: "bunny-flex bunny-items-center bunny-justify-center bunny-rounded-full bunny-shadow bunny-p-1 bunny-cursor-pointer", onClick: () => {
@@ -26058,12 +25619,12 @@ function priceDescriptionString({ unitName, showPriceAsMonthly, periodMonths, pr
26058
25619
  return `Per ${unitName && !priceListHasFlatFeeCharges ? `${unitName.toLowerCase()} / ` : ''}${showPriceAsMonthly ? 'month' : periodLabel}`;
26059
25620
  }
26060
25621
 
26061
- const { Text: Text$e } = antd.Typography;
25622
+ const { Text: Text$g } = antd.Typography;
26062
25623
  const PriceTierPrice = ({ currencyId, priceDecimals, tier, }) => {
26063
- return (jsxRuntime.jsx(Text$e, { className: "bunny-text-white", children: formatCurrency(tier.price, currencyId, priceDecimals) }));
25624
+ return (jsxRuntime.jsx(Text$g, { className: "bunny-text-white", children: formatCurrency(tier.price, currencyId, priceDecimals) }));
26064
25625
  };
26065
25626
 
26066
- const { Text: Text$d } = antd.Typography;
25627
+ const { Text: Text$f } = antd.Typography;
26067
25628
  const PriceTierRow_PriceTierFragment = t(`
26068
25629
  fragment PriceTierRow_PriceTierFragment on PriceListChargeTier {
26069
25630
  starts
@@ -26078,10 +25639,10 @@ const PriceTierRow = ({ tier: maskedTier, nextTier: maskedNextTier, }) => {
26078
25639
  }
26079
25640
  return `${tier === null || tier === void 0 ? void 0 : tier.starts}+`;
26080
25641
  })();
26081
- return jsxRuntime.jsx(Text$d, { className: "bunny-text-white", children: text });
25642
+ return jsxRuntime.jsx(Text$f, { className: "bunny-text-white", children: text });
26082
25643
  };
26083
25644
 
26084
- const { Text: Text$c } = antd.Typography;
25645
+ const { Text: Text$e } = antd.Typography;
26085
25646
  const ChargePriceTiers_PriceListChargeFragment = t(`
26086
25647
  fragment ChargePriceTiers_PriceListChargeFragment on PriceListCharge {
26087
25648
  id
@@ -26098,7 +25659,7 @@ const ChargePriceTiers_PriceListChargeFragment = t(`
26098
25659
  const ChargePriceTiers = ({ charge: maskedCharge, currencyId, }) => {
26099
25660
  var _a;
26100
25661
  const charge = readFragment(ChargePriceTiers_PriceListChargeFragment, maskedCharge);
26101
- return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-1 bunny-w-full", children: [jsxRuntime.jsx(Text$c, { className: "bunny-text-white bunny-font-bold", children: charge.name }), jsxRuntime.jsxs(Text$c, { className: "bunny-flex bunny-flex-row bunny-text-gray-400 bunny-text-xs/3", children: [getPricingModelTitle(charge.pricingModel), " pricing -", ' ', getPricingModelDescription(charge.pricingModel)] }), jsxRuntime.jsx("div", { style: {
25662
+ return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-1 bunny-w-full", children: [jsxRuntime.jsx(Text$e, { className: "bunny-text-white bunny-font-bold", children: charge.name }), jsxRuntime.jsxs(Text$e, { className: "bunny-flex bunny-flex-row bunny-text-gray-400 bunny-text-xs/3", children: [getPricingModelTitle(charge.pricingModel), " pricing -", ' ', getPricingModelDescription(charge.pricingModel)] }), jsxRuntime.jsx("div", { style: {
26102
25663
  maxWidth: '150px',
26103
25664
  minWidth: '50%',
26104
25665
  gap: '0.1rem',
@@ -26249,7 +25810,7 @@ const hasMultipleRecurringCharges = (maskedPriceList) => {
26249
25810
  return (((_b = (_a = priceList.charges) === null || _a === void 0 ? void 0 : _a.filter(charge => charge.chargeType !== t.scalar('ChargeType', 'USAGE') && charge.featureAddon !== true).length) !== null && _b !== void 0 ? _b : 0) > 1);
26250
25811
  };
26251
25812
 
26252
- const { Text: Text$b } = antd.Typography;
25813
+ const { Text: Text$d } = antd.Typography;
26253
25814
  const MarkupWrapper = defaultStyled.div `
26254
25815
  padding: 0 !important;
26255
25816
  margin: 0 !important;
@@ -26284,7 +25845,7 @@ const PriceListCardPriceDescription = ({ feature, priceList: maskedPriceList, })
26284
25845
  const billingPeriodText = periodMonthsConverted
26285
25846
  ? BillingPeriodConverter$1[periodMonthsConverted]
26286
25847
  : 'undefined';
26287
- return (jsxRuntime.jsxs(Text$b, { className: "bunny-text-start bunny-text-gray-400 bunny-text-sm", children: [jsxRuntime.jsx("div", { children: ((_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.pricingDescription) && !isEmptyHtml(priceList.plan.pricingDescription) ? (jsxRuntime.jsx(MarkupWrapper, { children: jsxRuntime.jsx(interweave.Markup, { content: priceList.plan.pricingDescription }) })) : (priceDescriptionString({
25848
+ return (jsxRuntime.jsxs(Text$d, { className: "bunny-text-start bunny-text-gray-400 bunny-text-sm", children: [jsxRuntime.jsx("div", { children: ((_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.pricingDescription) && !isEmptyHtml(priceList.plan.pricingDescription) ? (jsxRuntime.jsx(MarkupWrapper, { children: jsxRuntime.jsx(interweave.Markup, { content: priceList.plan.pricingDescription }) })) : (priceDescriptionString({
26288
25849
  unitName: hasMultipleRecurringCharges(priceList) ? undefined : feature === null || feature === void 0 ? void 0 : feature.unitName,
26289
25850
  showPriceAsMonthly: priceList.showPriceAsMonthly,
26290
25851
  periodMonths: priceList.periodMonths,
@@ -26292,9 +25853,9 @@ const PriceListCardPriceDescription = ({ feature, priceList: maskedPriceList, })
26292
25853
  })) }), priceList.periodMonths && priceList.periodMonths > 1 && (jsxRuntime.jsxs("div", { children: ["Billed ", billingPeriodText] }))] }));
26293
25854
  };
26294
25855
 
26295
- const { Text: Text$a } = antd.Typography;
25856
+ const { Text: Text$c } = antd.Typography;
26296
25857
  const PriceListCardDescription = ({ description }) => {
26297
- return (jsxRuntime.jsx(Text$a, { className: "bunny-text-gray-400 bunny-text-sm", children: jsxRuntime.jsx(interweave.Markup, { content: description }) }));
25858
+ return (jsxRuntime.jsx(Text$c, { className: "bunny-text-gray-400 bunny-text-sm", children: jsxRuntime.jsx(interweave.Markup, { content: description }) }));
26298
25859
  };
26299
25860
 
26300
25861
  const GetPrice_PriceListFragment = t(`
@@ -26320,218 +25881,609 @@ const PriceListPriceText_PriceListFragment = t(`
26320
25881
  id
26321
25882
  pricingStyle
26322
25883
  }
26323
- currencyId
26324
- ...GetPrice_PriceListFragment
25884
+ currencyId
25885
+ ...GetPrice_PriceListFragment
25886
+ }
25887
+ `, [GetPrice_PriceListFragment]);
25888
+ function priceListPriceText({ priceList: maskedPriceList, }) {
25889
+ var _a, _b, _c;
25890
+ // Read fragments
25891
+ const priceList = readFragment(PriceListPriceText_PriceListFragment, maskedPriceList);
25892
+ const calculatePriceDecimals = () => {
25893
+ var _a, _b;
25894
+ if (((_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.pricingStyle) === t.scalar('PlanPricingStyles', 'PRICED')) {
25895
+ const decimalPart = (_b = getPrice(priceList)) === null || _b === void 0 ? void 0 : _b.toString().split('.')[1];
25896
+ if (!decimalPart)
25897
+ return 0;
25898
+ // If decimal part consists only of zeros, return 0
25899
+ if (parseInt(decimalPart) === 0) {
25900
+ return 0;
25901
+ }
25902
+ return undefined;
25903
+ }
25904
+ return 0;
25905
+ };
25906
+ const priceDecimals = calculatePriceDecimals();
25907
+ const price = !((_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.pricingStyle) ||
25908
+ ((_b = priceList.plan) === null || _b === void 0 ? void 0 : _b.pricingStyle) === t.scalar('PlanPricingStyles', 'PRICED')
25909
+ ? formatCurrency(getPrice(priceList), priceList.currencyId, priceDecimals)
25910
+ : ((_c = priceList.plan) === null || _c === void 0 ? void 0 : _c.pricingStyle) === t.scalar('PlanPricingStyles', 'CONTACT_US')
25911
+ ? 'Custom'
25912
+ : 'Free';
25913
+ return price;
25914
+ }
25915
+
25916
+ const { Text: Text$b } = antd.Typography;
25917
+ const PriceListCardPrice_PriceListFragment = t(`
25918
+ fragment PriceListCardPrice_PriceListFragment on PriceList {
25919
+ ...PriceListPriceText_PriceListFragment
25920
+ }
25921
+ `, [PriceListPriceText_PriceListFragment]);
25922
+ const PriceListCardPrice = ({ className, priceList: maskedPriceList, }) => {
25923
+ // Read fragments
25924
+ const priceList = readFragment(PriceListCardPrice_PriceListFragment, maskedPriceList);
25925
+ return (jsxRuntime.jsx(Text$b, { className: className ? className : 'bunny-font-medium bunny-text-3xl bunny-text-gray-900', children: priceListPriceText({ priceList }) }));
25926
+ };
25927
+
25928
+ const { Text: Text$a } = antd.Typography;
25929
+ const PriceListCardTitle = ({ planName, isPriceListCurrentSubscription, trialRemainingDays, }) => {
25930
+ const { brandColor } = useBrand();
25931
+ return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-4", children: [Boolean(trialRemainingDays) && (jsxRuntime.jsx("div", { className: "bunny-font-medium bunny-text-secondary", style: { height: '1rem' }, children: isPriceListCurrentSubscription
25932
+ ? `Trial ends in ${trialRemainingDays} day${trialRemainingDays === 1 ? '' : 's'}`
25933
+ : ' ' })), jsxRuntime.jsx(Text$a, { className: "bunny-font-medium bunny-text-xl bunny-text-left", style: { color: brandColor }, children: planName })] }));
25934
+ };
25935
+
25936
+ const PLAN_GRID_PADDING = 4;
25937
+ const PlanPickerGridCell = ({ children, noBorder, }) => {
25938
+ const isMobile = useIsMobile();
25939
+ return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col", style: isMobile
25940
+ ? {}
25941
+ : {
25942
+ ...(noBorder ? {} : { borderLeft: `1px solid ${SLATE_200}` }),
25943
+ }, children: [jsxRuntime.jsx("div", { className: "bunny-grow", children: children }), jsxRuntime.jsx("div", { className: "bunny-mt-4" })] }));
25944
+ };
25945
+
25946
+ const PriceListCardDesktop_PriceListFragment = t(`
25947
+ fragment PriceListCardDesktop_PriceListFragment on PriceList {
25948
+ id
25949
+ deprecated
25950
+ plan {
25951
+ id
25952
+ pricingStyle
25953
+ contactUsUrl
25954
+ name
25955
+ }
25956
+ charges {
25957
+ id
25958
+ featureAddon
25959
+ priceListChargeTiers {
25960
+ starts
25961
+ price
25962
+ }
25963
+ ...PricingTooltip_PriceListChargeFragment
25964
+ }
25965
+ currencyId
25966
+ ...PriceListCardButton_PriceListFragment
25967
+ ...PriceListHasPriceTiers_PriceListFragment
25968
+ ...PricingTooltip_PriceListFragment
25969
+ ...PriceListCardPrice_PriceListFragment
25970
+ ...PriceListCardPriceDescription_PriceListFragment
25971
+ }
25972
+ `, [
25973
+ PriceListCardButton_PriceListFragment,
25974
+ PricingTooltip_PriceListChargeFragment,
25975
+ PriceListHasPriceTiers_PriceListFragment,
25976
+ PricingTooltip_PriceListFragment,
25977
+ PriceListCardPrice_PriceListFragment,
25978
+ PriceListCardPriceDescription_PriceListFragment,
25979
+ ]);
25980
+ const PriceListCardDesktop = ({ hideButton, description, disableSelectCurrentPlan, feature, isPriceListCurrentSubscription, isSelected, priceList: maskedPriceList, subscriptionPlan, trialRemainingDays, noBorder, onClickPriceListCard, }) => {
25981
+ var _a, _b, _c, _d;
25982
+ // Context
25983
+ const { isInPreviewMode } = useSubscriptionProps();
25984
+ // Read fragments
25985
+ const priceList = readFragment(PriceListCardDesktop_PriceListFragment, maskedPriceList);
25986
+ return (jsxRuntime.jsx(PlanPickerGridCell, { noBorder: noBorder, children: jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-items-start bunny-justify-between bunny-w-full bunny-rounded-md bunny-gap-4 bunny-pt-4 bunny-px-4 ${disableSelectCurrentPlan ? '' : 'cursor-pointer'} bunny-box-border`, onClick: () => {
25987
+ var _a, _b, _c;
25988
+ if (isInPreviewMode)
25989
+ return;
25990
+ if (!disableSelectCurrentPlan) {
25991
+ if (((_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.pricingStyle) === t.scalar('PlanPricingStyles', 'CONTACT_US')) {
25992
+ window.open((_c = (_b = priceList.plan) === null || _b === void 0 ? void 0 : _b.contactUsUrl) !== null && _c !== void 0 ? _c : undefined, '_blank');
25993
+ }
25994
+ else {
25995
+ onClickPriceListCard === null || onClickPriceListCard === void 0 ? void 0 : onClickPriceListCard(priceList);
25996
+ }
25997
+ }
25998
+ }, style: {
25999
+ height: '100%',
26000
+ }, children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-8 bunny-h-full bunny-justify-between", children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-items-start bunny-gap-2", children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2 bunny-items-center", children: [jsxRuntime.jsx(PriceListCardTitle, { isPriceListCurrentSubscription: isPriceListCurrentSubscription, planName: (_b = (_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : 'undefined', trialRemainingDays: trialRemainingDays }), priceList.deprecated && jsxRuntime.jsx(CustomizedTag, { color: 'orange', children: "Legacy" })] }), jsxRuntime.jsx(PriceListCardDescription, { description: description })] }), jsxRuntime.jsxs("div", { style: {
26001
+ display: 'grid',
26002
+ gridTemplateRows: 'auto minmax(40px, auto)',
26003
+ alignItems: 'start',
26004
+ }, children: [jsxRuntime.jsx(PriceListCardPrice, { priceList: priceList }), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2 bunny-items-center", children: [jsxRuntime.jsx(PriceListCardPriceDescription, { feature: feature, priceList: priceList }), priceListHasPriceTiers(priceList) && (jsxRuntime.jsx(PricingTooltip, { priceListCharges: (_d = (_c = priceList.charges) === null || _c === void 0 ? void 0 : _c.filter(charge => charge.featureAddon !== true)) !== null && _d !== void 0 ? _d : [], currencyId: priceList.currencyId, priceList: priceList }))] })] })] }), !hideButton && (jsxRuntime.jsx(PriceListCardButton, { disableSelectCurrentPlan: disableSelectCurrentPlan, isPriceListCurrentSubscription: isPriceListCurrentSubscription, isSelected: isSelected, priceList: priceList, subscriptionPlan: subscriptionPlan }))] }) }));
26005
+ };
26006
+
26007
+ const CheckIcon = ({ backgroundColor, size, }) => {
26008
+ return (jsxRuntime.jsx("div", { className: "bunny-flex bunny-items-center bunny-justify-center bunny-rounded-full bunny-shrink-0", style: { width: size, height: size, backgroundColor }, children: jsxRuntime.jsx("svg", { width: "8", height: "6", viewBox: "0 0 8 6", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsxRuntime.jsx("path", { d: "M1.5 2.99992L3.16667 4.66659L6.5 1.33325", stroke: "white", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
26009
+ };
26010
+
26011
+ const PriceListCardMobile_PriceListFragment = t(`
26012
+ fragment PriceListCardMobile_PriceListFragment on PriceList {
26013
+ plan {
26014
+ name
26015
+ }
26016
+ ...PriceListCardPriceDescription_PriceListFragment
26017
+ ...PriceListCardButton_PriceListFragment
26018
+ ...PriceListCardPrice_PriceListFragment
26019
+ ...PriceListCardButton_PriceListFragment
26020
+ }
26021
+ `, [
26022
+ PriceListCardPriceDescription_PriceListFragment,
26023
+ PriceListCardButton_PriceListFragment,
26024
+ PriceListCardPrice_PriceListFragment,
26025
+ PriceListCardButton_PriceListFragment,
26026
+ ]);
26027
+ const PriceListCardMobile = ({ description, feature, isPriceListCurrentSubscription, isSelected, priceList: maskedPriceList, subscriptionPlan, trialRemainingDays, disableOnClickPriceListCard, onClickPriceListCard, }) => {
26028
+ var _a, _b;
26029
+ // Context
26030
+ const { brandColor } = useBrand();
26031
+ const { isInPreviewMode } = useSubscriptionProps();
26032
+ // Read fragments
26033
+ const priceList = readFragment(PriceListCardMobile_PriceListFragment, maskedPriceList);
26034
+ return (jsxRuntime.jsxs("div", { className: `bunny-relative bunny-flex bunny-flex-col bunny-border-2 bunny-border-solid bunny-rounded-lg bunny-p-4`, onClick: () => {
26035
+ if (isInPreviewMode)
26036
+ return;
26037
+ if (!disableOnClickPriceListCard)
26038
+ onClickPriceListCard === null || onClickPriceListCard === void 0 ? void 0 : onClickPriceListCard(priceList);
26039
+ }, style: {
26040
+ minWidth: '220px',
26041
+ borderColor: isSelected ? brandColor : SLATE_200,
26042
+ }, children: [isSelected && (jsxRuntime.jsx("div", { className: "bunny-absolute", style: {
26043
+ top: '10px',
26044
+ right: '10px',
26045
+ }, children: jsxRuntime.jsx(CheckIcon, { backgroundColor: brandColor, size: "20px" }) })), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-items-center bunny-grow bunny-gap-2", children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-items-center bunny-gap-2", children: [jsxRuntime.jsx(PriceListCardTitle, { isPriceListCurrentSubscription: isPriceListCurrentSubscription, planName: (_b = (_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : 'undefined', trialRemainingDays: trialRemainingDays }), jsxRuntime.jsx(PriceListCardDescription, { description: description })] }), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-items-center bunny-gap-2", children: [jsxRuntime.jsx(PriceListCardPrice, { priceList: priceList }), jsxRuntime.jsx(PriceListCardPriceDescription, { feature: feature, priceList: priceList })] }), jsxRuntime.jsx(PriceListCardButton, { disableSelectCurrentPlan: disableOnClickPriceListCard, isPriceListCurrentSubscription: isPriceListCurrentSubscription, isSelected: isSelected, priceList: priceList, subscriptionPlan: subscriptionPlan })] })] }));
26046
+ };
26047
+
26048
+ const PriceListCard_PriceListFragment = t(`
26049
+ fragment PriceListCard_PriceListFragment on PriceList {
26050
+ id
26051
+ plan {
26052
+ description
26053
+ id
26054
+ }
26055
+ ...PriceListCardDesktop_PriceListFragment
26056
+ ...PriceListCardMobile_PriceListFragment
26057
+ }
26058
+ `, [PriceListCardDesktop_PriceListFragment, PriceListCardMobile_PriceListFragment]);
26059
+ const PriceListCard = ({ hideButton, isSelected, priceList: maskedPriceList, subscriptions, trialRemainingDays, noBorder, onClickPriceListCard, disableCurrentPlan, }) => {
26060
+ var _a, _b, _c, _d;
26061
+ const isMobile = useIsMobile();
26062
+ const upgradingSubscription = useUpgradingSubscription();
26063
+ // Read fragments
26064
+ const priceList = readFragment(PriceListCard_PriceListFragment, maskedPriceList);
26065
+ // Derived state
26066
+ const description = createPlanDescription((_b = (_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : '');
26067
+ // Get the active price list charge for this plan
26068
+ const activeCharge = (_c = getActivePlanPriceData(priceList, priceList)) === null || _c === void 0 ? void 0 : _c.activeCharge;
26069
+ // Is the price list the current price list for the upgradingSubscription
26070
+ const isPriceListCurrentSubscription = ((_d = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList) === null || _d === void 0 ? void 0 : _d.id) === priceList.id;
26071
+ const disableSelectCurrentPlan = disableCurrentPlan !== null && disableCurrentPlan !== void 0 ? disableCurrentPlan : isPriceListDisabled({
26072
+ priceList: priceList,
26073
+ upgradingSubscription: upgradingSubscription, // TODO: set type properly later
26074
+ });
26075
+ const subscriptionPlan = subscriptions === null || subscriptions === void 0 ? void 0 : subscriptions.find(subscription => {
26076
+ var _a, _b;
26077
+ return subscription.plan.id === ((_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.id) &&
26078
+ subscription.state !== t.scalar('SubscriptionState', 'CANCELED') &&
26079
+ subscription.state !== t.scalar('SubscriptionState', 'EXPIRED') &&
26080
+ ((_b = subscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED');
26081
+ });
26082
+ if (!activeCharge) {
26083
+ return null;
26084
+ }
26085
+ const { feature } = activeCharge;
26086
+ return isMobile ? (jsxRuntime.jsx(PriceListCardMobile, { description: description, feature: feature, isPriceListCurrentSubscription: isPriceListCurrentSubscription, isSelected: isSelected, priceList: priceList, trialRemainingDays: trialRemainingDays, subscriptionPlan: subscriptionPlan,
26087
+ // TODO: naming mismatch disableOnClickPriceListCard vs disableSelectCurrentPlan, maybe also functionality mismatch? (ignore for now, mobile won't ever show this currently)
26088
+ disableOnClickPriceListCard: disableSelectCurrentPlan, onClickPriceListCard: onClickPriceListCard })) : (jsxRuntime.jsx(PriceListCardDesktop, { hideButton: hideButton, description: description, disableSelectCurrentPlan: disableSelectCurrentPlan, feature: feature, isPriceListCurrentSubscription: isPriceListCurrentSubscription, isSelected: isSelected, priceList: priceList, trialRemainingDays: trialRemainingDays, subscriptionPlan: subscriptionPlan, noBorder: noBorder, onClickPriceListCard: onClickPriceListCard }));
26089
+ };
26090
+
26091
+ const useSetQuoteQueryData$1 = () => {
26092
+ const token = useToken();
26093
+ const queryClient = reactQuery.useQueryClient();
26094
+ const setQuoteQueryData = (quoteId, quote) => {
26095
+ queryClient.setQueryData(QueryKeyFactory.createObjectKey({
26096
+ id: quoteId,
26097
+ objectName: 'editingQuote',
26098
+ token,
26099
+ }), quote);
26100
+ };
26101
+ return { setQuoteQueryData };
26102
+ };
26103
+
26104
+ const CheckoutButton = ({ disabled, onClickCheckout, loading, tooltipText, }) => {
26105
+ const isMobile = useIsMobile();
26106
+ const TooltipWrapper = ({ children }) => {
26107
+ if (tooltipText) {
26108
+ return jsxRuntime.jsx(antd.Tooltip, { title: tooltipText, children: children });
26109
+ }
26110
+ return jsxRuntime.jsx("div", { children: children });
26111
+ };
26112
+ return (jsxRuntime.jsx(TooltipWrapper, { children: jsxRuntime.jsx(antd.Button, { className: isMobile ? 'w-full' : '', disabled: disabled, onClick: onClickCheckout, size: isMobile ? 'large' : 'middle', type: "primary", loading: loading, children: "Proceed to checkout" }) }));
26113
+ };
26114
+
26115
+ const CheckoutPrice_QuoteFragment = t(`
26116
+ fragment CheckoutPrice_QuoteFragment on Quote {
26117
+ periodAmount
26118
+ amountDue
26119
+ quoteChanges {
26120
+ charges {
26121
+ kind
26122
+ chargeType
26123
+ }
26124
+ }
26325
26125
  }
26326
- `, [GetPrice_PriceListFragment]);
26327
- function priceListPriceText({ priceList: maskedPriceList, }) {
26328
- var _a, _b, _c;
26126
+ `);
26127
+ // if there are any charges on the subscribe quote change
26128
+ const CheckoutPrice = ({ quote: maskedQuote, selectedPriceList, }) => {
26129
+ var _a, _b;
26329
26130
  // Read fragments
26330
- const priceList = readFragment(PriceListPriceText_PriceListFragment, maskedPriceList);
26331
- const calculatePriceDecimals = () => {
26332
- var _a, _b;
26333
- if (((_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.pricingStyle) === t.scalar('PlanPricingStyles', 'PRICED')) {
26334
- const decimalPart = (_b = getPrice(priceList)) === null || _b === void 0 ? void 0 : _b.toString().split('.')[1];
26335
- if (!decimalPart)
26336
- return 0;
26337
- // If decimal part consists only of zeros, return 0
26338
- if (parseInt(decimalPart) === 0) {
26339
- return 0;
26340
- }
26341
- return undefined;
26342
- }
26343
- return 0;
26344
- };
26345
- const priceDecimals = calculatePriceDecimals();
26346
- const price = !((_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.pricingStyle) ||
26347
- ((_b = priceList.plan) === null || _b === void 0 ? void 0 : _b.pricingStyle) === t.scalar('PlanPricingStyles', 'PRICED')
26348
- ? formatCurrency(getPrice(priceList), priceList.currencyId, priceDecimals)
26349
- : ((_c = priceList.plan) === null || _c === void 0 ? void 0 : _c.pricingStyle) === t.scalar('PlanPricingStyles', 'CONTACT_US')
26350
- ? 'Custom'
26351
- : 'Free';
26352
- return price;
26353
- }
26131
+ const quote = readFragment(CheckoutPrice_QuoteFragment, maskedQuote);
26132
+ // Hooks
26133
+ const isMobile = useIsMobile();
26134
+ const displayAmount = (_a = quote === null || quote === void 0 ? void 0 : quote.amountDue) !== null && _a !== void 0 ? _a : quote === null || quote === void 0 ? void 0 : quote.periodAmount; // amountDue might not be available, so we use periodAmount as a fallback
26135
+ const hasDisplayAmount = selectedPriceList && displayAmount !== undefined;
26136
+ const convertedPeriodMonths = periodMonthsConverter(selectedPriceList.periodMonths);
26137
+ const periodLabel = convertedPeriodMonths ? PERIOD_LABELS[convertedPeriodMonths] : 'undefined';
26138
+ const subscribingToUsageCharges = (_b = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _b === void 0 ? void 0 : _b.some(qc => qc.charges.some(c => c.kind === 'SUBSCRIBE' && c.chargeType === 'USAGE'));
26139
+ return (jsxRuntime.jsxs("div", { className: `bunny-font-medium ${isMobile ? 'bunny-text-2xl' : ''}`, children: [subscribingToUsageCharges ? 'Usage based pricing' : '', subscribingToUsageCharges && hasDisplayAmount ? ' + ' : '', hasDisplayAmount
26140
+ ? `${formatCurrency(displayAmount, selectedPriceList === null || selectedPriceList === void 0 ? void 0 : selectedPriceList.currencyId, undefined)} / ${periodLabel}`
26141
+ : ''] }));
26142
+ };
26354
26143
 
26355
26144
  const { Text: Text$9 } = antd.Typography;
26356
- const PriceListCardPrice_PriceListFragment = t(`
26357
- fragment PriceListCardPrice_PriceListFragment on PriceList {
26358
- ...PriceListPriceText_PriceListFragment
26145
+ const CheckoutBarSummarySection_QuoteFragment = t(`
26146
+ fragment CheckoutBarSummarySection_QuoteFragment on Quote {
26147
+ quoteChanges {
26148
+ charges {
26149
+ id
26150
+ }
26151
+ }
26152
+ ...CheckoutPrice_QuoteFragment
26359
26153
  }
26360
- `, [PriceListPriceText_PriceListFragment]);
26361
- const PriceListCardPrice = ({ className, priceList: maskedPriceList, }) => {
26362
- // Read fragments
26363
- const priceList = readFragment(PriceListCardPrice_PriceListFragment, maskedPriceList);
26364
- return (jsxRuntime.jsx(Text$9, { className: className ? className : 'bunny-font-medium bunny-text-3xl bunny-text-gray-900', children: priceListPriceText({ priceList }) }));
26154
+ `, [CheckoutPrice_QuoteFragment]);
26155
+ const CheckoutBarSummarySection = ({ selectedPriceList, onClickCheckout, }) => {
26156
+ var _a;
26157
+ // Context
26158
+ const { quote: maskedQuote, isQuotePending, isUpdatingQuote } = react.useContext(QuoteContext);
26159
+ const quote = readFragment(CheckoutBarSummarySection_QuoteFragment, maskedQuote);
26160
+ const { isInPreviewMode } = useSubscriptionProps();
26161
+ // Hooks
26162
+ const { paymentPlugins } = usePaymentPlugins(undefined);
26163
+ const isMobile = useIsMobile();
26164
+ const hasPaymentPlugins = Boolean(paymentPlugins === null || paymentPlugins === void 0 ? void 0 : paymentPlugins.length);
26165
+ const quoteHasCharges = Boolean((_a = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _a === void 0 ? void 0 : _a.some(qc => qc.charges.length > 0));
26166
+ const checkoutButtonDisabled = Boolean(!selectedPriceList || !quoteHasCharges || !hasPaymentPlugins || isInPreviewMode);
26167
+ return (jsxRuntime.jsxs(Text$9, { className: `bunny-flex bunny-items-center bunny-gap-4 ${isMobile ? 'bunny-flex-col' : ''}`, children: [quote && (jsxRuntime.jsxs("div", { className: `bunny-flex ${isMobile ? 'items-center justify-between w-full' : 'flex-col'}`, children: [jsxRuntime.jsx("div", { className: "bunny-text-slate-500 bunny-font-medium bunny-text-right", style: { fontSize: '11px' }, children: "TOTAL" }), jsxRuntime.jsx(CheckoutPrice, { quote: quote, selectedPriceList: selectedPriceList })] })), jsxRuntime.jsx(CheckoutButton, { disabled: checkoutButtonDisabled, onClickCheckout: onClickCheckout, loading: isQuotePending || isUpdatingQuote, tooltipText: isInPreviewMode
26168
+ ? 'Checkout is disabled in preview mode'
26169
+ : !hasPaymentPlugins
26170
+ ? 'Cannot checkout. No valid payment plugins found. Please contact your administrator.'
26171
+ : undefined })] }));
26365
26172
  };
26366
26173
 
26367
- const { Text: Text$8 } = antd.Typography;
26368
- const PriceListCardTitle = ({ planName, isPriceListCurrentSubscription, trialRemainingDays, }) => {
26369
- const { brandColor } = useBrand();
26370
- return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-4", children: [Boolean(trialRemainingDays) && (jsxRuntime.jsx("div", { className: "bunny-font-medium bunny-text-secondary", style: { height: '1rem' }, children: isPriceListCurrentSubscription
26371
- ? `Trial ends in ${trialRemainingDays} day${trialRemainingDays === 1 ? '' : 's'}`
26372
- : ' ' })), jsxRuntime.jsx(Text$8, { className: "bunny-font-medium bunny-text-xl bunny-text-left", style: { color: brandColor }, children: planName })] }));
26174
+ const accountQuery = (id) => `
26175
+ query account {
26176
+ account(id: ${id}) {
26177
+ billingCountry
26178
+ billingState
26179
+ billingStreet
26180
+ billingCity
26181
+ billingZip
26182
+ }
26183
+ }`;
26184
+ const getAccount$1 = async ({ id, apiHost, token, }) => {
26185
+ const response = await gqlRequest({
26186
+ query: accountQuery(id),
26187
+ token,
26188
+ apiHost,
26189
+ });
26190
+ return response === null || response === void 0 ? void 0 : response.account;
26373
26191
  };
26374
26192
 
26375
- const PLAN_GRID_PADDING = 4;
26376
- const PlanPickerGridCell = ({ children, noBorder, }) => {
26377
- const isMobile = useIsMobile();
26378
- return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col", style: isMobile
26379
- ? {}
26380
- : {
26381
- ...(noBorder ? {} : { borderLeft: `1px solid ${SLATE_200}` }),
26382
- }, children: [jsxRuntime.jsx("div", { className: "bunny-grow", children: children }), jsxRuntime.jsx("div", { className: "bunny-mt-4" })] }));
26193
+ const MUTATION = `{
26194
+ currentUser {
26195
+ taxationRequiredAccountFields
26196
+ }
26197
+ }`;
26198
+ const getTaxationRequiredAccountFields = async ({ apiHost, token, }) => {
26199
+ var _a, _b;
26200
+ const response = await gqlRequest({
26201
+ query: MUTATION,
26202
+ token,
26203
+ apiHost: apiHost,
26204
+ });
26205
+ return ((_b = (_a = response === null || response === void 0 ? void 0 : response.currentUser) === null || _a === void 0 ? void 0 : _a.taxationRequiredAccountFields) === null || _b === void 0 ? void 0 : _b.length) > 0
26206
+ ? response.currentUser.taxationRequiredAccountFields
26207
+ : null;
26383
26208
  };
26384
26209
 
26385
- const PriceListCardDesktop_PriceListFragment = t(`
26386
- fragment PriceListCardDesktop_PriceListFragment on PriceList {
26210
+ const Checkout_QuoteFragment = t(`
26211
+ fragment Checkout_QuoteFragment on Quote {
26387
26212
  id
26388
- deprecated
26389
- plan {
26390
- id
26391
- pricingStyle
26392
- contactUsUrl
26393
- name
26394
- }
26395
- charges {
26396
- id
26397
- featureAddon
26398
- priceListChargeTiers {
26399
- starts
26400
- price
26401
- }
26402
- ...PricingTooltip_PriceListChargeFragment
26213
+ accountId
26214
+ formattedQuote {
26215
+ html
26403
26216
  }
26404
- currencyId
26405
- ...PriceListCardButton_PriceListFragment
26406
- ...PriceListHasPriceTiers_PriceListFragment
26407
- ...PricingTooltip_PriceListFragment
26408
- ...PriceListCardPrice_PriceListFragment
26409
- ...PriceListCardPriceDescription_PriceListFragment
26217
+ ...QuoteCheckout_QuoteFragment
26410
26218
  }
26411
- `, [
26412
- PriceListCardButton_PriceListFragment,
26413
- PricingTooltip_PriceListChargeFragment,
26414
- PriceListHasPriceTiers_PriceListFragment,
26415
- PricingTooltip_PriceListFragment,
26416
- PriceListCardPrice_PriceListFragment,
26417
- PriceListCardPriceDescription_PriceListFragment,
26418
- ]);
26419
- const PriceListCardDesktop = ({ hideButton, description, disableSelectCurrentPlan, feature, isPriceListCurrentSubscription, isSelected, priceList: maskedPriceList, subscriptionPlan, trialRemainingDays, noBorder, onClickPriceListCard, }) => {
26420
- var _a, _b, _c, _d;
26219
+ `, [QuoteCheckout_QuoteFragment]);
26220
+ const Checkout = ({ onCancel, onSuccess, onFail, onRecalculateTaxes, invoice, open, quote: maskedQuote, isUpdatingQuote, }) => {
26221
+ var _a, _b, _c, _d, _e;
26222
+ const { apiHost } = react.useContext(BunnyContext);
26223
+ const isMobile = useIsMobile();
26224
+ const token = useToken();
26225
+ // Context
26226
+ const onPaymentMethodSaved = useOnPaymentMethodSaved();
26227
+ const onPaymentMethodRemoved = useOnPaymentMethodRemoved();
26421
26228
  // Read fragments
26422
- const priceList = readFragment(PriceListCardDesktop_PriceListFragment, maskedPriceList);
26423
- return (jsxRuntime.jsx(PlanPickerGridCell, { noBorder: noBorder, children: jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-items-start bunny-justify-between bunny-w-full bunny-rounded-md bunny-gap-4 bunny-pt-4 bunny-px-4 ${disableSelectCurrentPlan ? '' : 'cursor-pointer'} bunny-box-border`, onClick: () => {
26424
- var _a, _b, _c;
26425
- if (!disableSelectCurrentPlan) {
26426
- if (((_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.pricingStyle) === t.scalar('PlanPricingStyles', 'CONTACT_US')) {
26427
- window.open((_c = (_b = priceList.plan) === null || _b === void 0 ? void 0 : _b.contactUsUrl) !== null && _c !== void 0 ? _c : undefined, '_blank');
26428
- }
26429
- else {
26430
- onClickPriceListCard === null || onClickPriceListCard === void 0 ? void 0 : onClickPriceListCard(priceList);
26431
- }
26432
- }
26433
- }, style: {
26434
- height: '100%',
26435
- }, children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-8 bunny-h-full bunny-justify-between", children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-items-start bunny-gap-2", children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2 bunny-items-center", children: [jsxRuntime.jsx(PriceListCardTitle, { isPriceListCurrentSubscription: isPriceListCurrentSubscription, planName: (_b = (_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : 'undefined', trialRemainingDays: trialRemainingDays }), priceList.deprecated && jsxRuntime.jsx(CustomizedTag, { color: 'orange', children: "Legacy" })] }), jsxRuntime.jsx(PriceListCardDescription, { description: description })] }), jsxRuntime.jsxs("div", { style: {
26436
- display: 'grid',
26437
- gridTemplateRows: 'auto minmax(40px, auto)',
26438
- alignItems: 'start',
26439
- }, children: [jsxRuntime.jsx(PriceListCardPrice, { priceList: priceList }), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2 bunny-items-center", children: [jsxRuntime.jsx(PriceListCardPriceDescription, { feature: feature, priceList: priceList }), priceListHasPriceTiers(priceList) && (jsxRuntime.jsx(PricingTooltip, { priceListCharges: (_d = (_c = priceList.charges) === null || _c === void 0 ? void 0 : _c.filter(charge => charge.featureAddon !== true)) !== null && _d !== void 0 ? _d : [], currencyId: priceList.currencyId, priceList: priceList }))] })] })] }), !hideButton && (jsxRuntime.jsx(PriceListCardButton, { disableSelectCurrentPlan: disableSelectCurrentPlan, isPriceListCurrentSubscription: isPriceListCurrentSubscription, isSelected: isSelected, priceList: priceList, subscriptionPlan: subscriptionPlan }))] }) }));
26229
+ const quote = readFragment(Checkout_QuoteFragment, maskedQuote);
26230
+ const hasTaxPlugin = useHasTaxPlugin({
26231
+ apiHost,
26232
+ token,
26233
+ });
26234
+ // Queries
26235
+ const { data: taxationRequiredAccountFields, isLoading: isLoadingTaxationRequiredAccountFields } = reactQuery.useQuery({
26236
+ queryKey: ['getTaxationRequiredAccountFields', token],
26237
+ queryFn: () => getTaxationRequiredAccountFields({ apiHost, token }),
26238
+ enabled: Boolean(quote),
26239
+ staleTime: 0,
26240
+ });
26241
+ const { data: account, isLoading: isLoadingAccount } = reactQuery.useQuery({
26242
+ queryKey: ['account', quote === null || quote === void 0 ? void 0 : quote.accountId],
26243
+ queryFn: () => (quote === null || quote === void 0 ? void 0 : quote.accountId) && getAccount$1({ id: quote.accountId, apiHost, token }),
26244
+ enabled: Boolean(quote === null || quote === void 0 ? void 0 : quote.accountId) && ((taxationRequiredAccountFields === null || taxationRequiredAccountFields === void 0 ? void 0 : taxationRequiredAccountFields.length) || 0) > 0,
26245
+ });
26246
+ // Use onRecalculateTaxes callback because parents need to define recalculateTaxes to get and set the right quote data they need
26247
+ async function recalculateTaxes() {
26248
+ if (quote) {
26249
+ if (!quote.id)
26250
+ throw new Error('Quote ID is required');
26251
+ onRecalculateTaxes(quote.id);
26252
+ }
26253
+ return {};
26254
+ }
26255
+ const recalculateTaxesEnabled = Boolean(quote) &&
26256
+ open &&
26257
+ hasTaxPlugin &&
26258
+ !taxationRequiredAccountFields &&
26259
+ !isLoadingTaxationRequiredAccountFields &&
26260
+ !isUpdatingQuote;
26261
+ reactQuery.useQuery({
26262
+ queryKey: QueryKeyFactory.createQuoteTaxCalculateKey({
26263
+ id: (_a = quote === null || quote === void 0 ? void 0 : quote.id) !== null && _a !== void 0 ? _a : undefined,
26264
+ token,
26265
+ }),
26266
+ queryFn: recalculateTaxes,
26267
+ // Recalculate taxes if the quote is open, has a tax plugin, and the taxation required account fields are not required
26268
+ enabled: recalculateTaxesEnabled,
26269
+ staleTime: 0,
26270
+ });
26271
+ if (!open || isLoadingTaxationRequiredAccountFields || isLoadingAccount)
26272
+ return null;
26273
+ return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-flex-col bunny-fixed bunny-top-0 bunny-left-0 bunny-right-0 bunny-bottom-0 bunny-bg-slate-50
26274
+ bunny-overflow-auto bunny-height-full`, style: {
26275
+ zIndex: 1001,
26276
+ }, children: jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-grow bunny-pt-4 ${isMobile ? 'bunny-pb-4' : 'bunny-pb-8'} bunny-content-container`, children: [jsxRuntime.jsx("div", { className: "bunny-flex bunny-justify-end bunny-w-full bunny-pr-4", children: jsxRuntime.jsx(icons.CloseOutlined, { className: "bunny-text-base bunny-shadow-padding-xb", onClick: onCancel }) }), jsxRuntime.jsxs("div", { className: `bunny-flex bunny-justify-end bunny-pt-4 bunny-gap-4 ${isMobile ? 'bunny-flex-col' : 'bunny-shadow-padding-xb'}`, children: [((invoice === null || invoice === void 0 ? void 0 : invoice.html) || ((_b = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _b === void 0 ? void 0 : _b.html)) && (jsxRuntime.jsx(InvoiceQuoteView, { html: invoice ? invoice.html : (_d = (_c = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _c === void 0 ? void 0 : _c.html) !== null && _d !== void 0 ? _d : '' })), !isMobile && ((invoice === null || invoice === void 0 ? void 0 : invoice.html) || ((_e = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _e === void 0 ? void 0 : _e.html)) && (jsxRuntime.jsx(antd.Divider, { className: "bunny-h-full", type: "vertical" })), invoice ? (jsxRuntime.jsx("div", { className: "bunny-w-full bunny-pt-12", children: jsxRuntime.jsx(PaymentForm, { onPaymentSuccess: onSuccess, invoice: invoice, 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) }) })) : quote ? (jsxRuntime.jsx(QuoteCheckout, { account: account, onFail: error => {
26277
+ onFail(error);
26278
+ }, onSuccess: onSuccess, quote: quote, taxationRequiredAccountFields: taxationRequiredAccountFields, token: token, onRecalculateTaxes: async () => {
26279
+ if (recalculateTaxesEnabled) {
26280
+ await recalculateTaxes();
26281
+ }
26282
+ } })) : (jsxRuntime.jsx(PaymentForm, { onPaymentSuccess: onSuccess, 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) }))] }), jsxRuntime.jsx(Footer, { className: "bunny-px-12" })] }) }));
26440
26283
  };
26441
26284
 
26442
- const CheckIcon = ({ backgroundColor, size, }) => {
26443
- return (jsxRuntime.jsx("div", { className: "bunny-flex bunny-items-center bunny-justify-center bunny-rounded-full bunny-shrink-0", style: { width: size, height: size, backgroundColor }, children: jsxRuntime.jsx("svg", { width: "8", height: "6", viewBox: "0 0 8 6", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsxRuntime.jsx("path", { d: "M1.5 2.99992L3.16667 4.66659L6.5 1.33325", stroke: "white", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
26285
+ function canEditChargeQuantity(charge) {
26286
+ if (!charge)
26287
+ return false;
26288
+ if (charge.chargeType === graphql.scalar('ChargeType', 'USAGE'))
26289
+ return false;
26290
+ if (charge.pricingModel === graphql.scalar('PricingModel', 'FLAT'))
26291
+ return false;
26292
+ return true;
26293
+ }
26294
+
26295
+ const { Text: Text$8 } = antd.Typography;
26296
+ const CheckoutBarInput = ({ disabled, priceListCharge, quantity, onQuantityChanged, }) => {
26297
+ var _a;
26298
+ const [isTooltipOpen, setIsTooltipOpen] = react.useState(false);
26299
+ const isMobile = useIsMobile();
26300
+ react.useEffect(() => {
26301
+ setTimeout(() => {
26302
+ setIsTooltipOpen(true);
26303
+ }, 1000);
26304
+ setTimeout(() => {
26305
+ setIsTooltipOpen(false);
26306
+ }, 6000);
26307
+ }, []);
26308
+ return (jsxRuntime.jsxs(Text$8, { className: `bunny-flex bunny-items-center bunny-gap-2 ${isMobile ? 'bunny-justify-between' : ''}`, children: [jsxRuntime.jsx(QuantityLabel, { activeCharge: priceListCharge }), jsxRuntime.jsx(antd.Tooltip, { onOpenChange: setIsTooltipOpen, open: isTooltipOpen, title: "Change quantity here", styles: {
26309
+ body: {
26310
+ paddingTop: '0.75rem',
26311
+ paddingBottom: '0.75rem',
26312
+ },
26313
+ }, children: jsxRuntime.jsx(antd.Input, { id: `${(_a = priceListCharge.name) === null || _a === void 0 ? void 0 : _a.toLowerCase().replace(/ /g, '-')}-quantity-input`, className: isMobile ? 'text-right' : '', disabled: disabled, onChange: e => {
26314
+ onQuantityChanged(Number(e.target.value));
26315
+ }, min: priceListCharge === null || priceListCharge === void 0 ? void 0 : priceListCharge.quantityMin, max: priceListCharge === null || priceListCharge === void 0 ? void 0 : priceListCharge.quantityMax, style: { minWidth: '120px' }, type: "number", value: quantity, required: true }) })] }));
26316
+ };
26317
+ const QuantityLabel = ({ activeCharge }) => {
26318
+ const chargeName = activeCharge.name;
26319
+ return (jsxRuntime.jsx(Text$8, { className: "bunny-text-slate-500 bunny-font-medium bunny-text-nowrap", style: { fontSize: '11px' }, children: chargeName.toUpperCase() }));
26444
26320
  };
26445
26321
 
26446
- const PriceListCardMobile_PriceListFragment = t(`
26447
- fragment PriceListCardMobile_PriceListFragment on PriceList {
26448
- plan {
26449
- name
26322
+ const PlanPickerCheckoutBar_QuoteFragment = t(`
26323
+ fragment PlanPickerCheckoutBar_QuoteFragment on Quote {
26324
+ ...Checkout_QuoteFragment
26325
+ quoteChanges {
26326
+ priceList {
26327
+ id
26328
+ }
26329
+ charges {
26330
+ priceListCharge {
26331
+ id
26332
+ }
26333
+ }
26450
26334
  }
26451
- ...PriceListCardPriceDescription_PriceListFragment
26452
- ...PriceListCardButton_PriceListFragment
26453
- ...PriceListCardPrice_PriceListFragment
26454
- ...PriceListCardButton_PriceListFragment
26455
26335
  }
26456
- `, [
26457
- PriceListCardPriceDescription_PriceListFragment,
26458
- PriceListCardButton_PriceListFragment,
26459
- PriceListCardPrice_PriceListFragment,
26460
- PriceListCardButton_PriceListFragment,
26461
- ]);
26462
- const PriceListCardMobile = ({ description, feature, isPriceListCurrentSubscription, isSelected, priceList: maskedPriceList, subscriptionPlan, trialRemainingDays, disableOnClickPriceListCard, onClickPriceListCard, }) => {
26463
- var _a, _b;
26336
+ `, [Checkout_QuoteFragment]);
26337
+ const PlanPickerCheckoutBar = ({ selectedPriceList, handlePortalErrors, onCheckoutSuccess, }) => {
26464
26338
  // Context
26465
- const { brandColor } = useBrand();
26339
+ const { shadow, isInPreviewMode } = useSubscriptionProps();
26340
+ const { quote: maskedQuote, onChangeQuantity, getFeatureQuantity, onRecalculateTaxes, isFeatureAddonsLoading, isUpdatingQuote, } = react.useContext(QuoteContext);
26466
26341
  // Read fragments
26467
- const priceList = readFragment(PriceListCardMobile_PriceListFragment, maskedPriceList);
26468
- return (jsxRuntime.jsxs("div", { className: `bunny-relative bunny-flex bunny-flex-col bunny-border-2 bunny-border-solid bunny-rounded-lg bunny-p-4`, onClick: () => {
26469
- if (!disableOnClickPriceListCard)
26470
- onClickPriceListCard === null || onClickPriceListCard === void 0 ? void 0 : onClickPriceListCard(priceList);
26471
- }, style: {
26472
- minWidth: '220px',
26473
- borderColor: isSelected ? brandColor : SLATE_200,
26474
- }, children: [isSelected && (jsxRuntime.jsx("div", { className: "bunny-absolute", style: {
26475
- top: '10px',
26476
- right: '10px',
26477
- }, children: jsxRuntime.jsx(CheckIcon, { backgroundColor: brandColor, size: "20px" }) })), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-items-center bunny-grow bunny-gap-2", children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-items-center bunny-gap-2", children: [jsxRuntime.jsx(PriceListCardTitle, { isPriceListCurrentSubscription: isPriceListCurrentSubscription, planName: (_b = (_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : 'undefined', trialRemainingDays: trialRemainingDays }), jsxRuntime.jsx(PriceListCardDescription, { description: description })] }), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-items-center bunny-gap-2", children: [jsxRuntime.jsx(PriceListCardPrice, { priceList: priceList }), jsxRuntime.jsx(PriceListCardPriceDescription, { feature: feature, priceList: priceList })] }), jsxRuntime.jsx(PriceListCardButton, { disableSelectCurrentPlan: disableOnClickPriceListCard, isPriceListCurrentSubscription: isPriceListCurrentSubscription, isSelected: isSelected, priceList: priceList, subscriptionPlan: subscriptionPlan })] })] }));
26342
+ const quote = readFragment(PlanPickerCheckoutBar_QuoteFragment, maskedQuote);
26343
+ // Local state
26344
+ const [payModalVisible, setPayModalVisible] = react.useState(false);
26345
+ // Hooks
26346
+ const token = useToken();
26347
+ const showSuccessNotification = useSuccessNotification();
26348
+ const queryClient = reactQuery.useQueryClient();
26349
+ const isMobile = useIsMobile();
26350
+ const handleCheckoutSuccess = () => {
26351
+ queryClient.refetchQueries({
26352
+ queryKey: QueryKeyFactory.createTableKey({
26353
+ pluralType: 'subscriptions',
26354
+ token,
26355
+ }),
26356
+ });
26357
+ queryClient.invalidateQueries({
26358
+ queryKey: QueryKeyFactory.createTableKey({
26359
+ pluralType: 'upgradeSubscriptions',
26360
+ token,
26361
+ }),
26362
+ });
26363
+ queryClient.invalidateQueries({
26364
+ queryKey: QueryKeyFactory.createTableKey({
26365
+ pluralType: 'hasActiveSubscriptions',
26366
+ token,
26367
+ }),
26368
+ });
26369
+ queryClient.invalidateQueries({
26370
+ queryKey: QueryKeyFactory.transactionsKey({ token }),
26371
+ });
26372
+ setPayModalVisible(false);
26373
+ showSuccessNotification('Your subscription has been created', 'Checkout successful');
26374
+ onCheckoutSuccess();
26375
+ };
26376
+ return (jsxRuntime.jsxs("div", { className: `bunny-flex ${isMobile ? 'bunny-flex-col bunny-gap-4' : 'bunny-flex-row'} bunny-my-4 bunny-p-4 bunny-justify-between bunny-bg-white bunny-rounded-md ${shadow ? `shadow-${shadow}` : ''}`, children: [jsxRuntime.jsx("div", { className: `${isMobile ? 'bunny-flex bunny-flex-col' : 'bunny-flex'} bunny-gap-4`, children: selectedPriceList === null || selectedPriceList === void 0 ? void 0 : selectedPriceList.charges.map((charge, index) => {
26377
+ var _a, _b, _c, _d;
26378
+ if (!canEditChargeQuantity({
26379
+ chargeType: (_a = charge.chargeType) !== null && _a !== void 0 ? _a : null,
26380
+ pricingModel: (_b = charge.pricingModel) !== null && _b !== void 0 ? _b : null,
26381
+ }))
26382
+ return null;
26383
+ if (!((_c = charge.feature) === null || _c === void 0 ? void 0 : _c.id))
26384
+ throw new Error('Charge feature is undefined');
26385
+ const isFeatureAddon = charge.featureAddon;
26386
+ const quantity = getFeatureQuantity((_d = charge.feature) === null || _d === void 0 ? void 0 : _d.id, charge.id);
26387
+ const maybeIsChargeLoading = isFeatureAddon && isFeatureAddonsLoading;
26388
+ if (!quantity)
26389
+ return null;
26390
+ // if charge is a feature addon, and a corresponding quote charge is not found in quote, return null
26391
+ if (isFeatureAddon && !featureAddonInQuote(selectedPriceList, charge, quote)) {
26392
+ return null;
26393
+ }
26394
+ const isDisabled = !quote || maybeIsChargeLoading || !selectedPriceList || !charge.selfServiceQuantity;
26395
+ return (jsxRuntime.jsx(CheckoutBarInput, { disabled: isDisabled, priceListCharge: charge, quantity: quantity, onQuantityChanged: quantity => {
26396
+ if (isInPreviewMode)
26397
+ return;
26398
+ onChangeQuantity(charge.id, quantity);
26399
+ } }, index));
26400
+ }) }), jsxRuntime.jsx(CheckoutBarSummarySection, { onClickCheckout: () => setPayModalVisible(true), selectedPriceList: selectedPriceList }), jsxRuntime.jsx(Checkout, { onCancel: () => setPayModalVisible(false), onFail: error => handlePortalErrors === null || handlePortalErrors === void 0 ? void 0 : handlePortalErrors(error), onSuccess: handleCheckoutSuccess, onRecalculateTaxes: onRecalculateTaxes, open: payModalVisible, quote: quote, token: token, isUpdatingQuote: isUpdatingQuote })] }));
26478
26401
  };
26479
26402
 
26480
- const PriceListCard_PriceListFragment = t(`
26481
- fragment PriceListCard_PriceListFragment on PriceList {
26403
+ const useQuoteUpdateFeatureAddon_QuoteFragment = t(`
26404
+ fragment useQuoteUpdateFeatureAddon_QuoteFragment on Quote {
26482
26405
  id
26483
- plan {
26484
- description
26406
+ startDate
26407
+ }
26408
+ `);
26409
+
26410
+ const FeatureAddonRow_QuoteFragment = t(`
26411
+ fragment FeatureAddonRow_QuoteFragment on Quote {
26412
+ ...useQuoteUpdateFeatureAddon_QuoteFragment
26413
+ }
26414
+ `, [useQuoteUpdateFeatureAddon_QuoteFragment]);
26415
+
26416
+ const useToggleAddonPlan_QuoteFragment = t(`
26417
+ fragment useToggleAddonPlan_QuoteFragment on Quote {
26418
+ quoteChanges {
26419
+ priceList {
26420
+ id
26421
+ }
26485
26422
  id
26486
26423
  }
26487
- ...PriceListCardDesktop_PriceListFragment
26488
- ...PriceListCardMobile_PriceListFragment
26424
+ id
26489
26425
  }
26490
- `, [PriceListCardDesktop_PriceListFragment, PriceListCardMobile_PriceListFragment]);
26491
- const PriceListCard = ({ hideButton, isSelected, priceList: maskedPriceList, subscriptions, trialRemainingDays, noBorder, onClickPriceListCard, disableCurrentPlan, }) => {
26492
- var _a, _b, _c, _d;
26493
- const isMobile = useIsMobile();
26494
- const upgradingSubscription = useUpgradingSubscription();
26495
- // Read fragments
26496
- const priceList = readFragment(PriceListCard_PriceListFragment, maskedPriceList);
26497
- // Derived state
26498
- const description = createPlanDescription((_b = (_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : '');
26499
- // Get the active price list charge for this plan
26500
- const activeCharge = (_c = getActivePlanPriceData(priceList, priceList)) === null || _c === void 0 ? void 0 : _c.activeCharge;
26501
- // Is the price list the current price list for the upgradingSubscription
26502
- const isPriceListCurrentSubscription = ((_d = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList) === null || _d === void 0 ? void 0 : _d.id) === priceList.id;
26503
- const disableSelectCurrentPlan = disableCurrentPlan !== null && disableCurrentPlan !== void 0 ? disableCurrentPlan : isPriceListDisabled({
26504
- priceList: priceList,
26505
- upgradingSubscription: upgradingSubscription, // TODO: set type properly later
26506
- });
26507
- const subscriptionPlan = subscriptions === null || subscriptions === void 0 ? void 0 : subscriptions.find(subscription => {
26508
- var _a, _b;
26509
- return subscription.plan.id === ((_a = priceList.plan) === null || _a === void 0 ? void 0 : _a.id) &&
26510
- subscription.state !== t.scalar('SubscriptionState', 'CANCELED') &&
26511
- subscription.state !== t.scalar('SubscriptionState', 'EXPIRED') &&
26512
- ((_b = subscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED');
26513
- });
26514
- if (!activeCharge) {
26515
- return null;
26426
+ `);
26427
+
26428
+ const AddonPlanRow_QuoteFragment = t(`
26429
+ fragment AddonPlanRow_QuoteFragment on Quote {
26430
+ ...useToggleAddonPlan_QuoteFragment
26516
26431
  }
26517
- const { feature } = activeCharge;
26518
- return isMobile ? (jsxRuntime.jsx(PriceListCardMobile, { description: description, feature: feature, isPriceListCurrentSubscription: isPriceListCurrentSubscription, isSelected: isSelected, priceList: priceList, trialRemainingDays: trialRemainingDays, subscriptionPlan: subscriptionPlan,
26519
- // TODO: naming mismatch disableOnClickPriceListCard vs disableSelectCurrentPlan, maybe also functionality mismatch? (ignore for now, mobile won't ever show this currently)
26520
- disableOnClickPriceListCard: disableSelectCurrentPlan, onClickPriceListCard: onClickPriceListCard })) : (jsxRuntime.jsx(PriceListCardDesktop, { hideButton: hideButton, description: description, disableSelectCurrentPlan: disableSelectCurrentPlan, feature: feature, isPriceListCurrentSubscription: isPriceListCurrentSubscription, isSelected: isSelected, priceList: priceList, trialRemainingDays: trialRemainingDays, subscriptionPlan: subscriptionPlan, noBorder: noBorder, onClickPriceListCard: onClickPriceListCard }));
26521
- };
26432
+ `, [useToggleAddonPlan_QuoteFragment]);
26522
26433
 
26523
- const useSetQuoteQueryData$1 = () => {
26524
- const token = useToken();
26525
- const queryClient = reactQuery.useQueryClient();
26526
- const setQuoteQueryData = (quoteId, quote) => {
26527
- queryClient.setQueryData(QueryKeyFactory.createObjectKey({
26528
- id: quoteId,
26529
- objectName: 'editingQuote',
26530
- token,
26531
- }), quote);
26532
- };
26533
- return { setQuoteQueryData };
26534
- };
26434
+ /**
26435
+ * Central quote fragment for QuoteProvider context.
26436
+ *
26437
+ * This fragment aggregates all child component fragments to ensure the QuoteProvider
26438
+ * fetches all required quote data upfront. When a component needs specific quote fields,
26439
+ * add its fragment here to maintain type safety and avoid over-fetching.
26440
+ *
26441
+ * Pattern: Fragment Composition
26442
+ * - Components define their data needs via fragments
26443
+ * - Provider composes these fragments into a single query
26444
+ * - Type safety ensures all required fields are fetched
26445
+ */
26446
+ const QuoteContext_QuoteFragment = t(`
26447
+ fragment QuoteContext_QuoteFragment on Quote {
26448
+ id
26449
+ currencyId
26450
+ amountDue
26451
+ startDate
26452
+ quoteChanges {
26453
+ id
26454
+ kind
26455
+ priceList {
26456
+ id
26457
+ }
26458
+ charges {
26459
+ priceListCharge {
26460
+ id
26461
+ chargeType
26462
+ pricingModel
26463
+ quantityMin
26464
+ quantityMax
26465
+ selfServiceQuantity
26466
+ }
26467
+ feature {
26468
+ id
26469
+ }
26470
+ quantity
26471
+ id
26472
+ }
26473
+ }
26474
+ ...PlanPickerCheckoutBar_QuoteFragment
26475
+ ...CheckoutBarSummarySection_QuoteFragment
26476
+ ...AddonPlanRow_QuoteFragment
26477
+ ...FeatureAddonRow_QuoteFragment
26478
+ ...PaymentForms_QuoteFragment
26479
+ }
26480
+ `, [
26481
+ PlanPickerCheckoutBar_QuoteFragment,
26482
+ CheckoutBarSummarySection_QuoteFragment,
26483
+ AddonPlanRow_QuoteFragment,
26484
+ FeatureAddonRow_QuoteFragment,
26485
+ PaymentForms_QuoteFragment,
26486
+ ]);
26535
26487
 
26536
26488
  const mutation$c = t(`
26537
26489
  mutation QuoteChargeDelete($quoteChargeId: ID!) {
@@ -27128,7 +27080,11 @@ function AddonPlanRow({ addonPriceList: maskedAddonPriceList, selectedPriceList,
27128
27080
  // Derived state
27129
27081
  const switchDisabled = isInPreviewMode || isPurchased;
27130
27082
  const hasCustomPrice = ((_b = addonPriceList.plan) === null || _b === void 0 ? void 0 : _b.pricingDescription) != null;
27131
- return (jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-row bunny-gap-2 bunny-justify-between bunny-items-center bunny-p-4 bunny-rounded-md bunny-bg-white ${shadow ? `shadow-${shadow}` : ''} bunny-mb-2`, children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2 bunny-items-center", children: [jsxRuntime.jsx("div", { className: `bunny-font-medium bunny-text-center bunny-text-orange-600`, children: (_c = addonPriceList.plan) === null || _c === void 0 ? void 0 : _c.name }), jsxRuntime.jsx(PriceListCardDescription, { description: (_e = (_d = addonPriceList.plan) === null || _d === void 0 ? void 0 : _d.description) !== null && _e !== void 0 ? _e : '' }), !hasCustomPrice && (jsxRuntime.jsx(PriceListCardPrice, { priceList: addonPriceList, className: "bunny-text-sm bunny-font-medium bunny-text-gray-900" })), jsxRuntime.jsx(PriceListCardPriceDescription, { feature: activeCharge === null || activeCharge === void 0 ? void 0 : activeCharge.feature, priceList: addonPriceList }), jsxRuntime.jsx(antd.Button, { type: "link", onClick: onClickSelect, children: jsxRuntime.jsx(icons.InfoCircleOutlined, {}) })] }), jsxRuntime.jsx(antd.Switch, { id: addonPlanSwitchTestId((_g = (_f = addonPriceList.plan) === null || _f === void 0 ? void 0 : _f.name) !== null && _g !== void 0 ? _g : ''), loading: isPending && !switchDisabled, checked: addedQuoteChange || isPurchased, onChange: (checked) => {
27083
+ return (jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-row bunny-gap-2 bunny-justify-between bunny-items-center bunny-p-4 bunny-rounded-md bunny-bg-white ${shadow ? `shadow-${shadow}` : ''} bunny-mb-2`, children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2 bunny-items-center", children: [jsxRuntime.jsx("div", { className: `bunny-font-medium bunny-text-center bunny-text-orange-600`, children: (_c = addonPriceList.plan) === null || _c === void 0 ? void 0 : _c.name }), jsxRuntime.jsx(PriceListCardDescription, { description: (_e = (_d = addonPriceList.plan) === null || _d === void 0 ? void 0 : _d.description) !== null && _e !== void 0 ? _e : '' }), !hasCustomPrice && (jsxRuntime.jsx(PriceListCardPrice, { priceList: addonPriceList, className: "bunny-text-sm bunny-font-medium bunny-text-gray-900" })), jsxRuntime.jsx(PriceListCardPriceDescription, { feature: activeCharge === null || activeCharge === void 0 ? void 0 : activeCharge.feature, priceList: addonPriceList }), jsxRuntime.jsx(antd.Button, { type: "link", onClick: () => {
27084
+ if (isInPreviewMode)
27085
+ return;
27086
+ onClickSelect();
27087
+ }, children: jsxRuntime.jsx(icons.InfoCircleOutlined, {}) })] }), jsxRuntime.jsx(antd.Switch, { id: addonPlanSwitchTestId((_g = (_f = addonPriceList.plan) === null || _f === void 0 ? void 0 : _f.name) !== null && _g !== void 0 ? _g : ''), loading: isPending && !switchDisabled, checked: addedQuoteChange || isPurchased, onChange: (checked) => {
27132
27088
  if (checked) {
27133
27089
  addAddonQuoteChange();
27134
27090
  }
@@ -29275,7 +29231,8 @@ const UpgradeWrapper = ({ onChangePlanCancel, handlePortalErrors, upgradingSubsc
29275
29231
  pluralType: 'upgradeSubscriptions',
29276
29232
  token,
29277
29233
  }),
29278
- queryFn: () => getSubscriptions({ isInPreviewMode, token, apiHost }),
29234
+ queryFn: () => getSubscriptions({ token, apiHost, isInPreviewMode }),
29235
+ enabled: !isInPreviewMode, // Don't query subscriptions in preview mode
29279
29236
  });
29280
29237
  // find upgrading subscription based on upgradingSubscriptionId
29281
29238
  const upgradingSubscription = (_b = (_a = subscriptionsData === null || subscriptionsData === void 0 ? void 0 : subscriptionsData.subscriptions) === null || _a === void 0 ? void 0 : _a.nodes) === null || _b === void 0 ? void 0 : _b.find(subscription => (subscription === null || subscription === void 0 ? void 0 : subscription.id) === upgradingSubscriptionId);
@@ -29338,7 +29295,8 @@ const SubscriptionsWrapper = ({ handlePortalErrors, companyName, isInPreviewMode
29338
29295
  pluralType: 'subscriptions',
29339
29296
  token,
29340
29297
  }),
29341
- queryFn: () => getSubscriptions$1({ token, apiHost }),
29298
+ queryFn: () => getSubscriptions$1({ token, apiHost, isInPreviewMode }),
29299
+ enabled: !isInPreviewMode, // Don't query subscriptions in preview mode
29342
29300
  });
29343
29301
  const subscriptions = (_b = (_a = subscriptionsData === null || subscriptionsData === void 0 ? void 0 : subscriptionsData.subscriptions) === null || _a === void 0 ? void 0 : _a.nodes) === null || _b === void 0 ? void 0 : _b.filter(subscription => subscription !== null);
29344
29302
  const defaultStyles = {