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