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

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