@bunnyapp/components 1.6.0-beta.10 → 1.6.0-beta.11

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 (39) hide show
  1. package/dist/cjs/index.js +816 -726
  2. package/dist/cjs/types/src/components/Checkout/Checkout.d.ts +18 -3
  3. package/dist/cjs/types/src/components/Checkout/QuoteCheckout.d.ts +77 -3
  4. package/dist/cjs/types/src/components/Checkout/checkoutUtils.d.ts +4 -2
  5. package/dist/cjs/types/src/components/QuoteProvider/fragments/quoteFragment.d.ts +65 -0
  6. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/QuantityChangeGridRow.d.ts +2 -3
  7. package/dist/cjs/types/src/components/Subscriptions/{QuantityDrawerContainer.d.ts → quantityChangeDrawer/QuantityDrawer.d.ts} +4 -4
  8. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/QuantityInput.d.ts +3 -11
  9. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/fragments/QuantityDrawerQuoteFragment.d.ts +10 -0
  10. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/hooks/useQuoteQueryData.d.ts +3 -0
  11. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/hooks/useSetQuoteQueryData.d.ts +5 -0
  12. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/queries/quoteChargeCreate.d.ts +23 -0
  13. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/queries/quoteChargeUpdate.d.ts +12 -0
  14. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/queries/quoteSubscriptionUpdate.d.ts +22 -0
  15. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/utils/formatDateForApi.d.ts +2 -0
  16. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/{utils.d.ts → utils/utils.d.ts} +0 -9
  17. package/dist/cjs/types/src/components/Subscriptions/subscriptionsList/SubscriptionsNavigation.d.ts +1 -1
  18. package/dist/cjs/types/src/components/TaxationForm.d.ts +3 -3
  19. package/dist/cjs/types/src/graphql/QuoteRequests.d.ts +0 -5
  20. package/dist/esm/index.js +816 -726
  21. package/dist/esm/types/src/components/Checkout/Checkout.d.ts +18 -3
  22. package/dist/esm/types/src/components/Checkout/QuoteCheckout.d.ts +77 -3
  23. package/dist/esm/types/src/components/Checkout/checkoutUtils.d.ts +4 -2
  24. package/dist/esm/types/src/components/QuoteProvider/fragments/quoteFragment.d.ts +65 -0
  25. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/QuantityChangeGridRow.d.ts +2 -3
  26. package/dist/esm/types/src/components/Subscriptions/{QuantityDrawerContainer.d.ts → quantityChangeDrawer/QuantityDrawer.d.ts} +4 -4
  27. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/QuantityInput.d.ts +3 -11
  28. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/fragments/QuantityDrawerQuoteFragment.d.ts +10 -0
  29. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/hooks/useQuoteQueryData.d.ts +3 -0
  30. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/hooks/useSetQuoteQueryData.d.ts +5 -0
  31. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/queries/quoteChargeCreate.d.ts +23 -0
  32. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/queries/quoteChargeUpdate.d.ts +12 -0
  33. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/queries/quoteSubscriptionUpdate.d.ts +22 -0
  34. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/utils/formatDateForApi.d.ts +2 -0
  35. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/{utils.d.ts → utils/utils.d.ts} +0 -9
  36. package/dist/esm/types/src/components/Subscriptions/subscriptionsList/SubscriptionsNavigation.d.ts +1 -1
  37. package/dist/esm/types/src/components/TaxationForm.d.ts +3 -3
  38. package/dist/esm/types/src/graphql/QuoteRequests.d.ts +0 -5
  39. package/package.json +1 -1
package/dist/cjs/index.js CHANGED
@@ -52,7 +52,7 @@ var css_248z = ":root {\n --row-background: #ffffff;\n --row-background-altern
52
52
  styleInject(css_248z);
53
53
 
54
54
  // This will be replaced at build time by rollup-plugin-replace
55
- const PACKAGE_VERSION = '1.6.0-beta.9';
55
+ const PACKAGE_VERSION = '1.6.0-beta.10';
56
56
  const createRequestHeaders = (token) => {
57
57
  const headers = createClientDevHeaders({ token });
58
58
  // Add the components version header
@@ -21693,814 +21693,791 @@ function Signup({ companyName, priceListCode, returnUrl, couponCode, className,
21693
21693
  }, children: isLoadingPriceList ? (jsxRuntime.jsx(antd.Skeleton, { active: true, className: `bunny-flex bunny-flex-col bunny-w-3/5 bunny-mt-24` })) : (jsxRuntime.jsx("div", { className: `bunny-flex bunny-flex-col bunny-w-3/5 bunny-mt-24`, children: jsxRuntime.jsx(PaymentForms, { quote: quote, handlePaymentSuccess: handlePaymentSuccess, handlePaymentFail: handlePaymentFail, handleSubmit: handleSubmit, proceedingToPayment: isSigningUp || isLoadingQuote, accountId: accountId, overrideToken: portalSessionToken, customCheckoutFunction: accountSignupFunction, defaultValues: defaultValues }) })) })] }));
21694
21694
  }
21695
21695
 
21696
+ const SubscriptionsContext = react.createContext({});
21697
+
21696
21698
  const { Text: Text$l } = antd.Typography;
21697
21699
  const DrawerHeader = ({ description, onClose, title, closeButtonClassName, }) => {
21698
21700
  return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-4", children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center bunny-justify-between bunny-gap-2", children: [jsxRuntime.jsx(Text$l, { className: "bunny-text-xl bunny-font-normal", children: title }), onClose ? (jsxRuntime.jsx("button", { id: "closePayment", onClick: onClose, className: closeButtonClassName, children: jsxRuntime.jsx(icons.CloseOutlined, {}) })) : null] }), description && jsxRuntime.jsx("div", { className: "bunny-text-sm bunny-font-medium", children: description })] }));
21699
21701
  };
21700
21702
 
21701
- const QUOTE_CHARGE_CREATE = `
21702
- ${QUOTE_FIELDS()}
21703
- mutation QuoteChargeCreate ($quoteChangeId: ID!, $startDate: ISO8601Date!, $endDate: ISO8601Date, $priceListChargeId: ID, $subscriptionChargeId: ID, $price: Float, $quantity: Int) {
21704
- quoteChargeCreate(
21705
- endDate: $endDate
21706
- price: $price
21707
- priceListChargeId: $priceListChargeId
21708
- quantity: $quantity
21709
- quoteChangeId: $quoteChangeId
21710
- startDate: $startDate
21711
- subscriptionChargeId: $subscriptionChargeId
21712
- ) {
21713
- quoteCharge {
21714
- quoteChange {
21715
- id
21716
- quoteId
21717
- quote {
21718
- ...QuoteFields
21719
- }
21720
- }
21721
- id
21722
- }
21703
+ const MUTATION$2 = `{
21704
+ currentUser {
21705
+ taxationRequiredAccountFields
21723
21706
  }
21724
- }
21725
-
21726
- `;
21727
- const quoteChargeCreate = async ({ price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId, token, apiHost, }) => {
21707
+ }`;
21708
+ const getTaxationRequiredAccountFields = async ({ apiHost, token, }) => {
21709
+ var _a, _b;
21728
21710
  const response = await gqlRequest({
21729
- query: QUOTE_CHARGE_CREATE,
21730
- vars: {
21731
- price,
21732
- priceListChargeId,
21733
- quantity,
21734
- quoteChangeId,
21735
- startDate,
21736
- subscriptionChargeId,
21737
- },
21738
- apiHost,
21711
+ query: MUTATION$2,
21739
21712
  token,
21713
+ apiHost: apiHost,
21740
21714
  });
21741
- if (response.errors) {
21742
- throw new Error(response.errors[0].message);
21743
- }
21744
- return response.quoteChargeCreate.quoteCharge;
21715
+ 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
21716
+ ? response.currentUser.taxationRequiredAccountFields
21717
+ : null;
21745
21718
  };
21746
21719
 
21747
- const quoteSubscriptionUpgrade = ({ subscriptionId, priceListId, apiHost, token, }) => {
21748
- return gqlRequest({
21749
- query: `mutation QuoteSubscriptionUpgrade($subscriptionId: ID!, $priceListId: ID!) {
21750
- quoteSubscriptionUpgrade(
21751
- subscriptionId: $subscriptionId
21752
- priceListId: $priceListId
21753
- ) {
21754
- quote {
21755
- id
21756
- }
21757
- }
21758
- }`,
21759
- vars: { subscriptionId, priceListId },
21720
+ const useHasTaxPlugin = ({ apiHost, token, }) => {
21721
+ const { data: plugins } = usePlugins({
21760
21722
  apiHost,
21761
21723
  token,
21762
21724
  });
21725
+ return Boolean(plugins === null || plugins === void 0 ? void 0 : plugins.some((plugin) => plugin.type === "taxation"));
21763
21726
  };
21764
- const useCreateSubscriptionQuote = () => {
21765
- const graphQLRequest = useGraphQLRequest();
21766
- return async (subscriptionIds, apiHost, token) => {
21767
- const data = await graphQLRequest(`
21768
- mutation quoteSubscriptionUpdate(
21769
- $subscriptionIds: [ID!]!,
21770
- ) {
21771
- quoteSubscriptionUpdate(
21772
- subscriptionIds: $subscriptionIds,
21727
+
21728
+ var SubscriptionState;
21729
+ (function (SubscriptionState) {
21730
+ SubscriptionState["ACTIVE"] = "ACTIVE";
21731
+ SubscriptionState["TRIAL"] = "TRIAL";
21732
+ SubscriptionState["PENDING"] = "PENDING";
21733
+ SubscriptionState["EXPIRED"] = "EXPIRED";
21734
+ SubscriptionState["CANCELED"] = "CANCELED";
21735
+ SubscriptionState["TRIAL_EXPIRED"] = "TRIAL_EXPIRED";
21736
+ })(SubscriptionState || (SubscriptionState = {}));
21737
+ var SubscriptionState$1 = SubscriptionState;
21738
+
21739
+ function shouldShowCouponEditor(quote, activeCouponsExist, upgradingSubscription) {
21740
+ var _a, _b;
21741
+ const upgradingFromTrial = ((_a = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === SubscriptionState$1.TRIAL ||
21742
+ ((_b = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === SubscriptionState$1.TRIAL_EXPIRED;
21743
+ function upgradingFromFree() {
21744
+ const totalPrice = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.charges.reduce((acc, charge) => acc + Number((charge === null || charge === void 0 ? void 0 : charge.discountedPrice) || 0), 0);
21745
+ return totalPrice === 0;
21746
+ }
21747
+ const quoteKindIsValid = quote.kind === common.QuoteChangeKind.SUBSCRIBE ||
21748
+ quote.kind === common.QuoteChangeKind.ADJUSTMENT ||
21749
+ quote.kind === common.QuoteChangeKind.ACTIVATE;
21750
+ if (quoteKindIsValid) {
21751
+ return activeCouponsExist && (upgradingFromTrial || upgradingFromFree());
21752
+ }
21753
+ return false;
21754
+ }
21755
+
21756
+ const MUTATION$1 = `
21757
+ mutation accountUpdate(
21758
+ $id: ID!,
21759
+ $attributes: AccountAttributes!) {
21760
+ accountUpdate(
21761
+ id: $id,
21762
+ attributes: $attributes
21773
21763
  ) {
21774
- quote {
21764
+ account {
21775
21765
  id
21776
- quoteChanges {
21777
- id
21778
- priceList {
21779
- id
21780
- }
21781
- subscription {
21782
- charges {
21783
- startDate
21784
- endDate
21785
- id
21786
- priceListCharge {
21787
- id
21788
- }
21789
- }
21790
- }
21791
- }
21792
- }
21793
- }
21794
- }
21795
- `, apiHost, token, {
21796
- subscriptionIds,
21797
- });
21798
- return data;
21799
- };
21800
- };
21801
- const useQuoteChangeUpdate = () => {
21802
- const graphQLRequest = useGraphQLRequest();
21803
- return async (charges, quoteChangeId, apiHost, token) => {
21804
- const response = await graphQLRequest(`mutation QuoteChangeUpdate($charges:[QuoteChargeAttributes!], $id:ID!) {
21805
- quoteChangeUpdate(id:$id, charges:$charges) {
21806
- quoteChange { id quoteId }
21807
- errors
21808
- }
21809
- }`, apiHost, token, { charges, id: quoteChangeId });
21810
- if (response.errors) {
21811
- throw new Error(response.errors[0].message);
21766
+ billingCountry
21767
+ billingState
21768
+ billingStreet
21769
+ billingCity
21770
+ billingZip
21771
+ name
21812
21772
  }
21813
- return response;
21814
- };
21815
- };
21816
- const quoteSubscriptionAddon = ({ subscriptionId, priceListId, apiHost, token, }) => {
21817
- return gqlRequest({
21818
- query: `mutation QuoteSubscriptionAddon($subscriptionId: ID!, $priceListId: ID) {
21819
- quoteSubscriptionAddon(subscriptionId: $subscriptionId, priceListId: $priceListId) {
21820
21773
  errors
21821
- quote {
21822
- id
21823
- }
21824
21774
  }
21825
- }`,
21826
- vars: {
21827
- subscriptionId,
21828
- priceListId,
21829
- },
21830
- apiHost,
21775
+ }
21776
+ `;
21777
+ const accountUpdate = async ({ accountId, attributes, token, apiHost, }) => {
21778
+ var _a;
21779
+ const vars = { id: accountId, attributes };
21780
+ const response = await gqlRequest({
21781
+ query: MUTATION$1,
21831
21782
  token,
21783
+ vars,
21784
+ apiHost,
21832
21785
  });
21786
+ const errors = (_a = response === null || response === void 0 ? void 0 : response.accountUpdate) === null || _a === void 0 ? void 0 : _a.errors;
21787
+ if (errors)
21788
+ throw errors;
21789
+ return response.accountUpdate;
21833
21790
  };
21834
- const quoteSubscriptionActivate = ({ subscriptionId, apiHost, token, }) => {
21835
- return gqlRequest({
21836
- query: `mutation QuoteSubscriptionActivate($subscriptionId: ID!) {
21837
- quoteSubscriptionActivate(subscriptionId: $subscriptionId) {
21838
- quote {
21839
- id
21840
- }
21841
- }
21842
- }`,
21843
- vars: {
21844
- subscriptionId,
21791
+
21792
+ const COUNTRIES_REQUIRING_STATE = ['US', 'CA'];
21793
+ const TaxationForm = ({ account, accountId }) => {
21794
+ // Hooks
21795
+ const queryClient = reactQuery.useQueryClient();
21796
+ const { apiHost } = react.useContext(BunnyContext);
21797
+ const token = useToken();
21798
+ const [form] = antd.Form.useForm();
21799
+ // Mutations
21800
+ const { mutate: updateAccount, isPending: isUpdatingAccount } = reactQuery.useMutation({
21801
+ mutationFn: async (changedFormData) => {
21802
+ const account = await accountUpdate({
21803
+ accountId,
21804
+ attributes: changedFormData,
21805
+ token,
21806
+ apiHost,
21807
+ });
21808
+ return account;
21809
+ },
21810
+ onSuccess: () => {
21811
+ queryClient.invalidateQueries({
21812
+ queryKey: ['getTaxationRequiredAccountFields', token],
21813
+ });
21845
21814
  },
21846
- apiHost,
21847
- token,
21848
21815
  });
21816
+ return (jsxRuntime.jsxs(antd.Form, { className: "bunny-flex bunny-flex-col bunny-gap-4", form: form, initialValues: account, layout: "vertical", onFinish: updateAccount, children: [jsxRuntime.jsx(antd.Form.Item, { label: "Billing street", name: "billingStreet", children: jsxRuntime.jsx(antd.Input, { placeholder: "Street" }) }), jsxRuntime.jsx(antd.Form.Item, { label: "Billing city", name: "billingCity", children: jsxRuntime.jsx(antd.Input, { placeholder: "City" }) }), jsxRuntime.jsx(FormBillingState, {}), jsxRuntime.jsx(antd.Form.Item, { label: "Billing country", name: "billingCountry", rules: [{ required: true }], children: jsxRuntime.jsx(antd.Select, { options: common.Lists.COUNTRY_LIST, placeholder: "Select a country", showSearch: true, filterOption: (input, option) => {
21817
+ var _a, _b;
21818
+ return ((_a = option === null || option === void 0 ? void 0 : option.label) !== null && _a !== void 0 ? _a : '').toLowerCase().includes(input.toLowerCase()) ||
21819
+ ((_b = option === null || option === void 0 ? void 0 : option.value) !== null && _b !== void 0 ? _b : '').toLowerCase().includes(input.toLowerCase());
21820
+ } }) }), jsxRuntime.jsx(antd.Form.Item, { label: "Billing zip", name: "billingZip", children: jsxRuntime.jsx(antd.Input, { placeholder: "Zip" }) }), jsxRuntime.jsx(antd.Form.Item, { children: jsxRuntime.jsx(antd.Button, { className: "bunny-w-full", disabled: isUpdatingAccount, htmlType: "submit", type: "primary", children: "Submit" }) })] }));
21821
+ };
21822
+ const FormBillingState = () => {
21823
+ const billingCountry = antd.Form.useWatch('billingCountry');
21824
+ const billingStateRequired = COUNTRIES_REQUIRING_STATE.includes(billingCountry);
21825
+ return (jsxRuntime.jsx(antd.Form.Item, { label: "Billing state", name: "billingState", rules: [{ required: billingStateRequired }], children: jsxRuntime.jsx(antd.Input, { placeholder: "State" }) }));
21849
21826
  };
21850
21827
 
21851
- const CanShowQuantitiesInput_SubscriptionChargeFragment = t(`
21852
- fragment CanShowQuantitiesInput_SubscriptionChargeFragment on SubscriptionCharge {
21853
- id
21854
- pricingModel
21855
- expired
21856
- selfServiceQuantity
21857
- }
21858
- `);
21859
- const CanShowQuantitiesInput_SubscriptionFragment = t(`
21860
- fragment CanShowQuantitiesInput_SubscriptionFragment on Subscription {
21828
+ // HACK: I have imported QuoteFields_QuoteFragment here as a hack to ensure I have all of the quote data needed for
21829
+ // the eventual children of this component.
21830
+ // Solution: Eventually all children of this component should be using query fragments to avoid this
21831
+ const QuoteCheckout_QuoteFragment = t(`
21832
+ fragment QuoteCheckout_QuoteFragment on Quote {
21861
21833
  id
21862
- state
21863
- priceList {
21834
+ accountId
21835
+ amountDue
21836
+ amount
21837
+ quoteChanges {
21864
21838
  id
21839
+ charges {
21840
+ kind
21841
+ coupon {
21842
+ couponCode
21843
+ }
21844
+ }
21865
21845
  }
21866
- chargeReport {
21867
- ...CanShowQuantitiesInput_SubscriptionChargeFragment
21868
- }
21869
- }
21870
- `, [CanShowQuantitiesInput_SubscriptionChargeFragment]);
21871
- const createQuoteParams = (quote, subscriptionQuantity, editedSubscription) => {
21872
- if (!editedSubscription || editedSubscription.quantity === undefined) {
21873
- return { charges: [], quoteChange: undefined };
21846
+ ...QuoteFields_QuoteFragment
21874
21847
  }
21875
- const quoteChange = quote.quoteChanges.find(quoteChange => { var _a, _b; return quoteChange.priceList.id === ((_b = (_a = editedSubscription === null || editedSubscription === void 0 ? void 0 : editedSubscription.subscription) === null || _a === void 0 ? void 0 : _a.priceList) === null || _b === void 0 ? void 0 : _b.id); });
21876
- const quoteChangeCharge = quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.charges.find(charge => charge.priceListCharge.id === editedSubscription.chargeId);
21877
- let charges = [
21878
- {
21879
- id: quoteChangeCharge.id,
21880
- quantity: editedSubscription.quantity - subscriptionQuantity,
21881
- },
21882
- ];
21883
- return { charges, quoteChange };
21884
- };
21885
- // Create an id using the charge id and the subscription id
21886
- const getUpdatingChargeQuantityId = (priceListChargeId, subscriptionId) => {
21887
- return `${priceListChargeId}-${subscriptionId}`;
21888
- };
21889
- const canShowQuantitiesInput = ({ charge: maskedCharge, subscription: maskedSubscription, }) => {
21890
- const subscription = readFragment(CanShowQuantitiesInput_SubscriptionFragment, maskedSubscription);
21891
- const charge = readFragment(CanShowQuantitiesInput_SubscriptionChargeFragment, maskedCharge);
21892
- // Check if the subscription is active, pending, or in trial,
21893
- // the pricing model is not flat,
21894
- // and if it's not a trial, also check if the current charge is the last one in the subscription.
21895
- const isActiveSubscription = (subscription === null || subscription === void 0 ? void 0 : subscription.state) === 'ACTIVE';
21896
- const isPendingSubscription = (subscription === null || subscription === void 0 ? void 0 : subscription.state) === 'PENDING';
21897
- const isTrialSubscription = (subscription === null || subscription === void 0 ? void 0 : subscription.state) === 'TRIAL';
21898
- const isFlatPricing = (charge === null || charge === void 0 ? void 0 : charge.pricingModel) === 'FLAT';
21899
- const shouldProcessCharge = (isActiveSubscription || isPendingSubscription || isTrialSubscription) &&
21900
- !isFlatPricing &&
21901
- (charge === null || charge === void 0 ? void 0 : charge.selfServiceQuantity) &&
21902
- !(charge === null || charge === void 0 ? void 0 : charge.expired);
21903
- // Now you can use the value of shouldProcessCharge to determine whether to process the charge.
21904
- return shouldProcessCharge;
21905
- };
21906
- const canShowChangeQuantities = ({ subscriptions, }) => {
21907
- return subscriptions === null || subscriptions === void 0 ? void 0 : subscriptions.some(maskedSubscription => {
21908
- var _a;
21909
- if (!maskedSubscription)
21910
- return false;
21911
- const subscription = readFragment(CanShowQuantitiesInput_SubscriptionFragment, maskedSubscription);
21912
- return (_a = subscription === null || subscription === void 0 ? void 0 : subscription.chargeReport) === null || _a === void 0 ? void 0 : _a.some(charge => {
21913
- return canShowQuantitiesInput({ charge, subscription: maskedSubscription });
21914
- });
21915
- });
21916
- };
21917
-
21918
- const QuantityInput_SubscriptionChargeFragment = t(`
21919
- fragment QuantityInput_SubscriptionChargeFragment on SubscriptionCharge {
21920
- id
21921
- quantity
21922
- selfServiceQuantity
21923
- priceListChargeId
21924
- }
21925
- `);
21926
- const QuantityInput_SubscriptionFragment = t(`
21927
- fragment QuantityInput_SubscriptionFragment on Subscription {
21928
- id
21929
- state
21930
- priceList {
21931
- id
21932
- }
21933
- chargeReport {
21934
- ...QuantityInput_SubscriptionChargeFragment
21935
- ...CanShowQuantitiesInput_SubscriptionChargeFragment
21936
- }
21937
- ...CanShowQuantitiesInput_SubscriptionFragment
21938
- }
21939
- `, [
21940
- QuantityInput_SubscriptionChargeFragment,
21941
- CanShowQuantitiesInput_SubscriptionChargeFragment,
21942
- CanShowQuantitiesInput_SubscriptionFragment,
21943
- ]);
21944
- const formatDateForApi = (date) => {
21945
- if (typeof date === 'string')
21946
- date = dayjs(date);
21947
- return date.format('YYYY-MM-DD');
21948
- };
21949
- const QuantityInput = ({ charge: maskedCharge, chargeIndex, editingQuote, setEditingQuoteData, subscription: maskedSubscription, subscriptionIndex, setUpdatingChargeQuantityId, updatingChargeQuantityId, setErrorUpdatingQuantity, }) => {
21950
- // Context
21951
- const token = useToken();
21848
+ `, [QuoteFields_QuoteFragment]);
21849
+ const showSuccessNotification = common.useSuccessNotification();
21850
+ const QuoteCheckout = ({ account, onSuccess, onFail, quote: maskedQuote, taxationRequiredAccountFields, onRecalculateTaxes, }) => {
21851
+ var _a, _b, _c, _d, _e;
21852
+ // Read fragments
21853
+ const quote = readFragment(QuoteCheckout_QuoteFragment, maskedQuote);
21952
21854
  const { apiHost } = react.useContext(BunnyContext);
21953
- // Local state
21954
- const [editedSubscription, setEditedSubscription] = react.useState();
21955
- // Derived state
21956
- const charge = readFragment(QuantityInput_SubscriptionChargeFragment, maskedCharge);
21957
- const subscription = readFragment(QuantityInput_SubscriptionFragment, maskedSubscription);
21958
- // Hooks
21855
+ const { upgradingSubscription } = react.useContext(SubscriptionsContext);
21856
+ const token = useToken();
21857
+ const isMobile = common.useIsMobile();
21858
+ const [isSaving, setIsSaving] = react.useState(false);
21859
+ const paymentRequired = getQuoteAmountDue(quote) > 0;
21959
21860
  const queryClient = reactQuery.useQueryClient();
21960
- const createSubscriptionQuote = useCreateSubscriptionQuote();
21961
- const quoteChangeUpdate = useQuoteChangeUpdate();
21962
- const showErrorNotification = common.useErrorNotification();
21963
- const quantityDisabled =
21964
- // If we are editing a quote, we disable the quantity input
21965
- // If we don't have a editedSubscription, we disable the quantity input
21966
- (updatingChargeQuantityId &&
21967
- charge.priceListChargeId &&
21968
- subscription.id &&
21969
- updatingChargeQuantityId !==
21970
- getUpdatingChargeQuantityId(charge.priceListChargeId, subscription.id)) ||
21971
- // If the subscription is not self-service, we disable the quantity input
21972
- !charge.selfServiceQuantity;
21973
- const value = (editedSubscription === null || editedSubscription === void 0 ? void 0 : editedSubscription.quantity) === undefined ? '' : editedSubscription.quantity;
21974
- // Mutations
21975
- const { mutate: createCharge } = reactQuery.useMutation({
21976
- mutationFn: quoteChargeCreate,
21977
- onSuccess: (response) => {
21978
- var _a, _b, _c;
21979
- if (!(editingQuote === null || editingQuote === void 0 ? void 0 : editingQuote.id)) {
21980
- const isTrial = ((_a = editedSubscription === null || editedSubscription === void 0 ? void 0 : editedSubscription.subscription) === null || _a === void 0 ? void 0 : _a.state) === 'TRIAL';
21981
- setEditingQuoteData({
21982
- id: (_b = response.quoteChange) === null || _b === void 0 ? void 0 : _b.quoteId,
21983
- isTrial,
21984
- });
21985
- }
21861
+ const [couponCode, setCouponCode] = react.useState('');
21862
+ const { addCoupon, removeCoupon, isAddingCoupon, isRemovingCoupon, activeCouponsExist } = useUpdateCoupons({
21863
+ apiHost,
21864
+ token,
21865
+ 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,
21866
+ onCouponAdded: () => {
21867
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id))
21868
+ throw new Error('Quote ID is required');
21986
21869
  queryClient.invalidateQueries({
21987
21870
  queryKey: common.QueryKeyFactory.default.createObjectKey({
21988
- id: (_c = response.quoteChange) === null || _c === void 0 ? void 0 : _c.quoteId,
21871
+ id: quote === null || quote === void 0 ? void 0 : quote.id,
21989
21872
  objectName: 'editingQuote',
21990
21873
  token,
21991
21874
  }),
21992
21875
  });
21876
+ showSuccessNotification('Coupon applied');
21877
+ onRecalculateTaxes();
21878
+ setCouponCode('');
21993
21879
  },
21994
- });
21995
- const createQuote = reactQuery.useMutation({
21996
- mutationFn: (subscriptionId) => createSubscriptionQuote([subscriptionId], apiHost, token),
21997
- onSuccess: (subscriptionUpdateData) => {
21998
- var _a, _b;
21999
- const quote = (_a = subscriptionUpdateData === null || subscriptionUpdateData === void 0 ? void 0 : subscriptionUpdateData.quoteSubscriptionUpdate) === null || _a === void 0 ? void 0 : _a.quote;
22000
- const quoteChange = quote.quoteChanges.find(quoteChange => { var _a; return quoteChange.priceList.id === ((_a = editedSubscription === null || editedSubscription === void 0 ? void 0 : editedSubscription.subscription.priceList) === null || _a === void 0 ? void 0 : _a.id); });
22001
- const subscriptionCharge = (_b = quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.subscription) === null || _b === void 0 ? void 0 : _b.charges.find(charge => { var _a; return ((_a = charge === null || charge === void 0 ? void 0 : charge.priceListCharge) === null || _a === void 0 ? void 0 : _a.id) === (editedSubscription === null || editedSubscription === void 0 ? void 0 : editedSubscription.chargeId); });
22002
- if (subscriptionCharge && quoteChange && editedSubscription) {
22003
- createCharge({
22004
- apiHost,
22005
- quantity: editedSubscription.quantity,
22006
- quoteChangeId: quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.id,
22007
- startDate: formatDateForApi(dayjs()),
22008
- subscriptionChargeId: subscriptionCharge.id,
22009
- token,
22010
- });
22011
- }
22012
- },
22013
- });
22014
- const updateQuote = reactQuery.useMutation({
22015
- mutationFn: ({ charges, quoteChangeId, }) => quoteChangeUpdate(charges, quoteChangeId, apiHost, token),
22016
- onSuccess: (response) => {
22017
- var _a, _b, _c, _d, _e;
22018
- if (!(editingQuote === null || editingQuote === void 0 ? void 0 : editingQuote.id)) {
22019
- const isTrial = ((_a = editedSubscription === null || editedSubscription === void 0 ? void 0 : editedSubscription.subscription) === null || _a === void 0 ? void 0 : _a.state) === 'TRIAL';
22020
- setEditingQuoteData({
22021
- id: (_c = (_b = response.quoteChangeUpdate) === null || _b === void 0 ? void 0 : _b.quoteChange) === null || _c === void 0 ? void 0 : _c.quoteId,
22022
- isTrial,
22023
- });
22024
- }
21880
+ onCouponRemoved: () => {
21881
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id))
21882
+ throw new Error('Quote ID is required');
22025
21883
  queryClient.invalidateQueries({
22026
21884
  queryKey: common.QueryKeyFactory.default.createObjectKey({
22027
- id: (_e = (_d = response.quoteChangeUpdate) === null || _d === void 0 ? void 0 : _d.quoteChange) === null || _e === void 0 ? void 0 : _e.quoteId,
21885
+ id: quote === null || quote === void 0 ? void 0 : quote.id,
22028
21886
  objectName: 'editingQuote',
22029
21887
  token,
22030
21888
  }),
22031
21889
  });
22032
- setErrorUpdatingQuantity(false);
21890
+ showSuccessNotification('Coupon removed');
21891
+ onRecalculateTaxes();
22033
21892
  },
22034
- onError: () => {
22035
- setErrorUpdatingQuantity(true);
21893
+ });
21894
+ 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'); });
21895
+ const checkoutMutation = reactQuery.useMutation({
21896
+ mutationFn: async () => {
21897
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id))
21898
+ throw new Error('Quote ID is required');
21899
+ if (paymentRequired)
21900
+ throw new Error('Payment is required');
21901
+ return await checkout({ quoteId: quote.id, token, apiHost });
22036
21902
  },
21903
+ onSuccess,
21904
+ onError: onFail,
22037
21905
  });
22038
- // Handlers
22039
- const isQuantityLowerThanOriginal = (quantity) => (editedSubscription === null || editedSubscription === void 0 ? void 0 : editedSubscription.quantity) !== undefined && editedSubscription.quantity <= quantity;
22040
- const onChangeQuantity = (chargeIndex, value, priceListChargeId, subscription, subscriptionIndex) => {
22041
- // Handle empty string - don't convert to 0, keep it as undefined
22042
- const quantity = value === '' ? undefined : isNaN(parseInt(value)) ? 0 : parseInt(value);
22043
- setEditedSubscription({
22044
- chargeIndex,
22045
- subscriptionIndex,
22046
- chargeId: priceListChargeId,
22047
- quantity,
22048
- subscription,
22049
- });
22050
- if (quantity === undefined) {
22051
- setUpdatingChargeQuantityId(undefined);
22052
- setEditingQuoteData(undefined);
22053
- }
22054
- if (quantity === charge.quantity) {
22055
- setEditingQuoteData(undefined);
22056
- showErrorNotification('New quantity cannot be the same as current');
22057
- }
22058
- else {
22059
- if (quantity !== undefined && quantity !== charge.quantity) {
22060
- if (!(charge === null || charge === void 0 ? void 0 : charge.priceListChargeId)) {
22061
- showErrorNotification('Charge ID is not found');
22062
- return;
22063
- }
22064
- setUpdatingChargeQuantityId(getUpdatingChargeQuantityId(charge.priceListChargeId, subscription.id));
22065
- }
22066
- }
22067
- };
22068
- const handleSubscriptionUpdate = (editedSubscription) => {
22069
- if (!editedSubscription || editedSubscription.quantity === undefined)
22070
- return;
22071
- // If we are not editing a quote, we create a new one
22072
- if (!editingQuote) {
22073
- createQuote.mutate(editedSubscription.subscription.id);
22074
- }
22075
- else {
22076
- // If we are editing a quote, we update the quote change
22077
- if (!charge.quantity)
22078
- throw new Error('Charge quantity is required');
22079
- const { charges, quoteChange } = createQuoteParams(editingQuote, charge.quantity, editedSubscription);
22080
- if (quoteChange && charges.length > 0) {
22081
- updateQuote.mutate({
22082
- charges,
22083
- quoteChangeId: quoteChange.id,
22084
- });
22085
- }
22086
- }
22087
- };
22088
- // Edit subscription debounce
22089
- react.useEffect(() => {
22090
- const debounce = setTimeout(() => {
22091
- handleSubscriptionUpdate(editedSubscription);
22092
- }, 1000);
22093
- return () => clearTimeout(debounce);
22094
- }, [editedSubscription]);
22095
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(antd.Input, { className: "bunny-text-right", disabled: quantityDisabled, onChange: e => {
22096
- if (!charge.priceListChargeId)
22097
- throw new Error('Charge price list charge ID is required');
22098
- onChangeQuantity(chargeIndex, e.target.value, charge.priceListChargeId, subscription, subscriptionIndex);
22099
- }, status: charge.quantity && isQuantityLowerThanOriginal(charge.quantity) ? 'error' : '', style: { width: '96px' }, value: value }) }));
21906
+ async function handleCheckoutNoPayment() {
21907
+ setIsSaving(true);
21908
+ checkoutMutation.mutate();
21909
+ setIsSaving(false);
21910
+ }
21911
+ if (taxationRequiredAccountFields)
21912
+ return (jsxRuntime.jsx(PaymentFormWrapper, { setMaxHeight: false, children: jsxRuntime.jsx(TaxationForm, { account: account, accountId: quote.accountId }) }));
21913
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: paymentRequired ? (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2 bunny-w-full", children: [jsxRuntime.jsx(PaymentForm, { onFail: onFail, onPaymentSuccess: onSuccess, quote: quote }), (couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.length) === 0 ? (jsxRuntime.jsx(jsxRuntime.Fragment, { children: upgradingSubscription &&
21914
+ shouldShowCouponEditor(quote, activeCouponsExist, upgradingSubscription) && (jsxRuntime.jsx(CouponEditor, { className: "bunny-px-4 bunny-pt-1", quote: quote, onAddCoupon: addCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode })) })) : (jsxRuntime.jsx(antd.Button, { type: "link", loading: isRemovingCoupon, onClick: () => {
21915
+ couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.forEach(couponCharge => {
21916
+ var _a;
21917
+ const couponCode = (_a = couponCharge === null || couponCharge === void 0 ? void 0 : couponCharge.coupon) === null || _a === void 0 ? void 0 : _a.couponCode;
21918
+ if (couponCode) {
21919
+ removeCoupon(couponCode);
21920
+ }
21921
+ });
21922
+ }, children: "Remove coupon(s)" }))] })) : (jsxRuntime.jsx(PaymentFormWrapper, { setMaxHeight: false, children: jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-2 bunny-px-4 ${isMobile ? 'bunny-shadow-padding-x' : ''}`, children: [jsxRuntime.jsx(antd.Button, { onClick: handleCheckoutNoPayment, type: "primary", children: isSaving ? 'Processing...' : 'Complete order' }), jsxRuntime.jsx("div", { className: "bunny-text-xs bunny-text-slate-500", children: "No payment is required" })] }) })) }));
21923
+ };
21924
+ const PaymentFormWrapper = ({ children, setMaxHeight, className, }) => {
21925
+ const isMobile = common.useIsMobile();
21926
+ return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-w-full bunny-flex-col bunny-gap-6 ${isMobile ? 'bunny-shadow-padding-xb' : ''} ${className}`, style: {
21927
+ ...(isMobile
21928
+ ? setMaxHeight
21929
+ ? { maxHeight: '60vh' }
21930
+ : {}
21931
+ : {
21932
+ width: '100%',
21933
+ maxWidth: '350px',
21934
+ }),
21935
+ }, children: children }));
22100
21936
  };
22101
21937
 
22102
- const QuantityChangeGridRow_SubscriptionChargeFragment = t(`
22103
- fragment QuantityChangeGridRow_SubscriptionChargeFragment on SubscriptionCharge {
22104
- id
22105
- quantity
22106
- name
22107
- ...QuantityInput_SubscriptionChargeFragment
22108
- ...CanShowQuantitiesInput_SubscriptionChargeFragment
22109
- }
22110
- `, [QuantityInput_SubscriptionChargeFragment, CanShowQuantitiesInput_SubscriptionChargeFragment]);
22111
- const QuantityChangeGridRow_SubscriptionFragment = t(`
22112
- fragment QuantityChangeGridRow_SubscriptionFragment on Subscription {
21938
+ const queryKeyFactory = common.QueryKeyFactory.default;
21939
+ const Checkout_QuoteFragment = t(`
21940
+ fragment Checkout_QuoteFragment on Quote {
22113
21941
  id
22114
- priceList {
22115
- id
22116
- }
22117
- plan {
22118
- name
22119
- }
22120
- chargeReport {
22121
- ...QuantityChangeGridRow_SubscriptionChargeFragment
22122
- ...CanShowQuantitiesInput_SubscriptionChargeFragment
21942
+ accountId
21943
+ formattedQuote {
21944
+ html
22123
21945
  }
22124
- ...QuantityInput_SubscriptionFragment
22125
- ...CanShowQuantitiesInput_SubscriptionFragment
21946
+ ...QuoteCheckout_QuoteFragment
22126
21947
  }
22127
- `, [
22128
- QuantityChangeGridRow_SubscriptionChargeFragment,
22129
- CanShowQuantitiesInput_SubscriptionChargeFragment,
22130
- CanShowQuantitiesInput_SubscriptionFragment,
22131
- QuantityInput_SubscriptionFragment,
22132
- ]);
22133
- const { Text: Text$k } = antd.Typography;
22134
- const QuantityChangeGridRow = ({ chargeIndex, editingQuote, subscriptionIndex, setEditingQuoteData, subscription: maskedSubscription, subscriptionCharge: maskedSubscriptionCharge, setUpdatingChargeQuantityId, updatingChargeQuantityId, setErrorUpdatingQuantity, }) => {
22135
- var _a, _b;
22136
- const subscription = readFragment(QuantityChangeGridRow_SubscriptionFragment, maskedSubscription);
22137
- const charge = readFragment(QuantityChangeGridRow_SubscriptionChargeFragment, maskedSubscriptionCharge);
22138
- if (!canShowQuantitiesInput({ charge, subscription }))
22139
- return null;
22140
- const { brandColor } = react.useContext(BrandContext);
22141
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-1", children: [jsxRuntime.jsx(Text$k, { className: "bunny-font-medium bunny-text-sm bunny-col-span-full", style: { color: brandColor }, children: (_a = subscription === null || subscription === void 0 ? void 0 : subscription.plan) === null || _a === void 0 ? void 0 : _a.name }), jsxRuntime.jsx(Text$k, { className: "bunny-text-sm", children: (_b = charge.name) === null || _b === void 0 ? void 0 : _b.toUpperCase() })] }), jsxRuntime.jsx(Text$k, { className: "bunny-flex bunny-items-center bunny-justify-end bunny-font-medium bunny-text-sm bunny-text-gray-900", children: charge.quantity }), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-justify-center bunny-items-end", children: [jsxRuntime.jsx(QuantityInput, { charge: charge, chargeIndex: chargeIndex, editingQuote: editingQuote, setEditingQuoteData: setEditingQuoteData, subscription: subscription, subscriptionIndex: subscriptionIndex, setUpdatingChargeQuantityId: setUpdatingChargeQuantityId, updatingChargeQuantityId: updatingChargeQuantityId, setErrorUpdatingQuantity: setErrorUpdatingQuantity }), jsxRuntime.jsx("div", {})] }), jsxRuntime.jsx(antd.Divider, { className: "bunny-col-span-full bunny-my-2" })] }));
22142
- };
22143
-
22144
- const { Text: Text$j } = antd.Typography;
22145
- const QuantityChangeGridTitle = ({ children, right }) => (jsxRuntime.jsx(Text$j, { className: `bunny-font-medium bunny-text-sm bunny-text-slate-600 ${right ? 'bunny-text-right' : 'bunny-text-left'}`, children: children }));
22146
-
22147
- const QuoteChangeSummarySection = ({ editingQuote, editingQuoteData, openCheckout, setEditingQuoteData, errorUpdatingQuantity, }) => {
21948
+ `, [QuoteCheckout_QuoteFragment]);
21949
+ const Checkout = ({ onCancel, onSuccess, onFail, invoice, open, quote: maskedQuote, isUpdatingQuote, }) => {
21950
+ var _a, _b, _c, _d, _e;
22148
21951
  const { apiHost } = react.useContext(BunnyContext);
22149
21952
  const isMobile = common.useIsMobile();
22150
21953
  const token = useToken();
22151
- const showSuccessNotification = common.useSuccessNotification();
22152
- const trialUpgradeMutation = reactQuery.useMutation({
22153
- mutationFn: (quoteId) => checkout({ quoteId, token, apiHost }),
22154
- onSuccess: () => {
22155
- setEditingQuoteData(undefined);
22156
- showSuccessNotification('Subscription updated successfully');
22157
- },
21954
+ // Read fragments
21955
+ const quote = readFragment(Checkout_QuoteFragment, maskedQuote);
21956
+ const hasTaxPlugin = useHasTaxPlugin({
21957
+ apiHost,
21958
+ token,
22158
21959
  });
22159
- return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-items-end", children: [editingQuote && (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-mb-8", children: [jsxRuntime.jsx("div", { className: "bunny-text-slate-500 bunny-text-right bunny-text-xs bunny-mb-2", children: "TOTAL" }), jsxRuntime.jsx("div", { className: `bunny-text-right ${isMobile ? 'bunny-text-2xl' : 'bunny-text-xl'}`, children: common.formatCurrency(getQuoteAmountDue(editingQuote), (editingQuote === null || editingQuote === void 0 ? void 0 : editingQuote.currencyId) || '') })] })), jsxRuntime.jsx("div", { className: `bunny-flex bunny-items-center bunny-justify-end ${isMobile ? 'bunny-w-full' : ''}`, children: jsxRuntime.jsx(antd.Button, { className: "bunny-w-full", onClick: (editingQuoteData === null || editingQuoteData === void 0 ? void 0 : editingQuoteData.isTrial)
22160
- ? () => trialUpgradeMutation.mutate(editingQuoteData.id)
22161
- : openCheckout, disabled: !editingQuoteData || !editingQuote || errorUpdatingQuantity, size: isMobile ? 'large' : 'middle', type: "primary", children: (editingQuoteData === null || editingQuoteData === void 0 ? void 0 : editingQuoteData.isTrial) ? 'Activate Trial' : 'Proceed to checkout' }) })] }));
22162
- };
22163
-
22164
- const QUANTITY_CHANGE_HEADER_TITLE = 'Update quantities';
22165
- const QUANTITY_CHANGE_HEADER_DESCRIPTION = 'Adjust quantities below. The change will take effect immediately after checkout has been completed.';
22166
- const QuantityDrawerDesktop_SubscriptionFragment = t(`
22167
- fragment QuantityDrawerDesktop_SubscriptionFragment on Subscription {
22168
- currentCharges {
22169
- chargeType
22170
- ...QuantityChangeGridRow_SubscriptionChargeFragment
22171
- }
22172
- ...QuantityChangeGridRow_SubscriptionFragment
22173
- }
22174
- `, [QuantityChangeGridRow_SubscriptionFragment, QuantityChangeGridRow_SubscriptionChargeFragment]);
22175
- const QuantityChangeDrawerDesktop = ({ editingQuote, editingQuoteData, onClose, open, openCheckout, setEditingQuoteData, subscriptions, setUpdatingChargeQuantityId, updatingChargeQuantityId, }) => {
22176
- const [openLocal, setOpenLocal] = react.useState(open);
22177
- const [errorUpdatingQuantity, setErrorUpdatingQuantity] = react.useState(false);
22178
- const isMobile = common.useIsMobile();
22179
- react.useEffect(() => {
22180
- let timeoutId;
22181
- if (!open) {
22182
- timeoutId = setTimeout(() => {
22183
- setOpenLocal(false);
22184
- }, 300); // Delay to allow for close animation
22185
- }
22186
- else {
22187
- setOpenLocal(true);
21960
+ const queryClient = reactQuery.useQueryClient();
21961
+ // Queries
21962
+ const { data: taxationRequiredAccountFields, isLoading: isLoadingTaxationRequiredAccountFields } = reactQuery.useQuery({
21963
+ queryKey: ['getTaxationRequiredAccountFields', token],
21964
+ queryFn: () => getTaxationRequiredAccountFields({ apiHost, token }),
21965
+ enabled: Boolean(quote),
21966
+ staleTime: 0,
21967
+ });
21968
+ const { data: account, isLoading: isLoadingAccount } = reactQuery.useQuery({
21969
+ queryKey: ['account', quote === null || quote === void 0 ? void 0 : quote.accountId],
21970
+ queryFn: () => (quote === null || quote === void 0 ? void 0 : quote.accountId) &&
21971
+ common.getAccount({ id: quote.accountId, apiHost, token, componentsVersion: PACKAGE_VERSION }),
21972
+ enabled: Boolean(quote === null || quote === void 0 ? void 0 : quote.accountId) && ((taxationRequiredAccountFields === null || taxationRequiredAccountFields === void 0 ? void 0 : taxationRequiredAccountFields.length) || 0) > 0,
21973
+ });
21974
+ async function recalculateTaxes() {
21975
+ if (quote) {
21976
+ if (!quote.id)
21977
+ throw new Error('Quote ID is required');
21978
+ const updatedQuote = await quoteRecalculateTaxes({
21979
+ quoteId: quote.id,
21980
+ apiHost,
21981
+ token,
21982
+ });
21983
+ if (updatedQuote) {
21984
+ const quoteKey = queryKeyFactory.createObjectKey({
21985
+ id: updatedQuote.id,
21986
+ objectName: 'editingQuote',
21987
+ token,
21988
+ });
21989
+ queryClient.setQueryData(quoteKey, updatedQuote);
21990
+ }
22188
21991
  }
22189
- return () => clearTimeout(timeoutId);
22190
- }, [open]);
22191
- if (!openLocal)
21992
+ return {};
21993
+ }
21994
+ const recalculateTaxesEnabled = Boolean(quote) &&
21995
+ open &&
21996
+ hasTaxPlugin &&
21997
+ !taxationRequiredAccountFields &&
21998
+ !isLoadingTaxationRequiredAccountFields &&
21999
+ !isUpdatingQuote;
22000
+ reactQuery.useQuery({
22001
+ queryKey: queryKeyFactory.createQuoteTaxCalculateKey({
22002
+ id: (_a = quote === null || quote === void 0 ? void 0 : quote.id) !== null && _a !== void 0 ? _a : undefined,
22003
+ token,
22004
+ }),
22005
+ queryFn: recalculateTaxes,
22006
+ // Recalculate taxes if the quote is open, has a tax plugin, and the taxation required account fields are not required
22007
+ enabled: recalculateTaxesEnabled,
22008
+ staleTime: 0,
22009
+ });
22010
+ if (!open || isLoadingTaxationRequiredAccountFields || isLoadingAccount)
22192
22011
  return null;
22193
- return (jsxRuntime.jsxs(antd.Drawer, { closeIcon: null, destroyOnHidden: true, onClose: onClose, open: open, styles: isMobile
22194
- ? {
22195
- body: {
22196
- padding: '1rem',
22197
- background: common.SLATE_50,
22198
- },
22199
- wrapper: {
22200
- width: '100vw',
22201
- },
22202
- }
22203
- : {
22204
- wrapper: {
22205
- minWidth: '600px',
22206
- },
22207
- }, title: jsxRuntime.jsx(DrawerHeader, { description: QUANTITY_CHANGE_HEADER_DESCRIPTION, onClose: onClose, title: QUANTITY_CHANGE_HEADER_TITLE, closeButtonClassName: "ant-drawer-close" }), children: [jsxRuntime.jsxs("div", { className: "bunny-grid bunny-pb-2", style: {
22208
- gridTemplateColumns: '3fr 3fr 2fr',
22209
- rowGap: '0.25rem',
22210
- columnGap: '1rem',
22211
- }, children: [jsxRuntime.jsx(QuantityChangeGridTitle, { children: " " }), jsxRuntime.jsx(QuantityChangeGridTitle, { right: true, children: "CURRENT QUANTITY" }), jsxRuntime.jsx(QuantityChangeGridTitle, { right: true, children: "NEW QUANTITY" }), jsxRuntime.jsx(antd.Divider, { className: "bunny-col-span-full", style: { marginBottom: '8px', marginTop: '20px' } }), subscriptions.map((maskedSubscription, index) => {
22212
- var _a;
22213
- const subscription = readFragment(QuantityDrawerDesktop_SubscriptionFragment, maskedSubscription);
22214
- return (jsxRuntime.jsx("div", { className: "bunny-contents", children: (_a = subscription === null || subscription === void 0 ? void 0 : subscription.currentCharges) === null || _a === void 0 ? void 0 : _a.map((charge, chargeIndex) => {
22215
- if (charge.chargeType === 'USAGE')
22216
- return null;
22217
- return (jsxRuntime.jsx(QuantityChangeGridRow, { chargeIndex: chargeIndex, editingQuote: editingQuote, setEditingQuoteData: setEditingQuoteData, subscription: subscription, subscriptionCharge: charge, subscriptionIndex: index, setUpdatingChargeQuantityId: setUpdatingChargeQuantityId, updatingChargeQuantityId: updatingChargeQuantityId, setErrorUpdatingQuantity: setErrorUpdatingQuantity }, chargeIndex));
22218
- }) }, index));
22219
- })] }), jsxRuntime.jsx(QuoteChangeSummarySection, { editingQuote: editingQuote, editingQuoteData: editingQuoteData, openCheckout: openCheckout, setEditingQuoteData: setEditingQuoteData, errorUpdatingQuantity: errorUpdatingQuantity })] }));
22012
+ return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-flex-col bunny-fixed bunny-top-0 bunny-left-0 bunny-right-0 bunny-bottom-0 bunny-bg-slate-50
22013
+ bunny-overflow-auto bunny-height-full`, style: {
22014
+ zIndex: 1001,
22015
+ }, children: jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-grow bunny-pt-4 ${isMobile ? 'bunny-pb-4' : 'bunny-pb-8'} bunny-content-container`, children: [jsxRuntime.jsx("div", { className: "bunny-flex bunny-justify-end bunny-w-full bunny-pr-4", children: jsxRuntime.jsx(icons.CloseOutlined, { className: "bunny-text-base bunny-shadow-padding-xb", onClick: onCancel }) }), jsxRuntime.jsxs("div", { className: `bunny-flex bunny-justify-end bunny-pt-4 bunny-gap-4 ${isMobile ? 'bunny-flex-col' : 'bunny-shadow-padding-xb'}`, children: [((invoice === null || invoice === void 0 ? void 0 : invoice.html) || ((_b = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _b === void 0 ? void 0 : _b.html)) && (jsxRuntime.jsx(InvoiceQuoteView, { html: invoice ? invoice.html : (_d = (_c = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _c === void 0 ? void 0 : _c.html) !== null && _d !== void 0 ? _d : '' })), !isMobile && ((invoice === null || invoice === void 0 ? void 0 : invoice.html) || ((_e = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _e === void 0 ? void 0 : _e.html)) && (jsxRuntime.jsx(antd.Divider, { className: "bunny-h-full", type: "vertical" })), invoice ? (jsxRuntime.jsx("div", { className: "bunny-w-full bunny-pt-12", children: jsxRuntime.jsx(PaymentForm, { onPaymentSuccess: onSuccess, onFail: onFail, invoice: invoice }) })) : quote ? (jsxRuntime.jsx(QuoteCheckout, { account: account, onFail: error => {
22016
+ onFail(error);
22017
+ }, onSuccess: onSuccess, quote: quote, taxationRequiredAccountFields: taxationRequiredAccountFields, token: token, onRecalculateTaxes: async () => {
22018
+ if (recalculateTaxesEnabled) {
22019
+ await recalculateTaxes();
22020
+ }
22021
+ } })) : (jsxRuntime.jsx(PaymentForm, { onFail: error => {
22022
+ onFail(error);
22023
+ }, onPaymentSuccess: onSuccess }))] }), jsxRuntime.jsx(Footer, { className: "bunny-px-12" })] }) }));
22220
22024
  };
22221
22025
 
22222
- const SubscriptionsContext = react.createContext({});
22026
+ const QuantityDrawer_QuoteFragment = t(`
22027
+ fragment QuantityDrawer_QuoteFragment on Quote {
22028
+ id
22029
+ ...Checkout_QuoteFragment
22030
+ }
22031
+ `, [Checkout_QuoteFragment]);
22223
22032
 
22224
- const MUTATION$2 = `{
22225
- currentUser {
22226
- taxationRequiredAccountFields
22227
- }
22228
- }`;
22229
- const getTaxationRequiredAccountFields = async ({ apiHost, token, }) => {
22230
- var _a, _b;
22231
- const response = await gqlRequest({
22232
- query: MUTATION$2,
22233
- token,
22234
- apiHost: apiHost,
22235
- });
22236
- 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
22237
- ? response.currentUser.taxationRequiredAccountFields
22238
- : null;
22033
+ const useSetQuoteQueryData = () => {
22034
+ const token = useToken();
22035
+ const queryClient = reactQuery.useQueryClient();
22036
+ const setQuoteQueryData = (quoteId, maskedQuote) => {
22037
+ console.log('maskedQuote in setQuoteQueryData', maskedQuote);
22038
+ const quote = readFragment(QuantityDrawer_QuoteFragment, maskedQuote);
22039
+ queryClient.setQueryData(common.QueryKeyFactory.default.createObjectKey({
22040
+ id: quoteId,
22041
+ objectName: 'editingQuote',
22042
+ token,
22043
+ }), quote);
22044
+ };
22045
+ return { setQuoteQueryData };
22239
22046
  };
22240
22047
 
22241
- const useHasTaxPlugin = ({ apiHost, token, }) => {
22242
- const { data: plugins } = usePlugins({
22243
- apiHost,
22244
- token,
22245
- });
22246
- return Boolean(plugins === null || plugins === void 0 ? void 0 : plugins.some((plugin) => plugin.type === "taxation"));
22048
+ const mutation$4 = t(`
22049
+ mutation QuoteChargeCreate(
22050
+ $quoteChangeId: ID!
22051
+ $startDate: ISO8601Date!
22052
+ $endDate: ISO8601Date
22053
+ $priceListChargeId: ID
22054
+ $subscriptionChargeId: ID
22055
+ $price: Float
22056
+ $quantity: Int
22057
+ ) {
22058
+ quoteChargeCreate(
22059
+ endDate: $endDate
22060
+ price: $price
22061
+ priceListChargeId: $priceListChargeId
22062
+ quantity: $quantity
22063
+ quoteChangeId: $quoteChangeId
22064
+ startDate: $startDate
22065
+ subscriptionChargeId: $subscriptionChargeId
22066
+ ) {
22067
+ quoteCharge {
22068
+ quoteChange {
22069
+ id
22070
+ quoteId
22071
+ quote {
22072
+ ...QuantityDrawer_QuoteFragment
22073
+ }
22074
+ }
22075
+ id
22076
+ }
22077
+ errors
22078
+ }
22079
+ }
22080
+ `, [QuantityDrawer_QuoteFragment]);
22081
+ const quoteChargeCreate$1 = async ({ price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId, token, apiHost, }) => {
22082
+ var _a, _b;
22083
+ const response = await execute(mutation$4, { apiHost, token }, { price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId });
22084
+ if ((_a = response.quoteChargeCreate) === null || _a === void 0 ? void 0 : _a.errors) {
22085
+ throw new Error(response.quoteChargeCreate.errors[0]);
22086
+ }
22087
+ return (_b = response.quoteChargeCreate) === null || _b === void 0 ? void 0 : _b.quoteCharge;
22247
22088
  };
22248
22089
 
22249
- var SubscriptionState;
22250
- (function (SubscriptionState) {
22251
- SubscriptionState["ACTIVE"] = "ACTIVE";
22252
- SubscriptionState["TRIAL"] = "TRIAL";
22253
- SubscriptionState["PENDING"] = "PENDING";
22254
- SubscriptionState["EXPIRED"] = "EXPIRED";
22255
- SubscriptionState["CANCELED"] = "CANCELED";
22256
- SubscriptionState["TRIAL_EXPIRED"] = "TRIAL_EXPIRED";
22257
- })(SubscriptionState || (SubscriptionState = {}));
22258
- var SubscriptionState$1 = SubscriptionState;
22259
-
22260
- function shouldShowCouponEditor(quote, activeCouponsExist, upgradingSubscription) {
22261
- var _a, _b;
22262
- const upgradingFromTrial = ((_a = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === SubscriptionState$1.TRIAL ||
22263
- ((_b = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === SubscriptionState$1.TRIAL_EXPIRED;
22264
- function upgradingFromFree() {
22265
- const totalPrice = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.charges.reduce((acc, charge) => acc + Number((charge === null || charge === void 0 ? void 0 : charge.discountedPrice) || 0), 0);
22266
- return totalPrice === 0;
22090
+ const mutation$3 = t(`
22091
+ mutation QuoteChargeUpdate($quoteChargeId: ID!, $quantity: Int) {
22092
+ quoteChargeUpdate(quoteChargeId: $quoteChargeId, quantity: $quantity) {
22093
+ quoteCharge {
22094
+ quoteChange {
22095
+ id
22096
+ quoteId
22097
+ quote {
22098
+ ...QuantityDrawer_QuoteFragment
22099
+ }
22100
+ }
22101
+ id
22102
+ }
22103
+ errors
22104
+ }
22267
22105
  }
22268
- const quoteKindIsValid = quote.kind === common.QuoteChangeKind.SUBSCRIBE ||
22269
- quote.kind === common.QuoteChangeKind.ADJUSTMENT ||
22270
- quote.kind === common.QuoteChangeKind.ACTIVATE;
22271
- if (quoteKindIsValid) {
22272
- return activeCouponsExist && (upgradingFromTrial || upgradingFromFree());
22106
+ `, [QuantityDrawer_QuoteFragment]);
22107
+ const quoteChargeUpdate$1 = async (quoteChargeId, quantity, apiHost, token) => {
22108
+ var _a, _b;
22109
+ const response = await execute(mutation$3, { apiHost, token }, { quoteChargeId, quantity });
22110
+ if ((_a = response.quoteChargeUpdate) === null || _a === void 0 ? void 0 : _a.errors) {
22111
+ throw new Error(response.quoteChargeUpdate.errors[0]);
22273
22112
  }
22274
- return false;
22275
- }
22113
+ return (_b = response.quoteChargeUpdate) === null || _b === void 0 ? void 0 : _b.quoteCharge;
22114
+ };
22276
22115
 
22277
- const MUTATION$1 = `
22278
- mutation accountUpdate(
22279
- $id: ID!,
22280
- $attributes: AccountAttributes!) {
22281
- accountUpdate(
22282
- id: $id,
22283
- attributes: $attributes
22284
- ) {
22285
- account {
22116
+ const mutation$2 = t(`
22117
+ mutation quoteSubscriptionUpdate($subscriptionIds: [ID!]!) {
22118
+ quoteSubscriptionUpdate(subscriptionIds: $subscriptionIds) {
22119
+ quote {
22286
22120
  id
22287
- billingCountry
22288
- billingState
22289
- billingStreet
22290
- billingCity
22291
- billingZip
22292
- name
22121
+ quoteChanges {
22122
+ id
22123
+ priceList {
22124
+ id
22125
+ }
22126
+ subscription {
22127
+ charges {
22128
+ startDate
22129
+ endDate
22130
+ id
22131
+ priceListCharge {
22132
+ id
22133
+ }
22134
+ }
22135
+ }
22136
+ }
22137
+ ...QuantityDrawer_QuoteFragment
22293
22138
  }
22294
22139
  errors
22295
22140
  }
22141
+ }
22142
+ `, [QuantityDrawer_QuoteFragment]);
22143
+ const quoteSubscriptionUpdate = async (subscriptionIds, apiHost, token) => {
22144
+ var _a, _b;
22145
+ const response = await execute(mutation$2, { apiHost, token }, { subscriptionIds });
22146
+ if ((_a = response.quoteSubscriptionUpdate) === null || _a === void 0 ? void 0 : _a.errors) {
22147
+ throw new Error(response.quoteSubscriptionUpdate.errors[0]);
22148
+ }
22149
+ return (_b = response.quoteSubscriptionUpdate) === null || _b === void 0 ? void 0 : _b.quote;
22150
+ };
22151
+
22152
+ const formatDateForApi = (date) => {
22153
+ if (typeof date === 'string')
22154
+ date = dayjs(date);
22155
+ return date.format('YYYY-MM-DD');
22156
+ };
22157
+
22158
+ const CanShowQuantitiesInput_SubscriptionChargeFragment = t(`
22159
+ fragment CanShowQuantitiesInput_SubscriptionChargeFragment on SubscriptionCharge {
22160
+ id
22161
+ pricingModel
22162
+ expired
22163
+ selfServiceQuantity
22296
22164
  }
22297
- `;
22298
- const accountUpdate = async ({ accountId, attributes, token, apiHost, }) => {
22299
- var _a;
22300
- const vars = { id: accountId, attributes };
22301
- const response = await gqlRequest({
22302
- query: MUTATION$1,
22303
- token,
22304
- vars,
22305
- apiHost,
22165
+ `);
22166
+ const CanShowQuantitiesInput_SubscriptionFragment = t(`
22167
+ fragment CanShowQuantitiesInput_SubscriptionFragment on Subscription {
22168
+ id
22169
+ state
22170
+ priceList {
22171
+ id
22172
+ }
22173
+ chargeReport {
22174
+ ...CanShowQuantitiesInput_SubscriptionChargeFragment
22175
+ }
22176
+ }
22177
+ `, [CanShowQuantitiesInput_SubscriptionChargeFragment]);
22178
+ // Create an id using the charge id and the subscription id
22179
+ const getUpdatingChargeQuantityId = (priceListChargeId, subscriptionId) => {
22180
+ return `${priceListChargeId}-${subscriptionId}`;
22181
+ };
22182
+ const canShowQuantitiesInput = ({ charge: maskedCharge, subscription: maskedSubscription, }) => {
22183
+ const subscription = readFragment(CanShowQuantitiesInput_SubscriptionFragment, maskedSubscription);
22184
+ const charge = readFragment(CanShowQuantitiesInput_SubscriptionChargeFragment, maskedCharge);
22185
+ // Check if the subscription is active, pending, or in trial,
22186
+ // the pricing model is not flat,
22187
+ // and if it's not a trial, also check if the current charge is the last one in the subscription.
22188
+ const isActiveSubscription = (subscription === null || subscription === void 0 ? void 0 : subscription.state) === 'ACTIVE';
22189
+ const isPendingSubscription = (subscription === null || subscription === void 0 ? void 0 : subscription.state) === 'PENDING';
22190
+ const isTrialSubscription = (subscription === null || subscription === void 0 ? void 0 : subscription.state) === 'TRIAL';
22191
+ const isFlatPricing = (charge === null || charge === void 0 ? void 0 : charge.pricingModel) === 'FLAT';
22192
+ const shouldProcessCharge = (isActiveSubscription || isPendingSubscription || isTrialSubscription) &&
22193
+ !isFlatPricing &&
22194
+ (charge === null || charge === void 0 ? void 0 : charge.selfServiceQuantity) &&
22195
+ !(charge === null || charge === void 0 ? void 0 : charge.expired);
22196
+ // Now you can use the value of shouldProcessCharge to determine whether to process the charge.
22197
+ return shouldProcessCharge;
22198
+ };
22199
+ const canShowChangeQuantities = ({ subscriptions, }) => {
22200
+ return subscriptions === null || subscriptions === void 0 ? void 0 : subscriptions.some(maskedSubscription => {
22201
+ var _a;
22202
+ if (!maskedSubscription)
22203
+ return false;
22204
+ const subscription = readFragment(CanShowQuantitiesInput_SubscriptionFragment, maskedSubscription);
22205
+ return (_a = subscription === null || subscription === void 0 ? void 0 : subscription.chargeReport) === null || _a === void 0 ? void 0 : _a.some(charge => {
22206
+ return canShowQuantitiesInput({ charge, subscription: maskedSubscription });
22207
+ });
22306
22208
  });
22307
- const errors = (_a = response === null || response === void 0 ? void 0 : response.accountUpdate) === null || _a === void 0 ? void 0 : _a.errors;
22308
- if (errors)
22309
- throw errors;
22310
- return response.accountUpdate;
22311
22209
  };
22312
22210
 
22313
- const COUNTRIES_REQUIRING_STATE = ['US', 'CA'];
22314
- const TaxationForm = ({ account, quote }) => {
22315
- // Hooks
22316
- const queryClient = reactQuery.useQueryClient();
22317
- const { apiHost } = react.useContext(BunnyContext);
22211
+ const QuantityInput_SubscriptionChargeFragment = t(`
22212
+ fragment QuantityInput_SubscriptionChargeFragment on SubscriptionCharge {
22213
+ id
22214
+ quantity
22215
+ selfServiceQuantity
22216
+ priceListChargeId
22217
+ }
22218
+ `);
22219
+ const QuantityInput_SubscriptionFragment = t(`
22220
+ fragment QuantityInput_SubscriptionFragment on Subscription {
22221
+ id
22222
+ state
22223
+ priceList {
22224
+ id
22225
+ }
22226
+ chargeReport {
22227
+ ...QuantityInput_SubscriptionChargeFragment
22228
+ ...CanShowQuantitiesInput_SubscriptionChargeFragment
22229
+ }
22230
+ ...CanShowQuantitiesInput_SubscriptionFragment
22231
+ }
22232
+ `, [
22233
+ QuantityInput_SubscriptionChargeFragment,
22234
+ CanShowQuantitiesInput_SubscriptionChargeFragment,
22235
+ CanShowQuantitiesInput_SubscriptionFragment,
22236
+ ]);
22237
+ const DEBOUNCE_TIME = 1000;
22238
+ const QuantityInput = ({ charge: maskedCharge, editingQuote, editingQuoteId, setEditingQuoteData, subscription: maskedSubscription, setUpdatingChargeQuantityId, updatingChargeQuantityId, setErrorUpdatingQuantity, }) => {
22239
+ // Context
22318
22240
  const token = useToken();
22319
- const [form] = antd.Form.useForm();
22241
+ const { apiHost } = react.useContext(BunnyContext);
22242
+ // Local state
22243
+ const [quantity, setQuantity] = react.useState();
22244
+ // Derived state
22245
+ const charge = readFragment(QuantityInput_SubscriptionChargeFragment, maskedCharge);
22246
+ const subscription = readFragment(QuantityInput_SubscriptionFragment, maskedSubscription);
22247
+ // Hooks
22248
+ const showErrorNotification = common.useErrorNotification();
22249
+ const { setQuoteQueryData } = useSetQuoteQueryData();
22250
+ const quantityDisabled =
22251
+ // If we are editing a quote, we disable the quantity input
22252
+ // If we don't have a quantity, we disable the quantity input
22253
+ (updatingChargeQuantityId &&
22254
+ charge.priceListChargeId &&
22255
+ subscription.id &&
22256
+ updatingChargeQuantityId !==
22257
+ getUpdatingChargeQuantityId(charge.priceListChargeId, subscription.id)) ||
22258
+ // If the subscription is not self-service, we disable the quantity input
22259
+ !charge.selfServiceQuantity;
22260
+ const value = quantity === undefined ? '' : quantity;
22320
22261
  // Mutations
22321
- const { mutate: updateAccount, isPending: isUpdatingAccount } = reactQuery.useMutation({
22322
- mutationFn: async (changedFormData) => {
22323
- const account = await accountUpdate({
22324
- accountId: quote.accountId,
22325
- attributes: changedFormData,
22326
- token,
22327
- apiHost,
22328
- });
22329
- return account;
22330
- },
22331
- onSuccess: () => {
22332
- queryClient.invalidateQueries({
22333
- queryKey: ['getTaxationRequiredAccountFields', token],
22334
- });
22262
+ const { mutate: createCharge } = reactQuery.useMutation({
22263
+ mutationFn: quoteChargeCreate$1,
22264
+ onSuccess: response => {
22265
+ var _a, _b;
22266
+ if (!editingQuoteId)
22267
+ throw new Error('editingQuoteId is required');
22268
+ setQuoteQueryData(editingQuoteId, (_b = (_a = response === null || response === void 0 ? void 0 : response.quoteChange) === null || _a === void 0 ? void 0 : _a.quote) !== null && _b !== void 0 ? _b : null);
22335
22269
  },
22336
22270
  });
22337
- return (jsxRuntime.jsxs(antd.Form, { className: "bunny-flex bunny-flex-col bunny-gap-4", form: form, initialValues: account, layout: "vertical", onFinish: updateAccount, children: [jsxRuntime.jsx(antd.Form.Item, { label: "Billing street", name: "billingStreet", children: jsxRuntime.jsx(antd.Input, { placeholder: "Street" }) }), jsxRuntime.jsx(antd.Form.Item, { label: "Billing city", name: "billingCity", children: jsxRuntime.jsx(antd.Input, { placeholder: "City" }) }), jsxRuntime.jsx(FormBillingState, {}), jsxRuntime.jsx(antd.Form.Item, { label: "Billing country", name: "billingCountry", rules: [{ required: true }], children: jsxRuntime.jsx(antd.Select, { options: common.Lists.COUNTRY_LIST, placeholder: "Select a country", showSearch: true, filterOption: (input, option) => {
22338
- var _a, _b;
22339
- return ((_a = option === null || option === void 0 ? void 0 : option.label) !== null && _a !== void 0 ? _a : '').toLowerCase().includes(input.toLowerCase()) ||
22340
- ((_b = option === null || option === void 0 ? void 0 : option.value) !== null && _b !== void 0 ? _b : '').toLowerCase().includes(input.toLowerCase());
22341
- } }) }), jsxRuntime.jsx(antd.Form.Item, { label: "Billing zip", name: "billingZip", children: jsxRuntime.jsx(antd.Input, { placeholder: "Zip" }) }), jsxRuntime.jsx(antd.Form.Item, { children: jsxRuntime.jsx(antd.Button, { className: "bunny-w-full", disabled: isUpdatingAccount, htmlType: "submit", type: "primary", children: "Submit" }) })] }));
22342
- };
22343
- const FormBillingState = () => {
22344
- const billingCountry = antd.Form.useWatch('billingCountry');
22345
- const billingStateRequired = COUNTRIES_REQUIRING_STATE.includes(billingCountry);
22346
- return (jsxRuntime.jsx(antd.Form.Item, { label: "Billing state", name: "billingState", rules: [{ required: billingStateRequired }], children: jsxRuntime.jsx(antd.Input, { placeholder: "State" }) }));
22347
- };
22348
-
22349
- const showSuccessNotification = common.useSuccessNotification();
22350
- const QuoteCheckout = ({ account, onSuccess, onFail, quote, taxationRequiredAccountFields, onRecalculateTaxes, }) => {
22351
- var _a, _b;
22352
- const { apiHost } = react.useContext(BunnyContext);
22353
- const { upgradingSubscription } = react.useContext(SubscriptionsContext);
22354
- const token = useToken();
22355
- const isMobile = common.useIsMobile();
22356
- const [isSaving, setIsSaving] = react.useState(false);
22357
- const paymentRequired = getQuoteAmountDue(quote) > 0;
22358
- const queryClient = reactQuery.useQueryClient();
22359
- const [couponCode, setCouponCode] = react.useState('');
22360
- const { addCoupon, removeCoupon, isAddingCoupon, isRemovingCoupon, activeCouponsExist } = useUpdateCoupons({
22361
- apiHost,
22362
- token,
22363
- quoteChangeId: (_a = quote.quoteChanges[quote.quoteChanges.length - 1]) === null || _a === void 0 ? void 0 : _a.id,
22364
- onCouponAdded: () => {
22365
- queryClient.invalidateQueries({
22366
- queryKey: common.QueryKeyFactory.default.createObjectKey({
22367
- id: quote === null || quote === void 0 ? void 0 : quote.id,
22368
- objectName: 'editingQuote',
22369
- token,
22370
- }),
22271
+ const createQuote = reactQuery.useMutation({
22272
+ mutationFn: (subscriptionId) => quoteSubscriptionUpdate([subscriptionId], apiHost, token),
22273
+ onSuccess: quote => {
22274
+ var _a, _b, _c;
22275
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id))
22276
+ throw new Error('quote id is required');
22277
+ setEditingQuoteData({
22278
+ id: quote === null || quote === void 0 ? void 0 : quote.id,
22279
+ isTrial: (subscription === null || subscription === void 0 ? void 0 : subscription.state) === 'TRIAL',
22371
22280
  });
22372
- showSuccessNotification('Coupon applied');
22373
- onRecalculateTaxes();
22374
- setCouponCode('');
22375
- },
22376
- onCouponRemoved: () => {
22377
- queryClient.invalidateQueries({
22378
- queryKey: common.QueryKeyFactory.default.createObjectKey({
22379
- id: quote === null || quote === void 0 ? void 0 : quote.id,
22380
- objectName: 'editingQuote',
22381
- token,
22382
- }),
22281
+ const quoteChange = (_a = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _a === void 0 ? void 0 : _a.find(quoteChange => { var _a, _b; return ((_a = quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.priceList) === null || _a === void 0 ? void 0 : _a.id) === ((_b = subscription.priceList) === null || _b === void 0 ? void 0 : _b.id); });
22282
+ const subscriptionCharge = (_c = (_b = quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.subscription) === null || _b === void 0 ? void 0 : _b.charges) === null || _c === void 0 ? void 0 : _c.find(subscriptionCharge => { var _a; return ((_a = subscriptionCharge === null || subscriptionCharge === void 0 ? void 0 : subscriptionCharge.priceListCharge) === null || _a === void 0 ? void 0 : _a.id) === charge.priceListChargeId; });
22283
+ if (!(quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.id))
22284
+ throw new Error('quoteChange id is required');
22285
+ if (!(subscriptionCharge === null || subscriptionCharge === void 0 ? void 0 : subscriptionCharge.id))
22286
+ throw new Error('subscriptionCharge id is required');
22287
+ createCharge({
22288
+ apiHost,
22289
+ quantity,
22290
+ quoteChangeId: quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.id,
22291
+ startDate: formatDateForApi(dayjs()),
22292
+ subscriptionChargeId: subscriptionCharge.id,
22293
+ token,
22383
22294
  });
22384
- showSuccessNotification('Coupon removed');
22385
- onRecalculateTaxes();
22386
22295
  },
22387
22296
  });
22388
- const couponsOnQuote = (_b = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _b === void 0 ? void 0 : _b.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'); });
22389
- const checkoutMutation = reactQuery.useMutation({
22390
- mutationFn: async () => {
22391
- if (!quote)
22392
- throw new Error('Quote is required');
22393
- if (paymentRequired)
22394
- throw new Error('Payment is required');
22395
- return await checkout({ quoteId: quote.id, token, apiHost });
22297
+ const updateQuoteCharge = reactQuery.useMutation({
22298
+ mutationFn: ({ quoteChargeId, quantity }) => quoteChargeUpdate$1(quoteChargeId, quantity, apiHost, token),
22299
+ onSuccess: response => {
22300
+ var _a;
22301
+ const quote = (_a = response === null || response === void 0 ? void 0 : response.quoteChange) === null || _a === void 0 ? void 0 : _a.quote;
22302
+ if (!editingQuoteId)
22303
+ throw new Error('editingQuoteId is required');
22304
+ setQuoteQueryData(editingQuoteId, quote !== null && quote !== void 0 ? quote : null);
22305
+ setErrorUpdatingQuantity(false);
22306
+ },
22307
+ onError: () => {
22308
+ setErrorUpdatingQuantity(true);
22396
22309
  },
22397
- onSuccess,
22398
- onError: onFail,
22399
22310
  });
22400
- async function handleCheckoutNoPayment() {
22401
- setIsSaving(true);
22402
- checkoutMutation.mutate();
22403
- setIsSaving(false);
22404
- }
22405
- if (taxationRequiredAccountFields)
22406
- return (jsxRuntime.jsx(PaymentFormWrapper, { setMaxHeight: false, children: jsxRuntime.jsx(TaxationForm, { account: account, quote: quote }) }));
22407
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: paymentRequired ? (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2 bunny-w-full", children: [jsxRuntime.jsx(PaymentForm, { onFail: onFail, onPaymentSuccess: onSuccess, quote: quote }), (couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.length) === 0 ? (jsxRuntime.jsx(jsxRuntime.Fragment, { children: upgradingSubscription &&
22408
- shouldShowCouponEditor(quote, activeCouponsExist, upgradingSubscription) && (jsxRuntime.jsx(CouponEditor, { className: "bunny-px-4 bunny-pt-1", quote: quote, onAddCoupon: addCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode })) })) : (jsxRuntime.jsx(antd.Button, { type: "link", loading: isRemovingCoupon, onClick: () => {
22409
- couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.forEach(couponCharge => {
22410
- var _a;
22411
- const couponCode = (_a = couponCharge === null || couponCharge === void 0 ? void 0 : couponCharge.coupon) === null || _a === void 0 ? void 0 : _a.couponCode;
22412
- if (couponCode) {
22413
- removeCoupon(couponCode);
22414
- }
22415
- });
22416
- }, children: "Remove coupon(s)" }))] })) : (jsxRuntime.jsx(PaymentFormWrapper, { setMaxHeight: false, children: jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-2 bunny-px-4 ${isMobile ? 'bunny-shadow-padding-x' : ''}`, children: [jsxRuntime.jsx(antd.Button, { onClick: handleCheckoutNoPayment, type: "primary", children: isSaving ? 'Processing...' : 'Complete order' }), jsxRuntime.jsx("div", { className: "bunny-text-xs bunny-text-slate-500", children: "No payment is required" })] }) })) }));
22311
+ const onChangeQuantity = (value) => {
22312
+ var _a;
22313
+ // Handle empty string - don't convert to 0, keep it as undefined
22314
+ const quantity = value === '' ? undefined : isNaN(parseInt(value)) ? 0 : parseInt(value);
22315
+ setQuantity(quantity);
22316
+ if (quantity === undefined) {
22317
+ setUpdatingChargeQuantityId(undefined);
22318
+ }
22319
+ else {
22320
+ if (!(charge === null || charge === void 0 ? void 0 : charge.priceListChargeId)) {
22321
+ showErrorNotification('Charge ID is not found');
22322
+ return;
22323
+ }
22324
+ // The set charge id is used to disable all other quantity inputs
22325
+ setUpdatingChargeQuantityId(getUpdatingChargeQuantityId(charge.priceListChargeId, subscription.id));
22326
+ // if (quantity === charge.quantity) {
22327
+ // showErrorNotification('New quantity cannot be the same as current');
22328
+ // } else {
22329
+ // }
22330
+ const quantityDelta = quantity - ((_a = charge.quantity) !== null && _a !== void 0 ? _a : 0);
22331
+ debouncedQuantityUpdate.cancel();
22332
+ debouncedQuantityUpdate(charge.priceListChargeId, quantityDelta, subscription.id, editingQuote, // TODO: do not cast as Quote
22333
+ editingQuoteId);
22334
+ }
22335
+ };
22336
+ const debouncedQuantityUpdate = react.useCallback(lodashExports.debounce((priceListChargeId, quantityDelta, subscriptionId, quote, editingQuoteId) => {
22337
+ if (quantityDelta === 0) {
22338
+ setErrorUpdatingQuantity(true);
22339
+ showErrorNotification('New quantity cannot be the same as current');
22340
+ return;
22341
+ }
22342
+ // If we are not editing a quote, we create a new one
22343
+ if (editingQuoteId === undefined) {
22344
+ createQuote.mutate(subscriptionId);
22345
+ }
22346
+ else {
22347
+ const quoteChange = quote === null || quote === void 0 ? void 0 : quote.quoteChanges.find(quoteChange => { var _a; return quoteChange.priceList.id === ((_a = subscription.priceList) === null || _a === void 0 ? void 0 : _a.id); });
22348
+ const quoteCharge = quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.charges.find(charge => charge.priceListCharge.id === priceListChargeId);
22349
+ if (quoteCharge) {
22350
+ updateQuoteCharge.mutate({
22351
+ quoteChargeId: quoteCharge.id,
22352
+ quantity: quantityDelta,
22353
+ });
22354
+ }
22355
+ }
22356
+ }, DEBOUNCE_TIME), []);
22357
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(antd.Input, { className: "bunny-text-right", disabled: quantityDisabled, onChange: e => {
22358
+ onChangeQuantity(e.target.value);
22359
+ }, style: { width: '96px' }, value: value }) }));
22417
22360
  };
22418
- const PaymentFormWrapper = ({ children, setMaxHeight, className, }) => {
22419
- const isMobile = common.useIsMobile();
22420
- return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-w-full bunny-flex-col bunny-gap-6 ${isMobile ? 'bunny-shadow-padding-xb' : ''} ${className}`, style: {
22421
- ...(isMobile
22422
- ? setMaxHeight
22423
- ? { maxHeight: '60vh' }
22424
- : {}
22425
- : {
22426
- width: '100%',
22427
- maxWidth: '350px',
22428
- }),
22429
- }, children: children }));
22361
+
22362
+ const QuantityChangeGridRow_SubscriptionChargeFragment = t(`
22363
+ fragment QuantityChangeGridRow_SubscriptionChargeFragment on SubscriptionCharge {
22364
+ id
22365
+ quantity
22366
+ name
22367
+ ...QuantityInput_SubscriptionChargeFragment
22368
+ ...CanShowQuantitiesInput_SubscriptionChargeFragment
22369
+ }
22370
+ `, [QuantityInput_SubscriptionChargeFragment, CanShowQuantitiesInput_SubscriptionChargeFragment]);
22371
+ const QuantityChangeGridRow_SubscriptionFragment = t(`
22372
+ fragment QuantityChangeGridRow_SubscriptionFragment on Subscription {
22373
+ id
22374
+ priceList {
22375
+ id
22376
+ }
22377
+ plan {
22378
+ name
22379
+ }
22380
+ chargeReport {
22381
+ ...QuantityChangeGridRow_SubscriptionChargeFragment
22382
+ ...CanShowQuantitiesInput_SubscriptionChargeFragment
22383
+ }
22384
+ ...QuantityInput_SubscriptionFragment
22385
+ ...CanShowQuantitiesInput_SubscriptionFragment
22386
+ }
22387
+ `, [
22388
+ QuantityChangeGridRow_SubscriptionChargeFragment,
22389
+ CanShowQuantitiesInput_SubscriptionChargeFragment,
22390
+ CanShowQuantitiesInput_SubscriptionFragment,
22391
+ QuantityInput_SubscriptionFragment,
22392
+ ]);
22393
+ const { Text: Text$k } = antd.Typography;
22394
+ const QuantityChangeGridRow = ({ editingQuote, editingQuoteId, setEditingQuoteData, subscription: maskedSubscription, subscriptionCharge: maskedSubscriptionCharge, setUpdatingChargeQuantityId, updatingChargeQuantityId, setErrorUpdatingQuantity, }) => {
22395
+ var _a, _b;
22396
+ const subscription = readFragment(QuantityChangeGridRow_SubscriptionFragment, maskedSubscription);
22397
+ const charge = readFragment(QuantityChangeGridRow_SubscriptionChargeFragment, maskedSubscriptionCharge);
22398
+ if (!canShowQuantitiesInput({ charge, subscription }))
22399
+ return null;
22400
+ const { brandColor } = react.useContext(BrandContext);
22401
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-1", children: [jsxRuntime.jsx(Text$k, { className: "bunny-font-medium bunny-text-sm bunny-col-span-full", style: { color: brandColor }, children: (_a = subscription === null || subscription === void 0 ? void 0 : subscription.plan) === null || _a === void 0 ? void 0 : _a.name }), jsxRuntime.jsx(Text$k, { className: "bunny-text-sm", children: (_b = charge.name) === null || _b === void 0 ? void 0 : _b.toUpperCase() })] }), jsxRuntime.jsx(Text$k, { className: "bunny-flex bunny-items-center bunny-justify-end bunny-font-medium bunny-text-sm bunny-text-gray-900", children: charge.quantity }), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-justify-center bunny-items-end", children: [jsxRuntime.jsx(QuantityInput, { charge: charge, editingQuote: editingQuote, editingQuoteId: editingQuoteId, setEditingQuoteData: setEditingQuoteData, subscription: subscription, setUpdatingChargeQuantityId: setUpdatingChargeQuantityId, updatingChargeQuantityId: updatingChargeQuantityId, setErrorUpdatingQuantity: setErrorUpdatingQuantity }), jsxRuntime.jsx("div", {})] }), jsxRuntime.jsx(antd.Divider, { className: "bunny-col-span-full bunny-my-2" })] }));
22430
22402
  };
22431
22403
 
22432
- const queryKeyFactory = common.QueryKeyFactory.default;
22433
- const Checkout = ({ onCancel, onSuccess, onFail, invoice, open, quote, isUpdatingQuote, }) => {
22434
- var _a, _b;
22404
+ const { Text: Text$j } = antd.Typography;
22405
+ const QuantityChangeGridTitle = ({ children, right }) => (jsxRuntime.jsx(Text$j, { className: `bunny-font-medium bunny-text-sm bunny-text-slate-600 ${right ? 'bunny-text-right' : 'bunny-text-left'}`, children: children }));
22406
+
22407
+ const QuoteChangeSummarySection = ({ editingQuote, editingQuoteData, openCheckout, setEditingQuoteData, errorUpdatingQuantity, }) => {
22435
22408
  const { apiHost } = react.useContext(BunnyContext);
22436
22409
  const isMobile = common.useIsMobile();
22437
22410
  const token = useToken();
22438
- const hasTaxPlugin = useHasTaxPlugin({
22439
- apiHost,
22440
- token,
22441
- });
22442
- const queryClient = reactQuery.useQueryClient();
22443
- // Queries
22444
- const { data: taxationRequiredAccountFields, isLoading: isLoadingTaxationRequiredAccountFields } = reactQuery.useQuery({
22445
- queryKey: ['getTaxationRequiredAccountFields', token],
22446
- queryFn: () => getTaxationRequiredAccountFields({ apiHost, token }),
22447
- enabled: Boolean(quote),
22448
- staleTime: 0,
22449
- });
22450
- const { data: account, isLoading: isLoadingAccount } = reactQuery.useQuery({
22451
- queryKey: ['account', quote === null || quote === void 0 ? void 0 : quote.accountId],
22452
- queryFn: () => (quote === null || quote === void 0 ? void 0 : quote.accountId) &&
22453
- common.getAccount({ id: quote.accountId, apiHost, token, componentsVersion: PACKAGE_VERSION }),
22454
- enabled: Boolean(quote === null || quote === void 0 ? void 0 : quote.accountId) && ((taxationRequiredAccountFields === null || taxationRequiredAccountFields === void 0 ? void 0 : taxationRequiredAccountFields.length) || 0) > 0,
22411
+ const showSuccessNotification = common.useSuccessNotification();
22412
+ const trialUpgradeMutation = reactQuery.useMutation({
22413
+ mutationFn: (quoteId) => checkout({ quoteId, token, apiHost }),
22414
+ onSuccess: () => {
22415
+ setEditingQuoteData(undefined);
22416
+ showSuccessNotification('Subscription updated successfully');
22417
+ },
22455
22418
  });
22456
- async function recalculateTaxes() {
22457
- if (quote) {
22458
- const updatedQuote = await quoteRecalculateTaxes({
22459
- quoteId: quote.id,
22460
- apiHost,
22461
- token,
22462
- });
22463
- if (updatedQuote) {
22464
- const quoteKey = queryKeyFactory.createObjectKey({
22465
- id: updatedQuote.id,
22466
- objectName: 'editingQuote',
22467
- token,
22468
- });
22469
- queryClient.setQueryData(quoteKey, updatedQuote);
22470
- }
22471
- }
22472
- return {};
22419
+ const disabled = !editingQuoteData || !editingQuote || errorUpdatingQuantity;
22420
+ return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-items-end", children: [editingQuote && !disabled && (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-mb-8", children: [jsxRuntime.jsx("div", { className: "bunny-text-slate-500 bunny-text-right bunny-text-xs bunny-mb-2", children: "TOTAL" }), jsxRuntime.jsx("div", { className: `bunny-text-right ${isMobile ? 'bunny-text-2xl' : 'bunny-text-xl'}`, children: common.formatCurrency(getQuoteAmountDue(editingQuote), (editingQuote === null || editingQuote === void 0 ? void 0 : editingQuote.currencyId) || '') })] })), jsxRuntime.jsx("div", { className: `bunny-flex bunny-items-center bunny-justify-end ${isMobile ? 'bunny-w-full' : ''}`, children: jsxRuntime.jsx(antd.Button, { className: "bunny-w-full", onClick: (editingQuoteData === null || editingQuoteData === void 0 ? void 0 : editingQuoteData.isTrial)
22421
+ ? () => trialUpgradeMutation.mutate(editingQuoteData.id)
22422
+ : openCheckout, disabled: disabled, size: isMobile ? 'large' : 'middle', type: "primary", children: (editingQuoteData === null || editingQuoteData === void 0 ? void 0 : editingQuoteData.isTrial) ? 'Activate Trial' : 'Proceed to checkout' }) })] }));
22423
+ };
22424
+
22425
+ const QUANTITY_CHANGE_HEADER_TITLE = 'Update quantities';
22426
+ const QUANTITY_CHANGE_HEADER_DESCRIPTION = 'Adjust quantities below. The change will take effect immediately after checkout has been completed.';
22427
+ const QuantityDrawerDesktop_SubscriptionFragment = t(`
22428
+ fragment QuantityDrawerDesktop_SubscriptionFragment on Subscription {
22429
+ currentCharges {
22430
+ chargeType
22431
+ ...QuantityChangeGridRow_SubscriptionChargeFragment
22432
+ }
22433
+ ...QuantityChangeGridRow_SubscriptionFragment
22473
22434
  }
22474
- const recalculateTaxesEnabled = Boolean(quote) &&
22475
- open &&
22476
- hasTaxPlugin &&
22477
- !taxationRequiredAccountFields &&
22478
- !isLoadingTaxationRequiredAccountFields &&
22479
- !isUpdatingQuote;
22480
- reactQuery.useQuery({
22481
- queryKey: queryKeyFactory.createQuoteTaxCalculateKey({
22482
- id: quote === null || quote === void 0 ? void 0 : quote.id,
22483
- token,
22484
- }),
22485
- queryFn: recalculateTaxes,
22486
- // Recalculate taxes if the quote is open, has a tax plugin, and the taxation required account fields are not required
22487
- enabled: recalculateTaxesEnabled,
22488
- staleTime: 0,
22489
- });
22490
- if (!open || isLoadingTaxationRequiredAccountFields || isLoadingAccount)
22435
+ `, [QuantityChangeGridRow_SubscriptionFragment, QuantityChangeGridRow_SubscriptionChargeFragment]);
22436
+ const QuantityChangeDrawerDesktop = ({ editingQuote, editingQuoteData, onClose, open, openCheckout, setEditingQuoteData, subscriptions, setUpdatingChargeQuantityId, updatingChargeQuantityId, }) => {
22437
+ const [openLocal, setOpenLocal] = react.useState(open);
22438
+ const [errorUpdatingQuantity, setErrorUpdatingQuantity] = react.useState(false);
22439
+ const isMobile = common.useIsMobile();
22440
+ react.useEffect(() => {
22441
+ let timeoutId;
22442
+ if (!open) {
22443
+ timeoutId = setTimeout(() => {
22444
+ setOpenLocal(false);
22445
+ }, 300); // Delay to allow for close animation
22446
+ }
22447
+ else {
22448
+ setOpenLocal(true);
22449
+ }
22450
+ return () => clearTimeout(timeoutId);
22451
+ }, [open]);
22452
+ if (!openLocal)
22491
22453
  return null;
22492
- return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-flex-col bunny-fixed bunny-top-0 bunny-left-0 bunny-right-0 bunny-bottom-0 bunny-bg-slate-50
22493
- bunny-overflow-auto bunny-height-full`, style: {
22494
- zIndex: 1001,
22495
- }, children: jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-grow bunny-pt-4 ${isMobile ? 'bunny-pb-4' : 'bunny-pb-8'} bunny-content-container`, children: [jsxRuntime.jsx("div", { className: "bunny-flex bunny-justify-end bunny-w-full bunny-pr-4", children: jsxRuntime.jsx(icons.CloseOutlined, { className: "bunny-text-base bunny-shadow-padding-xb", onClick: onCancel }) }), jsxRuntime.jsxs("div", { className: `bunny-flex bunny-justify-end bunny-pt-4 bunny-gap-4 ${isMobile ? 'bunny-flex-col' : 'bunny-shadow-padding-xb'}`, children: [((invoice === null || invoice === void 0 ? void 0 : invoice.html) || ((_a = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _a === void 0 ? void 0 : _a.html)) && (jsxRuntime.jsx(InvoiceQuoteView, { html: invoice ? invoice.html : quote ? quote.formattedQuote.html : '' })), !isMobile && ((invoice === null || invoice === void 0 ? void 0 : invoice.html) || ((_b = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _b === void 0 ? void 0 : _b.html)) && (jsxRuntime.jsx(antd.Divider, { className: "bunny-h-full", type: "vertical" })), invoice ? (jsxRuntime.jsx("div", { className: "bunny-w-full bunny-pt-12", children: jsxRuntime.jsx(PaymentForm, { onPaymentSuccess: onSuccess, onFail: onFail, invoice: invoice }) })) : quote ? (jsxRuntime.jsx(QuoteCheckout, { account: account, onFail: error => {
22496
- onFail(error);
22497
- }, onSuccess: onSuccess, quote: quote, taxationRequiredAccountFields: taxationRequiredAccountFields, token: token, onRecalculateTaxes: async () => {
22498
- if (recalculateTaxesEnabled) {
22499
- await recalculateTaxes();
22500
- }
22501
- } })) : (jsxRuntime.jsx(PaymentForm, { onFail: error => {
22502
- onFail(error);
22503
- }, onPaymentSuccess: onSuccess }))] }), jsxRuntime.jsx(Footer, { className: "bunny-px-12" })] }) }));
22454
+ return (jsxRuntime.jsxs(antd.Drawer, { closeIcon: null, destroyOnHidden: true, onClose: onClose, open: open, styles: isMobile
22455
+ ? {
22456
+ body: {
22457
+ padding: '1rem',
22458
+ background: common.SLATE_50,
22459
+ },
22460
+ wrapper: {
22461
+ width: '100vw',
22462
+ },
22463
+ }
22464
+ : {
22465
+ wrapper: {
22466
+ minWidth: '600px',
22467
+ },
22468
+ }, title: jsxRuntime.jsx(DrawerHeader, { description: QUANTITY_CHANGE_HEADER_DESCRIPTION, onClose: onClose, title: QUANTITY_CHANGE_HEADER_TITLE, closeButtonClassName: "ant-drawer-close" }), children: [jsxRuntime.jsxs("div", { className: "bunny-grid bunny-pb-2", style: {
22469
+ gridTemplateColumns: '3fr 3fr 2fr',
22470
+ rowGap: '0.25rem',
22471
+ columnGap: '1rem',
22472
+ }, children: [jsxRuntime.jsx(QuantityChangeGridTitle, { children: " " }), jsxRuntime.jsx(QuantityChangeGridTitle, { right: true, children: "CURRENT QUANTITY" }), jsxRuntime.jsx(QuantityChangeGridTitle, { right: true, children: "NEW QUANTITY" }), jsxRuntime.jsx(antd.Divider, { className: "bunny-col-span-full", style: { marginBottom: '8px', marginTop: '20px' } }), subscriptions.map((maskedSubscription, index) => {
22473
+ var _a;
22474
+ const subscription = readFragment(QuantityDrawerDesktop_SubscriptionFragment, maskedSubscription);
22475
+ return (jsxRuntime.jsx("div", { className: "bunny-contents", children: (_a = subscription === null || subscription === void 0 ? void 0 : subscription.currentCharges) === null || _a === void 0 ? void 0 : _a.map((charge, chargeIndex) => {
22476
+ if (charge.chargeType === 'USAGE')
22477
+ return null;
22478
+ return (jsxRuntime.jsx(QuantityChangeGridRow, { editingQuote: editingQuote, editingQuoteId: editingQuoteData === null || editingQuoteData === void 0 ? void 0 : editingQuoteData.id, setEditingQuoteData: setEditingQuoteData, subscription: subscription, subscriptionCharge: charge, setUpdatingChargeQuantityId: setUpdatingChargeQuantityId, updatingChargeQuantityId: updatingChargeQuantityId, setErrorUpdatingQuantity: setErrorUpdatingQuantity }, chargeIndex));
22479
+ }) }, index));
22480
+ })] }), jsxRuntime.jsx(QuoteChangeSummarySection, { editingQuote: editingQuote, editingQuoteData: editingQuoteData, openCheckout: openCheckout, setEditingQuoteData: setEditingQuoteData, errorUpdatingQuantity: errorUpdatingQuantity })] }));
22504
22481
  };
22505
22482
 
22506
22483
  function invalidateSubscriptionsQueryKeys(queryClient, token) {
@@ -22524,26 +22501,41 @@ function invalidateSubscriptionsQueryKeys(queryClient, token) {
22524
22501
  });
22525
22502
  }
22526
22503
 
22527
- const QuantityDrawerContainer = ({ subscriptions, quantityDrawerOpen, setQuantityDrawerOpen, handlePortalErrors, setShowInactive, }) => {
22528
- const { apiHost } = react.useContext(BunnyContext);
22504
+ const useQuoteQueryData = (quoteId) => {
22529
22505
  const token = useToken();
22530
- const queryClient = reactQuery.useQueryClient();
22531
- const showSuccessNotification = common.useSuccessNotification();
22532
- // State management
22533
- const [editingQuoteData, setEditingQuoteData] = react.useState();
22534
- const [payModalVisible, setPayModalVisible] = react.useState(false);
22535
- const [updatingChargeQuantityId, setUpdatingChargeQuantityId] = react.useState(undefined);
22536
- // Quote query
22537
22506
  const { data } = reactQuery.useQuery({
22538
22507
  queryKey: common.QueryKeyFactory.default.createObjectKey({
22539
- id: editingQuoteData === null || editingQuoteData === void 0 ? void 0 : editingQuoteData.id,
22508
+ id: quoteId,
22540
22509
  objectName: 'editingQuote',
22541
22510
  token,
22542
22511
  }),
22543
- queryFn: () => (editingQuoteData === null || editingQuoteData === void 0 ? void 0 : editingQuoteData.id) ? getQuote$1({ token, id: editingQuoteData.id, apiHost }) : undefined,
22544
- enabled: Boolean(editingQuoteData === null || editingQuoteData === void 0 ? void 0 : editingQuoteData.id),
22512
+ queryFn: () => {
22513
+ // This queryFn should never be called if data is set via setQueryData
22514
+ // If called, it means data doesn't exist - return undefined
22515
+ // In practice, data should always be set via setQueryData before this hook is used
22516
+ return undefined;
22517
+ },
22518
+ enabled: false,
22519
+ staleTime: Infinity, // Never consider data stale, only use cache
22520
+ gcTime: Infinity, // Never garbage collect this data
22521
+ // Don't refetch if data exists in cache
22522
+ refetchOnMount: false,
22523
+ refetchOnWindowFocus: false,
22524
+ refetchOnReconnect: false,
22545
22525
  });
22546
- const quote = data;
22526
+ return data;
22527
+ };
22528
+
22529
+ const QuantityDrawer = ({ subscriptions, quantityDrawerOpen, setQuantityDrawerOpen, handlePortalErrors, setShowInactive, }) => {
22530
+ const token = useToken();
22531
+ const queryClient = reactQuery.useQueryClient();
22532
+ const showSuccessNotification = common.useSuccessNotification();
22533
+ // State management
22534
+ const [editingQuoteData, setEditingQuoteData] = react.useState();
22535
+ const [payModalVisible, setPayModalVisible] = react.useState(false);
22536
+ const [updatingChargeQuantityId, setUpdatingChargeQuantityId] = react.useState(undefined);
22537
+ const maskedQuote = useQuoteQueryData(editingQuoteData === null || editingQuoteData === void 0 ? void 0 : editingQuoteData.id);
22538
+ const quote = readFragment(QuantityDrawer_QuoteFragment, maskedQuote);
22547
22539
  // Handlers
22548
22540
  const onSuccess = () => {
22549
22541
  setQuantityDrawerOpen(false);
@@ -23618,6 +23610,58 @@ const SubscriptionsListContainer = ({ companyName, showInactive = false, onCance
23618
23610
 
23619
23611
  const QuoteContext = react.createContext({});
23620
23612
 
23613
+ const quoteSubscriptionUpgrade = ({ subscriptionId, priceListId, apiHost, token, }) => {
23614
+ return gqlRequest({
23615
+ query: `mutation QuoteSubscriptionUpgrade($subscriptionId: ID!, $priceListId: ID!) {
23616
+ quoteSubscriptionUpgrade(
23617
+ subscriptionId: $subscriptionId
23618
+ priceListId: $priceListId
23619
+ ) {
23620
+ quote {
23621
+ id
23622
+ }
23623
+ }
23624
+ }`,
23625
+ vars: { subscriptionId, priceListId },
23626
+ apiHost,
23627
+ token,
23628
+ });
23629
+ };
23630
+ const quoteSubscriptionAddon = ({ subscriptionId, priceListId, apiHost, token, }) => {
23631
+ return gqlRequest({
23632
+ query: `mutation QuoteSubscriptionAddon($subscriptionId: ID!, $priceListId: ID) {
23633
+ quoteSubscriptionAddon(subscriptionId: $subscriptionId, priceListId: $priceListId) {
23634
+ errors
23635
+ quote {
23636
+ id
23637
+ }
23638
+ }
23639
+ }`,
23640
+ vars: {
23641
+ subscriptionId,
23642
+ priceListId,
23643
+ },
23644
+ apiHost,
23645
+ token,
23646
+ });
23647
+ };
23648
+ const quoteSubscriptionActivate = ({ subscriptionId, apiHost, token, }) => {
23649
+ return gqlRequest({
23650
+ query: `mutation QuoteSubscriptionActivate($subscriptionId: ID!) {
23651
+ quoteSubscriptionActivate(subscriptionId: $subscriptionId) {
23652
+ quote {
23653
+ id
23654
+ }
23655
+ }
23656
+ }`,
23657
+ vars: {
23658
+ subscriptionId,
23659
+ },
23660
+ apiHost,
23661
+ token,
23662
+ });
23663
+ };
23664
+
23621
23665
  const FormattedQuoteFields_QuoteFragment = t(`
23622
23666
  fragment FormattedQuoteFields_QuoteFragment on Quote {
23623
23667
  formattedQuote {
@@ -24594,6 +24638,52 @@ const PriceListCard = ({ hideButton, isSelected, priceList, subscriptions, trial
24594
24638
  disableOnClickPriceListCard: disableSelectCurrentPlan, onClickPriceListCard: onClickPriceListCard })) : (jsxRuntime.jsx(PriceListCardDesktop, { hideButton: hideButton, description: description, disableSelectCurrentPlan: disableSelectCurrentPlan, feature: feature, isPriceListCurrentSubscription: isPriceListCurrentSubscription, isSelected: isSelected, priceList: priceList, trialRemainingDays: trialRemainingDays, subscriptionPlan: subscriptionPlan, noBorder: noBorder, onClickPriceListCard: onClickPriceListCard }));
24595
24639
  };
24596
24640
 
24641
+ const QUOTE_CHARGE_CREATE = `
24642
+ ${QUOTE_FIELDS()}
24643
+ mutation QuoteChargeCreate ($quoteChangeId: ID!, $startDate: ISO8601Date!, $endDate: ISO8601Date, $priceListChargeId: ID, $subscriptionChargeId: ID, $price: Float, $quantity: Int) {
24644
+ quoteChargeCreate(
24645
+ endDate: $endDate
24646
+ price: $price
24647
+ priceListChargeId: $priceListChargeId
24648
+ quantity: $quantity
24649
+ quoteChangeId: $quoteChangeId
24650
+ startDate: $startDate
24651
+ subscriptionChargeId: $subscriptionChargeId
24652
+ ) {
24653
+ quoteCharge {
24654
+ quoteChange {
24655
+ id
24656
+ quoteId
24657
+ quote {
24658
+ ...QuoteFields
24659
+ }
24660
+ }
24661
+ id
24662
+ }
24663
+ }
24664
+ }
24665
+
24666
+ `;
24667
+ const quoteChargeCreate = async ({ price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId, token, apiHost, }) => {
24668
+ const response = await gqlRequest({
24669
+ query: QUOTE_CHARGE_CREATE,
24670
+ vars: {
24671
+ price,
24672
+ priceListChargeId,
24673
+ quantity,
24674
+ quoteChangeId,
24675
+ startDate,
24676
+ subscriptionChargeId,
24677
+ },
24678
+ apiHost,
24679
+ token,
24680
+ });
24681
+ if (response.errors) {
24682
+ throw new Error(response.errors[0].message);
24683
+ }
24684
+ return response.quoteChargeCreate.quoteCharge;
24685
+ };
24686
+
24597
24687
  const mutation = t(`
24598
24688
  mutation QuoteChargeDelete($quoteChargeId: ID!) {
24599
24689
  quoteChargeDelete(quoteChargeId: $quoteChargeId) {
@@ -25803,7 +25893,7 @@ const Subscriptions = ({ handlePortalErrors, companyName, noSubscriptionsCompone
25803
25893
  setIsChangingPlan(false);
25804
25894
  }, handlePortalErrors: handlePortalErrors, upgradingSubscription: upgradingSubscription, className: className, shadow: shadow }));
25805
25895
  }
25806
- return (jsxRuntime.jsxs("div", { className: className, children: [jsxRuntime.jsx(PageHeaderWithActions, { title: jsxRuntime.jsx(jsxRuntime.Fragment, { children: !showInactiveSubscriptionsToggle && isMobile && inactiveSwitchVisible && (jsxRuntime.jsx(ShowInactiveToggle, { showInactive: showInactiveSubscriptions, setShowInactive: setShowInactiveSubscriptionsState })) }), children: !isMobile && ((_f = subscriptionsData === null || subscriptionsData === void 0 ? void 0 : subscriptionsData.subscriptions) === null || _f === void 0 ? void 0 : _f.nodes) && (jsxRuntime.jsx(SubscriptionsNavigation, { inactiveSwitchVisible: !showInactiveSubscriptionsToggle && inactiveSwitchVisible, showInactive: showInactiveSubscriptions, setShowInactive: setShowInactiveSubscriptionsState, setQuantityDrawerOpen: setQuantityDrawerOpen, subscriptions: (_g = subscriptionsData === null || subscriptionsData === void 0 ? void 0 : subscriptionsData.subscriptions) === null || _g === void 0 ? void 0 : _g.nodes })) }), jsxRuntime.jsx(SubscriptionsListContainer, { companyName: companyName, showInactive: showInactiveSubscriptions, onCancelSubscriptionClick: onCancelSubscriptionClick, onChangePlanClick: onChangePlanClick, subscriptions: (_h = subscriptionsData === null || subscriptionsData === void 0 ? void 0 : subscriptionsData.subscriptions) === null || _h === void 0 ? void 0 : _h.nodes, subscriptionsAreLoading: subscriptionsAreLoading, noSubscriptionsComponent: noSubscriptionsComponent }), isMobile && ((_j = subscriptionsData === null || subscriptionsData === void 0 ? void 0 : subscriptionsData.subscriptions) === null || _j === void 0 ? void 0 : _j.nodes) && (jsxRuntime.jsx("div", { className: "bunny-pt-4 bunny-pb-2", children: jsxRuntime.jsx(SubscriptionsNavigation, { inactiveSwitchVisible: inactiveSwitchVisible, showInactive: showInactiveSubscriptions, setShowInactive: setShowInactiveSubscriptionsState, setQuantityDrawerOpen: setQuantityDrawerOpen, subscriptions: (_k = subscriptionsData === null || subscriptionsData === void 0 ? void 0 : subscriptionsData.subscriptions) === null || _k === void 0 ? void 0 : _k.nodes }) })), ((_l = subscriptionsData === null || subscriptionsData === void 0 ? void 0 : subscriptionsData.subscriptions) === null || _l === void 0 ? void 0 : _l.nodes) && (jsxRuntime.jsx(QuantityDrawerContainer, { subscriptions: (_m = subscriptionsData === null || subscriptionsData === void 0 ? void 0 : subscriptionsData.subscriptions) === null || _m === void 0 ? void 0 : _m.nodes, quantityDrawerOpen: quantityDrawerOpen, setQuantityDrawerOpen: setQuantityDrawerOpen, handlePortalErrors: handlePortalErrors, setShowInactive: setShowInactiveSubscriptionsState }))] }));
25896
+ return (jsxRuntime.jsxs("div", { className: className, children: [jsxRuntime.jsx(PageHeaderWithActions, { title: jsxRuntime.jsx(jsxRuntime.Fragment, { children: !showInactiveSubscriptionsToggle && isMobile && inactiveSwitchVisible && (jsxRuntime.jsx(ShowInactiveToggle, { showInactive: showInactiveSubscriptions, setShowInactive: setShowInactiveSubscriptionsState })) }), children: !isMobile && ((_f = subscriptionsData === null || subscriptionsData === void 0 ? void 0 : subscriptionsData.subscriptions) === null || _f === void 0 ? void 0 : _f.nodes) && (jsxRuntime.jsx(SubscriptionsNavigation, { inactiveSwitchVisible: !showInactiveSubscriptionsToggle && inactiveSwitchVisible, showInactive: showInactiveSubscriptions, setShowInactive: setShowInactiveSubscriptionsState, setQuantityDrawerOpen: setQuantityDrawerOpen, subscriptions: (_g = subscriptionsData === null || subscriptionsData === void 0 ? void 0 : subscriptionsData.subscriptions) === null || _g === void 0 ? void 0 : _g.nodes })) }), jsxRuntime.jsx(SubscriptionsListContainer, { companyName: companyName, showInactive: showInactiveSubscriptions, onCancelSubscriptionClick: onCancelSubscriptionClick, onChangePlanClick: onChangePlanClick, subscriptions: (_h = subscriptionsData === null || subscriptionsData === void 0 ? void 0 : subscriptionsData.subscriptions) === null || _h === void 0 ? void 0 : _h.nodes, subscriptionsAreLoading: subscriptionsAreLoading, noSubscriptionsComponent: noSubscriptionsComponent }), isMobile && ((_j = subscriptionsData === null || subscriptionsData === void 0 ? void 0 : subscriptionsData.subscriptions) === null || _j === void 0 ? void 0 : _j.nodes) && (jsxRuntime.jsx("div", { className: "bunny-pt-4 bunny-pb-2", children: jsxRuntime.jsx(SubscriptionsNavigation, { inactiveSwitchVisible: inactiveSwitchVisible, showInactive: showInactiveSubscriptions, setShowInactive: setShowInactiveSubscriptionsState, setQuantityDrawerOpen: setQuantityDrawerOpen, subscriptions: (_k = subscriptionsData === null || subscriptionsData === void 0 ? void 0 : subscriptionsData.subscriptions) === null || _k === void 0 ? void 0 : _k.nodes }) })), ((_l = subscriptionsData === null || subscriptionsData === void 0 ? void 0 : subscriptionsData.subscriptions) === null || _l === void 0 ? void 0 : _l.nodes) && (jsxRuntime.jsx(QuantityDrawer, { subscriptions: (_m = subscriptionsData === null || subscriptionsData === void 0 ? void 0 : subscriptionsData.subscriptions) === null || _m === void 0 ? void 0 : _m.nodes, quantityDrawerOpen: quantityDrawerOpen, setQuantityDrawerOpen: setQuantityDrawerOpen, handlePortalErrors: handlePortalErrors, setShowInactive: setShowInactiveSubscriptionsState }))] }));
25807
25897
  };
25808
25898
  const PageHeaderWithActions = ({ children, title, }) => {
25809
25899
  const isMobile = common.useIsMobile();