@bunnyapp/components 1.8.0-beta.4 → 1.8.0-beta.6

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 (40) hide show
  1. package/dist/cjs/index.js +501 -400
  2. package/dist/cjs/types/src/ajax.d.ts +1 -1
  3. package/dist/cjs/types/src/components/Checkout/QuoteCheckout.d.ts +2 -2
  4. package/dist/cjs/types/src/components/PandadocPollingModal.d.ts +1 -1
  5. package/dist/cjs/types/src/components/Quote/Quote.d.ts +28 -1
  6. package/dist/cjs/types/src/components/Quote/components/PaymentHoldDisplay.d.ts +18 -0
  7. package/dist/cjs/types/src/components/Quote/components/QuoteButtons.d.ts +12 -4
  8. package/dist/cjs/types/src/components/Quote/hooks/{useSendAcceptQuote.d.ts → useAcceptQuote.d.ts} +6 -3
  9. package/dist/cjs/types/src/components/Quote/hooks/useQuotePaymentHold.d.ts +20 -0
  10. package/dist/{esm/types/src/graphql → cjs/types/src/components/Quote}/queries/getFormattedQuote.d.ts +6 -1
  11. package/dist/cjs/types/src/components/Quote/queries/quoteAccept.d.ts +14 -0
  12. package/dist/{esm/types/src/components/Signup → cjs/types/src/components/Signup/components/CheckoutSummary}/CheckoutSummary.d.ts +1 -1
  13. package/dist/cjs/types/src/components/Signup/components/CheckoutSummary/hooks/sortQuoteChangeCharges.d.ts +14 -0
  14. package/dist/cjs/types/src/components/Signup/fragments/Signup_QuoteFragment.d.ts +2 -0
  15. package/dist/cjs/types/src/components/Signup/hooks/useApplyDefaultCoupon.d.ts +21 -0
  16. package/dist/cjs/types/src/contexts/InvoiceQuoteContext.d.ts +1 -3
  17. package/dist/cjs/types/src/graphql/queries/getFormattedInvoice.d.ts +1 -1
  18. package/dist/cjs/types/src/utils/QueryKeyFactory.d.ts +4 -4
  19. package/dist/cjs/types/src/utils/couponUtils.d.ts +5 -5
  20. package/dist/esm/index.js +501 -400
  21. package/dist/esm/types/src/ajax.d.ts +1 -1
  22. package/dist/esm/types/src/components/Checkout/QuoteCheckout.d.ts +2 -2
  23. package/dist/esm/types/src/components/PandadocPollingModal.d.ts +1 -1
  24. package/dist/esm/types/src/components/Quote/Quote.d.ts +28 -1
  25. package/dist/esm/types/src/components/Quote/components/PaymentHoldDisplay.d.ts +18 -0
  26. package/dist/esm/types/src/components/Quote/components/QuoteButtons.d.ts +12 -4
  27. package/dist/esm/types/src/components/Quote/hooks/{useSendAcceptQuote.d.ts → useAcceptQuote.d.ts} +6 -3
  28. package/dist/esm/types/src/components/Quote/hooks/useQuotePaymentHold.d.ts +20 -0
  29. package/dist/{cjs/types/src/graphql → esm/types/src/components/Quote}/queries/getFormattedQuote.d.ts +6 -1
  30. package/dist/esm/types/src/components/Quote/queries/quoteAccept.d.ts +14 -0
  31. package/dist/{cjs/types/src/components/Signup → esm/types/src/components/Signup/components/CheckoutSummary}/CheckoutSummary.d.ts +1 -1
  32. package/dist/esm/types/src/components/Signup/components/CheckoutSummary/hooks/sortQuoteChangeCharges.d.ts +14 -0
  33. package/dist/esm/types/src/components/Signup/fragments/Signup_QuoteFragment.d.ts +2 -0
  34. package/dist/esm/types/src/components/Signup/hooks/useApplyDefaultCoupon.d.ts +21 -0
  35. package/dist/esm/types/src/contexts/InvoiceQuoteContext.d.ts +1 -3
  36. package/dist/esm/types/src/graphql/queries/getFormattedInvoice.d.ts +1 -1
  37. package/dist/esm/types/src/utils/QueryKeyFactory.d.ts +4 -4
  38. package/dist/esm/types/src/utils/couponUtils.d.ts +5 -5
  39. package/dist/index.d.ts +14 -5
  40. package/package.json +1 -1
package/dist/cjs/index.js CHANGED
@@ -1283,7 +1283,7 @@ const DEFAULT_CONFIG = {
1283
1283
  };
1284
1284
 
1285
1285
  // This will be replaced at build time by rollup-plugin-replace
1286
- const PACKAGE_VERSION = '1.8.0-beta.3';
1286
+ const PACKAGE_VERSION = '1.8.0-beta.5';
1287
1287
  const createRequestHeaders = (token) => {
1288
1288
  const headers = createClientDevHeaders({ token });
1289
1289
  // Add the components version header
@@ -19899,7 +19899,7 @@ const usePaymentMethod = ({ accountId, enabled = true, }) => {
19899
19899
  };
19900
19900
  };
19901
19901
 
19902
- const mutation$h = t(`
19902
+ const mutation$i = t(`
19903
19903
  query PaymentPlugins($accountId: ID) {
19904
19904
  paymentPlugins(accountId: $accountId) {
19905
19905
  enabled
@@ -19927,7 +19927,7 @@ const mutation$h = t(`
19927
19927
  // }[];
19928
19928
  // };
19929
19929
  const getPaymentPlugins = async ({ apiHost, token, accountId, }) => {
19930
- const response = await execute(mutation$h, { apiHost, token }, { accountId });
19930
+ const response = await execute(mutation$i, { apiHost, token }, { accountId });
19931
19931
  return response === null || response === void 0 ? void 0 : response.paymentPlugins;
19932
19932
  };
19933
19933
  const usePaymentPlugins = (accountId) => {
@@ -21698,6 +21698,102 @@ function ActualInvoice({ hidePaymentForm, onSavePaymentMethod, onPaymentMethodRe
21698
21698
  } }) }))] }) }));
21699
21699
  }
21700
21700
 
21701
+ const trimGraph = (s) => {
21702
+ return s.replace(/\s+/g, ' ');
21703
+ };
21704
+ const useGraphQL = (navigateOnTokenExpired, apiEndpoint, onError) => {
21705
+ return async (callback, bodyData = null, token, callbackParams) => {
21706
+ bodyData = trimGraph(bodyData);
21707
+ const headers = createClientDevHeaders({ token });
21708
+ const response = await fetch(apiEndpoint + '/graphql', {
21709
+ method: 'post',
21710
+ body: bodyData,
21711
+ headers,
21712
+ });
21713
+ if (response.status !== 200 && response.status !== 201) {
21714
+ return response.json().then((data) => {
21715
+ var _a, _b, _c;
21716
+ if (data.errors) {
21717
+ onError(data.errors[0].message);
21718
+ }
21719
+ else if (((_a = data === null || data === void 0 ? void 0 : data[0]) === null || _a === void 0 ? void 0 : _a.description) === 'Token is expired') {
21720
+ navigateOnTokenExpired();
21721
+ }
21722
+ else if ((_b = data === null || data === void 0 ? void 0 : data[0]) === null || _b === void 0 ? void 0 : _b.description) {
21723
+ throw new Error((_c = data === null || data === void 0 ? void 0 : data[0]) === null || _c === void 0 ? void 0 : _c.description);
21724
+ }
21725
+ return;
21726
+ });
21727
+ }
21728
+ return response
21729
+ .json()
21730
+ .then((data) => callback(data, callbackParams))
21731
+ .catch((err) => {
21732
+ console.error(err);
21733
+ onError(err);
21734
+ });
21735
+ };
21736
+ };
21737
+ const useGraphQLmutation = (navigateOnTokenExpired, apiEndpoint, onError) => {
21738
+ const graphQL = useGraphQL(navigateOnTokenExpired, apiEndpoint, onError);
21739
+ return (mutation, variables, callback, token, callbackParams) => {
21740
+ if (typeof variables === 'object')
21741
+ variables = JSON.stringify(variables);
21742
+ return graphQL(callback, `{ "query": "${mutation}", "variables": ${variables} }`, token, callbackParams);
21743
+ };
21744
+ };
21745
+
21746
+ const POLLING_INTERVAL = 2000;
21747
+ const PandadocPollingModal = ({ isVisible, setVisible, id }) => {
21748
+ const { apiHost, onTokenExpired } = react.useContext(BunnyContext);
21749
+ const token = useToken();
21750
+ const graphQLMutation = useGraphQLmutation(() => {
21751
+ console.log('graphQLMutation navigateOnTokenExpired not yet implemented');
21752
+ }, apiHost || '', () => {
21753
+ console.log('graphQLMutation onError not yet implemented');
21754
+ });
21755
+ const handleAllErrorFormats = useAllErrorFormats$1(onTokenExpired);
21756
+ const [numberOfPolls, setNumberOfPolls] = react.useState(0);
21757
+ const [infoMessage, setInfoMessage] = react.useState('');
21758
+ react.useEffect(() => {
21759
+ if (!isVisible)
21760
+ return;
21761
+ const pollPandadocMutation = () => {
21762
+ const mutation = `mutation quotePollSigningUrl($id: ID) {
21763
+ quotePollSigningUrl(quoteId: $id) {
21764
+ redirectUri
21765
+ status
21766
+ errors
21767
+ infoMessage
21768
+ }
21769
+ }`;
21770
+ const variables = {
21771
+ id,
21772
+ };
21773
+ graphQLMutation(mutation, variables, (rsp) => {
21774
+ if (rsp.errors)
21775
+ handleAllErrorFormats(rsp.errors[0].message);
21776
+ else if (rsp.data.quotePollSigningUrl.status === 'document.sent') {
21777
+ setVisible(false);
21778
+ window.location.href = rsp.data.quotePollSigningUrl.redirectUri;
21779
+ }
21780
+ setInfoMessage(rsp.data.quotePollSigningUrl.infoMessage || '');
21781
+ }, token);
21782
+ setNumberOfPolls(numberOfPolls + 1);
21783
+ };
21784
+ const interval = setInterval(pollPandadocMutation, POLLING_INTERVAL);
21785
+ return () => clearInterval(interval);
21786
+ }, [
21787
+ graphQLMutation,
21788
+ // handleAllErrorFormats,
21789
+ numberOfPolls,
21790
+ token,
21791
+ isVisible,
21792
+ setVisible,
21793
+ ]);
21794
+ return (jsxRuntime.jsxs(antd.Modal, { title: "Uploading quote to Pandadoc", open: isVisible, closable: false, footer: null, children: [jsxRuntime.jsxs("div", { className: "bunny-py-4 bunny-text-center", children: ["This may take a few seconds", '.'.repeat(numberOfPolls)] }), jsxRuntime.jsx("div", { className: "bunny-text-center", children: infoMessage })] }));
21795
+ };
21796
+
21701
21797
  const usePlugins = ({ apiHost, token }) => {
21702
21798
  const response = reactQuery.useQuery({
21703
21799
  queryKey: QueryKeyFactory.pluginsKey(token),
@@ -21820,76 +21916,7 @@ const AcceptQuoteModal = ({ acceptBoxVisible, formattedQuote: maskedFormattedQuo
21820
21916
  }, open: acceptBoxVisible, title: (signingPlugins === null || signingPlugins === void 0 ? void 0 : signingPlugins.length) ? 'Start signing' : 'Accept quote', width: 400, children: jsxRuntime.jsx(NoSigningPluginsForm, { isVisible: acceptBoxVisible, formattedQuote: formattedQuote, form: form }) }));
21821
21917
  };
21822
21918
 
21823
- const tagStyleMap = {
21824
- blue: { color: 'var(--bunny-blue-500)', background: 'var(--bunny-blue-200)' },
21825
- green: {
21826
- color: 'var(--bunny-green-600)',
21827
- background: 'var(--bunny-green-200)',
21828
- },
21829
- red: { color: 'var(--bunny-red-500)', background: 'var(--bunny-red-200)' },
21830
- orange: {
21831
- color: 'var(--bunny-orange-500)',
21832
- background: 'var(--bunny-orange-200)',
21833
- },
21834
- yellow: {
21835
- color: 'var(--bunny-yellow-500)',
21836
- background: 'var(--bunny-yellow-200)',
21837
- },
21838
- purple: {
21839
- color: 'var(--bunny-purple-500)',
21840
- background: 'var(--bunny-purple-200)',
21841
- },
21842
- black: { color: 'white', background: 'var(--bunny-black)' },
21843
- };
21844
- // This component provides custom styling for antd Tag components without using antd overwrites.
21845
- // Please use this component instead of the antd Tag component directly to maintain consistent styling.
21846
- const CustomizedTag = ({ children, color, className, style, }) => {
21847
- return (jsxRuntime.jsx(antd.Tag, { color: color, style: { ...(color ? tagStyleMap[color] : undefined), ...style }, className: `bunny-m-0 bunny-rounded-full bunny-border-none bunny-whitespace-nowrap ${className}`, children: children }));
21848
- };
21849
-
21850
- const useIsExpired = (expiresAt) => dayjs(expiresAt).diff(dayjs(dayjs().format("YYYY-MM-DD"))) < 0;
21851
-
21852
- dayjs.extend(localizedFormat);
21853
- const formatDate = (date) => dayjs(date).format('ll');
21854
-
21855
- const { Text: Text$z } = antd.Typography;
21856
- const QuoteButtons_FormattedQuoteFragment = t(`
21857
- fragment QuoteButtons_FormattedQuoteFragment on FormattedQuote {
21858
- acceptedAt
21859
- acceptedByName
21860
- currency
21861
- amount
21862
- expiresAt
21863
- }
21864
- `);
21865
- function QuoteButtons({ isAccepted, formattedQuote: maskedFormattedQuote, isMobile, hideDownloadButton, id, isAccepting, handleClickAccept, setPaymentHoldModalVisible, shouldDoPaymentHold, paymentHoldCompleted, paymentHold, isSendAcceptPending, }) {
21866
- // Read fragments
21867
- const formattedQuote = readFragment(QuoteButtons_FormattedQuoteFragment, maskedFormattedQuote);
21868
- const { apiHost } = react.useContext(BunnyContext);
21869
- const token = useToken();
21870
- const { secondaryColor } = useBrand();
21871
- const downloadFile = useDownloadFile(id);
21872
- const isExpired = useIsExpired(formattedQuote === null || formattedQuote === void 0 ? void 0 : formattedQuote.expiresAt);
21873
- const signingPlugins = useSigningPlugins({ apiHost, token });
21874
- return (jsxRuntime.jsxs("div", { className: "flex flex-row justify-end items-center gap-4", id: "acceptance", style: {
21875
- color: secondaryColor,
21876
- }, children: [isAccepted && formattedQuote.acceptedAt ? (jsxRuntime.jsx(Text$z, { children: `Quote was accepted by ${formattedQuote.acceptedByName} on ${formatDate(formattedQuote.acceptedAt)}` })) : null, (!isMobile || !isAccepted) && (jsxRuntime.jsxs("div", { className: isMobile ? 'flex w-full justify-end gap-2' : 'flex items-center justify-end gap-2', children: [paymentHold ? (jsxRuntime.jsx(PaymentHoldDisplay, { paymentHold: paymentHold, currency: formattedQuote.currency, amount: formattedQuote.amount })) : null, !isMobile && !hideDownloadButton ? (jsxRuntime.jsx(antd.Button, { icon: jsxRuntime.jsx(icons.DownloadOutlined, {}), onClick: () => downloadFile(apiHost + '/api/pdf/quote', token), children: "Download" })) : null, shouldDoPaymentHold && !paymentHoldCompleted ? (jsxRuntime.jsx(antd.Button, { disabled: isExpired, onClick: () => setPaymentHoldModalVisible(true), type: "primary", loading: isSendAcceptPending, children: "Pay and sign" })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: !isAccepted ? (jsxRuntime.jsx(antd.Button, { disabled: isExpired || isAccepting, onClick: handleClickAccept, type: "primary", children: isExpired
21877
- ? 'Quote is expired'
21878
- : (signingPlugins === null || signingPlugins === void 0 ? void 0 : signingPlugins.length)
21879
- ? 'Start signing'
21880
- : 'Accept quote' })) : null }))] }))] }));
21881
- }
21882
- function PaymentHoldDisplay({ paymentHold, currency, amount, }) {
21883
- var _a, _b, _c, _d;
21884
- const paymentMethod = ((_b = (_a = paymentHold.paymentMethod) === null || _a === void 0 ? void 0 : _a.metadata) === null || _b === void 0 ? void 0 : _b.identifier)
21885
- ? (_d = (_c = paymentHold.paymentMethod) === null || _c === void 0 ? void 0 : _c.metadata) === null || _d === void 0 ? void 0 : _d.identifier
21886
- : 'N/A';
21887
- const formattedAmount = currency ? formatCurrency(amount, currency) : 'N/A';
21888
- const expirationDate = paymentHold.expiresAt ? formatDate(paymentHold.expiresAt) : 'N/A';
21889
- return (jsxRuntime.jsx(antd.Tooltip, { title: `${formattedAmount} will be charged to ${paymentMethod} once the quote is accepted. Hold will be released on ${expirationDate} if not accepted.`, children: jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(CustomizedTag, { color: 'orange', className: "rounded-md", style: { padding: 6 }, children: ["Hold of ", formattedAmount, " on ****", paymentMethod] }) }) }));
21890
- }
21891
-
21892
- const { Title: Title$2, Text: Text$y } = antd.Typography;
21919
+ const { Title: Title$2, Text: Text$z } = antd.Typography;
21893
21920
  const showSuccessNotification$2 = useSuccessNotification();
21894
21921
  const showErrorNotification$5 = useErrorNotification();
21895
21922
  const PaymentHoldModal_FormattedQuoteFragment = t(`
@@ -21915,7 +21942,7 @@ const PaymentHoldModal = ({ visible, setVisible, formattedQuote: maskedFormatted
21915
21942
  const [form] = antd.Form.useForm();
21916
21943
  return (jsxRuntime.jsx(StyledModal$2, { centered: true, onCancel: () => {
21917
21944
  setVisible(false);
21918
- }, footer: null, open: visible, width: 800, className: 'bunny-flex bunny-flex-row bunny-gap-4', children: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row", children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-w-1/2", children: [jsxRuntime.jsxs("div", { className: "bunny-mt-5 bunny-mx-4", children: [jsxRuntime.jsx(Title$2, { className: "bunny-mt-0", level: 5, children: "Pay and sign" }), jsxRuntime.jsxs(Text$y, { className: "bunny-bt-2 bunny-text-sm/5 bunny-text-gray-500", children: ["To accept this quote, approve a payment hold for", ' ', formatCurrency(formattedQuote.amount, formattedQuote.currency || 'null'), ". This amount will be charged to your payment method once the quote is signed."] })] }), jsxRuntime.jsx("div", { className: "bunny-p-4", children: noSigningPlugins ? jsxRuntime.jsx(NoSigningPluginsForm, { isVisible: visible, formattedQuote: formattedQuote, form: form }) : null })] }), jsxRuntime.jsx(VerticalDivider, { className: "bunny-m-4" }), jsxRuntime.jsx("div", { className: "bunny-mb-3 bunny-w-1/2 bunny-pt-6", children: jsxRuntime.jsx(PaymentForm, { quote: formattedQuote.quote, paymentHoldOptions: {
21945
+ }, footer: null, open: visible, width: 800, className: 'bunny-flex bunny-flex-row bunny-gap-4', children: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row", children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-w-1/2", children: [jsxRuntime.jsxs("div", { className: "bunny-mt-5 bunny-mx-4", children: [jsxRuntime.jsx(Title$2, { className: "bunny-mt-0", level: 5, children: "Pay and sign" }), jsxRuntime.jsxs(Text$z, { className: "bunny-bt-2 bunny-text-sm/5 bunny-text-gray-500", children: ["To accept this quote, approve a payment hold for", ' ', formatCurrency(formattedQuote.amount, formattedQuote.currency || 'null'), ". This amount will be charged to your payment method once the quote is signed."] })] }), jsxRuntime.jsx("div", { className: "bunny-p-4", children: noSigningPlugins ? jsxRuntime.jsx(NoSigningPluginsForm, { isVisible: visible, formattedQuote: formattedQuote, form: form }) : null })] }), jsxRuntime.jsx(VerticalDivider, { className: "bunny-m-4" }), jsxRuntime.jsx("div", { className: "bunny-mb-3 bunny-w-1/2 bunny-pt-6", children: jsxRuntime.jsx(PaymentForm, { quote: formattedQuote.quote, paymentHoldOptions: {
21919
21946
  payToAccept: true,
21920
21947
  amountToHold: formattedQuote.amount,
21921
21948
  }, onPaymentSuccess: () => {
@@ -21938,13 +21965,15 @@ const PaymentHoldModal = ({ visible, setVisible, formattedQuote: maskedFormatted
21938
21965
  token,
21939
21966
  }),
21940
21967
  });
21941
- // accept quote automatically
21942
- form
21943
- .validateFields()
21944
- .then(changedFields => {
21945
- sendAccept(changedFields);
21946
- })
21947
- .catch(() => { });
21968
+ // accept quote automatically if no signing plugins are present
21969
+ if (noSigningPlugins) {
21970
+ form
21971
+ .validateFields()
21972
+ .then(changedFields => {
21973
+ sendAccept(changedFields);
21974
+ })
21975
+ .catch(() => { });
21976
+ }
21948
21977
  }, paymentHoldPrecondition: async () => {
21949
21978
  if (!noSigningPlugins)
21950
21979
  return true;
@@ -21990,232 +22019,125 @@ const StyledModal$2 = (props) => {
21990
22019
  return jsxRuntime.jsx(ModalOverrideBrandStylings, { closable: false, ...props });
21991
22020
  };
21992
22021
 
21993
- const query$7 = t(`
21994
- query formattedQuote($id: ID) {
21995
- formattedQuote(id: $id) {
21996
- quote {
21997
- documentTemplateId
21998
- documents {
21999
- id
22000
- filename
22001
- size
22002
- date
22003
- url
22004
- }
22005
- firstInvoice {
22006
- id
22007
- state
22008
- }
22009
- payableId
22010
- id
22011
- payToAccept
22012
- currentPaymentHold {
22013
- createdAt
22014
- expiresAt
22015
- id
22016
- updatedAt
22017
- paymentMethod {
22018
- accountId
22019
- createdAt
22020
- expirationDate
22021
- failureCode
22022
- id
22023
- isDefault
22024
- lastSuccess
22025
- paymentType
22026
- pluginId
22027
- state
22028
- updatedAt
22029
- metadata {
22030
- description
22031
- expiration
22032
- icon
22033
- identifier
22034
- issuer
22035
- kind
22036
- }
22037
- }
22038
- }
22039
- }
22040
- payableId
22041
- acceptedAt
22042
- acceptedByName
22043
- amount
22044
- amountDue
22045
- amountsByPeriod {
22046
- id
22047
- name
22048
- amount
22049
- }
22050
- billingCity
22051
- billingCountry
22052
- billingState
22053
- billingStreet
22054
- billingZip
22055
- contactName
22056
- currency
22057
- customerBillingCity
22058
- customerBillingCountry
22059
- customerBillingState
22060
- customerBillingStreet
22061
- customerBillingZip
22062
- customerName
22063
- discount
22064
- discountValue
22065
- duration
22066
- endDate
22067
- expiresAt
22068
- html
22069
- formattedLines {
22070
- amount
22071
- amountsByPeriod {
22072
- quantity
22073
- id
22074
- name
22075
- startDate
22076
- endDate
22077
- amount
22078
- amountsByTier {
22079
- id
22080
- tier {
22081
- starts
22082
- ends
22083
- price
22084
- }
22085
- quantity
22086
- amount
22087
- }
22088
- prorationRate
22089
- }
22090
- billingPeriodEnd
22091
- billingPeriodStart
22092
- chargeType
22093
- discount
22094
- frequency
22095
- isRamp
22096
- periods
22097
- planName
22098
- position
22099
- price
22100
- priceDecimals
22101
- priceListChargeId
22102
- priceListChargeName
22103
- priceListId
22104
- priceListName
22105
- priceTiers {
22106
- price
22107
- starts
22108
- }
22109
- pricingModel
22110
- productName
22111
- prorationRate
22112
- quantity
22113
- showProductNameOnLineItem
22114
- taxCode
22115
- trialEndDate
22116
- trialStartDate
22117
- unitOfMeasure
22118
- vatCode
22119
- }
22120
- netPaymentDays
22121
- notes
22122
- number
22123
- poNumberRequired
22124
- salesContactEmail
22125
- sharedAt
22126
- startDate
22127
- state
22128
- subtotal
22129
- taxAmount
22130
- taxNumberLabel
22131
- taxNumberRequired
22132
- vendorName
22133
- ...PaymentHoldModal_FormattedQuoteFragment
22134
- ...AcceptQuoteModal_FormattedQuoteFragment
22135
- ...QuoteButtons_FormattedQuoteFragment
22136
- }
22137
- }
22138
- `, [
22139
- PaymentHoldModal_FormattedQuoteFragment,
22140
- AcceptQuoteModal_FormattedQuoteFragment,
22141
- QuoteButtons_FormattedQuoteFragment,
22142
- ]);
22143
- const getFormattedQuote = async ({ token, apiHost, id, }) => {
22144
- const response = await execute(query$7, { apiHost, token }, { id });
22145
- return response === null || response === void 0 ? void 0 : response.formattedQuote;
22146
- };
22022
+ const useIsExpired = (expiresAt) => dayjs(expiresAt).diff(dayjs(dayjs().format("YYYY-MM-DD"))) < 0;
22147
22023
 
22148
- const trimGraph = (s) => {
22149
- return s.replace(/\s+/g, ' ');
22150
- };
22151
- const useGraphQL = (navigateOnTokenExpired, apiEndpoint, onError) => {
22152
- return async (callback, bodyData = null, token, callbackParams) => {
22153
- bodyData = trimGraph(bodyData);
22154
- const headers = createClientDevHeaders({ token });
22155
- const response = await fetch(apiEndpoint + '/graphql', {
22156
- method: 'post',
22157
- body: bodyData,
22158
- headers,
22159
- });
22160
- if (response.status !== 200 && response.status !== 201) {
22161
- return response.json().then((data) => {
22162
- var _a, _b, _c;
22163
- if (data.errors) {
22164
- onError(data.errors[0].message);
22165
- }
22166
- else if (((_a = data === null || data === void 0 ? void 0 : data[0]) === null || _a === void 0 ? void 0 : _a.description) === 'Token is expired') {
22167
- navigateOnTokenExpired();
22168
- }
22169
- else if ((_b = data === null || data === void 0 ? void 0 : data[0]) === null || _b === void 0 ? void 0 : _b.description) {
22170
- throw new Error((_c = data === null || data === void 0 ? void 0 : data[0]) === null || _c === void 0 ? void 0 : _c.description);
22171
- }
22172
- return;
22173
- });
22174
- }
22175
- return response
22176
- .json()
22177
- .then((data) => callback(data, callbackParams))
22178
- .catch((err) => {
22179
- console.error(err);
22180
- onError(err);
22181
- });
22182
- };
22024
+ dayjs.extend(localizedFormat);
22025
+ const formatDate = (date) => dayjs(date).format('ll');
22026
+
22027
+ const tagStyleMap = {
22028
+ blue: { color: 'var(--bunny-blue-500)', background: 'var(--bunny-blue-200)' },
22029
+ green: {
22030
+ color: 'var(--bunny-green-600)',
22031
+ background: 'var(--bunny-green-200)',
22032
+ },
22033
+ red: { color: 'var(--bunny-red-500)', background: 'var(--bunny-red-200)' },
22034
+ orange: {
22035
+ color: 'var(--bunny-orange-500)',
22036
+ background: 'var(--bunny-orange-200)',
22037
+ },
22038
+ yellow: {
22039
+ color: 'var(--bunny-yellow-500)',
22040
+ background: 'var(--bunny-yellow-200)',
22041
+ },
22042
+ purple: {
22043
+ color: 'var(--bunny-purple-500)',
22044
+ background: 'var(--bunny-purple-200)',
22045
+ },
22046
+ black: { color: 'white', background: 'var(--bunny-black)' },
22183
22047
  };
22184
- const useGraphQLmutation = (navigateOnTokenExpired, apiEndpoint, onError) => {
22185
- const graphQL = useGraphQL(navigateOnTokenExpired, apiEndpoint, onError);
22186
- return (mutation, variables, callback, token, callbackParams) => {
22187
- if (typeof variables === 'object')
22188
- variables = JSON.stringify(variables);
22189
- return graphQL(callback, `{ "query": "${mutation}", "variables": ${variables} }`, token, callbackParams);
22190
- };
22048
+ // This component provides custom styling for antd Tag components without using antd overwrites.
22049
+ // Please use this component instead of the antd Tag component directly to maintain consistent styling.
22050
+ const CustomizedTag = ({ children, color, className, style, }) => {
22051
+ return (jsxRuntime.jsx(antd.Tag, { color: color, style: { ...(color ? tagStyleMap[color] : undefined), ...style }, className: `bunny-m-0 bunny-rounded-full bunny-border-none bunny-whitespace-nowrap ${className}`, children: children }));
22191
22052
  };
22192
22053
 
22193
- const handleAllErrorFormats = useAllErrorFormats();
22194
- const QUOTE_ACCEPT = `
22195
- mutation quoteAccept($name: String!, $title: String!, $poNumber: String, $taxNumber: String, $quoteId: ID) {
22196
- quoteAccept(name: $name, title: $title, poNumber: $poNumber, taxNumber: $taxNumber, quoteId: $quoteId) {
22054
+ const PaymentHoldDisplay_PaymentHoldFragment = t(`
22055
+ fragment PaymentHoldDisplay_PaymentHoldFragment on PaymentHold {
22056
+ expiresAt
22057
+ paymentMethod {
22058
+ metadata {
22059
+ identifier
22060
+ }
22061
+ }
22062
+ }
22063
+ `);
22064
+ function PaymentHoldDisplay({ paymentHold: maskedPaymentHold, currency, amount, }) {
22065
+ var _a, _b, _c, _d;
22066
+ const paymentHold = readFragment(PaymentHoldDisplay_PaymentHoldFragment, maskedPaymentHold);
22067
+ const paymentMethod = ((_b = (_a = paymentHold.paymentMethod) === null || _a === void 0 ? void 0 : _a.metadata) === null || _b === void 0 ? void 0 : _b.identifier)
22068
+ ? (_d = (_c = paymentHold.paymentMethod) === null || _c === void 0 ? void 0 : _c.metadata) === null || _d === void 0 ? void 0 : _d.identifier
22069
+ : 'N/A';
22070
+ const formattedAmount = currency ? formatCurrency(amount, currency) : 'N/A';
22071
+ const expirationDate = paymentHold.expiresAt ? formatDate(paymentHold.expiresAt) : 'N/A';
22072
+ return (jsxRuntime.jsx(antd.Tooltip, { title: `${formattedAmount} will be charged to ${paymentMethod} once the quote is accepted.Hold will be released on ${expirationDate} if not accepted.`, children: jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(CustomizedTag, { color: 'orange', className: "rounded-md", style: { padding: 6 }, children: ["Hold of ", formattedAmount, " on ****", paymentMethod] }) }) }));
22073
+ }
22074
+
22075
+ const { Text: Text$y } = antd.Typography;
22076
+ const QuoteButtons_FormattedQuoteFragment = t(`
22077
+ fragment QuoteButtons_FormattedQuoteFragment on FormattedQuote {
22078
+ acceptedAt
22079
+ acceptedByName
22080
+ currency
22081
+ amount
22082
+ expiresAt
22083
+ }
22084
+ `);
22085
+ const PaymentHoldDisplay_QuoteButtonsFragment = t(`
22086
+ fragment PaymentHoldDisplay_QuoteButtonsFragment on PaymentHold {
22087
+ ...PaymentHoldDisplay_PaymentHoldFragment
22088
+ }
22089
+ `, [PaymentHoldDisplay_PaymentHoldFragment]);
22090
+ function QuoteButtons({ isAccepted, formattedQuote: maskedFormattedQuote, isMobile, hideDownloadButton, id, isAccepting, handleClickAccept, setPaymentHoldModalVisible, shouldDoPaymentHold, paymentHoldCompleted, paymentHold: maskedPaymentHold, isSendAcceptPending, }) {
22091
+ // Read fragments
22092
+ const formattedQuote = readFragment(QuoteButtons_FormattedQuoteFragment, maskedFormattedQuote);
22093
+ const paymentHold = readFragment(PaymentHoldDisplay_QuoteButtonsFragment, maskedPaymentHold);
22094
+ const { apiHost } = react.useContext(BunnyContext);
22095
+ const token = useToken();
22096
+ const { secondaryColor } = useBrand();
22097
+ const downloadFile = useDownloadFile(id);
22098
+ const isExpired = useIsExpired(formattedQuote === null || formattedQuote === void 0 ? void 0 : formattedQuote.expiresAt);
22099
+ const signingPlugins = useSigningPlugins({ apiHost, token });
22100
+ return (jsxRuntime.jsxs("div", { className: "flex flex-row justify-end items-center gap-4", id: "acceptance", style: {
22101
+ color: secondaryColor,
22102
+ }, children: [isAccepted && formattedQuote.acceptedAt ? (jsxRuntime.jsx(Text$y, { children: `Quote was accepted by ${formattedQuote.acceptedByName} on ${formatDate(formattedQuote.acceptedAt)}` })) : null, (!isMobile || !isAccepted) && (jsxRuntime.jsxs("div", { className: isMobile ? 'flex w-full justify-end gap-2' : 'flex items-center justify-end gap-2', children: [paymentHold ? (jsxRuntime.jsx(PaymentHoldDisplay, { paymentHold: paymentHold, currency: formattedQuote.currency, amount: formattedQuote.amount })) : null, !isMobile && !hideDownloadButton ? (jsxRuntime.jsx(antd.Button, { icon: jsxRuntime.jsx(icons.DownloadOutlined, {}), onClick: () => downloadFile(apiHost + '/api/pdf/quote', token), children: "Download" })) : null, shouldDoPaymentHold && !paymentHoldCompleted ? (jsxRuntime.jsx(antd.Button, { disabled: isExpired, onClick: () => setPaymentHoldModalVisible(true), type: "primary", loading: isSendAcceptPending, children: "Pay and sign" })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: !isAccepted ? (jsxRuntime.jsx(antd.Button, { disabled: isExpired || isAccepting, onClick: handleClickAccept, type: "primary", children: isExpired
22103
+ ? 'Quote is expired'
22104
+ : (signingPlugins === null || signingPlugins === void 0 ? void 0 : signingPlugins.length)
22105
+ ? 'Start signing'
22106
+ : 'Accept quote' })) : null }))] }))] }));
22107
+ }
22108
+
22109
+ const mutation$h = t(`
22110
+ mutation QuoteAccept(
22111
+ $name: String!
22112
+ $title: String!
22113
+ $poNumber: String
22114
+ $taxNumber: String
22115
+ $quoteId: ID
22116
+ ) {
22117
+ quoteAccept(
22118
+ name: $name
22119
+ title: $title
22120
+ poNumber: $poNumber
22121
+ taxNumber: $taxNumber
22122
+ quoteId: $quoteId
22123
+ ) {
22197
22124
  errors
22198
22125
  }
22199
22126
  }
22200
- `;
22201
- const quoteAccept = async ({ quoteId, apiHost, token, changedFormItems, }) => {
22127
+ `);
22128
+ const quoteAccept = async ({ quoteId, apiHost, token, changedFormItems }) => {
22202
22129
  var _a, _b;
22203
- const vars = {
22204
- ...changedFormItems,
22205
- quoteId,
22206
- };
22207
- const response = await gqlRequest({
22208
- query: QUOTE_ACCEPT,
22209
- token,
22210
- vars,
22211
- apiHost,
22130
+ return await execute(mutation$h, { apiHost, token }, {
22131
+ name: changedFormItems.name,
22132
+ title: changedFormItems.title,
22133
+ poNumber: (_a = changedFormItems.poNumber) !== null && _a !== void 0 ? _a : null,
22134
+ taxNumber: (_b = changedFormItems.taxNumber) !== null && _b !== void 0 ? _b : null,
22135
+ quoteId: quoteId !== null && quoteId !== void 0 ? quoteId : null,
22212
22136
  });
22213
- const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteAccept) === null || _a === void 0 ? void 0 : _a.errors;
22214
- if (errors)
22215
- throw errors;
22216
- return (_b = response.quoteAccept) === null || _b === void 0 ? void 0 : _b.quote;
22217
22137
  };
22218
- const useSendAcceptQuote = ({ quoteId, apiHost, token, onQuoteAccepted, }) => {
22138
+
22139
+ const handleAllErrorFormats = useAllErrorFormats();
22140
+ const useAcceptQuote = ({ quoteId, apiHost, token, onQuoteAccepted, }) => {
22219
22141
  // Hooks
22220
22142
  const graphQLMutation = useGraphQLmutation(() => {
22221
22143
  console.log('navigate in useGraphQLmutation in useSendAcceptQuote is not yet implemented');
@@ -22307,6 +22229,33 @@ const useSendAcceptQuote = ({ quoteId, apiHost, token, onQuoteAccepted, }) => {
22307
22229
  };
22308
22230
  };
22309
22231
 
22232
+ const useQuotePaymentHold_FormattedQuoteFragment = t(`
22233
+ fragment useQuotePaymentHold_FormattedQuoteFragment on FormattedQuote {
22234
+ quote {
22235
+ payToAccept
22236
+ currentPaymentHold {
22237
+ id
22238
+ }
22239
+ }
22240
+ }
22241
+ `);
22242
+ const useQuotePaymentHold = (maskedFormattedQuote) => {
22243
+ var _a, _b;
22244
+ const [paymentHoldModalVisible, setPaymentHoldModalVisible] = react.useState(false);
22245
+ const formattedQuote = maskedFormattedQuote
22246
+ ? readFragment(useQuotePaymentHold_FormattedQuoteFragment, maskedFormattedQuote)
22247
+ : undefined;
22248
+ const shouldDoPaymentHold = ((_a = formattedQuote === null || formattedQuote === void 0 ? void 0 : formattedQuote.quote) === null || _a === void 0 ? void 0 : _a.payToAccept) === true;
22249
+ const currentPaymentHold = (_b = formattedQuote === null || formattedQuote === void 0 ? void 0 : formattedQuote.quote) === null || _b === void 0 ? void 0 : _b.currentPaymentHold;
22250
+ return {
22251
+ // paymentHold: currentPaymentHold ?? undefined,
22252
+ paymentHoldModalVisible,
22253
+ setPaymentHoldModalVisible,
22254
+ shouldDoPaymentHold,
22255
+ paymentHoldCompleted: currentPaymentHold ? true : false,
22256
+ };
22257
+ };
22258
+
22310
22259
  const NavigationContext = react.createContext({});
22311
22260
 
22312
22261
  const useSigningComplete = ({ data, token }) => {
@@ -22322,63 +22271,186 @@ const useSigningComplete = ({ data, token }) => {
22322
22271
  }, [data, eventParam, queryClient, token]);
22323
22272
  };
22324
22273
 
22325
- const POLLING_INTERVAL = 2000;
22326
- const PandadocPollingModal = ({ isVisible, setVisible, id }) => {
22327
- const { apiHost, onTokenExpired } = react.useContext(BunnyContext);
22328
- const token = useToken();
22329
- const graphQLMutation = useGraphQLmutation(() => {
22330
- console.log('graphQLMutation navigateOnTokenExpired not yet implemented');
22331
- }, apiHost || '', () => {
22332
- console.log('graphQLMutation onError not yet implemented');
22333
- });
22334
- const handleAllErrorFormats = useAllErrorFormats$1(onTokenExpired);
22335
- const [numberOfPolls, setNumberOfPolls] = react.useState(0);
22336
- const [infoMessage, setInfoMessage] = react.useState('');
22337
- react.useEffect(() => {
22338
- if (!isVisible)
22339
- return;
22340
- const pollPandadocMutation = () => {
22341
- const mutation = `mutation quotePollSigningUrl($id: ID) {
22342
- quotePollSigningUrl(quoteId: $id) {
22343
- redirectUri
22344
- status
22345
- errors
22346
- infoMessage
22274
+ const query$7 = t(`
22275
+ query formattedQuote($id: ID) {
22276
+ formattedQuote(id: $id) {
22277
+ quote {
22278
+ documentTemplateId
22279
+ documents {
22280
+ id
22281
+ filename
22282
+ size
22283
+ date
22284
+ url
22285
+ }
22286
+ firstInvoice {
22287
+ id
22288
+ state
22289
+ }
22290
+ payableId
22291
+ id
22292
+ payToAccept
22293
+ currentPaymentHold {
22294
+ createdAt
22295
+ expiresAt
22296
+ id
22297
+ updatedAt
22298
+ paymentMethod {
22299
+ accountId
22300
+ createdAt
22301
+ expirationDate
22302
+ failureCode
22303
+ id
22304
+ isDefault
22305
+ lastSuccess
22306
+ paymentType
22307
+ pluginId
22308
+ state
22309
+ updatedAt
22310
+ metadata {
22311
+ description
22312
+ expiration
22313
+ icon
22314
+ identifier
22315
+ issuer
22316
+ kind
22317
+ }
22318
+ }
22319
+ ...PaymentHoldDisplay_QuoteButtonsFragment
22320
+ }
22347
22321
  }
22348
- }`;
22349
- const variables = {
22350
- id,
22351
- };
22352
- graphQLMutation(mutation, variables, (rsp) => {
22353
- if (rsp.errors)
22354
- handleAllErrorFormats(rsp.errors[0].message);
22355
- else if (rsp.data.quotePollSigningUrl.status === 'document.sent') {
22356
- setVisible(false);
22357
- window.location.href = rsp.data.quotePollSigningUrl.redirectUri;
22358
- }
22359
- setInfoMessage(rsp.data.quotePollSigningUrl.infoMessage || '');
22360
- }, token);
22361
- setNumberOfPolls(numberOfPolls + 1);
22362
- };
22363
- const interval = setInterval(pollPandadocMutation, POLLING_INTERVAL);
22364
- return () => clearInterval(interval);
22365
- }, [
22366
- graphQLMutation,
22367
- // handleAllErrorFormats,
22368
- numberOfPolls,
22369
- token,
22370
- isVisible,
22371
- setVisible,
22372
- ]);
22373
- return (jsxRuntime.jsxs(antd.Modal, { title: "Uploading quote to Pandadoc", open: isVisible, closable: false, footer: null, children: [jsxRuntime.jsxs("div", { className: "bunny-py-4 bunny-text-center", children: ["This may take a few seconds", '.'.repeat(numberOfPolls)] }), jsxRuntime.jsx("div", { className: "bunny-text-center", children: infoMessage })] }));
22322
+ payableId
22323
+ acceptedAt
22324
+ acceptedByName
22325
+ amount
22326
+ amountDue
22327
+ amountsByPeriod {
22328
+ id
22329
+ name
22330
+ amount
22331
+ }
22332
+ billingCity
22333
+ billingCountry
22334
+ billingState
22335
+ billingStreet
22336
+ billingZip
22337
+ contactName
22338
+ currency
22339
+ customerBillingCity
22340
+ customerBillingCountry
22341
+ customerBillingState
22342
+ customerBillingStreet
22343
+ customerBillingZip
22344
+ customerName
22345
+ discount
22346
+ discountValue
22347
+ duration
22348
+ endDate
22349
+ expiresAt
22350
+ html
22351
+ formattedLines {
22352
+ amount
22353
+ amountsByPeriod {
22354
+ quantity
22355
+ id
22356
+ name
22357
+ startDate
22358
+ endDate
22359
+ amount
22360
+ amountsByTier {
22361
+ id
22362
+ tier {
22363
+ starts
22364
+ ends
22365
+ price
22366
+ }
22367
+ quantity
22368
+ amount
22369
+ }
22370
+ prorationRate
22371
+ }
22372
+ billingPeriodEnd
22373
+ billingPeriodStart
22374
+ chargeType
22375
+ discount
22376
+ frequency
22377
+ isRamp
22378
+ periods
22379
+ planName
22380
+ position
22381
+ price
22382
+ priceDecimals
22383
+ priceListChargeId
22384
+ priceListChargeName
22385
+ priceListId
22386
+ priceListName
22387
+ priceTiers {
22388
+ price
22389
+ starts
22390
+ }
22391
+ pricingModel
22392
+ productName
22393
+ prorationRate
22394
+ quantity
22395
+ showProductNameOnLineItem
22396
+ taxCode
22397
+ trialEndDate
22398
+ trialStartDate
22399
+ unitOfMeasure
22400
+ vatCode
22401
+ }
22402
+ netPaymentDays
22403
+ notes
22404
+ number
22405
+ poNumberRequired
22406
+ salesContactEmail
22407
+ sharedAt
22408
+ startDate
22409
+ state
22410
+ subtotal
22411
+ taxAmount
22412
+ taxNumberLabel
22413
+ taxNumberRequired
22414
+ vendorName
22415
+ ...useQuotePaymentHold_FormattedQuoteFragment
22416
+ ...PaymentHoldModal_FormattedQuoteFragment
22417
+ ...AcceptQuoteModal_FormattedQuoteFragment
22418
+ ...QuoteButtons_FormattedQuoteFragment
22419
+ }
22420
+ }
22421
+ `, [
22422
+ useQuotePaymentHold_FormattedQuoteFragment,
22423
+ PaymentHoldModal_FormattedQuoteFragment,
22424
+ AcceptQuoteModal_FormattedQuoteFragment,
22425
+ QuoteButtons_FormattedQuoteFragment,
22426
+ PaymentHoldDisplay_QuoteButtonsFragment,
22427
+ ]);
22428
+ const getFormattedQuote = async ({ token, apiHost, id, }) => {
22429
+ const response = await execute(query$7, { apiHost, token }, { id });
22430
+ return response === null || response === void 0 ? void 0 : response.formattedQuote;
22374
22431
  };
22375
22432
 
22376
22433
  const showErrorNotification$4 = useErrorNotification();
22377
- defaultStyled.div `
22378
- Text {
22379
- width: 100%;
22380
- }
22381
- `;
22434
+ t(`
22435
+ fragment Quote_PaymentHoldFragment on FormattedQuote {
22436
+ quote {
22437
+ currentPaymentHold {
22438
+ ...PaymentHoldDisplay_QuoteButtonsFragment
22439
+ }
22440
+ firstInvoice {
22441
+ id
22442
+ }
22443
+ }
22444
+ }
22445
+ `, [PaymentHoldDisplay_QuoteButtonsFragment]);
22446
+ t(`
22447
+ fragment OnQuoteLoadedFragment on FormattedQuote {
22448
+ vendorName
22449
+ quote {
22450
+ id
22451
+ }
22452
+ }
22453
+ `);
22382
22454
  function Quote({ id, invoiceQuoteViewComponent, onInvoiceDownloadError, onPaymentSuccess, shadow = 'shadow-md', className, hideDownloadButton = false, onQuoteLoaded, onQuoteAccepted, onQuoteUnavailableError, suppressQuoteUnavailableErrorNotification = false, }) {
22383
22455
  return (jsxRuntime.jsx(InvoiceQuoteContext.Provider, { value: {
22384
22456
  id,
@@ -22388,30 +22460,16 @@ function Quote({ id, invoiceQuoteViewComponent, onInvoiceDownloadError, onPaymen
22388
22460
  shadow,
22389
22461
  className,
22390
22462
  hideDownloadButton,
22391
- onQuoteLoaded,
22392
22463
  onQuoteUnavailableError,
22393
22464
  suppressQuoteUnavailableErrorNotification,
22394
- }, children: jsxRuntime.jsx(ActualQuote, { onQuoteAccepted: onQuoteAccepted }) }));
22465
+ }, children: jsxRuntime.jsx(ActualQuote, { onQuoteAccepted: onQuoteAccepted, onQuoteLoaded: onQuoteLoaded }) }));
22395
22466
  }
22396
- const useQuotePaymentHold = (formattedQuote) => {
22397
- var _a, _b;
22398
- const [paymentHoldModalVisible, setPaymentHoldModalVisible] = react.useState(false);
22399
- const shouldDoPaymentHold = ((_a = formattedQuote === null || formattedQuote === void 0 ? void 0 : formattedQuote.quote) === null || _a === void 0 ? void 0 : _a.payToAccept) == true;
22400
- const currentPaymentHold = (_b = formattedQuote === null || formattedQuote === void 0 ? void 0 : formattedQuote.quote) === null || _b === void 0 ? void 0 : _b.currentPaymentHold;
22401
- return {
22402
- paymentHold: currentPaymentHold,
22403
- paymentHoldModalVisible,
22404
- setPaymentHoldModalVisible,
22405
- shouldDoPaymentHold,
22406
- paymentHoldCompleted: currentPaymentHold ? true : false,
22407
- };
22408
- };
22409
- function ActualQuote({ onQuoteAccepted }) {
22410
- var _a, _b, _c, _d, _e, _f;
22467
+ function ActualQuote({ onQuoteAccepted, onQuoteLoaded }) {
22468
+ var _a, _b, _c, _d, _e, _f, _g;
22411
22469
  // Context
22412
22470
  const { apiHost } = react.useContext(BunnyContext);
22413
22471
  const token = useToken();
22414
- const { className, id, hideDownloadButton, onQuoteLoaded, onQuoteUnavailableError, suppressQuoteUnavailableErrorNotification } = react.useContext(InvoiceQuoteContext);
22472
+ const { className, id, hideDownloadButton, onQuoteUnavailableError, suppressQuoteUnavailableErrorNotification } = react.useContext(InvoiceQuoteContext);
22415
22473
  // Queries
22416
22474
  const { data: formattedQuote, isLoading, error } = reactQuery.useQuery({
22417
22475
  queryKey: QueryKeyFactory.createQuoteKey({ id, token }),
@@ -22421,7 +22479,7 @@ function ActualQuote({ onQuoteAccepted }) {
22421
22479
  placeholderData: reactQuery.keepPreviousData,
22422
22480
  });
22423
22481
  // Hooks
22424
- const { acceptBoxVisible, isAccepting, sendAccept, setAcceptBoxVisible, setIsAccepting, startAcceptance, pandadocPollingModalVisible, setPandadocPollingModalVisible, isSendAcceptPending, } = useSendAcceptQuote({
22482
+ const { acceptBoxVisible, isAccepting, sendAccept, setAcceptBoxVisible, setIsAccepting, startAcceptance, pandadocPollingModalVisible, setPandadocPollingModalVisible, isSendAcceptPending, } = useAcceptQuote({
22425
22483
  token,
22426
22484
  apiHost,
22427
22485
  quoteId: id,
@@ -22431,7 +22489,7 @@ function ActualQuote({ onQuoteAccepted }) {
22431
22489
  const isMobile = useIsMobile();
22432
22490
  react.useEffect(() => {
22433
22491
  if (formattedQuote) {
22434
- onQuoteLoaded === null || onQuoteLoaded === void 0 ? void 0 : onQuoteLoaded(formattedQuote); // TODO: fix to use the correct type
22492
+ onQuoteLoaded === null || onQuoteLoaded === void 0 ? void 0 : onQuoteLoaded(formattedQuote);
22435
22493
  }
22436
22494
  }, [formattedQuote]);
22437
22495
  react.useEffect(() => {
@@ -22447,7 +22505,8 @@ function ActualQuote({ onQuoteAccepted }) {
22447
22505
  }
22448
22506
  }, [error]);
22449
22507
  // Payment hold stuff here
22450
- const { paymentHoldModalVisible, setPaymentHoldModalVisible, shouldDoPaymentHold, paymentHoldCompleted, paymentHold, } = useQuotePaymentHold(formattedQuote); // TODO: fix to use the correct type
22508
+ const { paymentHoldModalVisible, setPaymentHoldModalVisible, shouldDoPaymentHold, paymentHoldCompleted, } = useQuotePaymentHold(formattedQuote);
22509
+ const paymentHold = (_a = formattedQuote === null || formattedQuote === void 0 ? void 0 : formattedQuote.quote) === null || _a === void 0 ? void 0 : _a.currentPaymentHold;
22451
22510
  const handleClickAccept = () => {
22452
22511
  if (shouldDoPaymentHold && !paymentHoldCompleted) {
22453
22512
  setPaymentHoldModalVisible(true);
@@ -22461,12 +22520,12 @@ function ActualQuote({ onQuoteAccepted }) {
22461
22520
  }
22462
22521
  // Derived state
22463
22522
  const isAccepted = formattedQuote.state === 'ACCEPTED';
22464
- const firstInvoice = (_a = formattedQuote.quote) === null || _a === void 0 ? void 0 : _a.firstInvoice;
22523
+ const firstInvoice = (_b = formattedQuote.quote) === null || _b === void 0 ? void 0 : _b.firstInvoice;
22465
22524
  if ((firstInvoice === null || firstInvoice === void 0 ? void 0 : firstInvoice.state) === 'PAID' && paymentHoldCompleted) {
22466
22525
  return jsxRuntime.jsx(Invoice, { id: firstInvoice.id });
22467
22526
  }
22468
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-4 ${isMobile ? 'bunny-w-full bunny-overflow-hidden' : ''} ${className}`, children: [jsxRuntime.jsx(QuoteButtons, { isAccepted: isAccepted, formattedQuote: formattedQuote, isMobile: isMobile, hideDownloadButton: hideDownloadButton, id: id, isAccepting: isAccepting, handleClickAccept: handleClickAccept, setPaymentHoldModalVisible: setPaymentHoldModalVisible, shouldDoPaymentHold: shouldDoPaymentHold, paymentHoldCompleted: paymentHoldCompleted, paymentHold: paymentHold, isSendAcceptPending: isSendAcceptPending }), jsxRuntime.jsx(InvoiceQuoteView, { html: formattedQuote.html, targetUrl: ((_b = formattedQuote === null || formattedQuote === void 0 ? void 0 : formattedQuote.quote) === null || _b === void 0 ? void 0 : _b.documentTemplateId) ? `/pdf/quote` : undefined, children: ((_d = (_c = formattedQuote === null || formattedQuote === void 0 ? void 0 : formattedQuote.quote) === null || _c === void 0 ? void 0 : _c.documents) === null || _d === void 0 ? void 0 : _d.length) &&
22469
- ((_f = (_e = formattedQuote === null || formattedQuote === void 0 ? void 0 : formattedQuote.quote) === null || _e === void 0 ? void 0 : _e.documents) === null || _f === void 0 ? void 0 : _f.length) > 0 ? (jsxRuntime.jsx("div", { className: "bunny-flex bunny-flex-col bunny-items-end", children: formattedQuote.quote.documents.map((doc, index) => {
22527
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-4 ${isMobile ? 'bunny-w-full bunny-overflow-hidden' : ''} ${className}`, children: [jsxRuntime.jsx(QuoteButtons, { isAccepted: isAccepted, formattedQuote: formattedQuote, isMobile: isMobile, hideDownloadButton: hideDownloadButton, id: id, isAccepting: isAccepting, handleClickAccept: handleClickAccept, setPaymentHoldModalVisible: setPaymentHoldModalVisible, shouldDoPaymentHold: shouldDoPaymentHold, paymentHoldCompleted: paymentHoldCompleted, paymentHold: paymentHold, isSendAcceptPending: isSendAcceptPending }), jsxRuntime.jsx(InvoiceQuoteView, { html: formattedQuote.html, targetUrl: ((_c = formattedQuote === null || formattedQuote === void 0 ? void 0 : formattedQuote.quote) === null || _c === void 0 ? void 0 : _c.documentTemplateId) ? `/pdf/quote` : undefined, children: ((_e = (_d = formattedQuote === null || formattedQuote === void 0 ? void 0 : formattedQuote.quote) === null || _d === void 0 ? void 0 : _d.documents) === null || _e === void 0 ? void 0 : _e.length) &&
22528
+ ((_g = (_f = formattedQuote === null || formattedQuote === void 0 ? void 0 : formattedQuote.quote) === null || _f === void 0 ? void 0 : _f.documents) === null || _g === void 0 ? void 0 : _g.length) > 0 ? (jsxRuntime.jsx("div", { className: "bunny-flex bunny-flex-col bunny-items-end", children: formattedQuote.quote.documents.map((doc, index) => {
22470
22529
  return (jsxRuntime.jsx(antd.Button, { download: doc.filename, href: doc.url, type: "link", children: doc.filename }, index));
22471
22530
  }) })) : null })] }), jsxRuntime.jsx(AcceptQuoteModal, { acceptBoxVisible: acceptBoxVisible, formattedQuote: formattedQuote, setAcceptBoxVisible: setAcceptBoxVisible, setIsAccepting: setIsAccepting, sendAccept: sendAccept, isSendAcceptPending: isSendAcceptPending }), jsxRuntime.jsx(PaymentHoldModal, { visible: paymentHoldModalVisible, setVisible: setPaymentHoldModalVisible, formattedQuote: formattedQuote, sendAccept: sendAccept }), jsxRuntime.jsx(PandadocPollingModal, { isVisible: pandadocPollingModalVisible, setVisible: setPandadocPollingModalVisible, id: id })] }));
22472
22531
  }
@@ -22955,15 +23014,15 @@ function QuotesWrapper() {
22955
23014
  return (jsxRuntime.jsx(TransactionsDisplay, { transactions: quotesAsTransactions, onSearchValueChanged: setSearch, search: search }));
22956
23015
  }
22957
23016
 
22958
- const shouldShowCouponEditor_QuoteFragment = t(`
22959
- fragment shouldShowCouponEditor_QuoteFragment on Quote {
23017
+ const canApplyCoupons_QuoteFragment = t(`
23018
+ fragment canApplyCoupons_QuoteFragment on Quote {
22960
23019
  id
22961
23020
  kind
22962
23021
  amountDue
22963
23022
  }
22964
23023
  `, []);
22965
- const shouldShowCouponEditor_SubscriptionFragment = t(`
22966
- fragment shouldShowCouponEditor_SubscriptionFragment on Subscription {
23024
+ const canApplyCoupons_SubscriptionFragment = t(`
23025
+ fragment canApplyCoupons_SubscriptionFragment on Subscription {
22967
23026
  id
22968
23027
  state
22969
23028
  charges {
@@ -22971,10 +23030,10 @@ const shouldShowCouponEditor_SubscriptionFragment = t(`
22971
23030
  }
22972
23031
  }
22973
23032
  `, []);
22974
- function shouldShowCouponEditor(maskedQuote, activeCouponsExist, maskedUpgradingSubscription) {
23033
+ function canApplyCoupons(maskedQuote, activeCouponsExist, maskedUpgradingSubscription) {
22975
23034
  var _a, _b;
22976
- const quote = readFragment(shouldShowCouponEditor_QuoteFragment, maskedQuote);
22977
- const upgradingSubscription = readFragment(shouldShowCouponEditor_SubscriptionFragment, maskedUpgradingSubscription);
23035
+ const quote = readFragment(canApplyCoupons_QuoteFragment, maskedQuote);
23036
+ const upgradingSubscription = readFragment(canApplyCoupons_SubscriptionFragment, maskedUpgradingSubscription);
22978
23037
  const upgradingFromTrial = ((_a = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL') ||
22979
23038
  ((_b = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) ===
22980
23039
  t.scalar('SubscriptionState', 'TRIAL_EXPIRED');
@@ -22992,7 +23051,9 @@ function shouldShowCouponEditor(maskedQuote, activeCouponsExist, maskedUpgrading
22992
23051
  return false;
22993
23052
  }
22994
23053
  if (quoteKindIsValid) {
22995
- return activeCouponsExist && (upgradingFromTrial || upgradingFromFree() || signingUpForNewSubscription);
23054
+ const result = activeCouponsExist &&
23055
+ (upgradingFromTrial || upgradingFromFree() || signingUpForNewSubscription);
23056
+ return result;
22996
23057
  }
22997
23058
  return false;
22998
23059
  }
@@ -23004,6 +23065,27 @@ function CouponEditor({ className, onAddCoupon, isAddingCoupon, couponCode, setC
23004
23065
  return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-flex-col bunny-gap-2 ${className}`, children: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2", children: [jsxRuntime.jsx(antd.Input, { value: couponCode, onChange: e => setCouponCode(e.target.value), placeholder: "Coupon code", disabled: isAddingCoupon, size: "small" }), jsxRuntime.jsx(antd.Button, { loading: isAddingCoupon, type: "primary", onClick: handleAddCoupon, disabled: couponCode.length === 0, children: "Apply" })] }) }));
23005
23066
  }
23006
23067
 
23068
+ t(`
23069
+ fragment sortQuoteChangeCharges_QuoteChargeFragment on QuoteCharge {
23070
+ kind
23071
+ }
23072
+ `, []);
23073
+ /**
23074
+ * Sorts quote change charges so that coupon charges appear at the end of the list.
23075
+ * Uses a generic type so the full charge shape is preserved.
23076
+ */
23077
+ function sortQuoteChangeCharges(charges) {
23078
+ return [...charges].sort((chargeA, chargeB) => {
23079
+ const aIsCoupon = chargeA.kind === 'COUPON';
23080
+ const bIsCoupon = chargeB.kind === 'COUPON';
23081
+ if (aIsCoupon && !bIsCoupon)
23082
+ return 1;
23083
+ if (!aIsCoupon && bIsCoupon)
23084
+ return -1;
23085
+ return 0;
23086
+ });
23087
+ }
23088
+
23007
23089
  const { Text: Text$r } = antd.Typography;
23008
23090
  const CheckoutSummary_PriceListFragment = t(`
23009
23091
  fragment CheckoutSummary_PriceListFragment on PriceList {
@@ -23033,14 +23115,14 @@ const CheckoutSummary_QuoteFragment = t(`
23033
23115
  currencyId
23034
23116
  }
23035
23117
  }
23036
- ...shouldShowCouponEditor_QuoteFragment
23118
+ ...canApplyCoupons_QuoteFragment
23037
23119
  }
23038
- `, [shouldShowCouponEditor_QuoteFragment]);
23120
+ `, [canApplyCoupons_QuoteFragment]);
23039
23121
  function CheckoutSummary({ quote: maskedQuote, className, onAddCoupon, onRemoveCoupon, isRemovingCoupon, priceList: maskedPriceList, isAddingCoupon, couponCode, setCouponCode, activeCouponsExist, }) {
23040
23122
  var _a, _b;
23041
23123
  const priceList = readFragment(CheckoutSummary_PriceListFragment, maskedPriceList);
23042
23124
  const quote = readFragment(CheckoutSummary_QuoteFragment, maskedQuote);
23043
- return (jsxRuntime.jsxs("div", { className: `${className} bunny-space-y-4`, children: [jsxRuntime.jsxs(Text$r, { children: [jsxRuntime.jsxs("div", { className: "bunny-text-lg bunny-font-medium bunny-mb-4", children: ["Checkout summary - ", (_a = priceList === null || priceList === void 0 ? void 0 : priceList.product) === null || _a === void 0 ? void 0 : _a.name, " ", priceList === null || priceList === void 0 ? void 0 : priceList.name] }), jsxRuntime.jsx("div", { className: "bunny-space-y-4", children: (_b = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _b === void 0 ? void 0 : _b.map(quoteChange => quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.charges.map(charge => {
23125
+ return (jsxRuntime.jsxs("div", { className: `${className} bunny-space-y-4`, children: [jsxRuntime.jsxs(Text$r, { children: [jsxRuntime.jsxs("div", { className: "bunny-text-lg bunny-font-medium bunny-mb-4", children: ["Checkout summary - ", (_a = priceList === null || priceList === void 0 ? void 0 : priceList.product) === null || _a === void 0 ? void 0 : _a.name, " ", priceList === null || priceList === void 0 ? void 0 : priceList.name] }), jsxRuntime.jsx("div", { className: "bunny-space-y-4", children: (_b = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _b === void 0 ? void 0 : _b.map(quoteChange => sortQuoteChangeCharges(quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.charges).map(charge => {
23044
23126
  var _a;
23045
23127
  const multiplier = charge.kind === 'COUPON' ? -1 : 1;
23046
23128
  return (jsxRuntime.jsxs("div", { className: "bunny-grid bunny-grid-cols-3 bunny-gap-4 bunny-items-center", children: [jsxRuntime.jsx("div", { className: "bunny-col-span-1", children: charge.name }), jsxRuntime.jsx("div", { className: "bunny-col-span-1 bunny-text-center", children: ((_a = charge.coupon) === null || _a === void 0 ? void 0 : _a.couponCode) ? (jsxRuntime.jsx("button", { onClick: () => {
@@ -23053,7 +23135,7 @@ function CheckoutSummary({ quote: maskedQuote, className, onAddCoupon, onRemoveC
23053
23135
  }
23054
23136
  onRemoveCoupon((_b = charge.coupon) === null || _b === void 0 ? void 0 : _b.couponCode);
23055
23137
  }, className: "bunny-text-orange-500 hover:bunny-text-orange-400 bunny-cursor-pointer bunny-bg-transparent bunny-border-none", children: "Remove" })) : (jsxRuntime.jsx("div", { children: charge.quantity })) }), jsxRuntime.jsx("div", { className: "bunny-col-span-1 bunny-text-right", children: formatCurrency(multiplier * (charge.subtotal || 0), charge.currencyId) })] }, charge.id));
23056
- })) }), jsxRuntime.jsx(CheckoutSummaryDivider, {}), jsxRuntime.jsxs("div", { className: "bunny-space-y-4", children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsxRuntime.jsx("div", { children: "Subtotal" }), jsxRuntime.jsx("div", { children: formatCurrency(quote.subtotal, quote.currencyId) })] }), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsxRuntime.jsx("div", { children: "Taxes" }), jsxRuntime.jsx("div", { children: formatCurrency(quote.taxAmount, quote.currencyId) })] })] }), jsxRuntime.jsx(CheckoutSummaryDivider, {}), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsxRuntime.jsx("div", { children: "Total" }), jsxRuntime.jsx("div", { children: formatCurrency(quote.amountDue, quote.currencyId) })] })] }), shouldShowCouponEditor(quote, activeCouponsExist) && (jsxRuntime.jsx(CouponEditor, { className: "bunny-w-full", onAddCoupon: onAddCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode }))] }));
23138
+ })) }), jsxRuntime.jsx(CheckoutSummaryDivider, {}), jsxRuntime.jsxs("div", { className: "bunny-space-y-4", children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsxRuntime.jsx("div", { children: "Subtotal" }), jsxRuntime.jsx("div", { children: formatCurrency(quote.subtotal, quote.currencyId) })] }), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsxRuntime.jsx("div", { children: "Taxes" }), jsxRuntime.jsx("div", { children: formatCurrency(quote.taxAmount, quote.currencyId) })] })] }), jsxRuntime.jsx(CheckoutSummaryDivider, {}), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-justify-between", children: [jsxRuntime.jsx("div", { children: "Total" }), jsxRuntime.jsx("div", { children: formatCurrency(quote.amountDue, quote.currencyId) })] })] }), canApplyCoupons(quote, activeCouponsExist) && (jsxRuntime.jsx(CouponEditor, { className: "bunny-w-full", onAddCoupon: onAddCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode }))] }));
23057
23139
  }
23058
23140
  const CheckoutSummaryDivider = () => {
23059
23141
  return (jsxRuntime.jsx("div", { className: "bunny-my-2", children: jsxRuntime.jsx(antd.Divider, { className: "m-0" }) }));
@@ -23104,10 +23186,36 @@ function InitialSignupForm({ className, onSubmit, submitting, defaultValues, })
23104
23186
  } }) }) }) }), jsxRuntime.jsx(antd.Form.Item, { children: jsxRuntime.jsx(antd.Button, { type: "primary", onClick: handleSubmit, loading: submitting, className: "bunny-w-full", children: "Proceed to payment" }) })] }) }));
23105
23187
  }
23106
23188
 
23189
+ const useApplyDefaultCoupon_QuoteFragment = t(`
23190
+ fragment useApplyDefaultCoupon_QuoteFragment on Quote {
23191
+ ...canApplyCoupons_QuoteFragment
23192
+ }
23193
+ `, [canApplyCoupons_QuoteFragment]);
23194
+ /**
23195
+ * Applies a default coupon code once when quoteChangeId is available.
23196
+ * Uses a ref to ensure coupon code is only applied once.
23197
+ */
23198
+ function useApplyDefaultCoupon({ couponCode, quoteChangeId, quote: maskedQuote, activeCouponsExist, addCoupon, }) {
23199
+ const defaultCouponAppliedRef = react.useRef(undefined);
23200
+ // Derived state
23201
+ const quote = readFragment(useApplyDefaultCoupon_QuoteFragment, maskedQuote);
23202
+ const canApplyCouponsResult = canApplyCoupons(quote, activeCouponsExist);
23203
+ react.useEffect(() => {
23204
+ if (couponCode &&
23205
+ quoteChangeId &&
23206
+ defaultCouponAppliedRef.current !== couponCode &&
23207
+ canApplyCouponsResult) {
23208
+ addCoupon(couponCode);
23209
+ defaultCouponAppliedRef.current = couponCode;
23210
+ }
23211
+ }, [couponCode, quoteChangeId, addCoupon, canApplyCouponsResult]);
23212
+ }
23213
+
23107
23214
  const Signup_QuoteFragment = t(`
23108
23215
  fragment Signup_QuoteFragment on Quote {
23109
23216
  ...CheckoutSummary_QuoteFragment
23110
23217
  ...PaymentForms_QuoteFragment
23218
+ ...useApplyDefaultCoupon_QuoteFragment
23111
23219
  id
23112
23220
  currencyId
23113
23221
  amountDue
@@ -23115,7 +23223,7 @@ const Signup_QuoteFragment = t(`
23115
23223
  id
23116
23224
  }
23117
23225
  }
23118
- `, [CheckoutSummary_QuoteFragment, PaymentForms_QuoteFragment]);
23226
+ `, [CheckoutSummary_QuoteFragment, PaymentForms_QuoteFragment, useApplyDefaultCoupon_QuoteFragment]);
23119
23227
 
23120
23228
  const query$6 = t(`
23121
23229
  query quote($id: ID) {
@@ -23571,7 +23679,6 @@ function Signup({ companyName, priceListCode, returnUrl, couponCode, className,
23571
23679
  const [portalSessionToken, setPortalSessionToken] = react.useState(undefined);
23572
23680
  const token = portalSessionToken || tokenFromContexts;
23573
23681
  const [purchaseSucceeded, setPurchaseSucceeded] = react.useState(false);
23574
- const defaultCouponAppliedRef = react.useRef(undefined);
23575
23682
  const [couponEditorCouponCode, setCouponEditorCouponCode] = react.useState('');
23576
23683
  // Read fragment
23577
23684
  const initialQuoteId = (_a = readFragment(Signup_QuoteFragment, initialQuote)) === null || _a === void 0 ? void 0 : _a.id;
@@ -23688,13 +23795,7 @@ function Signup({ companyName, priceListCode, returnUrl, couponCode, className,
23688
23795
  handleRecalculateTaxes(quote === null || quote === void 0 ? void 0 : quote.id);
23689
23796
  },
23690
23797
  });
23691
- // Handle default coupon application
23692
- react.useEffect(() => {
23693
- if (couponCode && quoteChangeId && defaultCouponAppliedRef.current !== couponCode) {
23694
- addCoupon(couponCode);
23695
- defaultCouponAppliedRef.current = couponCode;
23696
- }
23697
- }, [couponCode, quoteChangeId]);
23798
+ useApplyDefaultCoupon({ couponCode, quoteChangeId, addCoupon, activeCouponsExist, quote });
23698
23799
  async function handleSubmit(formData) {
23699
23800
  if (selfServiceBuyEnabled === false) {
23700
23801
  handleShowSelfServiceBuyWarning();
@@ -23924,22 +24025,22 @@ const QuoteCheckout_QuoteFragment = t(`
23924
24025
  }
23925
24026
  }
23926
24027
  ...QuoteFields_QuoteFragment
23927
- ...shouldShowCouponEditor_QuoteFragment
24028
+ ...canApplyCoupons_QuoteFragment
23928
24029
  ...PaymentForm_QuoteFragment
23929
24030
  ...getQuoteAmountDue_QuoteFragment
23930
24031
  }
23931
24032
  `, [
23932
24033
  QuoteFields_QuoteFragment,
23933
- shouldShowCouponEditor_QuoteFragment,
24034
+ canApplyCoupons_QuoteFragment,
23934
24035
  PaymentForm_QuoteFragment,
23935
24036
  getQuoteAmountDue_QuoteFragment,
23936
24037
  ]);
23937
24038
  const QuoteCheckout_SubscriptionFragment = t(`
23938
24039
  fragment QuoteCheckout_SubscriptionFragment on Subscription {
23939
24040
  id
23940
- ...shouldShowCouponEditor_SubscriptionFragment
24041
+ ...canApplyCoupons_SubscriptionFragment
23941
24042
  }
23942
- `, [shouldShowCouponEditor_SubscriptionFragment]);
24043
+ `, [canApplyCoupons_SubscriptionFragment]);
23943
24044
  const showSuccessNotification = useSuccessNotification();
23944
24045
  const QuoteCheckout = ({ account, onSuccess, onFail, quote: maskedQuote, taxationRequiredAccountFields, isUpdatingQuote, onRecalculateTaxes, isRecalculatingTaxes, }) => {
23945
24046
  var _a, _b, _c, _d, _e;
@@ -24025,7 +24126,7 @@ const QuoteCheckout = ({ account, onSuccess, onFail, quote: maskedQuote, taxatio
24025
24126
  if (taxationRequiredAccountFields)
24026
24127
  return (jsxRuntime.jsx(PaymentFormWrapper, { setMaxHeight: false, children: jsxRuntime.jsx(TaxationForm, { account: account, accountId: quote.accountId }) }));
24027
24128
  return (jsxRuntime.jsx(PaymentFormWrapper, { setMaxHeight: false, children: paymentRequired ? (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2 bunny-w-full", children: [jsxRuntime.jsx(PaymentForm, { onPaymentSuccess: onSuccess, quote: quote, onSavePaymentMethod: (paymentMethod) => onPaymentMethodSaved === null || onPaymentMethodSaved === void 0 ? void 0 : onPaymentMethodSaved(paymentMethod.savedPaymentMethodResponse.paymentMethodId), onPaymentMethodRemoved: (paymentMethod) => onPaymentMethodRemoved === null || onPaymentMethodRemoved === void 0 ? void 0 : onPaymentMethodRemoved(paymentMethod.id), disablePayButton: isFinalizingQuote }), isFinalizingQuote && jsxRuntime.jsx(QuoteLoadingIndicator, {}), (couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.length) === 0 ? (jsxRuntime.jsx(jsxRuntime.Fragment, { children: upgradingSubscription &&
24028
- shouldShowCouponEditor(quote, activeCouponsExist, upgradingSubscription) && (jsxRuntime.jsx(CouponEditor, { className: "bunny-px-4 bunny-pt-1", onAddCoupon: addCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode })) })) : (jsxRuntime.jsx(antd.Button, { type: "link", loading: isRemovingCoupon, onClick: () => {
24129
+ canApplyCoupons(quote, activeCouponsExist, upgradingSubscription) && (jsxRuntime.jsx(CouponEditor, { className: "bunny-px-4 bunny-pt-1", onAddCoupon: addCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode })) })) : (jsxRuntime.jsx(antd.Button, { type: "link", loading: isRemovingCoupon, onClick: () => {
24029
24130
  couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.forEach(couponCharge => {
24030
24131
  var _a;
24031
24132
  const couponCode = (_a = couponCharge === null || couponCharge === void 0 ? void 0 : couponCharge.coupon) === null || _a === void 0 ? void 0 : _a.couponCode;