@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/cjs/index.js CHANGED
@@ -48,7 +48,7 @@ function styleInject(css, ref) {
48
48
  }
49
49
  }
50
50
 
51
- 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";
51
+ 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";
52
52
  styleInject(css_248z);
53
53
 
54
54
  const IGNORE_ERRORS = ['Invalid or missing authorization', '["Not found"]'];
@@ -143,7 +143,7 @@ const useAllErrorFormats = () => {
143
143
  };
144
144
 
145
145
  // This will be replaced at build time by rollup-plugin-replace
146
- const PACKAGE_VERSION = '1.6.0-beta.23';
146
+ const PACKAGE_VERSION = '1.7.0-beta.2';
147
147
  const createRequestHeaders = (token) => {
148
148
  const headers = createClientDevHeaders({ token });
149
149
  // Add the components version header
@@ -929,7 +929,7 @@ function readFragment(...r) {
929
929
 
930
930
  var t = initGraphQLTada();
931
931
 
932
- const query$7 = t(`
932
+ const query$9 = t(`
933
933
  query entityBranding {
934
934
  entityBranding {
935
935
  accentColor
@@ -939,7 +939,7 @@ const query$7 = t(`
939
939
  }
940
940
  `);
941
941
  const getBranding = async ({ token, apiHost }) => {
942
- return await execute(query$7, { apiHost, token }, {});
942
+ return await execute(query$9, { apiHost, token }, {});
943
943
  };
944
944
 
945
945
  const BunnyContext = react.createContext({});
@@ -1143,10 +1143,10 @@ const DocumentTemplatePreview = ({ targetUrl }) => {
1143
1143
  }, children: jsxRuntime.jsx(react$1.RPPages, {}) }))] }) }) }));
1144
1144
  };
1145
1145
 
1146
- const { Text: Text$A } = antd.Typography;
1146
+ const { Text: Text$B } = antd.Typography;
1147
1147
  function BackButton({ onClick, title }) {
1148
1148
  const { brandColor } = useBrand();
1149
- return (jsxRuntime.jsxs(StyledBackButton, { brandColor: brandColor, className: "bunny-flex bunny-items-center bunny-gap-2 bunny-p-0 bunny-text-gray-400", onClick: onClick, children: [jsxRuntime.jsx(reactFontawesome.FontAwesomeIcon, { className: "pt-0.5", icon: freeSolidSvgIcons.faArrowLeft }), jsxRuntime.jsx(Text$A, { className: "bunny-text-sm bunny-text-gray-400", children: title || 'back' })] }));
1149
+ return (jsxRuntime.jsxs(StyledBackButton, { brandColor: brandColor, className: "bunny-flex bunny-items-center bunny-gap-2 bunny-p-0 bunny-text-gray-400", onClick: onClick, children: [jsxRuntime.jsx(reactFontawesome.FontAwesomeIcon, { className: "pt-0.5", icon: freeSolidSvgIcons.faArrowLeft }), jsxRuntime.jsx(Text$B, { className: "bunny-text-sm bunny-text-gray-400 bunny-text-nowrap", children: title || 'back' })] }));
1150
1150
  }
1151
1151
  const StyledBackButton = styled.button.withConfig({
1152
1152
  shouldForwardProp: prop => !['brandColor'].includes(prop),
@@ -1182,7 +1182,7 @@ const InvoiceQuoteView = ({ children, formattedInvoice, html, backButtonName, on
1182
1182
  }, children: [targetUrl ? (jsxRuntime.jsx(DocumentTemplatePreview, { targetUrl: targetUrl })) : (jsxRuntime.jsx(interweave.Markup, { content: html })), children] }))] }));
1183
1183
  };
1184
1184
 
1185
- const MUTATION$9 = `
1185
+ const MUTATION$8 = `
1186
1186
  query FormattedInvoice($id: ID) {
1187
1187
  formattedInvoice(id: $id) {
1188
1188
  amount
@@ -1250,7 +1250,7 @@ query FormattedInvoice($id: ID) {
1250
1250
  const getFormattedInvoice = async ({ id, token, apiHost, }) => {
1251
1251
  const vars = { id };
1252
1252
  const response = await gqlRequest({
1253
- query: MUTATION$9,
1253
+ query: MUTATION$8,
1254
1254
  token,
1255
1255
  vars,
1256
1256
  apiHost,
@@ -18616,7 +18616,7 @@ function CardImage({ paymentMethod: maskedPaymentMethod, }) {
18616
18616
  }
18617
18617
  }
18618
18618
 
18619
- const { Text: Text$z } = antd.Typography;
18619
+ const { Text: Text$A } = antd.Typography;
18620
18620
  const MiniCreditCard_PaymentMethodFragment = t(`
18621
18621
  fragment MiniCreditCard_PaymentMethodFragment on PaymentMethod {
18622
18622
  ...CardImage_PaymentMethodFragment
@@ -18642,22 +18642,22 @@ function MiniCreditCard({ className, buttons, hideDropdownMenu = false, hideDefa
18642
18642
  return darkMode ? 'var(--row-background-alternate)' : 'bg-slate-50';
18643
18643
  }, [darkMode]);
18644
18644
  const isDefault = paymentMethod === null || paymentMethod === void 0 ? void 0 : paymentMethod.isDefault;
18645
- return (jsxRuntime.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 ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "bunny-flex bunny-flex-row bunny-gap-4", children: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-2 bunny-space-between bunny-w-full", children: [jsxRuntime.jsx(CardImage, { paymentMethod: paymentMethod }), jsxRuntime.jsx(Issuer, { issuer: (_a = paymentMethod === null || paymentMethod === void 0 ? void 0 : paymentMethod.metadata) === null || _a === void 0 ? void 0 : _a.issuer }), jsxRuntime.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 && (jsxRuntime.jsx("div", { children: isDefault ? (jsxRuntime.jsx(antd.Tag, { bordered: false, style: { color: brandColor, backgroundColor: `${brandColor}30` }, children: "Default" })) : null }))] }) }), buttons ? (buttons) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: !hideDropdownMenu && (jsxRuntime.jsx(DropdownMenu, { setDefault: onClickSetDefault, remove: onClickRemove, isDefault: isDefault !== null && isDefault !== void 0 ? isDefault : false, id: `credit-card-dropdown-${paymentMethod.id}` })) }))] })) : (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row bunny-items-center justify-between w-full", children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2 bunny-items-center", children: [jsxRuntime.jsx(icons.CreditCardOutlined, {}), jsxRuntime.jsx(Text$z, { className: "bunny-text-slate-400 bunny-text-sm", children: "No payment methods" })] }), jsxRuntime.jsx(antd.Button, { disabled: true, type: "link" }), buttons] })) }));
18645
+ return (jsxRuntime.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 ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "bunny-flex bunny-flex-row bunny-gap-4", children: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-2 bunny-space-between bunny-w-full", children: [jsxRuntime.jsx(CardImage, { paymentMethod: paymentMethod }), jsxRuntime.jsx(Issuer, { issuer: (_a = paymentMethod === null || paymentMethod === void 0 ? void 0 : paymentMethod.metadata) === null || _a === void 0 ? void 0 : _a.issuer }), jsxRuntime.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 && (jsxRuntime.jsx("div", { children: isDefault ? (jsxRuntime.jsx(antd.Tag, { bordered: false, style: { color: brandColor, backgroundColor: `${brandColor}30` }, children: "Default" })) : null }))] }) }), buttons ? (buttons) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: !hideDropdownMenu && (jsxRuntime.jsx(DropdownMenu, { setDefault: onClickSetDefault, remove: onClickRemove, isDefault: isDefault !== null && isDefault !== void 0 ? isDefault : false, id: `credit-card-dropdown-${paymentMethod.id}` })) }))] })) : (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row bunny-items-center justify-between w-full", children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2 bunny-items-center", children: [jsxRuntime.jsx(icons.CreditCardOutlined, {}), jsxRuntime.jsx(Text$A, { className: "bunny-text-slate-400 bunny-text-sm", children: "No payment methods" })] }), jsxRuntime.jsx(antd.Button, { disabled: true, type: "link" }), buttons] })) }));
18646
18646
  }
18647
18647
  const Identifier = ({ type, identifier, }) => {
18648
18648
  if (type === 'link') {
18649
18649
  return null;
18650
18650
  }
18651
18651
  if (type === 'cashapp') {
18652
- return jsxRuntime.jsx(Text$z, { children: "Cashapp" });
18652
+ return jsxRuntime.jsx(Text$A, { children: "Cashapp" });
18653
18653
  }
18654
- return (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(Text$z, { className: "relative -top-0.5", children: "****" }), jsxRuntime.jsx(Text$z, { children: identifier })] }));
18654
+ return (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(Text$A, { className: "relative -top-0.5", children: "****" }), jsxRuntime.jsx(Text$A, { children: identifier })] }));
18655
18655
  };
18656
18656
  const Issuer = ({ issuer }) => {
18657
18657
  const list = ['visa', 'link', 'jcb', 'discover', 'sepa'];
18658
18658
  if (!issuer || issuer.length == 0 || list.includes(issuer === null || issuer === void 0 ? void 0 : issuer.toLowerCase()))
18659
18659
  return null;
18660
- return jsxRuntime.jsx(Text$z, { children: lodashExports.capitalize(issuer) });
18660
+ return jsxRuntime.jsx(Text$A, { children: lodashExports.capitalize(issuer) });
18661
18661
  };
18662
18662
  const DropdownMenu = ({ setDefault, remove, isDefault, id, }) => {
18663
18663
  const { brandColor } = useBrand();
@@ -18702,6 +18702,16 @@ const QueryKeyFactory = {
18702
18702
  ...(entityId ? [entityId] : []),
18703
18703
  ...(token ? [token] : []),
18704
18704
  ],
18705
+ accountBillingDetailsKey: ({ accountId, token }) => [
18706
+ 'accountBillingDetails',
18707
+ ...(accountId ? [accountId] : []),
18708
+ ...(token ? [token] : []),
18709
+ ],
18710
+ accountContactsKey: ({ accountId, token }) => [
18711
+ 'accountContacts',
18712
+ ...(accountId ? [accountId] : []),
18713
+ ...(token ? [token] : []),
18714
+ ],
18705
18715
  brandingKey: (token) => ['branding', ...(token ? [token] : [])],
18706
18716
  calculatedPricesKey: ({ priceListId, quantity, token }) => [
18707
18717
  'calculatedPrices',
@@ -18768,7 +18778,7 @@ const QueryKeyFactory = {
18768
18778
  paymentPluginsKey: (token) => ['paymentPlugins', ...(token ? [token] : [])],
18769
18779
  };
18770
18780
 
18771
- const query$6 = t(`
18781
+ const query$8 = t(`
18772
18782
  query PaymentMethods($accountId: ID) {
18773
18783
  paymentMethods(accountId: $accountId) {
18774
18784
  nodes {
@@ -18797,7 +18807,7 @@ const query$6 = t(`
18797
18807
  `, [PaymentForm_PaymentMethodsFragment]);
18798
18808
  const getPaymentMethods = async ({ apiHost, token, accountId, }) => {
18799
18809
  var _a, _b, _c;
18800
- const response = await execute(query$6, { apiHost, token }, { accountId });
18810
+ const response = await execute(query$8, { apiHost, token }, { accountId });
18801
18811
  // Filter out null values that are technically possible due to api schema
18802
18812
  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 : [];
18803
18813
  };
@@ -18822,7 +18832,7 @@ const usePaymentMethod = ({ accountId, enabled = true, }) => {
18822
18832
  };
18823
18833
  };
18824
18834
 
18825
- const mutation$5 = t(`
18835
+ const mutation$d = t(`
18826
18836
  query PaymentPlugins($accountId: ID) {
18827
18837
  paymentPlugins(accountId: $accountId) {
18828
18838
  enabled
@@ -18850,7 +18860,7 @@ const mutation$5 = t(`
18850
18860
  // }[];
18851
18861
  // };
18852
18862
  const getPaymentPlugins = async ({ apiHost, token, accountId, }) => {
18853
- const response = await execute(mutation$5, { apiHost, token }, { accountId });
18863
+ const response = await execute(mutation$d, { apiHost, token }, { accountId });
18854
18864
  return response === null || response === void 0 ? void 0 : response.paymentPlugins;
18855
18865
  };
18856
18866
  const usePaymentPlugins = (accountId) => {
@@ -19074,7 +19084,7 @@ function useSave$1({ onSaveSuccess, onSaveError, accountId, }) {
19074
19084
  return { save, isSaving };
19075
19085
  }
19076
19086
 
19077
- const MUTATION$8 = `
19087
+ const MUTATION$7 = `
19078
19088
  mutation checkout(
19079
19089
  $invoiceId: ID,
19080
19090
  $quoteId: ID,
@@ -19123,7 +19133,7 @@ const checkout = async ({ quoteId, invoiceId, paymentMethodId, paymentMethodData
19123
19133
  };
19124
19134
  }
19125
19135
  const response = await gqlRequest({
19126
- query: MUTATION$8,
19136
+ query: MUTATION$7,
19127
19137
  token,
19128
19138
  vars: mutationVars,
19129
19139
  apiHost: apiHost,
@@ -19404,7 +19414,7 @@ var PaymentType;
19404
19414
  PaymentType["CHECKOUT_NO_PAYMENT"] = "CHECKOUT_NO_PAYMENT";
19405
19415
  })(PaymentType || (PaymentType = {}));
19406
19416
 
19407
- const handleAllErrorFormats$2 = common.useAllErrorFormats();
19417
+ const handleAllErrorFormats$3 = common.useAllErrorFormats();
19408
19418
  const showErrorNotification$6 = common.useErrorNotification();
19409
19419
  const useHandlePayment = ({ quote, invoice, onPaymentSuccess, onPaymentHoldSuccess, plugin, paymentHoldOptions, accountId, }) => {
19410
19420
  // Context
@@ -19426,7 +19436,7 @@ const useHandlePayment = ({ quote, invoice, onPaymentSuccess, onPaymentHoldSucce
19426
19436
  const { pay: payDemoPay, isPaying: isPayingDemoPay } = usePay$1({
19427
19437
  onPaymentSuccess: handlePaymentSuccess,
19428
19438
  onPaymentError: error => {
19429
- handleAllErrorFormats$2(error);
19439
+ handleAllErrorFormats$3(error);
19430
19440
  },
19431
19441
  quote: quote,
19432
19442
  invoice: invoice,
@@ -19435,7 +19445,7 @@ const useHandlePayment = ({ quote, invoice, onPaymentSuccess, onPaymentHoldSucce
19435
19445
  const { pay: payStripe, isPaying: isPayingStripe } = usePay({
19436
19446
  onPaymentSuccess: handlePaymentSuccess,
19437
19447
  onPaymentError: error => {
19438
- handleAllErrorFormats$2(error);
19448
+ handleAllErrorFormats$3(error);
19439
19449
  },
19440
19450
  quote: quote,
19441
19451
  invoice: invoice,
@@ -19447,7 +19457,7 @@ const useHandlePayment = ({ quote, invoice, onPaymentSuccess, onPaymentHoldSucce
19447
19457
  onPaymentHoldSuccess === null || onPaymentHoldSuccess === void 0 ? void 0 : onPaymentHoldSuccess(response);
19448
19458
  },
19449
19459
  onApproveHoldError: error => {
19450
- handleAllErrorFormats$2(error);
19460
+ handleAllErrorFormats$3(error);
19451
19461
  },
19452
19462
  });
19453
19463
  const { approveHold: approveHoldDemoPay, isApprovingHold: isApprovingHoldDemoPay } = useApproveHold$1({
@@ -19455,7 +19465,7 @@ const useHandlePayment = ({ quote, invoice, onPaymentSuccess, onPaymentHoldSucce
19455
19465
  onPaymentHoldSuccess === null || onPaymentHoldSuccess === void 0 ? void 0 : onPaymentHoldSuccess(response);
19456
19466
  },
19457
19467
  onApproveHoldError: error => {
19458
- handleAllErrorFormats$2(error);
19468
+ handleAllErrorFormats$3(error);
19459
19469
  },
19460
19470
  });
19461
19471
  // Mutations
@@ -19473,7 +19483,7 @@ const useHandlePayment = ({ quote, invoice, onPaymentSuccess, onPaymentHoldSucce
19473
19483
  onPaymentSuccess === null || onPaymentSuccess === void 0 ? void 0 : onPaymentSuccess({});
19474
19484
  },
19475
19485
  onError: error => {
19476
- handleAllErrorFormats$2(error);
19486
+ handleAllErrorFormats$3(error);
19477
19487
  },
19478
19488
  });
19479
19489
  const handleApproveHold = async (overridePaymentMethodId) => {
@@ -19616,7 +19626,7 @@ function useSave({ onSaveSuccess, onSaveError, accountId, }) {
19616
19626
  const useShowPaymentDetailsState = (isOpen = false) => react.useState(isOpen);
19617
19627
  const [ShowPaymentDetailsProvider, useShowPaymentDetails] = createStateContext(useShowPaymentDetailsState);
19618
19628
 
19619
- const handleAllErrorFormats$1 = common.useAllErrorFormats();
19629
+ const handleAllErrorFormats$2 = common.useAllErrorFormats();
19620
19630
  const showErrorNotification$5 = common.useErrorNotification();
19621
19631
  // Contexts
19622
19632
  const [FormattedAmountDueProvider, useFormattedAmountDue] = createValueContext();
@@ -19662,7 +19672,7 @@ function PaymentProvider({ children, accountId, quote, invoice, onPaymentSuccess
19662
19672
  });
19663
19673
  setShowPaymentMethodForm(false);
19664
19674
  },
19665
- onSaveError: handleAllErrorFormats$1,
19675
+ onSaveError: handleAllErrorFormats$2,
19666
19676
  accountId,
19667
19677
  });
19668
19678
  const { save: saveStripe, isSaving: isSavingStripe } = useSave({
@@ -19676,7 +19686,7 @@ function PaymentProvider({ children, accountId, quote, invoice, onPaymentSuccess
19676
19686
  });
19677
19687
  setShowPaymentMethodForm(false);
19678
19688
  },
19679
- onSaveError: handleAllErrorFormats$1,
19689
+ onSaveError: handleAllErrorFormats$2,
19680
19690
  accountId,
19681
19691
  });
19682
19692
  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;
@@ -19840,8 +19850,8 @@ const DemoPayExpiry = ({ autoFocus, onChange, placeholder, value, }) => {
19840
19850
  return (jsxRuntime.jsx("div", { className: "bunny-grow", children: jsxRuntime.jsx(antd.Input, { name: "expiry", autoFocus: autoFocus, onKeyDown: onKeyPress, onKeyUp: onKeyPress, onChange: onNumberChange, value: formatCardExpiry(value), maxLength: 5, placeholder: placeholder || "MM/YY" }) }));
19841
19851
  };
19842
19852
 
19843
- const { Text: Text$y } = antd.Typography;
19844
- const handleAllErrorFormats = common.useAllErrorFormats();
19853
+ const { Text: Text$z } = antd.Typography;
19854
+ const handleAllErrorFormats$1 = common.useAllErrorFormats();
19845
19855
  const TEST_CARD = '4242424242424242';
19846
19856
  const DemoPayForm = () => {
19847
19857
  // Context
@@ -19858,7 +19868,7 @@ const DemoPayForm = () => {
19858
19868
  onPaymentFormSubmit(cardDetails);
19859
19869
  }
19860
19870
  catch (error) {
19861
- handleAllErrorFormats(error);
19871
+ handleAllErrorFormats$1(error);
19862
19872
  }
19863
19873
  }
19864
19874
  function validateCardDetails() {
@@ -19880,7 +19890,7 @@ const DemoPayForm = () => {
19880
19890
  const onCardCvcChange = (cvc) => {
19881
19891
  setCardDetails({ ...cardDetails, cvc });
19882
19892
  };
19883
- return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2", children: [jsxRuntime.jsxs(StyledInputs, { className: "bunny-flex bunny-flex-col bunny-gap-2", darkMode: darkMode !== null && darkMode !== void 0 ? darkMode : false, children: [jsxRuntime.jsx(DemoPayCardNumber, { onChange: onCardNumberChange, value: cardDetails.number }), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-gap-2", children: [jsxRuntime.jsx(DemoPayExpiry, { onChange: onCardExpiryChange, value: cardDetails.expiry }), jsxRuntime.jsx(DemoPayCardCvc, { onChange: onCardCvcChange, value: cardDetails.cvc })] })] }), jsxRuntime.jsx(Text$y, { children: "DemoPay is for testing only." }), jsxRuntime.jsx(PaymentMethodFooter, { onSubmit: onSubmit })] }));
19893
+ return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2", children: [jsxRuntime.jsxs(StyledInputs, { className: "bunny-flex bunny-flex-col bunny-gap-2", darkMode: darkMode !== null && darkMode !== void 0 ? darkMode : false, children: [jsxRuntime.jsx(DemoPayCardNumber, { onChange: onCardNumberChange, value: cardDetails.number }), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-gap-2", children: [jsxRuntime.jsx(DemoPayExpiry, { onChange: onCardExpiryChange, value: cardDetails.expiry }), jsxRuntime.jsx(DemoPayCardCvc, { onChange: onCardCvcChange, value: cardDetails.cvc })] })] }), jsxRuntime.jsx(Text$z, { children: "DemoPay is for testing only." }), jsxRuntime.jsx(PaymentMethodFooter, { onSubmit: onSubmit })] }));
19884
19894
  };
19885
19895
  const StyledInputs = defaultStyled.div `
19886
19896
  .ant-input {
@@ -19929,7 +19939,7 @@ const CardIcon = ({ className }) => {
19929
19939
  return (jsxRuntime.jsxs("svg", { className: className, width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsxRuntime.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: common.SLATE_400, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }), jsxRuntime.jsx("path", { d: "M1.5 7.5H16.5", stroke: common.SLATE_400, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }));
19930
19940
  };
19931
19941
 
19932
- const { Text: Text$x } = antd.Typography;
19942
+ const { Text: Text$y } = antd.Typography;
19933
19943
  const PaymentMethodSelector = () => {
19934
19944
  const accountId = useAccountId();
19935
19945
  const { paymentPlugins } = usePaymentPlugins(accountId);
@@ -19943,7 +19953,7 @@ const PaymentOption = ({ selected, paymentPluginId, onClick, name, }) => {
19943
19953
  const isCard = name === null || name === void 0 ? void 0 : name.toLowerCase().includes('card');
19944
19954
  return (jsxRuntime.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
19945
19955
  ? `var(--row-background-dark) border-gray-500`
19946
- : 'bunny-bg-slate-50 bunny-border-slate-200'} bunny-border`, onClick: () => onClick(paymentPluginId), children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-gap-2 bunny-items-center bunny-pl-4", children: [jsxRuntime.jsx(antd.Checkbox, { checked: selected, className: darkMode ? 'border-gray-400' : '' }), jsxRuntime.jsx(Text$x, { children: name })] }), isAch ? (jsxRuntime.jsx(icons.BankOutlined, { className: "bunny-pr-4" })) : isCard ? (jsxRuntime.jsx(CardIcon, { className: "bunny-pr-4" })) : (jsxRuntime.jsx(CardIcon, { className: "bunny-pr-4" }))] }));
19956
+ : 'bunny-bg-slate-50 bunny-border-slate-200'} bunny-border`, onClick: () => onClick(paymentPluginId), children: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-gap-2 bunny-items-center bunny-pl-4", children: [jsxRuntime.jsx(antd.Checkbox, { checked: selected, className: darkMode ? 'border-gray-400' : '' }), jsxRuntime.jsx(Text$y, { children: name })] }), isAch ? (jsxRuntime.jsx(icons.BankOutlined, { className: "bunny-pr-4" })) : isCard ? (jsxRuntime.jsx(CardIcon, { className: "bunny-pr-4" })) : (jsxRuntime.jsx(CardIcon, { className: "bunny-pr-4" }))] }));
19947
19957
  };
19948
19958
  const PaymentOptionContainer = defaultStyled.div `
19949
19959
  transition: border 0.3s ease;
@@ -20001,7 +20011,7 @@ const useAutoSetDefaultPaymentMethod = ({ handleSetDefault, setDefaultPaymentMet
20001
20011
  ]);
20002
20012
  };
20003
20013
 
20004
- const query$5 = t(`
20014
+ const query$7 = t(`
20005
20015
  query GetCurrentUserData {
20006
20016
  company {
20007
20017
  name
@@ -20024,7 +20034,7 @@ const query$5 = t(`
20024
20034
  `);
20025
20035
  const getCurrentUserData = async ({ token, apiHost }) => {
20026
20036
  var _a, _b, _c, _d, _e, _f, _g, _h;
20027
- const response = await execute(query$5, { apiHost, token }, {});
20037
+ const response = await execute(query$7, { apiHost, token }, {});
20028
20038
  return {
20029
20039
  authObjectName: (_a = response === null || response === void 0 ? void 0 : response.currentUser) === null || _a === void 0 ? void 0 : _a.authObjectName,
20030
20040
  account: (_b = response === null || response === void 0 ? void 0 : response.currentUser) === null || _b === void 0 ? void 0 : _b.account,
@@ -20192,6 +20202,8 @@ function PaymentFormContent({ onRemovePaymentMethod, onSetDefaultPaymentMethod,
20192
20202
  const { paymentMethods: maskedPaymentMethods, isLoading: isPaymentMethodLoading } = usePaymentMethod({ accountId });
20193
20203
  // Read fragments
20194
20204
  const paymentMethods = react.useMemo(() => maskedPaymentMethods === null || maskedPaymentMethods === void 0 ? void 0 : maskedPaymentMethods.map(paymentMethod => readFragment(PaymentForm_PaymentMethodsFragment, paymentMethod)), [maskedPaymentMethods]);
20205
+ // Derived state
20206
+ const hasPaymentMethods = (paymentMethods === null || paymentMethods === void 0 ? void 0 : paymentMethods.length) && (paymentMethods === null || paymentMethods === void 0 ? void 0 : paymentMethods.length) > 0;
20195
20207
  // Custom hooks
20196
20208
  const { setDefaultPaymentMethod: handleSetDefault, loading: setDefaultPaymentMethodLoading } = useSetDefaultPaymentMethod(message => {
20197
20209
  showErrorNotification$4(message, 'Error setting default payment method');
@@ -20230,7 +20242,7 @@ function PaymentFormContent({ onRemovePaymentMethod, onSetDefaultPaymentMethod,
20230
20242
  label: !showPaymentMethodForm ? (jsxRuntime.jsx("div", { className: "bunny-pt-2", children: jsxRuntime.jsx(antd.Button, { onClick: handleClickAddPaymentMethod, type: "default", className: "bunny-w-full", id: "addPaymentMethod", children: "Add payment method" }) })) : null,
20231
20243
  children: (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2 bunny-mt-2", children: [jsxRuntime.jsx(PaymentMethodSelector, {}), selectedPlugin && (jsxRuntime.jsx("div", { className: "bunny-flex bunny-flex-col", children: jsxRuntime.jsx(PaymentMethodDetails, {}) }))] })),
20232
20244
  },
20233
- ] }), formattedAmountDue !== undefined && !showPaymentMethodForm && (jsxRuntime.jsx("div", { className: "bunny-px-4", children: jsxRuntime.jsx(CheckoutFooter, {}) }))] })) : (jsxRuntime.jsx(antd.Button, { style: { margin: '0 16px' }, loading: isPaying, onClick: () => onPaymentFormSubmit(), type: "primary", children: isPaying ? 'Processing...' : 'Complete Order' })) }));
20245
+ ] }), formattedAmountDue !== undefined && !showPaymentMethodForm && hasPaymentMethods ? (jsxRuntime.jsx("div", { className: "bunny-px-4", children: jsxRuntime.jsx(CheckoutFooter, {}) })) : null] })) : (jsxRuntime.jsx(antd.Button, { style: { margin: '0 16px' }, loading: isPaying, onClick: () => onPaymentFormSubmit(), type: "primary", children: isPaying ? 'Processing...' : 'Complete Order' })) }));
20234
20246
  }
20235
20247
 
20236
20248
  function Invoice({ id, invoiceQuoteViewComponent, backButtonName, onBackButtonClick, onInvoiceDownloadError, onPaymentSuccess, shadow = 'shadow-md', className, hideDownloadButton = false, hidePaymentForm = false, onInvoiceLoaded, }) {
@@ -20288,7 +20300,7 @@ function ActualInvoice({ hidePaymentForm }) {
20288
20300
  return (jsxRuntime.jsx("div", { className: "bunny-invoice-container", children: jsxRuntime.jsxs("div", { className: `bunny-flex bunny-gap-6 ${isMobile ? 'bunny-flex-col bunny-w-full' : ''} ${className}`, children: [formattedInvoice.isLegacy ? (jsxRuntime.jsx("div", { className: "bunny-flex bunny-justify-center bunny-w-full", children: jsxRuntime.jsx(LegacyDocument, { documentUuid: formattedInvoice.uuid, documentType: "invoice" }) })) : (invoiceQuoteViewComponent || (jsxRuntime.jsx(InvoiceQuoteView, { html: formattedInvoice.html, formattedInvoice: formattedInvoice, backButtonName: backButtonName, onBackButtonClick: onBackButtonClick }))), isInvoicePayable && !hidePaymentForm && (jsxRuntime.jsx("div", { className: `bunny-w-full ${hideDownloadButton || formattedInvoice.isLegacy ? '' : 'pt-12'}`, children: jsxRuntime.jsx(PaymentForm, { onPaymentSuccess: handlePaymentSuccess, invoice: formattedInvoice }) }))] }) }));
20289
20301
  }
20290
20302
 
20291
- const query$4 = t(`
20303
+ const query$6 = t(`
20292
20304
  query formattedQuote($id: ID) {
20293
20305
  formattedQuote(id: $id) {
20294
20306
  quote {
@@ -20432,7 +20444,7 @@ const query$4 = t(`
20432
20444
  }
20433
20445
  `);
20434
20446
  const getFormattedQuote = async ({ token, apiHost, id, }) => {
20435
- const response = await execute(query$4, { apiHost, token }, { id });
20447
+ const response = await execute(query$6, { apiHost, token }, { id });
20436
20448
  return response === null || response === void 0 ? void 0 : response.formattedQuote;
20437
20449
  };
20438
20450
 
@@ -20481,6 +20493,7 @@ const useSigningPlugins = ({ apiHost, token, }) => {
20481
20493
  return filterSigningPlugins(plugins.data);
20482
20494
  };
20483
20495
 
20496
+ const handleAllErrorFormats = common.useAllErrorFormats();
20484
20497
  const QUOTE_ACCEPT = `
20485
20498
  mutation quoteAccept($name: String!, $title: String!, $poNumber: String, $taxNumber: String, $quoteId: ID) {
20486
20499
  quoteAccept(name: $name, title: $title, poNumber: $poNumber, taxNumber: $taxNumber, quoteId: $quoteId) {
@@ -20534,8 +20547,10 @@ const useSendAcceptQuote = ({ quoteId, apiHost, token, onQuoteAccepted, }) => {
20534
20547
  quoteId,
20535
20548
  };
20536
20549
  graphQLMutation(mutation, variables, (rsp) => {
20537
- if (rsp.errors)
20538
- console.log('rsp.errors', rsp.errors);
20550
+ if (rsp.errors) {
20551
+ handleAllErrorFormats(rsp.errors[0].message);
20552
+ setIsAccepting(false);
20553
+ }
20539
20554
  else {
20540
20555
  const { redirectUri, message, pluginShortName } = rsp.data.quoteSigningUrlCreate;
20541
20556
  if (redirectUri) {
@@ -20686,7 +20701,7 @@ const PandadocPollingModal = ({ isVisible, setVisible, id }) => {
20686
20701
  };
20687
20702
  graphQLMutation(mutation, variables, (rsp) => {
20688
20703
  if (rsp.errors)
20689
- handleAllErrorFormats(rsp.errors);
20704
+ handleAllErrorFormats(rsp.errors[0].message);
20690
20705
  else if (rsp.data.quotePollSigningUrl.status === 'document.sent') {
20691
20706
  setVisible(false);
20692
20707
  window.location.href = rsp.data.quotePollSigningUrl.redirectUri;
@@ -20768,14 +20783,14 @@ const AcceptQuoteModal = ({ acceptBoxVisible, formattedQuote, sendAccept, setAcc
20768
20783
  }, open: acceptBoxVisible, title: (signingPlugins === null || signingPlugins === void 0 ? void 0 : signingPlugins.length) ? 'Start signing' : 'Accept quote', width: 400, children: jsxRuntime.jsxs(antd.Form, { className: "bunny-flex bunny-flex-col bunny-gap-2", form: form, layout: "vertical", children: [jsxRuntime.jsx(antd.Form.Item, { label: "Your name", name: "name", rules: createRules(true, 'Your name'), children: jsxRuntime.jsx(antd.Input, { autoFocus: true, ref: firstInputRef }) }), jsxRuntime.jsx(antd.Form.Item, { label: "Your job title", name: "title", rules: createRules(true, 'Your job title'), children: jsxRuntime.jsx(antd.Input, {}) }), jsxRuntime.jsx(antd.Form.Item, { label: "Purchase order number", name: "poNumber", rules: createRules(poNumberRequired, 'Purchase order number'), children: jsxRuntime.jsx(antd.Input, {}) }), taxNumberRequired && (jsxRuntime.jsx(antd.Form.Item, { name: "taxNumber", label: taxNumberLabel, rules: createRules(taxNumberRequired, taxNumberLabel), children: jsxRuntime.jsx(antd.Input, {}) }))] }) }));
20769
20784
  };
20770
20785
 
20771
- const { Title: Title$2, Text: Text$w } = antd.Typography;
20786
+ const { Title: Title$2, Text: Text$x } = antd.Typography;
20772
20787
  const showSuccessNotification$2 = common.useSuccessNotification();
20773
20788
  const PaymentHoldModal = ({ visible, setVisible, quote, }) => {
20774
20789
  const queryClient = reactQuery.useQueryClient();
20775
20790
  const token = useToken();
20776
20791
  return (jsxRuntime.jsxs(StyledModal$2, { centered: true, onCancel: () => {
20777
20792
  setVisible(false);
20778
- }, footer: null, open: visible, width: 600, children: [jsxRuntime.jsxs("div", { className: "bunny-mt-5 bunny-pb-4 bunny-mx-4", children: [jsxRuntime.jsx(Title$2, { className: "bunny-mt-0", level: 5, children: "Pay and sign" }), jsxRuntime.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", ' ', common.formatCurrency(quote.amount, quote.currency), ". This amount will be charged to your payment method once the quote is signed."] })] }), jsxRuntime.jsx("div", { className: "bunny-mb-3", children: jsxRuntime.jsx(PaymentForm, { quote: {
20793
+ }, footer: null, open: visible, width: 600, children: [jsxRuntime.jsxs("div", { className: "bunny-mt-5 bunny-pb-4 bunny-mx-4", children: [jsxRuntime.jsx(Title$2, { className: "bunny-mt-0", level: 5, children: "Pay and sign" }), jsxRuntime.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", ' ', common.formatCurrency(quote.amount, quote.currency), ". This amount will be charged to your payment method once the quote is signed."] })] }), jsxRuntime.jsx("div", { className: "bunny-mb-3", children: jsxRuntime.jsx(PaymentForm, { quote: {
20779
20794
  amount: quote.amount,
20780
20795
  currencyId: quote.currency,
20781
20796
  id: quote.quote.id,
@@ -20825,7 +20840,7 @@ const StyledModal$2 = (props) => {
20825
20840
  return jsxRuntime.jsx(ModalOverrideBrandStylings, { closable: false, ...props });
20826
20841
  };
20827
20842
 
20828
- const { Text: Text$v } = antd.Typography;
20843
+ const { Text: Text$w } = antd.Typography;
20829
20844
  defaultStyled.div `
20830
20845
  Text {
20831
20846
  width: 100%;
@@ -20917,7 +20932,7 @@ function QuoteButtons({ isAccepted, formattedQuote, isMobile, hideDownloadButton
20917
20932
  const signingPlugins = useSigningPlugins({ apiHost, token });
20918
20933
  return (jsxRuntime.jsxs("div", { className: "flex flex-row justify-end items-center gap-4", id: "acceptance", style: {
20919
20934
  color: secondaryColor,
20920
- }, children: [isAccepted && formattedQuote.acceptedAt ? (jsxRuntime.jsx(Text$v, { children: `Quote was accepted by ${formattedQuote.acceptedByName} on ${common.formatDate(formattedQuote.acceptedAt)}` })) : null, (!isMobile || !isAccepted) && (jsxRuntime.jsxs("div", { className: isMobile ? 'flex w-full justify-end gap-2' : 'flex items-center justify-end gap-2', children: [paymentHold ? (jsxRuntime.jsx(PaymentHoldDisplay, { paymentHold: paymentHold, currency: formattedQuote.currency, amount: formattedQuote.amount })) : null, !isMobile && !hideDownloadButton ? (jsxRuntime.jsx(antd.Button, { icon: jsxRuntime.jsx(icons.DownloadOutlined, {}), onClick: () => downloadFile(apiHost + '/api/pdf/quote', token), children: "Download" })) : null, shouldDoPaymentHold && !paymentHoldCompleted ? (jsxRuntime.jsx(antd.Button, { disabled: isExpired, onClick: () => setPaymentHoldModalVisible(true), type: "primary", children: "Pay and sign" })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: !isAccepted ? (jsxRuntime.jsx(antd.Button, { disabled: isExpired || isAccepting, onClick: handleClickAccept, type: "primary", children: isExpired
20935
+ }, children: [isAccepted && formattedQuote.acceptedAt ? (jsxRuntime.jsx(Text$w, { children: `Quote was accepted by ${formattedQuote.acceptedByName} on ${common.formatDate(formattedQuote.acceptedAt)}` })) : null, (!isMobile || !isAccepted) && (jsxRuntime.jsxs("div", { className: isMobile ? 'flex w-full justify-end gap-2' : 'flex items-center justify-end gap-2', children: [paymentHold ? (jsxRuntime.jsx(PaymentHoldDisplay, { paymentHold: paymentHold, currency: formattedQuote.currency, amount: formattedQuote.amount })) : null, !isMobile && !hideDownloadButton ? (jsxRuntime.jsx(antd.Button, { icon: jsxRuntime.jsx(icons.DownloadOutlined, {}), onClick: () => downloadFile(apiHost + '/api/pdf/quote', token), children: "Download" })) : null, shouldDoPaymentHold && !paymentHoldCompleted ? (jsxRuntime.jsx(antd.Button, { disabled: isExpired, onClick: () => setPaymentHoldModalVisible(true), type: "primary", children: "Pay and sign" })) : (jsxRuntime.jsx(jsxRuntime.Fragment, { children: !isAccepted ? (jsxRuntime.jsx(antd.Button, { disabled: isExpired || isAccepting, onClick: handleClickAccept, type: "primary", children: isExpired
20921
20936
  ? 'Quote is expired'
20922
20937
  : (signingPlugins === null || signingPlugins === void 0 ? void 0 : signingPlugins.length)
20923
20938
  ? 'Start signing'
@@ -21038,9 +21053,9 @@ const getColor = (state) => {
21038
21053
  }
21039
21054
  };
21040
21055
 
21041
- const { Text: Text$u } = antd.Typography;
21056
+ const { Text: Text$v } = antd.Typography;
21042
21057
  const TransactionDate = ({ date }) => {
21043
- return jsxRuntime.jsx(Text$u, { className: "bunny-text-sm", children: common.formatDate(date) });
21058
+ return jsxRuntime.jsx(Text$v, { className: "bunny-text-sm", children: common.formatDate(date) });
21044
21059
  };
21045
21060
 
21046
21061
  const ArrowDownToLine = ({ className, color = common.SLATE_600, }) => {
@@ -21084,13 +21099,13 @@ const TransactionGridCell = defaultStyled.div.withConfig({
21084
21099
  min-width: 48px;
21085
21100
  `;
21086
21101
 
21087
- const { Text: Text$t } = antd.Typography;
21102
+ const { Text: Text$u } = antd.Typography;
21088
21103
  const TransactionsEmptyState = () => {
21089
21104
  const { noTransactionsMessage } = react.useContext(TransactionsListContext);
21090
- return (jsxRuntime.jsx(Text$t, { className: "bunny-flex bunny-justify-center bunny-p-4 bunny-text-base", children: noTransactionsMessage || 'There are no transactions' }));
21105
+ return (jsxRuntime.jsx(Text$u, { className: "bunny-flex bunny-justify-center bunny-p-4 bunny-text-base", children: noTransactionsMessage || 'There are no transactions' }));
21091
21106
  };
21092
21107
 
21093
- const { Text: Text$s } = antd.Typography;
21108
+ const { Text: Text$t } = antd.Typography;
21094
21109
  const isInvoice = (transaction) => {
21095
21110
  return transaction.kind === 'INVOICE';
21096
21111
  };
@@ -21098,7 +21113,7 @@ const TransactionRowTitle = ({ transaction }) => {
21098
21113
  if (!isInvoice(transaction)) {
21099
21114
  return jsxRuntime.jsx(jsxRuntime.Fragment, {});
21100
21115
  }
21101
- return (jsxRuntime.jsx(Text$s, { className: "bunny-text-slate-400", style: { fontSize: '11px' }, children: transaction.transactionable.number }));
21116
+ return (jsxRuntime.jsx(Text$t, { className: "bunny-text-slate-400", style: { fontSize: '11px' }, children: transaction.transactionable.number }));
21102
21117
  };
21103
21118
 
21104
21119
  function transactionDateToDisplay(transaction, transactionDateType) {
@@ -21116,7 +21131,7 @@ function transactionDateToDisplay(transaction, transactionDateType) {
21116
21131
  }
21117
21132
  }
21118
21133
 
21119
- const { Text: Text$r } = antd.Typography;
21134
+ const { Text: Text$s } = antd.Typography;
21120
21135
  const TransactionsListDesktop = ({ transactions, onTransactionClick, }) => {
21121
21136
  const { columns, transactionDateType } = react.useContext(TransactionsListContext);
21122
21137
  const { apiHost, darkMode } = react.useContext(BunnyContext);
@@ -21144,11 +21159,11 @@ const TransactionsListDesktop = ({ transactions, onTransactionClick, }) => {
21144
21159
  !showState &&
21145
21160
  !showAmount &&
21146
21161
  !showDownload &&
21147
- !showAccountName && (jsxRuntime.jsx(TransactionGridCell, { children: jsxRuntime.jsx(Text$r, { children: "No columns selected" }) })), showDate && (jsxRuntime.jsx(TransactionGridCell, { right: false, children: jsxRuntime.jsx(TransactionDate, { date: transactionDateToDisplay(transaction, transactionDateType) }) })), showTitle && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(TransactionGridCell, { right: false, className: "bunny-flex bunny-items-center bunny-gap-2", children: [jsxRuntime.jsx(Text$r, { children: lodashExports.capitalize(transaction.kind.toLowerCase()) }), jsxRuntime.jsx(TransactionRowTitle, { transaction: transaction })] }) })), showAccountName && (jsxRuntime.jsx(TransactionGridCell, { right: false, children: jsxRuntime.jsx(Text$r, { children: (_a = transaction.account) === null || _a === void 0 ? void 0 : _a.name }) })), !showDate && !showTitle && !showAccountName && jsxRuntime.jsx(TransactionGridCell, { right: false }), showDownload && (jsxRuntime.jsx(TransactionGridCell, { children: jsxRuntime.jsx(TransactionDownload, { transaction: transaction, token: token, apiHost: apiHost }) })), showState ? (jsxRuntime.jsx(TransactionGridCell, { right: false, children: jsxRuntime.jsx(StateTag, { state: transaction.state }) })) : null, showAmount && (jsxRuntime.jsx(TransactionGridCell, { right: true, children: jsxRuntime.jsx(Text$r, { children: common.formatCurrency(((_b = transaction === null || transaction === void 0 ? void 0 : transaction.transactionable) === null || _b === void 0 ? void 0 : _b.amount) || transaction.amount, transaction.currencyId) }) }))] }, index));
21162
+ !showAccountName && (jsxRuntime.jsx(TransactionGridCell, { children: jsxRuntime.jsx(Text$s, { children: "No columns selected" }) })), showDate && (jsxRuntime.jsx(TransactionGridCell, { right: false, children: jsxRuntime.jsx(TransactionDate, { date: transactionDateToDisplay(transaction, transactionDateType) }) })), showTitle && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsxs(TransactionGridCell, { right: false, className: "bunny-flex bunny-items-center bunny-gap-2", children: [jsxRuntime.jsx(Text$s, { children: lodashExports.capitalize(transaction.kind.toLowerCase()) }), jsxRuntime.jsx(TransactionRowTitle, { transaction: transaction })] }) })), showAccountName && (jsxRuntime.jsx(TransactionGridCell, { right: false, children: jsxRuntime.jsx(Text$s, { children: (_a = transaction.account) === null || _a === void 0 ? void 0 : _a.name }) })), !showDate && !showTitle && !showAccountName && jsxRuntime.jsx(TransactionGridCell, { right: false }), showDownload && (jsxRuntime.jsx(TransactionGridCell, { children: jsxRuntime.jsx(TransactionDownload, { transaction: transaction, token: token, apiHost: apiHost }) })), showState ? (jsxRuntime.jsx(TransactionGridCell, { right: false, children: jsxRuntime.jsx(StateTag, { state: transaction.state }) })) : null, showAmount && (jsxRuntime.jsx(TransactionGridCell, { right: true, children: jsxRuntime.jsx(Text$s, { children: common.formatCurrency(((_b = transaction === null || transaction === void 0 ? void 0 : transaction.transactionable) === null || _b === void 0 ? void 0 : _b.amount) || transaction.amount, transaction.currencyId) }) }))] }, index));
21148
21163
  }) }));
21149
21164
  };
21150
21165
 
21151
- const { Text: Text$q } = antd.Typography;
21166
+ const { Text: Text$r } = antd.Typography;
21152
21167
  const TransactionsListMobile = ({ transactions, onTransactionClick, }) => {
21153
21168
  const { columns, transactionDateType } = react.useContext(TransactionsListContext);
21154
21169
  const { apiHost, darkMode } = react.useContext(BunnyContext);
@@ -21170,11 +21185,11 @@ const TransactionsListMobile = ({ transactions, onTransactionClick, }) => {
21170
21185
  backgroundColor: index % 2 === 0
21171
21186
  ? `var(--row-background${darkMode ? '-dark' : ''})`
21172
21187
  : `var(--row-background-alternate${darkMode ? '-dark' : ''})`,
21173
- }, children: [jsxRuntime.jsx(TransactionGridCell, { children: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2", children: [(showTitle || showState) && (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-2", children: [showTitle && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Text$q, { children: lodashExports.capitalize(transaction.kind.toLowerCase()) }), jsxRuntime.jsx(TransactionRowTitle, { transaction: transaction })] })), showState && jsxRuntime.jsx(StateTag, { state: transaction.state })] })), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-2", children: [showAccountName && jsxRuntime.jsx(Text$q, { children: (_a = transaction.account) === null || _a === void 0 ? void 0 : _a.name }), showAccountName && showDate && jsxRuntime.jsx(Text$q, { children: "\u00B7" }), showDate && (jsxRuntime.jsx(TransactionDate, { date: transactionDateToDisplay(transaction, transactionDateType) })), showDate && showAmount && jsxRuntime.jsx(Text$q, { children: "\u00B7" }), showAmount && (jsxRuntime.jsx(Text$q, { children: common.formatCurrency(transaction.transactionable.amount || transaction.amount, transaction.currencyId) }))] })] }) }), showDownload && (jsxRuntime.jsx(TransactionGridCell, { right: true, children: jsxRuntime.jsx(TransactionDownload, { transaction: transaction, token: token, apiHost: apiHost }) }))] }, index));
21188
+ }, children: [jsxRuntime.jsx(TransactionGridCell, { children: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2", children: [(showTitle || showState) && (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-2", children: [showTitle && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Text$r, { children: lodashExports.capitalize(transaction.kind.toLowerCase()) }), jsxRuntime.jsx(TransactionRowTitle, { transaction: transaction })] })), showState && jsxRuntime.jsx(StateTag, { state: transaction.state })] })), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-2", children: [showAccountName && jsxRuntime.jsx(Text$r, { children: (_a = transaction.account) === null || _a === void 0 ? void 0 : _a.name }), showAccountName && showDate && jsxRuntime.jsx(Text$r, { children: "\u00B7" }), showDate && (jsxRuntime.jsx(TransactionDate, { date: transactionDateToDisplay(transaction, transactionDateType) })), showDate && showAmount && jsxRuntime.jsx(Text$r, { children: "\u00B7" }), showAmount && (jsxRuntime.jsx(Text$r, { children: common.formatCurrency(transaction.transactionable.amount || transaction.amount, transaction.currencyId) }))] })] }) }), showDownload && (jsxRuntime.jsx(TransactionGridCell, { right: true, children: jsxRuntime.jsx(TransactionDownload, { transaction: transaction, token: token, apiHost: apiHost }) }))] }, index));
21174
21189
  }) }));
21175
21190
  };
21176
21191
 
21177
- const { Text: Text$p } = antd.Typography;
21192
+ const { Text: Text$q } = antd.Typography;
21178
21193
  const DISPLAY_WIDTH = 1200;
21179
21194
  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 = [
21180
21195
  common.TransactionKind.INVOICE,
@@ -21278,7 +21293,7 @@ function TransactionsDisplay({ transactions, onSearchValueChanged, search, }) {
21278
21293
  onTransactionDisplayClose === null || onTransactionDisplayClose === void 0 ? void 0 : onTransactionDisplayClose(selectedTransaction);
21279
21294
  setDrawerOpen(false);
21280
21295
  }
21281
- return (jsxRuntime.jsxs("div", { style: style, children: [jsxRuntime.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 ? (jsxRuntime.jsxs("div", { className: `bunny-flex ${isMobile ? 'bunny-flex-col bunny-gap-1' : 'bunny-flex-row bunny-items-center'} bunny-justify-between`, children: [showTitle ? (jsxRuntime.jsx(Text$p, { className: "bunny-shrink-0 bunny-font-medium", style: { color: darkMode ? undefined : secondaryColor }, children: title })) : (jsxRuntime.jsx("div", {}) // Empty div so justify-between works
21296
+ return (jsxRuntime.jsxs("div", { style: style, children: [jsxRuntime.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 ? (jsxRuntime.jsxs("div", { className: `bunny-flex ${isMobile ? 'bunny-flex-col bunny-gap-1' : 'bunny-flex-row bunny-items-center'} bunny-justify-between`, children: [showTitle ? (jsxRuntime.jsx(Text$q, { className: "bunny-shrink-0 bunny-font-medium", style: { color: darkMode ? undefined : secondaryColor }, children: title })) : (jsxRuntime.jsx("div", {}) // Empty div so justify-between works
21282
21297
  ), showSearchBar && (jsxRuntime.jsx("div", { className: `${isMobile ? 'bunny-w-full' : ''}`, children: jsxRuntime.jsx(antd.Input, { className: searchBarClassName ? searchBarClassName : '', onChange: e => {
21283
21298
  const value = e.target.value;
21284
21299
  // Allow empty string, numbers, and decimal point
@@ -21401,7 +21416,7 @@ const useHasTaxPlugin = ({ apiHost, token, }) => {
21401
21416
  return Boolean(plugins === null || plugins === void 0 ? void 0 : plugins.some((plugin) => plugin.type === "taxation"));
21402
21417
  };
21403
21418
 
21404
- const MUTATION$7 = () => `
21419
+ const MUTATION$6 = () => `
21405
21420
  mutation AccountSignup (
21406
21421
  $pluginId: String!,
21407
21422
  $paymentMethodId: String,
@@ -21475,7 +21490,7 @@ const accountSignup = async ({ token, apiHost, accountId, quoteId, paymentToken,
21475
21490
  priceListCode,
21476
21491
  };
21477
21492
  const response = await gqlRequest({
21478
- query: MUTATION$7(),
21493
+ query: MUTATION$6(),
21479
21494
  token,
21480
21495
  vars,
21481
21496
  apiHost,
@@ -21486,7 +21501,7 @@ const accountSignup = async ({ token, apiHost, accountId, quoteId, paymentToken,
21486
21501
  return response === null || response === void 0 ? void 0 : response.accountSignup;
21487
21502
  };
21488
21503
 
21489
- const MUTATION$6 = () => `
21504
+ const MUTATION$5 = () => `
21490
21505
  mutation QuoteAccountSignup (
21491
21506
  $accountName: String!,
21492
21507
  $billingContact: ContactAttributes!,
@@ -21563,7 +21578,7 @@ const quoteAccountSignup = async ({ token, apiHost, priceListCode, accountName,
21563
21578
  billingDetails,
21564
21579
  };
21565
21580
  const response = await gqlRequest({
21566
- query: MUTATION$6(),
21581
+ query: MUTATION$5(),
21567
21582
  token,
21568
21583
  vars,
21569
21584
  apiHost,
@@ -21641,7 +21656,7 @@ const QUOTE_RECALCULATE_TAXES = `
21641
21656
  }
21642
21657
  }
21643
21658
  `;
21644
- const quoteRecalculateTaxes = async ({ quoteId, apiHost, token, }) => {
21659
+ const quoteRecalculateTaxes$2 = async ({ quoteId, apiHost, token, }) => {
21645
21660
  var _a, _b;
21646
21661
  const vars = { id: quoteId };
21647
21662
  const response = await gqlRequest({
@@ -21656,7 +21671,7 @@ const quoteRecalculateTaxes = async ({ quoteId, apiHost, token, }) => {
21656
21671
  return (_b = response.quoteRecalculateTaxes) === null || _b === void 0 ? void 0 : _b.quote;
21657
21672
  };
21658
21673
 
21659
- const MUTATION$5 = () => `
21674
+ const MUTATION$4 = () => `
21660
21675
  query PriceList($code: String!) {
21661
21676
  priceList (code: $code) {
21662
21677
  basePrice
@@ -21681,7 +21696,7 @@ query PriceList($code: String!) {
21681
21696
  }`;
21682
21697
  const getPriceList = async ({ token, code, apiHost, }) => {
21683
21698
  const response = await gqlRequest({
21684
- query: MUTATION$5(),
21699
+ query: MUTATION$4(),
21685
21700
  token,
21686
21701
  vars: { code },
21687
21702
  apiHost,
@@ -21691,16 +21706,60 @@ const getPriceList = async ({ token, code, apiHost, }) => {
21691
21706
 
21692
21707
  const SubscriptionsContext = react.createContext({});
21693
21708
 
21709
+ const QuoteContext = react.createContext({});
21710
+
21694
21711
  const graphql = initGraphQLTada();
21695
21712
 
21696
- function canEditChargeQuantity(charge) {
21697
- if (!charge)
21698
- return false;
21699
- if (charge.chargeType === graphql.scalar('ChargeType', 'USAGE'))
21700
- return false;
21701
- if (charge.pricingModel === graphql.scalar('PricingModel', 'FLAT'))
21702
- return false;
21703
- return true;
21713
+ const periodMonthsConverter = (period) => {
21714
+ if (period === 0)
21715
+ return graphql.scalar('BillingPeriod', 'ONCE');
21716
+ else if (period === 1)
21717
+ return graphql.scalar('BillingPeriod', 'MONTHLY');
21718
+ else if (period === 3)
21719
+ return graphql.scalar('BillingPeriod', 'QUARTERLY');
21720
+ else if (period === 6)
21721
+ return graphql.scalar('BillingPeriod', 'SEMI_ANNUAL');
21722
+ else if (period === 12)
21723
+ return graphql.scalar('BillingPeriod', 'ANNUAL');
21724
+ else
21725
+ return null;
21726
+ };
21727
+ const billingPeriodConverter = (period) => {
21728
+ if (period === graphql.scalar('BillingPeriod', 'ONCE'))
21729
+ return 0;
21730
+ else if (period === graphql.scalar('BillingPeriod', 'MONTHLY'))
21731
+ return 1;
21732
+ else if (period === graphql.scalar('BillingPeriod', 'QUARTERLY'))
21733
+ return 3;
21734
+ else if (period === graphql.scalar('BillingPeriod', 'SEMI_ANNUAL'))
21735
+ return 6;
21736
+ else
21737
+ return 12;
21738
+ };
21739
+
21740
+ function getAddonsForBillingPeriod(billingPeriod, addonPlans) {
21741
+ const flattenedPriceLists = addonPlans.flatMap(addonPlan => addonPlan.priceLists);
21742
+ return flattenedPriceLists.filter(priceList => priceList.periodMonths === billingPeriodConverter(billingPeriod));
21743
+ }
21744
+
21745
+ const hasUnpurchasedAddonPriceLists_PlanFragment = t(`
21746
+ fragment hasUnpurchasedAddonPriceLists_PlanFragment on Plan {
21747
+ priceLists {
21748
+ id
21749
+ isVisible
21750
+ periodMonths
21751
+ }
21752
+ }
21753
+ `);
21754
+ function hasUnpurchasedAddonPriceLists(maskedPriceListAddonPlans, currentSubscription, billingPeriod) {
21755
+ // Read fragments
21756
+ const priceListAddonPlans = maskedPriceListAddonPlans.map(maskedAddonPlan => readFragment(hasUnpurchasedAddonPriceLists_PlanFragment, maskedAddonPlan));
21757
+ const addonPriceLists = getAddonsForBillingPeriod(billingPeriod, priceListAddonPlans).filter(priceList => priceList.isVisible);
21758
+ const unpurchasedAddonPriceLists = addonPriceLists === null || addonPriceLists === void 0 ? void 0 : addonPriceLists.filter(addonPriceList => {
21759
+ var _a;
21760
+ 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));
21761
+ });
21762
+ return unpurchasedAddonPriceLists.length > 0;
21704
21763
  }
21705
21764
 
21706
21765
  function hasUnpurchasedFeatureAddons(priceList, currentSubscription) {
@@ -21727,775 +21786,764 @@ function featureAddonSwitchTestId(addonName) {
21727
21786
  return `feature-addon-switch-${name}`;
21728
21787
  }
21729
21788
 
21730
- const MUTATION$4 = `{
21731
- currentUser {
21732
- taxationRequiredAccountFields
21733
- }
21734
- }`;
21735
- const getTaxationRequiredAccountFields = async ({ apiHost, token, }) => {
21736
- var _a, _b;
21737
- const response = await gqlRequest({
21738
- query: MUTATION$4,
21739
- token,
21740
- apiHost: apiHost,
21741
- });
21742
- 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
21743
- ? response.currentUser.taxationRequiredAccountFields
21744
- : null;
21789
+ const canSubscriptionUpgradeFromTrial = (subscription) => {
21790
+ var _a;
21791
+ return (((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL') &&
21792
+ subscription.plan.selfServiceBuy) ||
21793
+ false;
21745
21794
  };
21746
-
21747
- const BunnyFooterIcon = ({ color }) => {
21748
- return (jsxRuntime.jsxs("svg", { width: "45", height: "15", viewBox: "0 0 39 13", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsxRuntime.jsxs("g", { clipPath: "url(#clip0_6_851)", children: [jsxRuntime.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 }), jsxRuntime.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 }), jsxRuntime.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 }), jsxRuntime.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 }), jsxRuntime.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 }), jsxRuntime.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 })] }), jsxRuntime.jsx("defs", { children: jsxRuntime.jsx("clipPath", { id: "clip0_6_851", children: jsxRuntime.jsx("rect", { width: "39", height: "13", fill: "white" }) }) })] }));
21795
+ const canSubscriptionUpgradeFromTrialExpired = (subscription) => {
21796
+ var _a;
21797
+ return (((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED') &&
21798
+ subscription.plan.selfServiceBuy) ||
21799
+ false;
21749
21800
  };
21750
-
21751
- const { Text: Text$o } = antd.Typography;
21752
- const Footer = ({ className }) => {
21753
- const token = useToken();
21754
- const { currentUser } = useCurrentUserData(token);
21755
- const { privacyUrl, termsUrl } = currentUser;
21756
- const isMobile = common.useIsMobile();
21757
- return (jsxRuntime.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) && (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-3", children: [termsUrl && (jsxRuntime.jsx(StyedLink, { className: "bunny-text-xs bunny-text-slate-400", href: termsUrl, rel: "noopener noreferrer", target: "_blank", type: "text", children: "Terms" })), privacyUrl && (jsxRuntime.jsx(StyedLink, { className: "bunny-text-xs bunny-text-slate-400", href: privacyUrl, rel: "noopener noreferrer", target: "_blank", type: "text", children: "Privacy" }))] })), jsxRuntime.jsx(BunnyMarketingLink, {})] }));
21801
+ const isSubscriptionNotActive = (subscription) => {
21802
+ var _a, _b, _c;
21803
+ return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'EXPIRED') ||
21804
+ ((_b = subscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === t.scalar('SubscriptionState', 'CANCELED') ||
21805
+ ((_c = subscription.state) === null || _c === void 0 ? void 0 : _c.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED');
21758
21806
  };
21759
- const BunnyMarketingLink = () => {
21760
- const [isHovered, setIsHovered] = react.useState(false);
21761
- const isMobile = common.useIsMobile();
21762
- return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-items-end bunny-justify-end ${isMobile ? '' : 'grow'}`, children: jsxRuntime.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: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center", onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: [jsxRuntime.jsx(Text$o, { className: "bunny-text-slate-400", children: "Powered by\u00A0" }), jsxRuntime.jsx("div", { style: { paddingTop: '5px' }, children: jsxRuntime.jsx(BunnyFooterIcon, { color: isHovered ? common.PRIMARY_COLOR : common.SLATE_400 }) })] }) }) }));
21807
+ const isSubscriptionActiveOrPending = (subscription) => {
21808
+ var _a, _b;
21809
+ return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'ACTIVE') ||
21810
+ ((_b = subscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === t.scalar('SubscriptionState', 'PENDING');
21763
21811
  };
21764
- const StyedLink = styled.a `
21765
- color: ${common.SLATE_400};
21766
- transition: color 0.3s;
21767
- &:hover {
21768
- color: ${common.SLATE_500};
21769
- }
21770
- text-decoration: none;
21771
- `;
21772
- const StyledBunnyLink = styled(StyedLink) `
21773
- &:hover {
21774
- color: ${common.PRIMARY_COLOR} !important;
21775
- }
21776
- `;
21777
-
21778
- const MUTATION$3 = `mutation quoteChangeAddCoupon($couponCode: String!, $quoteChangeId: ID!) {
21779
- quoteChangeAddCoupon(couponCode: $couponCode, quoteChangeId: $quoteChangeId) {
21780
- quoteChange {
21781
- id
21782
- charges {
21783
- id
21784
- amount
21785
- couponId
21786
- }
21787
- }
21788
- }
21789
- }`;
21790
- const quoteChangeAddCoupon = async ({ quoteChangeId, couponCode, token, apiHost, }) => {
21812
+ const isSubscriptionTrial = (subscription) => { var _a; return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL'); };
21813
+ const isSubscriptionTrialExpired = (subscription) => { var _a; return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED'); };
21814
+ // Helper function to check if charge is a discount
21815
+ const isDiscount$1 = (kind) => kind === common.QuoteChangeKind.DISCOUNT || kind === common.QuoteChangeKind.FREE_PERIOD_DISCOUNT;
21816
+ const hasPriceTiers = (charge) => {
21791
21817
  var _a;
21792
- const vars = { couponCode, quoteChangeId };
21793
- const response = await gqlRequest({
21794
- query: MUTATION$3,
21795
- token,
21796
- vars,
21797
- apiHost,
21798
- });
21799
- const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteAddCoupon) === null || _a === void 0 ? void 0 : _a.errors;
21800
- if (errors)
21801
- throw errors;
21802
- return response.quote;
21818
+ return Boolean((_a = charge === null || charge === void 0 ? void 0 : charge.priceTiers) === null || _a === void 0 ? void 0 : _a.length);
21803
21819
  };
21804
21820
 
21805
- const MUTATION$2 = `mutation quoteChangeRemoveCoupon($quoteChangeId: ID!, $couponCode: String!) {
21806
- quoteChangeRemoveCoupon(quoteChangeId: $quoteChangeId, couponCode: $couponCode) {
21807
- errors
21808
- }
21809
- }
21810
- `;
21811
- const quoteChangeRemoveCoupon = async ({ quoteChangeId, couponCode, token, apiHost, }) => {
21812
- var _a;
21813
- const vars = { couponCode, quoteChangeId };
21814
- const response = await gqlRequest({
21815
- query: MUTATION$2,
21816
- token,
21817
- vars,
21818
- apiHost,
21819
- });
21820
- const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteChangeRemoveCoupon) === null || _a === void 0 ? void 0 : _a.errors;
21821
- if (errors)
21822
- throw errors;
21823
- return response.quote;
21821
+ const removeHTMLTagsRegex = /<br>(?=(?:\s*<[^>]*>)*$)|(<br>)|<[^>]*>/gi;
21822
+ // Description is a string that can contain HTML tags. We want to remove all HTML tags except <br> tags.
21823
+ const createPlanDescription = (planDescription) => {
21824
+ return (planDescription || '').replace(removeHTMLTagsRegex, (_, y) => (y ? ' & ' : ''));
21824
21825
  };
21825
-
21826
- const COUPONS_QUERY = (filter) => `
21827
- query Coupons {
21828
- coupons(filter: ${filter ? `"${filter}"` : 'null'}) {
21829
- totalCount
21830
- }
21826
+ const getActivePlanPriceData = (priceList, selectedPriceList) => {
21827
+ if (!priceList) {
21828
+ return;
21831
21829
  }
21832
- `;
21833
- const getCoupons = async ({ token, apiHost, filter, }) => {
21834
- const response = await gqlRequest({
21835
- query: COUPONS_QUERY(filter),
21836
- token,
21837
- vars: {},
21838
- apiHost,
21839
- });
21840
- return response === null || response === void 0 ? void 0 : response.coupons;
21841
- };
21842
-
21843
- const showErrorNotification$3 = common.useErrorNotification();
21844
- const useUpdateCoupons = ({ apiHost, token, quoteChangeId, onCouponAdded, onCouponRemoved, }) => {
21845
- const { data: coupons } = reactQuery.useQuery({
21846
- queryKey: ['coupons', token],
21847
- queryFn: () => getCoupons({ token, apiHost, filter: 'coupon.active is true' }),
21848
- });
21849
- const { mutate: addCoupon, isPending: isAddingCoupon } = reactQuery.useMutation({
21850
- mutationFn: (couponCode) => {
21851
- if (!token) {
21852
- throw new Error('Token is required');
21853
- }
21854
- if (!quoteChangeId) {
21855
- throw new Error('Quote change ID is required');
21856
- }
21857
- return quoteChangeAddCoupon({
21858
- quoteChangeId,
21859
- couponCode,
21860
- apiHost,
21861
- token,
21862
- });
21863
- },
21864
- onSuccess: () => {
21865
- onCouponAdded === null || onCouponAdded === void 0 ? void 0 : onCouponAdded();
21866
- },
21867
- onError: (error) => {
21868
- var _a, _b;
21869
- 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');
21870
- },
21871
- });
21872
- const { mutate: removeCoupon, isPending: isRemovingCoupon } = reactQuery.useMutation({
21873
- mutationFn: (couponCode) => {
21874
- if (!quoteChangeId) {
21875
- throw new Error('Quote change ID is required');
21830
+ // If a period option is selected, return the charge that matches the selected period option
21831
+ let activeBillingPLCharge;
21832
+ // Default to first price list charge
21833
+ let lowestPLCharge;
21834
+ // Find the lowest price list charge with a billing period that matches the selected period option
21835
+ if (priceList.id === (selectedPriceList === null || selectedPriceList === void 0 ? void 0 : selectedPriceList.id)) {
21836
+ activeBillingPLCharge = priceList.charges[0];
21837
+ }
21838
+ for (let j = 0; j < priceList.charges.length; j++) {
21839
+ const charge = priceList.charges[j];
21840
+ if (charge.chargeType === common.ChargeType.USAGE || charge.featureAddon === true)
21841
+ continue;
21842
+ if (activeBillingPLCharge) {
21843
+ // If we already found a charge with the same billing period check if this charge is lower
21844
+ if (charge.basePrice < activeBillingPLCharge.basePrice &&
21845
+ charge.billingPeriod === (activeBillingPLCharge === null || activeBillingPLCharge === void 0 ? void 0 : activeBillingPLCharge.billingPeriod)) {
21846
+ activeBillingPLCharge = charge;
21876
21847
  }
21877
- return quoteChangeRemoveCoupon({
21878
- quoteChangeId,
21879
- couponCode,
21880
- apiHost,
21881
- token,
21882
- });
21883
- },
21884
- onSuccess: () => {
21885
- onCouponRemoved === null || onCouponRemoved === void 0 ? void 0 : onCouponRemoved();
21886
- },
21887
- onError: (error) => {
21888
- var _a, _b;
21889
- 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');
21890
- },
21891
- });
21848
+ }
21849
+ // If a period option is selected, only return the charge if it matches the selected period option
21850
+ else if (selectedPriceList &&
21851
+ charge.billingPeriod === periodMonthsConverter(selectedPriceList.periodMonths)) {
21852
+ activeBillingPLCharge = charge;
21853
+ }
21854
+ // Otherwise, return the lowest price list charge
21855
+ else if (charge.basePrice < ((lowestPLCharge === null || lowestPLCharge === void 0 ? void 0 : lowestPLCharge.basePrice) || -1)) {
21856
+ lowestPLCharge = charge;
21857
+ }
21858
+ }
21892
21859
  return {
21893
- addCoupon,
21894
- removeCoupon,
21895
- isAddingCoupon,
21896
- isRemovingCoupon,
21897
- activeCouponsExist: (coupons === null || coupons === void 0 ? void 0 : coupons.totalCount) > 0,
21860
+ activeCharge: activeBillingPLCharge || lowestPLCharge,
21898
21861
  };
21899
21862
  };
21900
-
21901
- function shouldShowCouponEditor(quote, activeCouponsExist, upgradingSubscription) {
21902
- var _a, _b;
21903
- const upgradingFromTrial = ((_a = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL') ||
21904
- ((_b = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED');
21905
- function upgradingFromFree() {
21906
- 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);
21907
- return totalPrice === 0;
21863
+ const showErrorNotification$3 = common.useErrorNotification();
21864
+ const isPriceListDisabled = ({ priceList, upgradingSubscription, }) => {
21865
+ const priceListAddonPlans = priceList === null || priceList === void 0 ? void 0 : priceList.plan.addonPlans;
21866
+ if (!priceListAddonPlans) {
21867
+ showErrorNotification$3('Price list addon plans are undefined');
21868
+ return false;
21908
21869
  }
21909
- const quoteKindIsValid = quote.kind === common.QuoteChangeKind.SUBSCRIBE ||
21910
- quote.kind === common.QuoteChangeKind.ADJUSTMENT ||
21911
- quote.kind === common.QuoteChangeKind.ACTIVATE;
21912
- if (quoteKindIsValid) {
21913
- return activeCouponsExist && (upgradingFromTrial || upgradingFromFree());
21870
+ const canPurchaseFeatureAddons = hasUnpurchasedFeatureAddons(priceList, upgradingSubscription);
21871
+ const canPurchasePlanAddons = hasUnpurchasedAddonPriceLists(priceListAddonPlans, upgradingSubscription, periodMonthsConverter(priceList.periodMonths));
21872
+ const existingSubscriptionInTrial = upgradingSubscription && canSubscriptionUpgradeFromTrial(upgradingSubscription);
21873
+ const existingSubscriptionInTrialExpired = upgradingSubscription && canSubscriptionUpgradeFromTrialExpired(upgradingSubscription);
21874
+ const isUpgradingSubscriptionPriceList = (upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.id) === priceList.id;
21875
+ // When should priceList be disabled?
21876
+ // if upgradingSubscription?.priceList.id === priceList.id
21877
+ // AND the upgradingSubscription is not in trial
21878
+ // AND cannot purchase feature addons
21879
+ // AND cannot purchase add-on plans
21880
+ // AND selfServiceBuy is false
21881
+ // if upgradingSubscription?.priceList.id != priceList.id
21882
+ // AND upgradingSubscription is expired trial
21883
+ if (isUpgradingSubscriptionPriceList) {
21884
+ return (!existingSubscriptionInTrial &&
21885
+ !existingSubscriptionInTrialExpired &&
21886
+ !canPurchaseFeatureAddons &&
21887
+ !canPurchasePlanAddons);
21914
21888
  }
21915
- return false;
21916
- }
21917
-
21918
- function CouponEditor({ className, onAddCoupon, isAddingCoupon, couponCode, setCouponCode, }) {
21919
- async function handleAddCoupon() {
21920
- onAddCoupon(couponCode);
21889
+ else {
21890
+ return false;
21921
21891
  }
21922
- return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-flex-col bunny-gap-2 ${className}`, children: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2", children: [jsxRuntime.jsx(antd.Input, { value: couponCode, onChange: e => setCouponCode(e.target.value), placeholder: "Coupon code", disabled: isAddingCoupon, size: "small" }), jsxRuntime.jsx(antd.Button, { loading: isAddingCoupon, type: "primary", onClick: handleAddCoupon, disabled: couponCode.length === 0, children: "Apply" })] }) }));
21892
+ };
21893
+
21894
+ const CheckoutButton = ({ disabled, onClickCheckout, loading, tooltipText, }) => {
21895
+ const isMobile = common.useIsMobile();
21896
+ const TooltipWrapper = ({ children }) => {
21897
+ if (tooltipText) {
21898
+ return jsxRuntime.jsx(antd.Tooltip, { title: tooltipText, children: children });
21899
+ }
21900
+ return jsxRuntime.jsx("div", { children: children });
21901
+ };
21902
+ return (jsxRuntime.jsx(TooltipWrapper, { children: jsxRuntime.jsx(antd.Button, { className: isMobile ? 'w-full' : '', disabled: disabled, onClick: onClickCheckout, size: isMobile ? 'large' : 'middle', type: "primary", loading: loading, children: "Proceed to checkout" }) }));
21903
+ };
21904
+
21905
+ var localizedFormat$2 = {exports: {}};
21906
+
21907
+ var localizedFormat$1 = localizedFormat$2.exports;
21908
+
21909
+ var hasRequiredLocalizedFormat;
21910
+
21911
+ function requireLocalizedFormat () {
21912
+ if (hasRequiredLocalizedFormat) return localizedFormat$2.exports;
21913
+ hasRequiredLocalizedFormat = 1;
21914
+ (function (module, exports) {
21915
+ !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)};}}));
21916
+ } (localizedFormat$2));
21917
+ return localizedFormat$2.exports;
21923
21918
  }
21924
21919
 
21925
- const QuoteFields_QuoteFragment = t(`
21926
- fragment QuoteFields_QuoteFragment on Quote @_unmask {
21927
- accountId
21928
- amount
21929
- amountDue
21930
- smallUnitAmountDue
21931
- currencyId
21932
- id
21933
- payableId
21920
+ var localizedFormatExports = requireLocalizedFormat();
21921
+ var localizedFormat = /*@__PURE__*/getDefaultExportFromCjs(localizedFormatExports);
21922
+
21923
+ dayjs.extend(localizedFormat);
21924
+ const formatCurrency = (value, currencyIsoCode, decimals = 2) => {
21925
+ if (value !== 0 && !value)
21926
+ return '';
21927
+ const currencyValue = typeof value === 'string' ? parseFloat(value) : value;
21928
+ if (isNaN(currencyValue))
21929
+ return value;
21930
+ const localeOptions = {
21931
+ minimumFractionDigits: decimals,
21932
+ maximumFractionDigits: decimals,
21933
+ };
21934
+ localeOptions.style = 'currency';
21935
+ localeOptions.currency = currencyIsoCode;
21936
+ return currencyValue.toLocaleString(navigator.language, localeOptions);
21937
+ };
21938
+
21939
+ const CheckoutPrice_QuoteFragment = t(`
21940
+ fragment CheckoutPrice_QuoteFragment on Quote {
21934
21941
  periodAmount
21935
- subtotal
21936
- taxAmount
21937
- startDate
21938
- formattedQuote {
21939
- html
21940
- }
21941
- amountsByPeriod {
21942
- amount
21943
- startDate
21944
- }
21945
- kind
21942
+ amountDue
21943
+ }
21944
+ `);
21945
+ const CheckoutPrice = ({ isUsage, quote: maskedQuote, selectedPriceList, }) => {
21946
+ var _a;
21947
+ // Read fragments
21948
+ const quote = readFragment(CheckoutPrice_QuoteFragment, maskedQuote);
21949
+ // Hooks
21950
+ const isMobile = common.useIsMobile();
21951
+ // amountDue might not be available, so we use periodAmount as a fallback
21952
+ 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;
21953
+ if (!isUsage && (!selectedPriceList || displayAmount === undefined))
21954
+ return null;
21955
+ const convertedPeriodMonths = periodMonthsConverter(selectedPriceList.periodMonths);
21956
+ const periodLabel = convertedPeriodMonths ? common.PERIOD_LABELS[convertedPeriodMonths] : 'undefined';
21957
+ return (jsxRuntime.jsx("div", { className: `bunny-font-medium ${isMobile ? 'bunny-text-2xl' : ''}`, children: isUsage
21958
+ ? 'Usage based pricing'
21959
+ : selectedPriceList && displayAmount !== undefined
21960
+ ? `${formatCurrency(displayAmount, selectedPriceList === null || selectedPriceList === void 0 ? void 0 : selectedPriceList.currencyId, undefined)} / ${periodLabel}`
21961
+ : '' }));
21962
+ };
21963
+
21964
+ const { Text: Text$p } = antd.Typography;
21965
+ const CheckoutBarSummarySection_QuoteFragment = t(`
21966
+ fragment CheckoutBarSummarySection_QuoteFragment on Quote {
21946
21967
  quoteChanges {
21947
- currencyId
21948
- id
21949
- kind
21950
21968
  charges {
21951
- subtotal
21952
- amountsByPeriod {
21953
- amount
21954
- startDate
21955
- }
21956
- amount
21957
- billingPeriod
21958
- currencyId
21959
- feature {
21960
- unitName
21961
- }
21962
- id
21963
- name
21964
- priceListCharge {
21965
- id
21966
- }
21967
- priceList {
21968
- id
21969
- }
21970
- coupon {
21971
- couponCode
21972
- }
21973
- quantity
21974
- kind
21975
- }
21976
- priceList {
21977
21969
  id
21978
- plan {
21979
- name
21980
- }
21981
- product {
21982
- name
21983
- }
21984
21970
  }
21985
21971
  }
21972
+ ...CheckoutPrice_QuoteFragment
21986
21973
  }
21987
- `);
21974
+ `, [CheckoutPrice_QuoteFragment]);
21975
+ const CheckoutBarSummarySection = ({ selectedPriceList, onClickCheckout, }) => {
21976
+ var _a, _b;
21977
+ // Context
21978
+ const { quote: maskedQuote, isQuotePending, isUpdatingQuote } = react.useContext(QuoteContext);
21979
+ const quote = readFragment(CheckoutBarSummarySection_QuoteFragment, maskedQuote);
21980
+ const { isInPreviewMode } = react.useContext(SubscriptionsContext);
21981
+ // Hooks
21982
+ const { paymentPlugins } = usePaymentPlugins(undefined);
21983
+ const isMobile = common.useIsMobile();
21984
+ const hasPaymentPlugins = Boolean(paymentPlugins === null || paymentPlugins === void 0 ? void 0 : paymentPlugins.length);
21985
+ 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));
21986
+ const checkoutButtonDisabled = Boolean(!selectedPriceList || !quoteHasCharges || !hasPaymentPlugins || isInPreviewMode);
21987
+ const activeCharge = (_b = getActivePlanPriceData(selectedPriceList, selectedPriceList)) === null || _b === void 0 ? void 0 : _b.activeCharge;
21988
+ const isUsage = (activeCharge === null || activeCharge === void 0 ? void 0 : activeCharge.chargeType) === common.ChargeType.USAGE;
21989
+ return (jsxRuntime.jsxs(Text$p, { className: `bunny-flex bunny-items-center bunny-gap-4 ${isMobile ? 'bunny-flex-col' : ''}`, children: [quote && (jsxRuntime.jsxs("div", { className: `bunny-flex ${isMobile ? 'items-center justify-between w-full' : 'flex-col'}`, children: [jsxRuntime.jsx("div", { className: "bunny-text-slate-500 bunny-font-medium bunny-text-right", style: { fontSize: '11px' }, children: "TOTAL" }), jsxRuntime.jsx(CheckoutPrice, { isUsage: isUsage, quote: quote, selectedPriceList: selectedPriceList })] })), jsxRuntime.jsx(CheckoutButton, { disabled: checkoutButtonDisabled, onClickCheckout: onClickCheckout, loading: isQuotePending || isUpdatingQuote, tooltipText: isInPreviewMode
21990
+ ? 'Checkout is disabled in preview mode'
21991
+ : !hasPaymentPlugins
21992
+ ? 'Cannot checkout. No valid payment plugins found. Please contact your administrator.'
21993
+ : undefined })] }));
21994
+ };
21988
21995
 
21989
- const MUTATION$1 = `
21990
- mutation accountUpdate(
21991
- $id: ID!,
21992
- $attributes: AccountAttributes!) {
21993
- accountUpdate(
21994
- id: $id,
21995
- attributes: $attributes
21996
- ) {
21997
- account {
21998
- id
21999
- billingCountry
22000
- billingState
22001
- billingStreet
22002
- billingCity
22003
- billingZip
22004
- name
21996
+ const MUTATION$3 = `{
21997
+ currentUser {
21998
+ taxationRequiredAccountFields
21999
+ }
22000
+ }`;
22001
+ const getTaxationRequiredAccountFields = async ({ apiHost, token, }) => {
22002
+ var _a, _b;
22003
+ const response = await gqlRequest({
22004
+ query: MUTATION$3,
22005
+ token,
22006
+ apiHost: apiHost,
22007
+ });
22008
+ 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
22009
+ ? response.currentUser.taxationRequiredAccountFields
22010
+ : null;
22011
+ };
22012
+
22013
+ const BunnyFooterIcon = ({ color }) => {
22014
+ return (jsxRuntime.jsxs("svg", { width: "45", height: "15", viewBox: "0 0 39 13", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsxRuntime.jsxs("g", { clipPath: "url(#clip0_6_851)", children: [jsxRuntime.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 }), jsxRuntime.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 }), jsxRuntime.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 }), jsxRuntime.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 }), jsxRuntime.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 }), jsxRuntime.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 })] }), jsxRuntime.jsx("defs", { children: jsxRuntime.jsx("clipPath", { id: "clip0_6_851", children: jsxRuntime.jsx("rect", { width: "39", height: "13", fill: "white" }) }) })] }));
22015
+ };
22016
+
22017
+ const { Text: Text$o } = antd.Typography;
22018
+ const Footer = ({ className }) => {
22019
+ const token = useToken();
22020
+ const { currentUser } = useCurrentUserData(token);
22021
+ const { privacyUrl, termsUrl } = currentUser;
22022
+ const isMobile = common.useIsMobile();
22023
+ return (jsxRuntime.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) && (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center bunny-gap-3", children: [termsUrl && (jsxRuntime.jsx(StyedLink, { className: "bunny-text-xs bunny-text-slate-400", href: termsUrl, rel: "noopener noreferrer", target: "_blank", type: "text", children: "Terms" })), privacyUrl && (jsxRuntime.jsx(StyedLink, { className: "bunny-text-xs bunny-text-slate-400", href: privacyUrl, rel: "noopener noreferrer", target: "_blank", type: "text", children: "Privacy" }))] })), jsxRuntime.jsx(BunnyMarketingLink, {})] }));
22024
+ };
22025
+ const BunnyMarketingLink = () => {
22026
+ const [isHovered, setIsHovered] = react.useState(false);
22027
+ const isMobile = common.useIsMobile();
22028
+ return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-items-end bunny-justify-end ${isMobile ? '' : 'grow'}`, children: jsxRuntime.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: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-items-center", onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: [jsxRuntime.jsx(Text$o, { className: "bunny-text-slate-400", children: "Powered by\u00A0" }), jsxRuntime.jsx("div", { style: { paddingTop: '5px' }, children: jsxRuntime.jsx(BunnyFooterIcon, { color: isHovered ? common.PRIMARY_COLOR : common.SLATE_400 }) })] }) }) }));
22029
+ };
22030
+ const StyedLink = styled.a `
22031
+ color: ${common.SLATE_400};
22032
+ transition: color 0.3s;
22033
+ &:hover {
22034
+ color: ${common.SLATE_500};
22035
+ }
22036
+ text-decoration: none;
22037
+ `;
22038
+ const StyledBunnyLink = styled(StyedLink) `
22039
+ &:hover {
22040
+ color: ${common.PRIMARY_COLOR} !important;
22041
+ }
22042
+ `;
22043
+
22044
+ const MUTATION$2 = `mutation quoteChangeAddCoupon($couponCode: String!, $quoteChangeId: ID!) {
22045
+ quoteChangeAddCoupon(couponCode: $couponCode, quoteChangeId: $quoteChangeId) {
22046
+ quoteChange {
22047
+ id
22048
+ charges {
22049
+ id
22050
+ amount
22051
+ couponId
22005
22052
  }
22006
- errors
22007
22053
  }
22008
- }
22054
+ }
22055
+ }`;
22056
+ const quoteChangeAddCoupon = async ({ quoteChangeId, couponCode, token, apiHost, }) => {
22057
+ var _a;
22058
+ const vars = { couponCode, quoteChangeId };
22059
+ const response = await gqlRequest({
22060
+ query: MUTATION$2,
22061
+ token,
22062
+ vars,
22063
+ apiHost,
22064
+ });
22065
+ const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteAddCoupon) === null || _a === void 0 ? void 0 : _a.errors;
22066
+ if (errors)
22067
+ throw errors;
22068
+ return response.quote;
22069
+ };
22070
+
22071
+ const MUTATION$1 = `mutation quoteChangeRemoveCoupon($quoteChangeId: ID!, $couponCode: String!) {
22072
+ quoteChangeRemoveCoupon(quoteChangeId: $quoteChangeId, couponCode: $couponCode) {
22073
+ errors
22074
+ }
22075
+ }
22009
22076
  `;
22010
- const accountUpdate = async ({ accountId, attributes, token, apiHost, }) => {
22077
+ const quoteChangeRemoveCoupon = async ({ quoteChangeId, couponCode, token, apiHost, }) => {
22011
22078
  var _a;
22012
- const vars = { id: accountId, attributes };
22079
+ const vars = { couponCode, quoteChangeId };
22013
22080
  const response = await gqlRequest({
22014
22081
  query: MUTATION$1,
22015
22082
  token,
22016
22083
  vars,
22017
22084
  apiHost,
22018
22085
  });
22019
- const errors = (_a = response === null || response === void 0 ? void 0 : response.accountUpdate) === null || _a === void 0 ? void 0 : _a.errors;
22086
+ const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteChangeRemoveCoupon) === null || _a === void 0 ? void 0 : _a.errors;
22020
22087
  if (errors)
22021
22088
  throw errors;
22022
- return response.accountUpdate;
22089
+ return response.quote;
22023
22090
  };
22024
22091
 
22025
- const COUNTRIES_REQUIRING_STATE = ['US', 'CA'];
22026
- const TaxationForm = ({ account, accountId }) => {
22027
- // Hooks
22028
- const queryClient = reactQuery.useQueryClient();
22029
- const { apiHost } = react.useContext(BunnyContext);
22030
- const token = useToken();
22031
- const [form] = antd.Form.useForm();
22032
- // Mutations
22033
- const { mutate: updateAccount, isPending: isUpdatingAccount } = reactQuery.useMutation({
22034
- mutationFn: async (changedFormData) => {
22035
- const account = await accountUpdate({
22036
- accountId,
22037
- attributes: changedFormData,
22038
- token,
22092
+ const COUPONS_QUERY = (filter) => `
22093
+ query Coupons {
22094
+ coupons(filter: ${filter ? `"${filter}"` : 'null'}) {
22095
+ totalCount
22096
+ }
22097
+ }
22098
+ `;
22099
+ const getCoupons = async ({ token, apiHost, filter, }) => {
22100
+ const response = await gqlRequest({
22101
+ query: COUPONS_QUERY(filter),
22102
+ token,
22103
+ vars: {},
22104
+ apiHost,
22105
+ });
22106
+ return response === null || response === void 0 ? void 0 : response.coupons;
22107
+ };
22108
+
22109
+ const showErrorNotification$2 = common.useErrorNotification();
22110
+ const useUpdateCoupons = ({ apiHost, token, quoteChangeId, onCouponAdded, onCouponRemoved, }) => {
22111
+ const { data: coupons } = reactQuery.useQuery({
22112
+ queryKey: ['coupons', token],
22113
+ queryFn: () => getCoupons({ token, apiHost, filter: 'coupon.active is true' }),
22114
+ });
22115
+ const { mutate: addCoupon, isPending: isAddingCoupon } = reactQuery.useMutation({
22116
+ mutationFn: (couponCode) => {
22117
+ if (!token) {
22118
+ throw new Error('Token is required');
22119
+ }
22120
+ if (!quoteChangeId) {
22121
+ throw new Error('Quote change ID is required');
22122
+ }
22123
+ return quoteChangeAddCoupon({
22124
+ quoteChangeId,
22125
+ couponCode,
22039
22126
  apiHost,
22127
+ token,
22040
22128
  });
22041
- return account;
22042
22129
  },
22043
22130
  onSuccess: () => {
22044
- queryClient.invalidateQueries({
22045
- queryKey: ['getTaxationRequiredAccountFields', token],
22131
+ onCouponAdded === null || onCouponAdded === void 0 ? void 0 : onCouponAdded();
22132
+ },
22133
+ onError: (error) => {
22134
+ var _a, _b;
22135
+ 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');
22136
+ },
22137
+ });
22138
+ const { mutate: removeCoupon, isPending: isRemovingCoupon } = reactQuery.useMutation({
22139
+ mutationFn: (couponCode) => {
22140
+ if (!quoteChangeId) {
22141
+ throw new Error('Quote change ID is required');
22142
+ }
22143
+ return quoteChangeRemoveCoupon({
22144
+ quoteChangeId,
22145
+ couponCode,
22146
+ apiHost,
22147
+ token,
22046
22148
  });
22047
22149
  },
22150
+ onSuccess: () => {
22151
+ onCouponRemoved === null || onCouponRemoved === void 0 ? void 0 : onCouponRemoved();
22152
+ },
22153
+ onError: (error) => {
22154
+ var _a, _b;
22155
+ 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');
22156
+ },
22048
22157
  });
22049
- return (jsxRuntime.jsxs(antd.Form, { className: "bunny-flex bunny-flex-col bunny-gap-4", form: form, initialValues: account, layout: "vertical", onFinish: updateAccount, children: [jsxRuntime.jsx(antd.Form.Item, { label: "Billing street", name: "billingStreet", children: jsxRuntime.jsx(antd.Input, { placeholder: "Street" }) }), jsxRuntime.jsx(antd.Form.Item, { label: "Billing city", name: "billingCity", children: jsxRuntime.jsx(antd.Input, { placeholder: "City" }) }), jsxRuntime.jsx(FormBillingState, {}), jsxRuntime.jsx(antd.Form.Item, { label: "Billing country", name: "billingCountry", rules: [{ required: true }], children: jsxRuntime.jsx(antd.Select, { options: common.Lists.COUNTRY_LIST, placeholder: "Select a country", showSearch: true, filterOption: (input, option) => {
22050
- var _a, _b;
22051
- return ((_a = option === null || option === void 0 ? void 0 : option.label) !== null && _a !== void 0 ? _a : '').toLowerCase().includes(input.toLowerCase()) ||
22052
- ((_b = option === null || option === void 0 ? void 0 : option.value) !== null && _b !== void 0 ? _b : '').toLowerCase().includes(input.toLowerCase());
22053
- } }) }), jsxRuntime.jsx(antd.Form.Item, { label: "Billing zip", name: "billingZip", children: jsxRuntime.jsx(antd.Input, { placeholder: "Zip" }) }), jsxRuntime.jsx(antd.Form.Item, { children: jsxRuntime.jsx(antd.Button, { className: "bunny-w-full", disabled: isUpdatingAccount, htmlType: "submit", type: "primary", children: "Submit" }) })] }));
22054
- };
22055
- const FormBillingState = () => {
22056
- const billingCountry = antd.Form.useWatch('billingCountry');
22057
- const billingStateRequired = COUNTRIES_REQUIRING_STATE.includes(billingCountry);
22058
- return (jsxRuntime.jsx(antd.Form.Item, { label: "Billing state", name: "billingState", rules: [{ required: billingStateRequired }], children: jsxRuntime.jsx(antd.Input, { placeholder: "State" }) }));
22158
+ return {
22159
+ addCoupon,
22160
+ removeCoupon,
22161
+ isAddingCoupon,
22162
+ isRemovingCoupon,
22163
+ activeCouponsExist: (coupons === null || coupons === void 0 ? void 0 : coupons.totalCount) > 0,
22164
+ };
22059
22165
  };
22060
22166
 
22061
- // HACK: I have imported QuoteFields_QuoteFragment here as a hack to ensure I have all of the quote data needed for
22062
- // the eventual children of this component.
22063
- // Solution: Eventually all children of this component should be using query fragments to avoid this
22064
- const QuoteCheckout_QuoteFragment = t(`
22065
- fragment QuoteCheckout_QuoteFragment on Quote {
22066
- id
22167
+ function shouldShowCouponEditor(quote, activeCouponsExist, upgradingSubscription) {
22168
+ var _a, _b;
22169
+ const upgradingFromTrial = ((_a = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL') ||
22170
+ ((_b = upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED');
22171
+ function upgradingFromFree() {
22172
+ 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);
22173
+ return totalPrice === 0;
22174
+ }
22175
+ const quoteKindIsValid = quote.kind === common.QuoteChangeKind.SUBSCRIBE ||
22176
+ quote.kind === common.QuoteChangeKind.ADJUSTMENT ||
22177
+ quote.kind === common.QuoteChangeKind.ACTIVATE;
22178
+ if (quoteKindIsValid) {
22179
+ return activeCouponsExist && (upgradingFromTrial || upgradingFromFree());
22180
+ }
22181
+ return false;
22182
+ }
22183
+
22184
+ function CouponEditor({ className, onAddCoupon, isAddingCoupon, couponCode, setCouponCode, }) {
22185
+ async function handleAddCoupon() {
22186
+ onAddCoupon(couponCode);
22187
+ }
22188
+ return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-flex-col bunny-gap-2 ${className}`, children: jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2", children: [jsxRuntime.jsx(antd.Input, { value: couponCode, onChange: e => setCouponCode(e.target.value), placeholder: "Coupon code", disabled: isAddingCoupon, size: "small" }), jsxRuntime.jsx(antd.Button, { loading: isAddingCoupon, type: "primary", onClick: handleAddCoupon, disabled: couponCode.length === 0, children: "Apply" })] }) }));
22189
+ }
22190
+
22191
+ const QuoteFields_QuoteFragment = t(`
22192
+ fragment QuoteFields_QuoteFragment on Quote @_unmask {
22067
22193
  accountId
22068
- amountDue
22069
22194
  amount
22195
+ amountDue
22196
+ smallUnitAmountDue
22197
+ currencyId
22198
+ id
22199
+ payableId
22200
+ periodAmount
22201
+ subtotal
22202
+ taxAmount
22203
+ startDate
22204
+ formattedQuote {
22205
+ html
22206
+ }
22207
+ amountsByPeriod {
22208
+ amount
22209
+ startDate
22210
+ }
22211
+ kind
22070
22212
  quoteChanges {
22213
+ currencyId
22071
22214
  id
22215
+ kind
22072
22216
  charges {
22073
- kind
22217
+ subtotal
22218
+ amountsByPeriod {
22219
+ amount
22220
+ startDate
22221
+ }
22222
+ amount
22223
+ billingPeriod
22224
+ currencyId
22225
+ feature {
22226
+ unitName
22227
+ }
22228
+ id
22229
+ name
22230
+ priceListCharge {
22231
+ id
22232
+ }
22233
+ priceList {
22234
+ id
22235
+ }
22074
22236
  coupon {
22075
22237
  couponCode
22076
22238
  }
22239
+ quantity
22240
+ kind
22077
22241
  }
22078
- }
22079
- ...QuoteFields_QuoteFragment
22080
- }
22081
- `, [QuoteFields_QuoteFragment]);
22082
- const showSuccessNotification$1 = common.useSuccessNotification();
22083
- const QuoteCheckout = ({ account, onSuccess, onFail, quote: maskedQuote, taxationRequiredAccountFields, onRecalculateTaxes, }) => {
22084
- var _a, _b, _c, _d, _e;
22085
- // Read fragments
22086
- const quote = readFragment(QuoteCheckout_QuoteFragment, maskedQuote);
22242
+ priceList {
22243
+ id
22244
+ plan {
22245
+ name
22246
+ }
22247
+ product {
22248
+ name
22249
+ }
22250
+ }
22251
+ }
22252
+ }
22253
+ `);
22254
+
22255
+ const MUTATION = `
22256
+ mutation accountUpdate(
22257
+ $id: ID!,
22258
+ $attributes: AccountAttributes!) {
22259
+ accountUpdate(
22260
+ id: $id,
22261
+ attributes: $attributes
22262
+ ) {
22263
+ account {
22264
+ id
22265
+ billingCountry
22266
+ billingState
22267
+ billingStreet
22268
+ billingCity
22269
+ billingZip
22270
+ name
22271
+ }
22272
+ errors
22273
+ }
22274
+ }
22275
+ `;
22276
+ const accountUpdate$1 = async ({ accountId, attributes, token, apiHost, }) => {
22277
+ var _a;
22278
+ const vars = { id: accountId, attributes };
22279
+ const response = await gqlRequest({
22280
+ query: MUTATION,
22281
+ token,
22282
+ vars,
22283
+ apiHost,
22284
+ });
22285
+ const errors = (_a = response === null || response === void 0 ? void 0 : response.accountUpdate) === null || _a === void 0 ? void 0 : _a.errors;
22286
+ if (errors)
22287
+ throw errors;
22288
+ return response.accountUpdate;
22289
+ };
22290
+
22291
+ const COUNTRIES_REQUIRING_STATE = ['US', 'CA'];
22292
+ const TaxationForm = ({ account, accountId }) => {
22293
+ // Hooks
22294
+ const queryClient = reactQuery.useQueryClient();
22087
22295
  const { apiHost } = react.useContext(BunnyContext);
22088
- const { upgradingSubscription } = react.useContext(SubscriptionsContext);
22089
22296
  const token = useToken();
22090
- const isMobile = common.useIsMobile();
22091
- const [isSaving, setIsSaving] = react.useState(false);
22092
- const paymentRequired = getQuoteAmountDue(quote) > 0;
22093
- const queryClient = reactQuery.useQueryClient();
22094
- const [couponCode, setCouponCode] = react.useState('');
22095
- const { addCoupon, removeCoupon, isAddingCoupon, isRemovingCoupon, activeCouponsExist } = useUpdateCoupons({
22096
- apiHost,
22097
- token,
22098
- 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,
22099
- onCouponAdded: () => {
22100
- if (!(quote === null || quote === void 0 ? void 0 : quote.id))
22101
- throw new Error('Quote ID is required');
22102
- queryClient.invalidateQueries({
22103
- queryKey: common.QueryKeyFactory.default.createObjectKey({
22104
- id: quote === null || quote === void 0 ? void 0 : quote.id,
22105
- objectName: 'editingQuote',
22106
- token,
22107
- }),
22297
+ const [form] = antd.Form.useForm();
22298
+ // Mutations
22299
+ const { mutate: updateAccount, isPending: isUpdatingAccount } = reactQuery.useMutation({
22300
+ mutationFn: async (changedFormData) => {
22301
+ const account = await accountUpdate$1({
22302
+ accountId,
22303
+ attributes: changedFormData,
22304
+ token,
22305
+ apiHost,
22108
22306
  });
22109
- showSuccessNotification$1('Coupon applied');
22110
- onRecalculateTaxes();
22111
- setCouponCode('');
22307
+ return account;
22112
22308
  },
22113
- onCouponRemoved: () => {
22114
- if (!(quote === null || quote === void 0 ? void 0 : quote.id))
22115
- throw new Error('Quote ID is required');
22309
+ onSuccess: () => {
22116
22310
  queryClient.invalidateQueries({
22117
- queryKey: common.QueryKeyFactory.default.createObjectKey({
22118
- id: quote === null || quote === void 0 ? void 0 : quote.id,
22119
- objectName: 'editingQuote',
22120
- token,
22121
- }),
22311
+ queryKey: ['getTaxationRequiredAccountFields', token],
22122
22312
  });
22123
- showSuccessNotification$1('Coupon removed');
22124
- onRecalculateTaxes();
22125
22313
  },
22126
22314
  });
22127
- 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'); });
22128
- const checkoutMutation = reactQuery.useMutation({
22129
- mutationFn: async () => {
22130
- if (!(quote === null || quote === void 0 ? void 0 : quote.id))
22131
- throw new Error('Quote ID is required');
22132
- if (paymentRequired)
22133
- throw new Error('Payment is required');
22134
- return await checkout({ quoteId: quote.id, token, apiHost });
22135
- },
22136
- onSuccess,
22137
- onError: onFail,
22138
- });
22139
- async function handleCheckoutNoPayment() {
22140
- setIsSaving(true);
22141
- checkoutMutation.mutate();
22142
- setIsSaving(false);
22143
- }
22144
- if (taxationRequiredAccountFields)
22145
- return (jsxRuntime.jsx(PaymentFormWrapper, { setMaxHeight: false, children: jsxRuntime.jsx(TaxationForm, { account: account, accountId: quote.accountId }) }));
22146
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: paymentRequired ? (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2 bunny-w-full", children: [jsxRuntime.jsx(PaymentForm, { onPaymentSuccess: onSuccess, quote: quote }), (couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.length) === 0 ? (jsxRuntime.jsx(jsxRuntime.Fragment, { children: upgradingSubscription &&
22147
- shouldShowCouponEditor(quote, activeCouponsExist, upgradingSubscription) && (jsxRuntime.jsx(CouponEditor, { className: "bunny-px-4 bunny-pt-1", quote: quote, onAddCoupon: addCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode })) })) : (jsxRuntime.jsx(antd.Button, { type: "link", loading: isRemovingCoupon, onClick: () => {
22148
- couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.forEach(couponCharge => {
22149
- var _a;
22150
- const couponCode = (_a = couponCharge === null || couponCharge === void 0 ? void 0 : couponCharge.coupon) === null || _a === void 0 ? void 0 : _a.couponCode;
22151
- if (couponCode) {
22152
- removeCoupon(couponCode);
22153
- }
22154
- });
22155
- }, children: "Remove coupon(s)" }))] })) : (jsxRuntime.jsx(PaymentFormWrapper, { setMaxHeight: false, children: jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-2 bunny-px-4 ${isMobile ? 'bunny-shadow-padding-x' : ''}`, children: [jsxRuntime.jsx(antd.Button, { onClick: handleCheckoutNoPayment, type: "primary", children: isSaving ? 'Processing...' : 'Complete order' }), jsxRuntime.jsx("div", { className: "bunny-text-xs bunny-text-slate-500", children: "No payment is required" })] }) })) }));
22315
+ return (jsxRuntime.jsxs(antd.Form, { className: "bunny-flex bunny-flex-col bunny-gap-4", form: form, initialValues: account, layout: "vertical", onFinish: updateAccount, children: [jsxRuntime.jsx(antd.Form.Item, { label: "Billing street", name: "billingStreet", children: jsxRuntime.jsx(antd.Input, { placeholder: "Street" }) }), jsxRuntime.jsx(antd.Form.Item, { label: "Billing city", name: "billingCity", children: jsxRuntime.jsx(antd.Input, { placeholder: "City" }) }), jsxRuntime.jsx(FormBillingState, {}), jsxRuntime.jsx(antd.Form.Item, { label: "Billing country", name: "billingCountry", rules: [{ required: true }], children: jsxRuntime.jsx(antd.Select, { options: common.Lists.COUNTRY_LIST, placeholder: "Select a country", showSearch: true, filterOption: (input, option) => {
22316
+ var _a, _b;
22317
+ return ((_a = option === null || option === void 0 ? void 0 : option.label) !== null && _a !== void 0 ? _a : '').toLowerCase().includes(input.toLowerCase()) ||
22318
+ ((_b = option === null || option === void 0 ? void 0 : option.value) !== null && _b !== void 0 ? _b : '').toLowerCase().includes(input.toLowerCase());
22319
+ } }) }), jsxRuntime.jsx(antd.Form.Item, { label: "Billing zip", name: "billingZip", children: jsxRuntime.jsx(antd.Input, { placeholder: "Zip" }) }), jsxRuntime.jsx(antd.Form.Item, { children: jsxRuntime.jsx(antd.Button, { className: "bunny-w-full", disabled: isUpdatingAccount, htmlType: "submit", type: "primary", children: "Submit" }) })] }));
22156
22320
  };
22157
- const PaymentFormWrapper = ({ children, setMaxHeight, className, }) => {
22158
- const isMobile = common.useIsMobile();
22159
- return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-w-full bunny-flex-col bunny-gap-6 ${isMobile ? 'bunny-shadow-padding-xb' : ''} ${className}`, style: {
22160
- ...(isMobile
22161
- ? setMaxHeight
22162
- ? { maxHeight: '60vh' }
22163
- : {}
22164
- : {
22165
- width: '100%',
22166
- maxWidth: '350px',
22167
- }),
22168
- }, children: children }));
22321
+ const FormBillingState = () => {
22322
+ const billingCountry = antd.Form.useWatch('billingCountry');
22323
+ const billingStateRequired = COUNTRIES_REQUIRING_STATE.includes(billingCountry);
22324
+ return (jsxRuntime.jsx(antd.Form.Item, { label: "Billing state", name: "billingState", rules: [{ required: billingStateRequired }], children: jsxRuntime.jsx(antd.Input, { placeholder: "State" }) }));
22169
22325
  };
22170
22326
 
22171
- const queryKeyFactory = common.QueryKeyFactory.default;
22172
- const Checkout_QuoteFragment = t(`
22173
- fragment Checkout_QuoteFragment on Quote {
22327
+ const { Text: Text$n } = antd.Typography;
22328
+ // HACK: I have imported QuoteFields_QuoteFragment here as a hack to ensure I have all of the quote data needed for
22329
+ // the eventual children of this component.
22330
+ // Solution: Eventually all children of this component should be using query fragments to avoid this
22331
+ const QuoteCheckout_QuoteFragment = t(`
22332
+ fragment QuoteCheckout_QuoteFragment on Quote {
22174
22333
  id
22175
22334
  accountId
22176
- formattedQuote {
22177
- html
22335
+ amountDue
22336
+ amount
22337
+ quoteChanges {
22338
+ id
22339
+ charges {
22340
+ kind
22341
+ coupon {
22342
+ couponCode
22343
+ }
22344
+ }
22178
22345
  }
22179
- ...QuoteCheckout_QuoteFragment
22346
+ ...QuoteFields_QuoteFragment
22180
22347
  }
22181
- `, [QuoteCheckout_QuoteFragment]);
22182
- const Checkout = ({ onCancel, onSuccess, onFail, invoice, open, quote: maskedQuote, isUpdatingQuote, }) => {
22348
+ `, [QuoteFields_QuoteFragment]);
22349
+ const showSuccessNotification$1 = common.useSuccessNotification();
22350
+ const QuoteCheckout = ({ account, onSuccess, onFail, quote: maskedQuote, taxationRequiredAccountFields, onRecalculateTaxes, }) => {
22183
22351
  var _a, _b, _c, _d, _e;
22352
+ // Read fragments
22353
+ const quote = readFragment(QuoteCheckout_QuoteFragment, maskedQuote);
22184
22354
  const { apiHost } = react.useContext(BunnyContext);
22185
- const isMobile = common.useIsMobile();
22355
+ const { upgradingSubscription } = react.useContext(SubscriptionsContext);
22186
22356
  const token = useToken();
22187
- // Read fragments
22188
- const quote = readFragment(Checkout_QuoteFragment, maskedQuote);
22189
- const hasTaxPlugin = useHasTaxPlugin({
22357
+ const isMobile = common.useIsMobile();
22358
+ const [isSaving, setIsSaving] = react.useState(false);
22359
+ const paymentRequired = getQuoteAmountDue(quote) > 0;
22360
+ const queryClient = reactQuery.useQueryClient();
22361
+ const [couponCode, setCouponCode] = react.useState('');
22362
+ const { addCoupon, removeCoupon, isAddingCoupon, isRemovingCoupon, activeCouponsExist } = useUpdateCoupons({
22190
22363
  apiHost,
22191
22364
  token,
22192
- });
22193
- const queryClient = reactQuery.useQueryClient();
22194
- // Queries
22195
- const { data: taxationRequiredAccountFields, isLoading: isLoadingTaxationRequiredAccountFields } = reactQuery.useQuery({
22196
- queryKey: ['getTaxationRequiredAccountFields', token],
22197
- queryFn: () => getTaxationRequiredAccountFields({ apiHost, token }),
22198
- enabled: Boolean(quote),
22199
- staleTime: 0,
22200
- });
22201
- const { data: account, isLoading: isLoadingAccount } = reactQuery.useQuery({
22202
- queryKey: ['account', quote === null || quote === void 0 ? void 0 : quote.accountId],
22203
- queryFn: () => (quote === null || quote === void 0 ? void 0 : quote.accountId) &&
22204
- common.getAccount({ id: quote.accountId, apiHost, token, componentsVersion: PACKAGE_VERSION }),
22205
- enabled: Boolean(quote === null || quote === void 0 ? void 0 : quote.accountId) && ((taxationRequiredAccountFields === null || taxationRequiredAccountFields === void 0 ? void 0 : taxationRequiredAccountFields.length) || 0) > 0,
22206
- });
22207
- async function recalculateTaxes() {
22208
- if (quote) {
22209
- if (!quote.id)
22365
+ 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,
22366
+ onCouponAdded: () => {
22367
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id))
22210
22368
  throw new Error('Quote ID is required');
22211
- const updatedQuote = await quoteRecalculateTaxes({
22212
- quoteId: quote.id,
22213
- apiHost,
22214
- token,
22215
- });
22216
- if (updatedQuote) {
22217
- const quoteKey = queryKeyFactory.createObjectKey({
22218
- id: updatedQuote.id,
22219
- objectName: 'editingQuote',
22220
- token,
22221
- });
22222
- queryClient.setQueryData(quoteKey, updatedQuote);
22223
- }
22224
- }
22225
- return {};
22226
- }
22227
- const recalculateTaxesEnabled = Boolean(quote) &&
22228
- open &&
22229
- hasTaxPlugin &&
22230
- !taxationRequiredAccountFields &&
22231
- !isLoadingTaxationRequiredAccountFields &&
22232
- !isUpdatingQuote;
22233
- reactQuery.useQuery({
22234
- queryKey: queryKeyFactory.createQuoteTaxCalculateKey({
22235
- id: (_a = quote === null || quote === void 0 ? void 0 : quote.id) !== null && _a !== void 0 ? _a : undefined,
22236
- token,
22237
- }),
22238
- queryFn: recalculateTaxes,
22239
- // Recalculate taxes if the quote is open, has a tax plugin, and the taxation required account fields are not required
22240
- enabled: recalculateTaxesEnabled,
22241
- staleTime: 0,
22242
- });
22243
- if (!open || isLoadingTaxationRequiredAccountFields || isLoadingAccount)
22244
- return null;
22245
- return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-flex-col bunny-fixed bunny-top-0 bunny-left-0 bunny-right-0 bunny-bottom-0 bunny-bg-slate-50
22246
- bunny-overflow-auto bunny-height-full`, style: {
22247
- zIndex: 1001,
22248
- }, children: jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-grow bunny-pt-4 ${isMobile ? 'bunny-pb-4' : 'bunny-pb-8'} bunny-content-container`, children: [jsxRuntime.jsx("div", { className: "bunny-flex bunny-justify-end bunny-w-full bunny-pr-4", children: jsxRuntime.jsx(icons.CloseOutlined, { className: "bunny-text-base bunny-shadow-padding-xb", onClick: onCancel }) }), jsxRuntime.jsxs("div", { className: `bunny-flex bunny-justify-end bunny-pt-4 bunny-gap-4 ${isMobile ? 'bunny-flex-col' : 'bunny-shadow-padding-xb'}`, children: [((invoice === null || invoice === void 0 ? void 0 : invoice.html) || ((_b = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _b === void 0 ? void 0 : _b.html)) && (jsxRuntime.jsx(InvoiceQuoteView, { html: invoice ? invoice.html : (_d = (_c = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _c === void 0 ? void 0 : _c.html) !== null && _d !== void 0 ? _d : '' })), !isMobile && ((invoice === null || invoice === void 0 ? void 0 : invoice.html) || ((_e = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _e === void 0 ? void 0 : _e.html)) && (jsxRuntime.jsx(antd.Divider, { className: "bunny-h-full", type: "vertical" })), invoice ? (jsxRuntime.jsx("div", { className: "bunny-w-full bunny-pt-12", children: jsxRuntime.jsx(PaymentForm, { onPaymentSuccess: onSuccess, invoice: invoice }) })) : quote ? (jsxRuntime.jsx(QuoteCheckout, { account: account, onFail: error => {
22249
- onFail(error);
22250
- }, onSuccess: onSuccess, quote: quote, taxationRequiredAccountFields: taxationRequiredAccountFields, token: token, onRecalculateTaxes: async () => {
22251
- if (recalculateTaxesEnabled) {
22252
- await recalculateTaxes();
22253
- }
22254
- } })) : (jsxRuntime.jsx(PaymentForm, { onPaymentSuccess: onSuccess }))] }), jsxRuntime.jsx(Footer, { className: "bunny-px-12" })] }) }));
22255
- };
22256
-
22257
- const QuoteContext = react.createContext({});
22258
-
22259
- const { Text: Text$n } = antd.Typography;
22260
- const CheckoutBarInput = ({ disabled, priceListCharge, quantity, onQuantityChanged, }) => {
22261
- var _a;
22262
- const [isTooltipOpen, setIsTooltipOpen] = react.useState(false);
22263
- const isMobile = common.useIsMobile();
22264
- react.useEffect(() => {
22265
- setTimeout(() => {
22266
- setIsTooltipOpen(true);
22267
- }, 1000);
22268
- setTimeout(() => {
22269
- setIsTooltipOpen(false);
22270
- }, 6000);
22271
- }, []);
22272
- return (jsxRuntime.jsxs(Text$n, { className: `bunny-flex bunny-items-center bunny-gap-2 ${isMobile ? 'bunny-justify-between' : ''}`, children: [jsxRuntime.jsx(QuantityLabel, { activeCharge: priceListCharge }), jsxRuntime.jsx(antd.Tooltip, { onOpenChange: setIsTooltipOpen, open: isTooltipOpen, title: "Change quantity here", styles: {
22273
- body: {
22274
- paddingTop: '0.75rem',
22275
- paddingBottom: '0.75rem',
22276
- },
22277
- }, children: jsxRuntime.jsx(antd.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 => {
22278
- onQuantityChanged(Number(e.target.value));
22279
- }, 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 }) })] }));
22280
- };
22281
- const QuantityLabel = ({ activeCharge }) => {
22282
- const chargeName = activeCharge.name;
22283
- return (jsxRuntime.jsx(Text$n, { className: "bunny-text-slate-500 bunny-font-medium bunny-text-nowrap", style: { fontSize: '11px' }, children: chargeName.toUpperCase() }));
22284
- };
22285
-
22286
- const periodMonthsConverter = (period) => {
22287
- if (period === 0)
22288
- return graphql.scalar('BillingPeriod', 'ONCE');
22289
- else if (period === 1)
22290
- return graphql.scalar('BillingPeriod', 'MONTHLY');
22291
- else if (period === 3)
22292
- return graphql.scalar('BillingPeriod', 'QUARTERLY');
22293
- else if (period === 6)
22294
- return graphql.scalar('BillingPeriod', 'SEMI_ANNUAL');
22295
- else if (period === 12)
22296
- return graphql.scalar('BillingPeriod', 'ANNUAL');
22297
- else
22298
- return null;
22299
- };
22300
- const billingPeriodConverter = (period) => {
22301
- if (period === graphql.scalar('BillingPeriod', 'ONCE'))
22302
- return 0;
22303
- else if (period === graphql.scalar('BillingPeriod', 'MONTHLY'))
22304
- return 1;
22305
- else if (period === graphql.scalar('BillingPeriod', 'QUARTERLY'))
22306
- return 3;
22307
- else if (period === graphql.scalar('BillingPeriod', 'SEMI_ANNUAL'))
22308
- return 6;
22309
- else
22310
- return 12;
22311
- };
22312
-
22313
- function getAddonsForBillingPeriod(billingPeriod, addonPlans) {
22314
- const flattenedPriceLists = addonPlans.flatMap(addonPlan => addonPlan.priceLists);
22315
- return flattenedPriceLists.filter(priceList => priceList.periodMonths === billingPeriodConverter(billingPeriod));
22316
- }
22317
-
22318
- const hasUnpurchasedAddonPriceLists_PlanFragment = t(`
22319
- fragment hasUnpurchasedAddonPriceLists_PlanFragment on Plan {
22320
- priceLists {
22321
- id
22322
- isVisible
22323
- periodMonths
22324
- }
22325
- }
22326
- `);
22327
- function hasUnpurchasedAddonPriceLists(maskedPriceListAddonPlans, currentSubscription, billingPeriod) {
22328
- // Read fragments
22329
- const priceListAddonPlans = maskedPriceListAddonPlans.map(maskedAddonPlan => readFragment(hasUnpurchasedAddonPriceLists_PlanFragment, maskedAddonPlan));
22330
- const addonPriceLists = getAddonsForBillingPeriod(billingPeriod, priceListAddonPlans).filter(priceList => priceList.isVisible);
22331
- const unpurchasedAddonPriceLists = addonPriceLists === null || addonPriceLists === void 0 ? void 0 : addonPriceLists.filter(addonPriceList => {
22332
- var _a;
22333
- 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));
22334
- });
22335
- return unpurchasedAddonPriceLists.length > 0;
22336
- }
22337
-
22338
- const canSubscriptionUpgradeFromTrial = (subscription) => {
22339
- var _a;
22340
- return (((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL') &&
22341
- subscription.plan.selfServiceBuy) ||
22342
- false;
22343
- };
22344
- const canSubscriptionUpgradeFromTrialExpired = (subscription) => {
22345
- var _a;
22346
- return (((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED') &&
22347
- subscription.plan.selfServiceBuy) ||
22348
- false;
22349
- };
22350
- const isSubscriptionNotActive = (subscription) => {
22351
- var _a, _b, _c;
22352
- return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'EXPIRED') ||
22353
- ((_b = subscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === t.scalar('SubscriptionState', 'CANCELED') ||
22354
- ((_c = subscription.state) === null || _c === void 0 ? void 0 : _c.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED');
22355
- };
22356
- const isSubscriptionActiveOrPending = (subscription) => {
22357
- var _a, _b;
22358
- return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'ACTIVE') ||
22359
- ((_b = subscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === t.scalar('SubscriptionState', 'PENDING');
22360
- };
22361
- const isSubscriptionTrial = (subscription) => { var _a; return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL'); };
22362
- const isSubscriptionTrialExpired = (subscription) => { var _a; return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED'); };
22363
- // Helper function to check if charge is a discount
22364
- const isDiscount$1 = (kind) => kind === common.QuoteChangeKind.DISCOUNT || kind === common.QuoteChangeKind.FREE_PERIOD_DISCOUNT;
22365
- const hasPriceTiers = (charge) => {
22366
- var _a;
22367
- return Boolean((_a = charge === null || charge === void 0 ? void 0 : charge.priceTiers) === null || _a === void 0 ? void 0 : _a.length);
22368
- };
22369
-
22370
- const removeHTMLTagsRegex = /<br>(?=(?:\s*<[^>]*>)*$)|(<br>)|<[^>]*>/gi;
22371
- // Description is a string that can contain HTML tags. We want to remove all HTML tags except <br> tags.
22372
- const createPlanDescription = (planDescription) => {
22373
- return (planDescription || '').replace(removeHTMLTagsRegex, (_, y) => (y ? ' & ' : ''));
22374
- };
22375
- const getActivePlanPriceData = (priceList, selectedPriceList) => {
22376
- if (!priceList) {
22377
- return;
22378
- }
22379
- // If a period option is selected, return the charge that matches the selected period option
22380
- let activeBillingPLCharge;
22381
- // Default to first price list charge
22382
- let lowestPLCharge;
22383
- // Find the lowest price list charge with a billing period that matches the selected period option
22384
- if (priceList.id === (selectedPriceList === null || selectedPriceList === void 0 ? void 0 : selectedPriceList.id)) {
22385
- activeBillingPLCharge = priceList.charges[0];
22386
- }
22387
- for (let j = 0; j < priceList.charges.length; j++) {
22388
- const charge = priceList.charges[j];
22389
- if (charge.chargeType === common.ChargeType.USAGE || charge.featureAddon === true)
22390
- continue;
22391
- if (activeBillingPLCharge) {
22392
- // If we already found a charge with the same billing period check if this charge is lower
22393
- if (charge.basePrice < activeBillingPLCharge.basePrice &&
22394
- charge.billingPeriod === (activeBillingPLCharge === null || activeBillingPLCharge === void 0 ? void 0 : activeBillingPLCharge.billingPeriod)) {
22395
- activeBillingPLCharge = charge;
22396
- }
22397
- }
22398
- // If a period option is selected, only return the charge if it matches the selected period option
22399
- else if (selectedPriceList &&
22400
- charge.billingPeriod === periodMonthsConverter(selectedPriceList.periodMonths)) {
22401
- activeBillingPLCharge = charge;
22402
- }
22403
- // Otherwise, return the lowest price list charge
22404
- else if (charge.basePrice < ((lowestPLCharge === null || lowestPLCharge === void 0 ? void 0 : lowestPLCharge.basePrice) || -1)) {
22405
- lowestPLCharge = charge;
22406
- }
22407
- }
22408
- return {
22409
- activeCharge: activeBillingPLCharge || lowestPLCharge,
22410
- };
22411
- };
22412
- const showErrorNotification$2 = common.useErrorNotification();
22413
- const isPriceListDisabled = ({ priceList, upgradingSubscription, }) => {
22414
- const priceListAddonPlans = priceList === null || priceList === void 0 ? void 0 : priceList.plan.addonPlans;
22415
- if (!priceListAddonPlans) {
22416
- showErrorNotification$2('Price list addon plans are undefined');
22417
- return false;
22418
- }
22419
- const canPurchaseFeatureAddons = hasUnpurchasedFeatureAddons(priceList, upgradingSubscription);
22420
- const canPurchasePlanAddons = hasUnpurchasedAddonPriceLists(priceListAddonPlans, upgradingSubscription, periodMonthsConverter(priceList.periodMonths));
22421
- const existingSubscriptionInTrial = upgradingSubscription && canSubscriptionUpgradeFromTrial(upgradingSubscription);
22422
- const existingSubscriptionInTrialExpired = upgradingSubscription && canSubscriptionUpgradeFromTrialExpired(upgradingSubscription);
22423
- const isUpgradingSubscriptionPriceList = (upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.id) === priceList.id;
22424
- // When should priceList be disabled?
22425
- // if upgradingSubscription?.priceList.id === priceList.id
22426
- // AND the upgradingSubscription is not in trial
22427
- // AND cannot purchase feature addons
22428
- // AND cannot purchase add-on plans
22429
- // AND selfServiceBuy is false
22430
- // if upgradingSubscription?.priceList.id != priceList.id
22431
- // AND upgradingSubscription is expired trial
22432
- if (isUpgradingSubscriptionPriceList) {
22433
- return (!existingSubscriptionInTrial &&
22434
- !existingSubscriptionInTrialExpired &&
22435
- !canPurchaseFeatureAddons &&
22436
- !canPurchasePlanAddons);
22437
- }
22438
- else {
22439
- return false;
22369
+ queryClient.invalidateQueries({
22370
+ queryKey: common.QueryKeyFactory.default.createObjectKey({
22371
+ id: quote === null || quote === void 0 ? void 0 : quote.id,
22372
+ objectName: 'editingQuote',
22373
+ token,
22374
+ }),
22375
+ });
22376
+ showSuccessNotification$1('Coupon applied');
22377
+ onRecalculateTaxes();
22378
+ setCouponCode('');
22379
+ },
22380
+ onCouponRemoved: () => {
22381
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id))
22382
+ throw new Error('Quote ID is required');
22383
+ queryClient.invalidateQueries({
22384
+ queryKey: common.QueryKeyFactory.default.createObjectKey({
22385
+ id: quote === null || quote === void 0 ? void 0 : quote.id,
22386
+ objectName: 'editingQuote',
22387
+ token,
22388
+ }),
22389
+ });
22390
+ showSuccessNotification$1('Coupon removed');
22391
+ onRecalculateTaxes();
22392
+ },
22393
+ });
22394
+ 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'); });
22395
+ const checkoutMutation = reactQuery.useMutation({
22396
+ mutationFn: async () => {
22397
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id))
22398
+ throw new Error('Quote ID is required');
22399
+ if (paymentRequired)
22400
+ throw new Error('Payment is required');
22401
+ return await checkout({ quoteId: quote.id, token, apiHost });
22402
+ },
22403
+ onSuccess,
22404
+ onError: onFail,
22405
+ });
22406
+ async function handleCheckoutNoPayment() {
22407
+ setIsSaving(true);
22408
+ checkoutMutation.mutate();
22409
+ setIsSaving(false);
22440
22410
  }
22411
+ if (taxationRequiredAccountFields)
22412
+ return (jsxRuntime.jsx(PaymentFormWrapper, { setMaxHeight: false, children: jsxRuntime.jsx(TaxationForm, { account: account, accountId: quote.accountId }) }));
22413
+ return (jsxRuntime.jsx(PaymentFormWrapper, { setMaxHeight: false, children: paymentRequired ? (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-gap-2 bunny-w-full", children: [jsxRuntime.jsx(PaymentForm, { onPaymentSuccess: onSuccess, quote: quote }), (couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.length) === 0 ? (jsxRuntime.jsx(jsxRuntime.Fragment, { children: upgradingSubscription &&
22414
+ shouldShowCouponEditor(quote, activeCouponsExist, upgradingSubscription) && (jsxRuntime.jsx(CouponEditor, { className: "bunny-px-4 bunny-pt-1", quote: quote, onAddCoupon: addCoupon, isAddingCoupon: isAddingCoupon, couponCode: couponCode, setCouponCode: setCouponCode })) })) : (jsxRuntime.jsx(antd.Button, { type: "link", loading: isRemovingCoupon, onClick: () => {
22415
+ couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.forEach(couponCharge => {
22416
+ var _a;
22417
+ const couponCode = (_a = couponCharge === null || couponCharge === void 0 ? void 0 : couponCharge.coupon) === null || _a === void 0 ? void 0 : _a.couponCode;
22418
+ if (couponCode) {
22419
+ removeCoupon(couponCode);
22420
+ }
22421
+ });
22422
+ }, children: "Remove coupon(s)" }))] })) : (jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-2 bunny-px-4 ${isMobile ? 'bunny-shadow-padding-x' : ''}`, children: [jsxRuntime.jsx(antd.Button, { onClick: handleCheckoutNoPayment, type: "primary", children: isSaving ? 'Processing...' : 'Complete order' }), jsxRuntime.jsx(Text$n, { className: "bunny-text-xs bunny-text-slate-500", children: "No payment is required" })] })) }));
22441
22423
  };
22442
-
22443
- const CheckoutButton = ({ checkoutButtonDisabled, onClickCheckout, loading, tooltipText, }) => {
22424
+ const PaymentFormWrapper = ({ children, setMaxHeight, className, }) => {
22444
22425
  const isMobile = common.useIsMobile();
22445
- const TooltipWrapper = ({ children }) => {
22446
- if (tooltipText) {
22447
- return jsxRuntime.jsx(antd.Tooltip, { title: tooltipText, children: children });
22448
- }
22449
- return jsxRuntime.jsx("div", { children: children });
22450
- };
22451
- return (jsxRuntime.jsx(TooltipWrapper, { children: jsxRuntime.jsx(antd.Button, { className: isMobile ? 'w-full' : '', disabled: checkoutButtonDisabled, onClick: onClickCheckout, size: isMobile ? 'large' : 'middle', type: "primary", loading: loading, children: "Proceed to checkout" }) }));
22426
+ return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-w-full bunny-flex-col bunny-gap-6 ${isMobile ? 'bunny-shadow-padding-xb' : ''} ${className}`, style: {
22427
+ ...(isMobile
22428
+ ? setMaxHeight
22429
+ ? { maxHeight: '60vh' }
22430
+ : {}
22431
+ : {
22432
+ width: '100%',
22433
+ maxWidth: '400px',
22434
+ }),
22435
+ }, children: children }));
22452
22436
  };
22453
22437
 
22454
- const CheckoutPrice = ({ isUsage, quote, selectedPriceList, }) => {
22438
+ const queryKeyFactory = common.QueryKeyFactory.default;
22439
+ const Checkout_QuoteFragment = t(`
22440
+ fragment Checkout_QuoteFragment on Quote {
22441
+ id
22442
+ accountId
22443
+ formattedQuote {
22444
+ html
22445
+ }
22446
+ ...QuoteCheckout_QuoteFragment
22447
+ }
22448
+ `, [QuoteCheckout_QuoteFragment]);
22449
+ const Checkout = ({ onCancel, onSuccess, onFail, onRecalculateTaxes, invoice, open, quote: maskedQuote, isUpdatingQuote, }) => {
22450
+ var _a, _b, _c, _d, _e;
22451
+ const { apiHost } = react.useContext(BunnyContext);
22455
22452
  const isMobile = common.useIsMobile();
22456
- if (!isUsage && (!selectedPriceList || (quote === null || quote === void 0 ? void 0 : quote.periodAmount) === undefined))
22453
+ const token = useToken();
22454
+ // Read fragments
22455
+ const quote = readFragment(Checkout_QuoteFragment, maskedQuote);
22456
+ const hasTaxPlugin = useHasTaxPlugin({
22457
+ apiHost,
22458
+ token,
22459
+ });
22460
+ // Queries
22461
+ const { data: taxationRequiredAccountFields, isLoading: isLoadingTaxationRequiredAccountFields } = reactQuery.useQuery({
22462
+ queryKey: ['getTaxationRequiredAccountFields', token],
22463
+ queryFn: () => getTaxationRequiredAccountFields({ apiHost, token }),
22464
+ enabled: Boolean(quote),
22465
+ staleTime: 0,
22466
+ });
22467
+ const { data: account, isLoading: isLoadingAccount } = reactQuery.useQuery({
22468
+ queryKey: ['account', quote === null || quote === void 0 ? void 0 : quote.accountId],
22469
+ queryFn: () => (quote === null || quote === void 0 ? void 0 : quote.accountId) &&
22470
+ common.getAccount({ id: quote.accountId, apiHost, token, componentsVersion: PACKAGE_VERSION }),
22471
+ enabled: Boolean(quote === null || quote === void 0 ? void 0 : quote.accountId) && ((taxationRequiredAccountFields === null || taxationRequiredAccountFields === void 0 ? void 0 : taxationRequiredAccountFields.length) || 0) > 0,
22472
+ });
22473
+ // Use onRecalculateTaxes callback because parents need to define recalculateTaxes to get and set the right quote data they need
22474
+ async function recalculateTaxes() {
22475
+ if (quote) {
22476
+ if (!quote.id)
22477
+ throw new Error('Quote ID is required');
22478
+ onRecalculateTaxes(quote.id);
22479
+ }
22480
+ return {};
22481
+ }
22482
+ const recalculateTaxesEnabled = Boolean(quote) &&
22483
+ open &&
22484
+ hasTaxPlugin &&
22485
+ !taxationRequiredAccountFields &&
22486
+ !isLoadingTaxationRequiredAccountFields &&
22487
+ !isUpdatingQuote;
22488
+ reactQuery.useQuery({
22489
+ queryKey: queryKeyFactory.createQuoteTaxCalculateKey({
22490
+ id: (_a = quote === null || quote === void 0 ? void 0 : quote.id) !== null && _a !== void 0 ? _a : undefined,
22491
+ token,
22492
+ }),
22493
+ queryFn: recalculateTaxes,
22494
+ // Recalculate taxes if the quote is open, has a tax plugin, and the taxation required account fields are not required
22495
+ enabled: recalculateTaxesEnabled,
22496
+ staleTime: 0,
22497
+ });
22498
+ if (!open || isLoadingTaxationRequiredAccountFields || isLoadingAccount)
22457
22499
  return null;
22458
- const convertedPeriodMonths = periodMonthsConverter(selectedPriceList.periodMonths);
22459
- const periodLabel = convertedPeriodMonths ? common.PERIOD_LABELS[convertedPeriodMonths] : 'undefined';
22460
- return (jsxRuntime.jsx("div", { className: `bunny-font-medium ${isMobile ? 'bunny-text-2xl' : ''}`, children: isUsage
22461
- ? 'Usage based pricing'
22462
- : selectedPriceList && (quote === null || quote === void 0 ? void 0 : quote.periodAmount) !== undefined
22463
- ? `${common.formatCurrency(quote.periodAmount, selectedPriceList === null || selectedPriceList === void 0 ? void 0 : selectedPriceList.currencyId, 0)} / ${periodLabel}`
22464
- : '' }));
22500
+ return (jsxRuntime.jsx("div", { className: `bunny-flex bunny-flex-col bunny-fixed bunny-top-0 bunny-left-0 bunny-right-0 bunny-bottom-0 bunny-bg-slate-50
22501
+ bunny-overflow-auto bunny-height-full`, style: {
22502
+ zIndex: 1001,
22503
+ }, children: jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-grow bunny-pt-4 ${isMobile ? 'bunny-pb-4' : 'bunny-pb-8'} bunny-content-container`, children: [jsxRuntime.jsx("div", { className: "bunny-flex bunny-justify-end bunny-w-full bunny-pr-4", children: jsxRuntime.jsx(icons.CloseOutlined, { className: "bunny-text-base bunny-shadow-padding-xb", onClick: onCancel }) }), jsxRuntime.jsxs("div", { className: `bunny-flex bunny-justify-end bunny-pt-4 bunny-gap-4 ${isMobile ? 'bunny-flex-col' : 'bunny-shadow-padding-xb'}`, children: [((invoice === null || invoice === void 0 ? void 0 : invoice.html) || ((_b = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _b === void 0 ? void 0 : _b.html)) && (jsxRuntime.jsx(InvoiceQuoteView, { html: invoice ? invoice.html : (_d = (_c = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _c === void 0 ? void 0 : _c.html) !== null && _d !== void 0 ? _d : '' })), !isMobile && ((invoice === null || invoice === void 0 ? void 0 : invoice.html) || ((_e = quote === null || quote === void 0 ? void 0 : quote.formattedQuote) === null || _e === void 0 ? void 0 : _e.html)) && (jsxRuntime.jsx(antd.Divider, { className: "bunny-h-full", type: "vertical" })), invoice ? (jsxRuntime.jsx("div", { className: "bunny-w-full bunny-pt-12", children: jsxRuntime.jsx(PaymentForm, { onPaymentSuccess: onSuccess, invoice: invoice }) })) : quote ? (jsxRuntime.jsx(QuoteCheckout, { account: account, onFail: error => {
22504
+ onFail(error);
22505
+ }, onSuccess: onSuccess, quote: quote, taxationRequiredAccountFields: taxationRequiredAccountFields, token: token, onRecalculateTaxes: async () => {
22506
+ if (recalculateTaxesEnabled) {
22507
+ await recalculateTaxes();
22508
+ }
22509
+ } })) : (jsxRuntime.jsx(PaymentForm, { onPaymentSuccess: onSuccess }))] }), jsxRuntime.jsx(Footer, { className: "bunny-px-12" })] }) }));
22465
22510
  };
22466
22511
 
22512
+ function canEditChargeQuantity(charge) {
22513
+ if (!charge)
22514
+ return false;
22515
+ if (charge.chargeType === graphql.scalar('ChargeType', 'USAGE'))
22516
+ return false;
22517
+ if (charge.pricingModel === graphql.scalar('PricingModel', 'FLAT'))
22518
+ return false;
22519
+ return true;
22520
+ }
22521
+
22467
22522
  const { Text: Text$m } = antd.Typography;
22468
- const CheckoutBarSummarySection = ({ open, selectedPriceList, onClickCheckout, }) => {
22523
+ const CheckoutBarInput = ({ disabled, priceListCharge, quantity, onQuantityChanged, }) => {
22469
22524
  var _a;
22470
- // Context
22471
- const { quote: quoteData, isQuotePending, isUpdatingQuote } = react.useContext(QuoteContext);
22472
- const quote = quoteData;
22473
- const { upgradingSubscription, isInPreviewMode } = react.useContext(SubscriptionsContext);
22474
- // Hooks
22475
- const token = useToken();
22476
- const { paymentPlugins } = usePaymentPlugins(undefined);
22477
- const queryClient = reactQuery.useQueryClient();
22525
+ const [isTooltipOpen, setIsTooltipOpen] = react.useState(false);
22478
22526
  const isMobile = common.useIsMobile();
22479
- // Derived state
22480
- const isFetching = queryClient.isFetching({
22481
- queryKey: common.QueryKeyFactory.default.planChangeOptionsKey({
22482
- subscriptionId: upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.id,
22483
- token,
22484
- }),
22485
- });
22486
- // When should checkout button be disabled?
22487
- const isUpdatingCharges = (quote === null || quote === void 0 ? void 0 : quote.quoteChanges.some(qc => qc.kind === 'UPDATE' && qc.charges.length > 0)) || false;
22488
- const isUpgradingSubscription = selectedPriceList.id !== (upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.id);
22489
- const disableCheckoutButton = Boolean(!selectedPriceList || isFetching || !(isUpgradingSubscription || isUpdatingCharges) || open);
22490
- const checkoutButtonDisabled = (quote === null || quote === void 0 ? void 0 : quote.amountDue) && (quote === null || quote === void 0 ? void 0 : quote.amountDue) > 0 ? false : disableCheckoutButton;
22491
- const activeCharge = (_a = getActivePlanPriceData(selectedPriceList, selectedPriceList)) === null || _a === void 0 ? void 0 : _a.activeCharge;
22492
- const isUsage = (activeCharge === null || activeCharge === void 0 ? void 0 : activeCharge.chargeType) === common.ChargeType.USAGE;
22493
- const hasPaymentPlugins = Boolean(paymentPlugins === null || paymentPlugins === void 0 ? void 0 : paymentPlugins.length);
22494
- return (jsxRuntime.jsxs(Text$m, { className: `bunny-flex bunny-items-center bunny-gap-4 ${isMobile ? 'bunny-flex-col' : ''}`, children: [quote && (jsxRuntime.jsxs("div", { className: `bunny-flex ${isMobile ? 'items-center justify-between w-full' : 'flex-col'}`, children: [jsxRuntime.jsx("div", { className: "bunny-text-slate-500 bunny-font-medium bunny-text-right", style: { fontSize: '11px' }, children: "TOTAL" }), jsxRuntime.jsx(CheckoutPrice, { isUsage: isUsage, quote: quote, selectedPriceList: selectedPriceList })] })), jsxRuntime.jsx(CheckoutButton, { checkoutButtonDisabled: checkoutButtonDisabled || !hasPaymentPlugins || isInPreviewMode, onClickCheckout: onClickCheckout, loading: isQuotePending || isUpdatingQuote, tooltipText: isInPreviewMode
22495
- ? 'Checkout is disabled in preview mode'
22496
- : !hasPaymentPlugins
22497
- ? 'Cannot checkout. No valid payment plugins found. Please contact your administrator.'
22498
- : undefined })] }));
22527
+ react.useEffect(() => {
22528
+ setTimeout(() => {
22529
+ setIsTooltipOpen(true);
22530
+ }, 1000);
22531
+ setTimeout(() => {
22532
+ setIsTooltipOpen(false);
22533
+ }, 6000);
22534
+ }, []);
22535
+ return (jsxRuntime.jsxs(Text$m, { className: `bunny-flex bunny-items-center bunny-gap-2 ${isMobile ? 'bunny-justify-between' : ''}`, children: [jsxRuntime.jsx(QuantityLabel, { activeCharge: priceListCharge }), jsxRuntime.jsx(antd.Tooltip, { onOpenChange: setIsTooltipOpen, open: isTooltipOpen, title: "Change quantity here", styles: {
22536
+ body: {
22537
+ paddingTop: '0.75rem',
22538
+ paddingBottom: '0.75rem',
22539
+ },
22540
+ }, children: jsxRuntime.jsx(antd.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 => {
22541
+ onQuantityChanged(Number(e.target.value));
22542
+ }, 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 }) })] }));
22543
+ };
22544
+ const QuantityLabel = ({ activeCharge }) => {
22545
+ const chargeName = activeCharge.name;
22546
+ return (jsxRuntime.jsx(Text$m, { className: "bunny-text-slate-500 bunny-font-medium bunny-text-nowrap", style: { fontSize: '11px' }, children: chargeName.toUpperCase() }));
22499
22547
  };
22500
22548
 
22501
22549
  const PlanPickerCheckoutBar_QuoteFragment = t(`
@@ -22515,8 +22563,8 @@ const PlanPickerCheckoutBar_QuoteFragment = t(`
22515
22563
  `, [Checkout_QuoteFragment]);
22516
22564
  const PlanPickerCheckoutBar = ({ selectedPriceList, handlePortalErrors, onCheckoutSuccess, }) => {
22517
22565
  // Context
22518
- const { shadow, upgradingSubscription } = react.useContext(SubscriptionsContext);
22519
- const { quote: maskedQuote, onChangeQuantity, getFeatureQuantity, isFeatureAddonsLoading, isUpdatingQuote, } = react.useContext(QuoteContext);
22566
+ const { shadow } = react.useContext(SubscriptionsContext);
22567
+ const { quote: maskedQuote, onChangeQuantity, getFeatureQuantity, onRecalculateTaxes, isFeatureAddonsLoading, isUpdatingQuote, } = react.useContext(QuoteContext);
22520
22568
  // Read fragments
22521
22569
  const quote = readFragment(PlanPickerCheckoutBar_QuoteFragment, maskedQuote);
22522
22570
  // Local state
@@ -22564,9 +22612,6 @@ const PlanPickerCheckoutBar = ({ selectedPriceList, handlePortalErrors, onChecko
22564
22612
  const isFeatureAddon = charge.featureAddon;
22565
22613
  const quantity = getFeatureQuantity((_d = charge.feature) === null || _d === void 0 ? void 0 : _d.id, charge.id);
22566
22614
  const maybeIsChargeLoading = isFeatureAddon && isFeatureAddonsLoading;
22567
- const showInput = selectedPriceList.id !== (upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.id);
22568
- if (!isFeatureAddon && !showInput)
22569
- return null;
22570
22615
  if (!quantity)
22571
22616
  return null;
22572
22617
  // if charge is a feature addon, and a corresponding quote charge is not found in quote, return null
@@ -22577,9 +22622,40 @@ const PlanPickerCheckoutBar = ({ selectedPriceList, handlePortalErrors, onChecko
22577
22622
  return (jsxRuntime.jsx(CheckoutBarInput, { disabled: isDisabled, priceListCharge: charge, quantity: quantity, onQuantityChanged: quantity => {
22578
22623
  onChangeQuantity(charge.id, quantity);
22579
22624
  } }, index));
22580
- }) }), jsxRuntime.jsx(CheckoutBarSummarySection, { onClickCheckout: () => setPayModalVisible(true), open: payModalVisible, selectedPriceList: selectedPriceList }), jsxRuntime.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 })] }));
22625
+ }) }), jsxRuntime.jsx(CheckoutBarSummarySection, { onClickCheckout: () => setPayModalVisible(true), selectedPriceList: selectedPriceList }), jsxRuntime.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 })] }));
22581
22626
  };
22582
22627
 
22628
+ const useQuoteUpdateFeatureAddon_QuoteFragment = t(`
22629
+ fragment useQuoteUpdateFeatureAddon_QuoteFragment on Quote {
22630
+ id
22631
+ startDate
22632
+ }
22633
+ `);
22634
+
22635
+ const FeatureAddonRow_QuoteFragment = t(`
22636
+ fragment FeatureAddonRow_QuoteFragment on Quote {
22637
+ ...useQuoteUpdateFeatureAddon_QuoteFragment
22638
+ }
22639
+ `, [useQuoteUpdateFeatureAddon_QuoteFragment]);
22640
+
22641
+ const useToggleAddonPlan_QuoteFragment = t(`
22642
+ fragment useToggleAddonPlan_QuoteFragment on Quote {
22643
+ quoteChanges {
22644
+ priceList {
22645
+ id
22646
+ }
22647
+ id
22648
+ }
22649
+ id
22650
+ }
22651
+ `);
22652
+
22653
+ const AddonPlanRow_QuoteFragment = t(`
22654
+ fragment AddonPlanRow_QuoteFragment on Quote {
22655
+ ...useToggleAddonPlan_QuoteFragment
22656
+ }
22657
+ `, [useToggleAddonPlan_QuoteFragment]);
22658
+
22583
22659
  /**
22584
22660
  * Central quote fragment for QuoteProvider context.
22585
22661
  *
@@ -22597,6 +22673,7 @@ const QuoteContext_QuoteFragment = t(`
22597
22673
  id
22598
22674
  currencyId
22599
22675
  amountDue
22676
+ startDate
22600
22677
  quoteChanges {
22601
22678
  id
22602
22679
  kind
@@ -22620,75 +22697,17 @@ const QuoteContext_QuoteFragment = t(`
22620
22697
  }
22621
22698
  }
22622
22699
  ...PlanPickerCheckoutBar_QuoteFragment
22623
- }
22624
- `, [QuoteFields_QuoteFragment, PlanPickerCheckoutBar_QuoteFragment]);
22625
-
22626
- // Deprecated: Keeping this for now because its used in many places
22627
- const QUOTE_FIELDS = (removeFormattedQuoteField) => `
22628
- fragment QuoteFields on Quote {
22629
- accountId
22630
- amount
22631
- amountDue
22632
- smallUnitAmountDue
22633
- currencyId
22634
- ${removeFormattedQuoteField ? '' : `formattedQuote { html }`}
22635
- id
22636
- payableId
22637
- periodAmount
22638
- subtotal
22639
- taxAmount
22640
- startDate
22641
- amountsByPeriod {
22642
- amount
22643
- startDate
22644
- }
22645
- kind
22646
- quoteChanges {
22647
- currencyId
22648
- id
22649
- kind
22650
- charges {
22651
- subtotal
22652
- amountsByPeriod {
22653
- amount
22654
- startDate
22655
- }
22656
- amount
22657
- billingPeriod
22658
- currencyId
22659
- feature {
22660
- id
22661
- unitName
22662
- }
22663
- id
22664
- name
22665
- priceListCharge {
22666
- id
22667
- quantityMax
22668
- quantityMin
22669
- selfServiceQuantity
22670
- }
22671
- priceList {
22672
- id
22673
- }
22674
- coupon {
22675
- couponCode
22676
- }
22677
- quantity
22678
- kind
22679
- }
22680
- priceList {
22681
- id
22682
- plan {
22683
- name
22684
- }
22685
- product {
22686
- name
22687
- }
22688
- }
22689
- }
22690
- }
22691
- `;
22700
+ ...CheckoutBarSummarySection_QuoteFragment
22701
+ ...AddonPlanRow_QuoteFragment
22702
+ ...FeatureAddonRow_QuoteFragment
22703
+ }
22704
+ `, [
22705
+ PlanPickerCheckoutBar_QuoteFragment,
22706
+ CheckoutBarSummarySection_QuoteFragment,
22707
+ AddonPlanRow_QuoteFragment,
22708
+ FeatureAddonRow_QuoteFragment,
22709
+ ]);
22710
+
22692
22711
  const FormattedQuoteField_QuoteFragment = t(`
22693
22712
  fragment FormattedQuoteField_QuoteFragment on Quote {
22694
22713
  formattedQuote {
@@ -22696,7 +22715,7 @@ const FormattedQuoteField_QuoteFragment = t(`
22696
22715
  }
22697
22716
  }
22698
22717
  `);
22699
- const query$3 = t(`
22718
+ const query$5 = t(`
22700
22719
  query quote($id: ID, $removeFormattedQuoteField: Boolean!) {
22701
22720
  quote(id: $id) {
22702
22721
  ...QuoteContext_QuoteFragment
@@ -22705,7 +22724,7 @@ const query$3 = t(`
22705
22724
  }
22706
22725
  `, [QuoteContext_QuoteFragment, FormattedQuoteField_QuoteFragment]);
22707
22726
  const getQuote$1 = async ({ id, token, apiHost, removeFormattedQuoteField = false, }) => {
22708
- const response = await execute(query$3, { apiHost, token }, { id, removeFormattedQuoteField });
22727
+ const response = await execute(query$5, { apiHost, token }, { id, removeFormattedQuoteField });
22709
22728
  return response === null || response === void 0 ? void 0 : response.quote;
22710
22729
  };
22711
22730
 
@@ -22810,7 +22829,7 @@ function Signup({ companyName, priceListCode, returnUrl, couponCode, className,
22810
22829
  });
22811
22830
  const { mutate: recalculateTaxesMutation } = reactQuery.useMutation({
22812
22831
  mutationFn: (quoteId) => {
22813
- return quoteRecalculateTaxes({ token, apiHost, quoteId });
22832
+ return quoteRecalculateTaxes$2({ token, apiHost, quoteId });
22814
22833
  },
22815
22834
  onError: (error) => {
22816
22835
  if (!error[0].message.includes('Ensure that you have a taxation plugin')) {
@@ -22991,7 +23010,7 @@ const useQuoteQueryData = (quoteId) => {
22991
23010
  return data;
22992
23011
  };
22993
23012
 
22994
- const useSetQuoteQueryData = () => {
23013
+ const useSetQuoteQueryData$1 = () => {
22995
23014
  const token = useToken();
22996
23015
  const queryClient = reactQuery.useQueryClient();
22997
23016
  const setQuoteQueryData = (quoteId, quote) => {
@@ -23030,6 +23049,9 @@ const QuantityInput_QuoteFragment = t(`
23030
23049
  }
23031
23050
  `, []);
23032
23051
 
23052
+ const useQuoteIsLoadingState = (isLoading) => react.useState(isLoading !== null && isLoading !== void 0 ? isLoading : false);
23053
+ const [QuoteIsLoadingProvider, useQuoteIsLoading] = createStateContext(useQuoteIsLoadingState);
23054
+
23033
23055
  const QuoteChangeSummarySection_QuoteFragment = t(`
23034
23056
  fragment QuoteChangeSummarySection_QuoteFragment on Quote {
23035
23057
  id
@@ -23041,10 +23063,11 @@ const QuoteChangeSummarySection_QuoteFragment = t(`
23041
23063
  const QuoteChangeSummarySection = ({ openCheckout, errorUpdatingQuantity, }) => {
23042
23064
  const isMobile = common.useIsMobile();
23043
23065
  const [quoteId] = useQuoteId();
23066
+ const [isQuoteLoading] = useQuoteIsLoading();
23044
23067
  const maskedQuote = useQuoteQueryData(quoteId);
23045
23068
  const quote = readFragment(QuoteChangeSummarySection_QuoteFragment, maskedQuote);
23046
- const disabled = !quoteId || !quote || errorUpdatingQuantity;
23047
- return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-items-end", children: [quote && !disabled && (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-mb-8", children: [jsxRuntime.jsx("div", { className: "bunny-text-slate-500 bunny-text-right bunny-text-xs bunny-mb-2", children: "TOTAL" }), jsxRuntime.jsx("div", { className: `bunny-text-right ${isMobile ? 'bunny-text-2xl' : 'bunny-text-xl'}`, children: common.formatCurrency(getQuoteAmountDue(quote), (quote === null || quote === void 0 ? void 0 : quote.currencyId) || '') })] })), jsxRuntime.jsx("div", { className: `bunny-flex bunny-items-center bunny-justify-end ${isMobile ? 'bunny-w-full' : ''}`, children: jsxRuntime.jsx(antd.Button, { className: "bunny-w-full", onClick: openCheckout, disabled: disabled, size: isMobile ? 'large' : 'middle', type: "primary", children: "Proceed to checkout" }) })] }));
23069
+ const disabled = !quoteId || !quote || errorUpdatingQuantity || isQuoteLoading;
23070
+ return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-items-end", children: [quote && !disabled && (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-col bunny-mb-8", children: [jsxRuntime.jsx("div", { className: "bunny-text-slate-500 bunny-text-right bunny-text-xs bunny-mb-2", children: "TOTAL" }), jsxRuntime.jsx("div", { className: `bunny-text-right ${isMobile ? 'bunny-text-2xl' : 'bunny-text-xl'}`, children: common.formatCurrency(getQuoteAmountDue(quote), (quote === null || quote === void 0 ? void 0 : quote.currencyId) || '') })] })), jsxRuntime.jsx("div", { className: `bunny-flex bunny-items-center bunny-justify-end ${isMobile ? 'bunny-w-full' : ''}`, children: jsxRuntime.jsx(antd.Button, { className: "bunny-w-full", onClick: openCheckout, disabled: disabled, size: isMobile ? 'large' : 'middle', type: "primary", loading: isQuoteLoading, children: "Proceed to checkout" }) })] }));
23048
23071
  };
23049
23072
 
23050
23073
  const QuantityDrawer_QuoteFragment = t(`
@@ -23056,7 +23079,7 @@ const QuantityDrawer_QuoteFragment = t(`
23056
23079
  }
23057
23080
  `, [Checkout_QuoteFragment, QuantityInput_QuoteFragment, QuoteChangeSummarySection_QuoteFragment]);
23058
23081
 
23059
- const mutation$4 = t(`
23082
+ const mutation$c = t(`
23060
23083
  mutation QuoteChargeCreate(
23061
23084
  $quoteChangeId: ID!
23062
23085
  $startDate: ISO8601Date!
@@ -23091,11 +23114,11 @@ const mutation$4 = t(`
23091
23114
  `, [QuantityDrawer_QuoteFragment]);
23092
23115
  const quoteChargeCreate$1 = async ({ price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId, token, apiHost, }) => {
23093
23116
  var _a;
23094
- const response = await execute(mutation$4, { apiHost, token }, { price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId });
23117
+ const response = await execute(mutation$c, { apiHost, token }, { price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId });
23095
23118
  return (_a = response.quoteChargeCreate) === null || _a === void 0 ? void 0 : _a.quoteCharge;
23096
23119
  };
23097
23120
 
23098
- const mutation$3 = t(`
23121
+ const mutation$b = t(`
23099
23122
  mutation QuoteChargeUpdate($quoteChargeId: ID!, $quantity: Int) {
23100
23123
  quoteChargeUpdate(quoteChargeId: $quoteChargeId, quantity: $quantity) {
23101
23124
  quoteCharge {
@@ -23114,14 +23137,29 @@ const mutation$3 = t(`
23114
23137
  `, [QuantityDrawer_QuoteFragment]);
23115
23138
  const quoteChargeUpdate = async (quoteChargeId, quantity, apiHost, token) => {
23116
23139
  var _a, _b;
23117
- const response = await execute(mutation$3, { apiHost, token }, { quoteChargeId, quantity });
23140
+ const response = await execute(mutation$b, { apiHost, token }, { quoteChargeId, quantity });
23118
23141
  if ((_a = response.quoteChargeUpdate) === null || _a === void 0 ? void 0 : _a.errors) {
23119
23142
  throw new Error(response.quoteChargeUpdate.errors[0]);
23120
23143
  }
23121
23144
  return (_b = response.quoteChargeUpdate) === null || _b === void 0 ? void 0 : _b.quoteCharge;
23122
23145
  };
23123
23146
 
23124
- const mutation$2 = t(`
23147
+ const mutation$a = t(`
23148
+ mutation QuoteDelete($id: ID!) {
23149
+ quoteDelete(id: $id) {
23150
+ errors
23151
+ quote {
23152
+ id
23153
+ }
23154
+ }
23155
+ }
23156
+ `, []);
23157
+ const quoteDelete = async ({ id, token, apiHost }) => {
23158
+ const response = await execute(mutation$a, { apiHost, token }, { id });
23159
+ return response.quoteDelete;
23160
+ };
23161
+
23162
+ const mutation$9 = t(`
23125
23163
  mutation quoteSubscriptionUpdate($subscriptionIds: [ID!]!) {
23126
23164
  quoteSubscriptionUpdate(subscriptionIds: $subscriptionIds) {
23127
23165
  quote {
@@ -23150,7 +23188,7 @@ const mutation$2 = t(`
23150
23188
  `, [QuantityDrawer_QuoteFragment]);
23151
23189
  const quoteSubscriptionUpdate = async (subscriptionIds, apiHost, token) => {
23152
23190
  var _a, _b;
23153
- const response = await execute(mutation$2, { apiHost, token }, { subscriptionIds });
23191
+ const response = await execute(mutation$9, { apiHost, token }, { subscriptionIds });
23154
23192
  if ((_a = response.quoteSubscriptionUpdate) === null || _a === void 0 ? void 0 : _a.errors) {
23155
23193
  throw new Error(response.quoteSubscriptionUpdate.errors[0]);
23156
23194
  }
@@ -23219,6 +23257,23 @@ const canShowChangeQuantities = ({ subscriptions, }) => {
23219
23257
  });
23220
23258
  };
23221
23259
 
23260
+ /**
23261
+ * Note: It is good practice to isolate useEffects into their own components.
23262
+ * This approach helps prevent unnecessary re-renders when data is unchanged,
23263
+ * since useEffect will only be triggered in this dedicated sibling component.
23264
+ */
23265
+ const QuoteIsLoadingUpdater = ({ quoteIsPending }) => {
23266
+ const [, setQuoteIsLoading] = useQuoteIsLoading();
23267
+ const prevValue = react.useRef(quoteIsPending);
23268
+ react.useEffect(() => {
23269
+ if (prevValue.current !== quoteIsPending) {
23270
+ setQuoteIsLoading(quoteIsPending);
23271
+ prevValue.current = quoteIsPending;
23272
+ }
23273
+ }, [quoteIsPending, setQuoteIsLoading]);
23274
+ return null;
23275
+ };
23276
+
23222
23277
  const QuantityInput_SubscriptionChargeFragment = t(`
23223
23278
  fragment QuantityInput_SubscriptionChargeFragment on SubscriptionCharge {
23224
23279
  id
@@ -23230,7 +23285,6 @@ const QuantityInput_SubscriptionChargeFragment = t(`
23230
23285
  const QuantityInput_SubscriptionFragment = t(`
23231
23286
  fragment QuantityInput_SubscriptionFragment on Subscription {
23232
23287
  id
23233
- state
23234
23288
  priceList {
23235
23289
  id
23236
23290
  }
@@ -23246,6 +23300,16 @@ const QuantityInput_SubscriptionFragment = t(`
23246
23300
  CanShowQuantitiesInput_SubscriptionFragment,
23247
23301
  ]);
23248
23302
  const DEBOUNCE_TIME$1 = 1000;
23303
+ /**
23304
+ * Design note:
23305
+ * If the quantity is cleared by the user (quantity becomes undefined), we delete the quote.
23306
+ *
23307
+ * Rationale:
23308
+ * The user may next change the quantity for a charge on a different subscription, and we need to
23309
+ * allow creating a new quote/quoteChange in that context. Currently there is no way to create a
23310
+ * quoteChange of kind "update" without first calling `quoteSubscriptionUpdate`, so we delete the
23311
+ * existing quote to reset the flow.
23312
+ */
23249
23313
  const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription, setUpdatingChargeQuantityId, updatingChargeQuantityId, setErrorUpdatingQuantity, }) => {
23250
23314
  // Context
23251
23315
  const token = useToken();
@@ -23260,7 +23324,7 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23260
23324
  const quote = readFragment(QuantityInput_QuoteFragment, maskedQuote);
23261
23325
  // Hooks
23262
23326
  const showErrorNotification = common.useErrorNotification();
23263
- const { setQuoteQueryData } = useSetQuoteQueryData();
23327
+ const { setQuoteQueryData } = useSetQuoteQueryData$1();
23264
23328
  const quantityDisabled =
23265
23329
  // If we are editing a quote, we disable the quantity input
23266
23330
  // If we don't have a quantity, we disable the quantity input
@@ -23273,7 +23337,7 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23273
23337
  !charge.selfServiceQuantity;
23274
23338
  const value = quantity === undefined ? '' : quantity;
23275
23339
  // Mutations
23276
- const { mutate: createCharge } = reactQuery.useMutation({
23340
+ const { mutate: createCharge, isPending: isCreatingCharge } = reactQuery.useMutation({
23277
23341
  mutationFn: quoteChargeCreate$1,
23278
23342
  onSuccess: response => {
23279
23343
  var _a, _b;
@@ -23288,7 +23352,23 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23288
23352
  setErrorUpdatingQuantity(true);
23289
23353
  },
23290
23354
  });
23291
- const createQuote = reactQuery.useMutation({
23355
+ const { mutate: deleteQuote, isPending: isDeletingQuote } = reactQuery.useMutation({
23356
+ mutationFn: quoteDelete,
23357
+ onSuccess: response => {
23358
+ var _a;
23359
+ const quoteId = (_a = response === null || response === void 0 ? void 0 : response.quote) === null || _a === void 0 ? void 0 : _a.id;
23360
+ if (!quoteId) {
23361
+ showErrorNotification('quoteId is required');
23362
+ return;
23363
+ }
23364
+ setQuoteQueryData(quoteId, null);
23365
+ setQuoteId(undefined);
23366
+ },
23367
+ onError: () => {
23368
+ setErrorUpdatingQuantity(true);
23369
+ },
23370
+ });
23371
+ const { mutate: createQuote, isPending: isCreatingQuote } = reactQuery.useMutation({
23292
23372
  mutationFn: (subscriptionId) => quoteSubscriptionUpdate([subscriptionId], apiHost, token),
23293
23373
  onSuccess: quote => {
23294
23374
  var _a, _b, _c;
@@ -23316,7 +23396,7 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23316
23396
  setErrorUpdatingQuantity(true);
23317
23397
  },
23318
23398
  });
23319
- const updateQuoteCharge = reactQuery.useMutation({
23399
+ const { mutate: updateQuoteCharge, isPending: isUpdatingQuoteCharge } = reactQuery.useMutation({
23320
23400
  mutationFn: ({ quoteChargeId, quantity, }) => {
23321
23401
  if (!quoteChargeId)
23322
23402
  throw new Error('quoteChargeId is required');
@@ -23338,26 +23418,35 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23338
23418
  });
23339
23419
  const onChangeQuantity = (value) => {
23340
23420
  var _a;
23421
+ // Cancel all debounced functions first
23422
+ debouncedQuantityUpdate.cancel();
23423
+ debouncedDeleteQuote.cancel();
23341
23424
  // Handle empty string - don't convert to 0, keep it as undefined
23342
23425
  const quantity = value === '' ? undefined : isNaN(parseInt(value)) ? 0 : parseInt(value);
23343
23426
  setQuantity(quantity);
23344
23427
  if (quantity === undefined) {
23345
23428
  setUpdatingChargeQuantityId(undefined);
23429
+ if (quoteId) {
23430
+ // Only delete the quote if it exists
23431
+ debouncedDeleteQuote(quoteId);
23432
+ }
23346
23433
  }
23347
23434
  else {
23348
23435
  if (!(charge === null || charge === void 0 ? void 0 : charge.priceListChargeId)) {
23349
23436
  showErrorNotification('Charge ID is not found');
23350
23437
  return;
23351
23438
  }
23352
- // The set charge id is used to disable all other quantity inputs
23439
+ // Used to disable all other quantity inputs for this subscription
23353
23440
  setUpdatingChargeQuantityId(getUpdatingChargeQuantityId(charge.priceListChargeId, subscription.id));
23354
23441
  const quantityDelta = quantity - ((_a = charge.quantity) !== null && _a !== void 0 ? _a : 0);
23355
- debouncedQuantityUpdate.cancel();
23356
- debouncedQuantityUpdate(charge.priceListChargeId, quantityDelta, quantity, subscription.id, quote, quoteId);
23442
+ debouncedQuantityUpdate(charge.priceListChargeId, quantityDelta, subscription.id, quote, quoteId);
23357
23443
  }
23358
23444
  };
23359
- const debouncedQuantityUpdate = react.useCallback(lodashExports.debounce((priceListChargeId, quantityDelta, quantity, subscriptionId, quote, quoteId) => {
23360
- var _a, _b, _c;
23445
+ const debouncedDeleteQuote = react.useCallback(lodashExports.debounce((quoteId) => {
23446
+ deleteQuote({ id: quoteId, apiHost, token });
23447
+ }, DEBOUNCE_TIME$1), []);
23448
+ const debouncedQuantityUpdate = react.useCallback(lodashExports.debounce((priceListChargeId, quantityDelta, subscriptionId, quote, quoteId) => {
23449
+ var _a;
23361
23450
  if (quantityDelta === 0) {
23362
23451
  setErrorUpdatingQuantity(true);
23363
23452
  showErrorNotification('New quantity cannot be the same as current');
@@ -23365,37 +23454,22 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23365
23454
  }
23366
23455
  // If we are not editing a quote, we create a new one
23367
23456
  if (quoteId === undefined) {
23368
- createQuote.mutate(subscriptionId);
23457
+ createQuote(subscriptionId);
23369
23458
  }
23370
23459
  else {
23371
23460
  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); });
23372
23461
  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; });
23373
23462
  if (quoteCharge) {
23374
- updateQuoteCharge.mutate({
23463
+ updateQuoteCharge({
23375
23464
  quoteChargeId: quoteCharge.id,
23376
23465
  quantity: quantityDelta,
23377
23466
  });
23378
23467
  }
23379
- else {
23380
- 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; });
23381
- if (!(subscriptionCharge === null || subscriptionCharge === void 0 ? void 0 : subscriptionCharge.id))
23382
- throw new Error('subscriptionCharge id is required');
23383
- if (!(quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.id))
23384
- throw new Error('quoteChange id is required');
23385
- createCharge({
23386
- apiHost,
23387
- quantity, // This is a new charge so use quantity instead of quantityDelta
23388
- quoteChangeId: quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.id,
23389
- startDate: formatDateForApi(dayjs()),
23390
- subscriptionChargeId: subscriptionCharge.id,
23391
- token,
23392
- });
23393
- }
23394
23468
  }
23395
23469
  }, DEBOUNCE_TIME$1), []);
23396
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(antd.Input, { className: "bunny-text-right", disabled: quantityDisabled, onChange: e => {
23397
- onChangeQuantity(e.target.value);
23398
- }, style: { width: '96px' }, value: value }) }));
23470
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(antd.Input, { className: "bunny-text-right", disabled: quantityDisabled, onChange: e => {
23471
+ onChangeQuantity(e.target.value);
23472
+ }, style: { width: '96px' }, value: value }), jsxRuntime.jsx(QuoteIsLoadingUpdater, { quoteIsPending: isCreatingCharge || isDeletingQuote || isCreatingQuote || isUpdatingQuoteCharge })] }));
23399
23473
  };
23400
23474
 
23401
23475
  const QuantityChangeGridRow_SubscriptionChargeFragment = t(`
@@ -23522,6 +23596,46 @@ function invalidateSubscriptionsQueryKeys(queryClient, token) {
23522
23596
  });
23523
23597
  }
23524
23598
 
23599
+ const [QuoteRecalculateTaxesProvider, useQuoteRecalculateTaxes$2] = createValueContext();
23600
+
23601
+ const mutation$8 = t(`
23602
+ mutation QuoteRecalculateTaxes($id: ID!) {
23603
+ quoteRecalculateTaxes(id: $id) {
23604
+ quote {
23605
+ ...QuantityDrawer_QuoteFragment
23606
+ id
23607
+ }
23608
+ errors
23609
+ }
23610
+ }
23611
+ `, [QuantityDrawer_QuoteFragment]);
23612
+ const quoteRecalculateTaxes$1 = async ({ quoteId, apiHost, token, }) => {
23613
+ var _a;
23614
+ const response = await execute(mutation$8, { apiHost, token }, { id: quoteId });
23615
+ return (_a = response.quoteRecalculateTaxes) === null || _a === void 0 ? void 0 : _a.quote;
23616
+ };
23617
+
23618
+ const useQuoteRecalculateTaxes$1 = () => {
23619
+ const token = useToken();
23620
+ const { apiHost } = react.useContext(BunnyContext);
23621
+ const { setQuoteQueryData } = useSetQuoteQueryData$1();
23622
+ const { mutate: quoteRecalculateTaxesMutation, isPending: isRecalculatingTaxes } = reactQuery.useMutation({
23623
+ mutationFn: async ({ quoteId }) => {
23624
+ return await quoteRecalculateTaxes$1({ quoteId, apiHost, token });
23625
+ },
23626
+ onSuccess: quote => {
23627
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
23628
+ throw new Error('Quote ID is undefined');
23629
+ }
23630
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, quote);
23631
+ },
23632
+ });
23633
+ return {
23634
+ quoteRecalculateTaxesMutation,
23635
+ isRecalculatingTaxes,
23636
+ };
23637
+ };
23638
+
23525
23639
  const QuantityDrawerContent = ({ subscriptions, quantityDrawerOpen, setQuantityDrawerOpen, handlePortalErrors, setShowInactive, }) => {
23526
23640
  const token = useToken();
23527
23641
  const queryClient = reactQuery.useQueryClient();
@@ -23531,6 +23645,8 @@ const QuantityDrawerContent = ({ subscriptions, quantityDrawerOpen, setQuantityD
23531
23645
  const [payModalVisible, setPayModalVisible] = react.useState(false);
23532
23646
  const [updatingChargeQuantityId, setUpdatingChargeQuantityId] = react.useState(undefined);
23533
23647
  const quote = useQuoteQueryData(quoteId);
23648
+ // Context
23649
+ const onRecalculateTaxes = useQuoteRecalculateTaxes$2();
23534
23650
  // Handlers
23535
23651
  const onSuccess = () => {
23536
23652
  setQuantityDrawerOpen(false);
@@ -23560,10 +23676,11 @@ const QuantityDrawerContent = ({ subscriptions, quantityDrawerOpen, setQuantityD
23560
23676
  const handleOpenCheckout = () => {
23561
23677
  setPayModalVisible(true);
23562
23678
  };
23563
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(QuantityChangeDrawerDesktop, { onClose: handleDrawerClose, open: quantityDrawerOpen, openCheckout: handleOpenCheckout, subscriptions: subscriptions, setUpdatingChargeQuantityId: setUpdatingChargeQuantityId, updatingChargeQuantityId: updatingChargeQuantityId }), jsxRuntime.jsx(Checkout, { onCancel: onCancel, onSuccess: onSuccess, onFail: onFail, open: payModalVisible, quote: quote, token: token, isUpdatingQuote: false })] }));
23679
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(QuantityChangeDrawerDesktop, { onClose: handleDrawerClose, open: quantityDrawerOpen, openCheckout: handleOpenCheckout, subscriptions: subscriptions, setUpdatingChargeQuantityId: setUpdatingChargeQuantityId, updatingChargeQuantityId: updatingChargeQuantityId }), jsxRuntime.jsx(Checkout, { onCancel: onCancel, onSuccess: onSuccess, onFail: onFail, onRecalculateTaxes: onRecalculateTaxes, open: payModalVisible, quote: quote, token: token, isUpdatingQuote: false })] }));
23564
23680
  };
23565
23681
  const QuantityDrawer = ({ subscriptions, quantityDrawerOpen, setQuantityDrawerOpen, handlePortalErrors, setShowInactive, }) => {
23566
- return (jsxRuntime.jsx(QuoteIdProvider, { children: jsxRuntime.jsx(QuantityDrawerContent, { subscriptions: subscriptions, quantityDrawerOpen: quantityDrawerOpen, setQuantityDrawerOpen: setQuantityDrawerOpen, handlePortalErrors: handlePortalErrors, setShowInactive: setShowInactive }) }));
23682
+ const { quoteRecalculateTaxesMutation } = useQuoteRecalculateTaxes$1();
23683
+ return (jsxRuntime.jsx(QuoteIdProvider, { children: jsxRuntime.jsx(QuoteIsLoadingProvider, { children: jsxRuntime.jsx(QuoteRecalculateTaxesProvider, { value: quoteId => quoteRecalculateTaxesMutation({ quoteId }), children: jsxRuntime.jsx(QuantityDrawerContent, { subscriptions: subscriptions, quantityDrawerOpen: quantityDrawerOpen, setQuantityDrawerOpen: setQuantityDrawerOpen, handlePortalErrors: handlePortalErrors, setShowInactive: setShowInactive }) }) }) }));
23567
23684
  };
23568
23685
 
23569
23686
  const useCancelSubscription = () => {
@@ -23827,14 +23944,27 @@ const SubscriptionCardActions = ({ onChangePlanClick, onCancelSubscriptionClick,
23827
23944
  const isInTrial = isSubscriptionTrial(subscription);
23828
23945
  const isTrialExpired = isSubscriptionTrialExpired(subscription);
23829
23946
  const isActiveOrPending = isSubscriptionActiveOrPending(subscription);
23947
+ const getButtonLabel = () => {
23948
+ if (isInTrial) {
23949
+ return 'Upgrade from trial';
23950
+ }
23951
+ if (isTrialExpired) {
23952
+ return 'Upgrade';
23953
+ }
23954
+ // If the subscription is an addon, we should show the "Adjust plan" button since we don't support changing add-on plans.
23955
+ if (subscription.priceList.plan.addon === true) {
23956
+ return 'Adjust plan';
23957
+ }
23958
+ return 'Change plan';
23959
+ };
23830
23960
  if (isPaymentMethodLoading)
23831
23961
  return null;
23832
23962
  return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [isSelfServiceCancelable && onCancelSubscriptionClick && (isInTrial || isActiveOrPending) && (jsxRuntime.jsx(antd.Popconfirm, { icon: null, onConfirm: () => onCancelSubscriptionClick(subscription), title: "Cancel subscription", children: jsxRuntime.jsx(antd.Button, { className: "bunny-p-0", type: "link", children: "Cancel subscription" }) })), arePlansAvailable &&
23833
23963
  onChangePlanClick &&
23834
- (isActiveOrPending || isInTrial || isTrialExpired) && (jsxRuntime.jsx(antd.Button, { onClick: () => onChangePlanClick(subscription), type: 'primary', children: isInTrial ? 'Upgrade from trial' : isTrialExpired ? 'Upgrade' : 'Change plan' })), !arePlansAvailable && isInTrial && jsxRuntime.jsx(antd.Tag, { color: "warning", children: "Cannot upgrade" })] }));
23964
+ (isActiveOrPending || isInTrial || isTrialExpired) && (jsxRuntime.jsx(antd.Button, { onClick: () => onChangePlanClick(subscription), type: 'primary', children: getButtonLabel() })), !arePlansAvailable && isInTrial && jsxRuntime.jsx(antd.Tag, { color: "warning", children: "Cannot upgrade" })] }));
23835
23965
  };
23836
23966
 
23837
- const query$2 = t(`
23967
+ const query$4 = t(`
23838
23968
  query priceListChangeOptions($productId: ID!) {
23839
23969
  priceListChangeOptions(productId: $productId) {
23840
23970
  ...SubscriptionCardActions_PriceListChangeOptionsFragment
@@ -23842,7 +23972,7 @@ const query$2 = t(`
23842
23972
  }
23843
23973
  `, [SubscriptionCardActions_PriceListChangeOptionsFragment]);
23844
23974
  const getPriceListChangeOptions$1 = async ({ apiHost, productId, token, }) => {
23845
- const response = await execute(query$2, { apiHost, token }, { productId });
23975
+ const response = await execute(query$4, { apiHost, token }, { productId });
23846
23976
  return response.priceListChangeOptions;
23847
23977
  };
23848
23978
 
@@ -23876,7 +24006,7 @@ const getSubscriptionStatusText = (subscription) => {
23876
24006
  return `Trial expires on ${common.formatDate(trialEndDate)}`;
23877
24007
  }
23878
24008
  }
23879
- if (evergreen) {
24009
+ if (evergreen && subscription.state === t.scalar('SubscriptionState', 'ACTIVE')) {
23880
24010
  return `Renews on ${common.formatDate(endDate)}`;
23881
24011
  }
23882
24012
  return `Ends on ${common.formatDate(endDate || trialEndDate)}`;
@@ -23954,40 +24084,66 @@ const formatNumber = (num, decimals = 2) => {
23954
24084
  });
23955
24085
  };
23956
24086
 
24087
+ const getPricingModelDescription = (pricingModel) => {
24088
+ switch (pricingModel) {
24089
+ case 'TIERED':
24090
+ return 'units in each tier are priced separately.';
24091
+ case 'VOLUME':
24092
+ return 'the highest tier reached prices all units.';
24093
+ case 'BANDS':
24094
+ return 'the quantity indexes to a flat price.';
24095
+ default:
24096
+ return '';
24097
+ }
24098
+ };
24099
+
24100
+ const getPricingModelTitle = (pricingModel) => {
24101
+ switch (pricingModel) {
24102
+ case 'TIERED':
24103
+ return 'Tiered';
24104
+ case 'VOLUME':
24105
+ return 'Volume';
24106
+ case 'BANDS':
24107
+ return 'Bands';
24108
+ default:
24109
+ return '';
24110
+ }
24111
+ };
24112
+
23957
24113
  const StyledTable = styled(antd.Table) `
23958
24114
  .ant-table-cell {
23959
24115
  border-bottom: none !important;
23960
24116
  }
23961
24117
  `;
23962
- const TieredDisplayDropdown = ({ priceTiers, currencyId, priceDecimals, truncatedText, }) => {
24118
+ const TieredDisplayDropdown = ({ pricingModel, priceTiers, currencyId, priceDecimals, truncatedText, }) => {
23963
24119
  const onlyHasOneTier = (priceTiers === null || priceTiers === void 0 ? void 0 : priceTiers.length) === 1;
23964
24120
  const dropdownTrigger = (jsxRuntime.jsx("div", { className: `w-full ${onlyHasOneTier ? '' : 'underline cursor-pointer'}`, children: truncatedText }));
23965
24121
  if (onlyHasOneTier) {
23966
24122
  return dropdownTrigger;
23967
24123
  }
23968
24124
  return (jsxRuntime.jsx(antd.Dropdown, { popupRender: () => {
23969
- return (jsxRuntime.jsx("div", { className: "rounded border border-solid border-slate-200 bg-white overflow-hidden", children: jsxRuntime.jsx(StyledTable, { columns: [
23970
- {
23971
- dataIndex: 'starts',
23972
- title: 'From # of units',
23973
- align: 'right',
23974
- render: (_, record, index) => {
23975
- record = record;
23976
- const nextRecord = priceTiers === null || priceTiers === void 0 ? void 0 : priceTiers[index + 1];
23977
- const starts = record.starts;
23978
- const ends = (nextRecord === null || nextRecord === void 0 ? void 0 : nextRecord.starts) ? nextRecord.starts - 1 : '';
23979
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [formatNumber(starts, 0), " -", ' ', typeof ends === 'number' ? formatNumber(ends, 0) : ''] }));
24125
+ return (jsxRuntime.jsxs("div", { className: "rounded border border-solid border-slate-200 bg-white overflow-hidden", children: [jsxRuntime.jsxs("div", { className: "bunny-text-gray-400 bunny-p-2", children: [getPricingModelTitle(pricingModel), " pricing -", ' ', getPricingModelDescription(pricingModel)] }), jsxRuntime.jsx(StyledTable, { columns: [
24126
+ {
24127
+ dataIndex: 'starts',
24128
+ title: 'From # of units',
24129
+ align: 'right',
24130
+ render: (_, record, index) => {
24131
+ record = record;
24132
+ const nextRecord = priceTiers === null || priceTiers === void 0 ? void 0 : priceTiers[index + 1];
24133
+ const starts = record.starts;
24134
+ const ends = (nextRecord === null || nextRecord === void 0 ? void 0 : nextRecord.starts) ? nextRecord.starts - 1 : '+';
24135
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [formatNumber(starts, 0), typeof ends === 'number' ? formatNumber(ends, 0) : '+'] }));
24136
+ },
23980
24137
  },
23981
- },
23982
- {
23983
- dataIndex: 'price',
23984
- title: 'Unit price',
23985
- align: 'right',
23986
- render: value => {
23987
- return jsxRuntime.jsx(jsxRuntime.Fragment, { children: common.formatCurrency(value, currencyId, priceDecimals) });
24138
+ {
24139
+ dataIndex: 'price',
24140
+ title: 'Unit price',
24141
+ align: 'right',
24142
+ render: value => {
24143
+ return jsxRuntime.jsx(jsxRuntime.Fragment, { children: common.formatCurrency(value, currencyId, priceDecimals) });
24144
+ },
23988
24145
  },
23989
- },
23990
- ], dataSource: priceTiers, rowKey: "starts", pagination: false, size: "small" }) }));
24146
+ ], dataSource: priceTiers, rowKey: "starts", pagination: false, size: "small" })] }));
23991
24147
  }, children: dropdownTrigger }));
23992
24148
  };
23993
24149
 
@@ -24038,7 +24194,7 @@ const SubscriptionChargeUnitPrice = ({ charge, currencyId, }) => {
24038
24194
  ? '-'
24039
24195
  : common.formatCurrency(charge.discountedPrice, currencyId, charge.priceDecimals);
24040
24196
  const isChargeDiscount = isDiscount$1(charge.kind);
24041
- return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: hasPriceTiers(charge) ? (jsxRuntime.jsx(TieredDisplayDropdown, { priceTiers: charge.priceTiers, currencyId: currencyId, priceDecimals: charge.priceDecimals, truncatedText: `${charge.kind === common.QuoteChangeKind.PRICE_UPDATE ? 'new ' : ''}${getApplicablePriceTier(charge, currencyId, charge.priceDecimals)}` })) : isChargeDiscount ? (`-${price}`) : (price) }));
24197
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: hasPriceTiers(charge) ? (jsxRuntime.jsx(TieredDisplayDropdown, { pricingModel: charge.pricingModel, priceTiers: charge.priceTiers, currencyId: currencyId, priceDecimals: charge.priceDecimals, truncatedText: `${charge.kind === common.QuoteChangeKind.PRICE_UPDATE ? 'new ' : ''}${getApplicablePriceTier(charge, currencyId, charge.priceDecimals)}` })) : isChargeDiscount ? (`-${price}`) : (price) }));
24042
24198
  };
24043
24199
 
24044
24200
  const { Text: Text$e } = antd.Typography;
@@ -24175,7 +24331,7 @@ const SubscriptionCardDesktopRow = ({ charge, chargeIndex, charges, currencyId,
24175
24331
  : (_b = charge.quantity) === null || _b === void 0 ? void 0 : _b.toLocaleString() }), jsxRuntime.jsx(SubscriptionsListCell, { right: true, children: jsxRuntime.jsx(SubscriptionChargeUnitPrice, { charge: charge, currencyId: currencyId }) }), jsxRuntime.jsx(SubscriptionsListCell, { right: true, children: jsxRuntime.jsx(SubscriptionChargeTotal, { charge: charge, currencyId: currencyId }) })] }));
24176
24332
  };
24177
24333
 
24178
- function AddonSubscriptionsCards({ onCancelSubscriptionClick, subscriptions, subscription, showInactive, }) {
24334
+ function AddonSubscriptionsCards({ onCancelSubscriptionClick, onChangePlanClick, subscriptions, subscription, showInactive, }) {
24179
24335
  const addonSubscriptions = findAddonSubscriptions(subscription, subscriptions);
24180
24336
  if (addonSubscriptions.length === 0) {
24181
24337
  return null;
@@ -24184,7 +24340,7 @@ function AddonSubscriptionsCards({ onCancelSubscriptionClick, subscriptions, sub
24184
24340
  if (!showInactive && isSubscriptionNotActive(addonSubscription))
24185
24341
  return null;
24186
24342
  const isLast = addonSubscriptionIndex === addonSubscriptions.length - 1;
24187
- return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row", children: [jsxRuntime.jsx(AddonIndentation, { isLast: isLast, indentation: ADDON_INDENTATION, verticalMargin: "-1rem" }), jsxRuntime.jsx("div", { className: "bunny-flex-1", children: jsxRuntime.jsx(SubscriptionCardDesktop, { onCancelSubscriptionClick: onCancelSubscriptionClick, subscription: addonSubscription, isAddon: true }) })] }, addonSubscriptionIndex));
24343
+ return (jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row", children: [jsxRuntime.jsx(AddonIndentation, { isLast: isLast, indentation: ADDON_INDENTATION, verticalMargin: "-1rem" }), jsxRuntime.jsx("div", { className: "bunny-flex-1", children: jsxRuntime.jsx(SubscriptionCardDesktop, { onChangePlanClick: onChangePlanClick, onCancelSubscriptionClick: onCancelSubscriptionClick, subscription: addonSubscription, isAddon: true }) })] }, addonSubscriptionIndex));
24188
24344
  }) }));
24189
24345
  }
24190
24346
 
@@ -24243,8 +24399,8 @@ const SubscriptionsList = ({ showInactive, onChangePlanClick, onCancelSubscripti
24243
24399
  if (!showInactive && isSubscriptionNotActive(subscription))
24244
24400
  return null;
24245
24401
  if (isMobile)
24246
- return (jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-${gap}`, children: [jsxRuntime.jsx(SubscriptionCard, { subscription: subscription }), jsxRuntime.jsx(AddonSubscriptionsCards, { onCancelSubscriptionClick: onCancelSubscriptionClick, subscription: subscription, subscriptions: subscriptions, showInactive: showInactive })] }, subscriptionIndex));
24247
- return (jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-${gap}`, children: [jsxRuntime.jsx(SubscriptionCardDesktop, { onChangePlanClick: onChangePlanClick, onCancelSubscriptionClick: onCancelSubscriptionClick, subscription: subscription }), jsxRuntime.jsx(AddonSubscriptionsCards, { onCancelSubscriptionClick: onCancelSubscriptionClick, subscription: subscription, subscriptions: subscriptions, showInactive: showInactive })] }, subscriptionIndex));
24402
+ return (jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-${gap}`, children: [jsxRuntime.jsx(SubscriptionCard, { subscription: subscription }), jsxRuntime.jsx(AddonSubscriptionsCards, { onCancelSubscriptionClick: onCancelSubscriptionClick, onChangePlanClick: onChangePlanClick, subscription: subscription, subscriptions: subscriptions, showInactive: showInactive })] }, subscriptionIndex));
24403
+ return (jsxRuntime.jsxs("div", { className: `bunny-flex bunny-flex-col bunny-gap-${gap}`, children: [jsxRuntime.jsx(SubscriptionCardDesktop, { onChangePlanClick: onChangePlanClick, onCancelSubscriptionClick: onCancelSubscriptionClick, subscription: subscription }), jsxRuntime.jsx(AddonSubscriptionsCards, { onCancelSubscriptionClick: onCancelSubscriptionClick, onChangePlanClick: onChangePlanClick, subscription: subscription, subscriptions: subscriptions, showInactive: showInactive })] }, subscriptionIndex));
24248
24404
  }) }));
24249
24405
  };
24250
24406
 
@@ -24315,7 +24471,7 @@ const FormattedQuoteFields_QuoteFragment = t(`
24315
24471
  }
24316
24472
  }
24317
24473
  `);
24318
- const query$1 = t(`
24474
+ const query$3 = t(`
24319
24475
  query quote($id: ID, $includeHtmlField: Boolean!) {
24320
24476
  quote(id: $id) {
24321
24477
  ...FormattedQuoteFields_QuoteFragment @include(if: $includeHtmlField)
@@ -24324,7 +24480,7 @@ const query$1 = t(`
24324
24480
  }
24325
24481
  `, [FormattedQuoteFields_QuoteFragment, QuoteContext_QuoteFragment]);
24326
24482
  const getQuote = async ({ id, token, apiHost, includeHtmlField = false, }) => {
24327
- const response = await execute(query$1, { apiHost, token }, { id, includeHtmlField });
24483
+ const response = await execute(query$3, { apiHost, token }, { id, includeHtmlField });
24328
24484
  return response === null || response === void 0 ? void 0 : response.quote;
24329
24485
  };
24330
24486
 
@@ -24429,7 +24585,7 @@ const calculateNewQuantity = (priceListCharge, currentQuantity = 1) => {
24429
24585
  return quantityMin;
24430
24586
  };
24431
24587
 
24432
- const mutation$1 = t(`
24588
+ const mutation$7 = t(`
24433
24589
  mutation QuoteChangeUpdate($id: ID!, $charges: [QuoteChargeAttributes!]!) {
24434
24590
  quoteChangeUpdate(id: $id, charges: $charges) {
24435
24591
  quoteChange {
@@ -24443,7 +24599,7 @@ const mutation$1 = t(`
24443
24599
  `, [QuoteContext_QuoteFragment]);
24444
24600
  const quoteChangeUpdate = async ({ quoteChangeId, charges, apiHost, token, }) => {
24445
24601
  var _a, _b;
24446
- const response = await execute(mutation$1, {
24602
+ const response = await execute(mutation$7, {
24447
24603
  apiHost,
24448
24604
  token,
24449
24605
  }, {
@@ -24499,6 +24655,19 @@ function useFeatureQuantities({ onFeatureQuantitiesChanged, }) {
24499
24655
  };
24500
24656
  }
24501
24657
 
24658
+ const useSetQuoteQueryData = () => {
24659
+ const token = useToken();
24660
+ const queryClient = reactQuery.useQueryClient();
24661
+ const setQuoteQueryData = (quoteId, quote) => {
24662
+ queryClient.setQueryData(common.QueryKeyFactory.default.createObjectKey({
24663
+ id: quoteId,
24664
+ objectName: 'editingQuote',
24665
+ token,
24666
+ }), quote);
24667
+ };
24668
+ return { setQuoteQueryData };
24669
+ };
24670
+
24502
24671
  // Functionality:
24503
24672
  // 1: keep track of quantities set for features based on feature.id
24504
24673
  // a. copy those quantities over to charges with same feature when initializing
@@ -24511,9 +24680,9 @@ function useFeatureQuantities({ onFeatureQuantitiesChanged, }) {
24511
24680
  const showErrorNotification = common.useErrorNotification();
24512
24681
  const DEBOUNCE_TIME = 1000;
24513
24682
  const useQuoteQuantities = ({ selectedPriceList, quote, }) => {
24514
- const queryClient = reactQuery.useQueryClient();
24515
24683
  const token = useToken();
24516
24684
  const { apiHost } = react.useContext(BunnyContext);
24685
+ const { setQuoteQueryData } = useSetQuoteQueryData();
24517
24686
  // Derived state
24518
24687
  const selectedPriceListQuoteChange = react.useMemo(() => {
24519
24688
  var _a;
@@ -24532,23 +24701,27 @@ const useQuoteQuantities = ({ selectedPriceList, quote, }) => {
24532
24701
  });
24533
24702
  },
24534
24703
  onSuccess: quoteChange => {
24535
- var _a;
24536
- queryClient.setQueryData(common.QueryKeyFactory.default.createObjectKey({
24537
- objectName: 'editingQuote',
24538
- id: (_a = quote === null || quote === void 0 ? void 0 : quote.id) !== null && _a !== void 0 ? _a : undefined,
24539
- token,
24540
- }), quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.quote);
24704
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
24705
+ throw new Error('Quote ID is undefined');
24706
+ }
24707
+ if (!(quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.quote)) {
24708
+ throw new Error('Quote is undefined');
24709
+ }
24710
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.quote);
24541
24711
  },
24542
24712
  });
24543
24713
  function handleUpdateQuoteQuantities(featureQuantities) {
24544
24714
  if (!selectedPriceListQuoteChange) {
24545
- throw new Error('Quote change is undefined');
24715
+ console.error('Quote change is undefined');
24716
+ return;
24546
24717
  }
24547
24718
  if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
24548
- throw new Error('Quote ID is undefined');
24719
+ console.error('Quote ID is undefined');
24720
+ return;
24549
24721
  }
24550
24722
  if (!(selectedPriceListQuoteChange === null || selectedPriceListQuoteChange === void 0 ? void 0 : selectedPriceListQuoteChange.id)) {
24551
- throw new Error('Quote change ID is undefined');
24723
+ console.error('Quote change ID is undefined');
24724
+ return;
24552
24725
  }
24553
24726
  const featureIdsToUpdate = Object.keys(featureQuantities).filter(featureId => {
24554
24727
  // If the quantities differ, then update quote with the quantities present in useFeatureQuantities
@@ -24560,20 +24733,24 @@ const useQuoteQuantities = ({ selectedPriceList, quote, }) => {
24560
24733
  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; });
24561
24734
  return quoteCharge !== undefined && localAndQuoteQuantitiesDiffer;
24562
24735
  });
24563
- const charges = featureIdsToUpdate.map(featureId => {
24736
+ const charges = featureIdsToUpdate
24737
+ .map(featureId => {
24564
24738
  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; });
24565
24739
  const quantity = getFeatureQuantity(featureId, featureQuantities);
24566
24740
  if (!quantity) {
24567
- throw new Error('Quantity is undefined');
24741
+ console.error('Quantity is undefined');
24742
+ return;
24568
24743
  }
24569
24744
  if (!(quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.id)) {
24570
- throw new Error('Quote charge for featureId is undefined');
24745
+ console.error('Quote charge for featureId is undefined');
24746
+ return;
24571
24747
  }
24572
24748
  return {
24573
24749
  id: quoteCharge.id,
24574
24750
  quantity: quantity,
24575
24751
  };
24576
- });
24752
+ })
24753
+ .filter(charge => charge !== undefined);
24577
24754
  if (charges.length === 0) {
24578
24755
  return;
24579
24756
  }
@@ -24641,6 +24818,44 @@ const useQuoteQuantities = ({ selectedPriceList, quote, }) => {
24641
24818
  };
24642
24819
  };
24643
24820
 
24821
+ const mutation$6 = t(`
24822
+ mutation QuoteRecalculateTaxes($id: ID!) {
24823
+ quoteRecalculateTaxes(id: $id) {
24824
+ quote {
24825
+ ...QuoteContext_QuoteFragment
24826
+ id
24827
+ }
24828
+ errors
24829
+ }
24830
+ }
24831
+ `, [QuoteContext_QuoteFragment]);
24832
+ const quoteRecalculateTaxes = async ({ quoteId, apiHost, token, }) => {
24833
+ var _a;
24834
+ const response = await execute(mutation$6, { apiHost, token }, { id: quoteId });
24835
+ return (_a = response.quoteRecalculateTaxes) === null || _a === void 0 ? void 0 : _a.quote;
24836
+ };
24837
+
24838
+ const useQuoteRecalculateTaxes = () => {
24839
+ const token = useToken();
24840
+ const { apiHost } = react.useContext(BunnyContext);
24841
+ const { setQuoteQueryData } = useSetQuoteQueryData();
24842
+ const { mutate: quoteRecalculateTaxesMutation, isPending: isRecalculatingTaxes } = reactQuery.useMutation({
24843
+ mutationFn: async ({ quoteId }) => {
24844
+ return await quoteRecalculateTaxes({ quoteId, apiHost, token });
24845
+ },
24846
+ onSuccess: quote => {
24847
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
24848
+ throw new Error('Quote ID is undefined');
24849
+ }
24850
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, quote);
24851
+ },
24852
+ });
24853
+ return {
24854
+ quoteRecalculateTaxesMutation,
24855
+ isRecalculatingTaxes,
24856
+ };
24857
+ };
24858
+
24644
24859
  function useFeatureAddonsPending() {
24645
24860
  const [featureAddonsLoading, setFeatureAddonsLoading] = react.useState([]);
24646
24861
  const addFeatureAddonLoading = (featureAddonId) => {
@@ -24664,6 +24879,7 @@ function QuoteProvider({ children }) {
24664
24879
  // Hooks
24665
24880
  const token = useToken();
24666
24881
  const { isFeatureAddonsLoading, addFeatureAddonLoading, removeFeatureAddonLoading } = useFeatureAddonsPending();
24882
+ const { quoteRecalculateTaxesMutation } = useQuoteRecalculateTaxes();
24667
24883
  const { quote: maskedQuote, isQuotePending } = useQuoteCreate({
24668
24884
  upgradingSubscription,
24669
24885
  selectedPriceList: selectedPriceList,
@@ -24699,6 +24915,7 @@ function QuoteProvider({ children }) {
24699
24915
  onChangeSelectedPriceList: handleChangeSelectedPriceList,
24700
24916
  onChangeQuantity,
24701
24917
  getFeatureQuantity,
24918
+ onRecalculateTaxes: (id) => quoteRecalculateTaxesMutation({ quoteId: id }),
24702
24919
  }, children: children }));
24703
24920
  }
24704
24921
 
@@ -24725,40 +24942,6 @@ function priceDescriptionString({ unitName, showPriceAsMonthly, periodMonths, pr
24725
24942
  return `Per ${unitName && !priceListHasFlatFeeCharges ? `${unitName.toLowerCase()} / ` : ''}${showPriceAsMonthly ? 'month' : periodLabel}`;
24726
24943
  }
24727
24944
 
24728
- var localizedFormat$2 = {exports: {}};
24729
-
24730
- var localizedFormat$1 = localizedFormat$2.exports;
24731
-
24732
- var hasRequiredLocalizedFormat;
24733
-
24734
- function requireLocalizedFormat () {
24735
- if (hasRequiredLocalizedFormat) return localizedFormat$2.exports;
24736
- hasRequiredLocalizedFormat = 1;
24737
- (function (module, exports) {
24738
- !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)};}}));
24739
- } (localizedFormat$2));
24740
- return localizedFormat$2.exports;
24741
- }
24742
-
24743
- var localizedFormatExports = requireLocalizedFormat();
24744
- var localizedFormat = /*@__PURE__*/getDefaultExportFromCjs(localizedFormatExports);
24745
-
24746
- dayjs.extend(localizedFormat);
24747
- const formatCurrency = (value, currencyIsoCode, decimals = 2) => {
24748
- if (value !== 0 && !value)
24749
- return '';
24750
- const currencyValue = typeof value === 'string' ? parseFloat(value) : value;
24751
- if (isNaN(currencyValue))
24752
- return value;
24753
- const localeOptions = {
24754
- minimumFractionDigits: decimals,
24755
- maximumFractionDigits: decimals,
24756
- };
24757
- localeOptions.style = 'currency';
24758
- localeOptions.currency = currencyIsoCode;
24759
- return currencyValue.toLocaleString(navigator.language, localeOptions);
24760
- };
24761
-
24762
24945
  const { Text: Text$b } = antd.Typography;
24763
24946
  const PriceTierPrice = ({ currencyId, priceDecimals, tier, }) => {
24764
24947
  return (jsxRuntime.jsx(Text$b, { className: "bunny-text-white", children: formatCurrency(tier.price, currencyId, priceDecimals) }));
@@ -24782,32 +24965,6 @@ const PriceTierRow = ({ tier: maskedTier, nextTier: maskedNextTier, }) => {
24782
24965
  return jsxRuntime.jsx(Text$a, { className: "bunny-text-white", children: text });
24783
24966
  };
24784
24967
 
24785
- const getPricingModelTitle = (pricingModel) => {
24786
- switch (pricingModel) {
24787
- case 'TIERED':
24788
- return 'Tiered';
24789
- case 'VOLUME':
24790
- return 'Volume';
24791
- case 'BANDS':
24792
- return 'Bands';
24793
- default:
24794
- return '';
24795
- }
24796
- };
24797
-
24798
- const getPricingModelDescription = (pricingModel) => {
24799
- switch (pricingModel) {
24800
- case 'TIERED':
24801
- return 'units in each tier are priced separately.';
24802
- case 'VOLUME':
24803
- return 'the highest tier reached prices all units.';
24804
- case 'BANDS':
24805
- return 'the quantity indexes to a flat price.';
24806
- default:
24807
- return '';
24808
- }
24809
- };
24810
-
24811
24968
  const { Text: Text$9 } = antd.Typography;
24812
24969
  const ChargePriceTiers_PriceListChargeFragment = t(`
24813
24970
  fragment ChargePriceTiers_PriceListChargeFragment on PriceListCharge {
@@ -25442,57 +25599,13 @@ const getAvailablePlansAndPriceLists = ({ availablePriceLists, priceListChangeOp
25442
25599
  return {
25443
25600
  availablePriceListsArray,
25444
25601
  displayPriceLists,
25445
- };
25446
- };
25447
- const everythingInPlusString = ({ priceList }) => {
25448
- return `Everything in ${priceList.plan.name}, plus`;
25449
- };
25450
-
25451
- const QUOTE_CHARGE_CREATE = `
25452
- ${QUOTE_FIELDS()}
25453
- mutation QuoteChargeCreate ($quoteChangeId: ID!, $startDate: ISO8601Date!, $endDate: ISO8601Date, $priceListChargeId: ID, $subscriptionChargeId: ID, $price: Float, $quantity: Int) {
25454
- quoteChargeCreate(
25455
- endDate: $endDate
25456
- price: $price
25457
- priceListChargeId: $priceListChargeId
25458
- quantity: $quantity
25459
- quoteChangeId: $quoteChangeId
25460
- startDate: $startDate
25461
- subscriptionChargeId: $subscriptionChargeId
25462
- ) {
25463
- quoteCharge {
25464
- quoteChange {
25465
- id
25466
- quoteId
25467
- quote {
25468
- ...QuoteFields
25469
- }
25470
- }
25471
- id
25472
- }
25473
- }
25474
- }
25475
-
25476
- `;
25477
- const quoteChargeCreate = async ({ price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId, token, apiHost, }) => {
25478
- var _a;
25479
- const response = await gqlRequest({
25480
- query: QUOTE_CHARGE_CREATE,
25481
- vars: {
25482
- price,
25483
- priceListChargeId,
25484
- quantity,
25485
- quoteChangeId,
25486
- startDate,
25487
- subscriptionChargeId,
25488
- },
25489
- apiHost,
25490
- token,
25491
- });
25492
- return (_a = response === null || response === void 0 ? void 0 : response.quoteChargeCreate) === null || _a === void 0 ? void 0 : _a.quoteCharge;
25602
+ };
25603
+ };
25604
+ const everythingInPlusString = ({ priceList }) => {
25605
+ return `Everything in ${priceList.plan.name}, plus`;
25493
25606
  };
25494
25607
 
25495
- const mutation = t(`
25608
+ const mutation$5 = t(`
25496
25609
  mutation QuoteChargeDelete($quoteChargeId: ID!) {
25497
25610
  quoteChargeDelete(quoteChargeId: $quoteChargeId) {
25498
25611
  errors
@@ -25510,21 +25623,76 @@ const mutation = t(`
25510
25623
  `, [QuoteContext_QuoteFragment]);
25511
25624
  const quoteChargeDelete = async ({ quoteChargeId, token, apiHost }) => {
25512
25625
  var _a, _b, _c, _d;
25513
- const response = await execute(mutation, { apiHost, token }, { quoteChargeId });
25626
+ const response = await execute(mutation$5, { apiHost, token }, { quoteChargeId });
25514
25627
  if ((_a = response.quoteChargeDelete) === null || _a === void 0 ? void 0 : _a.errors) {
25515
25628
  throw new Error((_c = (_b = response.quoteChargeDelete) === null || _b === void 0 ? void 0 : _b.errors) === null || _c === void 0 ? void 0 : _c[0]);
25516
25629
  }
25517
25630
  return (_d = response.quoteChargeDelete) === null || _d === void 0 ? void 0 : _d.quoteCharge;
25518
25631
  };
25519
25632
 
25520
- const useQuoteUpdateFeatureAddon = (quote, featureAddon) => {
25633
+ const mutation$4 = t(`
25634
+ mutation QuoteChargeCreate(
25635
+ $quoteChangeId: ID!
25636
+ $startDate: ISO8601Date!
25637
+ $endDate: ISO8601Date
25638
+ $priceListChargeId: ID
25639
+ $subscriptionChargeId: ID
25640
+ $price: Float
25641
+ $quantity: Int
25642
+ ) {
25643
+ quoteChargeCreate(
25644
+ endDate: $endDate
25645
+ price: $price
25646
+ priceListChargeId: $priceListChargeId
25647
+ quantity: $quantity
25648
+ quoteChangeId: $quoteChangeId
25649
+ startDate: $startDate
25650
+ subscriptionChargeId: $subscriptionChargeId
25651
+ ) {
25652
+ quoteCharge {
25653
+ quoteChange {
25654
+ id
25655
+ quoteId
25656
+ quote {
25657
+ ...QuoteContext_QuoteFragment
25658
+ }
25659
+ }
25660
+ id
25661
+ }
25662
+ }
25663
+ }
25664
+ `, [QuoteContext_QuoteFragment]);
25665
+ const quoteChargeCreate = async ({ price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId, token, apiHost, }) => {
25666
+ var _a;
25667
+ const response = await execute(mutation$4, { apiHost, token }, { price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId });
25668
+ return (_a = response === null || response === void 0 ? void 0 : response.quoteChargeCreate) === null || _a === void 0 ? void 0 : _a.quoteCharge;
25669
+ };
25670
+
25671
+ const useQuoteUpdateFeatureAddon = (maskedQuote, featureAddon) => {
25521
25672
  const { apiHost } = react.useContext(BunnyContext);
25522
25673
  const { addFeatureAddonLoading, removeFeatureAddonLoading } = react.useContext(QuoteContext);
25523
25674
  const token = useToken();
25524
- const queryClient = reactQuery.useQueryClient();
25675
+ const { setQuoteQueryData } = useSetQuoteQueryData();
25676
+ // Read fragments
25677
+ const quote = readFragment(useQuoteUpdateFeatureAddon_QuoteFragment, maskedQuote);
25525
25678
  const addedQuoteChargeId = react.useRef();
25526
25679
  function handleAddFeatureAddon() {
25527
- quoteChargeCreateMutation();
25680
+ if (!token)
25681
+ throw new Error('Token is required');
25682
+ if (!quote)
25683
+ throw new Error('Editing quote is required');
25684
+ const quoteChangeId = findQuoteChangeForFeatureAddon(quote);
25685
+ if (!quoteChangeId)
25686
+ throw new Error('No available quote change for feature add-on');
25687
+ console.log('quote', quote);
25688
+ console.log('startDate', quote === null || quote === void 0 ? void 0 : quote.startDate);
25689
+ quoteChargeCreateMutation({
25690
+ quoteChangeId: quoteChangeId.id,
25691
+ priceListChargeId: featureAddon.id,
25692
+ startDate: quote === null || quote === void 0 ? void 0 : quote.startDate,
25693
+ apiHost,
25694
+ token,
25695
+ });
25528
25696
  }
25529
25697
  function handleRemoveFeatureAddon() {
25530
25698
  if (!addedQuoteChargeId.current)
@@ -25532,30 +25700,16 @@ const useQuoteUpdateFeatureAddon = (quote, featureAddon) => {
25532
25700
  quoteChargeDeleteMutation({ quoteChargeId: addedQuoteChargeId.current });
25533
25701
  }
25534
25702
  const { mutate: quoteChargeCreateMutation, isPending: isCreatingFeatureAddon } = reactQuery.useMutation({
25535
- mutationFn: async () => {
25536
- if (!token)
25537
- throw new Error('Token is required');
25538
- if (!quote)
25539
- throw new Error('Editing quote is required');
25540
- const quoteChangeId = findQuoteChangeForFeatureAddon(quote);
25541
- if (!quoteChangeId)
25542
- throw new Error('No available quote change for feature add-on');
25543
- const quoteCharge = await quoteChargeCreate({
25544
- quoteChangeId: quoteChangeId.id,
25545
- priceListChargeId: featureAddon.id,
25546
- startDate: quote === null || quote === void 0 ? void 0 : quote.startDate,
25547
- apiHost,
25548
- token,
25549
- });
25550
- return { quoteCharge };
25551
- },
25552
- onSuccess: ({ quoteCharge }) => {
25553
- addedQuoteChargeId.current = quoteCharge.id;
25554
- queryClient.setQueryData(common.QueryKeyFactory.default.createObjectKey({
25555
- objectName: 'editingQuote',
25556
- id: quote === null || quote === void 0 ? void 0 : quote.id,
25557
- token,
25558
- }), quoteCharge.quoteChange.quote);
25703
+ mutationFn: quoteChargeCreate,
25704
+ onSuccess: quoteCharge => {
25705
+ addedQuoteChargeId.current = quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.id;
25706
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
25707
+ throw new Error('Quote ID is undefined');
25708
+ }
25709
+ if (!(quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.quoteChange.quote)) {
25710
+ throw new Error('Quote is undefined');
25711
+ }
25712
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.quoteChange.quote);
25559
25713
  },
25560
25714
  });
25561
25715
  const { mutate: quoteChargeDeleteMutation, isPending: isDeletingFeatureAddon } = reactQuery.useMutation({
@@ -25565,11 +25719,13 @@ const useQuoteUpdateFeatureAddon = (quote, featureAddon) => {
25565
25719
  },
25566
25720
  onSuccess: quoteCharge => {
25567
25721
  addedQuoteChargeId.current = undefined;
25568
- queryClient.setQueryData(common.QueryKeyFactory.default.createObjectKey({
25569
- objectName: 'editingQuote',
25570
- id: quote === null || quote === void 0 ? void 0 : quote.id,
25571
- token,
25572
- }), quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.quoteChange.quote);
25722
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
25723
+ throw new Error('Quote ID is undefined');
25724
+ }
25725
+ if (!(quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.quoteChange.quote)) {
25726
+ throw new Error('Quote is undefined');
25727
+ }
25728
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.quoteChange.quote);
25573
25729
  },
25574
25730
  });
25575
25731
  const isPending = isCreatingFeatureAddon || isDeletingFeatureAddon;
@@ -25649,10 +25805,11 @@ const FeatureAddonRow_PriceListChargeFragment = t(`
25649
25805
  }
25650
25806
  `, [isAddonPurchased_PriceListChargeFragment, PricingTooltip_PriceListChargeFragment]);
25651
25807
  function FeatureAddonRow({ featureAddon: maskedFeatureAddon, priceList: maskedPriceList, }) {
25808
+ const { quote: maskedQuote, selectedPriceList } = react.useContext(QuoteContext);
25652
25809
  // Read fragments
25653
25810
  const featureAddon = readFragment(FeatureAddonRow_PriceListChargeFragment, maskedFeatureAddon);
25654
25811
  const priceList = readFragment(FeatureAddonRow_PriceListFragment, maskedPriceList);
25655
- const { quote, selectedPriceList } = react.useContext(QuoteContext);
25812
+ const quote = readFragment(FeatureAddonRow_QuoteFragment, maskedQuote);
25656
25813
  const { handleAddFeatureAddon, handleRemoveFeatureAddon, isPending, isChecked } = useQuoteUpdateFeatureAddon(quote, featureAddon);
25657
25814
  const { brandColor } = useBrand();
25658
25815
  const { upgradingSubscription } = react.useContext(SubscriptionsContext);
@@ -25867,107 +26024,84 @@ function AddonPlanModal({ onClose, priceList: maskedPriceList, }) {
25867
26024
  return (jsxRuntime.jsx(StyledModal, { open: !!priceList, onCancel: onClose, footer: null, centered: true, children: jsxRuntime.jsxs("div", { className: `bunny-w-full bunny-overflow-hidden`, children: [jsxRuntime.jsx(GridTemplateColumnsWrapper, { className: "bunny-grid bunny-w-full", everythingInPlus: false, plansToDisplay: 1, children: priceList && (jsxRuntime.jsx(PriceListCard, { isSelected: true, priceList: priceList, noBorder: true, hideButton: true, disableCurrentPlan: true })) }), hasFeatureAddons && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(antd.Divider, { className: "bunny-my-0" }), jsxRuntime.jsx("div", { className: "bunny-flex bunny-flex-col bunny-gap-4 bunny-p-4", children: jsxRuntime.jsx(FeatureAddonsList, { priceList: priceList }) })] }))] }) }));
25868
26025
  }
25869
26026
 
25870
- const QUOTE_CHANGE_CREATE = `
25871
- ${QUOTE_FIELDS()}
25872
- mutation QuoteChangeCreate(
25873
- $quoteId: ID!
25874
- $priceListId: ID!
25875
- $parentQuoteChangeId: ID!
25876
- ) {
25877
- quoteChangeCreate(
25878
- quoteId: $quoteId
25879
- priceListId: $priceListId
25880
- parentQuoteChangeId: $parentQuoteChangeId
25881
- ) {
25882
- errors
25883
- quoteChange {
25884
- id
25885
- quote {
25886
- ...QuoteFields
26027
+ const mutation$3 = t(`
26028
+ mutation QuoteChangeCreate($quoteId: ID!, $priceListId: ID!, $parentQuoteChangeId: ID!) {
26029
+ quoteChangeCreate(
26030
+ quoteId: $quoteId
26031
+ priceListId: $priceListId
26032
+ parentQuoteChangeId: $parentQuoteChangeId
26033
+ ) {
26034
+ errors
26035
+ quoteChange {
26036
+ id
26037
+ quote {
26038
+ ...QuoteContext_QuoteFragment
26039
+ }
26040
+ }
25887
26041
  }
25888
26042
  }
25889
- }
25890
- }
25891
- `;
26043
+ `, [QuoteContext_QuoteFragment]);
25892
26044
  const quoteChangeCreate = async ({ parentQuoteChangeId, priceListId, apiHost, token, quoteId, }) => {
25893
- var _a;
25894
- const vars = {
25895
- parentQuoteChangeId,
25896
- priceListId,
25897
- quoteId,
25898
- };
25899
- const response = await gqlRequest({
25900
- query: QUOTE_CHANGE_CREATE,
25901
- token,
25902
- vars,
25903
- apiHost,
25904
- });
25905
- const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteChangeCreate) === null || _a === void 0 ? void 0 : _a.errors;
25906
- if (errors)
25907
- throw errors;
26045
+ const response = await execute(mutation$3, { apiHost, token }, { parentQuoteChangeId, priceListId, quoteId });
25908
26046
  return response.quoteChangeCreate;
25909
26047
  };
25910
26048
 
25911
- const QUOTE_CHANGE_DELETE = `
25912
- ${QUOTE_FIELDS()}
25913
- mutation QuoteChangeDelete($id: ID!) {
25914
- quoteChangeDelete(id: $id) {
25915
- errors
25916
- quoteChange {
25917
- quote {
25918
- ...QuoteFields
26049
+ const mutation$2 = t(`
26050
+ mutation QuoteChangeDelete($id: ID!) {
26051
+ quoteChangeDelete(id: $id) {
26052
+ errors
26053
+ quoteChange {
26054
+ quote {
26055
+ ...QuoteContext_QuoteFragment
26056
+ }
25919
26057
  }
25920
26058
  }
25921
26059
  }
25922
- }
25923
- `;
26060
+ `, [QuoteContext_QuoteFragment]);
25924
26061
  const quoteChangeDelete = async ({ id, apiHost, token, }) => {
25925
- var _a;
25926
- const vars = {
25927
- id,
25928
- };
25929
- const response = await gqlRequest({
25930
- query: QUOTE_CHANGE_DELETE,
25931
- token,
25932
- vars,
25933
- apiHost,
25934
- });
25935
- const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteChangeDelete) === null || _a === void 0 ? void 0 : _a.errors;
25936
- if (errors)
25937
- throw errors;
26062
+ const response = await execute(mutation$2, { apiHost, token }, { id });
25938
26063
  return response.quoteChangeDelete;
25939
26064
  };
25940
26065
 
25941
- const useToggleAddonPlan = (quote, addonPriceListId, selectedPriceList, setIsAddonPlanLoading) => {
26066
+ const useToggleAddonPlan = (maskedQuote, addonPriceListId, selectedPriceList, setIsAddonPlanLoading) => {
25942
26067
  const token = useToken();
25943
26068
  const isAdded = react.useRef(false);
25944
- const queryClient = reactQuery.useQueryClient();
25945
26069
  const { apiHost } = react.useContext(BunnyContext);
26070
+ const { setQuoteQueryData } = useSetQuoteQueryData();
26071
+ // Read fragments
26072
+ const quote = readFragment(useToggleAddonPlan_QuoteFragment, maskedQuote);
25946
26073
  const parentQuoteChange = react.useMemo(() => {
25947
- return quote === null || quote === void 0 ? void 0 : quote.quoteChanges.find(qc => qc.priceList.id === selectedPriceList.id);
26074
+ var _a;
26075
+ 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; });
25948
26076
  }, [quote, selectedPriceList]);
25949
26077
  const { mutate: addAddonQuoteChange, isPending: isAddingAddonQuoteChange } = reactQuery.useMutation({
25950
26078
  mutationFn: quoteChangeCreate,
25951
- onSuccess: (quoteChangeCreate) => {
26079
+ onSuccess: quoteChangeCreate => {
26080
+ var _a;
25952
26081
  isAdded.current = true;
25953
- const updatedQuote = quoteChangeCreate.quoteChange.quote;
25954
- queryClient.setQueryData(common.QueryKeyFactory.default.createObjectKey({
25955
- objectName: 'editingQuote',
25956
- id: quote === null || quote === void 0 ? void 0 : quote.id,
25957
- token,
25958
- }), updatedQuote);
26082
+ const updatedQuote = (_a = quoteChangeCreate === null || quoteChangeCreate === void 0 ? void 0 : quoteChangeCreate.quoteChange) === null || _a === void 0 ? void 0 : _a.quote;
26083
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
26084
+ throw new Error('Updated quote ID not found');
26085
+ }
26086
+ if (!updatedQuote) {
26087
+ throw new Error('Updated quote not found');
26088
+ }
26089
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, updatedQuote);
25959
26090
  },
25960
26091
  });
25961
26092
  const { mutate: deleteQuoteChange, isPending: isDeletingQuoteChange } = reactQuery.useMutation({
25962
26093
  mutationFn: quoteChangeDelete,
25963
- onSuccess: (quoteChangeDelete) => {
26094
+ onSuccess: quoteChangeDelete => {
26095
+ var _a;
25964
26096
  isAdded.current = false;
25965
- const updatedQuote = quoteChangeDelete.quoteChange.quote;
25966
- queryClient.setQueryData(common.QueryKeyFactory.default.createObjectKey({
25967
- objectName: 'editingQuote',
25968
- id: quote === null || quote === void 0 ? void 0 : quote.id,
25969
- token,
25970
- }), updatedQuote);
26097
+ const updatedQuote = (_a = quoteChangeDelete === null || quoteChangeDelete === void 0 ? void 0 : quoteChangeDelete.quoteChange) === null || _a === void 0 ? void 0 : _a.quote;
26098
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
26099
+ throw new Error('Updated quote ID not found');
26100
+ }
26101
+ if (!updatedQuote) {
26102
+ throw new Error('Updated quote not found');
26103
+ }
26104
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, updatedQuote);
25971
26105
  },
25972
26106
  });
25973
26107
  function handleAddAddonQuoteChange() {
@@ -25977,6 +26111,9 @@ const useToggleAddonPlan = (quote, addonPriceListId, selectedPriceList, setIsAdd
25977
26111
  if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
25978
26112
  throw new Error('Quote ID not found');
25979
26113
  }
26114
+ if (!parentQuoteChange.id) {
26115
+ throw new Error('Parent quote change ID not found');
26116
+ }
25980
26117
  addAddonQuoteChange({
25981
26118
  parentQuoteChangeId: parentQuoteChange.id,
25982
26119
  priceListId: addonPriceListId,
@@ -25986,9 +26123,10 @@ const useToggleAddonPlan = (quote, addonPriceListId, selectedPriceList, setIsAdd
25986
26123
  });
25987
26124
  }
25988
26125
  function handleDeleteQuoteChange() {
25989
- const quoteChange = quote === null || quote === void 0 ? void 0 : quote.quoteChanges.find(qc => qc.priceList.id === addonPriceListId);
25990
- if (!quoteChange) {
25991
- throw new Error('Quote change not found');
26126
+ var _a;
26127
+ 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; });
26128
+ if (!(quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.id)) {
26129
+ throw new Error('Quote change ID not found');
25992
26130
  }
25993
26131
  deleteQuoteChange({
25994
26132
  id: quoteChange.id,
@@ -26022,6 +26160,7 @@ const AddonPlanRow_PriceListFragment = t(`
26022
26160
  plan {
26023
26161
  description
26024
26162
  name
26163
+ pricingDescription
26025
26164
  }
26026
26165
  ...PriceListCardPriceDescription_PriceListFragment
26027
26166
  ...PriceListCardPrice_PriceListFragment
@@ -26035,16 +26174,18 @@ const AddonPlanRow_PriceListFragment = t(`
26035
26174
  PriceListCardPriceDescription_PriceListFragment,
26036
26175
  ]);
26037
26176
  function AddonPlanRow({ addonPriceList: maskedAddonPriceList, selectedPriceList, onClickSelect, isPurchased, }) {
26038
- var _a, _b, _c, _d, _e, _f;
26177
+ var _a, _b, _c, _d, _e, _f, _g;
26039
26178
  // Read fragments
26040
26179
  const addonPriceList = readFragment(AddonPlanRow_PriceListFragment, maskedAddonPriceList);
26041
- const { quote, setIsAddonPlanLoading } = react.useContext(QuoteContext);
26180
+ const { quote: maskedQuote, setIsAddonPlanLoading } = react.useContext(QuoteContext);
26181
+ const quote = readFragment(AddonPlanRow_QuoteFragment, maskedQuote);
26042
26182
  const { shadow, isInPreviewMode } = react.useContext(SubscriptionsContext);
26043
26183
  const { isPending, addedQuoteChange, addAddonQuoteChange, deleteQuoteChange } = useToggleAddonPlan(quote, addonPriceList.id, selectedPriceList, setIsAddonPlanLoading);
26044
26184
  const activeCharge = (_a = getActivePlanPriceData(addonPriceList, selectedPriceList)) === null || _a === void 0 ? void 0 : _a.activeCharge;
26045
26185
  // Derived state
26046
26186
  const switchDisabled = isInPreviewMode || isPurchased;
26047
- return (jsxRuntime.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: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2 bunny-items-center", children: [jsxRuntime.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 }), jsxRuntime.jsx(PriceListCardDescription, { description: (_d = (_c = addonPriceList.plan) === null || _c === void 0 ? void 0 : _c.description) !== null && _d !== void 0 ? _d : '' }), jsxRuntime.jsx(PriceListCardPrice, { priceList: addonPriceList, className: "bunny-text-sm bunny-font-medium bunny-text-gray-900" }), jsxRuntime.jsx(PriceListCardPriceDescription, { feature: activeCharge === null || activeCharge === void 0 ? void 0 : activeCharge.feature, priceList: addonPriceList }), jsxRuntime.jsx(antd.Button, { type: "link", onClick: onClickSelect, children: jsxRuntime.jsx(icons.InfoCircleOutlined, {}) })] }), jsxRuntime.jsx(antd.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) => {
26187
+ const hasCustomPrice = ((_b = addonPriceList.plan) === null || _b === void 0 ? void 0 : _b.pricingDescription) != null;
26188
+ return (jsxRuntime.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: [jsxRuntime.jsxs("div", { className: "bunny-flex bunny-flex-row bunny-gap-2 bunny-items-center", children: [jsxRuntime.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 }), jsxRuntime.jsx(PriceListCardDescription, { description: (_e = (_d = addonPriceList.plan) === null || _d === void 0 ? void 0 : _d.description) !== null && _e !== void 0 ? _e : '' }), !hasCustomPrice && (jsxRuntime.jsx(PriceListCardPrice, { priceList: addonPriceList, className: "bunny-text-sm bunny-font-medium bunny-text-gray-900" })), jsxRuntime.jsx(PriceListCardPriceDescription, { feature: activeCharge === null || activeCharge === void 0 ? void 0 : activeCharge.feature, priceList: addonPriceList }), jsxRuntime.jsx(antd.Button, { type: "link", onClick: onClickSelect, children: jsxRuntime.jsx(icons.InfoCircleOutlined, {}) })] }), jsxRuntime.jsx(antd.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) => {
26048
26189
  if (checked) {
26049
26190
  addAddonQuoteChange();
26050
26191
  }
@@ -26068,7 +26209,7 @@ const AddonPlans_PlanFragment = t(`
26068
26209
  }
26069
26210
  `, [AddonPlanModal_PriceListFragment, AddonPlanRow_PriceListFragment]);
26070
26211
 
26071
- const query = t(`
26212
+ const query$2 = t(`
26072
26213
  query PriceList($id: ID!) {
26073
26214
  priceList(id: $id) {
26074
26215
  addonPlans {
@@ -26082,7 +26223,7 @@ const query = t(`
26082
26223
  `, [AddonPlans_PlanFragment]);
26083
26224
  const getAddonPlans = async ({ token, id, apiHost, }) => {
26084
26225
  var _a;
26085
- const response = await execute(query, { apiHost, token }, { id });
26226
+ const response = await execute(query$2, { apiHost, token }, { id });
26086
26227
  const addonPlans = (_a = response === null || response === void 0 ? void 0 : response.priceList) === null || _a === void 0 ? void 0 : _a.addonPlans;
26087
26228
  // for each addon plan, filter out the price lists that are not visible
26088
26229
  const visibleAddonPlans = addonPlans === null || addonPlans === void 0 ? void 0 : addonPlans.map(addonPlan => {
@@ -26190,7 +26331,10 @@ const PriceListGrid = ({ availablePriceLists, priceListChangeOptions, priceListS
26190
26331
  onClickPriceListCard: onClickPriceListCard })) : (jsxRuntime.jsx(PriceListGridDesktop, { availablePriceLists: availablePriceLists, priceListChangeOptions: priceListChangeOptions, priceListStart: priceListStart, selectedPriceList: selectedPriceList, selectedProduct: selectedProduct, setPriceListStart: setPriceListStart, subscriptions: subscriptions, trialRemainingDays: trialRemainingDays, selectedBillingPeriod: selectedBillingPeriod, onClickPriceListCard: onClickPriceListCard }));
26191
26332
  };
26192
26333
 
26193
- const createAvailableBillingPeriods = (priceLists, selectedProduct) => {
26334
+ const createAvailableBillingPeriods = (priceLists, selectedProduct, upgradingSubscription) => {
26335
+ if ((upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.plan.addon) === true) {
26336
+ return [upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.periodMonths];
26337
+ }
26194
26338
  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));
26195
26339
  };
26196
26340
  const showInfoNotification$1 = common.useInfoNotification();
@@ -26204,11 +26348,18 @@ const PriceListSelector = ({ arePlanChangeOptionsLoading, areSubscriptionsLoadin
26204
26348
  const [selectedBillingPeriod, setSelectedBillingPeriod] = react.useState(null);
26205
26349
  const [priceListStart, setPriceListStart] = react.useState(0);
26206
26350
  // Derived state
26207
- const availableBillingPeriods = react.useMemo(() => createAvailableBillingPeriods(priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, selectedProduct), [priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, selectedProduct]);
26351
+ const availableBillingPeriods = react.useMemo(() => createAvailableBillingPeriods(priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, selectedProduct, upgradingSubscription), [priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, selectedProduct]);
26352
+ // TODO: clean up available pricelists calculation. We should calculate it once, not three times.
26353
+ const subscriptionIsAddon = (upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.plan.addon) === true;
26208
26354
  const availablePriceLists = react.useMemo(() => {
26209
26355
  var _a;
26210
- return (((_a = priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists) === null || _a === void 0 ? void 0 : _a.filter(priceList => periodMonthsConverter(priceList.periodMonths) === selectedBillingPeriod &&
26211
- priceList.product.id === (selectedProduct === null || selectedProduct === void 0 ? void 0 : selectedProduct.id)).filter(priceList => priceList.plan.addon !== true)) || []);
26356
+ 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 &&
26357
+ priceList.product.id === (selectedProduct === null || selectedProduct === void 0 ? void 0 : selectedProduct.id));
26358
+ // If the subscription is an addon, we should only show its price lists because we don't support changing add-on plans.
26359
+ if (subscriptionIsAddon) {
26360
+ 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))) || []);
26361
+ }
26362
+ return priceLists.filter(priceList => priceList.plan.addon !== true) || [];
26212
26363
  }, [priceListChangeOptions, selectedBillingPeriod, selectedProduct]);
26213
26364
  // Handlers
26214
26365
  const onChangeBillingPeriod = react.useCallback((billingPeriod) => {
@@ -26237,7 +26388,7 @@ const PriceListSelector = ({ arePlanChangeOptionsLoading, areSubscriptionsLoadin
26237
26388
  }
26238
26389
  }, [selectedPriceList, priceListChangeOptions, upgradingSubscription]);
26239
26390
  const onChangeProduct = react.useCallback((product) => {
26240
- const newAvailableBillingPeriods = createAvailableBillingPeriods(priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, product);
26391
+ const newAvailableBillingPeriods = createAvailableBillingPeriods(priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, product, upgradingSubscription);
26241
26392
  if (selectedBillingPeriod &&
26242
26393
  !(newAvailableBillingPeriods === null || newAvailableBillingPeriods === void 0 ? void 0 : newAvailableBillingPeriods.includes(billingPeriodConverter(selectedBillingPeriod)))) {
26243
26394
  onChangeBillingPeriod(periodMonthsConverter((newAvailableBillingPeriods === null || newAvailableBillingPeriods === void 0 ? void 0 : newAvailableBillingPeriods[0]) !== undefined ? newAvailableBillingPeriods[0] : 1));
@@ -26248,7 +26399,7 @@ const PriceListSelector = ({ arePlanChangeOptionsLoading, areSubscriptionsLoadin
26248
26399
  const initialProduct = (_a = priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.products) === null || _a === void 0 ? void 0 : _a[0];
26249
26400
  const initialBillingPeriod = react.useMemo(() => {
26250
26401
  var _a, _b, _c;
26251
- const initialAvailableBillingPeriods = createAvailableBillingPeriods(priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, initialProduct);
26402
+ const initialAvailableBillingPeriods = createAvailableBillingPeriods(priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, initialProduct, upgradingSubscription);
26252
26403
  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);
26253
26404
  if ((upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList) &&
26254
26405
  periodMonthsConverted &&
@@ -26904,80 +27055,177 @@ const PageSubTitle = ({ title }) => {
26904
27055
  return (jsxRuntime.jsx("div", { className: "bunny-shrink-0", style: { color: secondaryColor }, children: title }));
26905
27056
  };
26906
27057
 
26907
- const MUTATION = `
26908
- mutation BillingDetailsUpdate(
26909
- $attributes: BillingDetailsAttributes!) {
26910
- billingDetailsUpdate(
26911
- attributes: $attributes
26912
- ) {
26913
- billingDetails {
26914
- billingCity
26915
- billingContact {
26916
- email
27058
+ const AccountContactsFragment = t(`
27059
+ fragment AccountContactsFragment on Contact {
27060
+ id
27061
+ email
27062
+ firstName
27063
+ }
27064
+ `, []);
27065
+
27066
+ const AddContactButton = ({ onClick }) => {
27067
+ return (jsxRuntime.jsx("div", { className: "bunny-border-t bunny-border-gray-200 bunny-p-2", children: jsxRuntime.jsx(antd.Button, { type: "text", className: "bunny-w-full bunny-text-left", onClick: onClick, children: "+ Add new contact" }) }));
27068
+ };
27069
+
27070
+ const useSetAccountContactsQueryData = () => {
27071
+ const token = useToken();
27072
+ const queryClient = reactQuery.useQueryClient();
27073
+ const setAccountContactsQueryData = (accountId, updater) => {
27074
+ queryClient.setQueryData(QueryKeyFactory.accountContactsKey({ accountId, token }), updater);
27075
+ };
27076
+ return { setAccountContactsQueryData };
27077
+ };
27078
+
27079
+ const mutation$1 = t(`
27080
+ mutation ContactCreate($attributes: ContactAttributes!) {
27081
+ contactCreate(attributes: $attributes) {
27082
+ contact {
27083
+ id
27084
+ account {
27085
+ contacts {
27086
+ ...AccountContactsFragment
27087
+ }
26917
27088
  }
26918
- billingCountry
26919
- billingState
26920
- billingStreet
26921
- billingZip
26922
- name
26923
- taxNumber
26924
27089
  }
26925
27090
  errors
26926
27091
  }
26927
- }
26928
- `;
26929
- const billingDetailsUpdate = async ({ attributes, token, apiHost, }) => {
26930
- var _a;
26931
- const vars = { attributes };
26932
- const response = await gqlRequest({
26933
- query: MUTATION,
26934
- token,
26935
- vars,
26936
- apiHost,
27092
+ }
27093
+ `, [AccountContactsFragment]);
27094
+ const contactCreate = async ({ attributes, apiHost, token }) => {
27095
+ var _a, _b;
27096
+ const response = await execute(mutation$1, { apiHost, token }, { attributes });
27097
+ if ((_a = response.contactCreate) === null || _a === void 0 ? void 0 : _a.errors) {
27098
+ throw new Error(response.contactCreate.errors[0]);
27099
+ }
27100
+ return (_b = response.contactCreate) === null || _b === void 0 ? void 0 : _b.contact;
27101
+ };
27102
+
27103
+ const AddContactModal = ({ open, onClose, accountId, onContactCreated, }) => {
27104
+ const [form] = antd.Form.useForm();
27105
+ const { apiHost } = react.useContext(BunnyContext);
27106
+ const token = useToken();
27107
+ const showErrorNotification = common.useErrorNotification();
27108
+ const showSuccessNotification = common.useSuccessNotification();
27109
+ const { setAccountContactsQueryData } = useSetAccountContactsQueryData();
27110
+ const { mutate: createContact, isPending: isCreatingContact } = reactQuery.useMutation({
27111
+ mutationFn: (attributes) => contactCreate({ attributes, apiHost, token }),
27112
+ onSuccess: newContact => {
27113
+ var _a, _b;
27114
+ showSuccessNotification('Contact created successfully');
27115
+ // Add the new contact to the cache
27116
+ if (newContact && accountId) {
27117
+ 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);
27118
+ }
27119
+ onClose();
27120
+ form.resetFields();
27121
+ const newContactData = newContact ? readFragment(AccountContactsFragment, newContact) : null;
27122
+ if (newContactData === null || newContactData === void 0 ? void 0 : newContactData.id) {
27123
+ onContactCreated === null || onContactCreated === void 0 ? void 0 : onContactCreated(newContactData.id);
27124
+ }
27125
+ },
26937
27126
  });
26938
- const errors = (_a = response === null || response === void 0 ? void 0 : response.billingDetailsUpdate) === null || _a === void 0 ? void 0 : _a.errors;
26939
- if (errors)
26940
- throw errors;
26941
- return response.billingDetailsUpdate;
27127
+ const handleAddContact = () => {
27128
+ if (!accountId) {
27129
+ showErrorNotification('Account ID is required to create a contact');
27130
+ return;
27131
+ }
27132
+ form.validateFields().then(values => {
27133
+ createContact({
27134
+ email: values.email || null,
27135
+ firstName: values.firstName || null,
27136
+ lastName: values.lastName || null,
27137
+ accountId: accountId,
27138
+ portalAccess: true,
27139
+ });
27140
+ });
27141
+ };
27142
+ return (jsxRuntime.jsx(antd.Modal, { title: "Add new contact", open: open, onCancel: () => {
27143
+ onClose();
27144
+ form.resetFields();
27145
+ }, footer: [
27146
+ jsxRuntime.jsx(antd.Button, { onClick: () => {
27147
+ onClose();
27148
+ form.resetFields();
27149
+ }, children: "Cancel" }, "cancel"),
27150
+ jsxRuntime.jsx(antd.Button, { type: "primary", loading: isCreatingContact, onClick: handleAddContact, children: "Add contact" }, "submit"),
27151
+ ], children: jsxRuntime.jsxs(antd.Form, { form: form, layout: "vertical", className: "bunny-flex bunny-flex-col bunny-gap-2", children: [jsxRuntime.jsx(antd.Form.Item, { label: "First name", name: "firstName", rules: [{ required: false }], children: jsxRuntime.jsx(antd.Input, { placeholder: "Enter first name" }) }), jsxRuntime.jsx(antd.Form.Item, { label: "Last name", name: "lastName", rules: [{ required: false }], children: jsxRuntime.jsx(antd.Input, { placeholder: "Enter last name" }) }), jsxRuntime.jsx(antd.Form.Item, { label: "Email", name: "email", rules: [
27152
+ { required: true, message: 'Email is required' },
27153
+ { type: 'email', message: 'Please enter a valid email' },
27154
+ ], children: jsxRuntime.jsx(antd.Input, { placeholder: "Enter email" }) })] }) }));
26942
27155
  };
26943
27156
 
26944
- const billingDetailsQuery = () => `
26945
- query BillingDetails {
26946
- billingDetails {
26947
- billingCity
26948
- billingContact {
26949
- email
26950
- }
26951
- billingCountry
26952
- billingState
26953
- billingStreet
26954
- billingZip
26955
- name
26956
- taxNumber
26957
- currency {
27157
+ const BillingDetailsSection_AccountFragment = t(`
27158
+ fragment BillingDetailsSection_AccountFragment on Account {
26958
27159
  id
27160
+ name
27161
+ billingStreet
27162
+ billingCity
27163
+ billingState
27164
+ billingZip
27165
+ billingCountry
27166
+ taxNumber
27167
+ billingContactId
27168
+ secondaryBillingContactIds
27169
+ billingContact {
27170
+ email
27171
+ firstName
27172
+ }
26959
27173
  }
26960
- }
26961
- }`;
26962
- const getBillingDetails = async ({ token, apiHost }) => {
27174
+ `, []);
27175
+
27176
+ const mutation = t(`
27177
+ mutation AccountUpdate($id: ID!, $attributes: AccountAttributes!) {
27178
+ accountUpdate(id: $id, attributes: $attributes) {
27179
+ account {
27180
+ ...BillingDetailsSection_AccountFragment
27181
+ }
27182
+ errors
27183
+ }
27184
+ }
27185
+ `, [BillingDetailsSection_AccountFragment]);
27186
+ const accountUpdate = async ({ accountId, attributes, apiHost, token, }) => {
26963
27187
  var _a;
26964
- const response = await gqlRequest({
26965
- query: billingDetailsQuery(),
26966
- token,
26967
- apiHost,
26968
- });
26969
- if (response === null || response === void 0 ? void 0 : response.errors) {
26970
- throw new Error((_a = response === null || response === void 0 ? void 0 : response.errors[0]) === null || _a === void 0 ? void 0 : _a.message);
27188
+ const response = await execute(mutation, { apiHost, token }, { id: accountId, attributes });
27189
+ return (_a = response.accountUpdate) === null || _a === void 0 ? void 0 : _a.account;
27190
+ };
27191
+
27192
+ const query$1 = t(`
27193
+ query GetAccount($id: ID!) {
27194
+ account(id: $id) {
27195
+ ...BillingDetailsSection_AccountFragment
27196
+ }
27197
+ }
27198
+ `, [BillingDetailsSection_AccountFragment]);
27199
+ const getAccount = async ({ accountId, apiHost, token, }) => {
27200
+ const response = await execute(query$1, { apiHost, token }, { id: accountId });
27201
+ return response.account;
27202
+ };
27203
+
27204
+ const query = t(`
27205
+ query GetAccountContacts($accountId: ID!) {
27206
+ account(id: $accountId) {
27207
+ id
27208
+ contacts {
27209
+ ...AccountContactsFragment
27210
+ }
27211
+ }
26971
27212
  }
26972
- return response === null || response === void 0 ? void 0 : response.billingDetails;
27213
+ `, [AccountContactsFragment]);
27214
+ const getAccountContacts = async ({ accountId, apiHost, token, }) => {
27215
+ var _a;
27216
+ const response = await execute(query, { apiHost, token }, { accountId });
27217
+ return (_a = response.account) === null || _a === void 0 ? void 0 : _a.contacts;
26973
27218
  };
26974
27219
 
26975
27220
  const { Text } = antd.Typography;
26976
27221
  function BillingDetailsSection({ hidePaymentMethodForm, countryListFilter, }) {
27222
+ var _a, _b, _c;
26977
27223
  // State
26978
27224
  const [isFormEdited, setIsFormEdited] = react.useState(false);
26979
27225
  const [form] = antd.Form.useForm();
26980
27226
  const values = antd.Form.useWatch([], form);
27227
+ const [isAddContactModalOpen, setIsAddContactModalOpen] = react.useState(false);
27228
+ const [contactFieldType, setContactFieldType] = react.useState(null);
26981
27229
  // Context
26982
27230
  const { apiHost } = react.useContext(BunnyContext);
26983
27231
  const token = useToken();
@@ -26986,14 +27234,37 @@ function BillingDetailsSection({ hidePaymentMethodForm, countryListFilter, }) {
26986
27234
  const queryClient = reactQuery.useQueryClient();
26987
27235
  const showErrorNotification = common.useErrorNotification();
26988
27236
  const showSuccessNotification = common.useSuccessNotification();
27237
+ const { currentUser } = useCurrentUserData(token);
27238
+ const accountId = (_a = currentUser === null || currentUser === void 0 ? void 0 : currentUser.account) === null || _a === void 0 ? void 0 : _a.id;
26989
27239
  // Queries
26990
- const { data: billingDetails, isLoading: isLoadingBillingDetails } = reactQuery.useQuery({
26991
- queryKey: common.QueryKeyFactory.default.billingDetailsKey({ token }),
26992
- queryFn: () => getBillingDetails({ token, apiHost }),
27240
+ const { data: maskedAccount, isLoading: isLoadingAccount } = reactQuery.useQuery({
27241
+ queryKey: QueryKeyFactory.accountBillingDetailsKey({ accountId, token }),
27242
+ queryFn: () => {
27243
+ if (!accountId) {
27244
+ throw new Error('Account ID is required');
27245
+ }
27246
+ return getAccount({ accountId, apiHost, token });
27247
+ },
27248
+ enabled: !!accountId,
27249
+ });
27250
+ const account = readFragment(BillingDetailsSection_AccountFragment, maskedAccount);
27251
+ const { data: contacts, isLoading: isLoadingContacts } = reactQuery.useQuery({
27252
+ queryKey: QueryKeyFactory.accountContactsKey({ accountId, token }),
27253
+ queryFn: () => {
27254
+ if (!accountId) {
27255
+ throw new Error('Account ID is required');
27256
+ }
27257
+ return getAccountContacts({ accountId, apiHost, token });
27258
+ },
27259
+ enabled: !!accountId,
26993
27260
  });
26994
- const { mutate: updateBillingDetails, isPending: isUpdatingBillingDetails } = reactQuery.useMutation({
27261
+ const { mutate: updateAccount, isPending: isUpdatingAccount } = reactQuery.useMutation({
26995
27262
  mutationFn: async (changedFormData) => {
26996
- const updatedBillingDetails = await billingDetailsUpdate({
27263
+ if (!accountId) {
27264
+ throw new Error('Account ID is required');
27265
+ }
27266
+ const updatedAccount = await accountUpdate({
27267
+ accountId,
26997
27268
  attributes: {
26998
27269
  name: changedFormData.name,
26999
27270
  billingStreet: changedFormData.billingStreet,
@@ -27001,77 +27272,92 @@ function BillingDetailsSection({ hidePaymentMethodForm, countryListFilter, }) {
27001
27272
  billingZip: changedFormData.billingZip,
27002
27273
  billingState: changedFormData.billingState,
27003
27274
  billingCountry: changedFormData.billingCountry,
27004
- billingContactEmail: changedFormData.billingContactEmail,
27005
27275
  taxNumber: changedFormData.taxNumber,
27276
+ billingContactId: changedFormData.billingContactId || null,
27277
+ secondaryBillingContactIds: Array.isArray(changedFormData.secondaryBillingContactIds)
27278
+ ? changedFormData.secondaryBillingContactIds
27279
+ : null,
27006
27280
  },
27007
27281
  token,
27008
27282
  apiHost,
27009
27283
  });
27010
- queryClient.setQueryData(common.QueryKeyFactory.default.billingDetailsKey({ token }), (old) => {
27011
- return {
27012
- ...old,
27013
- ...updatedBillingDetails.billingDetails,
27014
- };
27015
- });
27016
- return updatedBillingDetails;
27284
+ queryClient.setQueryData(QueryKeyFactory.accountBillingDetailsKey({ accountId, token }), updatedAccount);
27285
+ return updatedAccount;
27017
27286
  },
27018
27287
  onSuccess: () => {
27019
27288
  showSuccessNotification('Your account details have been saved');
27020
27289
  queryClient.invalidateQueries({
27021
- queryKey: common.QueryKeyFactory.default.taxationRequiredAccountFieldsKey({
27290
+ queryKey: QueryKeyFactory.taxationRequiredAccountFieldsKey({
27022
27291
  token,
27023
27292
  }),
27024
27293
  });
27025
27294
  },
27026
27295
  });
27027
- // Set form values when billing details are loaded
27296
+ // Set form values when account is loaded
27028
27297
  react.useEffect(() => {
27029
- var _a;
27030
- if (billingDetails) {
27298
+ if (account) {
27031
27299
  form.setFieldsValue({
27032
- billingStreet: billingDetails.billingStreet,
27033
- billingCity: billingDetails.billingCity,
27034
- billingZip: billingDetails.billingZip,
27035
- billingState: billingDetails.billingState,
27036
- billingCountry: billingDetails.billingCountry,
27037
- billingContactEmail: (_a = billingDetails.billingContact) === null || _a === void 0 ? void 0 : _a.email,
27038
- taxNumber: billingDetails.taxNumber,
27300
+ billingStreet: account.billingStreet,
27301
+ billingCity: account.billingCity,
27302
+ billingZip: account.billingZip,
27303
+ billingState: account.billingState,
27304
+ billingCountry: account.billingCountry,
27305
+ billingContactId: account.billingContactId,
27306
+ secondaryBillingContactIds: account.secondaryBillingContactIds,
27307
+ taxNumber: account.taxNumber,
27039
27308
  });
27040
27309
  }
27041
- }, [billingDetails]);
27310
+ }, [account]);
27042
27311
  react.useEffect(() => {
27043
27312
  form.validateFields({ validateOnly: true });
27044
27313
  const isFormEdited = () => {
27045
- var _a;
27046
- if (!billingDetails)
27314
+ if (!account)
27047
27315
  return false;
27048
27316
  const currentValues = form.getFieldsValue();
27049
27317
  const accountValues = {
27050
- billingStreet: billingDetails.billingStreet,
27051
- billingCity: billingDetails.billingCity,
27052
- billingZip: billingDetails.billingZip,
27053
- billingState: billingDetails.billingState,
27054
- billingCountry: billingDetails.billingCountry,
27055
- billingContactEmail: (_a = billingDetails.billingContact) === null || _a === void 0 ? void 0 : _a.email,
27056
- taxNumber: billingDetails.taxNumber,
27318
+ billingStreet: account.billingStreet,
27319
+ billingCity: account.billingCity,
27320
+ billingZip: account.billingZip,
27321
+ billingState: account.billingState,
27322
+ billingCountry: account.billingCountry,
27323
+ billingContactId: account.billingContactId,
27324
+ secondaryBillingContactIds: account.secondaryBillingContactIds,
27325
+ taxNumber: account.taxNumber,
27057
27326
  };
27058
- return Object.keys(currentValues).some(key => {
27327
+ return Object.keys(accountValues).some(key => {
27059
27328
  const value = accountValues[key];
27060
- return currentValues[key] !== value;
27329
+ const currentValue = currentValues[key];
27330
+ // Handle array comparison for secondaryBillingContactIds
27331
+ if (Array.isArray(value) && Array.isArray(currentValue)) {
27332
+ return JSON.stringify(value === null || value === void 0 ? void 0 : value.sort()) !== JSON.stringify(currentValue === null || currentValue === void 0 ? void 0 : currentValue.sort());
27333
+ }
27334
+ return currentValue !== value;
27061
27335
  });
27062
27336
  };
27063
27337
  setIsFormEdited(isFormEdited());
27064
- }, [form, values, billingDetails]);
27338
+ }, [form, values, account]);
27065
27339
  // Validate form fields when isFormEdited changes
27066
27340
  react.useEffect(() => {
27067
27341
  const validateOnly = isFormEdited ? false : true;
27068
27342
  form.validateFields({ validateOnly: validateOnly });
27069
27343
  }, [isFormEdited]);
27344
+ const handleContactCreated = (contactId) => {
27345
+ if (contactFieldType === 'primary') {
27346
+ form.setFieldValue('billingContactId', contactId);
27347
+ }
27348
+ else if (contactFieldType === 'secondary') {
27349
+ const currentSecondaryContacts = form.getFieldValue('secondaryBillingContactIds') || [];
27350
+ if (!currentSecondaryContacts.includes(contactId)) {
27351
+ form.setFieldValue('secondaryBillingContactIds', [...currentSecondaryContacts, contactId]);
27352
+ }
27353
+ }
27354
+ setContactFieldType(null);
27355
+ };
27070
27356
  const saveBillingDetails = async () => {
27071
27357
  form.validateFields({ validateOnly: false }).then(async () => {
27072
27358
  try {
27073
27359
  await form.validateFields();
27074
- updateBillingDetails(form.getFieldsValue());
27360
+ updateAccount(form.getFieldsValue());
27075
27361
  }
27076
27362
  catch (error) {
27077
27363
  if (error instanceof Error) {
@@ -27089,21 +27375,38 @@ function BillingDetailsSection({ hidePaymentMethodForm, countryListFilter, }) {
27089
27375
  const filteredCountryList = react.useMemo(() => {
27090
27376
  return countryListFilter ? common.Lists.COUNTRY_LIST.filter(countryListFilter) : common.Lists.COUNTRY_LIST;
27091
27377
  }, [countryListFilter]);
27092
- return (jsxRuntime.jsx("div", { className: `${isMobile || hidePaymentMethodForm ? 'bunny-w-full' : 'bunny-w-1/2'}`, children: jsxRuntime.jsxs("div", { className: "bunny-px-4", children: [jsxRuntime.jsxs(antd.Skeleton, { loading: isLoadingBillingDetails, children: [jsxRuntime.jsx("div", { className: "bunny-mb-2 bunny-pl-1", children: jsxRuntime.jsx(Text, { className: "bunny-font-medium bunny-text-lg", children: (billingDetails === null || billingDetails === void 0 ? void 0 : billingDetails.name) || 'No company name' }) }), jsxRuntime.jsxs(antd.Form, { className: "bunny-flex bunny-flex-col bunny-gap-2", form: form, layout: "vertical", disabled: isUpdatingBillingDetails, autoComplete: "off", requiredMark: false, children: [jsxRuntime.jsx(antd.Form.Item, { label: "Street address", name: "billingStreet", rules: [{ required: true, message: 'Street address is required' }], children: jsxRuntime.jsx(antd.Input, {}) }), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-gap-4", children: [jsxRuntime.jsx(antd.Form.Item, { label: "City", name: "billingCity", rules: [{ required: true, message: 'City is required' }], className: "bunny-flex-1", children: jsxRuntime.jsx(antd.Input, {}) }), jsxRuntime.jsx(antd.Form.Item, { label: "Zipcode", name: "billingZip", rules: [{ required: true, message: 'Zipcode is required' }], className: "bunny-flex-1", children: jsxRuntime.jsx(antd.Input, {}) })] }), jsxRuntime.jsxs("div", { className: `bunny-flex ${isMobile ? 'bunny-flex-row bunny-pb-2' : 'bunny-flex-row'} bunny-gap-4`, children: [jsxRuntime.jsx("div", { className: "bunny-flex-1 bunny-w-1/2", children: jsxRuntime.jsx(antd.Form.Item, { label: "State", name: "billingState", rules: [
27093
- {
27094
- required: false,
27095
- },
27096
- ], children: jsxRuntime.jsx(antd.Input, {}) }) }), jsxRuntime.jsx("div", { className: "bunny-flex-1 bunny-w-1/2", children: jsxRuntime.jsx(antd.Form.Item, { label: "Country", name: "billingCountry", rules: [{ required: true, message: 'Country is required' }], children: jsxRuntime.jsx(antd.Select, { className: "bunny-w-full", options: filteredCountryList, placeholder: "Select a country", popupMatchSelectWidth: false, showSearch: true, filterOption: (input, option) => {
27097
- var _a, _b;
27098
- return ((_a = option === null || option === void 0 ? void 0 : option.label) !== null && _a !== void 0 ? _a : '').toLowerCase().includes(input.toLowerCase()) ||
27099
- ((_b = option === null || option === void 0 ? void 0 : option.value) !== null && _b !== void 0 ? _b : '').toLowerCase().includes(input.toLowerCase());
27100
- } }) }) })] }), jsxRuntime.jsx(antd.Form.Item, { label: "Email", name: "billingContactEmail", rules: [
27101
- {
27102
- required: true,
27103
- message: 'Email is required',
27104
- type: 'email',
27105
- },
27106
- ], children: jsxRuntime.jsx(antd.Input, {}) }), jsxRuntime.jsx(antd.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: jsxRuntime.jsx(antd.Input, {}) })] })] }), jsxRuntime.jsx(antd.Button, { disabled: !isFormEdited || isUpdatingBillingDetails, className: "bunny-w-full bunny-mt-4", type: "primary", onClick: saveBillingDetails, children: "Save" })] }) }));
27378
+ const isLoading = isLoadingAccount || isLoadingContacts;
27379
+ return (jsxRuntime.jsxs("div", { className: `${isMobile || hidePaymentMethodForm ? 'bunny-w-full' : 'bunny-w-1/2'}`, children: [jsxRuntime.jsxs("div", { className: "bunny-px-4", children: [jsxRuntime.jsxs(antd.Skeleton, { loading: isLoading || account === undefined, children: [jsxRuntime.jsx("div", { className: "bunny-mb-2 bunny-pl-1", children: jsxRuntime.jsx(Text, { className: "bunny-font-medium bunny-text-lg", children: (account === null || account === void 0 ? void 0 : account.name) || 'No company name' }) }), jsxRuntime.jsxs(antd.Form, { className: "bunny-flex bunny-flex-col bunny-gap-2", form: form, layout: "vertical", disabled: isUpdatingAccount, autoComplete: "off", requiredMark: false, children: [jsxRuntime.jsx(antd.Form.Item, { label: "Street address", name: "billingStreet", rules: [{ required: true, message: 'Street address is required' }], children: jsxRuntime.jsx(antd.Input, {}) }), jsxRuntime.jsxs("div", { className: "bunny-flex bunny-gap-4", children: [jsxRuntime.jsx(antd.Form.Item, { label: "City", name: "billingCity", rules: [{ required: true, message: 'City is required' }], className: "bunny-flex-1", children: jsxRuntime.jsx(antd.Input, {}) }), jsxRuntime.jsx(antd.Form.Item, { label: "Zipcode", name: "billingZip", rules: [{ required: true, message: 'Zipcode is required' }], className: "bunny-flex-1", children: jsxRuntime.jsx(antd.Input, {}) })] }), jsxRuntime.jsxs("div", { className: `bunny-flex ${isMobile ? 'bunny-flex-row bunny-pb-2' : 'bunny-flex-row'} bunny-gap-4`, children: [jsxRuntime.jsx("div", { className: "bunny-flex-1 bunny-w-1/2", children: jsxRuntime.jsx(antd.Form.Item, { label: "State", name: "billingState", rules: [
27380
+ {
27381
+ required: false,
27382
+ },
27383
+ ], children: jsxRuntime.jsx(antd.Input, {}) }) }), jsxRuntime.jsx("div", { className: "bunny-flex-1 bunny-w-1/2", children: jsxRuntime.jsx(antd.Form.Item, { label: "Country", name: "billingCountry", rules: [{ required: true, message: 'Country is required' }], children: jsxRuntime.jsx(antd.Select, { className: "bunny-w-full", options: filteredCountryList, placeholder: "Select a country", popupMatchSelectWidth: false, showSearch: true, filterOption: (input, option) => {
27384
+ var _a, _b;
27385
+ return ((_a = option === null || option === void 0 ? void 0 : option.label) !== null && _a !== void 0 ? _a : '').toLowerCase().includes(input.toLowerCase()) ||
27386
+ ((_b = option === null || option === void 0 ? void 0 : option.value) !== null && _b !== void 0 ? _b : '').toLowerCase().includes(input.toLowerCase());
27387
+ } }) }) })] }), jsxRuntime.jsx(antd.Form.Item, { label: "Primary billing contact", name: "billingContactId", rules: [{ required: true, message: 'Primary billing contact is required' }], children: jsxRuntime.jsx(antd.Select, { className: "bunny-w-full", placeholder: "Select a contact", options: (_b = contacts === null || contacts === void 0 ? void 0 : contacts.map(contact => {
27388
+ const contactData = readFragment(AccountContactsFragment, contact);
27389
+ return {
27390
+ label: (contactData === null || contactData === void 0 ? void 0 : contactData.firstName)
27391
+ ? `${contactData.firstName}`
27392
+ : contactData === null || contactData === void 0 ? void 0 : contactData.email,
27393
+ value: contactData === null || contactData === void 0 ? void 0 : contactData.id,
27394
+ };
27395
+ })) !== null && _b !== void 0 ? _b : [], popupRender: menu => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [menu, jsxRuntime.jsx(AddContactButton, { onClick: () => setIsAddContactModalOpen(true) })] })) }) }), jsxRuntime.jsx(antd.Form.Item, { label: "Secondary billing contacts", name: "secondaryBillingContactIds", children: jsxRuntime.jsx(antd.Select, { className: "bunny-w-full", mode: "multiple", maxTagCount: "responsive", placeholder: "Select contacts", options: (_c = contacts === null || contacts === void 0 ? void 0 : contacts.map(contact => {
27396
+ const contactData = readFragment(AccountContactsFragment, contact);
27397
+ return {
27398
+ label: (contactData === null || contactData === void 0 ? void 0 : contactData.firstName)
27399
+ ? `${contactData.firstName}`
27400
+ : contactData === null || contactData === void 0 ? void 0 : contactData.email,
27401
+ value: contactData === null || contactData === void 0 ? void 0 : contactData.id,
27402
+ };
27403
+ })) !== null && _c !== void 0 ? _c : [], popupRender: menu => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [menu, jsxRuntime.jsx(AddContactButton, { onClick: () => {
27404
+ setContactFieldType('secondary');
27405
+ setIsAddContactModalOpen(true);
27406
+ } })] })) }) }), jsxRuntime.jsx(antd.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: jsxRuntime.jsx(antd.Input, {}) })] })] }), jsxRuntime.jsx(antd.Button, { disabled: !isFormEdited || isUpdatingAccount || isLoading, className: "bunny-w-full bunny-mt-4", type: "primary", onClick: saveBillingDetails, children: "Save" })] }), jsxRuntime.jsx(AddContactModal, { open: isAddContactModalOpen, onClose: () => {
27407
+ setIsAddContactModalOpen(false);
27408
+ setContactFieldType(null);
27409
+ }, accountId: accountId, onContactCreated: handleContactCreated })] }));
27107
27410
  }
27108
27411
 
27109
27412
  const BillingDetails = ({ className, countryListFilter, hideBillingDetailsForm = false, hidePaymentMethodForm = false, isCardEnabled = true, isUpgradeFromTrial = false, shadow = 'shadow-md', onSavePaymentMethod, }) => {