@bunnyapp/components 1.6.0 → 1.7.0-beta.3

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 (99) hide show
  1. package/dist/cjs/index.js +1561 -1258
  2. package/dist/cjs/types/src/components/BillingDetails/BillingDetailsForm.d.ts +0 -1
  3. package/dist/cjs/types/src/components/BillingDetails/components/AddContactButton.d.ts +3 -0
  4. package/dist/cjs/types/src/components/BillingDetails/components/AddContactModal.d.ts +8 -0
  5. package/dist/cjs/types/src/components/BillingDetails/fragments/AccountContactsFragment.d.ts +9 -0
  6. package/dist/cjs/types/src/components/BillingDetails/fragments/BillingDetailsSection_AccountFragment.d.ts +20 -0
  7. package/dist/cjs/types/src/components/BillingDetails/hooks/useSetAccountContactsQueryData.d.ts +5 -0
  8. package/dist/cjs/types/src/components/BillingDetails/mutations/accountUpdate.d.ts +22 -0
  9. package/dist/cjs/types/src/components/BillingDetails/mutations/contactCreate.d.ts +22 -0
  10. package/dist/cjs/types/src/components/BillingDetails/queries/getAccount.d.ts +9 -0
  11. package/dist/cjs/types/src/components/BillingDetails/queries/getAccountContacts.d.ts +9 -0
  12. package/dist/cjs/types/src/components/Checkout/Checkout.d.ts +2 -1
  13. package/dist/cjs/types/src/components/QuoteProvider/context/QuoteContext.d.ts +1 -0
  14. package/dist/cjs/types/src/components/QuoteProvider/fragments/quoteFragment.d.ts +7 -0
  15. package/dist/cjs/types/src/components/QuoteProvider/hooks/useQuoteRecalculateTaxes.d.ts +11 -0
  16. package/dist/cjs/types/src/components/QuoteProvider/hooks/useSetQuoteQueryData.d.ts +5 -0
  17. package/dist/cjs/types/src/components/QuoteProvider/mutations/quoteRecalculateTaxes.d.ts +11 -0
  18. package/dist/cjs/types/src/components/Subscriptions/AddonSubscriptionCards.d.ts +3 -2
  19. package/dist/cjs/types/src/components/Subscriptions/SubscriptionsListContainer.d.ts +2 -2
  20. package/dist/cjs/types/src/components/Subscriptions/Upgrade/PlanPicker/checkoutBar/CheckoutBarSummarySection.d.ts +15 -2
  21. package/dist/cjs/types/src/components/Subscriptions/Upgrade/PlanPicker/checkoutBar/CheckoutButton.d.ts +2 -2
  22. package/dist/cjs/types/src/components/Subscriptions/Upgrade/PlanPicker/checkoutBar/CheckoutPrice.d.ts +12 -3
  23. package/dist/cjs/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/featureAddons/fragments/FeatureAddonRow_QuoteFragment.d.ts +9 -0
  24. package/dist/cjs/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/featureAddons/fragments/useQuoteUpdateFeatureAddon_QuoteFragment.d.ts +8 -0
  25. package/dist/cjs/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/featureAddons/hooks/useQuoteUpdateFeatureAddon.d.ts +9 -0
  26. package/dist/cjs/types/src/{graphql → components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/featureAddons}/mutations/quoteChargeCreate.d.ts +12 -2
  27. package/dist/cjs/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/priceListCardDesktop/addonPlans/components/AddonPlanRow.d.ts +1 -0
  28. package/dist/cjs/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/priceListCardDesktop/addonPlans/fragments/AddonPlanRow_QuoteFragment.d.ts +9 -0
  29. package/dist/cjs/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/priceListCardDesktop/addonPlans/fragments/useToggleAddonPlan_QuoteFragment.d.ts +13 -0
  30. package/dist/cjs/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/priceListCardDesktop/addonPlans/hooks/useToggleAddonQuoteChange.d.ts +9 -0
  31. package/dist/cjs/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/priceListCardDesktop/addonPlans/mutations/quoteChangeCreate.d.ts +18 -0
  32. package/dist/cjs/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/priceListCardDesktop/addonPlans/mutations/quoteChangeDelete.d.ts +15 -0
  33. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/context/quoteIsLoadingContext.d.ts +5 -0
  34. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/context/quoteRecalculateTaxesContext.d.ts +6 -0
  35. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/hooks/useQuoteRecalculateTaxes.d.ts +11 -0
  36. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/mutations/quoteDelete.d.ts +12 -0
  37. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/mutations/quoteRecalculateTaxes.d.ts +11 -0
  38. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/quantityInput/QuantityInput.d.ts +10 -1
  39. package/dist/cjs/types/src/components/Subscriptions/quantityChangeDrawer/quantityInput/QuoteIsLoadingUpdater.d.ts +9 -0
  40. package/dist/cjs/types/src/components/Subscriptions/subscriptionsList/SubscriptionsList.d.ts +2 -2
  41. package/dist/cjs/types/src/components/Subscriptions/tieredDisplayDropdown/TieredDisplayDropdown.d.ts +3 -1
  42. package/dist/cjs/types/src/utils/QueryKeyFactory.d.ts +10 -0
  43. package/dist/esm/index.js +1562 -1259
  44. package/dist/esm/types/src/components/BillingDetails/BillingDetailsForm.d.ts +0 -1
  45. package/dist/esm/types/src/components/BillingDetails/components/AddContactButton.d.ts +3 -0
  46. package/dist/esm/types/src/components/BillingDetails/components/AddContactModal.d.ts +8 -0
  47. package/dist/esm/types/src/components/BillingDetails/fragments/AccountContactsFragment.d.ts +9 -0
  48. package/dist/esm/types/src/components/BillingDetails/fragments/BillingDetailsSection_AccountFragment.d.ts +20 -0
  49. package/dist/esm/types/src/components/BillingDetails/hooks/useSetAccountContactsQueryData.d.ts +5 -0
  50. package/dist/esm/types/src/components/BillingDetails/mutations/accountUpdate.d.ts +22 -0
  51. package/dist/esm/types/src/components/BillingDetails/mutations/contactCreate.d.ts +22 -0
  52. package/dist/esm/types/src/components/BillingDetails/queries/getAccount.d.ts +9 -0
  53. package/dist/esm/types/src/components/BillingDetails/queries/getAccountContacts.d.ts +9 -0
  54. package/dist/esm/types/src/components/Checkout/Checkout.d.ts +2 -1
  55. package/dist/esm/types/src/components/QuoteProvider/context/QuoteContext.d.ts +1 -0
  56. package/dist/esm/types/src/components/QuoteProvider/fragments/quoteFragment.d.ts +7 -0
  57. package/dist/esm/types/src/components/QuoteProvider/hooks/useQuoteRecalculateTaxes.d.ts +11 -0
  58. package/dist/esm/types/src/components/QuoteProvider/hooks/useSetQuoteQueryData.d.ts +5 -0
  59. package/dist/esm/types/src/components/QuoteProvider/mutations/quoteRecalculateTaxes.d.ts +11 -0
  60. package/dist/esm/types/src/components/Subscriptions/AddonSubscriptionCards.d.ts +3 -2
  61. package/dist/esm/types/src/components/Subscriptions/SubscriptionsListContainer.d.ts +2 -2
  62. package/dist/esm/types/src/components/Subscriptions/Upgrade/PlanPicker/checkoutBar/CheckoutBarSummarySection.d.ts +15 -2
  63. package/dist/esm/types/src/components/Subscriptions/Upgrade/PlanPicker/checkoutBar/CheckoutButton.d.ts +2 -2
  64. package/dist/esm/types/src/components/Subscriptions/Upgrade/PlanPicker/checkoutBar/CheckoutPrice.d.ts +12 -3
  65. package/dist/esm/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/featureAddons/fragments/FeatureAddonRow_QuoteFragment.d.ts +9 -0
  66. package/dist/esm/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/featureAddons/fragments/useQuoteUpdateFeatureAddon_QuoteFragment.d.ts +8 -0
  67. package/dist/esm/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/featureAddons/hooks/useQuoteUpdateFeatureAddon.d.ts +9 -0
  68. package/dist/esm/types/src/{graphql → components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/featureAddons}/mutations/quoteChargeCreate.d.ts +12 -2
  69. package/dist/esm/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/priceListCardDesktop/addonPlans/components/AddonPlanRow.d.ts +1 -0
  70. package/dist/esm/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/priceListCardDesktop/addonPlans/fragments/AddonPlanRow_QuoteFragment.d.ts +9 -0
  71. package/dist/esm/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/priceListCardDesktop/addonPlans/fragments/useToggleAddonPlan_QuoteFragment.d.ts +13 -0
  72. package/dist/esm/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/priceListCardDesktop/addonPlans/hooks/useToggleAddonQuoteChange.d.ts +9 -0
  73. package/dist/esm/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/priceListCardDesktop/addonPlans/mutations/quoteChangeCreate.d.ts +18 -0
  74. package/dist/esm/types/src/components/Subscriptions/Upgrade/PlanPicker/planPickerDesktop/priceListCardDesktop/addonPlans/mutations/quoteChangeDelete.d.ts +15 -0
  75. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/context/quoteIsLoadingContext.d.ts +5 -0
  76. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/context/quoteRecalculateTaxesContext.d.ts +6 -0
  77. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/hooks/useQuoteRecalculateTaxes.d.ts +11 -0
  78. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/mutations/quoteDelete.d.ts +12 -0
  79. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/mutations/quoteRecalculateTaxes.d.ts +11 -0
  80. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/quantityInput/QuantityInput.d.ts +10 -1
  81. package/dist/esm/types/src/components/Subscriptions/quantityChangeDrawer/quantityInput/QuoteIsLoadingUpdater.d.ts +9 -0
  82. package/dist/esm/types/src/components/Subscriptions/subscriptionsList/SubscriptionsList.d.ts +2 -2
  83. package/dist/esm/types/src/components/Subscriptions/tieredDisplayDropdown/TieredDisplayDropdown.d.ts +3 -1
  84. package/dist/esm/types/src/utils/QueryKeyFactory.d.ts +10 -0
  85. package/package.json +2 -2
  86. package/dist/cjs/types/src/graphql/mutations/billingDetailsUpdate.d.ts +0 -6
  87. package/dist/cjs/types/src/graphql/mutations/quoteAddonCreate.d.ts +0 -7
  88. package/dist/cjs/types/src/graphql/mutations/quoteChangeCreate.d.ts +0 -8
  89. package/dist/cjs/types/src/graphql/mutations/quoteChangeDelete.d.ts +0 -6
  90. package/dist/cjs/types/src/graphql/queries/getBillingDetails.d.ts +0 -6
  91. package/dist/cjs/types/src/hooks/quotes/useQuoteUpdateFeatureAddon.d.ts +0 -7
  92. package/dist/cjs/types/src/hooks/useToggleAddonQuoteChange.d.ts +0 -7
  93. package/dist/esm/types/src/graphql/mutations/billingDetailsUpdate.d.ts +0 -6
  94. package/dist/esm/types/src/graphql/mutations/quoteAddonCreate.d.ts +0 -7
  95. package/dist/esm/types/src/graphql/mutations/quoteChangeCreate.d.ts +0 -8
  96. package/dist/esm/types/src/graphql/mutations/quoteChangeDelete.d.ts +0 -6
  97. package/dist/esm/types/src/graphql/queries/getBillingDetails.d.ts +0 -6
  98. package/dist/esm/types/src/hooks/quotes/useQuoteUpdateFeatureAddon.d.ts +0 -7
  99. package/dist/esm/types/src/hooks/useToggleAddonQuoteChange.d.ts +0 -7
package/dist/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
2
  import { isValidElement, createContext, useContext, useMemo, useState, useEffect, useRef, createElement, useCallback, Fragment as Fragment$1 } from 'react';
3
3
  import { DownloadOutlined, CreditCardOutlined, EllipsisOutlined, BankOutlined, SearchOutlined, CloseOutlined, CheckCircleFilled, InfoCircleOutlined } from '@ant-design/icons';
4
- import { useErrorNotification, DEFAULT_CONFIG, createClientDevHeaders as createClientDevHeaders$1, X_BUNNY_COMPONENTS_VERSION_HEADER_NAME, QueryKeyFactory as QueryKeyFactory$1, useIsMobile as useIsMobile$1, DEFAULT_BRAND_COLOR, isColorTooDark, DEFAULT_TOP_NAV_IMAGE_URL, DEFAULT_ACCENT_COLOR, INPUT_BORDER_COLOR, SLATE_50, SLATE_400, SLATE_200, DEFAULT_SECONDARY_COLOR, request as request$1, useAllErrorFormats as useAllErrorFormats$1, formatCurrency as formatCurrency$1, GRAY_500, GRAY_200, useSuccessNotification, PAYABLE_INVOICE_STATES, BreakpointNumbers as BreakpointNumbers$1, useGraphQLmutation, useInfoNotification, formatDate, TransactionState, SLATE_600, WHITE, TransactionKind, QuoteChangeKind, SLATE_500, PRIMARY_COLOR, Lists, getAccount, ChargeType, PERIOD_LABELS, MODAL_MAX_HEIGHT, DataInterval, SLATE_100 } from '@bunnyapp/common';
4
+ import { useErrorNotification, DEFAULT_CONFIG, createClientDevHeaders as createClientDevHeaders$1, X_BUNNY_COMPONENTS_VERSION_HEADER_NAME, QueryKeyFactory as QueryKeyFactory$1, useIsMobile as useIsMobile$1, DEFAULT_BRAND_COLOR, isColorTooDark, DEFAULT_TOP_NAV_IMAGE_URL, DEFAULT_ACCENT_COLOR, INPUT_BORDER_COLOR, SLATE_50, SLATE_400, SLATE_200, DEFAULT_SECONDARY_COLOR, request as request$1, useAllErrorFormats as useAllErrorFormats$1, formatCurrency as formatCurrency$1, GRAY_500, GRAY_200, useSuccessNotification, PAYABLE_INVOICE_STATES, BreakpointNumbers as BreakpointNumbers$1, useGraphQLmutation, useInfoNotification, formatDate, TransactionState, SLATE_600, WHITE, TransactionKind, QuoteChangeKind, ChargeType, PERIOD_LABELS, SLATE_500, PRIMARY_COLOR, Lists, getAccount as getAccount$1, MODAL_MAX_HEIGHT, DataInterval, SLATE_100 } from '@bunnyapp/common';
5
5
  import { ConfigProvider, Spin, Typography, Button, theme as theme$1, Tag, Dropdown, Input, Modal, Checkbox, Skeleton, Collapse, Form, Tooltip, Drawer, Card as Card$1, Select, Divider, Popconfirm, Table, Radio, Space, Switch } from 'antd';
6
6
  import { Markup } from 'interweave';
7
7
  import request from 'graphql-request';
@@ -46,7 +46,7 @@ function styleInject(css, ref) {
46
46
  }
47
47
  }
48
48
 
49
- var css_248z = ":root {\n --row-background: #ffffff;\n --row-background-alternate: rgba(100, 116, 139, 0.04);\n --row-background-dark: #121212;\n --row-background-alternate-dark: #1e1e1e;\n --bunny-blue-500: #3b82f6;\n --bunny-blue-200: #bfdbfe;\n --bunny-green-600: #059669;\n --bunny-green-200: #a7f3d0;\n --bunny-red-500: #ef4444;\n --bunny-red-200: #fecaca;\n --bunny-orange-500: #f97316;\n --bunny-orange-200: #fed7aa;\n --bunny-yellow-500: #f59e0b;\n --bunny-yellow-200: #fde68a;\n --bunny-purple-500: #8b5cf6;\n --bunny-purple-200: #ddd6fe;\n --bunny-black: #000000;\n}\n.bunny-component-wrapper {\n box-sizing: border-box;\n}\n.bunny-component-wrapper * {\n box-sizing: border-box;\n}\n.hidden {\n display: none;\n}\n.bunny-show-on-hover {\n opacity: 0;\n}\n.bunny-show-on-hover-container:hover .bunny-show-on-hover {\n opacity: 1;\n}\n.has-tooltip:hover .tooltip {\n visibility: visible;\n z-index: 100;\n}\n.pdf-only {\n display: none !important;\n}\n.notes p {\n margin: 0;\n padding: 0;\n padding-bottom: 0.25rem;\n}\n.bunny-icon-path {\n transition: fill 0.3s;\n}\n.bunny-shadow-padding-x {\n padding-right: 1rem;\n padding-left: 1rem;\n}\n.bunny-shadow-padding-xb {\n padding-right: 1rem;\n padding-left: 1rem;\n padding-bottom: 0.5rem;\n}\n.content-container {\n width: 100%;\n margin: 0 auto;\n}\n@media (min-width: 1220px) {\n .content-container {\n width: 1220px !important;\n margin: 0 auto;\n }\n}\n@media (min-width: 768px) {\n .bunny-shadow-padding-x {\n padding-right: 2rem;\n padding-left: 2rem;\n }\n .bunny-shadow-padding-xb {\n padding-right: 2rem;\n padding-left: 2rem;\n padding-bottom: 0.5rem;\n }\n .sm\\:flex {\n display: flex !important;\n }\n .sm\\:hidden {\n display: none !important;\n }\n}\n.bunny-shadow,\n.bunny-shadow-md {\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-ring-shadow: 0 0 #0000;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-colored: 0 0 #0000;\n}\n.bunny-fixed {\n position: fixed;\n}\n.bunny-absolute {\n position: absolute;\n}\n.bunny-relative {\n position: relative;\n}\n.bunny-sticky {\n position: sticky;\n}\n.bunny-bottom-0 {\n bottom: 0px;\n}\n.bunny-bottom-4 {\n bottom: 1rem;\n}\n.bunny-left-0 {\n left: 0px;\n}\n.bunny-right-0 {\n right: 0px;\n}\n.bunny-top-0 {\n top: 0px;\n}\n.bunny-col-span-1 {\n grid-column: span 1 / span 1;\n}\n.bunny-col-span-full {\n grid-column: 1 / -1;\n}\n.bunny-m-0 {\n margin: 0px;\n}\n.bunny-mx-0 {\n margin-left: 0px;\n margin-right: 0px;\n}\n.bunny-mx-4 {\n margin-left: 1rem;\n margin-right: 1rem;\n}\n.bunny-mx-auto {\n margin-left: auto;\n margin-right: auto;\n}\n.bunny-my-0 {\n margin-top: 0px;\n margin-bottom: 0px;\n}\n.bunny-my-2 {\n margin-top: 0.5rem;\n margin-bottom: 0.5rem;\n}\n.bunny-my-24 {\n margin-top: 6rem;\n margin-bottom: 6rem;\n}\n.bunny-my-4 {\n margin-top: 1rem;\n margin-bottom: 1rem;\n}\n.bunny-mb-2 {\n margin-bottom: 0.5rem;\n}\n.bunny-mb-3 {\n margin-bottom: 0.75rem;\n}\n.bunny-mb-4 {\n margin-bottom: 1rem;\n}\n.bunny-mb-8 {\n margin-bottom: 2rem;\n}\n.bunny-ml-auto {\n margin-left: auto;\n}\n.bunny-mt-0 {\n margin-top: 0px;\n}\n.bunny-mt-2 {\n margin-top: 0.5rem;\n}\n.bunny-mt-24 {\n margin-top: 6rem;\n}\n.bunny-mt-4 {\n margin-top: 1rem;\n}\n.bunny-mt-5 {\n margin-top: 1.25rem;\n}\n.bunny-box-border {\n box-sizing: border-box;\n}\n.bunny-flex {\n display: flex;\n}\n.bunny-grid {\n display: grid;\n}\n.bunny-contents {\n display: contents;\n}\n.bunny-h-0\\.5 {\n height: 0.125rem;\n}\n.bunny-h-1\\/2 {\n height: 50%;\n}\n.bunny-h-8 {\n height: 2rem;\n}\n.bunny-h-full {\n height: 100%;\n}\n.bunny-h-screen {\n height: 100vh;\n}\n.bunny-max-h-\\[calc\\(100vh-10rem\\)\\] {\n max-height: calc(100vh - 10rem);\n}\n.bunny-min-h-0 {\n min-height: 0px;\n}\n.bunny-w-0\\.5 {\n width: 0.125rem;\n}\n.bunny-w-1\\/2 {\n width: 50%;\n}\n.bunny-w-3\\/5 {\n width: 60%;\n}\n.bunny-w-full {\n width: 100%;\n}\n.bunny-w-screen {\n width: 100vw;\n}\n.bunny-flex-1 {\n flex: 1 1 0%;\n}\n.bunny-shrink {\n flex-shrink: 1;\n}\n.bunny-shrink-0 {\n flex-shrink: 0;\n}\n.bunny-grow {\n flex-grow: 1;\n}\n.bunny-cursor-pointer {\n cursor: pointer;\n}\n.bunny-grid-cols-3 {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n}\n.bunny-flex-row {\n flex-direction: row;\n}\n.bunny-flex-col {\n flex-direction: column;\n}\n.bunny-flex-wrap {\n flex-wrap: wrap;\n}\n.bunny-items-start {\n align-items: flex-start;\n}\n.bunny-items-end {\n align-items: flex-end;\n}\n.bunny-items-center {\n align-items: center;\n}\n.bunny-justify-end {\n justify-content: flex-end;\n}\n.bunny-justify-center {\n justify-content: center;\n}\n.bunny-justify-between {\n justify-content: space-between;\n}\n.bunny-gap-0 {\n gap: 0px;\n}\n.bunny-gap-1 {\n gap: 0.25rem;\n}\n.bunny-gap-2 {\n gap: 0.5rem;\n}\n.bunny-gap-3 {\n gap: 0.75rem;\n}\n.bunny-gap-4 {\n gap: 1rem;\n}\n.bunny-gap-6 {\n gap: 1.5rem;\n}\n.bunny-gap-8 {\n gap: 2rem;\n}\n.bunny-space-y-2 > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));\n}\n.bunny-space-y-4 > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(1rem * var(--tw-space-y-reverse));\n}\n.bunny-space-y-8 > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(2rem * var(--tw-space-y-reverse));\n}\n.bunny-overflow-auto {\n overflow: auto;\n}\n.bunny-overflow-hidden {\n overflow: hidden;\n}\n.bunny-overflow-y-auto {\n overflow-y: auto;\n}\n.bunny-whitespace-nowrap {\n white-space: nowrap;\n}\n.bunny-text-nowrap {\n text-wrap: nowrap;\n}\n.bunny-rounded {\n border-radius: 0.25rem;\n}\n.bunny-rounded-full {\n border-radius: 9999px;\n}\n.bunny-rounded-lg {\n border-radius: 0.5rem;\n}\n.bunny-rounded-md {\n border-radius: 0.375rem;\n}\n.bunny-border {\n border-width: 1px;\n}\n.bunny-border-2 {\n border-width: 2px;\n}\n.bunny-border-solid {\n border-style: solid;\n}\n.bunny-border-none {\n border-style: none;\n}\n.bunny-border-slate-200 {\n --tw-border-opacity: 1;\n border-color: rgb(226 232 240 / var(--tw-border-opacity, 1));\n}\n.bunny-bg-gray-300 {\n --tw-bg-opacity: 1;\n background-color: rgb(209 213 219 / var(--tw-bg-opacity, 1));\n}\n.bunny-bg-slate-50 {\n --tw-bg-opacity: 1;\n background-color: rgb(248 250 252 / var(--tw-bg-opacity, 1));\n}\n.bunny-bg-transparent {\n background-color: transparent;\n}\n.bunny-bg-white {\n --tw-bg-opacity: 1;\n background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));\n}\n.bunny-p-0 {\n padding: 0px;\n}\n.bunny-p-1 {\n padding: 0.25rem;\n}\n.bunny-p-2 {\n padding: 0.5rem;\n}\n.bunny-p-4 {\n padding: 1rem;\n}\n.bunny-px-12 {\n padding-left: 3rem;\n padding-right: 3rem;\n}\n.bunny-px-3 {\n padding-left: 0.75rem;\n padding-right: 0.75rem;\n}\n.bunny-px-4 {\n padding-left: 1rem;\n padding-right: 1rem;\n}\n.bunny-px-6 {\n padding-left: 1.5rem;\n padding-right: 1.5rem;\n}\n.bunny-py-2 {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n}\n.bunny-py-4 {\n padding-top: 1rem;\n padding-bottom: 1rem;\n}\n.bunny-py-6 {\n padding-top: 1.5rem;\n padding-bottom: 1.5rem;\n}\n.bunny-pb-2 {\n padding-bottom: 0.5rem;\n}\n.bunny-pb-4 {\n padding-bottom: 1rem;\n}\n.bunny-pb-6 {\n padding-bottom: 1.5rem;\n}\n.bunny-pb-8 {\n padding-bottom: 2rem;\n}\n.bunny-pl-0 {\n padding-left: 0px;\n}\n.bunny-pl-1 {\n padding-left: 0.25rem;\n}\n.bunny-pl-4 {\n padding-left: 1rem;\n}\n.bunny-pr-4 {\n padding-right: 1rem;\n}\n.bunny-pt-1 {\n padding-top: 0.25rem;\n}\n.bunny-pt-12 {\n padding-top: 3rem;\n}\n.bunny-pt-2 {\n padding-top: 0.5rem;\n}\n.bunny-pt-4 {\n padding-top: 1rem;\n}\n.bunny-pt-5 {\n padding-top: 1.25rem;\n}\n.bunny-pt-\\[25vh\\] {\n padding-top: 25vh;\n}\n.bunny-text-left {\n text-align: left;\n}\n.bunny-text-center {\n text-align: center;\n}\n.bunny-text-right {\n text-align: right;\n}\n.bunny-text-start {\n text-align: start;\n}\n.bunny-text-2xl {\n font-size: 1.5rem;\n line-height: 2rem;\n}\n.bunny-text-3xl {\n font-size: 1.875rem;\n line-height: 2.25rem;\n}\n.bunny-text-base {\n font-size: 1rem;\n line-height: 1.5rem;\n}\n.bunny-text-lg {\n font-size: 1.125rem;\n line-height: 1.75rem;\n}\n.bunny-text-sm {\n font-size: 0.875rem;\n line-height: 1.25rem;\n}\n.bunny-text-sm\\/5 {\n font-size: 0.875rem;\n line-height: 1.25rem;\n}\n.bunny-text-xl {\n font-size: 1.25rem;\n line-height: 1.75rem;\n}\n.bunny-text-xs {\n font-size: 0.75rem;\n line-height: 1rem;\n}\n.bunny-text-xs\\/3 {\n font-size: 0.75rem;\n line-height: 0.75rem;\n}\n.bunny-font-bold {\n font-weight: 700;\n}\n.bunny-font-medium {\n font-weight: 500;\n}\n.bunny-font-normal {\n font-weight: 400;\n}\n.bunny-text-gray-400 {\n --tw-text-opacity: 1;\n color: rgb(156 163 175 / var(--tw-text-opacity, 1));\n}\n.bunny-text-gray-500 {\n --tw-text-opacity: 1;\n color: rgb(107 114 128 / var(--tw-text-opacity, 1));\n}\n.bunny-text-gray-600 {\n --tw-text-opacity: 1;\n color: rgb(75 85 99 / var(--tw-text-opacity, 1));\n}\n.bunny-text-gray-900 {\n --tw-text-opacity: 1;\n color: rgb(17 24 39 / var(--tw-text-opacity, 1));\n}\n.bunny-text-orange-500 {\n --tw-text-opacity: 1;\n color: rgb(249 115 22 / var(--tw-text-opacity, 1));\n}\n.bunny-text-orange-600 {\n --tw-text-opacity: 1;\n color: rgb(234 88 12 / var(--tw-text-opacity, 1));\n}\n.bunny-text-slate-400 {\n --tw-text-opacity: 1;\n color: rgb(148 163 184 / var(--tw-text-opacity, 1));\n}\n.bunny-text-slate-500 {\n --tw-text-opacity: 1;\n color: rgb(100 116 139 / var(--tw-text-opacity, 1));\n}\n.bunny-text-slate-600 {\n --tw-text-opacity: 1;\n color: rgb(71 85 105 / var(--tw-text-opacity, 1));\n}\n.bunny-text-white {\n --tw-text-opacity: 1;\n color: rgb(255 255 255 / var(--tw-text-opacity, 1));\n}\n.bunny-underline {\n text-decoration-line: underline;\n}\n.bunny-shadow {\n --tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);\n --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.bunny-shadow-md {\n --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);\n --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.bunny-transition-\\[margin\\] {\n transition-property: margin;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.bunny-duration-300 {\n transition-duration: 300ms;\n}\n.rotate-45,\n.transform {\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-rotate: 0;\n --tw-skew-x: 0;\n --tw-skew-y: 0;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n}\n.shadow,\n.shadow-lg,\n.shadow-md,\n.shadow-none,\n.shadow-sm,\n.shadow-xl {\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-ring-shadow: 0 0 #0000;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-colored: 0 0 #0000;\n}\n.container {\n width: 100%;\n}\n@media (min-width: 768px) {\n .container {\n max-width: 768px;\n }\n}\n@media (min-width: 1024px) {\n .container {\n max-width: 1024px;\n }\n}\n@media (min-width: 1280px) {\n .container {\n max-width: 1280px;\n }\n}\n@media (min-width: 1536px) {\n .container {\n max-width: 1536px;\n }\n}\n.visible {\n visibility: visible;\n}\n.fixed {\n position: fixed;\n}\n.absolute {\n position: absolute;\n}\n.relative {\n position: relative;\n}\n.sticky {\n position: sticky;\n}\n.-top-0\\.5 {\n top: -0.125rem;\n}\n.bottom-0 {\n bottom: 0px;\n}\n.bottom-4 {\n bottom: 1rem;\n}\n.left-0 {\n left: 0px;\n}\n.right-0 {\n right: 0px;\n}\n.top-0 {\n top: 0px;\n}\n.z-50 {\n z-index: 50;\n}\n.col-span-2 {\n grid-column: span 2 / span 2;\n}\n.col-span-3 {\n grid-column: span 3 / span 3;\n}\n.col-span-full {\n grid-column: 1 / -1;\n}\n.m-0 {\n margin: 0px;\n}\n.mx-0 {\n margin-left: 0px;\n margin-right: 0px;\n}\n.mx-4 {\n margin-left: 1rem;\n margin-right: 1rem;\n}\n.my-12 {\n margin-top: 3rem;\n margin-bottom: 3rem;\n}\n.my-2 {\n margin-top: 0.5rem;\n margin-bottom: 0.5rem;\n}\n.my-4 {\n margin-top: 1rem;\n margin-bottom: 1rem;\n}\n.mb-2 {\n margin-bottom: 0.5rem;\n}\n.mb-4 {\n margin-bottom: 1rem;\n}\n.mb-8 {\n margin-bottom: 2rem;\n}\n.ml-2 {\n margin-left: 0.5rem;\n}\n.mr-8 {\n margin-right: 2rem;\n}\n.mt-1 {\n margin-top: 0.25rem;\n}\n.mt-2 {\n margin-top: 0.5rem;\n}\n.mt-4 {\n margin-top: 1rem;\n}\n.mt-6 {\n margin-top: 1.5rem;\n}\n.mt-8 {\n margin-top: 2rem;\n}\n.block {\n display: block;\n}\n.flex {\n display: flex;\n}\n.table {\n display: table;\n}\n.grid {\n display: grid;\n}\n.contents {\n display: contents;\n}\n.hidden {\n display: none;\n}\n.h-4 {\n height: 1rem;\n}\n.h-5 {\n height: 1.25rem;\n}\n.h-8 {\n height: 2rem;\n}\n.h-full {\n height: 100%;\n}\n.w-1\\/2 {\n width: 50%;\n}\n.w-1\\/3 {\n width: 33.333333%;\n}\n.w-12 {\n width: 3rem;\n}\n.w-2\\/3 {\n width: 66.666667%;\n}\n.w-4 {\n width: 1rem;\n}\n.w-full {\n width: 100%;\n}\n.max-w-32 {\n max-width: 8rem;\n}\n.flex-1 {\n flex: 1 1 0%;\n}\n.shrink {\n flex-shrink: 1;\n}\n.shrink-0 {\n flex-shrink: 0;\n}\n.flex-grow {\n flex-grow: 1;\n}\n.grow {\n flex-grow: 1;\n}\n.border-collapse {\n border-collapse: collapse;\n}\n.rotate-45 {\n --tw-rotate: 45deg;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.transform {\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.cursor-pointer {\n cursor: pointer;\n}\n.grid-cols-2 {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n}\n.grid-cols-3 {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n}\n.flex-row {\n flex-direction: row;\n}\n.flex-col {\n flex-direction: column;\n}\n.items-end {\n align-items: flex-end;\n}\n.items-center {\n align-items: center;\n}\n.justify-start {\n justify-content: flex-start;\n}\n.justify-end {\n justify-content: flex-end;\n}\n.justify-center {\n justify-content: center;\n}\n.justify-between {\n justify-content: space-between;\n}\n.gap-0 {\n gap: 0px;\n}\n.gap-1 {\n gap: 0.25rem;\n}\n.gap-2 {\n gap: 0.5rem;\n}\n.gap-3 {\n gap: 0.75rem;\n}\n.gap-4 {\n gap: 1rem;\n}\n.gap-6 {\n gap: 1.5rem;\n}\n.gap-8 {\n gap: 2rem;\n}\n.space-y-2 > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));\n}\n.space-y-4 > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(1rem * var(--tw-space-y-reverse));\n}\n.space-y-8 > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(2rem * var(--tw-space-y-reverse));\n}\n.overflow-auto {\n overflow: auto;\n}\n.overflow-hidden {\n overflow: hidden;\n}\n.overflow-visible {\n overflow: visible;\n}\n.whitespace-nowrap {\n white-space: nowrap;\n}\n.text-nowrap {\n text-wrap: nowrap;\n}\n.rounded {\n border-radius: 0.25rem;\n}\n.rounded-full {\n border-radius: 9999px;\n}\n.rounded-lg {\n border-radius: 0.5rem;\n}\n.rounded-md {\n border-radius: 0.375rem;\n}\n.rounded-sm {\n border-radius: 0.125rem;\n}\n.border {\n border-width: 1px;\n}\n.border-2 {\n border-width: 2px;\n}\n.border-b {\n border-bottom-width: 1px;\n}\n.border-t {\n border-top-width: 1px;\n}\n.border-solid {\n border-style: solid;\n}\n.border-none {\n border-style: none;\n}\n.border-gray-400 {\n --tw-border-opacity: 1;\n border-color: rgb(156 163 175 / var(--tw-border-opacity, 1));\n}\n.border-gray-500 {\n --tw-border-opacity: 1;\n border-color: rgb(107 114 128 / var(--tw-border-opacity, 1));\n}\n.border-slate-200 {\n --tw-border-opacity: 1;\n border-color: rgb(226 232 240 / var(--tw-border-opacity, 1));\n}\n.border-slate-300 {\n --tw-border-opacity: 1;\n border-color: rgb(203 213 225 / var(--tw-border-opacity, 1));\n}\n.border-slate-700 {\n --tw-border-opacity: 1;\n border-color: rgb(51 65 85 / var(--tw-border-opacity, 1));\n}\n.bg-black {\n --tw-bg-opacity: 1;\n background-color: rgb(0 0 0 / var(--tw-bg-opacity, 1));\n}\n.bg-emerald-200 {\n --tw-bg-opacity: 1;\n background-color: rgb(167 243 208 / var(--tw-bg-opacity, 1));\n}\n.bg-green-200 {\n --tw-bg-opacity: 1;\n background-color: rgb(187 247 208 / var(--tw-bg-opacity, 1));\n}\n.bg-orange-200 {\n --tw-bg-opacity: 1;\n background-color: rgb(254 215 170 / var(--tw-bg-opacity, 1));\n}\n.bg-red-200 {\n --tw-bg-opacity: 1;\n background-color: rgb(254 202 202 / var(--tw-bg-opacity, 1));\n}\n.bg-red-500 {\n --tw-bg-opacity: 1;\n background-color: rgb(239 68 68 / var(--tw-bg-opacity, 1));\n}\n.bg-slate-50 {\n --tw-bg-opacity: 1;\n background-color: rgb(248 250 252 / var(--tw-bg-opacity, 1));\n}\n.bg-transparent {\n background-color: transparent;\n}\n.bg-white {\n --tw-bg-opacity: 1;\n background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));\n}\n.bg-yellow-200 {\n --tw-bg-opacity: 1;\n background-color: rgb(254 240 138 / var(--tw-bg-opacity, 1));\n}\n.p-0 {\n padding: 0px;\n}\n.p-1 {\n padding: 0.25rem;\n}\n.p-2 {\n padding: 0.5rem;\n}\n.p-4 {\n padding: 1rem;\n}\n.p-8 {\n padding: 2rem;\n}\n.px-2 {\n padding-left: 0.5rem;\n padding-right: 0.5rem;\n}\n.px-3 {\n padding-left: 0.75rem;\n padding-right: 0.75rem;\n}\n.px-4 {\n padding-left: 1rem;\n padding-right: 1rem;\n}\n.px-6 {\n padding-left: 1.5rem;\n padding-right: 1.5rem;\n}\n.px-8 {\n padding-left: 2rem;\n padding-right: 2rem;\n}\n.py-1 {\n padding-top: 0.25rem;\n padding-bottom: 0.25rem;\n}\n.py-2 {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n}\n.py-4 {\n padding-top: 1rem;\n padding-bottom: 1rem;\n}\n.py-6 {\n padding-top: 1.5rem;\n padding-bottom: 1.5rem;\n}\n.pb-2 {\n padding-bottom: 0.5rem;\n}\n.pb-4 {\n padding-bottom: 1rem;\n}\n.pb-6 {\n padding-bottom: 1.5rem;\n}\n.pb-8 {\n padding-bottom: 2rem;\n}\n.pl-0 {\n padding-left: 0px;\n}\n.pl-2 {\n padding-left: 0.5rem;\n}\n.pl-4 {\n padding-left: 1rem;\n}\n.pt-1 {\n padding-top: 0.25rem;\n}\n.pt-12 {\n padding-top: 3rem;\n}\n.pt-2 {\n padding-top: 0.5rem;\n}\n.pt-4 {\n padding-top: 1rem;\n}\n.pt-5 {\n padding-top: 1.25rem;\n}\n.pt-6 {\n padding-top: 1.5rem;\n}\n.pt-8 {\n padding-top: 2rem;\n}\n.text-left {\n text-align: left;\n}\n.text-center {\n text-align: center;\n}\n.text-right {\n text-align: right;\n}\n.align-middle {\n vertical-align: middle;\n}\n.text-2xl {\n font-size: 1.5rem;\n line-height: 2rem;\n}\n.text-base {\n font-size: 1rem;\n line-height: 1.5rem;\n}\n.text-lg {\n font-size: 1.125rem;\n line-height: 1.75rem;\n}\n.text-sm {\n font-size: 0.875rem;\n line-height: 1.25rem;\n}\n.text-xl {\n font-size: 1.25rem;\n line-height: 1.75rem;\n}\n.text-xs {\n font-size: 0.75rem;\n line-height: 1rem;\n}\n.font-bold {\n font-weight: 700;\n}\n.font-medium {\n font-weight: 500;\n}\n.font-normal {\n font-weight: 400;\n}\n.capitalize {\n text-transform: capitalize;\n}\n.text-emerald-600 {\n --tw-text-opacity: 1;\n color: rgb(5 150 105 / var(--tw-text-opacity, 1));\n}\n.text-emerald-700 {\n --tw-text-opacity: 1;\n color: rgb(4 120 87 / var(--tw-text-opacity, 1));\n}\n.text-gray-600 {\n --tw-text-opacity: 1;\n color: rgb(75 85 99 / var(--tw-text-opacity, 1));\n}\n.text-gray-900 {\n --tw-text-opacity: 1;\n color: rgb(17 24 39 / var(--tw-text-opacity, 1));\n}\n.text-green-600 {\n --tw-text-opacity: 1;\n color: rgb(22 163 74 / var(--tw-text-opacity, 1));\n}\n.text-orange-500 {\n --tw-text-opacity: 1;\n color: rgb(249 115 22 / var(--tw-text-opacity, 1));\n}\n.text-orange-600 {\n --tw-text-opacity: 1;\n color: rgb(234 88 12 / var(--tw-text-opacity, 1));\n}\n.text-red-500 {\n --tw-text-opacity: 1;\n color: rgb(239 68 68 / var(--tw-text-opacity, 1));\n}\n.text-slate-400 {\n --tw-text-opacity: 1;\n color: rgb(148 163 184 / var(--tw-text-opacity, 1));\n}\n.text-slate-500 {\n --tw-text-opacity: 1;\n color: rgb(100 116 139 / var(--tw-text-opacity, 1));\n}\n.text-slate-600 {\n --tw-text-opacity: 1;\n color: rgb(71 85 105 / var(--tw-text-opacity, 1));\n}\n.text-white {\n --tw-text-opacity: 1;\n color: rgb(255 255 255 / var(--tw-text-opacity, 1));\n}\n.text-yellow-500 {\n --tw-text-opacity: 1;\n color: rgb(234 179 8 / var(--tw-text-opacity, 1));\n}\n.underline {\n text-decoration-line: underline;\n}\n.shadow {\n --tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);\n --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.shadow-lg {\n --tw-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);\n --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.shadow-md {\n --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);\n --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.shadow-none {\n --tw-shadow: 0 0 #0000;\n --tw-shadow-colored: 0 0 #0000;\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.shadow-sm {\n --tw-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.shadow-xl {\n --tw-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);\n --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.transition {\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.transition-\\[margin\\] {\n transition-property: margin;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.transition-all {\n transition-property: all;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.duration-200 {\n transition-duration: 200ms;\n}\n.duration-300 {\n transition-duration: 300ms;\n}\n.hover\\:bg-gray-100:hover {\n --tw-bg-opacity: 1;\n background-color: rgb(243 244 246 / var(--tw-bg-opacity, 1));\n}\n.hover\\:bg-slate-100:hover {\n --tw-bg-opacity: 1;\n background-color: rgb(241 245 249 / var(--tw-bg-opacity, 1));\n}\n.hover\\:bg-slate-200:hover {\n --tw-bg-opacity: 1;\n background-color: rgb(226 232 240 / var(--tw-bg-opacity, 1));\n}\n.hover\\:bg-gray-200:hover {\n --tw-bg-opacity: 1;\n background-color: rgb(229 231 235 / var(--tw-bg-opacity, 1));\n}\n@media (min-width: 768px) {\n .sm\\:flex {\n display: flex;\n }\n .sm\\:hidden {\n display: none;\n }\n}\n.hover\\:bunny-text-orange-400:hover {\n --tw-text-opacity: 1;\n color: rgb(251 146 60 / var(--tw-text-opacity, 1));\n}\n.bunny-components .ant-upload-select-picture-card {\n margin: 0 !important;\n}\n.bunny-components .ant-upload {\n border-radius: 0.5rem !important;\n}\n.bunny-components .ant-row {\n margin-bottom: 0px;\n}\n.bunny-components .ant-select-disabled .ant-select-selector .ant-select-selection-item {\n color: rgba(0, 0, 0, 0.25) !important;\n}\n.bunny-components .ant-input-number,\n.bunny-components .ant-input,\n.bunny-components .ant-picker,\n.bunny-components .ant-input-affix-wrapper,\n.bunny-components .ant-select-selector {\n font-size: 0.875rem !important;\n transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);\n color: #232323 !important;\n}\n.bunny-components .ant-input-affix-wrapper {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n}\n.bunny-components .ant-input-group-addon,\n.bunny-components .ant-input-number-group-addon {\n color: #475569 !important;\n}\n.bunny-components .ant-input-number-group-wrapper,\n.bunny-components .ant-input-number-affix-wrapper {\n width: 100%;\n}\n.bunny-components .ant-input-affix-wrapper input {\n border: none !important;\n}\n.bunny-components .ant-form-item {\n margin-bottom: 0;\n}\n.bunny-components .ant-form-item-label {\n text-transform: none !important;\n font-size: 0.75rem;\n padding-bottom: 2px !important;\n}\n.bunny-components .ant-form-item-label > label {\n width: 100%;\n color: #4b5563 !important;\n}\n.bunny-components .form .ant-form-item-label label {\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n box-sizing: border-box;\n}\n.bunny-components .ant-form-item-explain,\n.bunny-components .ant-form-item-explain-error {\n font-size: 11px;\n min-height: 11px;\n line-height: 11px;\n padding-top: 2px;\n}\n.bunny-components .ant-timeline-item-content {\n font-size: smaller;\n}\n.bunny-components .ant-tree {\n font-size: 0.875rem;\n}\n.bunny-components .ant-tree-treenode {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.bunny-components .ant-tree-draggable-icon {\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.bunny-components .ant-tree-node-content-wrapper {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.bunny-components .ant-tree-switcher {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.bunny-components .ant-page-header {\n padding-left: 0;\n padding-right: 0;\n padding-top: 0;\n}\n.bunny-components .ant-tag {\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: 14px;\n font-weight: 500;\n white-space: nowrap;\n padding-inline-start: 0.625rem;\n padding-inline-end: 0.625rem;\n margin: 0;\n}\n.bunny-components .ant-tag-blue {\n color: #3b82f6 !important;\n background: #bfdbfe !important;\n}\n.bunny-components .ant-tag-green {\n color: #059669 !important;\n background: #a7f3d0 !important;\n}\n.bunny-components .ant-tag-red {\n color: #ef4444 !important;\n background: #fecaca !important;\n}\n.bunny-components .ant-tag-orange {\n color: #f97316 !important;\n background: #fed7aa !important;\n}\n.bunny-components .ant-tag-yellow {\n color: #f59e0b !important;\n background: #fde68a !important;\n}\n.bunny-components .ant-tag-purple {\n color: #8b5cf6 !important;\n background: #ddd6fe !important;\n}\n.bunny-components .ant-tag-gray {\n color: #6b7280 !important;\n background: #e5e7eb !important;\n}\n.bunny-components .ant-tag-black {\n color: white !important;\n background: black !important;\n}\n.bunny-components .ant-picker {\n width: 100%;\n}\n.bunny-components .ant-input,\n.bunny-components .ant-select,\n.bunny-components .ant-picker {\n height: 32px !important;\n}\n.bunny-components .ant-slider-dot {\n border: 2px solid #f0f0f0;\n}\n.bunny-components .ant-slider-dot-active {\n border-color: #ff5833;\n}\n.bunny-components .ant-slider-mark :last-child {\n transform: translateX(-75%) !important;\n}\n.bunny-components .ant-drawer-content {\n background: #f3f3f9ff;\n}\n.bunny-components .ant-drawer-body,\n.bunny-components .ant-layout {\n background: #f8fafc;\n}\n.bunny-components .vista-link {\n color: #1890ff;\n}\n.bunny-components .vista-link:hover {\n text-decoration: underline;\n cursor: pointer;\n}\n.bunny-components .ant-popover-inner-content {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n max-width: 300px;\n}\n.bunny-components .ant-popconfirm-message-text {\n width: 100% !important;\n}\n.bunny-components .ant-popconfirm-title {\n padding: 0;\n text-align: center;\n font-size: 0.875rem !important;\n width: 100% !important;\n}\n.bunny-components .ant-popconfirm-buttons {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n}\n.bunny-components .ant-popconfirm-buttons button {\n margin-inline-start: 0 !important;\n}\n.bunny-components .ant-pagination-item {\n display: flex !important;\n align-items: center;\n justify-content: center;\n}\n.bunny-components .ant-btn-primary:disabled {\n background: #eef0f2 !important;\n color: rgba(0, 0, 0, 0.25) !important;\n border: none;\n}\n.bunny-components .ant-btn {\n box-shadow: none;\n text-shadow: none;\n outline: none !important;\n line-height: 1;\n font-weight: normal;\n}\n.bunny-components .ant-btn-default .ant-btn-icon {\n color: #94a3b8;\n transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);\n}\n.bunny-components .ant-btn-default:hover .ant-btn-icon {\n color: #ff7f5c;\n}\n.bunny-components .ant-btn-default:disabled {\n border-color: rgba(113, 125, 148, 0.2) !important;\n}\n.bunny-components .ant-btn-primary:disabled {\n background-color: rgba(113, 125, 148, 0.1) !important;\n border-color: rgba(113, 125, 148, 0.1) !important;\n}\n.bunny-components .ant-btn-primary:hover:disabled,\n.bunny-components .ant-btn-primary:disabled {\n background-clip: padding-box;\n}\n.bunny-components .ant-select-selection-item-content {\n display: flex !important;\n align-items: center;\n}\n.bunny-components .ant-select-item {\n font-size: 0.875rem;\n}\n.bunny-components .ant-select-item-option-content {\n display: flex;\n align-items: center;\n white-space: nowrap !important;\n overflow: visible !important;\n text-overflow: default !important;\n font-size: 0.875rem;\n}\n.bunny-components .ant-select-arrow .anticon:not(.ant-select-suffix) {\n pointer-events: none;\n}\n.bunny-components .select-dropdown-blue-gray .ant-select-item-option {\n background-color: #fff !important;\n}\n.bunny-components .select-dropdown-blue-gray .ant-select-item-option-active {\n color: #ff5833;\n}\n.bunny-components .ant-dropdown-menu-items {\n padding-left: 0 !important;\n}\n.bunny-components .ant-dropdown-menu-item-active {\n background-color: transparent !important;\n}\n.bunny-components .ant-input-affix-wrapper.searchfield {\n background: white !important;\n}\n.bunny-components .ant-input-affix-wrapper.searchfield input {\n background: white !important;\n}\n.bunny-components .ant-input-affix-wrapper-focused {\n background: white !important;\n}\n.bunny-components .panel .ant-input-affix-wrapper.searchfield {\n background: #f8f8f8 !important;\n}\n.bunny-components .panel .ant-input-affix-wrapper.searchfield input {\n background: #f8f8f8 !important;\n}\n.bunny-components .ant-input-steps-hidden .ant-input-number-handler-wrap {\n display: none;\n}\n.bunny-components .ant-layout-header {\n height: 48px;\n}\n.bunny-components .ant-layout-sider-children {\n width: inherit;\n position: fixed;\n}\n.bunny-components .ant-menu-item-group-list {\n display: flex !important;\n flex-direction: column !important;\n align-items: flex-start !important;\n gap: 4px !important;\n}\n.bunny-components .group {\n display: flex;\n flex-direction: row;\n flex-flow: row wrap;\n box-sizing: border-box;\n}\n.bunny-components .select-datepicker {\n animation-duration: 0.35s !important;\n}\n.bunny-components .header-datepicker {\n top: 96px !important;\n animation-duration: 0s !important;\n}\n.bunny-components .ant-picker-header {\n border-bottom: none !important;\n}\n.bunny-components .ant-picker-content thead tr th {\n font-weight: 500;\n}\n.bunny-components .ant-picker-panel-container {\n border-radius: 0.375rem;\n}\n.bunny-components .ant-picker-cell-selected .custom-date-display {\n color: #ffffff;\n background-color: #ff5833;\n}\n.bunny-components .ant-picker-cell-today .custom-date-display {\n border: 1px solid #ff5833;\n}\n.bunny-components .ant-select:hover,\n.bunny-components * .cardElement:hover {\n border-color: #ff5833;\n}\n.bunny-components .ant-input-number {\n width: 100%;\n}\n.bunny-components .ant-input-number-focused {\n border-color: #ff5833 !important;\n background-color: #ffffff !important;\n}\n.bunny-components .ant-input-affix-wrapper-focused,\n.bunny-components .ant-input-number-focused,\n.bunny-components .ant-picker,\n.bunny-components .ant-input,\n.bunny-components .ant-select-focused .ant-select-selector,\n.bunny-components .ant-select-selector:focus,\n.bunny-components .ant-select-selector:active,\n.bunny-components .ant-select-open .ant-select-selector {\n box-shadow: none !important;\n}\n.bunny-components .ant-select-item-option-selected .ant-select-item-option-state {\n display: none !important;\n}\n.bunny-components .ant-form * input[type='text'].ant-input:not(:disabled),\n.bunny-components .ant-select-selection-item:not(:disabled) {\n color: #232323;\n}\n.bunny-components .ant-tabs-ink-bar {\n display: none !important;\n}\n.bunny-components .ant-tabs-tab.ant-tabs-tab-active {\n border-bottom: 2px solid #ff5833 !important;\n}\n.bunny-components .ant-tabs-tab {\n border-bottom: 2px solid transparent !important;\n padding-bottom: 14px !important;\n}\n.bunny-components .ant-upload-wrapper {\n display: flex;\n}\n.bunny-components .ant-form-item-label > label::after {\n display: none !important;\n}\n.bunny-components .ant-menu-item {\n display: flex !important;\n align-items: center !important;\n}\n.ant-notification {\n width: min-content;\n}\n.ant-notification-topRight {\n right: 0 !important;\n left: 0 !important;\n margin-left: auto !important;\n margin-right: auto !important;\n}\n.ant-notification-notice-wrapper {\n width: 350px !important;\n overflow: hidden !important;\n}\n.ant-notification-notice {\n padding: 16px !important;\n width: 350px !important;\n border-radius: 8px !important;\n display: flex !important;\n box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.08), 0px 1px 18px rgba(0, 0, 0, 0.08), 0px 3px 5px rgba(0, 0, 0, 0.16) !important;\n}\n.ant-notification-notice-description {\n padding: 0 14px 0 0 !important;\n font-size: 14px !important;\n overflow-wrap: break-word;\n}\n.ant-notification-notice-success {\n background-color: #edfffa !important;\n}\n.ant-notification-notice-error {\n background-color: #fff8f4 !important;\n}\n.ant-notification-notice-error .ant-notification-notice-message {\n color: #ff5833 !important;\n font-weight: 500 !important;\n}\n.ant-notification-notice-error .ant-notification-notice-icon {\n color: #ff5833;\n}\n.ant-notification-notice-success .ant-notification-notice-message {\n color: #00b76a !important;\n font-weight: 500 !important;\n}\n.ant-notification-notice-success .ant-notification-notice-icon {\n color: #00b76a !important;\n}\n.ant-notification-notice-message {\n margin-bottom: 0 !important;\n}\n.ant-notification-notice-close {\n top: 16px !important;\n right: 16px !important;\n}\n.bunny-invoice-container {\n padding: 0;\n box-sizing: border-box !important;\n line-height: 1.15;\n}\n@media only screen and (max-width: 768px) {\n select,\n textarea,\n input[type='text'],\n input[type='password'],\n input[type='datetime'],\n input[type='datetime-local'],\n input[type='date'],\n input[type='month'],\n input[type='time'],\n input[type='week'],\n input[type='number'],\n input[type='email'],\n input[type='url'],\n input[type='search'],\n input[type='tel'],\n input[type='color'] {\n font-size: 16px !important;\n }\n}\n@keyframes App-logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n";
49
+ var css_248z = ":root {\n --row-background: #ffffff;\n --row-background-alternate: rgba(100, 116, 139, 0.04);\n --row-background-dark: #121212;\n --row-background-alternate-dark: #1e1e1e;\n --bunny-blue-500: #3b82f6;\n --bunny-blue-200: #bfdbfe;\n --bunny-green-600: #059669;\n --bunny-green-200: #a7f3d0;\n --bunny-red-500: #ef4444;\n --bunny-red-200: #fecaca;\n --bunny-orange-500: #f97316;\n --bunny-orange-200: #fed7aa;\n --bunny-yellow-500: #f59e0b;\n --bunny-yellow-200: #fde68a;\n --bunny-purple-500: #8b5cf6;\n --bunny-purple-200: #ddd6fe;\n --bunny-black: #000000;\n}\n.bunny-component-wrapper {\n box-sizing: border-box;\n}\n.bunny-component-wrapper * {\n box-sizing: border-box;\n}\n.hidden {\n display: none;\n}\n.bunny-show-on-hover {\n opacity: 0;\n}\n.bunny-show-on-hover-container:hover .bunny-show-on-hover {\n opacity: 1;\n}\n.has-tooltip:hover .tooltip {\n visibility: visible;\n z-index: 100;\n}\n.pdf-only {\n display: none !important;\n}\n.notes p {\n margin: 0;\n padding: 0;\n padding-bottom: 0.25rem;\n}\n.bunny-icon-path {\n transition: fill 0.3s;\n}\n.bunny-shadow-padding-x {\n padding-right: 1rem;\n padding-left: 1rem;\n}\n.bunny-shadow-padding-xb {\n padding-right: 1rem;\n padding-left: 1rem;\n padding-bottom: 0.5rem;\n}\n.content-container {\n width: 100%;\n margin: 0 auto;\n}\n@media (min-width: 1220px) {\n .content-container {\n width: 1220px !important;\n margin: 0 auto;\n }\n}\n@media (min-width: 768px) {\n .bunny-shadow-padding-x {\n padding-right: 2rem;\n padding-left: 2rem;\n }\n .bunny-shadow-padding-xb {\n padding-right: 2rem;\n padding-left: 2rem;\n padding-bottom: 0.5rem;\n }\n .sm\\:flex {\n display: flex !important;\n }\n .sm\\:hidden {\n display: none !important;\n }\n}\n.bunny-shadow,\n.bunny-shadow-md {\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-ring-shadow: 0 0 #0000;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-colored: 0 0 #0000;\n}\n.bunny-fixed {\n position: fixed;\n}\n.bunny-absolute {\n position: absolute;\n}\n.bunny-relative {\n position: relative;\n}\n.bunny-sticky {\n position: sticky;\n}\n.bunny-bottom-0 {\n bottom: 0px;\n}\n.bunny-bottom-4 {\n bottom: 1rem;\n}\n.bunny-left-0 {\n left: 0px;\n}\n.bunny-right-0 {\n right: 0px;\n}\n.bunny-top-0 {\n top: 0px;\n}\n.bunny-col-span-1 {\n grid-column: span 1 / span 1;\n}\n.bunny-col-span-full {\n grid-column: 1 / -1;\n}\n.bunny-m-0 {\n margin: 0px;\n}\n.bunny-mx-0 {\n margin-left: 0px;\n margin-right: 0px;\n}\n.bunny-mx-4 {\n margin-left: 1rem;\n margin-right: 1rem;\n}\n.bunny-mx-auto {\n margin-left: auto;\n margin-right: auto;\n}\n.bunny-my-0 {\n margin-top: 0px;\n margin-bottom: 0px;\n}\n.bunny-my-2 {\n margin-top: 0.5rem;\n margin-bottom: 0.5rem;\n}\n.bunny-my-24 {\n margin-top: 6rem;\n margin-bottom: 6rem;\n}\n.bunny-my-4 {\n margin-top: 1rem;\n margin-bottom: 1rem;\n}\n.bunny-mb-2 {\n margin-bottom: 0.5rem;\n}\n.bunny-mb-3 {\n margin-bottom: 0.75rem;\n}\n.bunny-mb-4 {\n margin-bottom: 1rem;\n}\n.bunny-mb-8 {\n margin-bottom: 2rem;\n}\n.bunny-ml-auto {\n margin-left: auto;\n}\n.bunny-mt-0 {\n margin-top: 0px;\n}\n.bunny-mt-2 {\n margin-top: 0.5rem;\n}\n.bunny-mt-24 {\n margin-top: 6rem;\n}\n.bunny-mt-4 {\n margin-top: 1rem;\n}\n.bunny-mt-5 {\n margin-top: 1.25rem;\n}\n.bunny-box-border {\n box-sizing: border-box;\n}\n.bunny-flex {\n display: flex;\n}\n.bunny-grid {\n display: grid;\n}\n.bunny-contents {\n display: contents;\n}\n.bunny-h-0\\.5 {\n height: 0.125rem;\n}\n.bunny-h-1\\/2 {\n height: 50%;\n}\n.bunny-h-8 {\n height: 2rem;\n}\n.bunny-h-full {\n height: 100%;\n}\n.bunny-h-screen {\n height: 100vh;\n}\n.bunny-max-h-\\[calc\\(100vh-10rem\\)\\] {\n max-height: calc(100vh - 10rem);\n}\n.bunny-min-h-0 {\n min-height: 0px;\n}\n.bunny-w-0\\.5 {\n width: 0.125rem;\n}\n.bunny-w-1\\/2 {\n width: 50%;\n}\n.bunny-w-3\\/5 {\n width: 60%;\n}\n.bunny-w-full {\n width: 100%;\n}\n.bunny-w-screen {\n width: 100vw;\n}\n.bunny-flex-1 {\n flex: 1 1 0%;\n}\n.bunny-shrink {\n flex-shrink: 1;\n}\n.bunny-shrink-0 {\n flex-shrink: 0;\n}\n.bunny-grow {\n flex-grow: 1;\n}\n.bunny-cursor-pointer {\n cursor: pointer;\n}\n.bunny-grid-cols-3 {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n}\n.bunny-flex-row {\n flex-direction: row;\n}\n.bunny-flex-col {\n flex-direction: column;\n}\n.bunny-flex-wrap {\n flex-wrap: wrap;\n}\n.bunny-items-start {\n align-items: flex-start;\n}\n.bunny-items-end {\n align-items: flex-end;\n}\n.bunny-items-center {\n align-items: center;\n}\n.bunny-justify-end {\n justify-content: flex-end;\n}\n.bunny-justify-center {\n justify-content: center;\n}\n.bunny-justify-between {\n justify-content: space-between;\n}\n.bunny-gap-0 {\n gap: 0px;\n}\n.bunny-gap-1 {\n gap: 0.25rem;\n}\n.bunny-gap-2 {\n gap: 0.5rem;\n}\n.bunny-gap-3 {\n gap: 0.75rem;\n}\n.bunny-gap-4 {\n gap: 1rem;\n}\n.bunny-gap-6 {\n gap: 1.5rem;\n}\n.bunny-gap-8 {\n gap: 2rem;\n}\n.bunny-space-y-2 > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));\n}\n.bunny-space-y-4 > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(1rem * var(--tw-space-y-reverse));\n}\n.bunny-space-y-8 > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(2rem * var(--tw-space-y-reverse));\n}\n.bunny-overflow-auto {\n overflow: auto;\n}\n.bunny-overflow-hidden {\n overflow: hidden;\n}\n.bunny-overflow-y-auto {\n overflow-y: auto;\n}\n.bunny-whitespace-nowrap {\n white-space: nowrap;\n}\n.bunny-text-nowrap {\n text-wrap: nowrap;\n}\n.bunny-rounded {\n border-radius: 0.25rem;\n}\n.bunny-rounded-full {\n border-radius: 9999px;\n}\n.bunny-rounded-lg {\n border-radius: 0.5rem;\n}\n.bunny-rounded-md {\n border-radius: 0.375rem;\n}\n.bunny-border {\n border-width: 1px;\n}\n.bunny-border-2 {\n border-width: 2px;\n}\n.bunny-border-t {\n border-top-width: 1px;\n}\n.bunny-border-solid {\n border-style: solid;\n}\n.bunny-border-none {\n border-style: none;\n}\n.bunny-border-gray-200 {\n --tw-border-opacity: 1;\n border-color: rgb(229 231 235 / var(--tw-border-opacity, 1));\n}\n.bunny-border-slate-200 {\n --tw-border-opacity: 1;\n border-color: rgb(226 232 240 / var(--tw-border-opacity, 1));\n}\n.bunny-bg-gray-300 {\n --tw-bg-opacity: 1;\n background-color: rgb(209 213 219 / var(--tw-bg-opacity, 1));\n}\n.bunny-bg-slate-50 {\n --tw-bg-opacity: 1;\n background-color: rgb(248 250 252 / var(--tw-bg-opacity, 1));\n}\n.bunny-bg-transparent {\n background-color: transparent;\n}\n.bunny-bg-white {\n --tw-bg-opacity: 1;\n background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));\n}\n.bunny-p-0 {\n padding: 0px;\n}\n.bunny-p-1 {\n padding: 0.25rem;\n}\n.bunny-p-2 {\n padding: 0.5rem;\n}\n.bunny-p-4 {\n padding: 1rem;\n}\n.bunny-px-12 {\n padding-left: 3rem;\n padding-right: 3rem;\n}\n.bunny-px-3 {\n padding-left: 0.75rem;\n padding-right: 0.75rem;\n}\n.bunny-px-4 {\n padding-left: 1rem;\n padding-right: 1rem;\n}\n.bunny-px-6 {\n padding-left: 1.5rem;\n padding-right: 1.5rem;\n}\n.bunny-py-2 {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n}\n.bunny-py-4 {\n padding-top: 1rem;\n padding-bottom: 1rem;\n}\n.bunny-py-6 {\n padding-top: 1.5rem;\n padding-bottom: 1.5rem;\n}\n.bunny-pb-2 {\n padding-bottom: 0.5rem;\n}\n.bunny-pb-4 {\n padding-bottom: 1rem;\n}\n.bunny-pb-6 {\n padding-bottom: 1.5rem;\n}\n.bunny-pb-8 {\n padding-bottom: 2rem;\n}\n.bunny-pl-0 {\n padding-left: 0px;\n}\n.bunny-pl-1 {\n padding-left: 0.25rem;\n}\n.bunny-pl-4 {\n padding-left: 1rem;\n}\n.bunny-pr-4 {\n padding-right: 1rem;\n}\n.bunny-pt-1 {\n padding-top: 0.25rem;\n}\n.bunny-pt-12 {\n padding-top: 3rem;\n}\n.bunny-pt-2 {\n padding-top: 0.5rem;\n}\n.bunny-pt-4 {\n padding-top: 1rem;\n}\n.bunny-pt-5 {\n padding-top: 1.25rem;\n}\n.bunny-pt-\\[25vh\\] {\n padding-top: 25vh;\n}\n.bunny-text-left {\n text-align: left;\n}\n.bunny-text-center {\n text-align: center;\n}\n.bunny-text-right {\n text-align: right;\n}\n.bunny-text-start {\n text-align: start;\n}\n.bunny-text-2xl {\n font-size: 1.5rem;\n line-height: 2rem;\n}\n.bunny-text-3xl {\n font-size: 1.875rem;\n line-height: 2.25rem;\n}\n.bunny-text-base {\n font-size: 1rem;\n line-height: 1.5rem;\n}\n.bunny-text-lg {\n font-size: 1.125rem;\n line-height: 1.75rem;\n}\n.bunny-text-sm {\n font-size: 0.875rem;\n line-height: 1.25rem;\n}\n.bunny-text-sm\\/5 {\n font-size: 0.875rem;\n line-height: 1.25rem;\n}\n.bunny-text-xl {\n font-size: 1.25rem;\n line-height: 1.75rem;\n}\n.bunny-text-xs {\n font-size: 0.75rem;\n line-height: 1rem;\n}\n.bunny-text-xs\\/3 {\n font-size: 0.75rem;\n line-height: 0.75rem;\n}\n.bunny-font-bold {\n font-weight: 700;\n}\n.bunny-font-medium {\n font-weight: 500;\n}\n.bunny-font-normal {\n font-weight: 400;\n}\n.bunny-text-gray-400 {\n --tw-text-opacity: 1;\n color: rgb(156 163 175 / var(--tw-text-opacity, 1));\n}\n.bunny-text-gray-500 {\n --tw-text-opacity: 1;\n color: rgb(107 114 128 / var(--tw-text-opacity, 1));\n}\n.bunny-text-gray-600 {\n --tw-text-opacity: 1;\n color: rgb(75 85 99 / var(--tw-text-opacity, 1));\n}\n.bunny-text-gray-900 {\n --tw-text-opacity: 1;\n color: rgb(17 24 39 / var(--tw-text-opacity, 1));\n}\n.bunny-text-orange-500 {\n --tw-text-opacity: 1;\n color: rgb(249 115 22 / var(--tw-text-opacity, 1));\n}\n.bunny-text-orange-600 {\n --tw-text-opacity: 1;\n color: rgb(234 88 12 / var(--tw-text-opacity, 1));\n}\n.bunny-text-slate-400 {\n --tw-text-opacity: 1;\n color: rgb(148 163 184 / var(--tw-text-opacity, 1));\n}\n.bunny-text-slate-500 {\n --tw-text-opacity: 1;\n color: rgb(100 116 139 / var(--tw-text-opacity, 1));\n}\n.bunny-text-slate-600 {\n --tw-text-opacity: 1;\n color: rgb(71 85 105 / var(--tw-text-opacity, 1));\n}\n.bunny-text-white {\n --tw-text-opacity: 1;\n color: rgb(255 255 255 / var(--tw-text-opacity, 1));\n}\n.bunny-underline {\n text-decoration-line: underline;\n}\n.bunny-shadow {\n --tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);\n --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.bunny-shadow-md {\n --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);\n --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.bunny-transition-\\[margin\\] {\n transition-property: margin;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.bunny-duration-300 {\n transition-duration: 300ms;\n}\n.rotate-45,\n.transform {\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-rotate: 0;\n --tw-skew-x: 0;\n --tw-skew-y: 0;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n}\n.shadow,\n.shadow-lg,\n.shadow-md,\n.shadow-none,\n.shadow-sm,\n.shadow-xl {\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-ring-shadow: 0 0 #0000;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-colored: 0 0 #0000;\n}\n.container {\n width: 100%;\n}\n@media (min-width: 768px) {\n .container {\n max-width: 768px;\n }\n}\n@media (min-width: 1024px) {\n .container {\n max-width: 1024px;\n }\n}\n@media (min-width: 1280px) {\n .container {\n max-width: 1280px;\n }\n}\n@media (min-width: 1536px) {\n .container {\n max-width: 1536px;\n }\n}\n.visible {\n visibility: visible;\n}\n.fixed {\n position: fixed;\n}\n.absolute {\n position: absolute;\n}\n.relative {\n position: relative;\n}\n.sticky {\n position: sticky;\n}\n.-top-0\\.5 {\n top: -0.125rem;\n}\n.bottom-0 {\n bottom: 0px;\n}\n.bottom-4 {\n bottom: 1rem;\n}\n.left-0 {\n left: 0px;\n}\n.right-0 {\n right: 0px;\n}\n.top-0 {\n top: 0px;\n}\n.z-50 {\n z-index: 50;\n}\n.col-span-2 {\n grid-column: span 2 / span 2;\n}\n.col-span-3 {\n grid-column: span 3 / span 3;\n}\n.col-span-full {\n grid-column: 1 / -1;\n}\n.m-0 {\n margin: 0px;\n}\n.mx-0 {\n margin-left: 0px;\n margin-right: 0px;\n}\n.mx-4 {\n margin-left: 1rem;\n margin-right: 1rem;\n}\n.my-12 {\n margin-top: 3rem;\n margin-bottom: 3rem;\n}\n.my-2 {\n margin-top: 0.5rem;\n margin-bottom: 0.5rem;\n}\n.my-4 {\n margin-top: 1rem;\n margin-bottom: 1rem;\n}\n.mb-2 {\n margin-bottom: 0.5rem;\n}\n.mb-4 {\n margin-bottom: 1rem;\n}\n.mb-8 {\n margin-bottom: 2rem;\n}\n.ml-2 {\n margin-left: 0.5rem;\n}\n.mr-8 {\n margin-right: 2rem;\n}\n.mt-1 {\n margin-top: 0.25rem;\n}\n.mt-2 {\n margin-top: 0.5rem;\n}\n.mt-4 {\n margin-top: 1rem;\n}\n.mt-6 {\n margin-top: 1.5rem;\n}\n.mt-8 {\n margin-top: 2rem;\n}\n.block {\n display: block;\n}\n.flex {\n display: flex;\n}\n.table {\n display: table;\n}\n.grid {\n display: grid;\n}\n.contents {\n display: contents;\n}\n.hidden {\n display: none;\n}\n.h-4 {\n height: 1rem;\n}\n.h-5 {\n height: 1.25rem;\n}\n.h-8 {\n height: 2rem;\n}\n.h-full {\n height: 100%;\n}\n.w-1\\/2 {\n width: 50%;\n}\n.w-1\\/3 {\n width: 33.333333%;\n}\n.w-12 {\n width: 3rem;\n}\n.w-2\\/3 {\n width: 66.666667%;\n}\n.w-4 {\n width: 1rem;\n}\n.w-full {\n width: 100%;\n}\n.max-w-32 {\n max-width: 8rem;\n}\n.flex-1 {\n flex: 1 1 0%;\n}\n.shrink {\n flex-shrink: 1;\n}\n.shrink-0 {\n flex-shrink: 0;\n}\n.flex-grow {\n flex-grow: 1;\n}\n.grow {\n flex-grow: 1;\n}\n.border-collapse {\n border-collapse: collapse;\n}\n.rotate-45 {\n --tw-rotate: 45deg;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.transform {\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.cursor-pointer {\n cursor: pointer;\n}\n.grid-cols-2 {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n}\n.grid-cols-3 {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n}\n.flex-row {\n flex-direction: row;\n}\n.flex-col {\n flex-direction: column;\n}\n.items-end {\n align-items: flex-end;\n}\n.items-center {\n align-items: center;\n}\n.justify-start {\n justify-content: flex-start;\n}\n.justify-end {\n justify-content: flex-end;\n}\n.justify-center {\n justify-content: center;\n}\n.justify-between {\n justify-content: space-between;\n}\n.gap-0 {\n gap: 0px;\n}\n.gap-1 {\n gap: 0.25rem;\n}\n.gap-2 {\n gap: 0.5rem;\n}\n.gap-3 {\n gap: 0.75rem;\n}\n.gap-4 {\n gap: 1rem;\n}\n.gap-6 {\n gap: 1.5rem;\n}\n.gap-8 {\n gap: 2rem;\n}\n.space-y-2 > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));\n}\n.space-y-4 > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(1rem * var(--tw-space-y-reverse));\n}\n.space-y-8 > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(2rem * var(--tw-space-y-reverse));\n}\n.overflow-auto {\n overflow: auto;\n}\n.overflow-hidden {\n overflow: hidden;\n}\n.overflow-visible {\n overflow: visible;\n}\n.whitespace-nowrap {\n white-space: nowrap;\n}\n.text-nowrap {\n text-wrap: nowrap;\n}\n.rounded {\n border-radius: 0.25rem;\n}\n.rounded-full {\n border-radius: 9999px;\n}\n.rounded-lg {\n border-radius: 0.5rem;\n}\n.rounded-md {\n border-radius: 0.375rem;\n}\n.rounded-sm {\n border-radius: 0.125rem;\n}\n.border {\n border-width: 1px;\n}\n.border-2 {\n border-width: 2px;\n}\n.border-b {\n border-bottom-width: 1px;\n}\n.border-t {\n border-top-width: 1px;\n}\n.border-solid {\n border-style: solid;\n}\n.border-none {\n border-style: none;\n}\n.border-gray-400 {\n --tw-border-opacity: 1;\n border-color: rgb(156 163 175 / var(--tw-border-opacity, 1));\n}\n.border-gray-500 {\n --tw-border-opacity: 1;\n border-color: rgb(107 114 128 / var(--tw-border-opacity, 1));\n}\n.border-slate-200 {\n --tw-border-opacity: 1;\n border-color: rgb(226 232 240 / var(--tw-border-opacity, 1));\n}\n.border-slate-300 {\n --tw-border-opacity: 1;\n border-color: rgb(203 213 225 / var(--tw-border-opacity, 1));\n}\n.border-slate-700 {\n --tw-border-opacity: 1;\n border-color: rgb(51 65 85 / var(--tw-border-opacity, 1));\n}\n.bg-black {\n --tw-bg-opacity: 1;\n background-color: rgb(0 0 0 / var(--tw-bg-opacity, 1));\n}\n.bg-emerald-200 {\n --tw-bg-opacity: 1;\n background-color: rgb(167 243 208 / var(--tw-bg-opacity, 1));\n}\n.bg-green-200 {\n --tw-bg-opacity: 1;\n background-color: rgb(187 247 208 / var(--tw-bg-opacity, 1));\n}\n.bg-orange-200 {\n --tw-bg-opacity: 1;\n background-color: rgb(254 215 170 / var(--tw-bg-opacity, 1));\n}\n.bg-red-200 {\n --tw-bg-opacity: 1;\n background-color: rgb(254 202 202 / var(--tw-bg-opacity, 1));\n}\n.bg-red-500 {\n --tw-bg-opacity: 1;\n background-color: rgb(239 68 68 / var(--tw-bg-opacity, 1));\n}\n.bg-slate-50 {\n --tw-bg-opacity: 1;\n background-color: rgb(248 250 252 / var(--tw-bg-opacity, 1));\n}\n.bg-transparent {\n background-color: transparent;\n}\n.bg-white {\n --tw-bg-opacity: 1;\n background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));\n}\n.bg-yellow-200 {\n --tw-bg-opacity: 1;\n background-color: rgb(254 240 138 / var(--tw-bg-opacity, 1));\n}\n.p-0 {\n padding: 0px;\n}\n.p-1 {\n padding: 0.25rem;\n}\n.p-2 {\n padding: 0.5rem;\n}\n.p-4 {\n padding: 1rem;\n}\n.p-8 {\n padding: 2rem;\n}\n.px-2 {\n padding-left: 0.5rem;\n padding-right: 0.5rem;\n}\n.px-3 {\n padding-left: 0.75rem;\n padding-right: 0.75rem;\n}\n.px-4 {\n padding-left: 1rem;\n padding-right: 1rem;\n}\n.px-6 {\n padding-left: 1.5rem;\n padding-right: 1.5rem;\n}\n.px-8 {\n padding-left: 2rem;\n padding-right: 2rem;\n}\n.py-1 {\n padding-top: 0.25rem;\n padding-bottom: 0.25rem;\n}\n.py-2 {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n}\n.py-4 {\n padding-top: 1rem;\n padding-bottom: 1rem;\n}\n.py-6 {\n padding-top: 1.5rem;\n padding-bottom: 1.5rem;\n}\n.pb-2 {\n padding-bottom: 0.5rem;\n}\n.pb-4 {\n padding-bottom: 1rem;\n}\n.pb-6 {\n padding-bottom: 1.5rem;\n}\n.pb-8 {\n padding-bottom: 2rem;\n}\n.pl-0 {\n padding-left: 0px;\n}\n.pl-2 {\n padding-left: 0.5rem;\n}\n.pl-4 {\n padding-left: 1rem;\n}\n.pt-1 {\n padding-top: 0.25rem;\n}\n.pt-12 {\n padding-top: 3rem;\n}\n.pt-2 {\n padding-top: 0.5rem;\n}\n.pt-4 {\n padding-top: 1rem;\n}\n.pt-5 {\n padding-top: 1.25rem;\n}\n.pt-6 {\n padding-top: 1.5rem;\n}\n.pt-8 {\n padding-top: 2rem;\n}\n.text-left {\n text-align: left;\n}\n.text-center {\n text-align: center;\n}\n.text-right {\n text-align: right;\n}\n.align-middle {\n vertical-align: middle;\n}\n.text-2xl {\n font-size: 1.5rem;\n line-height: 2rem;\n}\n.text-base {\n font-size: 1rem;\n line-height: 1.5rem;\n}\n.text-lg {\n font-size: 1.125rem;\n line-height: 1.75rem;\n}\n.text-sm {\n font-size: 0.875rem;\n line-height: 1.25rem;\n}\n.text-xl {\n font-size: 1.25rem;\n line-height: 1.75rem;\n}\n.text-xs {\n font-size: 0.75rem;\n line-height: 1rem;\n}\n.font-bold {\n font-weight: 700;\n}\n.font-medium {\n font-weight: 500;\n}\n.font-normal {\n font-weight: 400;\n}\n.capitalize {\n text-transform: capitalize;\n}\n.text-emerald-600 {\n --tw-text-opacity: 1;\n color: rgb(5 150 105 / var(--tw-text-opacity, 1));\n}\n.text-emerald-700 {\n --tw-text-opacity: 1;\n color: rgb(4 120 87 / var(--tw-text-opacity, 1));\n}\n.text-gray-600 {\n --tw-text-opacity: 1;\n color: rgb(75 85 99 / var(--tw-text-opacity, 1));\n}\n.text-gray-900 {\n --tw-text-opacity: 1;\n color: rgb(17 24 39 / var(--tw-text-opacity, 1));\n}\n.text-green-600 {\n --tw-text-opacity: 1;\n color: rgb(22 163 74 / var(--tw-text-opacity, 1));\n}\n.text-orange-500 {\n --tw-text-opacity: 1;\n color: rgb(249 115 22 / var(--tw-text-opacity, 1));\n}\n.text-orange-600 {\n --tw-text-opacity: 1;\n color: rgb(234 88 12 / var(--tw-text-opacity, 1));\n}\n.text-red-500 {\n --tw-text-opacity: 1;\n color: rgb(239 68 68 / var(--tw-text-opacity, 1));\n}\n.text-slate-400 {\n --tw-text-opacity: 1;\n color: rgb(148 163 184 / var(--tw-text-opacity, 1));\n}\n.text-slate-500 {\n --tw-text-opacity: 1;\n color: rgb(100 116 139 / var(--tw-text-opacity, 1));\n}\n.text-slate-600 {\n --tw-text-opacity: 1;\n color: rgb(71 85 105 / var(--tw-text-opacity, 1));\n}\n.text-white {\n --tw-text-opacity: 1;\n color: rgb(255 255 255 / var(--tw-text-opacity, 1));\n}\n.text-yellow-500 {\n --tw-text-opacity: 1;\n color: rgb(234 179 8 / var(--tw-text-opacity, 1));\n}\n.underline {\n text-decoration-line: underline;\n}\n.shadow {\n --tw-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);\n --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.shadow-lg {\n --tw-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);\n --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.shadow-md {\n --tw-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);\n --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.shadow-none {\n --tw-shadow: 0 0 #0000;\n --tw-shadow-colored: 0 0 #0000;\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.shadow-sm {\n --tw-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.shadow-xl {\n --tw-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);\n --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.transition {\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.transition-\\[margin\\] {\n transition-property: margin;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.transition-all {\n transition-property: all;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.duration-200 {\n transition-duration: 200ms;\n}\n.duration-300 {\n transition-duration: 300ms;\n}\n.hover\\:bg-gray-100:hover {\n --tw-bg-opacity: 1;\n background-color: rgb(243 244 246 / var(--tw-bg-opacity, 1));\n}\n.hover\\:bg-slate-100:hover {\n --tw-bg-opacity: 1;\n background-color: rgb(241 245 249 / var(--tw-bg-opacity, 1));\n}\n.hover\\:bg-slate-200:hover {\n --tw-bg-opacity: 1;\n background-color: rgb(226 232 240 / var(--tw-bg-opacity, 1));\n}\n.hover\\:bg-gray-200:hover {\n --tw-bg-opacity: 1;\n background-color: rgb(229 231 235 / var(--tw-bg-opacity, 1));\n}\n@media (min-width: 768px) {\n .sm\\:flex {\n display: flex;\n }\n .sm\\:hidden {\n display: none;\n }\n}\n.hover\\:bunny-text-orange-400:hover {\n --tw-text-opacity: 1;\n color: rgb(251 146 60 / var(--tw-text-opacity, 1));\n}\n.bunny-components .ant-upload-select-picture-card {\n margin: 0 !important;\n}\n.bunny-components .ant-upload {\n border-radius: 0.5rem !important;\n}\n.bunny-components .ant-row {\n margin-bottom: 0px;\n}\n.bunny-components .ant-select-disabled .ant-select-selector .ant-select-selection-item {\n color: rgba(0, 0, 0, 0.25) !important;\n}\n.bunny-components .ant-input-number,\n.bunny-components .ant-input,\n.bunny-components .ant-picker,\n.bunny-components .ant-input-affix-wrapper,\n.bunny-components .ant-select-selector {\n font-size: 0.875rem !important;\n transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);\n color: #232323 !important;\n}\n.bunny-components .ant-input-affix-wrapper {\n padding-top: 0 !important;\n padding-bottom: 0 !important;\n}\n.bunny-components .ant-input-group-addon,\n.bunny-components .ant-input-number-group-addon {\n color: #475569 !important;\n}\n.bunny-components .ant-input-number-group-wrapper,\n.bunny-components .ant-input-number-affix-wrapper {\n width: 100%;\n}\n.bunny-components .ant-input-affix-wrapper input {\n border: none !important;\n}\n.bunny-components .ant-form-item {\n margin-bottom: 0;\n}\n.bunny-components .ant-form-item-label {\n text-transform: none !important;\n font-size: 0.75rem;\n padding-bottom: 2px !important;\n}\n.bunny-components .ant-form-item-label > label {\n width: 100%;\n color: #4b5563 !important;\n}\n.bunny-components .form .ant-form-item-label label {\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n box-sizing: border-box;\n}\n.bunny-components .ant-form-item-explain,\n.bunny-components .ant-form-item-explain-error {\n font-size: 11px;\n min-height: 11px;\n line-height: 11px;\n padding-top: 2px;\n}\n.bunny-components .ant-timeline-item-content {\n font-size: smaller;\n}\n.bunny-components .ant-tree {\n font-size: 0.875rem;\n}\n.bunny-components .ant-tree-treenode {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.bunny-components .ant-tree-draggable-icon {\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.bunny-components .ant-tree-node-content-wrapper {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.bunny-components .ant-tree-switcher {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.bunny-components .ant-page-header {\n padding-left: 0;\n padding-right: 0;\n padding-top: 0;\n}\n.bunny-components .ant-tag {\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: 14px;\n font-weight: 500;\n white-space: nowrap;\n padding-inline-start: 0.625rem;\n padding-inline-end: 0.625rem;\n margin: 0;\n}\n.bunny-components .ant-tag-blue {\n color: #3b82f6 !important;\n background: #bfdbfe !important;\n}\n.bunny-components .ant-tag-green {\n color: #059669 !important;\n background: #a7f3d0 !important;\n}\n.bunny-components .ant-tag-red {\n color: #ef4444 !important;\n background: #fecaca !important;\n}\n.bunny-components .ant-tag-orange {\n color: #f97316 !important;\n background: #fed7aa !important;\n}\n.bunny-components .ant-tag-yellow {\n color: #f59e0b !important;\n background: #fde68a !important;\n}\n.bunny-components .ant-tag-purple {\n color: #8b5cf6 !important;\n background: #ddd6fe !important;\n}\n.bunny-components .ant-tag-gray {\n color: #6b7280 !important;\n background: #e5e7eb !important;\n}\n.bunny-components .ant-tag-black {\n color: white !important;\n background: black !important;\n}\n.bunny-components .ant-picker {\n width: 100%;\n}\n.bunny-components .ant-input,\n.bunny-components .ant-select,\n.bunny-components .ant-picker {\n height: 32px !important;\n}\n.bunny-components .ant-slider-dot {\n border: 2px solid #f0f0f0;\n}\n.bunny-components .ant-slider-dot-active {\n border-color: #ff5833;\n}\n.bunny-components .ant-slider-mark :last-child {\n transform: translateX(-75%) !important;\n}\n.bunny-components .ant-drawer-content {\n background: #f3f3f9ff;\n}\n.bunny-components .ant-drawer-body,\n.bunny-components .ant-layout {\n background: #f8fafc;\n}\n.bunny-components .vista-link {\n color: #1890ff;\n}\n.bunny-components .vista-link:hover {\n text-decoration: underline;\n cursor: pointer;\n}\n.bunny-components .ant-popover-inner-content {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n max-width: 300px;\n}\n.bunny-components .ant-popconfirm-message-text {\n width: 100% !important;\n}\n.bunny-components .ant-popconfirm-title {\n padding: 0;\n text-align: center;\n font-size: 0.875rem !important;\n width: 100% !important;\n}\n.bunny-components .ant-popconfirm-buttons {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n}\n.bunny-components .ant-popconfirm-buttons button {\n margin-inline-start: 0 !important;\n}\n.bunny-components .ant-pagination-item {\n display: flex !important;\n align-items: center;\n justify-content: center;\n}\n.bunny-components .ant-btn-primary:disabled {\n background: #eef0f2 !important;\n color: rgba(0, 0, 0, 0.25) !important;\n border: none;\n}\n.bunny-components .ant-btn {\n box-shadow: none;\n text-shadow: none;\n outline: none !important;\n line-height: 1;\n font-weight: normal;\n}\n.bunny-components .ant-btn-default .ant-btn-icon {\n color: #94a3b8;\n transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);\n}\n.bunny-components .ant-btn-default:hover .ant-btn-icon {\n color: #ff7f5c;\n}\n.bunny-components .ant-btn-default:disabled {\n border-color: rgba(113, 125, 148, 0.2) !important;\n}\n.bunny-components .ant-btn-primary:disabled {\n background-color: rgba(113, 125, 148, 0.1) !important;\n border-color: rgba(113, 125, 148, 0.1) !important;\n}\n.bunny-components .ant-btn-primary:hover:disabled,\n.bunny-components .ant-btn-primary:disabled {\n background-clip: padding-box;\n}\n.bunny-components .ant-select-selection-item-content {\n display: flex !important;\n align-items: center;\n}\n.bunny-components .ant-select-item {\n font-size: 0.875rem;\n}\n.bunny-components .ant-select-item-option-content {\n display: flex;\n align-items: center;\n white-space: nowrap !important;\n overflow: visible !important;\n text-overflow: default !important;\n font-size: 0.875rem;\n}\n.bunny-components .ant-select-arrow .anticon:not(.ant-select-suffix) {\n pointer-events: none;\n}\n.bunny-components .select-dropdown-blue-gray .ant-select-item-option {\n background-color: #fff !important;\n}\n.bunny-components .select-dropdown-blue-gray .ant-select-item-option-active {\n color: #ff5833;\n}\n.bunny-components .ant-dropdown-menu-items {\n padding-left: 0 !important;\n}\n.bunny-components .ant-dropdown-menu-item-active {\n background-color: transparent !important;\n}\n.bunny-components .ant-input-affix-wrapper.searchfield {\n background: white !important;\n}\n.bunny-components .ant-input-affix-wrapper.searchfield input {\n background: white !important;\n}\n.bunny-components .ant-input-affix-wrapper-focused {\n background: white !important;\n}\n.bunny-components .panel .ant-input-affix-wrapper.searchfield {\n background: #f8f8f8 !important;\n}\n.bunny-components .panel .ant-input-affix-wrapper.searchfield input {\n background: #f8f8f8 !important;\n}\n.bunny-components .ant-input-steps-hidden .ant-input-number-handler-wrap {\n display: none;\n}\n.bunny-components .ant-layout-header {\n height: 48px;\n}\n.bunny-components .ant-layout-sider-children {\n width: inherit;\n position: fixed;\n}\n.bunny-components .ant-menu-item-group-list {\n display: flex !important;\n flex-direction: column !important;\n align-items: flex-start !important;\n gap: 4px !important;\n}\n.bunny-components .group {\n display: flex;\n flex-direction: row;\n flex-flow: row wrap;\n box-sizing: border-box;\n}\n.bunny-components .select-datepicker {\n animation-duration: 0.35s !important;\n}\n.bunny-components .header-datepicker {\n top: 96px !important;\n animation-duration: 0s !important;\n}\n.bunny-components .ant-picker-header {\n border-bottom: none !important;\n}\n.bunny-components .ant-picker-content thead tr th {\n font-weight: 500;\n}\n.bunny-components .ant-picker-panel-container {\n border-radius: 0.375rem;\n}\n.bunny-components .ant-picker-cell-selected .custom-date-display {\n color: #ffffff;\n background-color: #ff5833;\n}\n.bunny-components .ant-picker-cell-today .custom-date-display {\n border: 1px solid #ff5833;\n}\n.bunny-components .ant-select:hover,\n.bunny-components * .cardElement:hover {\n border-color: #ff5833;\n}\n.bunny-components .ant-input-number {\n width: 100%;\n}\n.bunny-components .ant-input-number-focused {\n border-color: #ff5833 !important;\n background-color: #ffffff !important;\n}\n.bunny-components .ant-input-affix-wrapper-focused,\n.bunny-components .ant-input-number-focused,\n.bunny-components .ant-picker,\n.bunny-components .ant-input,\n.bunny-components .ant-select-focused .ant-select-selector,\n.bunny-components .ant-select-selector:focus,\n.bunny-components .ant-select-selector:active,\n.bunny-components .ant-select-open .ant-select-selector {\n box-shadow: none !important;\n}\n.bunny-components .ant-select-item-option-selected .ant-select-item-option-state {\n display: none !important;\n}\n.bunny-components .ant-form * input[type='text'].ant-input:not(:disabled),\n.bunny-components .ant-select-selection-item:not(:disabled) {\n color: #232323;\n}\n.bunny-components .ant-tabs-ink-bar {\n display: none !important;\n}\n.bunny-components .ant-tabs-tab.ant-tabs-tab-active {\n border-bottom: 2px solid #ff5833 !important;\n}\n.bunny-components .ant-tabs-tab {\n border-bottom: 2px solid transparent !important;\n padding-bottom: 14px !important;\n}\n.bunny-components .ant-upload-wrapper {\n display: flex;\n}\n.bunny-components .ant-form-item-label > label::after {\n display: none !important;\n}\n.bunny-components .ant-menu-item {\n display: flex !important;\n align-items: center !important;\n}\n.ant-notification {\n width: min-content;\n}\n.ant-notification-topRight {\n right: 0 !important;\n left: 0 !important;\n margin-left: auto !important;\n margin-right: auto !important;\n}\n.ant-notification-notice-wrapper {\n width: 350px !important;\n overflow: hidden !important;\n}\n.ant-notification-notice {\n padding: 16px !important;\n width: 350px !important;\n border-radius: 8px !important;\n display: flex !important;\n box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.08), 0px 1px 18px rgba(0, 0, 0, 0.08), 0px 3px 5px rgba(0, 0, 0, 0.16) !important;\n}\n.ant-notification-notice-description {\n padding: 0 14px 0 0 !important;\n font-size: 14px !important;\n overflow-wrap: break-word;\n}\n.ant-notification-notice-success {\n background-color: #edfffa !important;\n}\n.ant-notification-notice-error {\n background-color: #fff8f4 !important;\n}\n.ant-notification-notice-error .ant-notification-notice-message {\n color: #ff5833 !important;\n font-weight: 500 !important;\n}\n.ant-notification-notice-error .ant-notification-notice-icon {\n color: #ff5833;\n}\n.ant-notification-notice-success .ant-notification-notice-message {\n color: #00b76a !important;\n font-weight: 500 !important;\n}\n.ant-notification-notice-success .ant-notification-notice-icon {\n color: #00b76a !important;\n}\n.ant-notification-notice-message {\n margin-bottom: 0 !important;\n}\n.ant-notification-notice-close {\n top: 16px !important;\n right: 16px !important;\n}\n.bunny-invoice-container {\n padding: 0;\n box-sizing: border-box !important;\n line-height: 1.15;\n}\n@media only screen and (max-width: 768px) {\n select,\n textarea,\n input[type='text'],\n input[type='password'],\n input[type='datetime'],\n input[type='datetime-local'],\n input[type='date'],\n input[type='month'],\n input[type='time'],\n input[type='week'],\n input[type='number'],\n input[type='email'],\n input[type='url'],\n input[type='search'],\n input[type='tel'],\n input[type='color'] {\n font-size: 16px !important;\n }\n}\n@keyframes App-logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n";
50
50
  styleInject(css_248z);
51
51
 
52
52
  const IGNORE_ERRORS = ['Invalid or missing authorization', '["Not found"]'];
@@ -141,7 +141,7 @@ const useAllErrorFormats = () => {
141
141
  };
142
142
 
143
143
  // This will be replaced at build time by rollup-plugin-replace
144
- const PACKAGE_VERSION = '1.6.0-beta.23';
144
+ const PACKAGE_VERSION = '1.7.0-beta.2';
145
145
  const createRequestHeaders = (token) => {
146
146
  const headers = createClientDevHeaders({ token });
147
147
  // Add the components version header
@@ -927,7 +927,7 @@ function readFragment(...r) {
927
927
 
928
928
  var t = initGraphQLTada();
929
929
 
930
- const query$7 = t(`
930
+ const query$9 = t(`
931
931
  query entityBranding {
932
932
  entityBranding {
933
933
  accentColor
@@ -937,7 +937,7 @@ const query$7 = t(`
937
937
  }
938
938
  `);
939
939
  const getBranding = async ({ token, apiHost }) => {
940
- return await execute(query$7, { apiHost, token }, {});
940
+ return await execute(query$9, { apiHost, token }, {});
941
941
  };
942
942
 
943
943
  const BunnyContext = createContext({});
@@ -1141,10 +1141,10 @@ const DocumentTemplatePreview = ({ targetUrl }) => {
1141
1141
  }, children: jsx(RPPages, {}) }))] }) }) }));
1142
1142
  };
1143
1143
 
1144
- const { Text: Text$A } = Typography;
1144
+ const { Text: Text$B } = Typography;
1145
1145
  function BackButton({ onClick, title }) {
1146
1146
  const { brandColor } = useBrand();
1147
- return (jsxs(StyledBackButton, { brandColor: brandColor, className: "bunny-flex bunny-items-center bunny-gap-2 bunny-p-0 bunny-text-gray-400", onClick: onClick, children: [jsx(FontAwesomeIcon, { className: "pt-0.5", icon: faArrowLeft }), jsx(Text$A, { className: "bunny-text-sm bunny-text-gray-400", children: title || 'back' })] }));
1147
+ return (jsxs(StyledBackButton, { brandColor: brandColor, className: "bunny-flex bunny-items-center bunny-gap-2 bunny-p-0 bunny-text-gray-400", onClick: onClick, children: [jsx(FontAwesomeIcon, { className: "pt-0.5", icon: faArrowLeft }), jsx(Text$B, { className: "bunny-text-sm bunny-text-gray-400 bunny-text-nowrap", children: title || 'back' })] }));
1148
1148
  }
1149
1149
  const StyledBackButton = styled.button.withConfig({
1150
1150
  shouldForwardProp: prop => !['brandColor'].includes(prop),
@@ -1180,7 +1180,7 @@ const InvoiceQuoteView = ({ children, formattedInvoice, html, backButtonName, on
1180
1180
  }, children: [targetUrl ? (jsx(DocumentTemplatePreview, { targetUrl: targetUrl })) : (jsx(Markup, { content: html })), children] }))] }));
1181
1181
  };
1182
1182
 
1183
- const MUTATION$9 = `
1183
+ const MUTATION$8 = `
1184
1184
  query FormattedInvoice($id: ID) {
1185
1185
  formattedInvoice(id: $id) {
1186
1186
  amount
@@ -1248,7 +1248,7 @@ query FormattedInvoice($id: ID) {
1248
1248
  const getFormattedInvoice = async ({ id, token, apiHost, }) => {
1249
1249
  const vars = { id };
1250
1250
  const response = await gqlRequest({
1251
- query: MUTATION$9,
1251
+ query: MUTATION$8,
1252
1252
  token,
1253
1253
  vars,
1254
1254
  apiHost,
@@ -18614,7 +18614,7 @@ function CardImage({ paymentMethod: maskedPaymentMethod, }) {
18614
18614
  }
18615
18615
  }
18616
18616
 
18617
- const { Text: Text$z } = Typography;
18617
+ const { Text: Text$A } = Typography;
18618
18618
  const MiniCreditCard_PaymentMethodFragment = t(`
18619
18619
  fragment MiniCreditCard_PaymentMethodFragment on PaymentMethod {
18620
18620
  ...CardImage_PaymentMethodFragment
@@ -18640,22 +18640,22 @@ function MiniCreditCard({ className, buttons, hideDropdownMenu = false, hideDefa
18640
18640
  return darkMode ? 'var(--row-background-alternate)' : 'bg-slate-50';
18641
18641
  }, [darkMode]);
18642
18642
  const isDefault = paymentMethod === null || paymentMethod === void 0 ? void 0 : paymentMethod.isDefault;
18643
- return (jsx("div", { className: `bunny-flex bunny-flex-row bunny-justify-between bunny-items-center bunny-p-1 bunny-px-3 bunny-border-solid ${backgroundColor} bunny-${borderColor} bunny-rounded-md bunny-border ${className}`, id: id, children: paymentMethod ? (jsxs(Fragment, { children: [jsx("div", { className: "bunny-flex bunny-flex-row bunny-gap-4", children: jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-2 bunny-space-between bunny-w-full", children: [jsx(CardImage, { paymentMethod: paymentMethod }), jsx(Issuer, { issuer: (_a = paymentMethod === null || paymentMethod === void 0 ? void 0 : paymentMethod.metadata) === null || _a === void 0 ? void 0 : _a.issuer }), jsx(Identifier, { type: (_b = paymentMethod === null || paymentMethod === void 0 ? void 0 : paymentMethod.metadata) === null || _b === void 0 ? void 0 : _b.type, identifier: (_c = paymentMethod === null || paymentMethod === void 0 ? void 0 : paymentMethod.metadata) === null || _c === void 0 ? void 0 : _c.identifier }), !hideDefaultTag && (jsx("div", { children: isDefault ? (jsx(Tag, { bordered: false, style: { color: brandColor, backgroundColor: `${brandColor}30` }, children: "Default" })) : null }))] }) }), buttons ? (buttons) : (jsx(Fragment, { children: !hideDropdownMenu && (jsx(DropdownMenu, { setDefault: onClickSetDefault, remove: onClickRemove, isDefault: isDefault !== null && isDefault !== void 0 ? isDefault : false, id: `credit-card-dropdown-${paymentMethod.id}` })) }))] })) : (jsxs("div", { className: "bunny-flex bunny-flex-row bunny-items-center justify-between w-full", children: [jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2 bunny-items-center", children: [jsx(CreditCardOutlined, {}), jsx(Text$z, { className: "bunny-text-slate-400 bunny-text-sm", children: "No payment methods" })] }), jsx(Button, { disabled: true, type: "link" }), buttons] })) }));
18643
+ return (jsx("div", { className: `bunny-flex bunny-flex-row bunny-justify-between bunny-items-center bunny-p-1 bunny-px-3 bunny-border-solid ${backgroundColor} bunny-${borderColor} bunny-rounded-md bunny-border ${className}`, id: id, children: paymentMethod ? (jsxs(Fragment, { children: [jsx("div", { className: "bunny-flex bunny-flex-row bunny-gap-4", children: jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-2 bunny-space-between bunny-w-full", children: [jsx(CardImage, { paymentMethod: paymentMethod }), jsx(Issuer, { issuer: (_a = paymentMethod === null || paymentMethod === void 0 ? void 0 : paymentMethod.metadata) === null || _a === void 0 ? void 0 : _a.issuer }), jsx(Identifier, { type: (_b = paymentMethod === null || paymentMethod === void 0 ? void 0 : paymentMethod.metadata) === null || _b === void 0 ? void 0 : _b.type, identifier: (_c = paymentMethod === null || paymentMethod === void 0 ? void 0 : paymentMethod.metadata) === null || _c === void 0 ? void 0 : _c.identifier }), !hideDefaultTag && (jsx("div", { children: isDefault ? (jsx(Tag, { bordered: false, style: { color: brandColor, backgroundColor: `${brandColor}30` }, children: "Default" })) : null }))] }) }), buttons ? (buttons) : (jsx(Fragment, { children: !hideDropdownMenu && (jsx(DropdownMenu, { setDefault: onClickSetDefault, remove: onClickRemove, isDefault: isDefault !== null && isDefault !== void 0 ? isDefault : false, id: `credit-card-dropdown-${paymentMethod.id}` })) }))] })) : (jsxs("div", { className: "bunny-flex bunny-flex-row bunny-items-center justify-between w-full", children: [jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2 bunny-items-center", children: [jsx(CreditCardOutlined, {}), jsx(Text$A, { className: "bunny-text-slate-400 bunny-text-sm", children: "No payment methods" })] }), jsx(Button, { disabled: true, type: "link" }), buttons] })) }));
18644
18644
  }
18645
18645
  const Identifier = ({ type, identifier, }) => {
18646
18646
  if (type === 'link') {
18647
18647
  return null;
18648
18648
  }
18649
18649
  if (type === 'cashapp') {
18650
- return jsx(Text$z, { children: "Cashapp" });
18650
+ return jsx(Text$A, { children: "Cashapp" });
18651
18651
  }
18652
- return (jsxs("div", { children: [jsx(Text$z, { className: "relative -top-0.5", children: "****" }), jsx(Text$z, { children: identifier })] }));
18652
+ return (jsxs("div", { children: [jsx(Text$A, { className: "relative -top-0.5", children: "****" }), jsx(Text$A, { children: identifier })] }));
18653
18653
  };
18654
18654
  const Issuer = ({ issuer }) => {
18655
18655
  const list = ['visa', 'link', 'jcb', 'discover', 'sepa'];
18656
18656
  if (!issuer || issuer.length == 0 || list.includes(issuer === null || issuer === void 0 ? void 0 : issuer.toLowerCase()))
18657
18657
  return null;
18658
- return jsx(Text$z, { children: lodashExports.capitalize(issuer) });
18658
+ return jsx(Text$A, { children: lodashExports.capitalize(issuer) });
18659
18659
  };
18660
18660
  const DropdownMenu = ({ setDefault, remove, isDefault, id, }) => {
18661
18661
  const { brandColor } = useBrand();
@@ -18700,6 +18700,16 @@ const QueryKeyFactory = {
18700
18700
  ...(entityId ? [entityId] : []),
18701
18701
  ...(token ? [token] : []),
18702
18702
  ],
18703
+ accountBillingDetailsKey: ({ accountId, token }) => [
18704
+ 'accountBillingDetails',
18705
+ ...(accountId ? [accountId] : []),
18706
+ ...(token ? [token] : []),
18707
+ ],
18708
+ accountContactsKey: ({ accountId, token }) => [
18709
+ 'accountContacts',
18710
+ ...(accountId ? [accountId] : []),
18711
+ ...(token ? [token] : []),
18712
+ ],
18703
18713
  brandingKey: (token) => ['branding', ...(token ? [token] : [])],
18704
18714
  calculatedPricesKey: ({ priceListId, quantity, token }) => [
18705
18715
  'calculatedPrices',
@@ -18766,7 +18776,7 @@ const QueryKeyFactory = {
18766
18776
  paymentPluginsKey: (token) => ['paymentPlugins', ...(token ? [token] : [])],
18767
18777
  };
18768
18778
 
18769
- const query$6 = t(`
18779
+ const query$8 = t(`
18770
18780
  query PaymentMethods($accountId: ID) {
18771
18781
  paymentMethods(accountId: $accountId) {
18772
18782
  nodes {
@@ -18795,7 +18805,7 @@ const query$6 = t(`
18795
18805
  `, [PaymentForm_PaymentMethodsFragment]);
18796
18806
  const getPaymentMethods = async ({ apiHost, token, accountId, }) => {
18797
18807
  var _a, _b, _c;
18798
- const response = await execute(query$6, { apiHost, token }, { accountId });
18808
+ const response = await execute(query$8, { apiHost, token }, { accountId });
18799
18809
  // Filter out null values that are technically possible due to api schema
18800
18810
  return (_c = (_b = (_a = response === null || response === void 0 ? void 0 : response.paymentMethods) === null || _a === void 0 ? void 0 : _a.nodes) === null || _b === void 0 ? void 0 : _b.filter(paymentMethod => paymentMethod !== null)) !== null && _c !== void 0 ? _c : [];
18801
18811
  };
@@ -18820,7 +18830,7 @@ const usePaymentMethod = ({ accountId, enabled = true, }) => {
18820
18830
  };
18821
18831
  };
18822
18832
 
18823
- const mutation$5 = t(`
18833
+ const mutation$d = t(`
18824
18834
  query PaymentPlugins($accountId: ID) {
18825
18835
  paymentPlugins(accountId: $accountId) {
18826
18836
  enabled
@@ -18848,7 +18858,7 @@ const mutation$5 = t(`
18848
18858
  // }[];
18849
18859
  // };
18850
18860
  const getPaymentPlugins = async ({ apiHost, token, accountId, }) => {
18851
- const response = await execute(mutation$5, { apiHost, token }, { accountId });
18861
+ const response = await execute(mutation$d, { apiHost, token }, { accountId });
18852
18862
  return response === null || response === void 0 ? void 0 : response.paymentPlugins;
18853
18863
  };
18854
18864
  const usePaymentPlugins = (accountId) => {
@@ -19072,7 +19082,7 @@ function useSave$1({ onSaveSuccess, onSaveError, accountId, }) {
19072
19082
  return { save, isSaving };
19073
19083
  }
19074
19084
 
19075
- const MUTATION$8 = `
19085
+ const MUTATION$7 = `
19076
19086
  mutation checkout(
19077
19087
  $invoiceId: ID,
19078
19088
  $quoteId: ID,
@@ -19121,7 +19131,7 @@ const checkout = async ({ quoteId, invoiceId, paymentMethodId, paymentMethodData
19121
19131
  };
19122
19132
  }
19123
19133
  const response = await gqlRequest({
19124
- query: MUTATION$8,
19134
+ query: MUTATION$7,
19125
19135
  token,
19126
19136
  vars: mutationVars,
19127
19137
  apiHost: apiHost,
@@ -19402,7 +19412,7 @@ var PaymentType;
19402
19412
  PaymentType["CHECKOUT_NO_PAYMENT"] = "CHECKOUT_NO_PAYMENT";
19403
19413
  })(PaymentType || (PaymentType = {}));
19404
19414
 
19405
- const handleAllErrorFormats$2 = useAllErrorFormats$1();
19415
+ const handleAllErrorFormats$3 = useAllErrorFormats$1();
19406
19416
  const showErrorNotification$6 = useErrorNotification();
19407
19417
  const useHandlePayment = ({ quote, invoice, onPaymentSuccess, onPaymentHoldSuccess, plugin, paymentHoldOptions, accountId, }) => {
19408
19418
  // Context
@@ -19424,7 +19434,7 @@ const useHandlePayment = ({ quote, invoice, onPaymentSuccess, onPaymentHoldSucce
19424
19434
  const { pay: payDemoPay, isPaying: isPayingDemoPay } = usePay$1({
19425
19435
  onPaymentSuccess: handlePaymentSuccess,
19426
19436
  onPaymentError: error => {
19427
- handleAllErrorFormats$2(error);
19437
+ handleAllErrorFormats$3(error);
19428
19438
  },
19429
19439
  quote: quote,
19430
19440
  invoice: invoice,
@@ -19433,7 +19443,7 @@ const useHandlePayment = ({ quote, invoice, onPaymentSuccess, onPaymentHoldSucce
19433
19443
  const { pay: payStripe, isPaying: isPayingStripe } = usePay({
19434
19444
  onPaymentSuccess: handlePaymentSuccess,
19435
19445
  onPaymentError: error => {
19436
- handleAllErrorFormats$2(error);
19446
+ handleAllErrorFormats$3(error);
19437
19447
  },
19438
19448
  quote: quote,
19439
19449
  invoice: invoice,
@@ -19445,7 +19455,7 @@ const useHandlePayment = ({ quote, invoice, onPaymentSuccess, onPaymentHoldSucce
19445
19455
  onPaymentHoldSuccess === null || onPaymentHoldSuccess === void 0 ? void 0 : onPaymentHoldSuccess(response);
19446
19456
  },
19447
19457
  onApproveHoldError: error => {
19448
- handleAllErrorFormats$2(error);
19458
+ handleAllErrorFormats$3(error);
19449
19459
  },
19450
19460
  });
19451
19461
  const { approveHold: approveHoldDemoPay, isApprovingHold: isApprovingHoldDemoPay } = useApproveHold$1({
@@ -19453,7 +19463,7 @@ const useHandlePayment = ({ quote, invoice, onPaymentSuccess, onPaymentHoldSucce
19453
19463
  onPaymentHoldSuccess === null || onPaymentHoldSuccess === void 0 ? void 0 : onPaymentHoldSuccess(response);
19454
19464
  },
19455
19465
  onApproveHoldError: error => {
19456
- handleAllErrorFormats$2(error);
19466
+ handleAllErrorFormats$3(error);
19457
19467
  },
19458
19468
  });
19459
19469
  // Mutations
@@ -19471,7 +19481,7 @@ const useHandlePayment = ({ quote, invoice, onPaymentSuccess, onPaymentHoldSucce
19471
19481
  onPaymentSuccess === null || onPaymentSuccess === void 0 ? void 0 : onPaymentSuccess({});
19472
19482
  },
19473
19483
  onError: error => {
19474
- handleAllErrorFormats$2(error);
19484
+ handleAllErrorFormats$3(error);
19475
19485
  },
19476
19486
  });
19477
19487
  const handleApproveHold = async (overridePaymentMethodId) => {
@@ -19614,7 +19624,7 @@ function useSave({ onSaveSuccess, onSaveError, accountId, }) {
19614
19624
  const useShowPaymentDetailsState = (isOpen = false) => useState(isOpen);
19615
19625
  const [ShowPaymentDetailsProvider, useShowPaymentDetails] = createStateContext(useShowPaymentDetailsState);
19616
19626
 
19617
- const handleAllErrorFormats$1 = useAllErrorFormats$1();
19627
+ const handleAllErrorFormats$2 = useAllErrorFormats$1();
19618
19628
  const showErrorNotification$5 = useErrorNotification();
19619
19629
  // Contexts
19620
19630
  const [FormattedAmountDueProvider, useFormattedAmountDue] = createValueContext();
@@ -19660,7 +19670,7 @@ function PaymentProvider({ children, accountId, quote, invoice, onPaymentSuccess
19660
19670
  });
19661
19671
  setShowPaymentMethodForm(false);
19662
19672
  },
19663
- onSaveError: handleAllErrorFormats$1,
19673
+ onSaveError: handleAllErrorFormats$2,
19664
19674
  accountId,
19665
19675
  });
19666
19676
  const { save: saveStripe, isSaving: isSavingStripe } = useSave({
@@ -19674,7 +19684,7 @@ function PaymentProvider({ children, accountId, quote, invoice, onPaymentSuccess
19674
19684
  });
19675
19685
  setShowPaymentMethodForm(false);
19676
19686
  },
19677
- onSaveError: handleAllErrorFormats$1,
19687
+ onSaveError: handleAllErrorFormats$2,
19678
19688
  accountId,
19679
19689
  });
19680
19690
  const pluginName = (_c = (_b = (_a = selectedPlugin === null || selectedPlugin === void 0 ? void 0 : selectedPlugin.components) === null || _a === void 0 ? void 0 : _a.frontend) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.name;
@@ -19838,8 +19848,8 @@ const DemoPayExpiry = ({ autoFocus, onChange, placeholder, value, }) => {
19838
19848
  return (jsx("div", { className: "bunny-grow", children: jsx(Input, { name: "expiry", autoFocus: autoFocus, onKeyDown: onKeyPress, onKeyUp: onKeyPress, onChange: onNumberChange, value: formatCardExpiry(value), maxLength: 5, placeholder: placeholder || "MM/YY" }) }));
19839
19849
  };
19840
19850
 
19841
- const { Text: Text$y } = Typography;
19842
- const handleAllErrorFormats = useAllErrorFormats$1();
19851
+ const { Text: Text$z } = Typography;
19852
+ const handleAllErrorFormats$1 = useAllErrorFormats$1();
19843
19853
  const TEST_CARD = '4242424242424242';
19844
19854
  const DemoPayForm = () => {
19845
19855
  // Context
@@ -19856,7 +19866,7 @@ const DemoPayForm = () => {
19856
19866
  onPaymentFormSubmit(cardDetails);
19857
19867
  }
19858
19868
  catch (error) {
19859
- handleAllErrorFormats(error);
19869
+ handleAllErrorFormats$1(error);
19860
19870
  }
19861
19871
  }
19862
19872
  function validateCardDetails() {
@@ -19878,7 +19888,7 @@ const DemoPayForm = () => {
19878
19888
  const onCardCvcChange = (cvc) => {
19879
19889
  setCardDetails({ ...cardDetails, cvc });
19880
19890
  };
19881
- return (jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2", children: [jsxs(StyledInputs, { className: "bunny-flex bunny-flex-col bunny-gap-2", darkMode: darkMode !== null && darkMode !== void 0 ? darkMode : false, children: [jsx(DemoPayCardNumber, { onChange: onCardNumberChange, value: cardDetails.number }), jsxs("div", { className: "bunny-flex bunny-gap-2", children: [jsx(DemoPayExpiry, { onChange: onCardExpiryChange, value: cardDetails.expiry }), jsx(DemoPayCardCvc, { onChange: onCardCvcChange, value: cardDetails.cvc })] })] }), jsx(Text$y, { children: "DemoPay is for testing only." }), jsx(PaymentMethodFooter, { onSubmit: onSubmit })] }));
19891
+ return (jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2", children: [jsxs(StyledInputs, { className: "bunny-flex bunny-flex-col bunny-gap-2", darkMode: darkMode !== null && darkMode !== void 0 ? darkMode : false, children: [jsx(DemoPayCardNumber, { onChange: onCardNumberChange, value: cardDetails.number }), jsxs("div", { className: "bunny-flex bunny-gap-2", children: [jsx(DemoPayExpiry, { onChange: onCardExpiryChange, value: cardDetails.expiry }), jsx(DemoPayCardCvc, { onChange: onCardCvcChange, value: cardDetails.cvc })] })] }), jsx(Text$z, { children: "DemoPay is for testing only." }), jsx(PaymentMethodFooter, { onSubmit: onSubmit })] }));
19882
19892
  };
19883
19893
  const StyledInputs = defaultStyled.div `
19884
19894
  .ant-input {
@@ -19927,7 +19937,7 @@ const CardIcon = ({ className }) => {
19927
19937
  return (jsxs("svg", { className: className, width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsx("path", { d: "M15 3.75H3C2.17157 3.75 1.5 4.42157 1.5 5.25V12.75C1.5 13.5784 2.17157 14.25 3 14.25H15C15.8284 14.25 16.5 13.5784 16.5 12.75V5.25C16.5 4.42157 15.8284 3.75 15 3.75Z", stroke: SLATE_400, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }), jsx("path", { d: "M1.5 7.5H16.5", stroke: SLATE_400, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }));
19928
19938
  };
19929
19939
 
19930
- const { Text: Text$x } = Typography;
19940
+ const { Text: Text$y } = Typography;
19931
19941
  const PaymentMethodSelector = () => {
19932
19942
  const accountId = useAccountId();
19933
19943
  const { paymentPlugins } = usePaymentPlugins(accountId);
@@ -19941,7 +19951,7 @@ const PaymentOption = ({ selected, paymentPluginId, onClick, name, }) => {
19941
19951
  const isCard = name === null || name === void 0 ? void 0 : name.toLowerCase().includes('card');
19942
19952
  return (jsxs(PaymentOptionContainer, { "$brandColor": brandColor, "$selected": selected, className: `bunny-flex bunny-justify-between bunny-items-center bunny-cursor-pointer bunny-py-2 bunny-rounded bunny-border-solid ${darkMode
19943
19953
  ? `var(--row-background-dark) border-gray-500`
19944
- : 'bunny-bg-slate-50 bunny-border-slate-200'} bunny-border`, onClick: () => onClick(paymentPluginId), children: [jsxs("div", { className: "bunny-flex bunny-gap-2 bunny-items-center bunny-pl-4", children: [jsx(Checkbox, { checked: selected, className: darkMode ? 'border-gray-400' : '' }), jsx(Text$x, { children: name })] }), isAch ? (jsx(BankOutlined, { className: "bunny-pr-4" })) : isCard ? (jsx(CardIcon, { className: "bunny-pr-4" })) : (jsx(CardIcon, { className: "bunny-pr-4" }))] }));
19954
+ : 'bunny-bg-slate-50 bunny-border-slate-200'} bunny-border`, onClick: () => onClick(paymentPluginId), children: [jsxs("div", { className: "bunny-flex bunny-gap-2 bunny-items-center bunny-pl-4", children: [jsx(Checkbox, { checked: selected, className: darkMode ? 'border-gray-400' : '' }), jsx(Text$y, { children: name })] }), isAch ? (jsx(BankOutlined, { className: "bunny-pr-4" })) : isCard ? (jsx(CardIcon, { className: "bunny-pr-4" })) : (jsx(CardIcon, { className: "bunny-pr-4" }))] }));
19945
19955
  };
19946
19956
  const PaymentOptionContainer = defaultStyled.div `
19947
19957
  transition: border 0.3s ease;
@@ -19999,7 +20009,7 @@ const useAutoSetDefaultPaymentMethod = ({ handleSetDefault, setDefaultPaymentMet
19999
20009
  ]);
20000
20010
  };
20001
20011
 
20002
- const query$5 = t(`
20012
+ const query$7 = t(`
20003
20013
  query GetCurrentUserData {
20004
20014
  company {
20005
20015
  name
@@ -20022,7 +20032,7 @@ const query$5 = t(`
20022
20032
  `);
20023
20033
  const getCurrentUserData = async ({ token, apiHost }) => {
20024
20034
  var _a, _b, _c, _d, _e, _f, _g, _h;
20025
- const response = await execute(query$5, { apiHost, token }, {});
20035
+ const response = await execute(query$7, { apiHost, token }, {});
20026
20036
  return {
20027
20037
  authObjectName: (_a = response === null || response === void 0 ? void 0 : response.currentUser) === null || _a === void 0 ? void 0 : _a.authObjectName,
20028
20038
  account: (_b = response === null || response === void 0 ? void 0 : response.currentUser) === null || _b === void 0 ? void 0 : _b.account,
@@ -20190,6 +20200,8 @@ function PaymentFormContent({ onRemovePaymentMethod, onSetDefaultPaymentMethod,
20190
20200
  const { paymentMethods: maskedPaymentMethods, isLoading: isPaymentMethodLoading } = usePaymentMethod({ accountId });
20191
20201
  // Read fragments
20192
20202
  const paymentMethods = useMemo(() => maskedPaymentMethods === null || maskedPaymentMethods === void 0 ? void 0 : maskedPaymentMethods.map(paymentMethod => readFragment(PaymentForm_PaymentMethodsFragment, paymentMethod)), [maskedPaymentMethods]);
20203
+ // Derived state
20204
+ const hasPaymentMethods = (paymentMethods === null || paymentMethods === void 0 ? void 0 : paymentMethods.length) && (paymentMethods === null || paymentMethods === void 0 ? void 0 : paymentMethods.length) > 0;
20193
20205
  // Custom hooks
20194
20206
  const { setDefaultPaymentMethod: handleSetDefault, loading: setDefaultPaymentMethodLoading } = useSetDefaultPaymentMethod(message => {
20195
20207
  showErrorNotification$4(message, 'Error setting default payment method');
@@ -20228,7 +20240,7 @@ function PaymentFormContent({ onRemovePaymentMethod, onSetDefaultPaymentMethod,
20228
20240
  label: !showPaymentMethodForm ? (jsx("div", { className: "bunny-pt-2", children: jsx(Button, { onClick: handleClickAddPaymentMethod, type: "default", className: "bunny-w-full", id: "addPaymentMethod", children: "Add payment method" }) })) : null,
20229
20241
  children: (jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2 bunny-mt-2", children: [jsx(PaymentMethodSelector, {}), selectedPlugin && (jsx("div", { className: "bunny-flex bunny-flex-col", children: jsx(PaymentMethodDetails, {}) }))] })),
20230
20242
  },
20231
- ] }), formattedAmountDue !== undefined && !showPaymentMethodForm && (jsx("div", { className: "bunny-px-4", children: jsx(CheckoutFooter, {}) }))] })) : (jsx(Button, { style: { margin: '0 16px' }, loading: isPaying, onClick: () => onPaymentFormSubmit(), type: "primary", children: isPaying ? 'Processing...' : 'Complete Order' })) }));
20243
+ ] }), formattedAmountDue !== undefined && !showPaymentMethodForm && hasPaymentMethods ? (jsx("div", { className: "bunny-px-4", children: jsx(CheckoutFooter, {}) })) : null] })) : (jsx(Button, { style: { margin: '0 16px' }, loading: isPaying, onClick: () => onPaymentFormSubmit(), type: "primary", children: isPaying ? 'Processing...' : 'Complete Order' })) }));
20232
20244
  }
20233
20245
 
20234
20246
  function Invoice({ id, invoiceQuoteViewComponent, backButtonName, onBackButtonClick, onInvoiceDownloadError, onPaymentSuccess, shadow = 'shadow-md', className, hideDownloadButton = false, hidePaymentForm = false, onInvoiceLoaded, }) {
@@ -20286,7 +20298,7 @@ function ActualInvoice({ hidePaymentForm }) {
20286
20298
  return (jsx("div", { className: "bunny-invoice-container", children: jsxs("div", { className: `bunny-flex bunny-gap-6 ${isMobile ? 'bunny-flex-col bunny-w-full' : ''} ${className}`, children: [formattedInvoice.isLegacy ? (jsx("div", { className: "bunny-flex bunny-justify-center bunny-w-full", children: jsx(LegacyDocument, { documentUuid: formattedInvoice.uuid, documentType: "invoice" }) })) : (invoiceQuoteViewComponent || (jsx(InvoiceQuoteView, { html: formattedInvoice.html, formattedInvoice: formattedInvoice, backButtonName: backButtonName, onBackButtonClick: onBackButtonClick }))), isInvoicePayable && !hidePaymentForm && (jsx("div", { className: `bunny-w-full ${hideDownloadButton || formattedInvoice.isLegacy ? '' : 'pt-12'}`, children: jsx(PaymentForm, { onPaymentSuccess: handlePaymentSuccess, invoice: formattedInvoice }) }))] }) }));
20287
20299
  }
20288
20300
 
20289
- const query$4 = t(`
20301
+ const query$6 = t(`
20290
20302
  query formattedQuote($id: ID) {
20291
20303
  formattedQuote(id: $id) {
20292
20304
  quote {
@@ -20430,7 +20442,7 @@ const query$4 = t(`
20430
20442
  }
20431
20443
  `);
20432
20444
  const getFormattedQuote = async ({ token, apiHost, id, }) => {
20433
- const response = await execute(query$4, { apiHost, token }, { id });
20445
+ const response = await execute(query$6, { apiHost, token }, { id });
20434
20446
  return response === null || response === void 0 ? void 0 : response.formattedQuote;
20435
20447
  };
20436
20448
 
@@ -20479,6 +20491,7 @@ const useSigningPlugins = ({ apiHost, token, }) => {
20479
20491
  return filterSigningPlugins(plugins.data);
20480
20492
  };
20481
20493
 
20494
+ const handleAllErrorFormats = useAllErrorFormats$1();
20482
20495
  const QUOTE_ACCEPT = `
20483
20496
  mutation quoteAccept($name: String!, $title: String!, $poNumber: String, $taxNumber: String, $quoteId: ID) {
20484
20497
  quoteAccept(name: $name, title: $title, poNumber: $poNumber, taxNumber: $taxNumber, quoteId: $quoteId) {
@@ -20532,8 +20545,10 @@ const useSendAcceptQuote = ({ quoteId, apiHost, token, onQuoteAccepted, }) => {
20532
20545
  quoteId,
20533
20546
  };
20534
20547
  graphQLMutation(mutation, variables, (rsp) => {
20535
- if (rsp.errors)
20536
- console.log('rsp.errors', rsp.errors);
20548
+ if (rsp.errors) {
20549
+ handleAllErrorFormats(rsp.errors[0].message);
20550
+ setIsAccepting(false);
20551
+ }
20537
20552
  else {
20538
20553
  const { redirectUri, message, pluginShortName } = rsp.data.quoteSigningUrlCreate;
20539
20554
  if (redirectUri) {
@@ -20684,7 +20699,7 @@ const PandadocPollingModal = ({ isVisible, setVisible, id }) => {
20684
20699
  };
20685
20700
  graphQLMutation(mutation, variables, (rsp) => {
20686
20701
  if (rsp.errors)
20687
- handleAllErrorFormats(rsp.errors);
20702
+ handleAllErrorFormats(rsp.errors[0].message);
20688
20703
  else if (rsp.data.quotePollSigningUrl.status === 'document.sent') {
20689
20704
  setVisible(false);
20690
20705
  window.location.href = rsp.data.quotePollSigningUrl.redirectUri;
@@ -20766,14 +20781,14 @@ const AcceptQuoteModal = ({ acceptBoxVisible, formattedQuote, sendAccept, setAcc
20766
20781
  }, open: acceptBoxVisible, title: (signingPlugins === null || signingPlugins === void 0 ? void 0 : signingPlugins.length) ? 'Start signing' : 'Accept quote', width: 400, children: jsxs(Form, { className: "bunny-flex bunny-flex-col bunny-gap-2", form: form, layout: "vertical", children: [jsx(Form.Item, { label: "Your name", name: "name", rules: createRules(true, 'Your name'), children: jsx(Input, { autoFocus: true, ref: firstInputRef }) }), jsx(Form.Item, { label: "Your job title", name: "title", rules: createRules(true, 'Your job title'), children: jsx(Input, {}) }), jsx(Form.Item, { label: "Purchase order number", name: "poNumber", rules: createRules(poNumberRequired, 'Purchase order number'), children: jsx(Input, {}) }), taxNumberRequired && (jsx(Form.Item, { name: "taxNumber", label: taxNumberLabel, rules: createRules(taxNumberRequired, taxNumberLabel), children: jsx(Input, {}) }))] }) }));
20767
20782
  };
20768
20783
 
20769
- const { Title: Title$2, Text: Text$w } = Typography;
20784
+ const { Title: Title$2, Text: Text$x } = Typography;
20770
20785
  const showSuccessNotification$2 = useSuccessNotification();
20771
20786
  const PaymentHoldModal = ({ visible, setVisible, quote, }) => {
20772
20787
  const queryClient = useQueryClient();
20773
20788
  const token = useToken();
20774
20789
  return (jsxs(StyledModal$2, { centered: true, onCancel: () => {
20775
20790
  setVisible(false);
20776
- }, footer: null, open: visible, width: 600, children: [jsxs("div", { className: "bunny-mt-5 bunny-pb-4 bunny-mx-4", children: [jsx(Title$2, { className: "bunny-mt-0", level: 5, children: "Pay and sign" }), jsxs(Text$w, { className: "bunny-bt-2 bunny-text-sm/5 bunny-text-gray-500", children: ["To accept this quote, approve a payment hold for", ' ', formatCurrency$1(quote.amount, quote.currency), ". This amount will be charged to your payment method once the quote is signed."] })] }), jsx("div", { className: "bunny-mb-3", children: jsx(PaymentForm, { quote: {
20791
+ }, footer: null, open: visible, width: 600, children: [jsxs("div", { className: "bunny-mt-5 bunny-pb-4 bunny-mx-4", children: [jsx(Title$2, { className: "bunny-mt-0", level: 5, children: "Pay and sign" }), jsxs(Text$x, { className: "bunny-bt-2 bunny-text-sm/5 bunny-text-gray-500", children: ["To accept this quote, approve a payment hold for", ' ', formatCurrency$1(quote.amount, quote.currency), ". This amount will be charged to your payment method once the quote is signed."] })] }), jsx("div", { className: "bunny-mb-3", children: jsx(PaymentForm, { quote: {
20777
20792
  amount: quote.amount,
20778
20793
  currencyId: quote.currency,
20779
20794
  id: quote.quote.id,
@@ -20823,7 +20838,7 @@ const StyledModal$2 = (props) => {
20823
20838
  return jsx(ModalOverrideBrandStylings, { closable: false, ...props });
20824
20839
  };
20825
20840
 
20826
- const { Text: Text$v } = Typography;
20841
+ const { Text: Text$w } = Typography;
20827
20842
  defaultStyled.div `
20828
20843
  Text {
20829
20844
  width: 100%;
@@ -20915,7 +20930,7 @@ function QuoteButtons({ isAccepted, formattedQuote, isMobile, hideDownloadButton
20915
20930
  const signingPlugins = useSigningPlugins({ apiHost, token });
20916
20931
  return (jsxs("div", { className: "flex flex-row justify-end items-center gap-4", id: "acceptance", style: {
20917
20932
  color: secondaryColor,
20918
- }, children: [isAccepted && formattedQuote.acceptedAt ? (jsx(Text$v, { children: `Quote was accepted by ${formattedQuote.acceptedByName} on ${formatDate(formattedQuote.acceptedAt)}` })) : null, (!isMobile || !isAccepted) && (jsxs("div", { className: isMobile ? 'flex w-full justify-end gap-2' : 'flex items-center justify-end gap-2', children: [paymentHold ? (jsx(PaymentHoldDisplay, { paymentHold: paymentHold, currency: formattedQuote.currency, amount: formattedQuote.amount })) : null, !isMobile && !hideDownloadButton ? (jsx(Button, { icon: jsx(DownloadOutlined, {}), onClick: () => downloadFile(apiHost + '/api/pdf/quote', token), children: "Download" })) : null, shouldDoPaymentHold && !paymentHoldCompleted ? (jsx(Button, { disabled: isExpired, onClick: () => setPaymentHoldModalVisible(true), type: "primary", children: "Pay and sign" })) : (jsx(Fragment, { children: !isAccepted ? (jsx(Button, { disabled: isExpired || isAccepting, onClick: handleClickAccept, type: "primary", children: isExpired
20933
+ }, children: [isAccepted && formattedQuote.acceptedAt ? (jsx(Text$w, { children: `Quote was accepted by ${formattedQuote.acceptedByName} on ${formatDate(formattedQuote.acceptedAt)}` })) : null, (!isMobile || !isAccepted) && (jsxs("div", { className: isMobile ? 'flex w-full justify-end gap-2' : 'flex items-center justify-end gap-2', children: [paymentHold ? (jsx(PaymentHoldDisplay, { paymentHold: paymentHold, currency: formattedQuote.currency, amount: formattedQuote.amount })) : null, !isMobile && !hideDownloadButton ? (jsx(Button, { icon: jsx(DownloadOutlined, {}), onClick: () => downloadFile(apiHost + '/api/pdf/quote', token), children: "Download" })) : null, shouldDoPaymentHold && !paymentHoldCompleted ? (jsx(Button, { disabled: isExpired, onClick: () => setPaymentHoldModalVisible(true), type: "primary", children: "Pay and sign" })) : (jsx(Fragment, { children: !isAccepted ? (jsx(Button, { disabled: isExpired || isAccepting, onClick: handleClickAccept, type: "primary", children: isExpired
20919
20934
  ? 'Quote is expired'
20920
20935
  : (signingPlugins === null || signingPlugins === void 0 ? void 0 : signingPlugins.length)
20921
20936
  ? 'Start signing'
@@ -21036,9 +21051,9 @@ const getColor = (state) => {
21036
21051
  }
21037
21052
  };
21038
21053
 
21039
- const { Text: Text$u } = Typography;
21054
+ const { Text: Text$v } = Typography;
21040
21055
  const TransactionDate = ({ date }) => {
21041
- return jsx(Text$u, { className: "bunny-text-sm", children: formatDate(date) });
21056
+ return jsx(Text$v, { className: "bunny-text-sm", children: formatDate(date) });
21042
21057
  };
21043
21058
 
21044
21059
  const ArrowDownToLine = ({ className, color = SLATE_600, }) => {
@@ -21082,13 +21097,13 @@ const TransactionGridCell = defaultStyled.div.withConfig({
21082
21097
  min-width: 48px;
21083
21098
  `;
21084
21099
 
21085
- const { Text: Text$t } = Typography;
21100
+ const { Text: Text$u } = Typography;
21086
21101
  const TransactionsEmptyState = () => {
21087
21102
  const { noTransactionsMessage } = useContext(TransactionsListContext);
21088
- return (jsx(Text$t, { className: "bunny-flex bunny-justify-center bunny-p-4 bunny-text-base", children: noTransactionsMessage || 'There are no transactions' }));
21103
+ return (jsx(Text$u, { className: "bunny-flex bunny-justify-center bunny-p-4 bunny-text-base", children: noTransactionsMessage || 'There are no transactions' }));
21089
21104
  };
21090
21105
 
21091
- const { Text: Text$s } = Typography;
21106
+ const { Text: Text$t } = Typography;
21092
21107
  const isInvoice = (transaction) => {
21093
21108
  return transaction.kind === 'INVOICE';
21094
21109
  };
@@ -21096,7 +21111,7 @@ const TransactionRowTitle = ({ transaction }) => {
21096
21111
  if (!isInvoice(transaction)) {
21097
21112
  return jsx(Fragment, {});
21098
21113
  }
21099
- return (jsx(Text$s, { className: "bunny-text-slate-400", style: { fontSize: '11px' }, children: transaction.transactionable.number }));
21114
+ return (jsx(Text$t, { className: "bunny-text-slate-400", style: { fontSize: '11px' }, children: transaction.transactionable.number }));
21100
21115
  };
21101
21116
 
21102
21117
  function transactionDateToDisplay(transaction, transactionDateType) {
@@ -21114,7 +21129,7 @@ function transactionDateToDisplay(transaction, transactionDateType) {
21114
21129
  }
21115
21130
  }
21116
21131
 
21117
- const { Text: Text$r } = Typography;
21132
+ const { Text: Text$s } = Typography;
21118
21133
  const TransactionsListDesktop = ({ transactions, onTransactionClick, }) => {
21119
21134
  const { columns, transactionDateType } = useContext(TransactionsListContext);
21120
21135
  const { apiHost, darkMode } = useContext(BunnyContext);
@@ -21142,11 +21157,11 @@ const TransactionsListDesktop = ({ transactions, onTransactionClick, }) => {
21142
21157
  !showState &&
21143
21158
  !showAmount &&
21144
21159
  !showDownload &&
21145
- !showAccountName && (jsx(TransactionGridCell, { children: jsx(Text$r, { children: "No columns selected" }) })), showDate && (jsx(TransactionGridCell, { right: false, children: jsx(TransactionDate, { date: transactionDateToDisplay(transaction, transactionDateType) }) })), showTitle && (jsx(Fragment, { children: jsxs(TransactionGridCell, { right: false, className: "bunny-flex bunny-items-center bunny-gap-2", children: [jsx(Text$r, { children: lodashExports.capitalize(transaction.kind.toLowerCase()) }), jsx(TransactionRowTitle, { transaction: transaction })] }) })), showAccountName && (jsx(TransactionGridCell, { right: false, children: jsx(Text$r, { children: (_a = transaction.account) === null || _a === void 0 ? void 0 : _a.name }) })), !showDate && !showTitle && !showAccountName && jsx(TransactionGridCell, { right: false }), showDownload && (jsx(TransactionGridCell, { children: jsx(TransactionDownload, { transaction: transaction, token: token, apiHost: apiHost }) })), showState ? (jsx(TransactionGridCell, { right: false, children: jsx(StateTag, { state: transaction.state }) })) : null, showAmount && (jsx(TransactionGridCell, { right: true, children: jsx(Text$r, { children: formatCurrency$1(((_b = transaction === null || transaction === void 0 ? void 0 : transaction.transactionable) === null || _b === void 0 ? void 0 : _b.amount) || transaction.amount, transaction.currencyId) }) }))] }, index));
21160
+ !showAccountName && (jsx(TransactionGridCell, { children: jsx(Text$s, { children: "No columns selected" }) })), showDate && (jsx(TransactionGridCell, { right: false, children: jsx(TransactionDate, { date: transactionDateToDisplay(transaction, transactionDateType) }) })), showTitle && (jsx(Fragment, { children: jsxs(TransactionGridCell, { right: false, className: "bunny-flex bunny-items-center bunny-gap-2", children: [jsx(Text$s, { children: lodashExports.capitalize(transaction.kind.toLowerCase()) }), jsx(TransactionRowTitle, { transaction: transaction })] }) })), showAccountName && (jsx(TransactionGridCell, { right: false, children: jsx(Text$s, { children: (_a = transaction.account) === null || _a === void 0 ? void 0 : _a.name }) })), !showDate && !showTitle && !showAccountName && jsx(TransactionGridCell, { right: false }), showDownload && (jsx(TransactionGridCell, { children: jsx(TransactionDownload, { transaction: transaction, token: token, apiHost: apiHost }) })), showState ? (jsx(TransactionGridCell, { right: false, children: jsx(StateTag, { state: transaction.state }) })) : null, showAmount && (jsx(TransactionGridCell, { right: true, children: jsx(Text$s, { children: formatCurrency$1(((_b = transaction === null || transaction === void 0 ? void 0 : transaction.transactionable) === null || _b === void 0 ? void 0 : _b.amount) || transaction.amount, transaction.currencyId) }) }))] }, index));
21146
21161
  }) }));
21147
21162
  };
21148
21163
 
21149
- const { Text: Text$q } = Typography;
21164
+ const { Text: Text$r } = Typography;
21150
21165
  const TransactionsListMobile = ({ transactions, onTransactionClick, }) => {
21151
21166
  const { columns, transactionDateType } = useContext(TransactionsListContext);
21152
21167
  const { apiHost, darkMode } = useContext(BunnyContext);
@@ -21168,11 +21183,11 @@ const TransactionsListMobile = ({ transactions, onTransactionClick, }) => {
21168
21183
  backgroundColor: index % 2 === 0
21169
21184
  ? `var(--row-background${darkMode ? '-dark' : ''})`
21170
21185
  : `var(--row-background-alternate${darkMode ? '-dark' : ''})`,
21171
- }, children: [jsx(TransactionGridCell, { children: jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2", children: [(showTitle || showState) && (jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-2", children: [showTitle && (jsxs(Fragment, { children: [jsx(Text$q, { children: lodashExports.capitalize(transaction.kind.toLowerCase()) }), jsx(TransactionRowTitle, { transaction: transaction })] })), showState && jsx(StateTag, { state: transaction.state })] })), jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-2", children: [showAccountName && jsx(Text$q, { children: (_a = transaction.account) === null || _a === void 0 ? void 0 : _a.name }), showAccountName && showDate && jsx(Text$q, { children: "\u00B7" }), showDate && (jsx(TransactionDate, { date: transactionDateToDisplay(transaction, transactionDateType) })), showDate && showAmount && jsx(Text$q, { children: "\u00B7" }), showAmount && (jsx(Text$q, { children: formatCurrency$1(transaction.transactionable.amount || transaction.amount, transaction.currencyId) }))] })] }) }), showDownload && (jsx(TransactionGridCell, { right: true, children: jsx(TransactionDownload, { transaction: transaction, token: token, apiHost: apiHost }) }))] }, index));
21186
+ }, children: [jsx(TransactionGridCell, { children: jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2", children: [(showTitle || showState) && (jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-2", children: [showTitle && (jsxs(Fragment, { children: [jsx(Text$r, { children: lodashExports.capitalize(transaction.kind.toLowerCase()) }), jsx(TransactionRowTitle, { transaction: transaction })] })), showState && jsx(StateTag, { state: transaction.state })] })), jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-2", children: [showAccountName && jsx(Text$r, { children: (_a = transaction.account) === null || _a === void 0 ? void 0 : _a.name }), showAccountName && showDate && jsx(Text$r, { children: "\u00B7" }), showDate && (jsx(TransactionDate, { date: transactionDateToDisplay(transaction, transactionDateType) })), showDate && showAmount && jsx(Text$r, { children: "\u00B7" }), showAmount && (jsx(Text$r, { children: formatCurrency$1(transaction.transactionable.amount || transaction.amount, transaction.currencyId) }))] })] }) }), showDownload && (jsx(TransactionGridCell, { right: true, children: jsx(TransactionDownload, { transaction: transaction, token: token, apiHost: apiHost }) }))] }, index));
21172
21187
  }) }));
21173
21188
  };
21174
21189
 
21175
- const { Text: Text$p } = Typography;
21190
+ const { Text: Text$q } = Typography;
21176
21191
  const DISPLAY_WIDTH = 1200;
21177
21192
  function Transactions({ transactionComponent, showSearchBar = true, showTitle = true, title = 'Past transactions', columns = ['date', 'title', 'state', 'amount', 'download'], className, shadow = 'shadow-md', searchBarClassName, useModal = false, onTransactionClick, suppressTransactionDisplay = false, kindsToShow = [
21178
21193
  TransactionKind.INVOICE,
@@ -21276,7 +21291,7 @@ function TransactionsDisplay({ transactions, onSearchValueChanged, search, }) {
21276
21291
  onTransactionDisplayClose === null || onTransactionDisplayClose === void 0 ? void 0 : onTransactionDisplayClose(selectedTransaction);
21277
21292
  setDrawerOpen(false);
21278
21293
  }
21279
- return (jsxs("div", { style: style, children: [jsxs("div", { className: `bunny-flex bunny-flex-col bunny-w-full bunny-shadow-padding-xb bunny-gap-2 ${isMobile ? 'bunny-overflow-hidden' : ''} ${className}`, children: [showTitle || showSearchBar ? (jsxs("div", { className: `bunny-flex ${isMobile ? 'bunny-flex-col bunny-gap-1' : 'bunny-flex-row bunny-items-center'} bunny-justify-between`, children: [showTitle ? (jsx(Text$p, { className: "bunny-shrink-0 bunny-font-medium", style: { color: darkMode ? undefined : secondaryColor }, children: title })) : (jsx("div", {}) // Empty div so justify-between works
21294
+ return (jsxs("div", { style: style, children: [jsxs("div", { className: `bunny-flex bunny-flex-col bunny-w-full bunny-shadow-padding-xb bunny-gap-2 ${isMobile ? 'bunny-overflow-hidden' : ''} ${className}`, children: [showTitle || showSearchBar ? (jsxs("div", { className: `bunny-flex ${isMobile ? 'bunny-flex-col bunny-gap-1' : 'bunny-flex-row bunny-items-center'} bunny-justify-between`, children: [showTitle ? (jsx(Text$q, { className: "bunny-shrink-0 bunny-font-medium", style: { color: darkMode ? undefined : secondaryColor }, children: title })) : (jsx("div", {}) // Empty div so justify-between works
21280
21295
  ), showSearchBar && (jsx("div", { className: `${isMobile ? 'bunny-w-full' : ''}`, children: jsx(Input, { className: searchBarClassName ? searchBarClassName : '', onChange: e => {
21281
21296
  const value = e.target.value;
21282
21297
  // Allow empty string, numbers, and decimal point
@@ -21399,7 +21414,7 @@ const useHasTaxPlugin = ({ apiHost, token, }) => {
21399
21414
  return Boolean(plugins === null || plugins === void 0 ? void 0 : plugins.some((plugin) => plugin.type === "taxation"));
21400
21415
  };
21401
21416
 
21402
- const MUTATION$7 = () => `
21417
+ const MUTATION$6 = () => `
21403
21418
  mutation AccountSignup (
21404
21419
  $pluginId: String!,
21405
21420
  $paymentMethodId: String,
@@ -21473,7 +21488,7 @@ const accountSignup = async ({ token, apiHost, accountId, quoteId, paymentToken,
21473
21488
  priceListCode,
21474
21489
  };
21475
21490
  const response = await gqlRequest({
21476
- query: MUTATION$7(),
21491
+ query: MUTATION$6(),
21477
21492
  token,
21478
21493
  vars,
21479
21494
  apiHost,
@@ -21484,7 +21499,7 @@ const accountSignup = async ({ token, apiHost, accountId, quoteId, paymentToken,
21484
21499
  return response === null || response === void 0 ? void 0 : response.accountSignup;
21485
21500
  };
21486
21501
 
21487
- const MUTATION$6 = () => `
21502
+ const MUTATION$5 = () => `
21488
21503
  mutation QuoteAccountSignup (
21489
21504
  $accountName: String!,
21490
21505
  $billingContact: ContactAttributes!,
@@ -21561,7 +21576,7 @@ const quoteAccountSignup = async ({ token, apiHost, priceListCode, accountName,
21561
21576
  billingDetails,
21562
21577
  };
21563
21578
  const response = await gqlRequest({
21564
- query: MUTATION$6(),
21579
+ query: MUTATION$5(),
21565
21580
  token,
21566
21581
  vars,
21567
21582
  apiHost,
@@ -21639,7 +21654,7 @@ const QUOTE_RECALCULATE_TAXES = `
21639
21654
  }
21640
21655
  }
21641
21656
  `;
21642
- const quoteRecalculateTaxes = async ({ quoteId, apiHost, token, }) => {
21657
+ const quoteRecalculateTaxes$2 = async ({ quoteId, apiHost, token, }) => {
21643
21658
  var _a, _b;
21644
21659
  const vars = { id: quoteId };
21645
21660
  const response = await gqlRequest({
@@ -21654,7 +21669,7 @@ const quoteRecalculateTaxes = async ({ quoteId, apiHost, token, }) => {
21654
21669
  return (_b = response.quoteRecalculateTaxes) === null || _b === void 0 ? void 0 : _b.quote;
21655
21670
  };
21656
21671
 
21657
- const MUTATION$5 = () => `
21672
+ const MUTATION$4 = () => `
21658
21673
  query PriceList($code: String!) {
21659
21674
  priceList (code: $code) {
21660
21675
  basePrice
@@ -21679,7 +21694,7 @@ query PriceList($code: String!) {
21679
21694
  }`;
21680
21695
  const getPriceList = async ({ token, code, apiHost, }) => {
21681
21696
  const response = await gqlRequest({
21682
- query: MUTATION$5(),
21697
+ query: MUTATION$4(),
21683
21698
  token,
21684
21699
  vars: { code },
21685
21700
  apiHost,
@@ -21689,16 +21704,60 @@ const getPriceList = async ({ token, code, apiHost, }) => {
21689
21704
 
21690
21705
  const SubscriptionsContext = createContext({});
21691
21706
 
21707
+ const QuoteContext = createContext({});
21708
+
21692
21709
  const graphql = initGraphQLTada();
21693
21710
 
21694
- function canEditChargeQuantity(charge) {
21695
- if (!charge)
21696
- return false;
21697
- if (charge.chargeType === graphql.scalar('ChargeType', 'USAGE'))
21698
- return false;
21699
- if (charge.pricingModel === graphql.scalar('PricingModel', 'FLAT'))
21700
- return false;
21701
- return true;
21711
+ const periodMonthsConverter = (period) => {
21712
+ if (period === 0)
21713
+ return graphql.scalar('BillingPeriod', 'ONCE');
21714
+ else if (period === 1)
21715
+ return graphql.scalar('BillingPeriod', 'MONTHLY');
21716
+ else if (period === 3)
21717
+ return graphql.scalar('BillingPeriod', 'QUARTERLY');
21718
+ else if (period === 6)
21719
+ return graphql.scalar('BillingPeriod', 'SEMI_ANNUAL');
21720
+ else if (period === 12)
21721
+ return graphql.scalar('BillingPeriod', 'ANNUAL');
21722
+ else
21723
+ return null;
21724
+ };
21725
+ const billingPeriodConverter = (period) => {
21726
+ if (period === graphql.scalar('BillingPeriod', 'ONCE'))
21727
+ return 0;
21728
+ else if (period === graphql.scalar('BillingPeriod', 'MONTHLY'))
21729
+ return 1;
21730
+ else if (period === graphql.scalar('BillingPeriod', 'QUARTERLY'))
21731
+ return 3;
21732
+ else if (period === graphql.scalar('BillingPeriod', 'SEMI_ANNUAL'))
21733
+ return 6;
21734
+ else
21735
+ return 12;
21736
+ };
21737
+
21738
+ function getAddonsForBillingPeriod(billingPeriod, addonPlans) {
21739
+ const flattenedPriceLists = addonPlans.flatMap(addonPlan => addonPlan.priceLists);
21740
+ return flattenedPriceLists.filter(priceList => priceList.periodMonths === billingPeriodConverter(billingPeriod));
21741
+ }
21742
+
21743
+ const hasUnpurchasedAddonPriceLists_PlanFragment = t(`
21744
+ fragment hasUnpurchasedAddonPriceLists_PlanFragment on Plan {
21745
+ priceLists {
21746
+ id
21747
+ isVisible
21748
+ periodMonths
21749
+ }
21750
+ }
21751
+ `);
21752
+ function hasUnpurchasedAddonPriceLists(maskedPriceListAddonPlans, currentSubscription, billingPeriod) {
21753
+ // Read fragments
21754
+ const priceListAddonPlans = maskedPriceListAddonPlans.map(maskedAddonPlan => readFragment(hasUnpurchasedAddonPriceLists_PlanFragment, maskedAddonPlan));
21755
+ const addonPriceLists = getAddonsForBillingPeriod(billingPeriod, priceListAddonPlans).filter(priceList => priceList.isVisible);
21756
+ const unpurchasedAddonPriceLists = addonPriceLists === null || addonPriceLists === void 0 ? void 0 : addonPriceLists.filter(addonPriceList => {
21757
+ var _a;
21758
+ return !((_a = currentSubscription === null || currentSubscription === void 0 ? void 0 : currentSubscription.addonSubscriptions) === null || _a === void 0 ? void 0 : _a.some(addonSubscription => addonSubscription.priceList.id === addonPriceList.id));
21759
+ });
21760
+ return unpurchasedAddonPriceLists.length > 0;
21702
21761
  }
21703
21762
 
21704
21763
  function hasUnpurchasedFeatureAddons(priceList, currentSubscription) {
@@ -21725,775 +21784,764 @@ function featureAddonSwitchTestId(addonName) {
21725
21784
  return `feature-addon-switch-${name}`;
21726
21785
  }
21727
21786
 
21728
- const MUTATION$4 = `{
21729
- currentUser {
21730
- taxationRequiredAccountFields
21731
- }
21732
- }`;
21733
- const getTaxationRequiredAccountFields = async ({ apiHost, token, }) => {
21734
- var _a, _b;
21735
- const response = await gqlRequest({
21736
- query: MUTATION$4,
21737
- token,
21738
- apiHost: apiHost,
21739
- });
21740
- 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
21741
- ? response.currentUser.taxationRequiredAccountFields
21742
- : null;
21787
+ const canSubscriptionUpgradeFromTrial = (subscription) => {
21788
+ var _a;
21789
+ return (((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL') &&
21790
+ subscription.plan.selfServiceBuy) ||
21791
+ false;
21743
21792
  };
21744
-
21745
- const BunnyFooterIcon = ({ color }) => {
21746
- return (jsxs("svg", { width: "45", height: "15", viewBox: "0 0 39 13", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsxs("g", { clipPath: "url(#clip0_6_851)", children: [jsx("path", { className: "bunny-icon-path", d: "M14.5898 7.19708C14.5898 9.35053 13.0926 10.325 11.2495 10.325C9.39955 10.325 7.90234 9.35001 7.90234 7.18967V3.26221H10.1125V7.00052C10.1125 7.87719 10.5855 8.27725 11.2495 8.27725C11.9061 8.27725 12.3865 7.87719 12.3865 7.00052V3.26221H14.5898V7.19708Z", fill: color }), jsx("path", { className: "bunny-icon-path", d: "M31.8943 12.9625H29.4793L31.8523 8.62816L28.9355 3.26221H31.4708L33.0457 6.35524L34.5924 3.26221H37.0075L31.8943 12.9625Z", fill: color }), jsx("path", { className: "bunny-icon-path", d: "M15.1602 5.96827C15.1602 3.8148 16.6574 2.84033 18.5005 2.84033C20.3504 2.84033 21.8476 3.81533 21.8476 5.97568V10.1473H19.6374V6.16483C19.6374 5.28815 19.1645 4.8881 18.5005 4.8881C17.8439 4.8881 17.3634 5.28815 17.3634 6.16483V10.1473H15.1602V5.96827Z", fill: color }), jsx("path", { className: "bunny-icon-path", d: "M22.4316 5.96827C22.4316 3.8148 23.9289 2.84033 25.7719 2.84033C27.6219 2.84033 29.1191 3.81533 29.1191 5.97568V10.1473H26.9089V6.16483C26.9089 5.28815 26.4359 4.8881 25.7719 4.8881C25.1154 4.8881 24.6349 5.28815 24.6349 6.16483V10.1473H22.4316V5.96827Z", fill: color }), jsx("path", { className: "bunny-icon-path", d: "M7.40511 6.68957C7.40511 8.7236 6.02815 10.3227 4.17816 10.3227C3.23907 10.3227 2.61071 9.94378 2.19358 9.40371V10.1404H0.0605469V0.0405273H2.26381V3.91939C2.68041 3.42158 3.28802 3.07069 4.17763 3.07069C6.02759 3.07069 7.40511 4.66981 7.40511 6.68957ZM2.17229 6.69642C2.17229 7.60802 2.77937 8.2744 3.64823 8.2744C4.53783 8.2744 5.13107 7.59372 5.13107 6.69642C5.13107 5.79912 4.53783 5.11844 3.64823 5.11844C2.77937 5.11844 2.17229 5.78482 2.17229 6.69642Z", fill: color }), jsx("path", { className: "bunny-icon-path", d: "M38.966 8.94801C38.966 9.76181 38.2668 10.4631 37.4618 10.4631C36.6499 10.4631 35.9434 9.76181 35.9434 8.94801C35.9434 8.14846 36.6494 7.46094 37.4618 7.46094C38.2668 7.46094 38.966 8.14846 38.966 8.94801Z", fill: color })] }), jsx("defs", { children: jsx("clipPath", { id: "clip0_6_851", children: jsx("rect", { width: "39", height: "13", fill: "white" }) }) })] }));
21793
+ const canSubscriptionUpgradeFromTrialExpired = (subscription) => {
21794
+ var _a;
21795
+ return (((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED') &&
21796
+ subscription.plan.selfServiceBuy) ||
21797
+ false;
21747
21798
  };
21748
-
21749
- const { Text: Text$o } = Typography;
21750
- const Footer = ({ className }) => {
21751
- const token = useToken();
21752
- const { currentUser } = useCurrentUserData(token);
21753
- const { privacyUrl, termsUrl } = currentUser;
21754
- const isMobile = useIsMobile$1();
21755
- return (jsxs("div", { className: `bunny-flex bunny-items-center bunny-justify-between bunny-shrink-0 ${isMobile ? 'bunny-flex-col bunny-gap-2' : ''} ${className}`, children: [(termsUrl || privacyUrl) && (jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-3", children: [termsUrl && (jsx(StyedLink, { className: "bunny-text-xs bunny-text-slate-400", href: termsUrl, rel: "noopener noreferrer", target: "_blank", type: "text", children: "Terms" })), privacyUrl && (jsx(StyedLink, { className: "bunny-text-xs bunny-text-slate-400", href: privacyUrl, rel: "noopener noreferrer", target: "_blank", type: "text", children: "Privacy" }))] })), jsx(BunnyMarketingLink, {})] }));
21799
+ const isSubscriptionNotActive = (subscription) => {
21800
+ var _a, _b, _c;
21801
+ return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'EXPIRED') ||
21802
+ ((_b = subscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === t.scalar('SubscriptionState', 'CANCELED') ||
21803
+ ((_c = subscription.state) === null || _c === void 0 ? void 0 : _c.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED');
21756
21804
  };
21757
- const BunnyMarketingLink = () => {
21758
- const [isHovered, setIsHovered] = useState(false);
21759
- const isMobile = useIsMobile$1();
21760
- return (jsx("div", { className: `bunny-flex bunny-items-end bunny-justify-end ${isMobile ? '' : 'grow'}`, children: jsx(StyledBunnyLink, { className: "bunny-flex bunny-items-end bunny-justify-end bunny-text-slate-400", href: "https://bunny.com/", rel: "noopener noreferrer", target: "_blank", children: jsxs("div", { className: "bunny-flex bunny-items-center", onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: [jsx(Text$o, { className: "bunny-text-slate-400", children: "Powered by\u00A0" }), jsx("div", { style: { paddingTop: '5px' }, children: jsx(BunnyFooterIcon, { color: isHovered ? PRIMARY_COLOR : SLATE_400 }) })] }) }) }));
21805
+ const isSubscriptionActiveOrPending = (subscription) => {
21806
+ var _a, _b;
21807
+ return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'ACTIVE') ||
21808
+ ((_b = subscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === t.scalar('SubscriptionState', 'PENDING');
21761
21809
  };
21762
- const StyedLink = styled.a `
21763
- color: ${SLATE_400};
21764
- transition: color 0.3s;
21765
- &:hover {
21766
- color: ${SLATE_500};
21767
- }
21768
- text-decoration: none;
21769
- `;
21770
- const StyledBunnyLink = styled(StyedLink) `
21771
- &:hover {
21772
- color: ${PRIMARY_COLOR} !important;
21773
- }
21774
- `;
21775
-
21776
- const MUTATION$3 = `mutation quoteChangeAddCoupon($couponCode: String!, $quoteChangeId: ID!) {
21777
- quoteChangeAddCoupon(couponCode: $couponCode, quoteChangeId: $quoteChangeId) {
21778
- quoteChange {
21779
- id
21780
- charges {
21781
- id
21782
- amount
21783
- couponId
21784
- }
21785
- }
21786
- }
21787
- }`;
21788
- const quoteChangeAddCoupon = async ({ quoteChangeId, couponCode, token, apiHost, }) => {
21810
+ const isSubscriptionTrial = (subscription) => { var _a; return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL'); };
21811
+ const isSubscriptionTrialExpired = (subscription) => { var _a; return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED'); };
21812
+ // Helper function to check if charge is a discount
21813
+ const isDiscount$1 = (kind) => kind === QuoteChangeKind.DISCOUNT || kind === QuoteChangeKind.FREE_PERIOD_DISCOUNT;
21814
+ const hasPriceTiers = (charge) => {
21789
21815
  var _a;
21790
- const vars = { couponCode, quoteChangeId };
21791
- const response = await gqlRequest({
21792
- query: MUTATION$3,
21793
- token,
21794
- vars,
21795
- apiHost,
21796
- });
21797
- const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteAddCoupon) === null || _a === void 0 ? void 0 : _a.errors;
21798
- if (errors)
21799
- throw errors;
21800
- return response.quote;
21816
+ return Boolean((_a = charge === null || charge === void 0 ? void 0 : charge.priceTiers) === null || _a === void 0 ? void 0 : _a.length);
21801
21817
  };
21802
21818
 
21803
- const MUTATION$2 = `mutation quoteChangeRemoveCoupon($quoteChangeId: ID!, $couponCode: String!) {
21804
- quoteChangeRemoveCoupon(quoteChangeId: $quoteChangeId, couponCode: $couponCode) {
21805
- errors
21806
- }
21807
- }
21808
- `;
21809
- const quoteChangeRemoveCoupon = async ({ quoteChangeId, couponCode, token, apiHost, }) => {
21810
- var _a;
21811
- const vars = { couponCode, quoteChangeId };
21812
- const response = await gqlRequest({
21813
- query: MUTATION$2,
21814
- token,
21815
- vars,
21816
- apiHost,
21817
- });
21818
- const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteChangeRemoveCoupon) === null || _a === void 0 ? void 0 : _a.errors;
21819
- if (errors)
21820
- throw errors;
21821
- return response.quote;
21819
+ const removeHTMLTagsRegex = /<br>(?=(?:\s*<[^>]*>)*$)|(<br>)|<[^>]*>/gi;
21820
+ // Description is a string that can contain HTML tags. We want to remove all HTML tags except <br> tags.
21821
+ const createPlanDescription = (planDescription) => {
21822
+ return (planDescription || '').replace(removeHTMLTagsRegex, (_, y) => (y ? ' & ' : ''));
21822
21823
  };
21823
-
21824
- const COUPONS_QUERY = (filter) => `
21825
- query Coupons {
21826
- coupons(filter: ${filter ? `"${filter}"` : 'null'}) {
21827
- totalCount
21828
- }
21824
+ const getActivePlanPriceData = (priceList, selectedPriceList) => {
21825
+ if (!priceList) {
21826
+ return;
21829
21827
  }
21830
- `;
21831
- const getCoupons = async ({ token, apiHost, filter, }) => {
21832
- const response = await gqlRequest({
21833
- query: COUPONS_QUERY(filter),
21834
- token,
21835
- vars: {},
21836
- apiHost,
21837
- });
21838
- return response === null || response === void 0 ? void 0 : response.coupons;
21839
- };
21840
-
21841
- const showErrorNotification$3 = useErrorNotification();
21842
- const useUpdateCoupons = ({ apiHost, token, quoteChangeId, onCouponAdded, onCouponRemoved, }) => {
21843
- const { data: coupons } = useQuery({
21844
- queryKey: ['coupons', token],
21845
- queryFn: () => getCoupons({ token, apiHost, filter: 'coupon.active is true' }),
21846
- });
21847
- const { mutate: addCoupon, isPending: isAddingCoupon } = useMutation({
21848
- mutationFn: (couponCode) => {
21849
- if (!token) {
21850
- throw new Error('Token is required');
21851
- }
21852
- if (!quoteChangeId) {
21853
- throw new Error('Quote change ID is required');
21854
- }
21855
- return quoteChangeAddCoupon({
21856
- quoteChangeId,
21857
- couponCode,
21858
- apiHost,
21859
- token,
21860
- });
21861
- },
21862
- onSuccess: () => {
21863
- onCouponAdded === null || onCouponAdded === void 0 ? void 0 : onCouponAdded();
21864
- },
21865
- onError: (error) => {
21866
- var _a, _b;
21867
- showErrorNotification$3((_b = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.errors[0]) === null || _b === void 0 ? void 0 : _b.message, 'Error adding coupon');
21868
- },
21869
- });
21870
- const { mutate: removeCoupon, isPending: isRemovingCoupon } = useMutation({
21871
- mutationFn: (couponCode) => {
21872
- if (!quoteChangeId) {
21873
- throw new Error('Quote change ID is required');
21828
+ // If a period option is selected, return the charge that matches the selected period option
21829
+ let activeBillingPLCharge;
21830
+ // Default to first price list charge
21831
+ let lowestPLCharge;
21832
+ // Find the lowest price list charge with a billing period that matches the selected period option
21833
+ if (priceList.id === (selectedPriceList === null || selectedPriceList === void 0 ? void 0 : selectedPriceList.id)) {
21834
+ activeBillingPLCharge = priceList.charges[0];
21835
+ }
21836
+ for (let j = 0; j < priceList.charges.length; j++) {
21837
+ const charge = priceList.charges[j];
21838
+ if (charge.chargeType === ChargeType.USAGE || charge.featureAddon === true)
21839
+ continue;
21840
+ if (activeBillingPLCharge) {
21841
+ // If we already found a charge with the same billing period check if this charge is lower
21842
+ if (charge.basePrice < activeBillingPLCharge.basePrice &&
21843
+ charge.billingPeriod === (activeBillingPLCharge === null || activeBillingPLCharge === void 0 ? void 0 : activeBillingPLCharge.billingPeriod)) {
21844
+ activeBillingPLCharge = charge;
21874
21845
  }
21875
- return quoteChangeRemoveCoupon({
21876
- quoteChangeId,
21877
- couponCode,
21878
- apiHost,
21879
- token,
21880
- });
21881
- },
21882
- onSuccess: () => {
21883
- onCouponRemoved === null || onCouponRemoved === void 0 ? void 0 : onCouponRemoved();
21884
- },
21885
- onError: (error) => {
21886
- var _a, _b;
21887
- showErrorNotification$3((_b = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.errors[0]) === null || _b === void 0 ? void 0 : _b.message, 'Error removing coupon');
21888
- },
21889
- });
21846
+ }
21847
+ // If a period option is selected, only return the charge if it matches the selected period option
21848
+ else if (selectedPriceList &&
21849
+ charge.billingPeriod === periodMonthsConverter(selectedPriceList.periodMonths)) {
21850
+ activeBillingPLCharge = charge;
21851
+ }
21852
+ // Otherwise, return the lowest price list charge
21853
+ else if (charge.basePrice < ((lowestPLCharge === null || lowestPLCharge === void 0 ? void 0 : lowestPLCharge.basePrice) || -1)) {
21854
+ lowestPLCharge = charge;
21855
+ }
21856
+ }
21890
21857
  return {
21891
- addCoupon,
21892
- removeCoupon,
21893
- isAddingCoupon,
21894
- isRemovingCoupon,
21895
- activeCouponsExist: (coupons === null || coupons === void 0 ? void 0 : coupons.totalCount) > 0,
21858
+ activeCharge: activeBillingPLCharge || lowestPLCharge,
21896
21859
  };
21897
21860
  };
21898
-
21899
- function shouldShowCouponEditor(quote, activeCouponsExist, upgradingSubscription) {
21900
- var _a, _b;
21901
- const upgradingFromTrial = ((_a = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL') ||
21902
- ((_b = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED');
21903
- function upgradingFromFree() {
21904
- 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);
21905
- return totalPrice === 0;
21861
+ const showErrorNotification$3 = useErrorNotification();
21862
+ const isPriceListDisabled = ({ priceList, upgradingSubscription, }) => {
21863
+ const priceListAddonPlans = priceList === null || priceList === void 0 ? void 0 : priceList.plan.addonPlans;
21864
+ if (!priceListAddonPlans) {
21865
+ showErrorNotification$3('Price list addon plans are undefined');
21866
+ return false;
21906
21867
  }
21907
- const quoteKindIsValid = quote.kind === QuoteChangeKind.SUBSCRIBE ||
21908
- quote.kind === QuoteChangeKind.ADJUSTMENT ||
21909
- quote.kind === QuoteChangeKind.ACTIVATE;
21910
- if (quoteKindIsValid) {
21911
- return activeCouponsExist && (upgradingFromTrial || upgradingFromFree());
21868
+ const canPurchaseFeatureAddons = hasUnpurchasedFeatureAddons(priceList, upgradingSubscription);
21869
+ const canPurchasePlanAddons = hasUnpurchasedAddonPriceLists(priceListAddonPlans, upgradingSubscription, periodMonthsConverter(priceList.periodMonths));
21870
+ const existingSubscriptionInTrial = upgradingSubscription && canSubscriptionUpgradeFromTrial(upgradingSubscription);
21871
+ const existingSubscriptionInTrialExpired = upgradingSubscription && canSubscriptionUpgradeFromTrialExpired(upgradingSubscription);
21872
+ const isUpgradingSubscriptionPriceList = (upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.id) === priceList.id;
21873
+ // When should priceList be disabled?
21874
+ // if upgradingSubscription?.priceList.id === priceList.id
21875
+ // AND the upgradingSubscription is not in trial
21876
+ // AND cannot purchase feature addons
21877
+ // AND cannot purchase add-on plans
21878
+ // AND selfServiceBuy is false
21879
+ // if upgradingSubscription?.priceList.id != priceList.id
21880
+ // AND upgradingSubscription is expired trial
21881
+ if (isUpgradingSubscriptionPriceList) {
21882
+ return (!existingSubscriptionInTrial &&
21883
+ !existingSubscriptionInTrialExpired &&
21884
+ !canPurchaseFeatureAddons &&
21885
+ !canPurchasePlanAddons);
21912
21886
  }
21913
- return false;
21914
- }
21915
-
21916
- function CouponEditor({ className, onAddCoupon, isAddingCoupon, couponCode, setCouponCode, }) {
21917
- async function handleAddCoupon() {
21918
- onAddCoupon(couponCode);
21887
+ else {
21888
+ return false;
21919
21889
  }
21920
- return (jsx("div", { className: `bunny-flex bunny-flex-col bunny-gap-2 ${className}`, children: jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2", children: [jsx(Input, { value: couponCode, onChange: e => setCouponCode(e.target.value), placeholder: "Coupon code", disabled: isAddingCoupon, size: "small" }), jsx(Button, { loading: isAddingCoupon, type: "primary", onClick: handleAddCoupon, disabled: couponCode.length === 0, children: "Apply" })] }) }));
21890
+ };
21891
+
21892
+ const CheckoutButton = ({ disabled, onClickCheckout, loading, tooltipText, }) => {
21893
+ const isMobile = useIsMobile$1();
21894
+ const TooltipWrapper = ({ children }) => {
21895
+ if (tooltipText) {
21896
+ return jsx(Tooltip, { title: tooltipText, children: children });
21897
+ }
21898
+ return jsx("div", { children: children });
21899
+ };
21900
+ return (jsx(TooltipWrapper, { children: jsx(Button, { className: isMobile ? 'w-full' : '', disabled: disabled, onClick: onClickCheckout, size: isMobile ? 'large' : 'middle', type: "primary", loading: loading, children: "Proceed to checkout" }) }));
21901
+ };
21902
+
21903
+ var localizedFormat$2 = {exports: {}};
21904
+
21905
+ var localizedFormat$1 = localizedFormat$2.exports;
21906
+
21907
+ var hasRequiredLocalizedFormat;
21908
+
21909
+ function requireLocalizedFormat () {
21910
+ if (hasRequiredLocalizedFormat) return localizedFormat$2.exports;
21911
+ hasRequiredLocalizedFormat = 1;
21912
+ (function (module, exports) {
21913
+ !function(e,t){module.exports=t();}(localizedFormat$1,(function(){var e={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"};return function(t,o,n){var r=o.prototype,i=r.format;n.en.formats=e,r.format=function(t){void 0===t&&(t="YYYY-MM-DDTHH:mm:ssZ");var o=this.$locale().formats,n=function(t,o){return t.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,(function(t,n,r){var i=r&&r.toUpperCase();return n||o[r]||e[r]||o[i].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,(function(e,t,o){return t||o.slice(1)}))}))}(t,void 0===o?{}:o);return i.call(this,n)};}}));
21914
+ } (localizedFormat$2));
21915
+ return localizedFormat$2.exports;
21921
21916
  }
21922
21917
 
21923
- const QuoteFields_QuoteFragment = t(`
21924
- fragment QuoteFields_QuoteFragment on Quote @_unmask {
21925
- accountId
21926
- amount
21927
- amountDue
21928
- smallUnitAmountDue
21929
- currencyId
21930
- id
21931
- payableId
21918
+ var localizedFormatExports = requireLocalizedFormat();
21919
+ var localizedFormat = /*@__PURE__*/getDefaultExportFromCjs(localizedFormatExports);
21920
+
21921
+ dayjs.extend(localizedFormat);
21922
+ const formatCurrency = (value, currencyIsoCode, decimals = 2) => {
21923
+ if (value !== 0 && !value)
21924
+ return '';
21925
+ const currencyValue = typeof value === 'string' ? parseFloat(value) : value;
21926
+ if (isNaN(currencyValue))
21927
+ return value;
21928
+ const localeOptions = {
21929
+ minimumFractionDigits: decimals,
21930
+ maximumFractionDigits: decimals,
21931
+ };
21932
+ localeOptions.style = 'currency';
21933
+ localeOptions.currency = currencyIsoCode;
21934
+ return currencyValue.toLocaleString(navigator.language, localeOptions);
21935
+ };
21936
+
21937
+ const CheckoutPrice_QuoteFragment = t(`
21938
+ fragment CheckoutPrice_QuoteFragment on Quote {
21932
21939
  periodAmount
21933
- subtotal
21934
- taxAmount
21935
- startDate
21936
- formattedQuote {
21937
- html
21938
- }
21939
- amountsByPeriod {
21940
- amount
21941
- startDate
21942
- }
21943
- kind
21940
+ amountDue
21941
+ }
21942
+ `);
21943
+ const CheckoutPrice = ({ isUsage, quote: maskedQuote, selectedPriceList, }) => {
21944
+ var _a;
21945
+ // Read fragments
21946
+ const quote = readFragment(CheckoutPrice_QuoteFragment, maskedQuote);
21947
+ // Hooks
21948
+ const isMobile = useIsMobile$1();
21949
+ // amountDue might not be available, so we use periodAmount as a fallback
21950
+ const displayAmount = (_a = quote === null || quote === void 0 ? void 0 : quote.amountDue) !== null && _a !== void 0 ? _a : quote === null || quote === void 0 ? void 0 : quote.periodAmount;
21951
+ if (!isUsage && (!selectedPriceList || displayAmount === undefined))
21952
+ return null;
21953
+ const convertedPeriodMonths = periodMonthsConverter(selectedPriceList.periodMonths);
21954
+ const periodLabel = convertedPeriodMonths ? PERIOD_LABELS[convertedPeriodMonths] : 'undefined';
21955
+ return (jsx("div", { className: `bunny-font-medium ${isMobile ? 'bunny-text-2xl' : ''}`, children: isUsage
21956
+ ? 'Usage based pricing'
21957
+ : selectedPriceList && displayAmount !== undefined
21958
+ ? `${formatCurrency(displayAmount, selectedPriceList === null || selectedPriceList === void 0 ? void 0 : selectedPriceList.currencyId, undefined)} / ${periodLabel}`
21959
+ : '' }));
21960
+ };
21961
+
21962
+ const { Text: Text$p } = Typography;
21963
+ const CheckoutBarSummarySection_QuoteFragment = t(`
21964
+ fragment CheckoutBarSummarySection_QuoteFragment on Quote {
21944
21965
  quoteChanges {
21945
- currencyId
21946
- id
21947
- kind
21948
21966
  charges {
21949
- subtotal
21950
- amountsByPeriod {
21951
- amount
21952
- startDate
21953
- }
21954
- amount
21955
- billingPeriod
21956
- currencyId
21957
- feature {
21958
- unitName
21959
- }
21960
- id
21961
- name
21962
- priceListCharge {
21963
- id
21964
- }
21965
- priceList {
21966
- id
21967
- }
21968
- coupon {
21969
- couponCode
21970
- }
21971
- quantity
21972
- kind
21973
- }
21974
- priceList {
21975
21967
  id
21976
- plan {
21977
- name
21978
- }
21979
- product {
21980
- name
21981
- }
21982
21968
  }
21983
21969
  }
21970
+ ...CheckoutPrice_QuoteFragment
21984
21971
  }
21985
- `);
21972
+ `, [CheckoutPrice_QuoteFragment]);
21973
+ const CheckoutBarSummarySection = ({ selectedPriceList, onClickCheckout, }) => {
21974
+ var _a, _b;
21975
+ // Context
21976
+ const { quote: maskedQuote, isQuotePending, isUpdatingQuote } = useContext(QuoteContext);
21977
+ const quote = readFragment(CheckoutBarSummarySection_QuoteFragment, maskedQuote);
21978
+ const { isInPreviewMode } = useContext(SubscriptionsContext);
21979
+ // Hooks
21980
+ const { paymentPlugins } = usePaymentPlugins(undefined);
21981
+ const isMobile = useIsMobile$1();
21982
+ const hasPaymentPlugins = Boolean(paymentPlugins === null || paymentPlugins === void 0 ? void 0 : paymentPlugins.length);
21983
+ const quoteHasCharges = Boolean((_a = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _a === void 0 ? void 0 : _a.some(qc => qc.charges.length > 0));
21984
+ const checkoutButtonDisabled = Boolean(!selectedPriceList || !quoteHasCharges || !hasPaymentPlugins || isInPreviewMode);
21985
+ const activeCharge = (_b = getActivePlanPriceData(selectedPriceList, selectedPriceList)) === null || _b === void 0 ? void 0 : _b.activeCharge;
21986
+ const isUsage = (activeCharge === null || activeCharge === void 0 ? void 0 : activeCharge.chargeType) === ChargeType.USAGE;
21987
+ return (jsxs(Text$p, { className: `bunny-flex bunny-items-center bunny-gap-4 ${isMobile ? 'bunny-flex-col' : ''}`, children: [quote && (jsxs("div", { className: `bunny-flex ${isMobile ? 'items-center justify-between w-full' : 'flex-col'}`, children: [jsx("div", { className: "bunny-text-slate-500 bunny-font-medium bunny-text-right", style: { fontSize: '11px' }, children: "TOTAL" }), jsx(CheckoutPrice, { isUsage: isUsage, quote: quote, selectedPriceList: selectedPriceList })] })), jsx(CheckoutButton, { disabled: checkoutButtonDisabled, onClickCheckout: onClickCheckout, loading: isQuotePending || isUpdatingQuote, tooltipText: isInPreviewMode
21988
+ ? 'Checkout is disabled in preview mode'
21989
+ : !hasPaymentPlugins
21990
+ ? 'Cannot checkout. No valid payment plugins found. Please contact your administrator.'
21991
+ : undefined })] }));
21992
+ };
21986
21993
 
21987
- const MUTATION$1 = `
21988
- mutation accountUpdate(
21989
- $id: ID!,
21990
- $attributes: AccountAttributes!) {
21991
- accountUpdate(
21992
- id: $id,
21993
- attributes: $attributes
21994
- ) {
21995
- account {
21996
- id
21997
- billingCountry
21998
- billingState
21999
- billingStreet
22000
- billingCity
22001
- billingZip
22002
- name
21994
+ const MUTATION$3 = `{
21995
+ currentUser {
21996
+ taxationRequiredAccountFields
21997
+ }
21998
+ }`;
21999
+ const getTaxationRequiredAccountFields = async ({ apiHost, token, }) => {
22000
+ var _a, _b;
22001
+ const response = await gqlRequest({
22002
+ query: MUTATION$3,
22003
+ token,
22004
+ apiHost: apiHost,
22005
+ });
22006
+ 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
22007
+ ? response.currentUser.taxationRequiredAccountFields
22008
+ : null;
22009
+ };
22010
+
22011
+ const BunnyFooterIcon = ({ color }) => {
22012
+ return (jsxs("svg", { width: "45", height: "15", viewBox: "0 0 39 13", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsxs("g", { clipPath: "url(#clip0_6_851)", children: [jsx("path", { className: "bunny-icon-path", d: "M14.5898 7.19708C14.5898 9.35053 13.0926 10.325 11.2495 10.325C9.39955 10.325 7.90234 9.35001 7.90234 7.18967V3.26221H10.1125V7.00052C10.1125 7.87719 10.5855 8.27725 11.2495 8.27725C11.9061 8.27725 12.3865 7.87719 12.3865 7.00052V3.26221H14.5898V7.19708Z", fill: color }), jsx("path", { className: "bunny-icon-path", d: "M31.8943 12.9625H29.4793L31.8523 8.62816L28.9355 3.26221H31.4708L33.0457 6.35524L34.5924 3.26221H37.0075L31.8943 12.9625Z", fill: color }), jsx("path", { className: "bunny-icon-path", d: "M15.1602 5.96827C15.1602 3.8148 16.6574 2.84033 18.5005 2.84033C20.3504 2.84033 21.8476 3.81533 21.8476 5.97568V10.1473H19.6374V6.16483C19.6374 5.28815 19.1645 4.8881 18.5005 4.8881C17.8439 4.8881 17.3634 5.28815 17.3634 6.16483V10.1473H15.1602V5.96827Z", fill: color }), jsx("path", { className: "bunny-icon-path", d: "M22.4316 5.96827C22.4316 3.8148 23.9289 2.84033 25.7719 2.84033C27.6219 2.84033 29.1191 3.81533 29.1191 5.97568V10.1473H26.9089V6.16483C26.9089 5.28815 26.4359 4.8881 25.7719 4.8881C25.1154 4.8881 24.6349 5.28815 24.6349 6.16483V10.1473H22.4316V5.96827Z", fill: color }), jsx("path", { className: "bunny-icon-path", d: "M7.40511 6.68957C7.40511 8.7236 6.02815 10.3227 4.17816 10.3227C3.23907 10.3227 2.61071 9.94378 2.19358 9.40371V10.1404H0.0605469V0.0405273H2.26381V3.91939C2.68041 3.42158 3.28802 3.07069 4.17763 3.07069C6.02759 3.07069 7.40511 4.66981 7.40511 6.68957ZM2.17229 6.69642C2.17229 7.60802 2.77937 8.2744 3.64823 8.2744C4.53783 8.2744 5.13107 7.59372 5.13107 6.69642C5.13107 5.79912 4.53783 5.11844 3.64823 5.11844C2.77937 5.11844 2.17229 5.78482 2.17229 6.69642Z", fill: color }), jsx("path", { className: "bunny-icon-path", d: "M38.966 8.94801C38.966 9.76181 38.2668 10.4631 37.4618 10.4631C36.6499 10.4631 35.9434 9.76181 35.9434 8.94801C35.9434 8.14846 36.6494 7.46094 37.4618 7.46094C38.2668 7.46094 38.966 8.14846 38.966 8.94801Z", fill: color })] }), jsx("defs", { children: jsx("clipPath", { id: "clip0_6_851", children: jsx("rect", { width: "39", height: "13", fill: "white" }) }) })] }));
22013
+ };
22014
+
22015
+ const { Text: Text$o } = Typography;
22016
+ const Footer = ({ className }) => {
22017
+ const token = useToken();
22018
+ const { currentUser } = useCurrentUserData(token);
22019
+ const { privacyUrl, termsUrl } = currentUser;
22020
+ const isMobile = useIsMobile$1();
22021
+ return (jsxs("div", { className: `bunny-flex bunny-items-center bunny-justify-between bunny-shrink-0 ${isMobile ? 'bunny-flex-col bunny-gap-2' : ''} ${className}`, children: [(termsUrl || privacyUrl) && (jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-3", children: [termsUrl && (jsx(StyedLink, { className: "bunny-text-xs bunny-text-slate-400", href: termsUrl, rel: "noopener noreferrer", target: "_blank", type: "text", children: "Terms" })), privacyUrl && (jsx(StyedLink, { className: "bunny-text-xs bunny-text-slate-400", href: privacyUrl, rel: "noopener noreferrer", target: "_blank", type: "text", children: "Privacy" }))] })), jsx(BunnyMarketingLink, {})] }));
22022
+ };
22023
+ const BunnyMarketingLink = () => {
22024
+ const [isHovered, setIsHovered] = useState(false);
22025
+ const isMobile = useIsMobile$1();
22026
+ return (jsx("div", { className: `bunny-flex bunny-items-end bunny-justify-end ${isMobile ? '' : 'grow'}`, children: jsx(StyledBunnyLink, { className: "bunny-flex bunny-items-end bunny-justify-end bunny-text-slate-400", href: "https://bunny.com/", rel: "noopener noreferrer", target: "_blank", children: jsxs("div", { className: "bunny-flex bunny-items-center", onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: [jsx(Text$o, { className: "bunny-text-slate-400", children: "Powered by\u00A0" }), jsx("div", { style: { paddingTop: '5px' }, children: jsx(BunnyFooterIcon, { color: isHovered ? PRIMARY_COLOR : SLATE_400 }) })] }) }) }));
22027
+ };
22028
+ const StyedLink = styled.a `
22029
+ color: ${SLATE_400};
22030
+ transition: color 0.3s;
22031
+ &:hover {
22032
+ color: ${SLATE_500};
22033
+ }
22034
+ text-decoration: none;
22035
+ `;
22036
+ const StyledBunnyLink = styled(StyedLink) `
22037
+ &:hover {
22038
+ color: ${PRIMARY_COLOR} !important;
22039
+ }
22040
+ `;
22041
+
22042
+ const MUTATION$2 = `mutation quoteChangeAddCoupon($couponCode: String!, $quoteChangeId: ID!) {
22043
+ quoteChangeAddCoupon(couponCode: $couponCode, quoteChangeId: $quoteChangeId) {
22044
+ quoteChange {
22045
+ id
22046
+ charges {
22047
+ id
22048
+ amount
22049
+ couponId
22003
22050
  }
22004
- errors
22005
22051
  }
22006
- }
22052
+ }
22053
+ }`;
22054
+ const quoteChangeAddCoupon = async ({ quoteChangeId, couponCode, token, apiHost, }) => {
22055
+ var _a;
22056
+ const vars = { couponCode, quoteChangeId };
22057
+ const response = await gqlRequest({
22058
+ query: MUTATION$2,
22059
+ token,
22060
+ vars,
22061
+ apiHost,
22062
+ });
22063
+ const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteAddCoupon) === null || _a === void 0 ? void 0 : _a.errors;
22064
+ if (errors)
22065
+ throw errors;
22066
+ return response.quote;
22067
+ };
22068
+
22069
+ const MUTATION$1 = `mutation quoteChangeRemoveCoupon($quoteChangeId: ID!, $couponCode: String!) {
22070
+ quoteChangeRemoveCoupon(quoteChangeId: $quoteChangeId, couponCode: $couponCode) {
22071
+ errors
22072
+ }
22073
+ }
22007
22074
  `;
22008
- const accountUpdate = async ({ accountId, attributes, token, apiHost, }) => {
22075
+ const quoteChangeRemoveCoupon = async ({ quoteChangeId, couponCode, token, apiHost, }) => {
22009
22076
  var _a;
22010
- const vars = { id: accountId, attributes };
22077
+ const vars = { couponCode, quoteChangeId };
22011
22078
  const response = await gqlRequest({
22012
22079
  query: MUTATION$1,
22013
22080
  token,
22014
22081
  vars,
22015
22082
  apiHost,
22016
22083
  });
22017
- const errors = (_a = response === null || response === void 0 ? void 0 : response.accountUpdate) === null || _a === void 0 ? void 0 : _a.errors;
22084
+ const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteChangeRemoveCoupon) === null || _a === void 0 ? void 0 : _a.errors;
22018
22085
  if (errors)
22019
22086
  throw errors;
22020
- return response.accountUpdate;
22087
+ return response.quote;
22021
22088
  };
22022
22089
 
22023
- const COUNTRIES_REQUIRING_STATE = ['US', 'CA'];
22024
- const TaxationForm = ({ account, accountId }) => {
22025
- // Hooks
22026
- const queryClient = useQueryClient();
22027
- const { apiHost } = useContext(BunnyContext);
22028
- const token = useToken();
22029
- const [form] = Form.useForm();
22030
- // Mutations
22031
- const { mutate: updateAccount, isPending: isUpdatingAccount } = useMutation({
22032
- mutationFn: async (changedFormData) => {
22033
- const account = await accountUpdate({
22034
- accountId,
22035
- attributes: changedFormData,
22036
- token,
22090
+ const COUPONS_QUERY = (filter) => `
22091
+ query Coupons {
22092
+ coupons(filter: ${filter ? `"${filter}"` : 'null'}) {
22093
+ totalCount
22094
+ }
22095
+ }
22096
+ `;
22097
+ const getCoupons = async ({ token, apiHost, filter, }) => {
22098
+ const response = await gqlRequest({
22099
+ query: COUPONS_QUERY(filter),
22100
+ token,
22101
+ vars: {},
22102
+ apiHost,
22103
+ });
22104
+ return response === null || response === void 0 ? void 0 : response.coupons;
22105
+ };
22106
+
22107
+ const showErrorNotification$2 = useErrorNotification();
22108
+ const useUpdateCoupons = ({ apiHost, token, quoteChangeId, onCouponAdded, onCouponRemoved, }) => {
22109
+ const { data: coupons } = useQuery({
22110
+ queryKey: ['coupons', token],
22111
+ queryFn: () => getCoupons({ token, apiHost, filter: 'coupon.active is true' }),
22112
+ });
22113
+ const { mutate: addCoupon, isPending: isAddingCoupon } = useMutation({
22114
+ mutationFn: (couponCode) => {
22115
+ if (!token) {
22116
+ throw new Error('Token is required');
22117
+ }
22118
+ if (!quoteChangeId) {
22119
+ throw new Error('Quote change ID is required');
22120
+ }
22121
+ return quoteChangeAddCoupon({
22122
+ quoteChangeId,
22123
+ couponCode,
22037
22124
  apiHost,
22125
+ token,
22038
22126
  });
22039
- return account;
22040
22127
  },
22041
22128
  onSuccess: () => {
22042
- queryClient.invalidateQueries({
22043
- queryKey: ['getTaxationRequiredAccountFields', token],
22129
+ onCouponAdded === null || onCouponAdded === void 0 ? void 0 : onCouponAdded();
22130
+ },
22131
+ onError: (error) => {
22132
+ var _a, _b;
22133
+ showErrorNotification$2((_b = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.errors[0]) === null || _b === void 0 ? void 0 : _b.message, 'Error adding coupon');
22134
+ },
22135
+ });
22136
+ const { mutate: removeCoupon, isPending: isRemovingCoupon } = useMutation({
22137
+ mutationFn: (couponCode) => {
22138
+ if (!quoteChangeId) {
22139
+ throw new Error('Quote change ID is required');
22140
+ }
22141
+ return quoteChangeRemoveCoupon({
22142
+ quoteChangeId,
22143
+ couponCode,
22144
+ apiHost,
22145
+ token,
22044
22146
  });
22045
22147
  },
22148
+ onSuccess: () => {
22149
+ onCouponRemoved === null || onCouponRemoved === void 0 ? void 0 : onCouponRemoved();
22150
+ },
22151
+ onError: (error) => {
22152
+ var _a, _b;
22153
+ showErrorNotification$2((_b = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.errors[0]) === null || _b === void 0 ? void 0 : _b.message, 'Error removing coupon');
22154
+ },
22046
22155
  });
22047
- 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) => {
22048
- var _a, _b;
22049
- return ((_a = option === null || option === void 0 ? void 0 : option.label) !== null && _a !== void 0 ? _a : '').toLowerCase().includes(input.toLowerCase()) ||
22050
- ((_b = option === null || option === void 0 ? void 0 : option.value) !== null && _b !== void 0 ? _b : '').toLowerCase().includes(input.toLowerCase());
22051
- } }) }), 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" }) })] }));
22052
- };
22053
- const FormBillingState = () => {
22054
- const billingCountry = Form.useWatch('billingCountry');
22055
- const billingStateRequired = COUNTRIES_REQUIRING_STATE.includes(billingCountry);
22056
- return (jsx(Form.Item, { label: "Billing state", name: "billingState", rules: [{ required: billingStateRequired }], children: jsx(Input, { placeholder: "State" }) }));
22156
+ return {
22157
+ addCoupon,
22158
+ removeCoupon,
22159
+ isAddingCoupon,
22160
+ isRemovingCoupon,
22161
+ activeCouponsExist: (coupons === null || coupons === void 0 ? void 0 : coupons.totalCount) > 0,
22162
+ };
22057
22163
  };
22058
22164
 
22059
- // HACK: I have imported QuoteFields_QuoteFragment here as a hack to ensure I have all of the quote data needed for
22060
- // the eventual children of this component.
22061
- // Solution: Eventually all children of this component should be using query fragments to avoid this
22062
- const QuoteCheckout_QuoteFragment = t(`
22063
- fragment QuoteCheckout_QuoteFragment on Quote {
22064
- id
22165
+ function shouldShowCouponEditor(quote, activeCouponsExist, upgradingSubscription) {
22166
+ var _a, _b;
22167
+ const upgradingFromTrial = ((_a = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL') ||
22168
+ ((_b = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED');
22169
+ function upgradingFromFree() {
22170
+ 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);
22171
+ return totalPrice === 0;
22172
+ }
22173
+ const quoteKindIsValid = quote.kind === QuoteChangeKind.SUBSCRIBE ||
22174
+ quote.kind === QuoteChangeKind.ADJUSTMENT ||
22175
+ quote.kind === QuoteChangeKind.ACTIVATE;
22176
+ if (quoteKindIsValid) {
22177
+ return activeCouponsExist && (upgradingFromTrial || upgradingFromFree());
22178
+ }
22179
+ return false;
22180
+ }
22181
+
22182
+ function CouponEditor({ className, onAddCoupon, isAddingCoupon, couponCode, setCouponCode, }) {
22183
+ async function handleAddCoupon() {
22184
+ onAddCoupon(couponCode);
22185
+ }
22186
+ return (jsx("div", { className: `bunny-flex bunny-flex-col bunny-gap-2 ${className}`, children: jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2", children: [jsx(Input, { value: couponCode, onChange: e => setCouponCode(e.target.value), placeholder: "Coupon code", disabled: isAddingCoupon, size: "small" }), jsx(Button, { loading: isAddingCoupon, type: "primary", onClick: handleAddCoupon, disabled: couponCode.length === 0, children: "Apply" })] }) }));
22187
+ }
22188
+
22189
+ const QuoteFields_QuoteFragment = t(`
22190
+ fragment QuoteFields_QuoteFragment on Quote @_unmask {
22065
22191
  accountId
22066
- amountDue
22067
22192
  amount
22193
+ amountDue
22194
+ smallUnitAmountDue
22195
+ currencyId
22196
+ id
22197
+ payableId
22198
+ periodAmount
22199
+ subtotal
22200
+ taxAmount
22201
+ startDate
22202
+ formattedQuote {
22203
+ html
22204
+ }
22205
+ amountsByPeriod {
22206
+ amount
22207
+ startDate
22208
+ }
22209
+ kind
22068
22210
  quoteChanges {
22211
+ currencyId
22069
22212
  id
22213
+ kind
22070
22214
  charges {
22071
- kind
22215
+ subtotal
22216
+ amountsByPeriod {
22217
+ amount
22218
+ startDate
22219
+ }
22220
+ amount
22221
+ billingPeriod
22222
+ currencyId
22223
+ feature {
22224
+ unitName
22225
+ }
22226
+ id
22227
+ name
22228
+ priceListCharge {
22229
+ id
22230
+ }
22231
+ priceList {
22232
+ id
22233
+ }
22072
22234
  coupon {
22073
22235
  couponCode
22074
22236
  }
22237
+ quantity
22238
+ kind
22075
22239
  }
22076
- }
22077
- ...QuoteFields_QuoteFragment
22078
- }
22079
- `, [QuoteFields_QuoteFragment]);
22080
- const showSuccessNotification$1 = useSuccessNotification();
22081
- const QuoteCheckout = ({ account, onSuccess, onFail, quote: maskedQuote, taxationRequiredAccountFields, onRecalculateTaxes, }) => {
22082
- var _a, _b, _c, _d, _e;
22083
- // Read fragments
22084
- const quote = readFragment(QuoteCheckout_QuoteFragment, maskedQuote);
22240
+ priceList {
22241
+ id
22242
+ plan {
22243
+ name
22244
+ }
22245
+ product {
22246
+ name
22247
+ }
22248
+ }
22249
+ }
22250
+ }
22251
+ `);
22252
+
22253
+ const MUTATION = `
22254
+ mutation accountUpdate(
22255
+ $id: ID!,
22256
+ $attributes: AccountAttributes!) {
22257
+ accountUpdate(
22258
+ id: $id,
22259
+ attributes: $attributes
22260
+ ) {
22261
+ account {
22262
+ id
22263
+ billingCountry
22264
+ billingState
22265
+ billingStreet
22266
+ billingCity
22267
+ billingZip
22268
+ name
22269
+ }
22270
+ errors
22271
+ }
22272
+ }
22273
+ `;
22274
+ const accountUpdate$1 = async ({ accountId, attributes, token, apiHost, }) => {
22275
+ var _a;
22276
+ const vars = { id: accountId, attributes };
22277
+ const response = await gqlRequest({
22278
+ query: MUTATION,
22279
+ token,
22280
+ vars,
22281
+ apiHost,
22282
+ });
22283
+ const errors = (_a = response === null || response === void 0 ? void 0 : response.accountUpdate) === null || _a === void 0 ? void 0 : _a.errors;
22284
+ if (errors)
22285
+ throw errors;
22286
+ return response.accountUpdate;
22287
+ };
22288
+
22289
+ const COUNTRIES_REQUIRING_STATE = ['US', 'CA'];
22290
+ const TaxationForm = ({ account, accountId }) => {
22291
+ // Hooks
22292
+ const queryClient = useQueryClient();
22085
22293
  const { apiHost } = useContext(BunnyContext);
22086
- const { upgradingSubscription } = useContext(SubscriptionsContext);
22087
22294
  const token = useToken();
22088
- const isMobile = useIsMobile$1();
22089
- const [isSaving, setIsSaving] = useState(false);
22090
- const paymentRequired = getQuoteAmountDue(quote) > 0;
22091
- const queryClient = useQueryClient();
22092
- const [couponCode, setCouponCode] = useState('');
22093
- const { addCoupon, removeCoupon, isAddingCoupon, isRemovingCoupon, activeCouponsExist } = useUpdateCoupons({
22094
- apiHost,
22095
- token,
22096
- 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,
22097
- onCouponAdded: () => {
22098
- if (!(quote === null || quote === void 0 ? void 0 : quote.id))
22099
- throw new Error('Quote ID is required');
22100
- queryClient.invalidateQueries({
22101
- queryKey: QueryKeyFactory$1.default.createObjectKey({
22102
- id: quote === null || quote === void 0 ? void 0 : quote.id,
22103
- objectName: 'editingQuote',
22104
- token,
22105
- }),
22295
+ const [form] = Form.useForm();
22296
+ // Mutations
22297
+ const { mutate: updateAccount, isPending: isUpdatingAccount } = useMutation({
22298
+ mutationFn: async (changedFormData) => {
22299
+ const account = await accountUpdate$1({
22300
+ accountId,
22301
+ attributes: changedFormData,
22302
+ token,
22303
+ apiHost,
22106
22304
  });
22107
- showSuccessNotification$1('Coupon applied');
22108
- onRecalculateTaxes();
22109
- setCouponCode('');
22305
+ return account;
22110
22306
  },
22111
- onCouponRemoved: () => {
22112
- if (!(quote === null || quote === void 0 ? void 0 : quote.id))
22113
- throw new Error('Quote ID is required');
22307
+ onSuccess: () => {
22114
22308
  queryClient.invalidateQueries({
22115
- queryKey: QueryKeyFactory$1.default.createObjectKey({
22116
- id: quote === null || quote === void 0 ? void 0 : quote.id,
22117
- objectName: 'editingQuote',
22118
- token,
22119
- }),
22309
+ queryKey: ['getTaxationRequiredAccountFields', token],
22120
22310
  });
22121
- showSuccessNotification$1('Coupon removed');
22122
- onRecalculateTaxes();
22123
- },
22124
- });
22125
- 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'); });
22126
- const checkoutMutation = useMutation({
22127
- mutationFn: async () => {
22128
- if (!(quote === null || quote === void 0 ? void 0 : quote.id))
22129
- throw new Error('Quote ID is required');
22130
- if (paymentRequired)
22131
- throw new Error('Payment is required');
22132
- return await checkout({ quoteId: quote.id, token, apiHost });
22133
22311
  },
22134
- onSuccess,
22135
- onError: onFail,
22136
22312
  });
22137
- async function handleCheckoutNoPayment() {
22138
- setIsSaving(true);
22139
- checkoutMutation.mutate();
22140
- setIsSaving(false);
22141
- }
22142
- if (taxationRequiredAccountFields)
22143
- return (jsx(PaymentFormWrapper, { setMaxHeight: false, children: jsx(TaxationForm, { account: account, accountId: quote.accountId }) }));
22144
- return (jsx(Fragment, { children: paymentRequired ? (jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2 bunny-w-full", children: [jsx(PaymentForm, { onPaymentSuccess: onSuccess, quote: quote }), (couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.length) === 0 ? (jsx(Fragment, { children: upgradingSubscription &&
22145
- 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: () => {
22146
- couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.forEach(couponCharge => {
22147
- var _a;
22148
- const couponCode = (_a = couponCharge === null || couponCharge === void 0 ? void 0 : couponCharge.coupon) === null || _a === void 0 ? void 0 : _a.couponCode;
22149
- if (couponCode) {
22150
- removeCoupon(couponCode);
22151
- }
22152
- });
22153
- }, 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" })] }) })) }));
22313
+ 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) => {
22314
+ var _a, _b;
22315
+ return ((_a = option === null || option === void 0 ? void 0 : option.label) !== null && _a !== void 0 ? _a : '').toLowerCase().includes(input.toLowerCase()) ||
22316
+ ((_b = option === null || option === void 0 ? void 0 : option.value) !== null && _b !== void 0 ? _b : '').toLowerCase().includes(input.toLowerCase());
22317
+ } }) }), 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" }) })] }));
22154
22318
  };
22155
- const PaymentFormWrapper = ({ children, setMaxHeight, className, }) => {
22156
- const isMobile = useIsMobile$1();
22157
- return (jsx("div", { className: `bunny-flex bunny-w-full bunny-flex-col bunny-gap-6 ${isMobile ? 'bunny-shadow-padding-xb' : ''} ${className}`, style: {
22158
- ...(isMobile
22159
- ? setMaxHeight
22160
- ? { maxHeight: '60vh' }
22161
- : {}
22162
- : {
22163
- width: '100%',
22164
- maxWidth: '350px',
22165
- }),
22166
- }, children: children }));
22319
+ const FormBillingState = () => {
22320
+ const billingCountry = Form.useWatch('billingCountry');
22321
+ const billingStateRequired = COUNTRIES_REQUIRING_STATE.includes(billingCountry);
22322
+ return (jsx(Form.Item, { label: "Billing state", name: "billingState", rules: [{ required: billingStateRequired }], children: jsx(Input, { placeholder: "State" }) }));
22167
22323
  };
22168
22324
 
22169
- const queryKeyFactory = QueryKeyFactory$1.default;
22170
- const Checkout_QuoteFragment = t(`
22171
- fragment Checkout_QuoteFragment on Quote {
22325
+ const { Text: Text$n } = Typography;
22326
+ // HACK: I have imported QuoteFields_QuoteFragment here as a hack to ensure I have all of the quote data needed for
22327
+ // the eventual children of this component.
22328
+ // Solution: Eventually all children of this component should be using query fragments to avoid this
22329
+ const QuoteCheckout_QuoteFragment = t(`
22330
+ fragment QuoteCheckout_QuoteFragment on Quote {
22172
22331
  id
22173
22332
  accountId
22174
- formattedQuote {
22175
- html
22333
+ amountDue
22334
+ amount
22335
+ quoteChanges {
22336
+ id
22337
+ charges {
22338
+ kind
22339
+ coupon {
22340
+ couponCode
22341
+ }
22342
+ }
22176
22343
  }
22177
- ...QuoteCheckout_QuoteFragment
22344
+ ...QuoteFields_QuoteFragment
22178
22345
  }
22179
- `, [QuoteCheckout_QuoteFragment]);
22180
- const Checkout = ({ onCancel, onSuccess, onFail, invoice, open, quote: maskedQuote, isUpdatingQuote, }) => {
22346
+ `, [QuoteFields_QuoteFragment]);
22347
+ const showSuccessNotification$1 = useSuccessNotification();
22348
+ const QuoteCheckout = ({ account, onSuccess, onFail, quote: maskedQuote, taxationRequiredAccountFields, onRecalculateTaxes, }) => {
22181
22349
  var _a, _b, _c, _d, _e;
22350
+ // Read fragments
22351
+ const quote = readFragment(QuoteCheckout_QuoteFragment, maskedQuote);
22182
22352
  const { apiHost } = useContext(BunnyContext);
22183
- const isMobile = useIsMobile$1();
22353
+ const { upgradingSubscription } = useContext(SubscriptionsContext);
22184
22354
  const token = useToken();
22185
- // Read fragments
22186
- const quote = readFragment(Checkout_QuoteFragment, maskedQuote);
22187
- const hasTaxPlugin = useHasTaxPlugin({
22355
+ const isMobile = useIsMobile$1();
22356
+ const [isSaving, setIsSaving] = useState(false);
22357
+ const paymentRequired = getQuoteAmountDue(quote) > 0;
22358
+ const queryClient = useQueryClient();
22359
+ const [couponCode, setCouponCode] = useState('');
22360
+ const { addCoupon, removeCoupon, isAddingCoupon, isRemovingCoupon, activeCouponsExist } = useUpdateCoupons({
22188
22361
  apiHost,
22189
22362
  token,
22190
- });
22191
- const queryClient = useQueryClient();
22192
- // Queries
22193
- const { data: taxationRequiredAccountFields, isLoading: isLoadingTaxationRequiredAccountFields } = useQuery({
22194
- queryKey: ['getTaxationRequiredAccountFields', token],
22195
- queryFn: () => getTaxationRequiredAccountFields({ apiHost, token }),
22196
- enabled: Boolean(quote),
22197
- staleTime: 0,
22198
- });
22199
- const { data: account, isLoading: isLoadingAccount } = useQuery({
22200
- queryKey: ['account', quote === null || quote === void 0 ? void 0 : quote.accountId],
22201
- queryFn: () => (quote === null || quote === void 0 ? void 0 : quote.accountId) &&
22202
- getAccount({ id: quote.accountId, apiHost, token, componentsVersion: PACKAGE_VERSION }),
22203
- enabled: Boolean(quote === null || quote === void 0 ? void 0 : quote.accountId) && ((taxationRequiredAccountFields === null || taxationRequiredAccountFields === void 0 ? void 0 : taxationRequiredAccountFields.length) || 0) > 0,
22204
- });
22205
- async function recalculateTaxes() {
22206
- if (quote) {
22207
- if (!quote.id)
22363
+ 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,
22364
+ onCouponAdded: () => {
22365
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id))
22208
22366
  throw new Error('Quote ID is required');
22209
- const updatedQuote = await quoteRecalculateTaxes({
22210
- quoteId: quote.id,
22211
- apiHost,
22212
- token,
22213
- });
22214
- if (updatedQuote) {
22215
- const quoteKey = queryKeyFactory.createObjectKey({
22216
- id: updatedQuote.id,
22217
- objectName: 'editingQuote',
22218
- token,
22219
- });
22220
- queryClient.setQueryData(quoteKey, updatedQuote);
22221
- }
22222
- }
22223
- return {};
22224
- }
22225
- const recalculateTaxesEnabled = Boolean(quote) &&
22226
- open &&
22227
- hasTaxPlugin &&
22228
- !taxationRequiredAccountFields &&
22229
- !isLoadingTaxationRequiredAccountFields &&
22230
- !isUpdatingQuote;
22231
- useQuery({
22232
- queryKey: queryKeyFactory.createQuoteTaxCalculateKey({
22233
- id: (_a = quote === null || quote === void 0 ? void 0 : quote.id) !== null && _a !== void 0 ? _a : undefined,
22234
- token,
22235
- }),
22236
- queryFn: recalculateTaxes,
22237
- // Recalculate taxes if the quote is open, has a tax plugin, and the taxation required account fields are not required
22238
- enabled: recalculateTaxesEnabled,
22239
- staleTime: 0,
22240
- });
22241
- if (!open || isLoadingTaxationRequiredAccountFields || isLoadingAccount)
22242
- return null;
22243
- 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
22244
- bunny-overflow-auto bunny-height-full`, style: {
22245
- zIndex: 1001,
22246
- }, children: jsxs("div", { className: `bunny-flex bunny-flex-col bunny-grow bunny-pt-4 ${isMobile ? 'bunny-pb-4' : 'bunny-pb-8'} bunny-content-container`, children: [jsx("div", { className: "bunny-flex bunny-justify-end bunny-w-full bunny-pr-4", children: jsx(CloseOutlined, { className: "bunny-text-base bunny-shadow-padding-xb", onClick: onCancel }) }), jsxs("div", { className: `bunny-flex bunny-justify-end bunny-pt-4 bunny-gap-4 ${isMobile ? 'bunny-flex-col' : 'bunny-shadow-padding-xb'}`, children: [((invoice === null || invoice === void 0 ? void 0 : invoice.html) || ((_b = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _b === void 0 ? void 0 : _b.html)) && (jsx(InvoiceQuoteView, { html: invoice ? invoice.html : (_d = (_c = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _c === void 0 ? void 0 : _c.html) !== null && _d !== void 0 ? _d : '' })), !isMobile && ((invoice === null || invoice === void 0 ? void 0 : invoice.html) || ((_e = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _e === void 0 ? void 0 : _e.html)) && (jsx(Divider, { className: "bunny-h-full", type: "vertical" })), invoice ? (jsx("div", { className: "bunny-w-full bunny-pt-12", children: jsx(PaymentForm, { onPaymentSuccess: onSuccess, invoice: invoice }) })) : quote ? (jsx(QuoteCheckout, { account: account, onFail: error => {
22247
- onFail(error);
22248
- }, onSuccess: onSuccess, quote: quote, taxationRequiredAccountFields: taxationRequiredAccountFields, token: token, onRecalculateTaxes: async () => {
22249
- if (recalculateTaxesEnabled) {
22250
- await recalculateTaxes();
22251
- }
22252
- } })) : (jsx(PaymentForm, { onPaymentSuccess: onSuccess }))] }), jsx(Footer, { className: "bunny-px-12" })] }) }));
22253
- };
22254
-
22255
- const QuoteContext = createContext({});
22256
-
22257
- const { Text: Text$n } = Typography;
22258
- const CheckoutBarInput = ({ disabled, priceListCharge, quantity, onQuantityChanged, }) => {
22259
- var _a;
22260
- const [isTooltipOpen, setIsTooltipOpen] = useState(false);
22261
- const isMobile = useIsMobile$1();
22262
- useEffect(() => {
22263
- setTimeout(() => {
22264
- setIsTooltipOpen(true);
22265
- }, 1000);
22266
- setTimeout(() => {
22267
- setIsTooltipOpen(false);
22268
- }, 6000);
22269
- }, []);
22270
- return (jsxs(Text$n, { className: `bunny-flex bunny-items-center bunny-gap-2 ${isMobile ? 'bunny-justify-between' : ''}`, children: [jsx(QuantityLabel, { activeCharge: priceListCharge }), jsx(Tooltip, { onOpenChange: setIsTooltipOpen, open: isTooltipOpen, title: "Change quantity here", styles: {
22271
- body: {
22272
- paddingTop: '0.75rem',
22273
- paddingBottom: '0.75rem',
22274
- },
22275
- }, children: jsx(Input, { id: `${(_a = priceListCharge.name) === null || _a === void 0 ? void 0 : _a.toLowerCase().replace(/ /g, '-')}-quantity-input`, className: isMobile ? 'text-right' : '', disabled: disabled, onChange: e => {
22276
- onQuantityChanged(Number(e.target.value));
22277
- }, min: priceListCharge === null || priceListCharge === void 0 ? void 0 : priceListCharge.quantityMin, max: priceListCharge === null || priceListCharge === void 0 ? void 0 : priceListCharge.quantityMax, style: { minWidth: '120px' }, type: "number", value: quantity, required: true }) })] }));
22278
- };
22279
- const QuantityLabel = ({ activeCharge }) => {
22280
- const chargeName = activeCharge.name;
22281
- return (jsx(Text$n, { className: "bunny-text-slate-500 bunny-font-medium bunny-text-nowrap", style: { fontSize: '11px' }, children: chargeName.toUpperCase() }));
22282
- };
22283
-
22284
- const periodMonthsConverter = (period) => {
22285
- if (period === 0)
22286
- return graphql.scalar('BillingPeriod', 'ONCE');
22287
- else if (period === 1)
22288
- return graphql.scalar('BillingPeriod', 'MONTHLY');
22289
- else if (period === 3)
22290
- return graphql.scalar('BillingPeriod', 'QUARTERLY');
22291
- else if (period === 6)
22292
- return graphql.scalar('BillingPeriod', 'SEMI_ANNUAL');
22293
- else if (period === 12)
22294
- return graphql.scalar('BillingPeriod', 'ANNUAL');
22295
- else
22296
- return null;
22297
- };
22298
- const billingPeriodConverter = (period) => {
22299
- if (period === graphql.scalar('BillingPeriod', 'ONCE'))
22300
- return 0;
22301
- else if (period === graphql.scalar('BillingPeriod', 'MONTHLY'))
22302
- return 1;
22303
- else if (period === graphql.scalar('BillingPeriod', 'QUARTERLY'))
22304
- return 3;
22305
- else if (period === graphql.scalar('BillingPeriod', 'SEMI_ANNUAL'))
22306
- return 6;
22307
- else
22308
- return 12;
22309
- };
22310
-
22311
- function getAddonsForBillingPeriod(billingPeriod, addonPlans) {
22312
- const flattenedPriceLists = addonPlans.flatMap(addonPlan => addonPlan.priceLists);
22313
- return flattenedPriceLists.filter(priceList => priceList.periodMonths === billingPeriodConverter(billingPeriod));
22314
- }
22315
-
22316
- const hasUnpurchasedAddonPriceLists_PlanFragment = t(`
22317
- fragment hasUnpurchasedAddonPriceLists_PlanFragment on Plan {
22318
- priceLists {
22319
- id
22320
- isVisible
22321
- periodMonths
22322
- }
22323
- }
22324
- `);
22325
- function hasUnpurchasedAddonPriceLists(maskedPriceListAddonPlans, currentSubscription, billingPeriod) {
22326
- // Read fragments
22327
- const priceListAddonPlans = maskedPriceListAddonPlans.map(maskedAddonPlan => readFragment(hasUnpurchasedAddonPriceLists_PlanFragment, maskedAddonPlan));
22328
- const addonPriceLists = getAddonsForBillingPeriod(billingPeriod, priceListAddonPlans).filter(priceList => priceList.isVisible);
22329
- const unpurchasedAddonPriceLists = addonPriceLists === null || addonPriceLists === void 0 ? void 0 : addonPriceLists.filter(addonPriceList => {
22330
- var _a;
22331
- return !((_a = currentSubscription === null || currentSubscription === void 0 ? void 0 : currentSubscription.addonSubscriptions) === null || _a === void 0 ? void 0 : _a.some(addonSubscription => addonSubscription.priceList.id === addonPriceList.id));
22332
- });
22333
- return unpurchasedAddonPriceLists.length > 0;
22334
- }
22335
-
22336
- const canSubscriptionUpgradeFromTrial = (subscription) => {
22337
- var _a;
22338
- return (((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL') &&
22339
- subscription.plan.selfServiceBuy) ||
22340
- false;
22341
- };
22342
- const canSubscriptionUpgradeFromTrialExpired = (subscription) => {
22343
- var _a;
22344
- return (((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED') &&
22345
- subscription.plan.selfServiceBuy) ||
22346
- false;
22347
- };
22348
- const isSubscriptionNotActive = (subscription) => {
22349
- var _a, _b, _c;
22350
- return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'EXPIRED') ||
22351
- ((_b = subscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === t.scalar('SubscriptionState', 'CANCELED') ||
22352
- ((_c = subscription.state) === null || _c === void 0 ? void 0 : _c.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED');
22353
- };
22354
- const isSubscriptionActiveOrPending = (subscription) => {
22355
- var _a, _b;
22356
- return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'ACTIVE') ||
22357
- ((_b = subscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === t.scalar('SubscriptionState', 'PENDING');
22358
- };
22359
- const isSubscriptionTrial = (subscription) => { var _a; return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL'); };
22360
- const isSubscriptionTrialExpired = (subscription) => { var _a; return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED'); };
22361
- // Helper function to check if charge is a discount
22362
- const isDiscount$1 = (kind) => kind === QuoteChangeKind.DISCOUNT || kind === QuoteChangeKind.FREE_PERIOD_DISCOUNT;
22363
- const hasPriceTiers = (charge) => {
22364
- var _a;
22365
- return Boolean((_a = charge === null || charge === void 0 ? void 0 : charge.priceTiers) === null || _a === void 0 ? void 0 : _a.length);
22366
- };
22367
-
22368
- const removeHTMLTagsRegex = /<br>(?=(?:\s*<[^>]*>)*$)|(<br>)|<[^>]*>/gi;
22369
- // Description is a string that can contain HTML tags. We want to remove all HTML tags except <br> tags.
22370
- const createPlanDescription = (planDescription) => {
22371
- return (planDescription || '').replace(removeHTMLTagsRegex, (_, y) => (y ? ' & ' : ''));
22372
- };
22373
- const getActivePlanPriceData = (priceList, selectedPriceList) => {
22374
- if (!priceList) {
22375
- return;
22376
- }
22377
- // If a period option is selected, return the charge that matches the selected period option
22378
- let activeBillingPLCharge;
22379
- // Default to first price list charge
22380
- let lowestPLCharge;
22381
- // Find the lowest price list charge with a billing period that matches the selected period option
22382
- if (priceList.id === (selectedPriceList === null || selectedPriceList === void 0 ? void 0 : selectedPriceList.id)) {
22383
- activeBillingPLCharge = priceList.charges[0];
22384
- }
22385
- for (let j = 0; j < priceList.charges.length; j++) {
22386
- const charge = priceList.charges[j];
22387
- if (charge.chargeType === ChargeType.USAGE || charge.featureAddon === true)
22388
- continue;
22389
- if (activeBillingPLCharge) {
22390
- // If we already found a charge with the same billing period check if this charge is lower
22391
- if (charge.basePrice < activeBillingPLCharge.basePrice &&
22392
- charge.billingPeriod === (activeBillingPLCharge === null || activeBillingPLCharge === void 0 ? void 0 : activeBillingPLCharge.billingPeriod)) {
22393
- activeBillingPLCharge = charge;
22394
- }
22395
- }
22396
- // If a period option is selected, only return the charge if it matches the selected period option
22397
- else if (selectedPriceList &&
22398
- charge.billingPeriod === periodMonthsConverter(selectedPriceList.periodMonths)) {
22399
- activeBillingPLCharge = charge;
22400
- }
22401
- // Otherwise, return the lowest price list charge
22402
- else if (charge.basePrice < ((lowestPLCharge === null || lowestPLCharge === void 0 ? void 0 : lowestPLCharge.basePrice) || -1)) {
22403
- lowestPLCharge = charge;
22404
- }
22405
- }
22406
- return {
22407
- activeCharge: activeBillingPLCharge || lowestPLCharge,
22408
- };
22409
- };
22410
- const showErrorNotification$2 = useErrorNotification();
22411
- const isPriceListDisabled = ({ priceList, upgradingSubscription, }) => {
22412
- const priceListAddonPlans = priceList === null || priceList === void 0 ? void 0 : priceList.plan.addonPlans;
22413
- if (!priceListAddonPlans) {
22414
- showErrorNotification$2('Price list addon plans are undefined');
22415
- return false;
22416
- }
22417
- const canPurchaseFeatureAddons = hasUnpurchasedFeatureAddons(priceList, upgradingSubscription);
22418
- const canPurchasePlanAddons = hasUnpurchasedAddonPriceLists(priceListAddonPlans, upgradingSubscription, periodMonthsConverter(priceList.periodMonths));
22419
- const existingSubscriptionInTrial = upgradingSubscription && canSubscriptionUpgradeFromTrial(upgradingSubscription);
22420
- const existingSubscriptionInTrialExpired = upgradingSubscription && canSubscriptionUpgradeFromTrialExpired(upgradingSubscription);
22421
- const isUpgradingSubscriptionPriceList = (upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.id) === priceList.id;
22422
- // When should priceList be disabled?
22423
- // if upgradingSubscription?.priceList.id === priceList.id
22424
- // AND the upgradingSubscription is not in trial
22425
- // AND cannot purchase feature addons
22426
- // AND cannot purchase add-on plans
22427
- // AND selfServiceBuy is false
22428
- // if upgradingSubscription?.priceList.id != priceList.id
22429
- // AND upgradingSubscription is expired trial
22430
- if (isUpgradingSubscriptionPriceList) {
22431
- return (!existingSubscriptionInTrial &&
22432
- !existingSubscriptionInTrialExpired &&
22433
- !canPurchaseFeatureAddons &&
22434
- !canPurchasePlanAddons);
22435
- }
22436
- else {
22437
- return false;
22367
+ queryClient.invalidateQueries({
22368
+ queryKey: QueryKeyFactory$1.default.createObjectKey({
22369
+ id: quote === null || quote === void 0 ? void 0 : quote.id,
22370
+ objectName: 'editingQuote',
22371
+ token,
22372
+ }),
22373
+ });
22374
+ showSuccessNotification$1('Coupon applied');
22375
+ onRecalculateTaxes();
22376
+ setCouponCode('');
22377
+ },
22378
+ onCouponRemoved: () => {
22379
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id))
22380
+ throw new Error('Quote ID is required');
22381
+ queryClient.invalidateQueries({
22382
+ queryKey: QueryKeyFactory$1.default.createObjectKey({
22383
+ id: quote === null || quote === void 0 ? void 0 : quote.id,
22384
+ objectName: 'editingQuote',
22385
+ token,
22386
+ }),
22387
+ });
22388
+ showSuccessNotification$1('Coupon removed');
22389
+ onRecalculateTaxes();
22390
+ },
22391
+ });
22392
+ 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'); });
22393
+ const checkoutMutation = useMutation({
22394
+ mutationFn: async () => {
22395
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id))
22396
+ throw new Error('Quote ID is required');
22397
+ if (paymentRequired)
22398
+ throw new Error('Payment is required');
22399
+ return await checkout({ quoteId: quote.id, token, apiHost });
22400
+ },
22401
+ onSuccess,
22402
+ onError: onFail,
22403
+ });
22404
+ async function handleCheckoutNoPayment() {
22405
+ setIsSaving(true);
22406
+ checkoutMutation.mutate();
22407
+ setIsSaving(false);
22438
22408
  }
22409
+ if (taxationRequiredAccountFields)
22410
+ return (jsx(PaymentFormWrapper, { setMaxHeight: false, children: jsx(TaxationForm, { account: account, accountId: quote.accountId }) }));
22411
+ return (jsx(PaymentFormWrapper, { setMaxHeight: false, children: paymentRequired ? (jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2 bunny-w-full", children: [jsx(PaymentForm, { onPaymentSuccess: onSuccess, quote: quote }), (couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.length) === 0 ? (jsx(Fragment, { children: upgradingSubscription &&
22412
+ 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: () => {
22413
+ couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.forEach(couponCharge => {
22414
+ var _a;
22415
+ const couponCode = (_a = couponCharge === null || couponCharge === void 0 ? void 0 : couponCharge.coupon) === null || _a === void 0 ? void 0 : _a.couponCode;
22416
+ if (couponCode) {
22417
+ removeCoupon(couponCode);
22418
+ }
22419
+ });
22420
+ }, children: "Remove coupon(s)" }))] })) : (jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-2 bunny-px-4 ${isMobile ? 'bunny-shadow-padding-x' : ''}`, children: [jsx(Button, { onClick: handleCheckoutNoPayment, type: "primary", children: isSaving ? 'Processing...' : 'Complete order' }), jsx(Text$n, { className: "bunny-text-xs bunny-text-slate-500", children: "No payment is required" })] })) }));
22439
22421
  };
22440
-
22441
- const CheckoutButton = ({ checkoutButtonDisabled, onClickCheckout, loading, tooltipText, }) => {
22422
+ const PaymentFormWrapper = ({ children, setMaxHeight, className, }) => {
22442
22423
  const isMobile = useIsMobile$1();
22443
- const TooltipWrapper = ({ children }) => {
22444
- if (tooltipText) {
22445
- return jsx(Tooltip, { title: tooltipText, children: children });
22446
- }
22447
- return jsx("div", { children: children });
22448
- };
22449
- return (jsx(TooltipWrapper, { children: jsx(Button, { className: isMobile ? 'w-full' : '', disabled: checkoutButtonDisabled, onClick: onClickCheckout, size: isMobile ? 'large' : 'middle', type: "primary", loading: loading, children: "Proceed to checkout" }) }));
22424
+ return (jsx("div", { className: `bunny-flex bunny-w-full bunny-flex-col bunny-gap-6 ${isMobile ? 'bunny-shadow-padding-xb' : ''} ${className}`, style: {
22425
+ ...(isMobile
22426
+ ? setMaxHeight
22427
+ ? { maxHeight: '60vh' }
22428
+ : {}
22429
+ : {
22430
+ width: '100%',
22431
+ maxWidth: '400px',
22432
+ }),
22433
+ }, children: children }));
22450
22434
  };
22451
22435
 
22452
- const CheckoutPrice = ({ isUsage, quote, selectedPriceList, }) => {
22436
+ const queryKeyFactory = QueryKeyFactory$1.default;
22437
+ const Checkout_QuoteFragment = t(`
22438
+ fragment Checkout_QuoteFragment on Quote {
22439
+ id
22440
+ accountId
22441
+ formattedQuote {
22442
+ html
22443
+ }
22444
+ ...QuoteCheckout_QuoteFragment
22445
+ }
22446
+ `, [QuoteCheckout_QuoteFragment]);
22447
+ const Checkout = ({ onCancel, onSuccess, onFail, onRecalculateTaxes, invoice, open, quote: maskedQuote, isUpdatingQuote, }) => {
22448
+ var _a, _b, _c, _d, _e;
22449
+ const { apiHost } = useContext(BunnyContext);
22453
22450
  const isMobile = useIsMobile$1();
22454
- if (!isUsage && (!selectedPriceList || (quote === null || quote === void 0 ? void 0 : quote.periodAmount) === undefined))
22451
+ const token = useToken();
22452
+ // Read fragments
22453
+ const quote = readFragment(Checkout_QuoteFragment, maskedQuote);
22454
+ const hasTaxPlugin = useHasTaxPlugin({
22455
+ apiHost,
22456
+ token,
22457
+ });
22458
+ // Queries
22459
+ const { data: taxationRequiredAccountFields, isLoading: isLoadingTaxationRequiredAccountFields } = useQuery({
22460
+ queryKey: ['getTaxationRequiredAccountFields', token],
22461
+ queryFn: () => getTaxationRequiredAccountFields({ apiHost, token }),
22462
+ enabled: Boolean(quote),
22463
+ staleTime: 0,
22464
+ });
22465
+ const { data: account, isLoading: isLoadingAccount } = useQuery({
22466
+ queryKey: ['account', quote === null || quote === void 0 ? void 0 : quote.accountId],
22467
+ queryFn: () => (quote === null || quote === void 0 ? void 0 : quote.accountId) &&
22468
+ getAccount$1({ id: quote.accountId, apiHost, token, componentsVersion: PACKAGE_VERSION }),
22469
+ enabled: Boolean(quote === null || quote === void 0 ? void 0 : quote.accountId) && ((taxationRequiredAccountFields === null || taxationRequiredAccountFields === void 0 ? void 0 : taxationRequiredAccountFields.length) || 0) > 0,
22470
+ });
22471
+ // Use onRecalculateTaxes callback because parents need to define recalculateTaxes to get and set the right quote data they need
22472
+ async function recalculateTaxes() {
22473
+ if (quote) {
22474
+ if (!quote.id)
22475
+ throw new Error('Quote ID is required');
22476
+ onRecalculateTaxes(quote.id);
22477
+ }
22478
+ return {};
22479
+ }
22480
+ const recalculateTaxesEnabled = Boolean(quote) &&
22481
+ open &&
22482
+ hasTaxPlugin &&
22483
+ !taxationRequiredAccountFields &&
22484
+ !isLoadingTaxationRequiredAccountFields &&
22485
+ !isUpdatingQuote;
22486
+ useQuery({
22487
+ queryKey: queryKeyFactory.createQuoteTaxCalculateKey({
22488
+ id: (_a = quote === null || quote === void 0 ? void 0 : quote.id) !== null && _a !== void 0 ? _a : undefined,
22489
+ token,
22490
+ }),
22491
+ queryFn: recalculateTaxes,
22492
+ // Recalculate taxes if the quote is open, has a tax plugin, and the taxation required account fields are not required
22493
+ enabled: recalculateTaxesEnabled,
22494
+ staleTime: 0,
22495
+ });
22496
+ if (!open || isLoadingTaxationRequiredAccountFields || isLoadingAccount)
22455
22497
  return null;
22456
- const convertedPeriodMonths = periodMonthsConverter(selectedPriceList.periodMonths);
22457
- const periodLabel = convertedPeriodMonths ? PERIOD_LABELS[convertedPeriodMonths] : 'undefined';
22458
- return (jsx("div", { className: `bunny-font-medium ${isMobile ? 'bunny-text-2xl' : ''}`, children: isUsage
22459
- ? 'Usage based pricing'
22460
- : selectedPriceList && (quote === null || quote === void 0 ? void 0 : quote.periodAmount) !== undefined
22461
- ? `${formatCurrency$1(quote.periodAmount, selectedPriceList === null || selectedPriceList === void 0 ? void 0 : selectedPriceList.currencyId, 0)} / ${periodLabel}`
22462
- : '' }));
22498
+ 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
22499
+ bunny-overflow-auto bunny-height-full`, style: {
22500
+ zIndex: 1001,
22501
+ }, children: jsxs("div", { className: `bunny-flex bunny-flex-col bunny-grow bunny-pt-4 ${isMobile ? 'bunny-pb-4' : 'bunny-pb-8'} bunny-content-container`, children: [jsx("div", { className: "bunny-flex bunny-justify-end bunny-w-full bunny-pr-4", children: jsx(CloseOutlined, { className: "bunny-text-base bunny-shadow-padding-xb", onClick: onCancel }) }), jsxs("div", { className: `bunny-flex bunny-justify-end bunny-pt-4 bunny-gap-4 ${isMobile ? 'bunny-flex-col' : 'bunny-shadow-padding-xb'}`, children: [((invoice === null || invoice === void 0 ? void 0 : invoice.html) || ((_b = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _b === void 0 ? void 0 : _b.html)) && (jsx(InvoiceQuoteView, { html: invoice ? invoice.html : (_d = (_c = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _c === void 0 ? void 0 : _c.html) !== null && _d !== void 0 ? _d : '' })), !isMobile && ((invoice === null || invoice === void 0 ? void 0 : invoice.html) || ((_e = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _e === void 0 ? void 0 : _e.html)) && (jsx(Divider, { className: "bunny-h-full", type: "vertical" })), invoice ? (jsx("div", { className: "bunny-w-full bunny-pt-12", children: jsx(PaymentForm, { onPaymentSuccess: onSuccess, invoice: invoice }) })) : quote ? (jsx(QuoteCheckout, { account: account, onFail: error => {
22502
+ onFail(error);
22503
+ }, onSuccess: onSuccess, quote: quote, taxationRequiredAccountFields: taxationRequiredAccountFields, token: token, onRecalculateTaxes: async () => {
22504
+ if (recalculateTaxesEnabled) {
22505
+ await recalculateTaxes();
22506
+ }
22507
+ } })) : (jsx(PaymentForm, { onPaymentSuccess: onSuccess }))] }), jsx(Footer, { className: "bunny-px-12" })] }) }));
22463
22508
  };
22464
22509
 
22510
+ function canEditChargeQuantity(charge) {
22511
+ if (!charge)
22512
+ return false;
22513
+ if (charge.chargeType === graphql.scalar('ChargeType', 'USAGE'))
22514
+ return false;
22515
+ if (charge.pricingModel === graphql.scalar('PricingModel', 'FLAT'))
22516
+ return false;
22517
+ return true;
22518
+ }
22519
+
22465
22520
  const { Text: Text$m } = Typography;
22466
- const CheckoutBarSummarySection = ({ open, selectedPriceList, onClickCheckout, }) => {
22521
+ const CheckoutBarInput = ({ disabled, priceListCharge, quantity, onQuantityChanged, }) => {
22467
22522
  var _a;
22468
- // Context
22469
- const { quote: quoteData, isQuotePending, isUpdatingQuote } = useContext(QuoteContext);
22470
- const quote = quoteData;
22471
- const { upgradingSubscription, isInPreviewMode } = useContext(SubscriptionsContext);
22472
- // Hooks
22473
- const token = useToken();
22474
- const { paymentPlugins } = usePaymentPlugins(undefined);
22475
- const queryClient = useQueryClient();
22523
+ const [isTooltipOpen, setIsTooltipOpen] = useState(false);
22476
22524
  const isMobile = useIsMobile$1();
22477
- // Derived state
22478
- const isFetching = queryClient.isFetching({
22479
- queryKey: QueryKeyFactory$1.default.planChangeOptionsKey({
22480
- subscriptionId: upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.id,
22481
- token,
22482
- }),
22483
- });
22484
- // When should checkout button be disabled?
22485
- const isUpdatingCharges = (quote === null || quote === void 0 ? void 0 : quote.quoteChanges.some(qc => qc.kind === 'UPDATE' && qc.charges.length > 0)) || false;
22486
- const isUpgradingSubscription = selectedPriceList.id !== (upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.id);
22487
- const disableCheckoutButton = Boolean(!selectedPriceList || isFetching || !(isUpgradingSubscription || isUpdatingCharges) || open);
22488
- const checkoutButtonDisabled = (quote === null || quote === void 0 ? void 0 : quote.amountDue) && (quote === null || quote === void 0 ? void 0 : quote.amountDue) > 0 ? false : disableCheckoutButton;
22489
- const activeCharge = (_a = getActivePlanPriceData(selectedPriceList, selectedPriceList)) === null || _a === void 0 ? void 0 : _a.activeCharge;
22490
- const isUsage = (activeCharge === null || activeCharge === void 0 ? void 0 : activeCharge.chargeType) === ChargeType.USAGE;
22491
- const hasPaymentPlugins = Boolean(paymentPlugins === null || paymentPlugins === void 0 ? void 0 : paymentPlugins.length);
22492
- return (jsxs(Text$m, { className: `bunny-flex bunny-items-center bunny-gap-4 ${isMobile ? 'bunny-flex-col' : ''}`, children: [quote && (jsxs("div", { className: `bunny-flex ${isMobile ? 'items-center justify-between w-full' : 'flex-col'}`, children: [jsx("div", { className: "bunny-text-slate-500 bunny-font-medium bunny-text-right", style: { fontSize: '11px' }, children: "TOTAL" }), jsx(CheckoutPrice, { isUsage: isUsage, quote: quote, selectedPriceList: selectedPriceList })] })), jsx(CheckoutButton, { checkoutButtonDisabled: checkoutButtonDisabled || !hasPaymentPlugins || isInPreviewMode, onClickCheckout: onClickCheckout, loading: isQuotePending || isUpdatingQuote, tooltipText: isInPreviewMode
22493
- ? 'Checkout is disabled in preview mode'
22494
- : !hasPaymentPlugins
22495
- ? 'Cannot checkout. No valid payment plugins found. Please contact your administrator.'
22496
- : undefined })] }));
22525
+ useEffect(() => {
22526
+ setTimeout(() => {
22527
+ setIsTooltipOpen(true);
22528
+ }, 1000);
22529
+ setTimeout(() => {
22530
+ setIsTooltipOpen(false);
22531
+ }, 6000);
22532
+ }, []);
22533
+ return (jsxs(Text$m, { className: `bunny-flex bunny-items-center bunny-gap-2 ${isMobile ? 'bunny-justify-between' : ''}`, children: [jsx(QuantityLabel, { activeCharge: priceListCharge }), jsx(Tooltip, { onOpenChange: setIsTooltipOpen, open: isTooltipOpen, title: "Change quantity here", styles: {
22534
+ body: {
22535
+ paddingTop: '0.75rem',
22536
+ paddingBottom: '0.75rem',
22537
+ },
22538
+ }, children: jsx(Input, { id: `${(_a = priceListCharge.name) === null || _a === void 0 ? void 0 : _a.toLowerCase().replace(/ /g, '-')}-quantity-input`, className: isMobile ? 'text-right' : '', disabled: disabled, onChange: e => {
22539
+ onQuantityChanged(Number(e.target.value));
22540
+ }, min: priceListCharge === null || priceListCharge === void 0 ? void 0 : priceListCharge.quantityMin, max: priceListCharge === null || priceListCharge === void 0 ? void 0 : priceListCharge.quantityMax, style: { minWidth: '120px' }, type: "number", value: quantity, required: true }) })] }));
22541
+ };
22542
+ const QuantityLabel = ({ activeCharge }) => {
22543
+ const chargeName = activeCharge.name;
22544
+ return (jsx(Text$m, { className: "bunny-text-slate-500 bunny-font-medium bunny-text-nowrap", style: { fontSize: '11px' }, children: chargeName.toUpperCase() }));
22497
22545
  };
22498
22546
 
22499
22547
  const PlanPickerCheckoutBar_QuoteFragment = t(`
@@ -22513,8 +22561,8 @@ const PlanPickerCheckoutBar_QuoteFragment = t(`
22513
22561
  `, [Checkout_QuoteFragment]);
22514
22562
  const PlanPickerCheckoutBar = ({ selectedPriceList, handlePortalErrors, onCheckoutSuccess, }) => {
22515
22563
  // Context
22516
- const { shadow, upgradingSubscription } = useContext(SubscriptionsContext);
22517
- const { quote: maskedQuote, onChangeQuantity, getFeatureQuantity, isFeatureAddonsLoading, isUpdatingQuote, } = useContext(QuoteContext);
22564
+ const { shadow } = useContext(SubscriptionsContext);
22565
+ const { quote: maskedQuote, onChangeQuantity, getFeatureQuantity, onRecalculateTaxes, isFeatureAddonsLoading, isUpdatingQuote, } = useContext(QuoteContext);
22518
22566
  // Read fragments
22519
22567
  const quote = readFragment(PlanPickerCheckoutBar_QuoteFragment, maskedQuote);
22520
22568
  // Local state
@@ -22562,9 +22610,6 @@ const PlanPickerCheckoutBar = ({ selectedPriceList, handlePortalErrors, onChecko
22562
22610
  const isFeatureAddon = charge.featureAddon;
22563
22611
  const quantity = getFeatureQuantity((_d = charge.feature) === null || _d === void 0 ? void 0 : _d.id, charge.id);
22564
22612
  const maybeIsChargeLoading = isFeatureAddon && isFeatureAddonsLoading;
22565
- const showInput = selectedPriceList.id !== (upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.id);
22566
- if (!isFeatureAddon && !showInput)
22567
- return null;
22568
22613
  if (!quantity)
22569
22614
  return null;
22570
22615
  // if charge is a feature addon, and a corresponding quote charge is not found in quote, return null
@@ -22575,9 +22620,40 @@ const PlanPickerCheckoutBar = ({ selectedPriceList, handlePortalErrors, onChecko
22575
22620
  return (jsx(CheckoutBarInput, { disabled: isDisabled, priceListCharge: charge, quantity: quantity, onQuantityChanged: quantity => {
22576
22621
  onChangeQuantity(charge.id, quantity);
22577
22622
  } }, index));
22578
- }) }), jsx(CheckoutBarSummarySection, { onClickCheckout: () => setPayModalVisible(true), open: payModalVisible, selectedPriceList: selectedPriceList }), jsx(Checkout, { onCancel: () => setPayModalVisible(false), onFail: error => handlePortalErrors === null || handlePortalErrors === void 0 ? void 0 : handlePortalErrors(error), onSuccess: handleCheckoutSuccess, open: payModalVisible, quote: quote, token: token, isUpdatingQuote: isUpdatingQuote })] }));
22623
+ }) }), jsx(CheckoutBarSummarySection, { onClickCheckout: () => setPayModalVisible(true), selectedPriceList: selectedPriceList }), jsx(Checkout, { onCancel: () => setPayModalVisible(false), onFail: error => handlePortalErrors === null || handlePortalErrors === void 0 ? void 0 : handlePortalErrors(error), onSuccess: handleCheckoutSuccess, onRecalculateTaxes: onRecalculateTaxes, open: payModalVisible, quote: quote, token: token, isUpdatingQuote: isUpdatingQuote })] }));
22579
22624
  };
22580
22625
 
22626
+ const useQuoteUpdateFeatureAddon_QuoteFragment = t(`
22627
+ fragment useQuoteUpdateFeatureAddon_QuoteFragment on Quote {
22628
+ id
22629
+ startDate
22630
+ }
22631
+ `);
22632
+
22633
+ const FeatureAddonRow_QuoteFragment = t(`
22634
+ fragment FeatureAddonRow_QuoteFragment on Quote {
22635
+ ...useQuoteUpdateFeatureAddon_QuoteFragment
22636
+ }
22637
+ `, [useQuoteUpdateFeatureAddon_QuoteFragment]);
22638
+
22639
+ const useToggleAddonPlan_QuoteFragment = t(`
22640
+ fragment useToggleAddonPlan_QuoteFragment on Quote {
22641
+ quoteChanges {
22642
+ priceList {
22643
+ id
22644
+ }
22645
+ id
22646
+ }
22647
+ id
22648
+ }
22649
+ `);
22650
+
22651
+ const AddonPlanRow_QuoteFragment = t(`
22652
+ fragment AddonPlanRow_QuoteFragment on Quote {
22653
+ ...useToggleAddonPlan_QuoteFragment
22654
+ }
22655
+ `, [useToggleAddonPlan_QuoteFragment]);
22656
+
22581
22657
  /**
22582
22658
  * Central quote fragment for QuoteProvider context.
22583
22659
  *
@@ -22595,6 +22671,7 @@ const QuoteContext_QuoteFragment = t(`
22595
22671
  id
22596
22672
  currencyId
22597
22673
  amountDue
22674
+ startDate
22598
22675
  quoteChanges {
22599
22676
  id
22600
22677
  kind
@@ -22618,75 +22695,17 @@ const QuoteContext_QuoteFragment = t(`
22618
22695
  }
22619
22696
  }
22620
22697
  ...PlanPickerCheckoutBar_QuoteFragment
22621
- }
22622
- `, [QuoteFields_QuoteFragment, PlanPickerCheckoutBar_QuoteFragment]);
22623
-
22624
- // Deprecated: Keeping this for now because its used in many places
22625
- const QUOTE_FIELDS = (removeFormattedQuoteField) => `
22626
- fragment QuoteFields on Quote {
22627
- accountId
22628
- amount
22629
- amountDue
22630
- smallUnitAmountDue
22631
- currencyId
22632
- ${removeFormattedQuoteField ? '' : `formattedQuote { html }`}
22633
- id
22634
- payableId
22635
- periodAmount
22636
- subtotal
22637
- taxAmount
22638
- startDate
22639
- amountsByPeriod {
22640
- amount
22641
- startDate
22642
- }
22643
- kind
22644
- quoteChanges {
22645
- currencyId
22646
- id
22647
- kind
22648
- charges {
22649
- subtotal
22650
- amountsByPeriod {
22651
- amount
22652
- startDate
22653
- }
22654
- amount
22655
- billingPeriod
22656
- currencyId
22657
- feature {
22658
- id
22659
- unitName
22660
- }
22661
- id
22662
- name
22663
- priceListCharge {
22664
- id
22665
- quantityMax
22666
- quantityMin
22667
- selfServiceQuantity
22668
- }
22669
- priceList {
22670
- id
22671
- }
22672
- coupon {
22673
- couponCode
22674
- }
22675
- quantity
22676
- kind
22677
- }
22678
- priceList {
22679
- id
22680
- plan {
22681
- name
22682
- }
22683
- product {
22684
- name
22685
- }
22686
- }
22687
- }
22688
- }
22689
- `;
22698
+ ...CheckoutBarSummarySection_QuoteFragment
22699
+ ...AddonPlanRow_QuoteFragment
22700
+ ...FeatureAddonRow_QuoteFragment
22701
+ }
22702
+ `, [
22703
+ PlanPickerCheckoutBar_QuoteFragment,
22704
+ CheckoutBarSummarySection_QuoteFragment,
22705
+ AddonPlanRow_QuoteFragment,
22706
+ FeatureAddonRow_QuoteFragment,
22707
+ ]);
22708
+
22690
22709
  const FormattedQuoteField_QuoteFragment = t(`
22691
22710
  fragment FormattedQuoteField_QuoteFragment on Quote {
22692
22711
  formattedQuote {
@@ -22694,7 +22713,7 @@ const FormattedQuoteField_QuoteFragment = t(`
22694
22713
  }
22695
22714
  }
22696
22715
  `);
22697
- const query$3 = t(`
22716
+ const query$5 = t(`
22698
22717
  query quote($id: ID, $removeFormattedQuoteField: Boolean!) {
22699
22718
  quote(id: $id) {
22700
22719
  ...QuoteContext_QuoteFragment
@@ -22703,7 +22722,7 @@ const query$3 = t(`
22703
22722
  }
22704
22723
  `, [QuoteContext_QuoteFragment, FormattedQuoteField_QuoteFragment]);
22705
22724
  const getQuote$1 = async ({ id, token, apiHost, removeFormattedQuoteField = false, }) => {
22706
- const response = await execute(query$3, { apiHost, token }, { id, removeFormattedQuoteField });
22725
+ const response = await execute(query$5, { apiHost, token }, { id, removeFormattedQuoteField });
22707
22726
  return response === null || response === void 0 ? void 0 : response.quote;
22708
22727
  };
22709
22728
 
@@ -22808,7 +22827,7 @@ function Signup({ companyName, priceListCode, returnUrl, couponCode, className,
22808
22827
  });
22809
22828
  const { mutate: recalculateTaxesMutation } = useMutation({
22810
22829
  mutationFn: (quoteId) => {
22811
- return quoteRecalculateTaxes({ token, apiHost, quoteId });
22830
+ return quoteRecalculateTaxes$2({ token, apiHost, quoteId });
22812
22831
  },
22813
22832
  onError: (error) => {
22814
22833
  if (!error[0].message.includes('Ensure that you have a taxation plugin')) {
@@ -22989,7 +23008,7 @@ const useQuoteQueryData = (quoteId) => {
22989
23008
  return data;
22990
23009
  };
22991
23010
 
22992
- const useSetQuoteQueryData = () => {
23011
+ const useSetQuoteQueryData$1 = () => {
22993
23012
  const token = useToken();
22994
23013
  const queryClient = useQueryClient();
22995
23014
  const setQuoteQueryData = (quoteId, quote) => {
@@ -23028,6 +23047,9 @@ const QuantityInput_QuoteFragment = t(`
23028
23047
  }
23029
23048
  `, []);
23030
23049
 
23050
+ const useQuoteIsLoadingState = (isLoading) => useState(isLoading !== null && isLoading !== void 0 ? isLoading : false);
23051
+ const [QuoteIsLoadingProvider, useQuoteIsLoading] = createStateContext(useQuoteIsLoadingState);
23052
+
23031
23053
  const QuoteChangeSummarySection_QuoteFragment = t(`
23032
23054
  fragment QuoteChangeSummarySection_QuoteFragment on Quote {
23033
23055
  id
@@ -23039,10 +23061,11 @@ const QuoteChangeSummarySection_QuoteFragment = t(`
23039
23061
  const QuoteChangeSummarySection = ({ openCheckout, errorUpdatingQuantity, }) => {
23040
23062
  const isMobile = useIsMobile$1();
23041
23063
  const [quoteId] = useQuoteId();
23064
+ const [isQuoteLoading] = useQuoteIsLoading();
23042
23065
  const maskedQuote = useQuoteQueryData(quoteId);
23043
23066
  const quote = readFragment(QuoteChangeSummarySection_QuoteFragment, maskedQuote);
23044
- const disabled = !quoteId || !quote || errorUpdatingQuantity;
23045
- return (jsxs("div", { className: "bunny-flex bunny-flex-col bunny-items-end", children: [quote && !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(quote), (quote === null || quote === void 0 ? void 0 : quote.currencyId) || '') })] })), jsx("div", { className: `bunny-flex bunny-items-center bunny-justify-end ${isMobile ? 'bunny-w-full' : ''}`, children: jsx(Button, { className: "bunny-w-full", onClick: openCheckout, disabled: disabled, size: isMobile ? 'large' : 'middle', type: "primary", children: "Proceed to checkout" }) })] }));
23067
+ const disabled = !quoteId || !quote || errorUpdatingQuantity || isQuoteLoading;
23068
+ return (jsxs("div", { className: "bunny-flex bunny-flex-col bunny-items-end", children: [quote && !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(quote), (quote === null || quote === void 0 ? void 0 : quote.currencyId) || '') })] })), jsx("div", { className: `bunny-flex bunny-items-center bunny-justify-end ${isMobile ? 'bunny-w-full' : ''}`, children: jsx(Button, { className: "bunny-w-full", onClick: openCheckout, disabled: disabled, size: isMobile ? 'large' : 'middle', type: "primary", loading: isQuoteLoading, children: "Proceed to checkout" }) })] }));
23046
23069
  };
23047
23070
 
23048
23071
  const QuantityDrawer_QuoteFragment = t(`
@@ -23054,7 +23077,7 @@ const QuantityDrawer_QuoteFragment = t(`
23054
23077
  }
23055
23078
  `, [Checkout_QuoteFragment, QuantityInput_QuoteFragment, QuoteChangeSummarySection_QuoteFragment]);
23056
23079
 
23057
- const mutation$4 = t(`
23080
+ const mutation$c = t(`
23058
23081
  mutation QuoteChargeCreate(
23059
23082
  $quoteChangeId: ID!
23060
23083
  $startDate: ISO8601Date!
@@ -23089,11 +23112,11 @@ const mutation$4 = t(`
23089
23112
  `, [QuantityDrawer_QuoteFragment]);
23090
23113
  const quoteChargeCreate$1 = async ({ price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId, token, apiHost, }) => {
23091
23114
  var _a;
23092
- const response = await execute(mutation$4, { apiHost, token }, { price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId });
23115
+ const response = await execute(mutation$c, { apiHost, token }, { price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId });
23093
23116
  return (_a = response.quoteChargeCreate) === null || _a === void 0 ? void 0 : _a.quoteCharge;
23094
23117
  };
23095
23118
 
23096
- const mutation$3 = t(`
23119
+ const mutation$b = t(`
23097
23120
  mutation QuoteChargeUpdate($quoteChargeId: ID!, $quantity: Int) {
23098
23121
  quoteChargeUpdate(quoteChargeId: $quoteChargeId, quantity: $quantity) {
23099
23122
  quoteCharge {
@@ -23112,14 +23135,29 @@ const mutation$3 = t(`
23112
23135
  `, [QuantityDrawer_QuoteFragment]);
23113
23136
  const quoteChargeUpdate = async (quoteChargeId, quantity, apiHost, token) => {
23114
23137
  var _a, _b;
23115
- const response = await execute(mutation$3, { apiHost, token }, { quoteChargeId, quantity });
23138
+ const response = await execute(mutation$b, { apiHost, token }, { quoteChargeId, quantity });
23116
23139
  if ((_a = response.quoteChargeUpdate) === null || _a === void 0 ? void 0 : _a.errors) {
23117
23140
  throw new Error(response.quoteChargeUpdate.errors[0]);
23118
23141
  }
23119
23142
  return (_b = response.quoteChargeUpdate) === null || _b === void 0 ? void 0 : _b.quoteCharge;
23120
23143
  };
23121
23144
 
23122
- const mutation$2 = t(`
23145
+ const mutation$a = t(`
23146
+ mutation QuoteDelete($id: ID!) {
23147
+ quoteDelete(id: $id) {
23148
+ errors
23149
+ quote {
23150
+ id
23151
+ }
23152
+ }
23153
+ }
23154
+ `, []);
23155
+ const quoteDelete = async ({ id, token, apiHost }) => {
23156
+ const response = await execute(mutation$a, { apiHost, token }, { id });
23157
+ return response.quoteDelete;
23158
+ };
23159
+
23160
+ const mutation$9 = t(`
23123
23161
  mutation quoteSubscriptionUpdate($subscriptionIds: [ID!]!) {
23124
23162
  quoteSubscriptionUpdate(subscriptionIds: $subscriptionIds) {
23125
23163
  quote {
@@ -23148,7 +23186,7 @@ const mutation$2 = t(`
23148
23186
  `, [QuantityDrawer_QuoteFragment]);
23149
23187
  const quoteSubscriptionUpdate = async (subscriptionIds, apiHost, token) => {
23150
23188
  var _a, _b;
23151
- const response = await execute(mutation$2, { apiHost, token }, { subscriptionIds });
23189
+ const response = await execute(mutation$9, { apiHost, token }, { subscriptionIds });
23152
23190
  if ((_a = response.quoteSubscriptionUpdate) === null || _a === void 0 ? void 0 : _a.errors) {
23153
23191
  throw new Error(response.quoteSubscriptionUpdate.errors[0]);
23154
23192
  }
@@ -23217,6 +23255,23 @@ const canShowChangeQuantities = ({ subscriptions, }) => {
23217
23255
  });
23218
23256
  };
23219
23257
 
23258
+ /**
23259
+ * Note: It is good practice to isolate useEffects into their own components.
23260
+ * This approach helps prevent unnecessary re-renders when data is unchanged,
23261
+ * since useEffect will only be triggered in this dedicated sibling component.
23262
+ */
23263
+ const QuoteIsLoadingUpdater = ({ quoteIsPending }) => {
23264
+ const [, setQuoteIsLoading] = useQuoteIsLoading();
23265
+ const prevValue = useRef(quoteIsPending);
23266
+ useEffect(() => {
23267
+ if (prevValue.current !== quoteIsPending) {
23268
+ setQuoteIsLoading(quoteIsPending);
23269
+ prevValue.current = quoteIsPending;
23270
+ }
23271
+ }, [quoteIsPending, setQuoteIsLoading]);
23272
+ return null;
23273
+ };
23274
+
23220
23275
  const QuantityInput_SubscriptionChargeFragment = t(`
23221
23276
  fragment QuantityInput_SubscriptionChargeFragment on SubscriptionCharge {
23222
23277
  id
@@ -23228,7 +23283,6 @@ const QuantityInput_SubscriptionChargeFragment = t(`
23228
23283
  const QuantityInput_SubscriptionFragment = t(`
23229
23284
  fragment QuantityInput_SubscriptionFragment on Subscription {
23230
23285
  id
23231
- state
23232
23286
  priceList {
23233
23287
  id
23234
23288
  }
@@ -23244,6 +23298,16 @@ const QuantityInput_SubscriptionFragment = t(`
23244
23298
  CanShowQuantitiesInput_SubscriptionFragment,
23245
23299
  ]);
23246
23300
  const DEBOUNCE_TIME$1 = 1000;
23301
+ /**
23302
+ * Design note:
23303
+ * If the quantity is cleared by the user (quantity becomes undefined), we delete the quote.
23304
+ *
23305
+ * Rationale:
23306
+ * The user may next change the quantity for a charge on a different subscription, and we need to
23307
+ * allow creating a new quote/quoteChange in that context. Currently there is no way to create a
23308
+ * quoteChange of kind "update" without first calling `quoteSubscriptionUpdate`, so we delete the
23309
+ * existing quote to reset the flow.
23310
+ */
23247
23311
  const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription, setUpdatingChargeQuantityId, updatingChargeQuantityId, setErrorUpdatingQuantity, }) => {
23248
23312
  // Context
23249
23313
  const token = useToken();
@@ -23258,7 +23322,7 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23258
23322
  const quote = readFragment(QuantityInput_QuoteFragment, maskedQuote);
23259
23323
  // Hooks
23260
23324
  const showErrorNotification = useErrorNotification();
23261
- const { setQuoteQueryData } = useSetQuoteQueryData();
23325
+ const { setQuoteQueryData } = useSetQuoteQueryData$1();
23262
23326
  const quantityDisabled =
23263
23327
  // If we are editing a quote, we disable the quantity input
23264
23328
  // If we don't have a quantity, we disable the quantity input
@@ -23271,7 +23335,7 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23271
23335
  !charge.selfServiceQuantity;
23272
23336
  const value = quantity === undefined ? '' : quantity;
23273
23337
  // Mutations
23274
- const { mutate: createCharge } = useMutation({
23338
+ const { mutate: createCharge, isPending: isCreatingCharge } = useMutation({
23275
23339
  mutationFn: quoteChargeCreate$1,
23276
23340
  onSuccess: response => {
23277
23341
  var _a, _b;
@@ -23286,7 +23350,23 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23286
23350
  setErrorUpdatingQuantity(true);
23287
23351
  },
23288
23352
  });
23289
- const createQuote = useMutation({
23353
+ const { mutate: deleteQuote, isPending: isDeletingQuote } = useMutation({
23354
+ mutationFn: quoteDelete,
23355
+ onSuccess: response => {
23356
+ var _a;
23357
+ const quoteId = (_a = response === null || response === void 0 ? void 0 : response.quote) === null || _a === void 0 ? void 0 : _a.id;
23358
+ if (!quoteId) {
23359
+ showErrorNotification('quoteId is required');
23360
+ return;
23361
+ }
23362
+ setQuoteQueryData(quoteId, null);
23363
+ setQuoteId(undefined);
23364
+ },
23365
+ onError: () => {
23366
+ setErrorUpdatingQuantity(true);
23367
+ },
23368
+ });
23369
+ const { mutate: createQuote, isPending: isCreatingQuote } = useMutation({
23290
23370
  mutationFn: (subscriptionId) => quoteSubscriptionUpdate([subscriptionId], apiHost, token),
23291
23371
  onSuccess: quote => {
23292
23372
  var _a, _b, _c;
@@ -23314,7 +23394,7 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23314
23394
  setErrorUpdatingQuantity(true);
23315
23395
  },
23316
23396
  });
23317
- const updateQuoteCharge = useMutation({
23397
+ const { mutate: updateQuoteCharge, isPending: isUpdatingQuoteCharge } = useMutation({
23318
23398
  mutationFn: ({ quoteChargeId, quantity, }) => {
23319
23399
  if (!quoteChargeId)
23320
23400
  throw new Error('quoteChargeId is required');
@@ -23336,26 +23416,35 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23336
23416
  });
23337
23417
  const onChangeQuantity = (value) => {
23338
23418
  var _a;
23419
+ // Cancel all debounced functions first
23420
+ debouncedQuantityUpdate.cancel();
23421
+ debouncedDeleteQuote.cancel();
23339
23422
  // Handle empty string - don't convert to 0, keep it as undefined
23340
23423
  const quantity = value === '' ? undefined : isNaN(parseInt(value)) ? 0 : parseInt(value);
23341
23424
  setQuantity(quantity);
23342
23425
  if (quantity === undefined) {
23343
23426
  setUpdatingChargeQuantityId(undefined);
23427
+ if (quoteId) {
23428
+ // Only delete the quote if it exists
23429
+ debouncedDeleteQuote(quoteId);
23430
+ }
23344
23431
  }
23345
23432
  else {
23346
23433
  if (!(charge === null || charge === void 0 ? void 0 : charge.priceListChargeId)) {
23347
23434
  showErrorNotification('Charge ID is not found');
23348
23435
  return;
23349
23436
  }
23350
- // The set charge id is used to disable all other quantity inputs
23437
+ // Used to disable all other quantity inputs for this subscription
23351
23438
  setUpdatingChargeQuantityId(getUpdatingChargeQuantityId(charge.priceListChargeId, subscription.id));
23352
23439
  const quantityDelta = quantity - ((_a = charge.quantity) !== null && _a !== void 0 ? _a : 0);
23353
- debouncedQuantityUpdate.cancel();
23354
- debouncedQuantityUpdate(charge.priceListChargeId, quantityDelta, quantity, subscription.id, quote, quoteId);
23440
+ debouncedQuantityUpdate(charge.priceListChargeId, quantityDelta, subscription.id, quote, quoteId);
23355
23441
  }
23356
23442
  };
23357
- const debouncedQuantityUpdate = useCallback(lodashExports.debounce((priceListChargeId, quantityDelta, quantity, subscriptionId, quote, quoteId) => {
23358
- var _a, _b, _c;
23443
+ const debouncedDeleteQuote = useCallback(lodashExports.debounce((quoteId) => {
23444
+ deleteQuote({ id: quoteId, apiHost, token });
23445
+ }, DEBOUNCE_TIME$1), []);
23446
+ const debouncedQuantityUpdate = useCallback(lodashExports.debounce((priceListChargeId, quantityDelta, subscriptionId, quote, quoteId) => {
23447
+ var _a;
23359
23448
  if (quantityDelta === 0) {
23360
23449
  setErrorUpdatingQuantity(true);
23361
23450
  showErrorNotification('New quantity cannot be the same as current');
@@ -23363,37 +23452,22 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23363
23452
  }
23364
23453
  // If we are not editing a quote, we create a new one
23365
23454
  if (quoteId === undefined) {
23366
- createQuote.mutate(subscriptionId);
23455
+ createQuote(subscriptionId);
23367
23456
  }
23368
23457
  else {
23369
23458
  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); });
23370
23459
  const quoteCharge = quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.charges.find(charge => { var _a; return ((_a = charge === null || charge === void 0 ? void 0 : charge.priceListCharge) === null || _a === void 0 ? void 0 : _a.id) === priceListChargeId; });
23371
23460
  if (quoteCharge) {
23372
- updateQuoteCharge.mutate({
23461
+ updateQuoteCharge({
23373
23462
  quoteChargeId: quoteCharge.id,
23374
23463
  quantity: quantityDelta,
23375
23464
  });
23376
23465
  }
23377
- else {
23378
- 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) === priceListChargeId; });
23379
- if (!(subscriptionCharge === null || subscriptionCharge === void 0 ? void 0 : subscriptionCharge.id))
23380
- throw new Error('subscriptionCharge id is required');
23381
- if (!(quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.id))
23382
- throw new Error('quoteChange id is required');
23383
- createCharge({
23384
- apiHost,
23385
- quantity, // This is a new charge so use quantity instead of quantityDelta
23386
- quoteChangeId: quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.id,
23387
- startDate: formatDateForApi(dayjs()),
23388
- subscriptionChargeId: subscriptionCharge.id,
23389
- token,
23390
- });
23391
- }
23392
23466
  }
23393
23467
  }, DEBOUNCE_TIME$1), []);
23394
- return (jsx(Fragment, { children: jsx(Input, { className: "bunny-text-right", disabled: quantityDisabled, onChange: e => {
23395
- onChangeQuantity(e.target.value);
23396
- }, style: { width: '96px' }, value: value }) }));
23468
+ return (jsxs(Fragment, { children: [jsx(Input, { className: "bunny-text-right", disabled: quantityDisabled, onChange: e => {
23469
+ onChangeQuantity(e.target.value);
23470
+ }, style: { width: '96px' }, value: value }), jsx(QuoteIsLoadingUpdater, { quoteIsPending: isCreatingCharge || isDeletingQuote || isCreatingQuote || isUpdatingQuoteCharge })] }));
23397
23471
  };
23398
23472
 
23399
23473
  const QuantityChangeGridRow_SubscriptionChargeFragment = t(`
@@ -23520,6 +23594,46 @@ function invalidateSubscriptionsQueryKeys(queryClient, token) {
23520
23594
  });
23521
23595
  }
23522
23596
 
23597
+ const [QuoteRecalculateTaxesProvider, useQuoteRecalculateTaxes$2] = createValueContext();
23598
+
23599
+ const mutation$8 = t(`
23600
+ mutation QuoteRecalculateTaxes($id: ID!) {
23601
+ quoteRecalculateTaxes(id: $id) {
23602
+ quote {
23603
+ ...QuantityDrawer_QuoteFragment
23604
+ id
23605
+ }
23606
+ errors
23607
+ }
23608
+ }
23609
+ `, [QuantityDrawer_QuoteFragment]);
23610
+ const quoteRecalculateTaxes$1 = async ({ quoteId, apiHost, token, }) => {
23611
+ var _a;
23612
+ const response = await execute(mutation$8, { apiHost, token }, { id: quoteId });
23613
+ return (_a = response.quoteRecalculateTaxes) === null || _a === void 0 ? void 0 : _a.quote;
23614
+ };
23615
+
23616
+ const useQuoteRecalculateTaxes$1 = () => {
23617
+ const token = useToken();
23618
+ const { apiHost } = useContext(BunnyContext);
23619
+ const { setQuoteQueryData } = useSetQuoteQueryData$1();
23620
+ const { mutate: quoteRecalculateTaxesMutation, isPending: isRecalculatingTaxes } = useMutation({
23621
+ mutationFn: async ({ quoteId }) => {
23622
+ return await quoteRecalculateTaxes$1({ quoteId, apiHost, token });
23623
+ },
23624
+ onSuccess: quote => {
23625
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
23626
+ throw new Error('Quote ID is undefined');
23627
+ }
23628
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, quote);
23629
+ },
23630
+ });
23631
+ return {
23632
+ quoteRecalculateTaxesMutation,
23633
+ isRecalculatingTaxes,
23634
+ };
23635
+ };
23636
+
23523
23637
  const QuantityDrawerContent = ({ subscriptions, quantityDrawerOpen, setQuantityDrawerOpen, handlePortalErrors, setShowInactive, }) => {
23524
23638
  const token = useToken();
23525
23639
  const queryClient = useQueryClient();
@@ -23529,6 +23643,8 @@ const QuantityDrawerContent = ({ subscriptions, quantityDrawerOpen, setQuantityD
23529
23643
  const [payModalVisible, setPayModalVisible] = useState(false);
23530
23644
  const [updatingChargeQuantityId, setUpdatingChargeQuantityId] = useState(undefined);
23531
23645
  const quote = useQuoteQueryData(quoteId);
23646
+ // Context
23647
+ const onRecalculateTaxes = useQuoteRecalculateTaxes$2();
23532
23648
  // Handlers
23533
23649
  const onSuccess = () => {
23534
23650
  setQuantityDrawerOpen(false);
@@ -23558,10 +23674,11 @@ const QuantityDrawerContent = ({ subscriptions, quantityDrawerOpen, setQuantityD
23558
23674
  const handleOpenCheckout = () => {
23559
23675
  setPayModalVisible(true);
23560
23676
  };
23561
- return (jsxs(Fragment, { children: [jsx(QuantityChangeDrawerDesktop, { onClose: handleDrawerClose, open: quantityDrawerOpen, openCheckout: handleOpenCheckout, subscriptions: subscriptions, setUpdatingChargeQuantityId: setUpdatingChargeQuantityId, updatingChargeQuantityId: updatingChargeQuantityId }), jsx(Checkout, { onCancel: onCancel, onSuccess: onSuccess, onFail: onFail, open: payModalVisible, quote: quote, token: token, isUpdatingQuote: false })] }));
23677
+ return (jsxs(Fragment, { children: [jsx(QuantityChangeDrawerDesktop, { onClose: handleDrawerClose, open: quantityDrawerOpen, openCheckout: handleOpenCheckout, subscriptions: subscriptions, setUpdatingChargeQuantityId: setUpdatingChargeQuantityId, updatingChargeQuantityId: updatingChargeQuantityId }), jsx(Checkout, { onCancel: onCancel, onSuccess: onSuccess, onFail: onFail, onRecalculateTaxes: onRecalculateTaxes, open: payModalVisible, quote: quote, token: token, isUpdatingQuote: false })] }));
23562
23678
  };
23563
23679
  const QuantityDrawer = ({ subscriptions, quantityDrawerOpen, setQuantityDrawerOpen, handlePortalErrors, setShowInactive, }) => {
23564
- return (jsx(QuoteIdProvider, { children: jsx(QuantityDrawerContent, { subscriptions: subscriptions, quantityDrawerOpen: quantityDrawerOpen, setQuantityDrawerOpen: setQuantityDrawerOpen, handlePortalErrors: handlePortalErrors, setShowInactive: setShowInactive }) }));
23680
+ const { quoteRecalculateTaxesMutation } = useQuoteRecalculateTaxes$1();
23681
+ return (jsx(QuoteIdProvider, { children: jsx(QuoteIsLoadingProvider, { children: jsx(QuoteRecalculateTaxesProvider, { value: quoteId => quoteRecalculateTaxesMutation({ quoteId }), children: jsx(QuantityDrawerContent, { subscriptions: subscriptions, quantityDrawerOpen: quantityDrawerOpen, setQuantityDrawerOpen: setQuantityDrawerOpen, handlePortalErrors: handlePortalErrors, setShowInactive: setShowInactive }) }) }) }));
23565
23682
  };
23566
23683
 
23567
23684
  const useCancelSubscription = () => {
@@ -23825,14 +23942,27 @@ const SubscriptionCardActions = ({ onChangePlanClick, onCancelSubscriptionClick,
23825
23942
  const isInTrial = isSubscriptionTrial(subscription);
23826
23943
  const isTrialExpired = isSubscriptionTrialExpired(subscription);
23827
23944
  const isActiveOrPending = isSubscriptionActiveOrPending(subscription);
23945
+ const getButtonLabel = () => {
23946
+ if (isInTrial) {
23947
+ return 'Upgrade from trial';
23948
+ }
23949
+ if (isTrialExpired) {
23950
+ return 'Upgrade';
23951
+ }
23952
+ // If the subscription is an addon, we should show the "Adjust plan" button since we don't support changing add-on plans.
23953
+ if (subscription.priceList.plan.addon === true) {
23954
+ return 'Adjust plan';
23955
+ }
23956
+ return 'Change plan';
23957
+ };
23828
23958
  if (isPaymentMethodLoading)
23829
23959
  return null;
23830
23960
  return (jsxs(Fragment, { children: [isSelfServiceCancelable && onCancelSubscriptionClick && (isInTrial || isActiveOrPending) && (jsx(Popconfirm, { icon: null, onConfirm: () => onCancelSubscriptionClick(subscription), title: "Cancel subscription", children: jsx(Button, { className: "bunny-p-0", type: "link", children: "Cancel subscription" }) })), arePlansAvailable &&
23831
23961
  onChangePlanClick &&
23832
- (isActiveOrPending || isInTrial || isTrialExpired) && (jsx(Button, { onClick: () => onChangePlanClick(subscription), type: 'primary', children: isInTrial ? 'Upgrade from trial' : isTrialExpired ? 'Upgrade' : 'Change plan' })), !arePlansAvailable && isInTrial && jsx(Tag, { color: "warning", children: "Cannot upgrade" })] }));
23962
+ (isActiveOrPending || isInTrial || isTrialExpired) && (jsx(Button, { onClick: () => onChangePlanClick(subscription), type: 'primary', children: getButtonLabel() })), !arePlansAvailable && isInTrial && jsx(Tag, { color: "warning", children: "Cannot upgrade" })] }));
23833
23963
  };
23834
23964
 
23835
- const query$2 = t(`
23965
+ const query$4 = t(`
23836
23966
  query priceListChangeOptions($productId: ID!) {
23837
23967
  priceListChangeOptions(productId: $productId) {
23838
23968
  ...SubscriptionCardActions_PriceListChangeOptionsFragment
@@ -23840,7 +23970,7 @@ const query$2 = t(`
23840
23970
  }
23841
23971
  `, [SubscriptionCardActions_PriceListChangeOptionsFragment]);
23842
23972
  const getPriceListChangeOptions$1 = async ({ apiHost, productId, token, }) => {
23843
- const response = await execute(query$2, { apiHost, token }, { productId });
23973
+ const response = await execute(query$4, { apiHost, token }, { productId });
23844
23974
  return response.priceListChangeOptions;
23845
23975
  };
23846
23976
 
@@ -23874,7 +24004,7 @@ const getSubscriptionStatusText = (subscription) => {
23874
24004
  return `Trial expires on ${formatDate(trialEndDate)}`;
23875
24005
  }
23876
24006
  }
23877
- if (evergreen) {
24007
+ if (evergreen && subscription.state === t.scalar('SubscriptionState', 'ACTIVE')) {
23878
24008
  return `Renews on ${formatDate(endDate)}`;
23879
24009
  }
23880
24010
  return `Ends on ${formatDate(endDate || trialEndDate)}`;
@@ -23952,40 +24082,66 @@ const formatNumber = (num, decimals = 2) => {
23952
24082
  });
23953
24083
  };
23954
24084
 
24085
+ const getPricingModelDescription = (pricingModel) => {
24086
+ switch (pricingModel) {
24087
+ case 'TIERED':
24088
+ return 'units in each tier are priced separately.';
24089
+ case 'VOLUME':
24090
+ return 'the highest tier reached prices all units.';
24091
+ case 'BANDS':
24092
+ return 'the quantity indexes to a flat price.';
24093
+ default:
24094
+ return '';
24095
+ }
24096
+ };
24097
+
24098
+ const getPricingModelTitle = (pricingModel) => {
24099
+ switch (pricingModel) {
24100
+ case 'TIERED':
24101
+ return 'Tiered';
24102
+ case 'VOLUME':
24103
+ return 'Volume';
24104
+ case 'BANDS':
24105
+ return 'Bands';
24106
+ default:
24107
+ return '';
24108
+ }
24109
+ };
24110
+
23955
24111
  const StyledTable = styled(Table) `
23956
24112
  .ant-table-cell {
23957
24113
  border-bottom: none !important;
23958
24114
  }
23959
24115
  `;
23960
- const TieredDisplayDropdown = ({ priceTiers, currencyId, priceDecimals, truncatedText, }) => {
24116
+ const TieredDisplayDropdown = ({ pricingModel, priceTiers, currencyId, priceDecimals, truncatedText, }) => {
23961
24117
  const onlyHasOneTier = (priceTiers === null || priceTiers === void 0 ? void 0 : priceTiers.length) === 1;
23962
24118
  const dropdownTrigger = (jsx("div", { className: `w-full ${onlyHasOneTier ? '' : 'underline cursor-pointer'}`, children: truncatedText }));
23963
24119
  if (onlyHasOneTier) {
23964
24120
  return dropdownTrigger;
23965
24121
  }
23966
24122
  return (jsx(Dropdown, { popupRender: () => {
23967
- return (jsx("div", { className: "rounded border border-solid border-slate-200 bg-white overflow-hidden", children: jsx(StyledTable, { columns: [
23968
- {
23969
- dataIndex: 'starts',
23970
- title: 'From # of units',
23971
- align: 'right',
23972
- render: (_, record, index) => {
23973
- record = record;
23974
- const nextRecord = priceTiers === null || priceTiers === void 0 ? void 0 : priceTiers[index + 1];
23975
- const starts = record.starts;
23976
- const ends = (nextRecord === null || nextRecord === void 0 ? void 0 : nextRecord.starts) ? nextRecord.starts - 1 : '';
23977
- return (jsxs(Fragment, { children: [formatNumber(starts, 0), " -", ' ', typeof ends === 'number' ? formatNumber(ends, 0) : ''] }));
24123
+ return (jsxs("div", { className: "rounded border border-solid border-slate-200 bg-white overflow-hidden", children: [jsxs("div", { className: "bunny-text-gray-400 bunny-p-2", children: [getPricingModelTitle(pricingModel), " pricing -", ' ', getPricingModelDescription(pricingModel)] }), jsx(StyledTable, { columns: [
24124
+ {
24125
+ dataIndex: 'starts',
24126
+ title: 'From # of units',
24127
+ align: 'right',
24128
+ render: (_, record, index) => {
24129
+ record = record;
24130
+ const nextRecord = priceTiers === null || priceTiers === void 0 ? void 0 : priceTiers[index + 1];
24131
+ const starts = record.starts;
24132
+ const ends = (nextRecord === null || nextRecord === void 0 ? void 0 : nextRecord.starts) ? nextRecord.starts - 1 : '+';
24133
+ return (jsxs(Fragment, { children: [formatNumber(starts, 0), typeof ends === 'number' ? formatNumber(ends, 0) : '+'] }));
24134
+ },
23978
24135
  },
23979
- },
23980
- {
23981
- dataIndex: 'price',
23982
- title: 'Unit price',
23983
- align: 'right',
23984
- render: value => {
23985
- return jsx(Fragment, { children: formatCurrency$1(value, currencyId, priceDecimals) });
24136
+ {
24137
+ dataIndex: 'price',
24138
+ title: 'Unit price',
24139
+ align: 'right',
24140
+ render: value => {
24141
+ return jsx(Fragment, { children: formatCurrency$1(value, currencyId, priceDecimals) });
24142
+ },
23986
24143
  },
23987
- },
23988
- ], dataSource: priceTiers, rowKey: "starts", pagination: false, size: "small" }) }));
24144
+ ], dataSource: priceTiers, rowKey: "starts", pagination: false, size: "small" })] }));
23989
24145
  }, children: dropdownTrigger }));
23990
24146
  };
23991
24147
 
@@ -24036,7 +24192,7 @@ const SubscriptionChargeUnitPrice = ({ charge, currencyId, }) => {
24036
24192
  ? '-'
24037
24193
  : formatCurrency$1(charge.discountedPrice, currencyId, charge.priceDecimals);
24038
24194
  const isChargeDiscount = isDiscount$1(charge.kind);
24039
- return (jsx(Fragment, { children: hasPriceTiers(charge) ? (jsx(TieredDisplayDropdown, { priceTiers: charge.priceTiers, currencyId: currencyId, priceDecimals: charge.priceDecimals, truncatedText: `${charge.kind === QuoteChangeKind.PRICE_UPDATE ? 'new ' : ''}${getApplicablePriceTier(charge, currencyId, charge.priceDecimals)}` })) : isChargeDiscount ? (`-${price}`) : (price) }));
24195
+ return (jsx(Fragment, { children: hasPriceTiers(charge) ? (jsx(TieredDisplayDropdown, { pricingModel: charge.pricingModel, priceTiers: charge.priceTiers, currencyId: currencyId, priceDecimals: charge.priceDecimals, truncatedText: `${charge.kind === QuoteChangeKind.PRICE_UPDATE ? 'new ' : ''}${getApplicablePriceTier(charge, currencyId, charge.priceDecimals)}` })) : isChargeDiscount ? (`-${price}`) : (price) }));
24040
24196
  };
24041
24197
 
24042
24198
  const { Text: Text$e } = Typography;
@@ -24173,7 +24329,7 @@ const SubscriptionCardDesktopRow = ({ charge, chargeIndex, charges, currencyId,
24173
24329
  : (_b = charge.quantity) === null || _b === void 0 ? void 0 : _b.toLocaleString() }), jsx(SubscriptionsListCell, { right: true, children: jsx(SubscriptionChargeUnitPrice, { charge: charge, currencyId: currencyId }) }), jsx(SubscriptionsListCell, { right: true, children: jsx(SubscriptionChargeTotal, { charge: charge, currencyId: currencyId }) })] }));
24174
24330
  };
24175
24331
 
24176
- function AddonSubscriptionsCards({ onCancelSubscriptionClick, subscriptions, subscription, showInactive, }) {
24332
+ function AddonSubscriptionsCards({ onCancelSubscriptionClick, onChangePlanClick, subscriptions, subscription, showInactive, }) {
24177
24333
  const addonSubscriptions = findAddonSubscriptions(subscription, subscriptions);
24178
24334
  if (addonSubscriptions.length === 0) {
24179
24335
  return null;
@@ -24182,7 +24338,7 @@ function AddonSubscriptionsCards({ onCancelSubscriptionClick, subscriptions, sub
24182
24338
  if (!showInactive && isSubscriptionNotActive(addonSubscription))
24183
24339
  return null;
24184
24340
  const isLast = addonSubscriptionIndex === addonSubscriptions.length - 1;
24185
- return (jsxs("div", { className: "bunny-flex bunny-flex-row", children: [jsx(AddonIndentation, { isLast: isLast, indentation: ADDON_INDENTATION, verticalMargin: "-1rem" }), jsx("div", { className: "bunny-flex-1", children: jsx(SubscriptionCardDesktop, { onCancelSubscriptionClick: onCancelSubscriptionClick, subscription: addonSubscription, isAddon: true }) })] }, addonSubscriptionIndex));
24341
+ return (jsxs("div", { className: "bunny-flex bunny-flex-row", children: [jsx(AddonIndentation, { isLast: isLast, indentation: ADDON_INDENTATION, verticalMargin: "-1rem" }), jsx("div", { className: "bunny-flex-1", children: jsx(SubscriptionCardDesktop, { onChangePlanClick: onChangePlanClick, onCancelSubscriptionClick: onCancelSubscriptionClick, subscription: addonSubscription, isAddon: true }) })] }, addonSubscriptionIndex));
24186
24342
  }) }));
24187
24343
  }
24188
24344
 
@@ -24241,8 +24397,8 @@ const SubscriptionsList = ({ showInactive, onChangePlanClick, onCancelSubscripti
24241
24397
  if (!showInactive && isSubscriptionNotActive(subscription))
24242
24398
  return null;
24243
24399
  if (isMobile)
24244
- return (jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-${gap}`, children: [jsx(SubscriptionCard, { subscription: subscription }), jsx(AddonSubscriptionsCards, { onCancelSubscriptionClick: onCancelSubscriptionClick, subscription: subscription, subscriptions: subscriptions, showInactive: showInactive })] }, subscriptionIndex));
24245
- return (jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-${gap}`, children: [jsx(SubscriptionCardDesktop, { onChangePlanClick: onChangePlanClick, onCancelSubscriptionClick: onCancelSubscriptionClick, subscription: subscription }), jsx(AddonSubscriptionsCards, { onCancelSubscriptionClick: onCancelSubscriptionClick, subscription: subscription, subscriptions: subscriptions, showInactive: showInactive })] }, subscriptionIndex));
24400
+ return (jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-${gap}`, children: [jsx(SubscriptionCard, { subscription: subscription }), jsx(AddonSubscriptionsCards, { onCancelSubscriptionClick: onCancelSubscriptionClick, onChangePlanClick: onChangePlanClick, subscription: subscription, subscriptions: subscriptions, showInactive: showInactive })] }, subscriptionIndex));
24401
+ return (jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-${gap}`, children: [jsx(SubscriptionCardDesktop, { onChangePlanClick: onChangePlanClick, onCancelSubscriptionClick: onCancelSubscriptionClick, subscription: subscription }), jsx(AddonSubscriptionsCards, { onCancelSubscriptionClick: onCancelSubscriptionClick, onChangePlanClick: onChangePlanClick, subscription: subscription, subscriptions: subscriptions, showInactive: showInactive })] }, subscriptionIndex));
24246
24402
  }) }));
24247
24403
  };
24248
24404
 
@@ -24313,7 +24469,7 @@ const FormattedQuoteFields_QuoteFragment = t(`
24313
24469
  }
24314
24470
  }
24315
24471
  `);
24316
- const query$1 = t(`
24472
+ const query$3 = t(`
24317
24473
  query quote($id: ID, $includeHtmlField: Boolean!) {
24318
24474
  quote(id: $id) {
24319
24475
  ...FormattedQuoteFields_QuoteFragment @include(if: $includeHtmlField)
@@ -24322,7 +24478,7 @@ const query$1 = t(`
24322
24478
  }
24323
24479
  `, [FormattedQuoteFields_QuoteFragment, QuoteContext_QuoteFragment]);
24324
24480
  const getQuote = async ({ id, token, apiHost, includeHtmlField = false, }) => {
24325
- const response = await execute(query$1, { apiHost, token }, { id, includeHtmlField });
24481
+ const response = await execute(query$3, { apiHost, token }, { id, includeHtmlField });
24326
24482
  return response === null || response === void 0 ? void 0 : response.quote;
24327
24483
  };
24328
24484
 
@@ -24427,7 +24583,7 @@ const calculateNewQuantity = (priceListCharge, currentQuantity = 1) => {
24427
24583
  return quantityMin;
24428
24584
  };
24429
24585
 
24430
- const mutation$1 = t(`
24586
+ const mutation$7 = t(`
24431
24587
  mutation QuoteChangeUpdate($id: ID!, $charges: [QuoteChargeAttributes!]!) {
24432
24588
  quoteChangeUpdate(id: $id, charges: $charges) {
24433
24589
  quoteChange {
@@ -24441,7 +24597,7 @@ const mutation$1 = t(`
24441
24597
  `, [QuoteContext_QuoteFragment]);
24442
24598
  const quoteChangeUpdate = async ({ quoteChangeId, charges, apiHost, token, }) => {
24443
24599
  var _a, _b;
24444
- const response = await execute(mutation$1, {
24600
+ const response = await execute(mutation$7, {
24445
24601
  apiHost,
24446
24602
  token,
24447
24603
  }, {
@@ -24497,6 +24653,19 @@ function useFeatureQuantities({ onFeatureQuantitiesChanged, }) {
24497
24653
  };
24498
24654
  }
24499
24655
 
24656
+ const useSetQuoteQueryData = () => {
24657
+ const token = useToken();
24658
+ const queryClient = useQueryClient();
24659
+ const setQuoteQueryData = (quoteId, quote) => {
24660
+ queryClient.setQueryData(QueryKeyFactory$1.default.createObjectKey({
24661
+ id: quoteId,
24662
+ objectName: 'editingQuote',
24663
+ token,
24664
+ }), quote);
24665
+ };
24666
+ return { setQuoteQueryData };
24667
+ };
24668
+
24500
24669
  // Functionality:
24501
24670
  // 1: keep track of quantities set for features based on feature.id
24502
24671
  // a. copy those quantities over to charges with same feature when initializing
@@ -24509,9 +24678,9 @@ function useFeatureQuantities({ onFeatureQuantitiesChanged, }) {
24509
24678
  const showErrorNotification = useErrorNotification();
24510
24679
  const DEBOUNCE_TIME = 1000;
24511
24680
  const useQuoteQuantities = ({ selectedPriceList, quote, }) => {
24512
- const queryClient = useQueryClient();
24513
24681
  const token = useToken();
24514
24682
  const { apiHost } = useContext(BunnyContext);
24683
+ const { setQuoteQueryData } = useSetQuoteQueryData();
24515
24684
  // Derived state
24516
24685
  const selectedPriceListQuoteChange = useMemo(() => {
24517
24686
  var _a;
@@ -24530,23 +24699,27 @@ const useQuoteQuantities = ({ selectedPriceList, quote, }) => {
24530
24699
  });
24531
24700
  },
24532
24701
  onSuccess: quoteChange => {
24533
- var _a;
24534
- queryClient.setQueryData(QueryKeyFactory$1.default.createObjectKey({
24535
- objectName: 'editingQuote',
24536
- id: (_a = quote === null || quote === void 0 ? void 0 : quote.id) !== null && _a !== void 0 ? _a : undefined,
24537
- token,
24538
- }), quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.quote);
24702
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
24703
+ throw new Error('Quote ID is undefined');
24704
+ }
24705
+ if (!(quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.quote)) {
24706
+ throw new Error('Quote is undefined');
24707
+ }
24708
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.quote);
24539
24709
  },
24540
24710
  });
24541
24711
  function handleUpdateQuoteQuantities(featureQuantities) {
24542
24712
  if (!selectedPriceListQuoteChange) {
24543
- throw new Error('Quote change is undefined');
24713
+ console.error('Quote change is undefined');
24714
+ return;
24544
24715
  }
24545
24716
  if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
24546
- throw new Error('Quote ID is undefined');
24717
+ console.error('Quote ID is undefined');
24718
+ return;
24547
24719
  }
24548
24720
  if (!(selectedPriceListQuoteChange === null || selectedPriceListQuoteChange === void 0 ? void 0 : selectedPriceListQuoteChange.id)) {
24549
- throw new Error('Quote change ID is undefined');
24721
+ console.error('Quote change ID is undefined');
24722
+ return;
24550
24723
  }
24551
24724
  const featureIdsToUpdate = Object.keys(featureQuantities).filter(featureId => {
24552
24725
  // If the quantities differ, then update quote with the quantities present in useFeatureQuantities
@@ -24558,20 +24731,24 @@ const useQuoteQuantities = ({ selectedPriceList, quote, }) => {
24558
24731
  const quoteCharge = selectedPriceListQuoteChange === null || selectedPriceListQuoteChange === void 0 ? void 0 : selectedPriceListQuoteChange.charges.find(charge => { var _a; return ((_a = charge === null || charge === void 0 ? void 0 : charge.feature) === null || _a === void 0 ? void 0 : _a.id) === featureId; });
24559
24732
  return quoteCharge !== undefined && localAndQuoteQuantitiesDiffer;
24560
24733
  });
24561
- const charges = featureIdsToUpdate.map(featureId => {
24734
+ const charges = featureIdsToUpdate
24735
+ .map(featureId => {
24562
24736
  const quoteCharge = selectedPriceListQuoteChange === null || selectedPriceListQuoteChange === void 0 ? void 0 : selectedPriceListQuoteChange.charges.find(charge => { var _a; return ((_a = charge === null || charge === void 0 ? void 0 : charge.feature) === null || _a === void 0 ? void 0 : _a.id) === featureId; });
24563
24737
  const quantity = getFeatureQuantity(featureId, featureQuantities);
24564
24738
  if (!quantity) {
24565
- throw new Error('Quantity is undefined');
24739
+ console.error('Quantity is undefined');
24740
+ return;
24566
24741
  }
24567
24742
  if (!(quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.id)) {
24568
- throw new Error('Quote charge for featureId is undefined');
24743
+ console.error('Quote charge for featureId is undefined');
24744
+ return;
24569
24745
  }
24570
24746
  return {
24571
24747
  id: quoteCharge.id,
24572
24748
  quantity: quantity,
24573
24749
  };
24574
- });
24750
+ })
24751
+ .filter(charge => charge !== undefined);
24575
24752
  if (charges.length === 0) {
24576
24753
  return;
24577
24754
  }
@@ -24639,6 +24816,44 @@ const useQuoteQuantities = ({ selectedPriceList, quote, }) => {
24639
24816
  };
24640
24817
  };
24641
24818
 
24819
+ const mutation$6 = t(`
24820
+ mutation QuoteRecalculateTaxes($id: ID!) {
24821
+ quoteRecalculateTaxes(id: $id) {
24822
+ quote {
24823
+ ...QuoteContext_QuoteFragment
24824
+ id
24825
+ }
24826
+ errors
24827
+ }
24828
+ }
24829
+ `, [QuoteContext_QuoteFragment]);
24830
+ const quoteRecalculateTaxes = async ({ quoteId, apiHost, token, }) => {
24831
+ var _a;
24832
+ const response = await execute(mutation$6, { apiHost, token }, { id: quoteId });
24833
+ return (_a = response.quoteRecalculateTaxes) === null || _a === void 0 ? void 0 : _a.quote;
24834
+ };
24835
+
24836
+ const useQuoteRecalculateTaxes = () => {
24837
+ const token = useToken();
24838
+ const { apiHost } = useContext(BunnyContext);
24839
+ const { setQuoteQueryData } = useSetQuoteQueryData();
24840
+ const { mutate: quoteRecalculateTaxesMutation, isPending: isRecalculatingTaxes } = useMutation({
24841
+ mutationFn: async ({ quoteId }) => {
24842
+ return await quoteRecalculateTaxes({ quoteId, apiHost, token });
24843
+ },
24844
+ onSuccess: quote => {
24845
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
24846
+ throw new Error('Quote ID is undefined');
24847
+ }
24848
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, quote);
24849
+ },
24850
+ });
24851
+ return {
24852
+ quoteRecalculateTaxesMutation,
24853
+ isRecalculatingTaxes,
24854
+ };
24855
+ };
24856
+
24642
24857
  function useFeatureAddonsPending() {
24643
24858
  const [featureAddonsLoading, setFeatureAddonsLoading] = useState([]);
24644
24859
  const addFeatureAddonLoading = (featureAddonId) => {
@@ -24662,6 +24877,7 @@ function QuoteProvider({ children }) {
24662
24877
  // Hooks
24663
24878
  const token = useToken();
24664
24879
  const { isFeatureAddonsLoading, addFeatureAddonLoading, removeFeatureAddonLoading } = useFeatureAddonsPending();
24880
+ const { quoteRecalculateTaxesMutation } = useQuoteRecalculateTaxes();
24665
24881
  const { quote: maskedQuote, isQuotePending } = useQuoteCreate({
24666
24882
  upgradingSubscription,
24667
24883
  selectedPriceList: selectedPriceList,
@@ -24697,6 +24913,7 @@ function QuoteProvider({ children }) {
24697
24913
  onChangeSelectedPriceList: handleChangeSelectedPriceList,
24698
24914
  onChangeQuantity,
24699
24915
  getFeatureQuantity,
24916
+ onRecalculateTaxes: (id) => quoteRecalculateTaxesMutation({ quoteId: id }),
24700
24917
  }, children: children }));
24701
24918
  }
24702
24919
 
@@ -24723,40 +24940,6 @@ function priceDescriptionString({ unitName, showPriceAsMonthly, periodMonths, pr
24723
24940
  return `Per ${unitName && !priceListHasFlatFeeCharges ? `${unitName.toLowerCase()} / ` : ''}${showPriceAsMonthly ? 'month' : periodLabel}`;
24724
24941
  }
24725
24942
 
24726
- var localizedFormat$2 = {exports: {}};
24727
-
24728
- var localizedFormat$1 = localizedFormat$2.exports;
24729
-
24730
- var hasRequiredLocalizedFormat;
24731
-
24732
- function requireLocalizedFormat () {
24733
- if (hasRequiredLocalizedFormat) return localizedFormat$2.exports;
24734
- hasRequiredLocalizedFormat = 1;
24735
- (function (module, exports) {
24736
- !function(e,t){module.exports=t();}(localizedFormat$1,(function(){var e={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"};return function(t,o,n){var r=o.prototype,i=r.format;n.en.formats=e,r.format=function(t){void 0===t&&(t="YYYY-MM-DDTHH:mm:ssZ");var o=this.$locale().formats,n=function(t,o){return t.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,(function(t,n,r){var i=r&&r.toUpperCase();return n||o[r]||e[r]||o[i].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,(function(e,t,o){return t||o.slice(1)}))}))}(t,void 0===o?{}:o);return i.call(this,n)};}}));
24737
- } (localizedFormat$2));
24738
- return localizedFormat$2.exports;
24739
- }
24740
-
24741
- var localizedFormatExports = requireLocalizedFormat();
24742
- var localizedFormat = /*@__PURE__*/getDefaultExportFromCjs(localizedFormatExports);
24743
-
24744
- dayjs.extend(localizedFormat);
24745
- const formatCurrency = (value, currencyIsoCode, decimals = 2) => {
24746
- if (value !== 0 && !value)
24747
- return '';
24748
- const currencyValue = typeof value === 'string' ? parseFloat(value) : value;
24749
- if (isNaN(currencyValue))
24750
- return value;
24751
- const localeOptions = {
24752
- minimumFractionDigits: decimals,
24753
- maximumFractionDigits: decimals,
24754
- };
24755
- localeOptions.style = 'currency';
24756
- localeOptions.currency = currencyIsoCode;
24757
- return currencyValue.toLocaleString(navigator.language, localeOptions);
24758
- };
24759
-
24760
24943
  const { Text: Text$b } = Typography;
24761
24944
  const PriceTierPrice = ({ currencyId, priceDecimals, tier, }) => {
24762
24945
  return (jsx(Text$b, { className: "bunny-text-white", children: formatCurrency(tier.price, currencyId, priceDecimals) }));
@@ -24780,32 +24963,6 @@ const PriceTierRow = ({ tier: maskedTier, nextTier: maskedNextTier, }) => {
24780
24963
  return jsx(Text$a, { className: "bunny-text-white", children: text });
24781
24964
  };
24782
24965
 
24783
- const getPricingModelTitle = (pricingModel) => {
24784
- switch (pricingModel) {
24785
- case 'TIERED':
24786
- return 'Tiered';
24787
- case 'VOLUME':
24788
- return 'Volume';
24789
- case 'BANDS':
24790
- return 'Bands';
24791
- default:
24792
- return '';
24793
- }
24794
- };
24795
-
24796
- const getPricingModelDescription = (pricingModel) => {
24797
- switch (pricingModel) {
24798
- case 'TIERED':
24799
- return 'units in each tier are priced separately.';
24800
- case 'VOLUME':
24801
- return 'the highest tier reached prices all units.';
24802
- case 'BANDS':
24803
- return 'the quantity indexes to a flat price.';
24804
- default:
24805
- return '';
24806
- }
24807
- };
24808
-
24809
24966
  const { Text: Text$9 } = Typography;
24810
24967
  const ChargePriceTiers_PriceListChargeFragment = t(`
24811
24968
  fragment ChargePriceTiers_PriceListChargeFragment on PriceListCharge {
@@ -25440,57 +25597,13 @@ const getAvailablePlansAndPriceLists = ({ availablePriceLists, priceListChangeOp
25440
25597
  return {
25441
25598
  availablePriceListsArray,
25442
25599
  displayPriceLists,
25443
- };
25444
- };
25445
- const everythingInPlusString = ({ priceList }) => {
25446
- return `Everything in ${priceList.plan.name}, plus`;
25447
- };
25448
-
25449
- const QUOTE_CHARGE_CREATE = `
25450
- ${QUOTE_FIELDS()}
25451
- mutation QuoteChargeCreate ($quoteChangeId: ID!, $startDate: ISO8601Date!, $endDate: ISO8601Date, $priceListChargeId: ID, $subscriptionChargeId: ID, $price: Float, $quantity: Int) {
25452
- quoteChargeCreate(
25453
- endDate: $endDate
25454
- price: $price
25455
- priceListChargeId: $priceListChargeId
25456
- quantity: $quantity
25457
- quoteChangeId: $quoteChangeId
25458
- startDate: $startDate
25459
- subscriptionChargeId: $subscriptionChargeId
25460
- ) {
25461
- quoteCharge {
25462
- quoteChange {
25463
- id
25464
- quoteId
25465
- quote {
25466
- ...QuoteFields
25467
- }
25468
- }
25469
- id
25470
- }
25471
- }
25472
- }
25473
-
25474
- `;
25475
- const quoteChargeCreate = async ({ price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId, token, apiHost, }) => {
25476
- var _a;
25477
- const response = await gqlRequest({
25478
- query: QUOTE_CHARGE_CREATE,
25479
- vars: {
25480
- price,
25481
- priceListChargeId,
25482
- quantity,
25483
- quoteChangeId,
25484
- startDate,
25485
- subscriptionChargeId,
25486
- },
25487
- apiHost,
25488
- token,
25489
- });
25490
- return (_a = response === null || response === void 0 ? void 0 : response.quoteChargeCreate) === null || _a === void 0 ? void 0 : _a.quoteCharge;
25600
+ };
25601
+ };
25602
+ const everythingInPlusString = ({ priceList }) => {
25603
+ return `Everything in ${priceList.plan.name}, plus`;
25491
25604
  };
25492
25605
 
25493
- const mutation = t(`
25606
+ const mutation$5 = t(`
25494
25607
  mutation QuoteChargeDelete($quoteChargeId: ID!) {
25495
25608
  quoteChargeDelete(quoteChargeId: $quoteChargeId) {
25496
25609
  errors
@@ -25508,21 +25621,76 @@ const mutation = t(`
25508
25621
  `, [QuoteContext_QuoteFragment]);
25509
25622
  const quoteChargeDelete = async ({ quoteChargeId, token, apiHost }) => {
25510
25623
  var _a, _b, _c, _d;
25511
- const response = await execute(mutation, { apiHost, token }, { quoteChargeId });
25624
+ const response = await execute(mutation$5, { apiHost, token }, { quoteChargeId });
25512
25625
  if ((_a = response.quoteChargeDelete) === null || _a === void 0 ? void 0 : _a.errors) {
25513
25626
  throw new Error((_c = (_b = response.quoteChargeDelete) === null || _b === void 0 ? void 0 : _b.errors) === null || _c === void 0 ? void 0 : _c[0]);
25514
25627
  }
25515
25628
  return (_d = response.quoteChargeDelete) === null || _d === void 0 ? void 0 : _d.quoteCharge;
25516
25629
  };
25517
25630
 
25518
- const useQuoteUpdateFeatureAddon = (quote, featureAddon) => {
25631
+ const mutation$4 = t(`
25632
+ mutation QuoteChargeCreate(
25633
+ $quoteChangeId: ID!
25634
+ $startDate: ISO8601Date!
25635
+ $endDate: ISO8601Date
25636
+ $priceListChargeId: ID
25637
+ $subscriptionChargeId: ID
25638
+ $price: Float
25639
+ $quantity: Int
25640
+ ) {
25641
+ quoteChargeCreate(
25642
+ endDate: $endDate
25643
+ price: $price
25644
+ priceListChargeId: $priceListChargeId
25645
+ quantity: $quantity
25646
+ quoteChangeId: $quoteChangeId
25647
+ startDate: $startDate
25648
+ subscriptionChargeId: $subscriptionChargeId
25649
+ ) {
25650
+ quoteCharge {
25651
+ quoteChange {
25652
+ id
25653
+ quoteId
25654
+ quote {
25655
+ ...QuoteContext_QuoteFragment
25656
+ }
25657
+ }
25658
+ id
25659
+ }
25660
+ }
25661
+ }
25662
+ `, [QuoteContext_QuoteFragment]);
25663
+ const quoteChargeCreate = async ({ price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId, token, apiHost, }) => {
25664
+ var _a;
25665
+ const response = await execute(mutation$4, { apiHost, token }, { price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId });
25666
+ return (_a = response === null || response === void 0 ? void 0 : response.quoteChargeCreate) === null || _a === void 0 ? void 0 : _a.quoteCharge;
25667
+ };
25668
+
25669
+ const useQuoteUpdateFeatureAddon = (maskedQuote, featureAddon) => {
25519
25670
  const { apiHost } = useContext(BunnyContext);
25520
25671
  const { addFeatureAddonLoading, removeFeatureAddonLoading } = useContext(QuoteContext);
25521
25672
  const token = useToken();
25522
- const queryClient = useQueryClient();
25673
+ const { setQuoteQueryData } = useSetQuoteQueryData();
25674
+ // Read fragments
25675
+ const quote = readFragment(useQuoteUpdateFeatureAddon_QuoteFragment, maskedQuote);
25523
25676
  const addedQuoteChargeId = useRef();
25524
25677
  function handleAddFeatureAddon() {
25525
- quoteChargeCreateMutation();
25678
+ if (!token)
25679
+ throw new Error('Token is required');
25680
+ if (!quote)
25681
+ throw new Error('Editing quote is required');
25682
+ const quoteChangeId = findQuoteChangeForFeatureAddon(quote);
25683
+ if (!quoteChangeId)
25684
+ throw new Error('No available quote change for feature add-on');
25685
+ console.log('quote', quote);
25686
+ console.log('startDate', quote === null || quote === void 0 ? void 0 : quote.startDate);
25687
+ quoteChargeCreateMutation({
25688
+ quoteChangeId: quoteChangeId.id,
25689
+ priceListChargeId: featureAddon.id,
25690
+ startDate: quote === null || quote === void 0 ? void 0 : quote.startDate,
25691
+ apiHost,
25692
+ token,
25693
+ });
25526
25694
  }
25527
25695
  function handleRemoveFeatureAddon() {
25528
25696
  if (!addedQuoteChargeId.current)
@@ -25530,30 +25698,16 @@ const useQuoteUpdateFeatureAddon = (quote, featureAddon) => {
25530
25698
  quoteChargeDeleteMutation({ quoteChargeId: addedQuoteChargeId.current });
25531
25699
  }
25532
25700
  const { mutate: quoteChargeCreateMutation, isPending: isCreatingFeatureAddon } = useMutation({
25533
- mutationFn: async () => {
25534
- if (!token)
25535
- throw new Error('Token is required');
25536
- if (!quote)
25537
- throw new Error('Editing quote is required');
25538
- const quoteChangeId = findQuoteChangeForFeatureAddon(quote);
25539
- if (!quoteChangeId)
25540
- throw new Error('No available quote change for feature add-on');
25541
- const quoteCharge = await quoteChargeCreate({
25542
- quoteChangeId: quoteChangeId.id,
25543
- priceListChargeId: featureAddon.id,
25544
- startDate: quote === null || quote === void 0 ? void 0 : quote.startDate,
25545
- apiHost,
25546
- token,
25547
- });
25548
- return { quoteCharge };
25549
- },
25550
- onSuccess: ({ quoteCharge }) => {
25551
- addedQuoteChargeId.current = quoteCharge.id;
25552
- queryClient.setQueryData(QueryKeyFactory$1.default.createObjectKey({
25553
- objectName: 'editingQuote',
25554
- id: quote === null || quote === void 0 ? void 0 : quote.id,
25555
- token,
25556
- }), quoteCharge.quoteChange.quote);
25701
+ mutationFn: quoteChargeCreate,
25702
+ onSuccess: quoteCharge => {
25703
+ addedQuoteChargeId.current = quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.id;
25704
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
25705
+ throw new Error('Quote ID is undefined');
25706
+ }
25707
+ if (!(quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.quoteChange.quote)) {
25708
+ throw new Error('Quote is undefined');
25709
+ }
25710
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.quoteChange.quote);
25557
25711
  },
25558
25712
  });
25559
25713
  const { mutate: quoteChargeDeleteMutation, isPending: isDeletingFeatureAddon } = useMutation({
@@ -25563,11 +25717,13 @@ const useQuoteUpdateFeatureAddon = (quote, featureAddon) => {
25563
25717
  },
25564
25718
  onSuccess: quoteCharge => {
25565
25719
  addedQuoteChargeId.current = undefined;
25566
- queryClient.setQueryData(QueryKeyFactory$1.default.createObjectKey({
25567
- objectName: 'editingQuote',
25568
- id: quote === null || quote === void 0 ? void 0 : quote.id,
25569
- token,
25570
- }), quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.quoteChange.quote);
25720
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
25721
+ throw new Error('Quote ID is undefined');
25722
+ }
25723
+ if (!(quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.quoteChange.quote)) {
25724
+ throw new Error('Quote is undefined');
25725
+ }
25726
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.quoteChange.quote);
25571
25727
  },
25572
25728
  });
25573
25729
  const isPending = isCreatingFeatureAddon || isDeletingFeatureAddon;
@@ -25647,10 +25803,11 @@ const FeatureAddonRow_PriceListChargeFragment = t(`
25647
25803
  }
25648
25804
  `, [isAddonPurchased_PriceListChargeFragment, PricingTooltip_PriceListChargeFragment]);
25649
25805
  function FeatureAddonRow({ featureAddon: maskedFeatureAddon, priceList: maskedPriceList, }) {
25806
+ const { quote: maskedQuote, selectedPriceList } = useContext(QuoteContext);
25650
25807
  // Read fragments
25651
25808
  const featureAddon = readFragment(FeatureAddonRow_PriceListChargeFragment, maskedFeatureAddon);
25652
25809
  const priceList = readFragment(FeatureAddonRow_PriceListFragment, maskedPriceList);
25653
- const { quote, selectedPriceList } = useContext(QuoteContext);
25810
+ const quote = readFragment(FeatureAddonRow_QuoteFragment, maskedQuote);
25654
25811
  const { handleAddFeatureAddon, handleRemoveFeatureAddon, isPending, isChecked } = useQuoteUpdateFeatureAddon(quote, featureAddon);
25655
25812
  const { brandColor } = useBrand();
25656
25813
  const { upgradingSubscription } = useContext(SubscriptionsContext);
@@ -25865,107 +26022,84 @@ function AddonPlanModal({ onClose, priceList: maskedPriceList, }) {
25865
26022
  return (jsx(StyledModal, { open: !!priceList, onCancel: onClose, footer: null, centered: true, children: jsxs("div", { className: `bunny-w-full bunny-overflow-hidden`, children: [jsx(GridTemplateColumnsWrapper, { className: "bunny-grid bunny-w-full", everythingInPlus: false, plansToDisplay: 1, children: priceList && (jsx(PriceListCard, { isSelected: true, priceList: priceList, noBorder: true, hideButton: true, disableCurrentPlan: true })) }), hasFeatureAddons && (jsxs(Fragment, { children: [jsx(Divider, { className: "bunny-my-0" }), jsx("div", { className: "bunny-flex bunny-flex-col bunny-gap-4 bunny-p-4", children: jsx(FeatureAddonsList, { priceList: priceList }) })] }))] }) }));
25866
26023
  }
25867
26024
 
25868
- const QUOTE_CHANGE_CREATE = `
25869
- ${QUOTE_FIELDS()}
25870
- mutation QuoteChangeCreate(
25871
- $quoteId: ID!
25872
- $priceListId: ID!
25873
- $parentQuoteChangeId: ID!
25874
- ) {
25875
- quoteChangeCreate(
25876
- quoteId: $quoteId
25877
- priceListId: $priceListId
25878
- parentQuoteChangeId: $parentQuoteChangeId
25879
- ) {
25880
- errors
25881
- quoteChange {
25882
- id
25883
- quote {
25884
- ...QuoteFields
26025
+ const mutation$3 = t(`
26026
+ mutation QuoteChangeCreate($quoteId: ID!, $priceListId: ID!, $parentQuoteChangeId: ID!) {
26027
+ quoteChangeCreate(
26028
+ quoteId: $quoteId
26029
+ priceListId: $priceListId
26030
+ parentQuoteChangeId: $parentQuoteChangeId
26031
+ ) {
26032
+ errors
26033
+ quoteChange {
26034
+ id
26035
+ quote {
26036
+ ...QuoteContext_QuoteFragment
26037
+ }
26038
+ }
25885
26039
  }
25886
26040
  }
25887
- }
25888
- }
25889
- `;
26041
+ `, [QuoteContext_QuoteFragment]);
25890
26042
  const quoteChangeCreate = async ({ parentQuoteChangeId, priceListId, apiHost, token, quoteId, }) => {
25891
- var _a;
25892
- const vars = {
25893
- parentQuoteChangeId,
25894
- priceListId,
25895
- quoteId,
25896
- };
25897
- const response = await gqlRequest({
25898
- query: QUOTE_CHANGE_CREATE,
25899
- token,
25900
- vars,
25901
- apiHost,
25902
- });
25903
- const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteChangeCreate) === null || _a === void 0 ? void 0 : _a.errors;
25904
- if (errors)
25905
- throw errors;
26043
+ const response = await execute(mutation$3, { apiHost, token }, { parentQuoteChangeId, priceListId, quoteId });
25906
26044
  return response.quoteChangeCreate;
25907
26045
  };
25908
26046
 
25909
- const QUOTE_CHANGE_DELETE = `
25910
- ${QUOTE_FIELDS()}
25911
- mutation QuoteChangeDelete($id: ID!) {
25912
- quoteChangeDelete(id: $id) {
25913
- errors
25914
- quoteChange {
25915
- quote {
25916
- ...QuoteFields
26047
+ const mutation$2 = t(`
26048
+ mutation QuoteChangeDelete($id: ID!) {
26049
+ quoteChangeDelete(id: $id) {
26050
+ errors
26051
+ quoteChange {
26052
+ quote {
26053
+ ...QuoteContext_QuoteFragment
26054
+ }
25917
26055
  }
25918
26056
  }
25919
26057
  }
25920
- }
25921
- `;
26058
+ `, [QuoteContext_QuoteFragment]);
25922
26059
  const quoteChangeDelete = async ({ id, apiHost, token, }) => {
25923
- var _a;
25924
- const vars = {
25925
- id,
25926
- };
25927
- const response = await gqlRequest({
25928
- query: QUOTE_CHANGE_DELETE,
25929
- token,
25930
- vars,
25931
- apiHost,
25932
- });
25933
- const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteChangeDelete) === null || _a === void 0 ? void 0 : _a.errors;
25934
- if (errors)
25935
- throw errors;
26060
+ const response = await execute(mutation$2, { apiHost, token }, { id });
25936
26061
  return response.quoteChangeDelete;
25937
26062
  };
25938
26063
 
25939
- const useToggleAddonPlan = (quote, addonPriceListId, selectedPriceList, setIsAddonPlanLoading) => {
26064
+ const useToggleAddonPlan = (maskedQuote, addonPriceListId, selectedPriceList, setIsAddonPlanLoading) => {
25940
26065
  const token = useToken();
25941
26066
  const isAdded = useRef(false);
25942
- const queryClient = useQueryClient();
25943
26067
  const { apiHost } = useContext(BunnyContext);
26068
+ const { setQuoteQueryData } = useSetQuoteQueryData();
26069
+ // Read fragments
26070
+ const quote = readFragment(useToggleAddonPlan_QuoteFragment, maskedQuote);
25944
26071
  const parentQuoteChange = useMemo(() => {
25945
- return quote === null || quote === void 0 ? void 0 : quote.quoteChanges.find(qc => qc.priceList.id === selectedPriceList.id);
26072
+ var _a;
26073
+ return (_a = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _a === void 0 ? void 0 : _a.find(qc => { var _a; return ((_a = qc.priceList) === null || _a === void 0 ? void 0 : _a.id) === selectedPriceList.id; });
25946
26074
  }, [quote, selectedPriceList]);
25947
26075
  const { mutate: addAddonQuoteChange, isPending: isAddingAddonQuoteChange } = useMutation({
25948
26076
  mutationFn: quoteChangeCreate,
25949
- onSuccess: (quoteChangeCreate) => {
26077
+ onSuccess: quoteChangeCreate => {
26078
+ var _a;
25950
26079
  isAdded.current = true;
25951
- const updatedQuote = quoteChangeCreate.quoteChange.quote;
25952
- queryClient.setQueryData(QueryKeyFactory$1.default.createObjectKey({
25953
- objectName: 'editingQuote',
25954
- id: quote === null || quote === void 0 ? void 0 : quote.id,
25955
- token,
25956
- }), updatedQuote);
26080
+ const updatedQuote = (_a = quoteChangeCreate === null || quoteChangeCreate === void 0 ? void 0 : quoteChangeCreate.quoteChange) === null || _a === void 0 ? void 0 : _a.quote;
26081
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
26082
+ throw new Error('Updated quote ID not found');
26083
+ }
26084
+ if (!updatedQuote) {
26085
+ throw new Error('Updated quote not found');
26086
+ }
26087
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, updatedQuote);
25957
26088
  },
25958
26089
  });
25959
26090
  const { mutate: deleteQuoteChange, isPending: isDeletingQuoteChange } = useMutation({
25960
26091
  mutationFn: quoteChangeDelete,
25961
- onSuccess: (quoteChangeDelete) => {
26092
+ onSuccess: quoteChangeDelete => {
26093
+ var _a;
25962
26094
  isAdded.current = false;
25963
- const updatedQuote = quoteChangeDelete.quoteChange.quote;
25964
- queryClient.setQueryData(QueryKeyFactory$1.default.createObjectKey({
25965
- objectName: 'editingQuote',
25966
- id: quote === null || quote === void 0 ? void 0 : quote.id,
25967
- token,
25968
- }), updatedQuote);
26095
+ const updatedQuote = (_a = quoteChangeDelete === null || quoteChangeDelete === void 0 ? void 0 : quoteChangeDelete.quoteChange) === null || _a === void 0 ? void 0 : _a.quote;
26096
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
26097
+ throw new Error('Updated quote ID not found');
26098
+ }
26099
+ if (!updatedQuote) {
26100
+ throw new Error('Updated quote not found');
26101
+ }
26102
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, updatedQuote);
25969
26103
  },
25970
26104
  });
25971
26105
  function handleAddAddonQuoteChange() {
@@ -25975,6 +26109,9 @@ const useToggleAddonPlan = (quote, addonPriceListId, selectedPriceList, setIsAdd
25975
26109
  if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
25976
26110
  throw new Error('Quote ID not found');
25977
26111
  }
26112
+ if (!parentQuoteChange.id) {
26113
+ throw new Error('Parent quote change ID not found');
26114
+ }
25978
26115
  addAddonQuoteChange({
25979
26116
  parentQuoteChangeId: parentQuoteChange.id,
25980
26117
  priceListId: addonPriceListId,
@@ -25984,9 +26121,10 @@ const useToggleAddonPlan = (quote, addonPriceListId, selectedPriceList, setIsAdd
25984
26121
  });
25985
26122
  }
25986
26123
  function handleDeleteQuoteChange() {
25987
- const quoteChange = quote === null || quote === void 0 ? void 0 : quote.quoteChanges.find(qc => qc.priceList.id === addonPriceListId);
25988
- if (!quoteChange) {
25989
- throw new Error('Quote change not found');
26124
+ var _a;
26125
+ const quoteChange = (_a = quote === null || quote === void 0 ? void 0 : quote.quoteChanges) === null || _a === void 0 ? void 0 : _a.find(qc => { var _a; return ((_a = qc.priceList) === null || _a === void 0 ? void 0 : _a.id) === addonPriceListId; });
26126
+ if (!(quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.id)) {
26127
+ throw new Error('Quote change ID not found');
25990
26128
  }
25991
26129
  deleteQuoteChange({
25992
26130
  id: quoteChange.id,
@@ -26020,6 +26158,7 @@ const AddonPlanRow_PriceListFragment = t(`
26020
26158
  plan {
26021
26159
  description
26022
26160
  name
26161
+ pricingDescription
26023
26162
  }
26024
26163
  ...PriceListCardPriceDescription_PriceListFragment
26025
26164
  ...PriceListCardPrice_PriceListFragment
@@ -26033,16 +26172,18 @@ const AddonPlanRow_PriceListFragment = t(`
26033
26172
  PriceListCardPriceDescription_PriceListFragment,
26034
26173
  ]);
26035
26174
  function AddonPlanRow({ addonPriceList: maskedAddonPriceList, selectedPriceList, onClickSelect, isPurchased, }) {
26036
- var _a, _b, _c, _d, _e, _f;
26175
+ var _a, _b, _c, _d, _e, _f, _g;
26037
26176
  // Read fragments
26038
26177
  const addonPriceList = readFragment(AddonPlanRow_PriceListFragment, maskedAddonPriceList);
26039
- const { quote, setIsAddonPlanLoading } = useContext(QuoteContext);
26178
+ const { quote: maskedQuote, setIsAddonPlanLoading } = useContext(QuoteContext);
26179
+ const quote = readFragment(AddonPlanRow_QuoteFragment, maskedQuote);
26040
26180
  const { shadow, isInPreviewMode } = useContext(SubscriptionsContext);
26041
26181
  const { isPending, addedQuoteChange, addAddonQuoteChange, deleteQuoteChange } = useToggleAddonPlan(quote, addonPriceList.id, selectedPriceList, setIsAddonPlanLoading);
26042
26182
  const activeCharge = (_a = getActivePlanPriceData(addonPriceList, selectedPriceList)) === null || _a === void 0 ? void 0 : _a.activeCharge;
26043
26183
  // Derived state
26044
26184
  const switchDisabled = isInPreviewMode || isPurchased;
26045
- return (jsxs("div", { className: `bunny-flex bunny-flex-row bunny-gap-2 bunny-justify-between bunny-items-center bunny-p-4 bunny-rounded-md bunny-bg-white ${shadow ? `shadow-${shadow}` : ''} bunny-mb-2`, children: [jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2 bunny-items-center", children: [jsx("div", { className: `bunny-font-medium bunny-text-center bunny-text-orange-600`, children: (_b = addonPriceList.plan) === null || _b === void 0 ? void 0 : _b.name }), jsx(PriceListCardDescription, { description: (_d = (_c = addonPriceList.plan) === null || _c === void 0 ? void 0 : _c.description) !== null && _d !== void 0 ? _d : '' }), jsx(PriceListCardPrice, { priceList: addonPriceList, className: "bunny-text-sm bunny-font-medium bunny-text-gray-900" }), jsx(PriceListCardPriceDescription, { feature: activeCharge === null || activeCharge === void 0 ? void 0 : activeCharge.feature, priceList: addonPriceList }), jsx(Button, { type: "link", onClick: onClickSelect, children: jsx(InfoCircleOutlined, {}) })] }), jsx(Switch, { id: addonPlanSwitchTestId((_f = (_e = addonPriceList.plan) === null || _e === void 0 ? void 0 : _e.name) !== null && _f !== void 0 ? _f : ''), loading: isPending && !switchDisabled, checked: addedQuoteChange || isPurchased, onChange: (checked) => {
26185
+ const hasCustomPrice = ((_b = addonPriceList.plan) === null || _b === void 0 ? void 0 : _b.pricingDescription) != null;
26186
+ return (jsxs("div", { className: `bunny-flex bunny-flex-row bunny-gap-2 bunny-justify-between bunny-items-center bunny-p-4 bunny-rounded-md bunny-bg-white ${shadow ? `shadow-${shadow}` : ''} bunny-mb-2`, children: [jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2 bunny-items-center", children: [jsx("div", { className: `bunny-font-medium bunny-text-center bunny-text-orange-600`, children: (_c = addonPriceList.plan) === null || _c === void 0 ? void 0 : _c.name }), jsx(PriceListCardDescription, { description: (_e = (_d = addonPriceList.plan) === null || _d === void 0 ? void 0 : _d.description) !== null && _e !== void 0 ? _e : '' }), !hasCustomPrice && (jsx(PriceListCardPrice, { priceList: addonPriceList, className: "bunny-text-sm bunny-font-medium bunny-text-gray-900" })), jsx(PriceListCardPriceDescription, { feature: activeCharge === null || activeCharge === void 0 ? void 0 : activeCharge.feature, priceList: addonPriceList }), jsx(Button, { type: "link", onClick: onClickSelect, children: jsx(InfoCircleOutlined, {}) })] }), jsx(Switch, { id: addonPlanSwitchTestId((_g = (_f = addonPriceList.plan) === null || _f === void 0 ? void 0 : _f.name) !== null && _g !== void 0 ? _g : ''), loading: isPending && !switchDisabled, checked: addedQuoteChange || isPurchased, onChange: (checked) => {
26046
26187
  if (checked) {
26047
26188
  addAddonQuoteChange();
26048
26189
  }
@@ -26066,7 +26207,7 @@ const AddonPlans_PlanFragment = t(`
26066
26207
  }
26067
26208
  `, [AddonPlanModal_PriceListFragment, AddonPlanRow_PriceListFragment]);
26068
26209
 
26069
- const query = t(`
26210
+ const query$2 = t(`
26070
26211
  query PriceList($id: ID!) {
26071
26212
  priceList(id: $id) {
26072
26213
  addonPlans {
@@ -26080,7 +26221,7 @@ const query = t(`
26080
26221
  `, [AddonPlans_PlanFragment]);
26081
26222
  const getAddonPlans = async ({ token, id, apiHost, }) => {
26082
26223
  var _a;
26083
- const response = await execute(query, { apiHost, token }, { id });
26224
+ const response = await execute(query$2, { apiHost, token }, { id });
26084
26225
  const addonPlans = (_a = response === null || response === void 0 ? void 0 : response.priceList) === null || _a === void 0 ? void 0 : _a.addonPlans;
26085
26226
  // for each addon plan, filter out the price lists that are not visible
26086
26227
  const visibleAddonPlans = addonPlans === null || addonPlans === void 0 ? void 0 : addonPlans.map(addonPlan => {
@@ -26188,7 +26329,10 @@ const PriceListGrid = ({ availablePriceLists, priceListChangeOptions, priceListS
26188
26329
  onClickPriceListCard: onClickPriceListCard })) : (jsx(PriceListGridDesktop, { availablePriceLists: availablePriceLists, priceListChangeOptions: priceListChangeOptions, priceListStart: priceListStart, selectedPriceList: selectedPriceList, selectedProduct: selectedProduct, setPriceListStart: setPriceListStart, subscriptions: subscriptions, trialRemainingDays: trialRemainingDays, selectedBillingPeriod: selectedBillingPeriod, onClickPriceListCard: onClickPriceListCard }));
26189
26330
  };
26190
26331
 
26191
- const createAvailableBillingPeriods = (priceLists, selectedProduct) => {
26332
+ const createAvailableBillingPeriods = (priceLists, selectedProduct, upgradingSubscription) => {
26333
+ if ((upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.plan.addon) === true) {
26334
+ return [upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.periodMonths];
26335
+ }
26192
26336
  return priceLists === null || priceLists === void 0 ? void 0 : priceLists.filter(priceList => priceList.product.id === (selectedProduct === null || selectedProduct === void 0 ? void 0 : selectedProduct.id)).map(priceList => priceList.periodMonths).sort((a, b) => a - b).filter((currentValue, index, array) => index === array.indexOf(currentValue));
26193
26337
  };
26194
26338
  const showInfoNotification$1 = useInfoNotification();
@@ -26202,11 +26346,18 @@ const PriceListSelector = ({ arePlanChangeOptionsLoading, areSubscriptionsLoadin
26202
26346
  const [selectedBillingPeriod, setSelectedBillingPeriod] = useState(null);
26203
26347
  const [priceListStart, setPriceListStart] = useState(0);
26204
26348
  // Derived state
26205
- const availableBillingPeriods = useMemo(() => createAvailableBillingPeriods(priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, selectedProduct), [priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, selectedProduct]);
26349
+ const availableBillingPeriods = useMemo(() => createAvailableBillingPeriods(priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, selectedProduct, upgradingSubscription), [priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, selectedProduct]);
26350
+ // TODO: clean up available pricelists calculation. We should calculate it once, not three times.
26351
+ const subscriptionIsAddon = (upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.plan.addon) === true;
26206
26352
  const availablePriceLists = useMemo(() => {
26207
26353
  var _a;
26208
- return (((_a = priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists) === null || _a === void 0 ? void 0 : _a.filter(priceList => periodMonthsConverter(priceList.periodMonths) === selectedBillingPeriod &&
26209
- priceList.product.id === (selectedProduct === null || selectedProduct === void 0 ? void 0 : selectedProduct.id)).filter(priceList => priceList.plan.addon !== true)) || []);
26354
+ const priceLists = (_a = priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists) === null || _a === void 0 ? void 0 : _a.filter(priceList => periodMonthsConverter(priceList.periodMonths) === selectedBillingPeriod &&
26355
+ priceList.product.id === (selectedProduct === null || selectedProduct === void 0 ? void 0 : selectedProduct.id));
26356
+ // If the subscription is an addon, we should only show its price lists because we don't support changing add-on plans.
26357
+ if (subscriptionIsAddon) {
26358
+ return ((priceLists === null || priceLists === void 0 ? void 0 : priceLists.filter(priceList => priceList.plan.id === (upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.plan.id))) || []);
26359
+ }
26360
+ return priceLists.filter(priceList => priceList.plan.addon !== true) || [];
26210
26361
  }, [priceListChangeOptions, selectedBillingPeriod, selectedProduct]);
26211
26362
  // Handlers
26212
26363
  const onChangeBillingPeriod = useCallback((billingPeriod) => {
@@ -26235,7 +26386,7 @@ const PriceListSelector = ({ arePlanChangeOptionsLoading, areSubscriptionsLoadin
26235
26386
  }
26236
26387
  }, [selectedPriceList, priceListChangeOptions, upgradingSubscription]);
26237
26388
  const onChangeProduct = useCallback((product) => {
26238
- const newAvailableBillingPeriods = createAvailableBillingPeriods(priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, product);
26389
+ const newAvailableBillingPeriods = createAvailableBillingPeriods(priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, product, upgradingSubscription);
26239
26390
  if (selectedBillingPeriod &&
26240
26391
  !(newAvailableBillingPeriods === null || newAvailableBillingPeriods === void 0 ? void 0 : newAvailableBillingPeriods.includes(billingPeriodConverter(selectedBillingPeriod)))) {
26241
26392
  onChangeBillingPeriod(periodMonthsConverter((newAvailableBillingPeriods === null || newAvailableBillingPeriods === void 0 ? void 0 : newAvailableBillingPeriods[0]) !== undefined ? newAvailableBillingPeriods[0] : 1));
@@ -26246,7 +26397,7 @@ const PriceListSelector = ({ arePlanChangeOptionsLoading, areSubscriptionsLoadin
26246
26397
  const initialProduct = (_a = priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.products) === null || _a === void 0 ? void 0 : _a[0];
26247
26398
  const initialBillingPeriod = useMemo(() => {
26248
26399
  var _a, _b, _c;
26249
- const initialAvailableBillingPeriods = createAvailableBillingPeriods(priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, initialProduct);
26400
+ const initialAvailableBillingPeriods = createAvailableBillingPeriods(priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, initialProduct, upgradingSubscription);
26250
26401
  const periodMonthsConverted = periodMonthsConverter((_b = (_a = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList) === null || _a === void 0 ? void 0 : _a.periodMonths) !== null && _b !== void 0 ? _b : null);
26251
26402
  if ((upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList) &&
26252
26403
  periodMonthsConverted &&
@@ -26902,80 +27053,177 @@ const PageSubTitle = ({ title }) => {
26902
27053
  return (jsx("div", { className: "bunny-shrink-0", style: { color: secondaryColor }, children: title }));
26903
27054
  };
26904
27055
 
26905
- const MUTATION = `
26906
- mutation BillingDetailsUpdate(
26907
- $attributes: BillingDetailsAttributes!) {
26908
- billingDetailsUpdate(
26909
- attributes: $attributes
26910
- ) {
26911
- billingDetails {
26912
- billingCity
26913
- billingContact {
26914
- email
27056
+ const AccountContactsFragment = t(`
27057
+ fragment AccountContactsFragment on Contact {
27058
+ id
27059
+ email
27060
+ firstName
27061
+ }
27062
+ `, []);
27063
+
27064
+ const AddContactButton = ({ onClick }) => {
27065
+ return (jsx("div", { className: "bunny-border-t bunny-border-gray-200 bunny-p-2", children: jsx(Button, { type: "text", className: "bunny-w-full bunny-text-left", onClick: onClick, children: "+ Add new contact" }) }));
27066
+ };
27067
+
27068
+ const useSetAccountContactsQueryData = () => {
27069
+ const token = useToken();
27070
+ const queryClient = useQueryClient();
27071
+ const setAccountContactsQueryData = (accountId, updater) => {
27072
+ queryClient.setQueryData(QueryKeyFactory.accountContactsKey({ accountId, token }), updater);
27073
+ };
27074
+ return { setAccountContactsQueryData };
27075
+ };
27076
+
27077
+ const mutation$1 = t(`
27078
+ mutation ContactCreate($attributes: ContactAttributes!) {
27079
+ contactCreate(attributes: $attributes) {
27080
+ contact {
27081
+ id
27082
+ account {
27083
+ contacts {
27084
+ ...AccountContactsFragment
27085
+ }
26915
27086
  }
26916
- billingCountry
26917
- billingState
26918
- billingStreet
26919
- billingZip
26920
- name
26921
- taxNumber
26922
27087
  }
26923
27088
  errors
26924
27089
  }
26925
- }
26926
- `;
26927
- const billingDetailsUpdate = async ({ attributes, token, apiHost, }) => {
26928
- var _a;
26929
- const vars = { attributes };
26930
- const response = await gqlRequest({
26931
- query: MUTATION,
26932
- token,
26933
- vars,
26934
- apiHost,
27090
+ }
27091
+ `, [AccountContactsFragment]);
27092
+ const contactCreate = async ({ attributes, apiHost, token }) => {
27093
+ var _a, _b;
27094
+ const response = await execute(mutation$1, { apiHost, token }, { attributes });
27095
+ if ((_a = response.contactCreate) === null || _a === void 0 ? void 0 : _a.errors) {
27096
+ throw new Error(response.contactCreate.errors[0]);
27097
+ }
27098
+ return (_b = response.contactCreate) === null || _b === void 0 ? void 0 : _b.contact;
27099
+ };
27100
+
27101
+ const AddContactModal = ({ open, onClose, accountId, onContactCreated, }) => {
27102
+ const [form] = Form.useForm();
27103
+ const { apiHost } = useContext(BunnyContext);
27104
+ const token = useToken();
27105
+ const showErrorNotification = useErrorNotification();
27106
+ const showSuccessNotification = useSuccessNotification();
27107
+ const { setAccountContactsQueryData } = useSetAccountContactsQueryData();
27108
+ const { mutate: createContact, isPending: isCreatingContact } = useMutation({
27109
+ mutationFn: (attributes) => contactCreate({ attributes, apiHost, token }),
27110
+ onSuccess: newContact => {
27111
+ var _a, _b;
27112
+ showSuccessNotification('Contact created successfully');
27113
+ // Add the new contact to the cache
27114
+ if (newContact && accountId) {
27115
+ setAccountContactsQueryData(accountId, (_b = (_a = newContact === null || newContact === void 0 ? void 0 : newContact.account) === null || _a === void 0 ? void 0 : _a.contacts) !== null && _b !== void 0 ? _b : null);
27116
+ }
27117
+ onClose();
27118
+ form.resetFields();
27119
+ const newContactData = newContact ? readFragment(AccountContactsFragment, newContact) : null;
27120
+ if (newContactData === null || newContactData === void 0 ? void 0 : newContactData.id) {
27121
+ onContactCreated === null || onContactCreated === void 0 ? void 0 : onContactCreated(newContactData.id);
27122
+ }
27123
+ },
26935
27124
  });
26936
- const errors = (_a = response === null || response === void 0 ? void 0 : response.billingDetailsUpdate) === null || _a === void 0 ? void 0 : _a.errors;
26937
- if (errors)
26938
- throw errors;
26939
- return response.billingDetailsUpdate;
27125
+ const handleAddContact = () => {
27126
+ if (!accountId) {
27127
+ showErrorNotification('Account ID is required to create a contact');
27128
+ return;
27129
+ }
27130
+ form.validateFields().then(values => {
27131
+ createContact({
27132
+ email: values.email || null,
27133
+ firstName: values.firstName || null,
27134
+ lastName: values.lastName || null,
27135
+ accountId: accountId,
27136
+ portalAccess: true,
27137
+ });
27138
+ });
27139
+ };
27140
+ return (jsx(Modal, { title: "Add new contact", open: open, onCancel: () => {
27141
+ onClose();
27142
+ form.resetFields();
27143
+ }, footer: [
27144
+ jsx(Button, { onClick: () => {
27145
+ onClose();
27146
+ form.resetFields();
27147
+ }, children: "Cancel" }, "cancel"),
27148
+ jsx(Button, { type: "primary", loading: isCreatingContact, onClick: handleAddContact, children: "Add contact" }, "submit"),
27149
+ ], children: jsxs(Form, { form: form, layout: "vertical", className: "bunny-flex bunny-flex-col bunny-gap-2", children: [jsx(Form.Item, { label: "First name", name: "firstName", rules: [{ required: false }], children: jsx(Input, { placeholder: "Enter first name" }) }), jsx(Form.Item, { label: "Last name", name: "lastName", rules: [{ required: false }], children: jsx(Input, { placeholder: "Enter last name" }) }), jsx(Form.Item, { label: "Email", name: "email", rules: [
27150
+ { required: true, message: 'Email is required' },
27151
+ { type: 'email', message: 'Please enter a valid email' },
27152
+ ], children: jsx(Input, { placeholder: "Enter email" }) })] }) }));
26940
27153
  };
26941
27154
 
26942
- const billingDetailsQuery = () => `
26943
- query BillingDetails {
26944
- billingDetails {
26945
- billingCity
26946
- billingContact {
26947
- email
26948
- }
26949
- billingCountry
26950
- billingState
26951
- billingStreet
26952
- billingZip
26953
- name
26954
- taxNumber
26955
- currency {
27155
+ const BillingDetailsSection_AccountFragment = t(`
27156
+ fragment BillingDetailsSection_AccountFragment on Account {
26956
27157
  id
27158
+ name
27159
+ billingStreet
27160
+ billingCity
27161
+ billingState
27162
+ billingZip
27163
+ billingCountry
27164
+ taxNumber
27165
+ billingContactId
27166
+ secondaryBillingContactIds
27167
+ billingContact {
27168
+ email
27169
+ firstName
27170
+ }
26957
27171
  }
26958
- }
26959
- }`;
26960
- const getBillingDetails = async ({ token, apiHost }) => {
27172
+ `, []);
27173
+
27174
+ const mutation = t(`
27175
+ mutation AccountUpdate($id: ID!, $attributes: AccountAttributes!) {
27176
+ accountUpdate(id: $id, attributes: $attributes) {
27177
+ account {
27178
+ ...BillingDetailsSection_AccountFragment
27179
+ }
27180
+ errors
27181
+ }
27182
+ }
27183
+ `, [BillingDetailsSection_AccountFragment]);
27184
+ const accountUpdate = async ({ accountId, attributes, apiHost, token, }) => {
26961
27185
  var _a;
26962
- const response = await gqlRequest({
26963
- query: billingDetailsQuery(),
26964
- token,
26965
- apiHost,
26966
- });
26967
- if (response === null || response === void 0 ? void 0 : response.errors) {
26968
- throw new Error((_a = response === null || response === void 0 ? void 0 : response.errors[0]) === null || _a === void 0 ? void 0 : _a.message);
27186
+ const response = await execute(mutation, { apiHost, token }, { id: accountId, attributes });
27187
+ return (_a = response.accountUpdate) === null || _a === void 0 ? void 0 : _a.account;
27188
+ };
27189
+
27190
+ const query$1 = t(`
27191
+ query GetAccount($id: ID!) {
27192
+ account(id: $id) {
27193
+ ...BillingDetailsSection_AccountFragment
27194
+ }
27195
+ }
27196
+ `, [BillingDetailsSection_AccountFragment]);
27197
+ const getAccount = async ({ accountId, apiHost, token, }) => {
27198
+ const response = await execute(query$1, { apiHost, token }, { id: accountId });
27199
+ return response.account;
27200
+ };
27201
+
27202
+ const query = t(`
27203
+ query GetAccountContacts($accountId: ID!) {
27204
+ account(id: $accountId) {
27205
+ id
27206
+ contacts {
27207
+ ...AccountContactsFragment
27208
+ }
27209
+ }
26969
27210
  }
26970
- return response === null || response === void 0 ? void 0 : response.billingDetails;
27211
+ `, [AccountContactsFragment]);
27212
+ const getAccountContacts = async ({ accountId, apiHost, token, }) => {
27213
+ var _a;
27214
+ const response = await execute(query, { apiHost, token }, { accountId });
27215
+ return (_a = response.account) === null || _a === void 0 ? void 0 : _a.contacts;
26971
27216
  };
26972
27217
 
26973
27218
  const { Text } = Typography;
26974
27219
  function BillingDetailsSection({ hidePaymentMethodForm, countryListFilter, }) {
27220
+ var _a, _b, _c;
26975
27221
  // State
26976
27222
  const [isFormEdited, setIsFormEdited] = useState(false);
26977
27223
  const [form] = Form.useForm();
26978
27224
  const values = Form.useWatch([], form);
27225
+ const [isAddContactModalOpen, setIsAddContactModalOpen] = useState(false);
27226
+ const [contactFieldType, setContactFieldType] = useState(null);
26979
27227
  // Context
26980
27228
  const { apiHost } = useContext(BunnyContext);
26981
27229
  const token = useToken();
@@ -26984,14 +27232,37 @@ function BillingDetailsSection({ hidePaymentMethodForm, countryListFilter, }) {
26984
27232
  const queryClient = useQueryClient();
26985
27233
  const showErrorNotification = useErrorNotification();
26986
27234
  const showSuccessNotification = useSuccessNotification();
27235
+ const { currentUser } = useCurrentUserData(token);
27236
+ const accountId = (_a = currentUser === null || currentUser === void 0 ? void 0 : currentUser.account) === null || _a === void 0 ? void 0 : _a.id;
26987
27237
  // Queries
26988
- const { data: billingDetails, isLoading: isLoadingBillingDetails } = useQuery({
26989
- queryKey: QueryKeyFactory$1.default.billingDetailsKey({ token }),
26990
- queryFn: () => getBillingDetails({ token, apiHost }),
27238
+ const { data: maskedAccount, isLoading: isLoadingAccount } = useQuery({
27239
+ queryKey: QueryKeyFactory.accountBillingDetailsKey({ accountId, token }),
27240
+ queryFn: () => {
27241
+ if (!accountId) {
27242
+ throw new Error('Account ID is required');
27243
+ }
27244
+ return getAccount({ accountId, apiHost, token });
27245
+ },
27246
+ enabled: !!accountId,
27247
+ });
27248
+ const account = readFragment(BillingDetailsSection_AccountFragment, maskedAccount);
27249
+ const { data: contacts, isLoading: isLoadingContacts } = useQuery({
27250
+ queryKey: QueryKeyFactory.accountContactsKey({ accountId, token }),
27251
+ queryFn: () => {
27252
+ if (!accountId) {
27253
+ throw new Error('Account ID is required');
27254
+ }
27255
+ return getAccountContacts({ accountId, apiHost, token });
27256
+ },
27257
+ enabled: !!accountId,
26991
27258
  });
26992
- const { mutate: updateBillingDetails, isPending: isUpdatingBillingDetails } = useMutation({
27259
+ const { mutate: updateAccount, isPending: isUpdatingAccount } = useMutation({
26993
27260
  mutationFn: async (changedFormData) => {
26994
- const updatedBillingDetails = await billingDetailsUpdate({
27261
+ if (!accountId) {
27262
+ throw new Error('Account ID is required');
27263
+ }
27264
+ const updatedAccount = await accountUpdate({
27265
+ accountId,
26995
27266
  attributes: {
26996
27267
  name: changedFormData.name,
26997
27268
  billingStreet: changedFormData.billingStreet,
@@ -26999,77 +27270,92 @@ function BillingDetailsSection({ hidePaymentMethodForm, countryListFilter, }) {
26999
27270
  billingZip: changedFormData.billingZip,
27000
27271
  billingState: changedFormData.billingState,
27001
27272
  billingCountry: changedFormData.billingCountry,
27002
- billingContactEmail: changedFormData.billingContactEmail,
27003
27273
  taxNumber: changedFormData.taxNumber,
27274
+ billingContactId: changedFormData.billingContactId || null,
27275
+ secondaryBillingContactIds: Array.isArray(changedFormData.secondaryBillingContactIds)
27276
+ ? changedFormData.secondaryBillingContactIds
27277
+ : null,
27004
27278
  },
27005
27279
  token,
27006
27280
  apiHost,
27007
27281
  });
27008
- queryClient.setQueryData(QueryKeyFactory$1.default.billingDetailsKey({ token }), (old) => {
27009
- return {
27010
- ...old,
27011
- ...updatedBillingDetails.billingDetails,
27012
- };
27013
- });
27014
- return updatedBillingDetails;
27282
+ queryClient.setQueryData(QueryKeyFactory.accountBillingDetailsKey({ accountId, token }), updatedAccount);
27283
+ return updatedAccount;
27015
27284
  },
27016
27285
  onSuccess: () => {
27017
27286
  showSuccessNotification('Your account details have been saved');
27018
27287
  queryClient.invalidateQueries({
27019
- queryKey: QueryKeyFactory$1.default.taxationRequiredAccountFieldsKey({
27288
+ queryKey: QueryKeyFactory.taxationRequiredAccountFieldsKey({
27020
27289
  token,
27021
27290
  }),
27022
27291
  });
27023
27292
  },
27024
27293
  });
27025
- // Set form values when billing details are loaded
27294
+ // Set form values when account is loaded
27026
27295
  useEffect(() => {
27027
- var _a;
27028
- if (billingDetails) {
27296
+ if (account) {
27029
27297
  form.setFieldsValue({
27030
- billingStreet: billingDetails.billingStreet,
27031
- billingCity: billingDetails.billingCity,
27032
- billingZip: billingDetails.billingZip,
27033
- billingState: billingDetails.billingState,
27034
- billingCountry: billingDetails.billingCountry,
27035
- billingContactEmail: (_a = billingDetails.billingContact) === null || _a === void 0 ? void 0 : _a.email,
27036
- taxNumber: billingDetails.taxNumber,
27298
+ billingStreet: account.billingStreet,
27299
+ billingCity: account.billingCity,
27300
+ billingZip: account.billingZip,
27301
+ billingState: account.billingState,
27302
+ billingCountry: account.billingCountry,
27303
+ billingContactId: account.billingContactId,
27304
+ secondaryBillingContactIds: account.secondaryBillingContactIds,
27305
+ taxNumber: account.taxNumber,
27037
27306
  });
27038
27307
  }
27039
- }, [billingDetails]);
27308
+ }, [account]);
27040
27309
  useEffect(() => {
27041
27310
  form.validateFields({ validateOnly: true });
27042
27311
  const isFormEdited = () => {
27043
- var _a;
27044
- if (!billingDetails)
27312
+ if (!account)
27045
27313
  return false;
27046
27314
  const currentValues = form.getFieldsValue();
27047
27315
  const accountValues = {
27048
- billingStreet: billingDetails.billingStreet,
27049
- billingCity: billingDetails.billingCity,
27050
- billingZip: billingDetails.billingZip,
27051
- billingState: billingDetails.billingState,
27052
- billingCountry: billingDetails.billingCountry,
27053
- billingContactEmail: (_a = billingDetails.billingContact) === null || _a === void 0 ? void 0 : _a.email,
27054
- taxNumber: billingDetails.taxNumber,
27316
+ billingStreet: account.billingStreet,
27317
+ billingCity: account.billingCity,
27318
+ billingZip: account.billingZip,
27319
+ billingState: account.billingState,
27320
+ billingCountry: account.billingCountry,
27321
+ billingContactId: account.billingContactId,
27322
+ secondaryBillingContactIds: account.secondaryBillingContactIds,
27323
+ taxNumber: account.taxNumber,
27055
27324
  };
27056
- return Object.keys(currentValues).some(key => {
27325
+ return Object.keys(accountValues).some(key => {
27057
27326
  const value = accountValues[key];
27058
- return currentValues[key] !== value;
27327
+ const currentValue = currentValues[key];
27328
+ // Handle array comparison for secondaryBillingContactIds
27329
+ if (Array.isArray(value) && Array.isArray(currentValue)) {
27330
+ return JSON.stringify(value === null || value === void 0 ? void 0 : value.sort()) !== JSON.stringify(currentValue === null || currentValue === void 0 ? void 0 : currentValue.sort());
27331
+ }
27332
+ return currentValue !== value;
27059
27333
  });
27060
27334
  };
27061
27335
  setIsFormEdited(isFormEdited());
27062
- }, [form, values, billingDetails]);
27336
+ }, [form, values, account]);
27063
27337
  // Validate form fields when isFormEdited changes
27064
27338
  useEffect(() => {
27065
27339
  const validateOnly = isFormEdited ? false : true;
27066
27340
  form.validateFields({ validateOnly: validateOnly });
27067
27341
  }, [isFormEdited]);
27342
+ const handleContactCreated = (contactId) => {
27343
+ if (contactFieldType === 'primary') {
27344
+ form.setFieldValue('billingContactId', contactId);
27345
+ }
27346
+ else if (contactFieldType === 'secondary') {
27347
+ const currentSecondaryContacts = form.getFieldValue('secondaryBillingContactIds') || [];
27348
+ if (!currentSecondaryContacts.includes(contactId)) {
27349
+ form.setFieldValue('secondaryBillingContactIds', [...currentSecondaryContacts, contactId]);
27350
+ }
27351
+ }
27352
+ setContactFieldType(null);
27353
+ };
27068
27354
  const saveBillingDetails = async () => {
27069
27355
  form.validateFields({ validateOnly: false }).then(async () => {
27070
27356
  try {
27071
27357
  await form.validateFields();
27072
- updateBillingDetails(form.getFieldsValue());
27358
+ updateAccount(form.getFieldsValue());
27073
27359
  }
27074
27360
  catch (error) {
27075
27361
  if (error instanceof Error) {
@@ -27087,21 +27373,38 @@ function BillingDetailsSection({ hidePaymentMethodForm, countryListFilter, }) {
27087
27373
  const filteredCountryList = useMemo(() => {
27088
27374
  return countryListFilter ? Lists.COUNTRY_LIST.filter(countryListFilter) : Lists.COUNTRY_LIST;
27089
27375
  }, [countryListFilter]);
27090
- return (jsx("div", { className: `${isMobile || hidePaymentMethodForm ? 'bunny-w-full' : 'bunny-w-1/2'}`, children: jsxs("div", { className: "bunny-px-4", children: [jsxs(Skeleton, { loading: isLoadingBillingDetails, children: [jsx("div", { className: "bunny-mb-2 bunny-pl-1", children: jsx(Text, { className: "bunny-font-medium bunny-text-lg", children: (billingDetails === null || billingDetails === void 0 ? void 0 : billingDetails.name) || 'No company name' }) }), jsxs(Form, { className: "bunny-flex bunny-flex-col bunny-gap-2", form: form, layout: "vertical", disabled: isUpdatingBillingDetails, autoComplete: "off", requiredMark: false, children: [jsx(Form.Item, { label: "Street address", name: "billingStreet", rules: [{ required: true, message: 'Street address is required' }], children: jsx(Input, {}) }), jsxs("div", { className: "bunny-flex bunny-gap-4", children: [jsx(Form.Item, { label: "City", name: "billingCity", rules: [{ required: true, message: 'City is required' }], className: "bunny-flex-1", children: jsx(Input, {}) }), jsx(Form.Item, { label: "Zipcode", name: "billingZip", rules: [{ required: true, message: 'Zipcode is required' }], className: "bunny-flex-1", children: jsx(Input, {}) })] }), jsxs("div", { className: `bunny-flex ${isMobile ? 'bunny-flex-row bunny-pb-2' : 'bunny-flex-row'} bunny-gap-4`, children: [jsx("div", { className: "bunny-flex-1 bunny-w-1/2", children: jsx(Form.Item, { label: "State", name: "billingState", rules: [
27091
- {
27092
- required: false,
27093
- },
27094
- ], children: jsx(Input, {}) }) }), jsx("div", { className: "bunny-flex-1 bunny-w-1/2", children: jsx(Form.Item, { label: "Country", name: "billingCountry", rules: [{ required: true, message: 'Country is required' }], children: jsx(Select, { className: "bunny-w-full", options: filteredCountryList, placeholder: "Select a country", popupMatchSelectWidth: false, showSearch: true, filterOption: (input, option) => {
27095
- var _a, _b;
27096
- return ((_a = option === null || option === void 0 ? void 0 : option.label) !== null && _a !== void 0 ? _a : '').toLowerCase().includes(input.toLowerCase()) ||
27097
- ((_b = option === null || option === void 0 ? void 0 : option.value) !== null && _b !== void 0 ? _b : '').toLowerCase().includes(input.toLowerCase());
27098
- } }) }) })] }), jsx(Form.Item, { label: "Email", name: "billingContactEmail", rules: [
27099
- {
27100
- required: true,
27101
- message: 'Email is required',
27102
- type: 'email',
27103
- },
27104
- ], children: jsx(Input, {}) }), jsx(Form.Item, { label: "Tax ID", name: "taxNumber", tooltip: "Tax ID will be printed on quotes and invoices below the account's address", rules: [{ required: false }], children: jsx(Input, {}) })] })] }), jsx(Button, { disabled: !isFormEdited || isUpdatingBillingDetails, className: "bunny-w-full bunny-mt-4", type: "primary", onClick: saveBillingDetails, children: "Save" })] }) }));
27376
+ const isLoading = isLoadingAccount || isLoadingContacts;
27377
+ return (jsxs("div", { className: `${isMobile || hidePaymentMethodForm ? 'bunny-w-full' : 'bunny-w-1/2'}`, children: [jsxs("div", { className: "bunny-px-4", children: [jsxs(Skeleton, { loading: isLoading || account === undefined, children: [jsx("div", { className: "bunny-mb-2 bunny-pl-1", children: jsx(Text, { className: "bunny-font-medium bunny-text-lg", children: (account === null || account === void 0 ? void 0 : account.name) || 'No company name' }) }), jsxs(Form, { className: "bunny-flex bunny-flex-col bunny-gap-2", form: form, layout: "vertical", disabled: isUpdatingAccount, autoComplete: "off", requiredMark: false, children: [jsx(Form.Item, { label: "Street address", name: "billingStreet", rules: [{ required: true, message: 'Street address is required' }], children: jsx(Input, {}) }), jsxs("div", { className: "bunny-flex bunny-gap-4", children: [jsx(Form.Item, { label: "City", name: "billingCity", rules: [{ required: true, message: 'City is required' }], className: "bunny-flex-1", children: jsx(Input, {}) }), jsx(Form.Item, { label: "Zipcode", name: "billingZip", rules: [{ required: true, message: 'Zipcode is required' }], className: "bunny-flex-1", children: jsx(Input, {}) })] }), jsxs("div", { className: `bunny-flex ${isMobile ? 'bunny-flex-row bunny-pb-2' : 'bunny-flex-row'} bunny-gap-4`, children: [jsx("div", { className: "bunny-flex-1 bunny-w-1/2", children: jsx(Form.Item, { label: "State", name: "billingState", rules: [
27378
+ {
27379
+ required: false,
27380
+ },
27381
+ ], children: jsx(Input, {}) }) }), jsx("div", { className: "bunny-flex-1 bunny-w-1/2", children: jsx(Form.Item, { label: "Country", name: "billingCountry", rules: [{ required: true, message: 'Country is required' }], children: jsx(Select, { className: "bunny-w-full", options: filteredCountryList, placeholder: "Select a country", popupMatchSelectWidth: false, showSearch: true, filterOption: (input, option) => {
27382
+ var _a, _b;
27383
+ return ((_a = option === null || option === void 0 ? void 0 : option.label) !== null && _a !== void 0 ? _a : '').toLowerCase().includes(input.toLowerCase()) ||
27384
+ ((_b = option === null || option === void 0 ? void 0 : option.value) !== null && _b !== void 0 ? _b : '').toLowerCase().includes(input.toLowerCase());
27385
+ } }) }) })] }), jsx(Form.Item, { label: "Primary billing contact", name: "billingContactId", rules: [{ required: true, message: 'Primary billing contact is required' }], children: jsx(Select, { className: "bunny-w-full", placeholder: "Select a contact", options: (_b = contacts === null || contacts === void 0 ? void 0 : contacts.map(contact => {
27386
+ const contactData = readFragment(AccountContactsFragment, contact);
27387
+ return {
27388
+ label: (contactData === null || contactData === void 0 ? void 0 : contactData.firstName)
27389
+ ? `${contactData.firstName}`
27390
+ : contactData === null || contactData === void 0 ? void 0 : contactData.email,
27391
+ value: contactData === null || contactData === void 0 ? void 0 : contactData.id,
27392
+ };
27393
+ })) !== null && _b !== void 0 ? _b : [], popupRender: menu => (jsxs(Fragment, { children: [menu, jsx(AddContactButton, { onClick: () => setIsAddContactModalOpen(true) })] })) }) }), jsx(Form.Item, { label: "Secondary billing contacts", name: "secondaryBillingContactIds", children: jsx(Select, { className: "bunny-w-full", mode: "multiple", maxTagCount: "responsive", placeholder: "Select contacts", options: (_c = contacts === null || contacts === void 0 ? void 0 : contacts.map(contact => {
27394
+ const contactData = readFragment(AccountContactsFragment, contact);
27395
+ return {
27396
+ label: (contactData === null || contactData === void 0 ? void 0 : contactData.firstName)
27397
+ ? `${contactData.firstName}`
27398
+ : contactData === null || contactData === void 0 ? void 0 : contactData.email,
27399
+ value: contactData === null || contactData === void 0 ? void 0 : contactData.id,
27400
+ };
27401
+ })) !== null && _c !== void 0 ? _c : [], popupRender: menu => (jsxs(Fragment, { children: [menu, jsx(AddContactButton, { onClick: () => {
27402
+ setContactFieldType('secondary');
27403
+ setIsAddContactModalOpen(true);
27404
+ } })] })) }) }), jsx(Form.Item, { label: "Tax ID", name: "taxNumber", tooltip: "Tax ID will be printed on quotes and invoices below the account's address", rules: [{ required: false }], children: jsx(Input, {}) })] })] }), jsx(Button, { disabled: !isFormEdited || isUpdatingAccount || isLoading, className: "bunny-w-full bunny-mt-4", type: "primary", onClick: saveBillingDetails, children: "Save" })] }), jsx(AddContactModal, { open: isAddContactModalOpen, onClose: () => {
27405
+ setIsAddContactModalOpen(false);
27406
+ setContactFieldType(null);
27407
+ }, accountId: accountId, onContactCreated: handleContactCreated })] }));
27105
27408
  }
27106
27409
 
27107
27410
  const BillingDetails = ({ className, countryListFilter, hideBillingDetailsForm = false, hidePaymentMethodForm = false, isCardEnabled = true, isUpgradeFromTrial = false, shadow = 'shadow-md', onSavePaymentMethod, }) => {