@bunnyapp/components 1.6.0 → 1.7.0-beta.2

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 +1204 -904
  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 +1206 -906
  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.1';
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,
@@ -19840,7 +19850,7 @@ 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;
19853
+ const { Text: Text$z } = antd.Typography;
19844
19854
  const handleAllErrorFormats = common.useAllErrorFormats();
19845
19855
  const TEST_CARD = '4242424242424242';
19846
19856
  const DemoPayForm = () => {
@@ -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
 
@@ -20768,14 +20780,14 @@ const AcceptQuoteModal = ({ acceptBoxVisible, formattedQuote, sendAccept, setAcc
20768
20780
  }, 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
20781
  };
20770
20782
 
20771
- const { Title: Title$2, Text: Text$w } = antd.Typography;
20783
+ const { Title: Title$2, Text: Text$x } = antd.Typography;
20772
20784
  const showSuccessNotification$2 = common.useSuccessNotification();
20773
20785
  const PaymentHoldModal = ({ visible, setVisible, quote, }) => {
20774
20786
  const queryClient = reactQuery.useQueryClient();
20775
20787
  const token = useToken();
20776
20788
  return (jsxRuntime.jsxs(StyledModal$2, { centered: true, onCancel: () => {
20777
20789
  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: {
20790
+ }, 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
20791
  amount: quote.amount,
20780
20792
  currencyId: quote.currency,
20781
20793
  id: quote.quote.id,
@@ -20825,7 +20837,7 @@ const StyledModal$2 = (props) => {
20825
20837
  return jsxRuntime.jsx(ModalOverrideBrandStylings, { closable: false, ...props });
20826
20838
  };
20827
20839
 
20828
- const { Text: Text$v } = antd.Typography;
20840
+ const { Text: Text$w } = antd.Typography;
20829
20841
  defaultStyled.div `
20830
20842
  Text {
20831
20843
  width: 100%;
@@ -20917,7 +20929,7 @@ function QuoteButtons({ isAccepted, formattedQuote, isMobile, hideDownloadButton
20917
20929
  const signingPlugins = useSigningPlugins({ apiHost, token });
20918
20930
  return (jsxRuntime.jsxs("div", { className: "flex flex-row justify-end items-center gap-4", id: "acceptance", style: {
20919
20931
  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
20932
+ }, 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
20933
  ? 'Quote is expired'
20922
20934
  : (signingPlugins === null || signingPlugins === void 0 ? void 0 : signingPlugins.length)
20923
20935
  ? 'Start signing'
@@ -21038,9 +21050,9 @@ const getColor = (state) => {
21038
21050
  }
21039
21051
  };
21040
21052
 
21041
- const { Text: Text$u } = antd.Typography;
21053
+ const { Text: Text$v } = antd.Typography;
21042
21054
  const TransactionDate = ({ date }) => {
21043
- return jsxRuntime.jsx(Text$u, { className: "bunny-text-sm", children: common.formatDate(date) });
21055
+ return jsxRuntime.jsx(Text$v, { className: "bunny-text-sm", children: common.formatDate(date) });
21044
21056
  };
21045
21057
 
21046
21058
  const ArrowDownToLine = ({ className, color = common.SLATE_600, }) => {
@@ -21084,13 +21096,13 @@ const TransactionGridCell = defaultStyled.div.withConfig({
21084
21096
  min-width: 48px;
21085
21097
  `;
21086
21098
 
21087
- const { Text: Text$t } = antd.Typography;
21099
+ const { Text: Text$u } = antd.Typography;
21088
21100
  const TransactionsEmptyState = () => {
21089
21101
  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' }));
21102
+ return (jsxRuntime.jsx(Text$u, { className: "bunny-flex bunny-justify-center bunny-p-4 bunny-text-base", children: noTransactionsMessage || 'There are no transactions' }));
21091
21103
  };
21092
21104
 
21093
- const { Text: Text$s } = antd.Typography;
21105
+ const { Text: Text$t } = antd.Typography;
21094
21106
  const isInvoice = (transaction) => {
21095
21107
  return transaction.kind === 'INVOICE';
21096
21108
  };
@@ -21098,7 +21110,7 @@ const TransactionRowTitle = ({ transaction }) => {
21098
21110
  if (!isInvoice(transaction)) {
21099
21111
  return jsxRuntime.jsx(jsxRuntime.Fragment, {});
21100
21112
  }
21101
- return (jsxRuntime.jsx(Text$s, { className: "bunny-text-slate-400", style: { fontSize: '11px' }, children: transaction.transactionable.number }));
21113
+ return (jsxRuntime.jsx(Text$t, { className: "bunny-text-slate-400", style: { fontSize: '11px' }, children: transaction.transactionable.number }));
21102
21114
  };
21103
21115
 
21104
21116
  function transactionDateToDisplay(transaction, transactionDateType) {
@@ -21116,7 +21128,7 @@ function transactionDateToDisplay(transaction, transactionDateType) {
21116
21128
  }
21117
21129
  }
21118
21130
 
21119
- const { Text: Text$r } = antd.Typography;
21131
+ const { Text: Text$s } = antd.Typography;
21120
21132
  const TransactionsListDesktop = ({ transactions, onTransactionClick, }) => {
21121
21133
  const { columns, transactionDateType } = react.useContext(TransactionsListContext);
21122
21134
  const { apiHost, darkMode } = react.useContext(BunnyContext);
@@ -21144,11 +21156,11 @@ const TransactionsListDesktop = ({ transactions, onTransactionClick, }) => {
21144
21156
  !showState &&
21145
21157
  !showAmount &&
21146
21158
  !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));
21159
+ !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
21160
  }) }));
21149
21161
  };
21150
21162
 
21151
- const { Text: Text$q } = antd.Typography;
21163
+ const { Text: Text$r } = antd.Typography;
21152
21164
  const TransactionsListMobile = ({ transactions, onTransactionClick, }) => {
21153
21165
  const { columns, transactionDateType } = react.useContext(TransactionsListContext);
21154
21166
  const { apiHost, darkMode } = react.useContext(BunnyContext);
@@ -21170,11 +21182,11 @@ const TransactionsListMobile = ({ transactions, onTransactionClick, }) => {
21170
21182
  backgroundColor: index % 2 === 0
21171
21183
  ? `var(--row-background${darkMode ? '-dark' : ''})`
21172
21184
  : `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));
21185
+ }, 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
21186
  }) }));
21175
21187
  };
21176
21188
 
21177
- const { Text: Text$p } = antd.Typography;
21189
+ const { Text: Text$q } = antd.Typography;
21178
21190
  const DISPLAY_WIDTH = 1200;
21179
21191
  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
21192
  common.TransactionKind.INVOICE,
@@ -21278,7 +21290,7 @@ function TransactionsDisplay({ transactions, onSearchValueChanged, search, }) {
21278
21290
  onTransactionDisplayClose === null || onTransactionDisplayClose === void 0 ? void 0 : onTransactionDisplayClose(selectedTransaction);
21279
21291
  setDrawerOpen(false);
21280
21292
  }
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
21293
+ 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
21294
  ), showSearchBar && (jsxRuntime.jsx("div", { className: `${isMobile ? 'bunny-w-full' : ''}`, children: jsxRuntime.jsx(antd.Input, { className: searchBarClassName ? searchBarClassName : '', onChange: e => {
21283
21295
  const value = e.target.value;
21284
21296
  // Allow empty string, numbers, and decimal point
@@ -21401,7 +21413,7 @@ const useHasTaxPlugin = ({ apiHost, token, }) => {
21401
21413
  return Boolean(plugins === null || plugins === void 0 ? void 0 : plugins.some((plugin) => plugin.type === "taxation"));
21402
21414
  };
21403
21415
 
21404
- const MUTATION$7 = () => `
21416
+ const MUTATION$6 = () => `
21405
21417
  mutation AccountSignup (
21406
21418
  $pluginId: String!,
21407
21419
  $paymentMethodId: String,
@@ -21475,7 +21487,7 @@ const accountSignup = async ({ token, apiHost, accountId, quoteId, paymentToken,
21475
21487
  priceListCode,
21476
21488
  };
21477
21489
  const response = await gqlRequest({
21478
- query: MUTATION$7(),
21490
+ query: MUTATION$6(),
21479
21491
  token,
21480
21492
  vars,
21481
21493
  apiHost,
@@ -21486,7 +21498,7 @@ const accountSignup = async ({ token, apiHost, accountId, quoteId, paymentToken,
21486
21498
  return response === null || response === void 0 ? void 0 : response.accountSignup;
21487
21499
  };
21488
21500
 
21489
- const MUTATION$6 = () => `
21501
+ const MUTATION$5 = () => `
21490
21502
  mutation QuoteAccountSignup (
21491
21503
  $accountName: String!,
21492
21504
  $billingContact: ContactAttributes!,
@@ -21563,7 +21575,7 @@ const quoteAccountSignup = async ({ token, apiHost, priceListCode, accountName,
21563
21575
  billingDetails,
21564
21576
  };
21565
21577
  const response = await gqlRequest({
21566
- query: MUTATION$6(),
21578
+ query: MUTATION$5(),
21567
21579
  token,
21568
21580
  vars,
21569
21581
  apiHost,
@@ -21641,7 +21653,7 @@ const QUOTE_RECALCULATE_TAXES = `
21641
21653
  }
21642
21654
  }
21643
21655
  `;
21644
- const quoteRecalculateTaxes = async ({ quoteId, apiHost, token, }) => {
21656
+ const quoteRecalculateTaxes$2 = async ({ quoteId, apiHost, token, }) => {
21645
21657
  var _a, _b;
21646
21658
  const vars = { id: quoteId };
21647
21659
  const response = await gqlRequest({
@@ -21656,7 +21668,7 @@ const quoteRecalculateTaxes = async ({ quoteId, apiHost, token, }) => {
21656
21668
  return (_b = response.quoteRecalculateTaxes) === null || _b === void 0 ? void 0 : _b.quote;
21657
21669
  };
21658
21670
 
21659
- const MUTATION$5 = () => `
21671
+ const MUTATION$4 = () => `
21660
21672
  query PriceList($code: String!) {
21661
21673
  priceList (code: $code) {
21662
21674
  basePrice
@@ -21681,7 +21693,7 @@ query PriceList($code: String!) {
21681
21693
  }`;
21682
21694
  const getPriceList = async ({ token, code, apiHost, }) => {
21683
21695
  const response = await gqlRequest({
21684
- query: MUTATION$5(),
21696
+ query: MUTATION$4(),
21685
21697
  token,
21686
21698
  vars: { code },
21687
21699
  apiHost,
@@ -21691,16 +21703,60 @@ const getPriceList = async ({ token, code, apiHost, }) => {
21691
21703
 
21692
21704
  const SubscriptionsContext = react.createContext({});
21693
21705
 
21706
+ const QuoteContext = react.createContext({});
21707
+
21694
21708
  const graphql = initGraphQLTada();
21695
21709
 
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;
21710
+ const periodMonthsConverter = (period) => {
21711
+ if (period === 0)
21712
+ return graphql.scalar('BillingPeriod', 'ONCE');
21713
+ else if (period === 1)
21714
+ return graphql.scalar('BillingPeriod', 'MONTHLY');
21715
+ else if (period === 3)
21716
+ return graphql.scalar('BillingPeriod', 'QUARTERLY');
21717
+ else if (period === 6)
21718
+ return graphql.scalar('BillingPeriod', 'SEMI_ANNUAL');
21719
+ else if (period === 12)
21720
+ return graphql.scalar('BillingPeriod', 'ANNUAL');
21721
+ else
21722
+ return null;
21723
+ };
21724
+ const billingPeriodConverter = (period) => {
21725
+ if (period === graphql.scalar('BillingPeriod', 'ONCE'))
21726
+ return 0;
21727
+ else if (period === graphql.scalar('BillingPeriod', 'MONTHLY'))
21728
+ return 1;
21729
+ else if (period === graphql.scalar('BillingPeriod', 'QUARTERLY'))
21730
+ return 3;
21731
+ else if (period === graphql.scalar('BillingPeriod', 'SEMI_ANNUAL'))
21732
+ return 6;
21733
+ else
21734
+ return 12;
21735
+ };
21736
+
21737
+ function getAddonsForBillingPeriod(billingPeriod, addonPlans) {
21738
+ const flattenedPriceLists = addonPlans.flatMap(addonPlan => addonPlan.priceLists);
21739
+ return flattenedPriceLists.filter(priceList => priceList.periodMonths === billingPeriodConverter(billingPeriod));
21740
+ }
21741
+
21742
+ const hasUnpurchasedAddonPriceLists_PlanFragment = t(`
21743
+ fragment hasUnpurchasedAddonPriceLists_PlanFragment on Plan {
21744
+ priceLists {
21745
+ id
21746
+ isVisible
21747
+ periodMonths
21748
+ }
21749
+ }
21750
+ `);
21751
+ function hasUnpurchasedAddonPriceLists(maskedPriceListAddonPlans, currentSubscription, billingPeriod) {
21752
+ // Read fragments
21753
+ const priceListAddonPlans = maskedPriceListAddonPlans.map(maskedAddonPlan => readFragment(hasUnpurchasedAddonPriceLists_PlanFragment, maskedAddonPlan));
21754
+ const addonPriceLists = getAddonsForBillingPeriod(billingPeriod, priceListAddonPlans).filter(priceList => priceList.isVisible);
21755
+ const unpurchasedAddonPriceLists = addonPriceLists === null || addonPriceLists === void 0 ? void 0 : addonPriceLists.filter(addonPriceList => {
21756
+ var _a;
21757
+ 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));
21758
+ });
21759
+ return unpurchasedAddonPriceLists.length > 0;
21704
21760
  }
21705
21761
 
21706
21762
  function hasUnpurchasedFeatureAddons(priceList, currentSubscription) {
@@ -21727,110 +21783,317 @@ function featureAddonSwitchTestId(addonName) {
21727
21783
  return `feature-addon-switch-${name}`;
21728
21784
  }
21729
21785
 
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;
21786
+ const canSubscriptionUpgradeFromTrial = (subscription) => {
21787
+ var _a;
21788
+ return (((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL') &&
21789
+ subscription.plan.selfServiceBuy) ||
21790
+ false;
21745
21791
  };
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" }) }) })] }));
21792
+ const canSubscriptionUpgradeFromTrialExpired = (subscription) => {
21793
+ var _a;
21794
+ return (((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED') &&
21795
+ subscription.plan.selfServiceBuy) ||
21796
+ false;
21749
21797
  };
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, {})] }));
21798
+ const isSubscriptionNotActive = (subscription) => {
21799
+ var _a, _b, _c;
21800
+ return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'EXPIRED') ||
21801
+ ((_b = subscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === t.scalar('SubscriptionState', 'CANCELED') ||
21802
+ ((_c = subscription.state) === null || _c === void 0 ? void 0 : _c.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED');
21758
21803
  };
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 }) })] }) }) }));
21804
+ const isSubscriptionActiveOrPending = (subscription) => {
21805
+ var _a, _b;
21806
+ return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'ACTIVE') ||
21807
+ ((_b = subscription.state) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === t.scalar('SubscriptionState', 'PENDING');
21763
21808
  };
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, }) => {
21809
+ const isSubscriptionTrial = (subscription) => { var _a; return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL'); };
21810
+ const isSubscriptionTrialExpired = (subscription) => { var _a; return ((_a = subscription.state) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === t.scalar('SubscriptionState', 'TRIAL_EXPIRED'); };
21811
+ // Helper function to check if charge is a discount
21812
+ const isDiscount$1 = (kind) => kind === common.QuoteChangeKind.DISCOUNT || kind === common.QuoteChangeKind.FREE_PERIOD_DISCOUNT;
21813
+ const hasPriceTiers = (charge) => {
21791
21814
  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;
21815
+ return Boolean((_a = charge === null || charge === void 0 ? void 0 : charge.priceTiers) === null || _a === void 0 ? void 0 : _a.length);
21803
21816
  };
21804
21817
 
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;
21818
+ const removeHTMLTagsRegex = /<br>(?=(?:\s*<[^>]*>)*$)|(<br>)|<[^>]*>/gi;
21819
+ // Description is a string that can contain HTML tags. We want to remove all HTML tags except <br> tags.
21820
+ const createPlanDescription = (planDescription) => {
21821
+ return (planDescription || '').replace(removeHTMLTagsRegex, (_, y) => (y ? ' & ' : ''));
21824
21822
  };
21825
-
21826
- const COUPONS_QUERY = (filter) => `
21827
- query Coupons {
21828
- coupons(filter: ${filter ? `"${filter}"` : 'null'}) {
21829
- totalCount
21823
+ const getActivePlanPriceData = (priceList, selectedPriceList) => {
21824
+ if (!priceList) {
21825
+ return;
21826
+ }
21827
+ // If a period option is selected, return the charge that matches the selected period option
21828
+ let activeBillingPLCharge;
21829
+ // Default to first price list charge
21830
+ let lowestPLCharge;
21831
+ // Find the lowest price list charge with a billing period that matches the selected period option
21832
+ if (priceList.id === (selectedPriceList === null || selectedPriceList === void 0 ? void 0 : selectedPriceList.id)) {
21833
+ activeBillingPLCharge = priceList.charges[0];
21834
+ }
21835
+ for (let j = 0; j < priceList.charges.length; j++) {
21836
+ const charge = priceList.charges[j];
21837
+ if (charge.chargeType === common.ChargeType.USAGE || charge.featureAddon === true)
21838
+ continue;
21839
+ if (activeBillingPLCharge) {
21840
+ // If we already found a charge with the same billing period check if this charge is lower
21841
+ if (charge.basePrice < activeBillingPLCharge.basePrice &&
21842
+ charge.billingPeriod === (activeBillingPLCharge === null || activeBillingPLCharge === void 0 ? void 0 : activeBillingPLCharge.billingPeriod)) {
21843
+ activeBillingPLCharge = charge;
21844
+ }
21845
+ }
21846
+ // If a period option is selected, only return the charge if it matches the selected period option
21847
+ else if (selectedPriceList &&
21848
+ charge.billingPeriod === periodMonthsConverter(selectedPriceList.periodMonths)) {
21849
+ activeBillingPLCharge = charge;
21850
+ }
21851
+ // Otherwise, return the lowest price list charge
21852
+ else if (charge.basePrice < ((lowestPLCharge === null || lowestPLCharge === void 0 ? void 0 : lowestPLCharge.basePrice) || -1)) {
21853
+ lowestPLCharge = charge;
21830
21854
  }
21831
21855
  }
21832
- `;
21833
- const getCoupons = async ({ token, apiHost, filter, }) => {
21856
+ return {
21857
+ activeCharge: activeBillingPLCharge || lowestPLCharge,
21858
+ };
21859
+ };
21860
+ const showErrorNotification$3 = common.useErrorNotification();
21861
+ const isPriceListDisabled = ({ priceList, upgradingSubscription, }) => {
21862
+ const priceListAddonPlans = priceList === null || priceList === void 0 ? void 0 : priceList.plan.addonPlans;
21863
+ if (!priceListAddonPlans) {
21864
+ showErrorNotification$3('Price list addon plans are undefined');
21865
+ return false;
21866
+ }
21867
+ const canPurchaseFeatureAddons = hasUnpurchasedFeatureAddons(priceList, upgradingSubscription);
21868
+ const canPurchasePlanAddons = hasUnpurchasedAddonPriceLists(priceListAddonPlans, upgradingSubscription, periodMonthsConverter(priceList.periodMonths));
21869
+ const existingSubscriptionInTrial = upgradingSubscription && canSubscriptionUpgradeFromTrial(upgradingSubscription);
21870
+ const existingSubscriptionInTrialExpired = upgradingSubscription && canSubscriptionUpgradeFromTrialExpired(upgradingSubscription);
21871
+ const isUpgradingSubscriptionPriceList = (upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.id) === priceList.id;
21872
+ // When should priceList be disabled?
21873
+ // if upgradingSubscription?.priceList.id === priceList.id
21874
+ // AND the upgradingSubscription is not in trial
21875
+ // AND cannot purchase feature addons
21876
+ // AND cannot purchase add-on plans
21877
+ // AND selfServiceBuy is false
21878
+ // if upgradingSubscription?.priceList.id != priceList.id
21879
+ // AND upgradingSubscription is expired trial
21880
+ if (isUpgradingSubscriptionPriceList) {
21881
+ return (!existingSubscriptionInTrial &&
21882
+ !existingSubscriptionInTrialExpired &&
21883
+ !canPurchaseFeatureAddons &&
21884
+ !canPurchasePlanAddons);
21885
+ }
21886
+ else {
21887
+ return false;
21888
+ }
21889
+ };
21890
+
21891
+ const CheckoutButton = ({ disabled, onClickCheckout, loading, tooltipText, }) => {
21892
+ const isMobile = common.useIsMobile();
21893
+ const TooltipWrapper = ({ children }) => {
21894
+ if (tooltipText) {
21895
+ return jsxRuntime.jsx(antd.Tooltip, { title: tooltipText, children: children });
21896
+ }
21897
+ return jsxRuntime.jsx("div", { children: children });
21898
+ };
21899
+ 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" }) }));
21900
+ };
21901
+
21902
+ var localizedFormat$2 = {exports: {}};
21903
+
21904
+ var localizedFormat$1 = localizedFormat$2.exports;
21905
+
21906
+ var hasRequiredLocalizedFormat;
21907
+
21908
+ function requireLocalizedFormat () {
21909
+ if (hasRequiredLocalizedFormat) return localizedFormat$2.exports;
21910
+ hasRequiredLocalizedFormat = 1;
21911
+ (function (module, exports) {
21912
+ !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)};}}));
21913
+ } (localizedFormat$2));
21914
+ return localizedFormat$2.exports;
21915
+ }
21916
+
21917
+ var localizedFormatExports = requireLocalizedFormat();
21918
+ var localizedFormat = /*@__PURE__*/getDefaultExportFromCjs(localizedFormatExports);
21919
+
21920
+ dayjs.extend(localizedFormat);
21921
+ const formatCurrency = (value, currencyIsoCode, decimals = 2) => {
21922
+ if (value !== 0 && !value)
21923
+ return '';
21924
+ const currencyValue = typeof value === 'string' ? parseFloat(value) : value;
21925
+ if (isNaN(currencyValue))
21926
+ return value;
21927
+ const localeOptions = {
21928
+ minimumFractionDigits: decimals,
21929
+ maximumFractionDigits: decimals,
21930
+ };
21931
+ localeOptions.style = 'currency';
21932
+ localeOptions.currency = currencyIsoCode;
21933
+ return currencyValue.toLocaleString(navigator.language, localeOptions);
21934
+ };
21935
+
21936
+ const CheckoutPrice_QuoteFragment = t(`
21937
+ fragment CheckoutPrice_QuoteFragment on Quote {
21938
+ periodAmount
21939
+ amountDue
21940
+ }
21941
+ `);
21942
+ const CheckoutPrice = ({ isUsage, quote: maskedQuote, selectedPriceList, }) => {
21943
+ var _a;
21944
+ // Read fragments
21945
+ const quote = readFragment(CheckoutPrice_QuoteFragment, maskedQuote);
21946
+ // Hooks
21947
+ const isMobile = common.useIsMobile();
21948
+ // amountDue might not be available, so we use periodAmount as a fallback
21949
+ 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;
21950
+ if (!isUsage && (!selectedPriceList || displayAmount === undefined))
21951
+ return null;
21952
+ const convertedPeriodMonths = periodMonthsConverter(selectedPriceList.periodMonths);
21953
+ const periodLabel = convertedPeriodMonths ? common.PERIOD_LABELS[convertedPeriodMonths] : 'undefined';
21954
+ return (jsxRuntime.jsx("div", { className: `bunny-font-medium ${isMobile ? 'bunny-text-2xl' : ''}`, children: isUsage
21955
+ ? 'Usage based pricing'
21956
+ : selectedPriceList && displayAmount !== undefined
21957
+ ? `${formatCurrency(displayAmount, selectedPriceList === null || selectedPriceList === void 0 ? void 0 : selectedPriceList.currencyId, undefined)} / ${periodLabel}`
21958
+ : '' }));
21959
+ };
21960
+
21961
+ const { Text: Text$p } = antd.Typography;
21962
+ const CheckoutBarSummarySection_QuoteFragment = t(`
21963
+ fragment CheckoutBarSummarySection_QuoteFragment on Quote {
21964
+ quoteChanges {
21965
+ charges {
21966
+ id
21967
+ }
21968
+ }
21969
+ ...CheckoutPrice_QuoteFragment
21970
+ }
21971
+ `, [CheckoutPrice_QuoteFragment]);
21972
+ const CheckoutBarSummarySection = ({ selectedPriceList, onClickCheckout, }) => {
21973
+ var _a, _b;
21974
+ // Context
21975
+ const { quote: maskedQuote, isQuotePending, isUpdatingQuote } = react.useContext(QuoteContext);
21976
+ const quote = readFragment(CheckoutBarSummarySection_QuoteFragment, maskedQuote);
21977
+ const { isInPreviewMode } = react.useContext(SubscriptionsContext);
21978
+ // Hooks
21979
+ const { paymentPlugins } = usePaymentPlugins(undefined);
21980
+ const isMobile = common.useIsMobile();
21981
+ const hasPaymentPlugins = Boolean(paymentPlugins === null || paymentPlugins === void 0 ? void 0 : paymentPlugins.length);
21982
+ 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));
21983
+ const checkoutButtonDisabled = Boolean(!selectedPriceList || !quoteHasCharges || !hasPaymentPlugins || isInPreviewMode);
21984
+ const activeCharge = (_b = getActivePlanPriceData(selectedPriceList, selectedPriceList)) === null || _b === void 0 ? void 0 : _b.activeCharge;
21985
+ const isUsage = (activeCharge === null || activeCharge === void 0 ? void 0 : activeCharge.chargeType) === common.ChargeType.USAGE;
21986
+ 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
21987
+ ? 'Checkout is disabled in preview mode'
21988
+ : !hasPaymentPlugins
21989
+ ? 'Cannot checkout. No valid payment plugins found. Please contact your administrator.'
21990
+ : undefined })] }));
21991
+ };
21992
+
21993
+ const MUTATION$3 = `{
21994
+ currentUser {
21995
+ taxationRequiredAccountFields
21996
+ }
21997
+ }`;
21998
+ const getTaxationRequiredAccountFields = async ({ apiHost, token, }) => {
21999
+ var _a, _b;
22000
+ const response = await gqlRequest({
22001
+ query: MUTATION$3,
22002
+ token,
22003
+ apiHost: apiHost,
22004
+ });
22005
+ 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
22006
+ ? response.currentUser.taxationRequiredAccountFields
22007
+ : null;
22008
+ };
22009
+
22010
+ const BunnyFooterIcon = ({ color }) => {
22011
+ 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" }) }) })] }));
22012
+ };
22013
+
22014
+ const { Text: Text$o } = antd.Typography;
22015
+ const Footer = ({ className }) => {
22016
+ const token = useToken();
22017
+ const { currentUser } = useCurrentUserData(token);
22018
+ const { privacyUrl, termsUrl } = currentUser;
22019
+ const isMobile = common.useIsMobile();
22020
+ 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, {})] }));
22021
+ };
22022
+ const BunnyMarketingLink = () => {
22023
+ const [isHovered, setIsHovered] = react.useState(false);
22024
+ const isMobile = common.useIsMobile();
22025
+ 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 }) })] }) }) }));
22026
+ };
22027
+ const StyedLink = styled.a `
22028
+ color: ${common.SLATE_400};
22029
+ transition: color 0.3s;
22030
+ &:hover {
22031
+ color: ${common.SLATE_500};
22032
+ }
22033
+ text-decoration: none;
22034
+ `;
22035
+ const StyledBunnyLink = styled(StyedLink) `
22036
+ &:hover {
22037
+ color: ${common.PRIMARY_COLOR} !important;
22038
+ }
22039
+ `;
22040
+
22041
+ const MUTATION$2 = `mutation quoteChangeAddCoupon($couponCode: String!, $quoteChangeId: ID!) {
22042
+ quoteChangeAddCoupon(couponCode: $couponCode, quoteChangeId: $quoteChangeId) {
22043
+ quoteChange {
22044
+ id
22045
+ charges {
22046
+ id
22047
+ amount
22048
+ couponId
22049
+ }
22050
+ }
22051
+ }
22052
+ }`;
22053
+ const quoteChangeAddCoupon = async ({ quoteChangeId, couponCode, token, apiHost, }) => {
22054
+ var _a;
22055
+ const vars = { couponCode, quoteChangeId };
22056
+ const response = await gqlRequest({
22057
+ query: MUTATION$2,
22058
+ token,
22059
+ vars,
22060
+ apiHost,
22061
+ });
22062
+ const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteAddCoupon) === null || _a === void 0 ? void 0 : _a.errors;
22063
+ if (errors)
22064
+ throw errors;
22065
+ return response.quote;
22066
+ };
22067
+
22068
+ const MUTATION$1 = `mutation quoteChangeRemoveCoupon($quoteChangeId: ID!, $couponCode: String!) {
22069
+ quoteChangeRemoveCoupon(quoteChangeId: $quoteChangeId, couponCode: $couponCode) {
22070
+ errors
22071
+ }
22072
+ }
22073
+ `;
22074
+ const quoteChangeRemoveCoupon = async ({ quoteChangeId, couponCode, token, apiHost, }) => {
22075
+ var _a;
22076
+ const vars = { couponCode, quoteChangeId };
22077
+ const response = await gqlRequest({
22078
+ query: MUTATION$1,
22079
+ token,
22080
+ vars,
22081
+ apiHost,
22082
+ });
22083
+ const errors = (_a = response === null || response === void 0 ? void 0 : response.quoteChangeRemoveCoupon) === null || _a === void 0 ? void 0 : _a.errors;
22084
+ if (errors)
22085
+ throw errors;
22086
+ return response.quote;
22087
+ };
22088
+
22089
+ const COUPONS_QUERY = (filter) => `
22090
+ query Coupons {
22091
+ coupons(filter: ${filter ? `"${filter}"` : 'null'}) {
22092
+ totalCount
22093
+ }
22094
+ }
22095
+ `;
22096
+ const getCoupons = async ({ token, apiHost, filter, }) => {
21834
22097
  const response = await gqlRequest({
21835
22098
  query: COUPONS_QUERY(filter),
21836
22099
  token,
@@ -21840,7 +22103,7 @@ const getCoupons = async ({ token, apiHost, filter, }) => {
21840
22103
  return response === null || response === void 0 ? void 0 : response.coupons;
21841
22104
  };
21842
22105
 
21843
- const showErrorNotification$3 = common.useErrorNotification();
22106
+ const showErrorNotification$2 = common.useErrorNotification();
21844
22107
  const useUpdateCoupons = ({ apiHost, token, quoteChangeId, onCouponAdded, onCouponRemoved, }) => {
21845
22108
  const { data: coupons } = reactQuery.useQuery({
21846
22109
  queryKey: ['coupons', token],
@@ -21866,7 +22129,7 @@ const useUpdateCoupons = ({ apiHost, token, quoteChangeId, onCouponAdded, onCoup
21866
22129
  },
21867
22130
  onError: (error) => {
21868
22131
  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');
22132
+ 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');
21870
22133
  },
21871
22134
  });
21872
22135
  const { mutate: removeCoupon, isPending: isRemovingCoupon } = reactQuery.useMutation({
@@ -21886,7 +22149,7 @@ const useUpdateCoupons = ({ apiHost, token, quoteChangeId, onCouponAdded, onCoup
21886
22149
  },
21887
22150
  onError: (error) => {
21888
22151
  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');
22152
+ 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');
21890
22153
  },
21891
22154
  });
21892
22155
  return {
@@ -21986,7 +22249,7 @@ const QuoteFields_QuoteFragment = t(`
21986
22249
  }
21987
22250
  `);
21988
22251
 
21989
- const MUTATION$1 = `
22252
+ const MUTATION = `
21990
22253
  mutation accountUpdate(
21991
22254
  $id: ID!,
21992
22255
  $attributes: AccountAttributes!) {
@@ -22007,11 +22270,11 @@ mutation accountUpdate(
22007
22270
  }
22008
22271
  }
22009
22272
  `;
22010
- const accountUpdate = async ({ accountId, attributes, token, apiHost, }) => {
22273
+ const accountUpdate$1 = async ({ accountId, attributes, token, apiHost, }) => {
22011
22274
  var _a;
22012
22275
  const vars = { id: accountId, attributes };
22013
22276
  const response = await gqlRequest({
22014
- query: MUTATION$1,
22277
+ query: MUTATION,
22015
22278
  token,
22016
22279
  vars,
22017
22280
  apiHost,
@@ -22032,7 +22295,7 @@ const TaxationForm = ({ account, accountId }) => {
22032
22295
  // Mutations
22033
22296
  const { mutate: updateAccount, isPending: isUpdatingAccount } = reactQuery.useMutation({
22034
22297
  mutationFn: async (changedFormData) => {
22035
- const account = await accountUpdate({
22298
+ const account = await accountUpdate$1({
22036
22299
  accountId,
22037
22300
  attributes: changedFormData,
22038
22301
  token,
@@ -22058,6 +22321,7 @@ const FormBillingState = () => {
22058
22321
  return (jsxRuntime.jsx(antd.Form.Item, { label: "Billing state", name: "billingState", rules: [{ required: billingStateRequired }], children: jsxRuntime.jsx(antd.Input, { placeholder: "State" }) }));
22059
22322
  };
22060
22323
 
22324
+ const { Text: Text$n } = antd.Typography;
22061
22325
  // HACK: I have imported QuoteFields_QuoteFragment here as a hack to ensure I have all of the quote data needed for
22062
22326
  // the eventual children of this component.
22063
22327
  // Solution: Eventually all children of this component should be using query fragments to avoid this
@@ -22143,7 +22407,7 @@ const QuoteCheckout = ({ account, onSuccess, onFail, quote: maskedQuote, taxatio
22143
22407
  }
22144
22408
  if (taxationRequiredAccountFields)
22145
22409
  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 &&
22410
+ 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 &&
22147
22411
  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
22412
  couponsOnQuote === null || couponsOnQuote === void 0 ? void 0 : couponsOnQuote.forEach(couponCharge => {
22149
22413
  var _a;
@@ -22152,7 +22416,7 @@ const QuoteCheckout = ({ account, onSuccess, onFail, quote: maskedQuote, taxatio
22152
22416
  removeCoupon(couponCode);
22153
22417
  }
22154
22418
  });
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" })] }) })) }));
22419
+ }, 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" })] })) }));
22156
22420
  };
22157
22421
  const PaymentFormWrapper = ({ children, setMaxHeight, className, }) => {
22158
22422
  const isMobile = common.useIsMobile();
@@ -22163,7 +22427,7 @@ const PaymentFormWrapper = ({ children, setMaxHeight, className, }) => {
22163
22427
  : {}
22164
22428
  : {
22165
22429
  width: '100%',
22166
- maxWidth: '350px',
22430
+ maxWidth: '400px',
22167
22431
  }),
22168
22432
  }, children: children }));
22169
22433
  };
@@ -22179,7 +22443,7 @@ const Checkout_QuoteFragment = t(`
22179
22443
  ...QuoteCheckout_QuoteFragment
22180
22444
  }
22181
22445
  `, [QuoteCheckout_QuoteFragment]);
22182
- const Checkout = ({ onCancel, onSuccess, onFail, invoice, open, quote: maskedQuote, isUpdatingQuote, }) => {
22446
+ const Checkout = ({ onCancel, onSuccess, onFail, onRecalculateTaxes, invoice, open, quote: maskedQuote, isUpdatingQuote, }) => {
22183
22447
  var _a, _b, _c, _d, _e;
22184
22448
  const { apiHost } = react.useContext(BunnyContext);
22185
22449
  const isMobile = common.useIsMobile();
@@ -22190,7 +22454,6 @@ const Checkout = ({ onCancel, onSuccess, onFail, invoice, open, quote: maskedQuo
22190
22454
  apiHost,
22191
22455
  token,
22192
22456
  });
22193
- const queryClient = reactQuery.useQueryClient();
22194
22457
  // Queries
22195
22458
  const { data: taxationRequiredAccountFields, isLoading: isLoadingTaxationRequiredAccountFields } = reactQuery.useQuery({
22196
22459
  queryKey: ['getTaxationRequiredAccountFields', token],
@@ -22204,23 +22467,12 @@ const Checkout = ({ onCancel, onSuccess, onFail, invoice, open, quote: maskedQuo
22204
22467
  common.getAccount({ id: quote.accountId, apiHost, token, componentsVersion: PACKAGE_VERSION }),
22205
22468
  enabled: Boolean(quote === null || quote === void 0 ? void 0 : quote.accountId) && ((taxationRequiredAccountFields === null || taxationRequiredAccountFields === void 0 ? void 0 : taxationRequiredAccountFields.length) || 0) > 0,
22206
22469
  });
22470
+ // Use onRecalculateTaxes callback because parents need to define recalculateTaxes to get and set the right quote data they need
22207
22471
  async function recalculateTaxes() {
22208
22472
  if (quote) {
22209
22473
  if (!quote.id)
22210
22474
  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
- }
22475
+ onRecalculateTaxes(quote.id);
22224
22476
  }
22225
22477
  return {};
22226
22478
  }
@@ -22254,9 +22506,17 @@ const Checkout = ({ onCancel, onSuccess, onFail, invoice, open, quote: maskedQuo
22254
22506
  } })) : (jsxRuntime.jsx(PaymentForm, { onPaymentSuccess: onSuccess }))] }), jsxRuntime.jsx(Footer, { className: "bunny-px-12" })] }) }));
22255
22507
  };
22256
22508
 
22257
- const QuoteContext = react.createContext({});
22509
+ function canEditChargeQuantity(charge) {
22510
+ if (!charge)
22511
+ return false;
22512
+ if (charge.chargeType === graphql.scalar('ChargeType', 'USAGE'))
22513
+ return false;
22514
+ if (charge.pricingModel === graphql.scalar('PricingModel', 'FLAT'))
22515
+ return false;
22516
+ return true;
22517
+ }
22258
22518
 
22259
- const { Text: Text$n } = antd.Typography;
22519
+ const { Text: Text$m } = antd.Typography;
22260
22520
  const CheckoutBarInput = ({ disabled, priceListCharge, quantity, onQuantityChanged, }) => {
22261
22521
  var _a;
22262
22522
  const [isTooltipOpen, setIsTooltipOpen] = react.useState(false);
@@ -22269,7 +22529,7 @@ const CheckoutBarInput = ({ disabled, priceListCharge, quantity, onQuantityChang
22269
22529
  setIsTooltipOpen(false);
22270
22530
  }, 6000);
22271
22531
  }, []);
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: {
22532
+ 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: {
22273
22533
  body: {
22274
22534
  paddingTop: '0.75rem',
22275
22535
  paddingBottom: '0.75rem',
@@ -22280,222 +22540,7 @@ const CheckoutBarInput = ({ disabled, priceListCharge, quantity, onQuantityChang
22280
22540
  };
22281
22541
  const QuantityLabel = ({ activeCharge }) => {
22282
22542
  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;
22440
- }
22441
- };
22442
-
22443
- const CheckoutButton = ({ checkoutButtonDisabled, onClickCheckout, loading, tooltipText, }) => {
22444
- 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" }) }));
22452
- };
22453
-
22454
- const CheckoutPrice = ({ isUsage, quote, selectedPriceList, }) => {
22455
- const isMobile = common.useIsMobile();
22456
- if (!isUsage && (!selectedPriceList || (quote === null || quote === void 0 ? void 0 : quote.periodAmount) === undefined))
22457
- 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
- : '' }));
22465
- };
22466
-
22467
- const { Text: Text$m } = antd.Typography;
22468
- const CheckoutBarSummarySection = ({ open, selectedPriceList, onClickCheckout, }) => {
22469
- 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();
22478
- 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 })] }));
22543
+ return (jsxRuntime.jsx(Text$m, { className: "bunny-text-slate-500 bunny-font-medium bunny-text-nowrap", style: { fontSize: '11px' }, children: chargeName.toUpperCase() }));
22499
22544
  };
22500
22545
 
22501
22546
  const PlanPickerCheckoutBar_QuoteFragment = t(`
@@ -22515,8 +22560,8 @@ const PlanPickerCheckoutBar_QuoteFragment = t(`
22515
22560
  `, [Checkout_QuoteFragment]);
22516
22561
  const PlanPickerCheckoutBar = ({ selectedPriceList, handlePortalErrors, onCheckoutSuccess, }) => {
22517
22562
  // Context
22518
- const { shadow, upgradingSubscription } = react.useContext(SubscriptionsContext);
22519
- const { quote: maskedQuote, onChangeQuantity, getFeatureQuantity, isFeatureAddonsLoading, isUpdatingQuote, } = react.useContext(QuoteContext);
22563
+ const { shadow } = react.useContext(SubscriptionsContext);
22564
+ const { quote: maskedQuote, onChangeQuantity, getFeatureQuantity, onRecalculateTaxes, isFeatureAddonsLoading, isUpdatingQuote, } = react.useContext(QuoteContext);
22520
22565
  // Read fragments
22521
22566
  const quote = readFragment(PlanPickerCheckoutBar_QuoteFragment, maskedQuote);
22522
22567
  // Local state
@@ -22564,9 +22609,6 @@ const PlanPickerCheckoutBar = ({ selectedPriceList, handlePortalErrors, onChecko
22564
22609
  const isFeatureAddon = charge.featureAddon;
22565
22610
  const quantity = getFeatureQuantity((_d = charge.feature) === null || _d === void 0 ? void 0 : _d.id, charge.id);
22566
22611
  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
22612
  if (!quantity)
22571
22613
  return null;
22572
22614
  // if charge is a feature addon, and a corresponding quote charge is not found in quote, return null
@@ -22577,9 +22619,40 @@ const PlanPickerCheckoutBar = ({ selectedPriceList, handlePortalErrors, onChecko
22577
22619
  return (jsxRuntime.jsx(CheckoutBarInput, { disabled: isDisabled, priceListCharge: charge, quantity: quantity, onQuantityChanged: quantity => {
22578
22620
  onChangeQuantity(charge.id, quantity);
22579
22621
  } }, 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 })] }));
22622
+ }) }), 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
22623
  };
22582
22624
 
22625
+ const useQuoteUpdateFeatureAddon_QuoteFragment = t(`
22626
+ fragment useQuoteUpdateFeatureAddon_QuoteFragment on Quote {
22627
+ id
22628
+ startDate
22629
+ }
22630
+ `);
22631
+
22632
+ const FeatureAddonRow_QuoteFragment = t(`
22633
+ fragment FeatureAddonRow_QuoteFragment on Quote {
22634
+ ...useQuoteUpdateFeatureAddon_QuoteFragment
22635
+ }
22636
+ `, [useQuoteUpdateFeatureAddon_QuoteFragment]);
22637
+
22638
+ const useToggleAddonPlan_QuoteFragment = t(`
22639
+ fragment useToggleAddonPlan_QuoteFragment on Quote {
22640
+ quoteChanges {
22641
+ priceList {
22642
+ id
22643
+ }
22644
+ id
22645
+ }
22646
+ id
22647
+ }
22648
+ `);
22649
+
22650
+ const AddonPlanRow_QuoteFragment = t(`
22651
+ fragment AddonPlanRow_QuoteFragment on Quote {
22652
+ ...useToggleAddonPlan_QuoteFragment
22653
+ }
22654
+ `, [useToggleAddonPlan_QuoteFragment]);
22655
+
22583
22656
  /**
22584
22657
  * Central quote fragment for QuoteProvider context.
22585
22658
  *
@@ -22597,6 +22670,7 @@ const QuoteContext_QuoteFragment = t(`
22597
22670
  id
22598
22671
  currencyId
22599
22672
  amountDue
22673
+ startDate
22600
22674
  quoteChanges {
22601
22675
  id
22602
22676
  kind
@@ -22620,75 +22694,17 @@ const QuoteContext_QuoteFragment = t(`
22620
22694
  }
22621
22695
  }
22622
22696
  ...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
- `;
22697
+ ...CheckoutBarSummarySection_QuoteFragment
22698
+ ...AddonPlanRow_QuoteFragment
22699
+ ...FeatureAddonRow_QuoteFragment
22700
+ }
22701
+ `, [
22702
+ PlanPickerCheckoutBar_QuoteFragment,
22703
+ CheckoutBarSummarySection_QuoteFragment,
22704
+ AddonPlanRow_QuoteFragment,
22705
+ FeatureAddonRow_QuoteFragment,
22706
+ ]);
22707
+
22692
22708
  const FormattedQuoteField_QuoteFragment = t(`
22693
22709
  fragment FormattedQuoteField_QuoteFragment on Quote {
22694
22710
  formattedQuote {
@@ -22696,7 +22712,7 @@ const FormattedQuoteField_QuoteFragment = t(`
22696
22712
  }
22697
22713
  }
22698
22714
  `);
22699
- const query$3 = t(`
22715
+ const query$5 = t(`
22700
22716
  query quote($id: ID, $removeFormattedQuoteField: Boolean!) {
22701
22717
  quote(id: $id) {
22702
22718
  ...QuoteContext_QuoteFragment
@@ -22705,7 +22721,7 @@ const query$3 = t(`
22705
22721
  }
22706
22722
  `, [QuoteContext_QuoteFragment, FormattedQuoteField_QuoteFragment]);
22707
22723
  const getQuote$1 = async ({ id, token, apiHost, removeFormattedQuoteField = false, }) => {
22708
- const response = await execute(query$3, { apiHost, token }, { id, removeFormattedQuoteField });
22724
+ const response = await execute(query$5, { apiHost, token }, { id, removeFormattedQuoteField });
22709
22725
  return response === null || response === void 0 ? void 0 : response.quote;
22710
22726
  };
22711
22727
 
@@ -22810,7 +22826,7 @@ function Signup({ companyName, priceListCode, returnUrl, couponCode, className,
22810
22826
  });
22811
22827
  const { mutate: recalculateTaxesMutation } = reactQuery.useMutation({
22812
22828
  mutationFn: (quoteId) => {
22813
- return quoteRecalculateTaxes({ token, apiHost, quoteId });
22829
+ return quoteRecalculateTaxes$2({ token, apiHost, quoteId });
22814
22830
  },
22815
22831
  onError: (error) => {
22816
22832
  if (!error[0].message.includes('Ensure that you have a taxation plugin')) {
@@ -22991,7 +23007,7 @@ const useQuoteQueryData = (quoteId) => {
22991
23007
  return data;
22992
23008
  };
22993
23009
 
22994
- const useSetQuoteQueryData = () => {
23010
+ const useSetQuoteQueryData$1 = () => {
22995
23011
  const token = useToken();
22996
23012
  const queryClient = reactQuery.useQueryClient();
22997
23013
  const setQuoteQueryData = (quoteId, quote) => {
@@ -23030,6 +23046,9 @@ const QuantityInput_QuoteFragment = t(`
23030
23046
  }
23031
23047
  `, []);
23032
23048
 
23049
+ const useQuoteIsLoadingState = (isLoading) => react.useState(isLoading !== null && isLoading !== void 0 ? isLoading : false);
23050
+ const [QuoteIsLoadingProvider, useQuoteIsLoading] = createStateContext(useQuoteIsLoadingState);
23051
+
23033
23052
  const QuoteChangeSummarySection_QuoteFragment = t(`
23034
23053
  fragment QuoteChangeSummarySection_QuoteFragment on Quote {
23035
23054
  id
@@ -23041,10 +23060,11 @@ const QuoteChangeSummarySection_QuoteFragment = t(`
23041
23060
  const QuoteChangeSummarySection = ({ openCheckout, errorUpdatingQuantity, }) => {
23042
23061
  const isMobile = common.useIsMobile();
23043
23062
  const [quoteId] = useQuoteId();
23063
+ const [isQuoteLoading] = useQuoteIsLoading();
23044
23064
  const maskedQuote = useQuoteQueryData(quoteId);
23045
23065
  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" }) })] }));
23066
+ const disabled = !quoteId || !quote || errorUpdatingQuantity || isQuoteLoading;
23067
+ 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
23068
  };
23049
23069
 
23050
23070
  const QuantityDrawer_QuoteFragment = t(`
@@ -23056,7 +23076,7 @@ const QuantityDrawer_QuoteFragment = t(`
23056
23076
  }
23057
23077
  `, [Checkout_QuoteFragment, QuantityInput_QuoteFragment, QuoteChangeSummarySection_QuoteFragment]);
23058
23078
 
23059
- const mutation$4 = t(`
23079
+ const mutation$c = t(`
23060
23080
  mutation QuoteChargeCreate(
23061
23081
  $quoteChangeId: ID!
23062
23082
  $startDate: ISO8601Date!
@@ -23091,11 +23111,11 @@ const mutation$4 = t(`
23091
23111
  `, [QuantityDrawer_QuoteFragment]);
23092
23112
  const quoteChargeCreate$1 = async ({ price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId, token, apiHost, }) => {
23093
23113
  var _a;
23094
- const response = await execute(mutation$4, { apiHost, token }, { price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId });
23114
+ const response = await execute(mutation$c, { apiHost, token }, { price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId });
23095
23115
  return (_a = response.quoteChargeCreate) === null || _a === void 0 ? void 0 : _a.quoteCharge;
23096
23116
  };
23097
23117
 
23098
- const mutation$3 = t(`
23118
+ const mutation$b = t(`
23099
23119
  mutation QuoteChargeUpdate($quoteChargeId: ID!, $quantity: Int) {
23100
23120
  quoteChargeUpdate(quoteChargeId: $quoteChargeId, quantity: $quantity) {
23101
23121
  quoteCharge {
@@ -23114,14 +23134,29 @@ const mutation$3 = t(`
23114
23134
  `, [QuantityDrawer_QuoteFragment]);
23115
23135
  const quoteChargeUpdate = async (quoteChargeId, quantity, apiHost, token) => {
23116
23136
  var _a, _b;
23117
- const response = await execute(mutation$3, { apiHost, token }, { quoteChargeId, quantity });
23137
+ const response = await execute(mutation$b, { apiHost, token }, { quoteChargeId, quantity });
23118
23138
  if ((_a = response.quoteChargeUpdate) === null || _a === void 0 ? void 0 : _a.errors) {
23119
23139
  throw new Error(response.quoteChargeUpdate.errors[0]);
23120
23140
  }
23121
23141
  return (_b = response.quoteChargeUpdate) === null || _b === void 0 ? void 0 : _b.quoteCharge;
23122
23142
  };
23123
23143
 
23124
- const mutation$2 = t(`
23144
+ const mutation$a = t(`
23145
+ mutation QuoteDelete($id: ID!) {
23146
+ quoteDelete(id: $id) {
23147
+ errors
23148
+ quote {
23149
+ id
23150
+ }
23151
+ }
23152
+ }
23153
+ `, []);
23154
+ const quoteDelete = async ({ id, token, apiHost }) => {
23155
+ const response = await execute(mutation$a, { apiHost, token }, { id });
23156
+ return response.quoteDelete;
23157
+ };
23158
+
23159
+ const mutation$9 = t(`
23125
23160
  mutation quoteSubscriptionUpdate($subscriptionIds: [ID!]!) {
23126
23161
  quoteSubscriptionUpdate(subscriptionIds: $subscriptionIds) {
23127
23162
  quote {
@@ -23150,7 +23185,7 @@ const mutation$2 = t(`
23150
23185
  `, [QuantityDrawer_QuoteFragment]);
23151
23186
  const quoteSubscriptionUpdate = async (subscriptionIds, apiHost, token) => {
23152
23187
  var _a, _b;
23153
- const response = await execute(mutation$2, { apiHost, token }, { subscriptionIds });
23188
+ const response = await execute(mutation$9, { apiHost, token }, { subscriptionIds });
23154
23189
  if ((_a = response.quoteSubscriptionUpdate) === null || _a === void 0 ? void 0 : _a.errors) {
23155
23190
  throw new Error(response.quoteSubscriptionUpdate.errors[0]);
23156
23191
  }
@@ -23219,6 +23254,23 @@ const canShowChangeQuantities = ({ subscriptions, }) => {
23219
23254
  });
23220
23255
  };
23221
23256
 
23257
+ /**
23258
+ * Note: It is good practice to isolate useEffects into their own components.
23259
+ * This approach helps prevent unnecessary re-renders when data is unchanged,
23260
+ * since useEffect will only be triggered in this dedicated sibling component.
23261
+ */
23262
+ const QuoteIsLoadingUpdater = ({ quoteIsPending }) => {
23263
+ const [, setQuoteIsLoading] = useQuoteIsLoading();
23264
+ const prevValue = react.useRef(quoteIsPending);
23265
+ react.useEffect(() => {
23266
+ if (prevValue.current !== quoteIsPending) {
23267
+ setQuoteIsLoading(quoteIsPending);
23268
+ prevValue.current = quoteIsPending;
23269
+ }
23270
+ }, [quoteIsPending, setQuoteIsLoading]);
23271
+ return null;
23272
+ };
23273
+
23222
23274
  const QuantityInput_SubscriptionChargeFragment = t(`
23223
23275
  fragment QuantityInput_SubscriptionChargeFragment on SubscriptionCharge {
23224
23276
  id
@@ -23230,7 +23282,6 @@ const QuantityInput_SubscriptionChargeFragment = t(`
23230
23282
  const QuantityInput_SubscriptionFragment = t(`
23231
23283
  fragment QuantityInput_SubscriptionFragment on Subscription {
23232
23284
  id
23233
- state
23234
23285
  priceList {
23235
23286
  id
23236
23287
  }
@@ -23246,6 +23297,16 @@ const QuantityInput_SubscriptionFragment = t(`
23246
23297
  CanShowQuantitiesInput_SubscriptionFragment,
23247
23298
  ]);
23248
23299
  const DEBOUNCE_TIME$1 = 1000;
23300
+ /**
23301
+ * Design note:
23302
+ * If the quantity is cleared by the user (quantity becomes undefined), we delete the quote.
23303
+ *
23304
+ * Rationale:
23305
+ * The user may next change the quantity for a charge on a different subscription, and we need to
23306
+ * allow creating a new quote/quoteChange in that context. Currently there is no way to create a
23307
+ * quoteChange of kind "update" without first calling `quoteSubscriptionUpdate`, so we delete the
23308
+ * existing quote to reset the flow.
23309
+ */
23249
23310
  const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription, setUpdatingChargeQuantityId, updatingChargeQuantityId, setErrorUpdatingQuantity, }) => {
23250
23311
  // Context
23251
23312
  const token = useToken();
@@ -23260,7 +23321,7 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23260
23321
  const quote = readFragment(QuantityInput_QuoteFragment, maskedQuote);
23261
23322
  // Hooks
23262
23323
  const showErrorNotification = common.useErrorNotification();
23263
- const { setQuoteQueryData } = useSetQuoteQueryData();
23324
+ const { setQuoteQueryData } = useSetQuoteQueryData$1();
23264
23325
  const quantityDisabled =
23265
23326
  // If we are editing a quote, we disable the quantity input
23266
23327
  // If we don't have a quantity, we disable the quantity input
@@ -23273,7 +23334,7 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23273
23334
  !charge.selfServiceQuantity;
23274
23335
  const value = quantity === undefined ? '' : quantity;
23275
23336
  // Mutations
23276
- const { mutate: createCharge } = reactQuery.useMutation({
23337
+ const { mutate: createCharge, isPending: isCreatingCharge } = reactQuery.useMutation({
23277
23338
  mutationFn: quoteChargeCreate$1,
23278
23339
  onSuccess: response => {
23279
23340
  var _a, _b;
@@ -23288,7 +23349,23 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23288
23349
  setErrorUpdatingQuantity(true);
23289
23350
  },
23290
23351
  });
23291
- const createQuote = reactQuery.useMutation({
23352
+ const { mutate: deleteQuote, isPending: isDeletingQuote } = reactQuery.useMutation({
23353
+ mutationFn: quoteDelete,
23354
+ onSuccess: response => {
23355
+ var _a;
23356
+ const quoteId = (_a = response === null || response === void 0 ? void 0 : response.quote) === null || _a === void 0 ? void 0 : _a.id;
23357
+ if (!quoteId) {
23358
+ showErrorNotification('quoteId is required');
23359
+ return;
23360
+ }
23361
+ setQuoteQueryData(quoteId, null);
23362
+ setQuoteId(undefined);
23363
+ },
23364
+ onError: () => {
23365
+ setErrorUpdatingQuantity(true);
23366
+ },
23367
+ });
23368
+ const { mutate: createQuote, isPending: isCreatingQuote } = reactQuery.useMutation({
23292
23369
  mutationFn: (subscriptionId) => quoteSubscriptionUpdate([subscriptionId], apiHost, token),
23293
23370
  onSuccess: quote => {
23294
23371
  var _a, _b, _c;
@@ -23316,7 +23393,7 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23316
23393
  setErrorUpdatingQuantity(true);
23317
23394
  },
23318
23395
  });
23319
- const updateQuoteCharge = reactQuery.useMutation({
23396
+ const { mutate: updateQuoteCharge, isPending: isUpdatingQuoteCharge } = reactQuery.useMutation({
23320
23397
  mutationFn: ({ quoteChargeId, quantity, }) => {
23321
23398
  if (!quoteChargeId)
23322
23399
  throw new Error('quoteChargeId is required');
@@ -23338,26 +23415,35 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23338
23415
  });
23339
23416
  const onChangeQuantity = (value) => {
23340
23417
  var _a;
23418
+ // Cancel all debounced functions first
23419
+ debouncedQuantityUpdate.cancel();
23420
+ debouncedDeleteQuote.cancel();
23341
23421
  // Handle empty string - don't convert to 0, keep it as undefined
23342
23422
  const quantity = value === '' ? undefined : isNaN(parseInt(value)) ? 0 : parseInt(value);
23343
23423
  setQuantity(quantity);
23344
23424
  if (quantity === undefined) {
23345
23425
  setUpdatingChargeQuantityId(undefined);
23426
+ if (quoteId) {
23427
+ // Only delete the quote if it exists
23428
+ debouncedDeleteQuote(quoteId);
23429
+ }
23346
23430
  }
23347
23431
  else {
23348
23432
  if (!(charge === null || charge === void 0 ? void 0 : charge.priceListChargeId)) {
23349
23433
  showErrorNotification('Charge ID is not found');
23350
23434
  return;
23351
23435
  }
23352
- // The set charge id is used to disable all other quantity inputs
23436
+ // Used to disable all other quantity inputs for this subscription
23353
23437
  setUpdatingChargeQuantityId(getUpdatingChargeQuantityId(charge.priceListChargeId, subscription.id));
23354
23438
  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);
23439
+ debouncedQuantityUpdate(charge.priceListChargeId, quantityDelta, subscription.id, quote, quoteId);
23357
23440
  }
23358
23441
  };
23359
- const debouncedQuantityUpdate = react.useCallback(lodashExports.debounce((priceListChargeId, quantityDelta, quantity, subscriptionId, quote, quoteId) => {
23360
- var _a, _b, _c;
23442
+ const debouncedDeleteQuote = react.useCallback(lodashExports.debounce((quoteId) => {
23443
+ deleteQuote({ id: quoteId, apiHost, token });
23444
+ }, DEBOUNCE_TIME$1), []);
23445
+ const debouncedQuantityUpdate = react.useCallback(lodashExports.debounce((priceListChargeId, quantityDelta, subscriptionId, quote, quoteId) => {
23446
+ var _a;
23361
23447
  if (quantityDelta === 0) {
23362
23448
  setErrorUpdatingQuantity(true);
23363
23449
  showErrorNotification('New quantity cannot be the same as current');
@@ -23365,37 +23451,22 @@ const QuantityInput = ({ charge: maskedCharge, subscription: maskedSubscription,
23365
23451
  }
23366
23452
  // If we are not editing a quote, we create a new one
23367
23453
  if (quoteId === undefined) {
23368
- createQuote.mutate(subscriptionId);
23454
+ createQuote(subscriptionId);
23369
23455
  }
23370
23456
  else {
23371
23457
  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
23458
  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
23459
  if (quoteCharge) {
23374
- updateQuoteCharge.mutate({
23460
+ updateQuoteCharge({
23375
23461
  quoteChargeId: quoteCharge.id,
23376
23462
  quantity: quantityDelta,
23377
23463
  });
23378
23464
  }
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
23465
  }
23395
23466
  }, 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 }) }));
23467
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(antd.Input, { className: "bunny-text-right", disabled: quantityDisabled, onChange: e => {
23468
+ onChangeQuantity(e.target.value);
23469
+ }, style: { width: '96px' }, value: value }), jsxRuntime.jsx(QuoteIsLoadingUpdater, { quoteIsPending: isCreatingCharge || isDeletingQuote || isCreatingQuote || isUpdatingQuoteCharge })] }));
23399
23470
  };
23400
23471
 
23401
23472
  const QuantityChangeGridRow_SubscriptionChargeFragment = t(`
@@ -23522,6 +23593,46 @@ function invalidateSubscriptionsQueryKeys(queryClient, token) {
23522
23593
  });
23523
23594
  }
23524
23595
 
23596
+ const [QuoteRecalculateTaxesProvider, useQuoteRecalculateTaxes$2] = createValueContext();
23597
+
23598
+ const mutation$8 = t(`
23599
+ mutation QuoteRecalculateTaxes($id: ID!) {
23600
+ quoteRecalculateTaxes(id: $id) {
23601
+ quote {
23602
+ ...QuantityDrawer_QuoteFragment
23603
+ id
23604
+ }
23605
+ errors
23606
+ }
23607
+ }
23608
+ `, [QuantityDrawer_QuoteFragment]);
23609
+ const quoteRecalculateTaxes$1 = async ({ quoteId, apiHost, token, }) => {
23610
+ var _a;
23611
+ const response = await execute(mutation$8, { apiHost, token }, { id: quoteId });
23612
+ return (_a = response.quoteRecalculateTaxes) === null || _a === void 0 ? void 0 : _a.quote;
23613
+ };
23614
+
23615
+ const useQuoteRecalculateTaxes$1 = () => {
23616
+ const token = useToken();
23617
+ const { apiHost } = react.useContext(BunnyContext);
23618
+ const { setQuoteQueryData } = useSetQuoteQueryData$1();
23619
+ const { mutate: quoteRecalculateTaxesMutation, isPending: isRecalculatingTaxes } = reactQuery.useMutation({
23620
+ mutationFn: async ({ quoteId }) => {
23621
+ return await quoteRecalculateTaxes$1({ quoteId, apiHost, token });
23622
+ },
23623
+ onSuccess: quote => {
23624
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
23625
+ throw new Error('Quote ID is undefined');
23626
+ }
23627
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, quote);
23628
+ },
23629
+ });
23630
+ return {
23631
+ quoteRecalculateTaxesMutation,
23632
+ isRecalculatingTaxes,
23633
+ };
23634
+ };
23635
+
23525
23636
  const QuantityDrawerContent = ({ subscriptions, quantityDrawerOpen, setQuantityDrawerOpen, handlePortalErrors, setShowInactive, }) => {
23526
23637
  const token = useToken();
23527
23638
  const queryClient = reactQuery.useQueryClient();
@@ -23531,6 +23642,8 @@ const QuantityDrawerContent = ({ subscriptions, quantityDrawerOpen, setQuantityD
23531
23642
  const [payModalVisible, setPayModalVisible] = react.useState(false);
23532
23643
  const [updatingChargeQuantityId, setUpdatingChargeQuantityId] = react.useState(undefined);
23533
23644
  const quote = useQuoteQueryData(quoteId);
23645
+ // Context
23646
+ const onRecalculateTaxes = useQuoteRecalculateTaxes$2();
23534
23647
  // Handlers
23535
23648
  const onSuccess = () => {
23536
23649
  setQuantityDrawerOpen(false);
@@ -23560,10 +23673,11 @@ const QuantityDrawerContent = ({ subscriptions, quantityDrawerOpen, setQuantityD
23560
23673
  const handleOpenCheckout = () => {
23561
23674
  setPayModalVisible(true);
23562
23675
  };
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 })] }));
23676
+ 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
23677
  };
23565
23678
  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 }) }));
23679
+ const { quoteRecalculateTaxesMutation } = useQuoteRecalculateTaxes$1();
23680
+ 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
23681
  };
23568
23682
 
23569
23683
  const useCancelSubscription = () => {
@@ -23827,14 +23941,27 @@ const SubscriptionCardActions = ({ onChangePlanClick, onCancelSubscriptionClick,
23827
23941
  const isInTrial = isSubscriptionTrial(subscription);
23828
23942
  const isTrialExpired = isSubscriptionTrialExpired(subscription);
23829
23943
  const isActiveOrPending = isSubscriptionActiveOrPending(subscription);
23944
+ const getButtonLabel = () => {
23945
+ if (isInTrial) {
23946
+ return 'Upgrade from trial';
23947
+ }
23948
+ if (isTrialExpired) {
23949
+ return 'Upgrade';
23950
+ }
23951
+ // If the subscription is an addon, we should show the "Adjust plan" button since we don't support changing add-on plans.
23952
+ if (subscription.priceList.plan.addon === true) {
23953
+ return 'Adjust plan';
23954
+ }
23955
+ return 'Change plan';
23956
+ };
23830
23957
  if (isPaymentMethodLoading)
23831
23958
  return null;
23832
23959
  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
23960
  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" })] }));
23961
+ (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
23962
  };
23836
23963
 
23837
- const query$2 = t(`
23964
+ const query$4 = t(`
23838
23965
  query priceListChangeOptions($productId: ID!) {
23839
23966
  priceListChangeOptions(productId: $productId) {
23840
23967
  ...SubscriptionCardActions_PriceListChangeOptionsFragment
@@ -23842,7 +23969,7 @@ const query$2 = t(`
23842
23969
  }
23843
23970
  `, [SubscriptionCardActions_PriceListChangeOptionsFragment]);
23844
23971
  const getPriceListChangeOptions$1 = async ({ apiHost, productId, token, }) => {
23845
- const response = await execute(query$2, { apiHost, token }, { productId });
23972
+ const response = await execute(query$4, { apiHost, token }, { productId });
23846
23973
  return response.priceListChangeOptions;
23847
23974
  };
23848
23975
 
@@ -23876,7 +24003,7 @@ const getSubscriptionStatusText = (subscription) => {
23876
24003
  return `Trial expires on ${common.formatDate(trialEndDate)}`;
23877
24004
  }
23878
24005
  }
23879
- if (evergreen) {
24006
+ if (evergreen && subscription.state === t.scalar('SubscriptionState', 'ACTIVE')) {
23880
24007
  return `Renews on ${common.formatDate(endDate)}`;
23881
24008
  }
23882
24009
  return `Ends on ${common.formatDate(endDate || trialEndDate)}`;
@@ -23954,40 +24081,66 @@ const formatNumber = (num, decimals = 2) => {
23954
24081
  });
23955
24082
  };
23956
24083
 
24084
+ const getPricingModelDescription = (pricingModel) => {
24085
+ switch (pricingModel) {
24086
+ case 'TIERED':
24087
+ return 'units in each tier are priced separately.';
24088
+ case 'VOLUME':
24089
+ return 'the highest tier reached prices all units.';
24090
+ case 'BANDS':
24091
+ return 'the quantity indexes to a flat price.';
24092
+ default:
24093
+ return '';
24094
+ }
24095
+ };
24096
+
24097
+ const getPricingModelTitle = (pricingModel) => {
24098
+ switch (pricingModel) {
24099
+ case 'TIERED':
24100
+ return 'Tiered';
24101
+ case 'VOLUME':
24102
+ return 'Volume';
24103
+ case 'BANDS':
24104
+ return 'Bands';
24105
+ default:
24106
+ return '';
24107
+ }
24108
+ };
24109
+
23957
24110
  const StyledTable = styled(antd.Table) `
23958
24111
  .ant-table-cell {
23959
24112
  border-bottom: none !important;
23960
24113
  }
23961
24114
  `;
23962
- const TieredDisplayDropdown = ({ priceTiers, currencyId, priceDecimals, truncatedText, }) => {
24115
+ const TieredDisplayDropdown = ({ pricingModel, priceTiers, currencyId, priceDecimals, truncatedText, }) => {
23963
24116
  const onlyHasOneTier = (priceTiers === null || priceTiers === void 0 ? void 0 : priceTiers.length) === 1;
23964
24117
  const dropdownTrigger = (jsxRuntime.jsx("div", { className: `w-full ${onlyHasOneTier ? '' : 'underline cursor-pointer'}`, children: truncatedText }));
23965
24118
  if (onlyHasOneTier) {
23966
24119
  return dropdownTrigger;
23967
24120
  }
23968
24121
  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) : ''] }));
24122
+ 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: [
24123
+ {
24124
+ dataIndex: 'starts',
24125
+ title: 'From # of units',
24126
+ align: 'right',
24127
+ render: (_, record, index) => {
24128
+ record = record;
24129
+ const nextRecord = priceTiers === null || priceTiers === void 0 ? void 0 : priceTiers[index + 1];
24130
+ const starts = record.starts;
24131
+ const ends = (nextRecord === null || nextRecord === void 0 ? void 0 : nextRecord.starts) ? nextRecord.starts - 1 : '+';
24132
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [formatNumber(starts, 0), typeof ends === 'number' ? formatNumber(ends, 0) : '+'] }));
24133
+ },
23980
24134
  },
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) });
24135
+ {
24136
+ dataIndex: 'price',
24137
+ title: 'Unit price',
24138
+ align: 'right',
24139
+ render: value => {
24140
+ return jsxRuntime.jsx(jsxRuntime.Fragment, { children: common.formatCurrency(value, currencyId, priceDecimals) });
24141
+ },
23988
24142
  },
23989
- },
23990
- ], dataSource: priceTiers, rowKey: "starts", pagination: false, size: "small" }) }));
24143
+ ], dataSource: priceTiers, rowKey: "starts", pagination: false, size: "small" })] }));
23991
24144
  }, children: dropdownTrigger }));
23992
24145
  };
23993
24146
 
@@ -24038,7 +24191,7 @@ const SubscriptionChargeUnitPrice = ({ charge, currencyId, }) => {
24038
24191
  ? '-'
24039
24192
  : common.formatCurrency(charge.discountedPrice, currencyId, charge.priceDecimals);
24040
24193
  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) }));
24194
+ 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
24195
  };
24043
24196
 
24044
24197
  const { Text: Text$e } = antd.Typography;
@@ -24175,7 +24328,7 @@ const SubscriptionCardDesktopRow = ({ charge, chargeIndex, charges, currencyId,
24175
24328
  : (_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
24329
  };
24177
24330
 
24178
- function AddonSubscriptionsCards({ onCancelSubscriptionClick, subscriptions, subscription, showInactive, }) {
24331
+ function AddonSubscriptionsCards({ onCancelSubscriptionClick, onChangePlanClick, subscriptions, subscription, showInactive, }) {
24179
24332
  const addonSubscriptions = findAddonSubscriptions(subscription, subscriptions);
24180
24333
  if (addonSubscriptions.length === 0) {
24181
24334
  return null;
@@ -24184,7 +24337,7 @@ function AddonSubscriptionsCards({ onCancelSubscriptionClick, subscriptions, sub
24184
24337
  if (!showInactive && isSubscriptionNotActive(addonSubscription))
24185
24338
  return null;
24186
24339
  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));
24340
+ 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
24341
  }) }));
24189
24342
  }
24190
24343
 
@@ -24243,8 +24396,8 @@ const SubscriptionsList = ({ showInactive, onChangePlanClick, onCancelSubscripti
24243
24396
  if (!showInactive && isSubscriptionNotActive(subscription))
24244
24397
  return null;
24245
24398
  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));
24399
+ 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));
24400
+ 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
24401
  }) }));
24249
24402
  };
24250
24403
 
@@ -24315,7 +24468,7 @@ const FormattedQuoteFields_QuoteFragment = t(`
24315
24468
  }
24316
24469
  }
24317
24470
  `);
24318
- const query$1 = t(`
24471
+ const query$3 = t(`
24319
24472
  query quote($id: ID, $includeHtmlField: Boolean!) {
24320
24473
  quote(id: $id) {
24321
24474
  ...FormattedQuoteFields_QuoteFragment @include(if: $includeHtmlField)
@@ -24324,7 +24477,7 @@ const query$1 = t(`
24324
24477
  }
24325
24478
  `, [FormattedQuoteFields_QuoteFragment, QuoteContext_QuoteFragment]);
24326
24479
  const getQuote = async ({ id, token, apiHost, includeHtmlField = false, }) => {
24327
- const response = await execute(query$1, { apiHost, token }, { id, includeHtmlField });
24480
+ const response = await execute(query$3, { apiHost, token }, { id, includeHtmlField });
24328
24481
  return response === null || response === void 0 ? void 0 : response.quote;
24329
24482
  };
24330
24483
 
@@ -24429,7 +24582,7 @@ const calculateNewQuantity = (priceListCharge, currentQuantity = 1) => {
24429
24582
  return quantityMin;
24430
24583
  };
24431
24584
 
24432
- const mutation$1 = t(`
24585
+ const mutation$7 = t(`
24433
24586
  mutation QuoteChangeUpdate($id: ID!, $charges: [QuoteChargeAttributes!]!) {
24434
24587
  quoteChangeUpdate(id: $id, charges: $charges) {
24435
24588
  quoteChange {
@@ -24443,7 +24596,7 @@ const mutation$1 = t(`
24443
24596
  `, [QuoteContext_QuoteFragment]);
24444
24597
  const quoteChangeUpdate = async ({ quoteChangeId, charges, apiHost, token, }) => {
24445
24598
  var _a, _b;
24446
- const response = await execute(mutation$1, {
24599
+ const response = await execute(mutation$7, {
24447
24600
  apiHost,
24448
24601
  token,
24449
24602
  }, {
@@ -24499,6 +24652,19 @@ function useFeatureQuantities({ onFeatureQuantitiesChanged, }) {
24499
24652
  };
24500
24653
  }
24501
24654
 
24655
+ const useSetQuoteQueryData = () => {
24656
+ const token = useToken();
24657
+ const queryClient = reactQuery.useQueryClient();
24658
+ const setQuoteQueryData = (quoteId, quote) => {
24659
+ queryClient.setQueryData(common.QueryKeyFactory.default.createObjectKey({
24660
+ id: quoteId,
24661
+ objectName: 'editingQuote',
24662
+ token,
24663
+ }), quote);
24664
+ };
24665
+ return { setQuoteQueryData };
24666
+ };
24667
+
24502
24668
  // Functionality:
24503
24669
  // 1: keep track of quantities set for features based on feature.id
24504
24670
  // a. copy those quantities over to charges with same feature when initializing
@@ -24511,9 +24677,9 @@ function useFeatureQuantities({ onFeatureQuantitiesChanged, }) {
24511
24677
  const showErrorNotification = common.useErrorNotification();
24512
24678
  const DEBOUNCE_TIME = 1000;
24513
24679
  const useQuoteQuantities = ({ selectedPriceList, quote, }) => {
24514
- const queryClient = reactQuery.useQueryClient();
24515
24680
  const token = useToken();
24516
24681
  const { apiHost } = react.useContext(BunnyContext);
24682
+ const { setQuoteQueryData } = useSetQuoteQueryData();
24517
24683
  // Derived state
24518
24684
  const selectedPriceListQuoteChange = react.useMemo(() => {
24519
24685
  var _a;
@@ -24532,23 +24698,27 @@ const useQuoteQuantities = ({ selectedPriceList, quote, }) => {
24532
24698
  });
24533
24699
  },
24534
24700
  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);
24701
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
24702
+ throw new Error('Quote ID is undefined');
24703
+ }
24704
+ if (!(quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.quote)) {
24705
+ throw new Error('Quote is undefined');
24706
+ }
24707
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.quote);
24541
24708
  },
24542
24709
  });
24543
24710
  function handleUpdateQuoteQuantities(featureQuantities) {
24544
24711
  if (!selectedPriceListQuoteChange) {
24545
- throw new Error('Quote change is undefined');
24712
+ console.error('Quote change is undefined');
24713
+ return;
24546
24714
  }
24547
24715
  if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
24548
- throw new Error('Quote ID is undefined');
24716
+ console.error('Quote ID is undefined');
24717
+ return;
24549
24718
  }
24550
24719
  if (!(selectedPriceListQuoteChange === null || selectedPriceListQuoteChange === void 0 ? void 0 : selectedPriceListQuoteChange.id)) {
24551
- throw new Error('Quote change ID is undefined');
24720
+ console.error('Quote change ID is undefined');
24721
+ return;
24552
24722
  }
24553
24723
  const featureIdsToUpdate = Object.keys(featureQuantities).filter(featureId => {
24554
24724
  // If the quantities differ, then update quote with the quantities present in useFeatureQuantities
@@ -24560,20 +24730,24 @@ const useQuoteQuantities = ({ selectedPriceList, quote, }) => {
24560
24730
  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
24731
  return quoteCharge !== undefined && localAndQuoteQuantitiesDiffer;
24562
24732
  });
24563
- const charges = featureIdsToUpdate.map(featureId => {
24733
+ const charges = featureIdsToUpdate
24734
+ .map(featureId => {
24564
24735
  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
24736
  const quantity = getFeatureQuantity(featureId, featureQuantities);
24566
24737
  if (!quantity) {
24567
- throw new Error('Quantity is undefined');
24738
+ console.error('Quantity is undefined');
24739
+ return;
24568
24740
  }
24569
24741
  if (!(quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.id)) {
24570
- throw new Error('Quote charge for featureId is undefined');
24742
+ console.error('Quote charge for featureId is undefined');
24743
+ return;
24571
24744
  }
24572
24745
  return {
24573
24746
  id: quoteCharge.id,
24574
24747
  quantity: quantity,
24575
24748
  };
24576
- });
24749
+ })
24750
+ .filter(charge => charge !== undefined);
24577
24751
  if (charges.length === 0) {
24578
24752
  return;
24579
24753
  }
@@ -24641,6 +24815,44 @@ const useQuoteQuantities = ({ selectedPriceList, quote, }) => {
24641
24815
  };
24642
24816
  };
24643
24817
 
24818
+ const mutation$6 = t(`
24819
+ mutation QuoteRecalculateTaxes($id: ID!) {
24820
+ quoteRecalculateTaxes(id: $id) {
24821
+ quote {
24822
+ ...QuoteContext_QuoteFragment
24823
+ id
24824
+ }
24825
+ errors
24826
+ }
24827
+ }
24828
+ `, [QuoteContext_QuoteFragment]);
24829
+ const quoteRecalculateTaxes = async ({ quoteId, apiHost, token, }) => {
24830
+ var _a;
24831
+ const response = await execute(mutation$6, { apiHost, token }, { id: quoteId });
24832
+ return (_a = response.quoteRecalculateTaxes) === null || _a === void 0 ? void 0 : _a.quote;
24833
+ };
24834
+
24835
+ const useQuoteRecalculateTaxes = () => {
24836
+ const token = useToken();
24837
+ const { apiHost } = react.useContext(BunnyContext);
24838
+ const { setQuoteQueryData } = useSetQuoteQueryData();
24839
+ const { mutate: quoteRecalculateTaxesMutation, isPending: isRecalculatingTaxes } = reactQuery.useMutation({
24840
+ mutationFn: async ({ quoteId }) => {
24841
+ return await quoteRecalculateTaxes({ quoteId, apiHost, token });
24842
+ },
24843
+ onSuccess: quote => {
24844
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
24845
+ throw new Error('Quote ID is undefined');
24846
+ }
24847
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, quote);
24848
+ },
24849
+ });
24850
+ return {
24851
+ quoteRecalculateTaxesMutation,
24852
+ isRecalculatingTaxes,
24853
+ };
24854
+ };
24855
+
24644
24856
  function useFeatureAddonsPending() {
24645
24857
  const [featureAddonsLoading, setFeatureAddonsLoading] = react.useState([]);
24646
24858
  const addFeatureAddonLoading = (featureAddonId) => {
@@ -24664,6 +24876,7 @@ function QuoteProvider({ children }) {
24664
24876
  // Hooks
24665
24877
  const token = useToken();
24666
24878
  const { isFeatureAddonsLoading, addFeatureAddonLoading, removeFeatureAddonLoading } = useFeatureAddonsPending();
24879
+ const { quoteRecalculateTaxesMutation } = useQuoteRecalculateTaxes();
24667
24880
  const { quote: maskedQuote, isQuotePending } = useQuoteCreate({
24668
24881
  upgradingSubscription,
24669
24882
  selectedPriceList: selectedPriceList,
@@ -24699,6 +24912,7 @@ function QuoteProvider({ children }) {
24699
24912
  onChangeSelectedPriceList: handleChangeSelectedPriceList,
24700
24913
  onChangeQuantity,
24701
24914
  getFeatureQuantity,
24915
+ onRecalculateTaxes: (id) => quoteRecalculateTaxesMutation({ quoteId: id }),
24702
24916
  }, children: children }));
24703
24917
  }
24704
24918
 
@@ -24725,40 +24939,6 @@ function priceDescriptionString({ unitName, showPriceAsMonthly, periodMonths, pr
24725
24939
  return `Per ${unitName && !priceListHasFlatFeeCharges ? `${unitName.toLowerCase()} / ` : ''}${showPriceAsMonthly ? 'month' : periodLabel}`;
24726
24940
  }
24727
24941
 
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
24942
  const { Text: Text$b } = antd.Typography;
24763
24943
  const PriceTierPrice = ({ currencyId, priceDecimals, tier, }) => {
24764
24944
  return (jsxRuntime.jsx(Text$b, { className: "bunny-text-white", children: formatCurrency(tier.price, currencyId, priceDecimals) }));
@@ -24782,32 +24962,6 @@ const PriceTierRow = ({ tier: maskedTier, nextTier: maskedNextTier, }) => {
24782
24962
  return jsxRuntime.jsx(Text$a, { className: "bunny-text-white", children: text });
24783
24963
  };
24784
24964
 
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
24965
  const { Text: Text$9 } = antd.Typography;
24812
24966
  const ChargePriceTiers_PriceListChargeFragment = t(`
24813
24967
  fragment ChargePriceTiers_PriceListChargeFragment on PriceListCharge {
@@ -25442,57 +25596,13 @@ const getAvailablePlansAndPriceLists = ({ availablePriceLists, priceListChangeOp
25442
25596
  return {
25443
25597
  availablePriceListsArray,
25444
25598
  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;
25599
+ };
25600
+ };
25601
+ const everythingInPlusString = ({ priceList }) => {
25602
+ return `Everything in ${priceList.plan.name}, plus`;
25493
25603
  };
25494
25604
 
25495
- const mutation = t(`
25605
+ const mutation$5 = t(`
25496
25606
  mutation QuoteChargeDelete($quoteChargeId: ID!) {
25497
25607
  quoteChargeDelete(quoteChargeId: $quoteChargeId) {
25498
25608
  errors
@@ -25510,21 +25620,76 @@ const mutation = t(`
25510
25620
  `, [QuoteContext_QuoteFragment]);
25511
25621
  const quoteChargeDelete = async ({ quoteChargeId, token, apiHost }) => {
25512
25622
  var _a, _b, _c, _d;
25513
- const response = await execute(mutation, { apiHost, token }, { quoteChargeId });
25623
+ const response = await execute(mutation$5, { apiHost, token }, { quoteChargeId });
25514
25624
  if ((_a = response.quoteChargeDelete) === null || _a === void 0 ? void 0 : _a.errors) {
25515
25625
  throw new Error((_c = (_b = response.quoteChargeDelete) === null || _b === void 0 ? void 0 : _b.errors) === null || _c === void 0 ? void 0 : _c[0]);
25516
25626
  }
25517
25627
  return (_d = response.quoteChargeDelete) === null || _d === void 0 ? void 0 : _d.quoteCharge;
25518
25628
  };
25519
25629
 
25520
- const useQuoteUpdateFeatureAddon = (quote, featureAddon) => {
25630
+ const mutation$4 = t(`
25631
+ mutation QuoteChargeCreate(
25632
+ $quoteChangeId: ID!
25633
+ $startDate: ISO8601Date!
25634
+ $endDate: ISO8601Date
25635
+ $priceListChargeId: ID
25636
+ $subscriptionChargeId: ID
25637
+ $price: Float
25638
+ $quantity: Int
25639
+ ) {
25640
+ quoteChargeCreate(
25641
+ endDate: $endDate
25642
+ price: $price
25643
+ priceListChargeId: $priceListChargeId
25644
+ quantity: $quantity
25645
+ quoteChangeId: $quoteChangeId
25646
+ startDate: $startDate
25647
+ subscriptionChargeId: $subscriptionChargeId
25648
+ ) {
25649
+ quoteCharge {
25650
+ quoteChange {
25651
+ id
25652
+ quoteId
25653
+ quote {
25654
+ ...QuoteContext_QuoteFragment
25655
+ }
25656
+ }
25657
+ id
25658
+ }
25659
+ }
25660
+ }
25661
+ `, [QuoteContext_QuoteFragment]);
25662
+ const quoteChargeCreate = async ({ price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId, token, apiHost, }) => {
25663
+ var _a;
25664
+ const response = await execute(mutation$4, { apiHost, token }, { price, priceListChargeId, quantity, quoteChangeId, startDate, subscriptionChargeId });
25665
+ return (_a = response === null || response === void 0 ? void 0 : response.quoteChargeCreate) === null || _a === void 0 ? void 0 : _a.quoteCharge;
25666
+ };
25667
+
25668
+ const useQuoteUpdateFeatureAddon = (maskedQuote, featureAddon) => {
25521
25669
  const { apiHost } = react.useContext(BunnyContext);
25522
25670
  const { addFeatureAddonLoading, removeFeatureAddonLoading } = react.useContext(QuoteContext);
25523
25671
  const token = useToken();
25524
- const queryClient = reactQuery.useQueryClient();
25672
+ const { setQuoteQueryData } = useSetQuoteQueryData();
25673
+ // Read fragments
25674
+ const quote = readFragment(useQuoteUpdateFeatureAddon_QuoteFragment, maskedQuote);
25525
25675
  const addedQuoteChargeId = react.useRef();
25526
25676
  function handleAddFeatureAddon() {
25527
- quoteChargeCreateMutation();
25677
+ if (!token)
25678
+ throw new Error('Token is required');
25679
+ if (!quote)
25680
+ throw new Error('Editing quote is required');
25681
+ const quoteChangeId = findQuoteChangeForFeatureAddon(quote);
25682
+ if (!quoteChangeId)
25683
+ throw new Error('No available quote change for feature add-on');
25684
+ console.log('quote', quote);
25685
+ console.log('startDate', quote === null || quote === void 0 ? void 0 : quote.startDate);
25686
+ quoteChargeCreateMutation({
25687
+ quoteChangeId: quoteChangeId.id,
25688
+ priceListChargeId: featureAddon.id,
25689
+ startDate: quote === null || quote === void 0 ? void 0 : quote.startDate,
25690
+ apiHost,
25691
+ token,
25692
+ });
25528
25693
  }
25529
25694
  function handleRemoveFeatureAddon() {
25530
25695
  if (!addedQuoteChargeId.current)
@@ -25532,30 +25697,16 @@ const useQuoteUpdateFeatureAddon = (quote, featureAddon) => {
25532
25697
  quoteChargeDeleteMutation({ quoteChargeId: addedQuoteChargeId.current });
25533
25698
  }
25534
25699
  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);
25700
+ mutationFn: quoteChargeCreate,
25701
+ onSuccess: quoteCharge => {
25702
+ addedQuoteChargeId.current = quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.id;
25703
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
25704
+ throw new Error('Quote ID is undefined');
25705
+ }
25706
+ if (!(quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.quoteChange.quote)) {
25707
+ throw new Error('Quote is undefined');
25708
+ }
25709
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.quoteChange.quote);
25559
25710
  },
25560
25711
  });
25561
25712
  const { mutate: quoteChargeDeleteMutation, isPending: isDeletingFeatureAddon } = reactQuery.useMutation({
@@ -25565,11 +25716,13 @@ const useQuoteUpdateFeatureAddon = (quote, featureAddon) => {
25565
25716
  },
25566
25717
  onSuccess: quoteCharge => {
25567
25718
  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);
25719
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
25720
+ throw new Error('Quote ID is undefined');
25721
+ }
25722
+ if (!(quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.quoteChange.quote)) {
25723
+ throw new Error('Quote is undefined');
25724
+ }
25725
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, quoteCharge === null || quoteCharge === void 0 ? void 0 : quoteCharge.quoteChange.quote);
25573
25726
  },
25574
25727
  });
25575
25728
  const isPending = isCreatingFeatureAddon || isDeletingFeatureAddon;
@@ -25649,10 +25802,11 @@ const FeatureAddonRow_PriceListChargeFragment = t(`
25649
25802
  }
25650
25803
  `, [isAddonPurchased_PriceListChargeFragment, PricingTooltip_PriceListChargeFragment]);
25651
25804
  function FeatureAddonRow({ featureAddon: maskedFeatureAddon, priceList: maskedPriceList, }) {
25805
+ const { quote: maskedQuote, selectedPriceList } = react.useContext(QuoteContext);
25652
25806
  // Read fragments
25653
25807
  const featureAddon = readFragment(FeatureAddonRow_PriceListChargeFragment, maskedFeatureAddon);
25654
25808
  const priceList = readFragment(FeatureAddonRow_PriceListFragment, maskedPriceList);
25655
- const { quote, selectedPriceList } = react.useContext(QuoteContext);
25809
+ const quote = readFragment(FeatureAddonRow_QuoteFragment, maskedQuote);
25656
25810
  const { handleAddFeatureAddon, handleRemoveFeatureAddon, isPending, isChecked } = useQuoteUpdateFeatureAddon(quote, featureAddon);
25657
25811
  const { brandColor } = useBrand();
25658
25812
  const { upgradingSubscription } = react.useContext(SubscriptionsContext);
@@ -25867,107 +26021,84 @@ function AddonPlanModal({ onClose, priceList: maskedPriceList, }) {
25867
26021
  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
26022
  }
25869
26023
 
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
26024
+ const mutation$3 = t(`
26025
+ mutation QuoteChangeCreate($quoteId: ID!, $priceListId: ID!, $parentQuoteChangeId: ID!) {
26026
+ quoteChangeCreate(
26027
+ quoteId: $quoteId
26028
+ priceListId: $priceListId
26029
+ parentQuoteChangeId: $parentQuoteChangeId
26030
+ ) {
26031
+ errors
26032
+ quoteChange {
26033
+ id
26034
+ quote {
26035
+ ...QuoteContext_QuoteFragment
26036
+ }
26037
+ }
25887
26038
  }
25888
26039
  }
25889
- }
25890
- }
25891
- `;
26040
+ `, [QuoteContext_QuoteFragment]);
25892
26041
  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;
26042
+ const response = await execute(mutation$3, { apiHost, token }, { parentQuoteChangeId, priceListId, quoteId });
25908
26043
  return response.quoteChangeCreate;
25909
26044
  };
25910
26045
 
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
26046
+ const mutation$2 = t(`
26047
+ mutation QuoteChangeDelete($id: ID!) {
26048
+ quoteChangeDelete(id: $id) {
26049
+ errors
26050
+ quoteChange {
26051
+ quote {
26052
+ ...QuoteContext_QuoteFragment
26053
+ }
25919
26054
  }
25920
26055
  }
25921
26056
  }
25922
- }
25923
- `;
26057
+ `, [QuoteContext_QuoteFragment]);
25924
26058
  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;
26059
+ const response = await execute(mutation$2, { apiHost, token }, { id });
25938
26060
  return response.quoteChangeDelete;
25939
26061
  };
25940
26062
 
25941
- const useToggleAddonPlan = (quote, addonPriceListId, selectedPriceList, setIsAddonPlanLoading) => {
26063
+ const useToggleAddonPlan = (maskedQuote, addonPriceListId, selectedPriceList, setIsAddonPlanLoading) => {
25942
26064
  const token = useToken();
25943
26065
  const isAdded = react.useRef(false);
25944
- const queryClient = reactQuery.useQueryClient();
25945
26066
  const { apiHost } = react.useContext(BunnyContext);
26067
+ const { setQuoteQueryData } = useSetQuoteQueryData();
26068
+ // Read fragments
26069
+ const quote = readFragment(useToggleAddonPlan_QuoteFragment, maskedQuote);
25946
26070
  const parentQuoteChange = react.useMemo(() => {
25947
- return quote === null || quote === void 0 ? void 0 : quote.quoteChanges.find(qc => qc.priceList.id === selectedPriceList.id);
26071
+ var _a;
26072
+ 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
26073
  }, [quote, selectedPriceList]);
25949
26074
  const { mutate: addAddonQuoteChange, isPending: isAddingAddonQuoteChange } = reactQuery.useMutation({
25950
26075
  mutationFn: quoteChangeCreate,
25951
- onSuccess: (quoteChangeCreate) => {
26076
+ onSuccess: quoteChangeCreate => {
26077
+ var _a;
25952
26078
  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);
26079
+ const updatedQuote = (_a = quoteChangeCreate === null || quoteChangeCreate === void 0 ? void 0 : quoteChangeCreate.quoteChange) === null || _a === void 0 ? void 0 : _a.quote;
26080
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
26081
+ throw new Error('Updated quote ID not found');
26082
+ }
26083
+ if (!updatedQuote) {
26084
+ throw new Error('Updated quote not found');
26085
+ }
26086
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, updatedQuote);
25959
26087
  },
25960
26088
  });
25961
26089
  const { mutate: deleteQuoteChange, isPending: isDeletingQuoteChange } = reactQuery.useMutation({
25962
26090
  mutationFn: quoteChangeDelete,
25963
- onSuccess: (quoteChangeDelete) => {
26091
+ onSuccess: quoteChangeDelete => {
26092
+ var _a;
25964
26093
  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);
26094
+ const updatedQuote = (_a = quoteChangeDelete === null || quoteChangeDelete === void 0 ? void 0 : quoteChangeDelete.quoteChange) === null || _a === void 0 ? void 0 : _a.quote;
26095
+ if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
26096
+ throw new Error('Updated quote ID not found');
26097
+ }
26098
+ if (!updatedQuote) {
26099
+ throw new Error('Updated quote not found');
26100
+ }
26101
+ setQuoteQueryData(quote === null || quote === void 0 ? void 0 : quote.id, updatedQuote);
25971
26102
  },
25972
26103
  });
25973
26104
  function handleAddAddonQuoteChange() {
@@ -25977,6 +26108,9 @@ const useToggleAddonPlan = (quote, addonPriceListId, selectedPriceList, setIsAdd
25977
26108
  if (!(quote === null || quote === void 0 ? void 0 : quote.id)) {
25978
26109
  throw new Error('Quote ID not found');
25979
26110
  }
26111
+ if (!parentQuoteChange.id) {
26112
+ throw new Error('Parent quote change ID not found');
26113
+ }
25980
26114
  addAddonQuoteChange({
25981
26115
  parentQuoteChangeId: parentQuoteChange.id,
25982
26116
  priceListId: addonPriceListId,
@@ -25986,9 +26120,10 @@ const useToggleAddonPlan = (quote, addonPriceListId, selectedPriceList, setIsAdd
25986
26120
  });
25987
26121
  }
25988
26122
  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');
26123
+ var _a;
26124
+ 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; });
26125
+ if (!(quoteChange === null || quoteChange === void 0 ? void 0 : quoteChange.id)) {
26126
+ throw new Error('Quote change ID not found');
25992
26127
  }
25993
26128
  deleteQuoteChange({
25994
26129
  id: quoteChange.id,
@@ -26022,6 +26157,7 @@ const AddonPlanRow_PriceListFragment = t(`
26022
26157
  plan {
26023
26158
  description
26024
26159
  name
26160
+ pricingDescription
26025
26161
  }
26026
26162
  ...PriceListCardPriceDescription_PriceListFragment
26027
26163
  ...PriceListCardPrice_PriceListFragment
@@ -26035,16 +26171,18 @@ const AddonPlanRow_PriceListFragment = t(`
26035
26171
  PriceListCardPriceDescription_PriceListFragment,
26036
26172
  ]);
26037
26173
  function AddonPlanRow({ addonPriceList: maskedAddonPriceList, selectedPriceList, onClickSelect, isPurchased, }) {
26038
- var _a, _b, _c, _d, _e, _f;
26174
+ var _a, _b, _c, _d, _e, _f, _g;
26039
26175
  // Read fragments
26040
26176
  const addonPriceList = readFragment(AddonPlanRow_PriceListFragment, maskedAddonPriceList);
26041
- const { quote, setIsAddonPlanLoading } = react.useContext(QuoteContext);
26177
+ const { quote: maskedQuote, setIsAddonPlanLoading } = react.useContext(QuoteContext);
26178
+ const quote = readFragment(AddonPlanRow_QuoteFragment, maskedQuote);
26042
26179
  const { shadow, isInPreviewMode } = react.useContext(SubscriptionsContext);
26043
26180
  const { isPending, addedQuoteChange, addAddonQuoteChange, deleteQuoteChange } = useToggleAddonPlan(quote, addonPriceList.id, selectedPriceList, setIsAddonPlanLoading);
26044
26181
  const activeCharge = (_a = getActivePlanPriceData(addonPriceList, selectedPriceList)) === null || _a === void 0 ? void 0 : _a.activeCharge;
26045
26182
  // Derived state
26046
26183
  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) => {
26184
+ const hasCustomPrice = ((_b = addonPriceList.plan) === null || _b === void 0 ? void 0 : _b.pricingDescription) != null;
26185
+ 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
26186
  if (checked) {
26049
26187
  addAddonQuoteChange();
26050
26188
  }
@@ -26068,7 +26206,7 @@ const AddonPlans_PlanFragment = t(`
26068
26206
  }
26069
26207
  `, [AddonPlanModal_PriceListFragment, AddonPlanRow_PriceListFragment]);
26070
26208
 
26071
- const query = t(`
26209
+ const query$2 = t(`
26072
26210
  query PriceList($id: ID!) {
26073
26211
  priceList(id: $id) {
26074
26212
  addonPlans {
@@ -26082,7 +26220,7 @@ const query = t(`
26082
26220
  `, [AddonPlans_PlanFragment]);
26083
26221
  const getAddonPlans = async ({ token, id, apiHost, }) => {
26084
26222
  var _a;
26085
- const response = await execute(query, { apiHost, token }, { id });
26223
+ const response = await execute(query$2, { apiHost, token }, { id });
26086
26224
  const addonPlans = (_a = response === null || response === void 0 ? void 0 : response.priceList) === null || _a === void 0 ? void 0 : _a.addonPlans;
26087
26225
  // for each addon plan, filter out the price lists that are not visible
26088
26226
  const visibleAddonPlans = addonPlans === null || addonPlans === void 0 ? void 0 : addonPlans.map(addonPlan => {
@@ -26190,7 +26328,10 @@ const PriceListGrid = ({ availablePriceLists, priceListChangeOptions, priceListS
26190
26328
  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
26329
  };
26192
26330
 
26193
- const createAvailableBillingPeriods = (priceLists, selectedProduct) => {
26331
+ const createAvailableBillingPeriods = (priceLists, selectedProduct, upgradingSubscription) => {
26332
+ if ((upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.plan.addon) === true) {
26333
+ return [upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.periodMonths];
26334
+ }
26194
26335
  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
26336
  };
26196
26337
  const showInfoNotification$1 = common.useInfoNotification();
@@ -26204,11 +26345,18 @@ const PriceListSelector = ({ arePlanChangeOptionsLoading, areSubscriptionsLoadin
26204
26345
  const [selectedBillingPeriod, setSelectedBillingPeriod] = react.useState(null);
26205
26346
  const [priceListStart, setPriceListStart] = react.useState(0);
26206
26347
  // 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]);
26348
+ 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]);
26349
+ // TODO: clean up available pricelists calculation. We should calculate it once, not three times.
26350
+ const subscriptionIsAddon = (upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList.plan.addon) === true;
26208
26351
  const availablePriceLists = react.useMemo(() => {
26209
26352
  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)) || []);
26353
+ 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 &&
26354
+ priceList.product.id === (selectedProduct === null || selectedProduct === void 0 ? void 0 : selectedProduct.id));
26355
+ // If the subscription is an addon, we should only show its price lists because we don't support changing add-on plans.
26356
+ if (subscriptionIsAddon) {
26357
+ 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))) || []);
26358
+ }
26359
+ return priceLists.filter(priceList => priceList.plan.addon !== true) || [];
26212
26360
  }, [priceListChangeOptions, selectedBillingPeriod, selectedProduct]);
26213
26361
  // Handlers
26214
26362
  const onChangeBillingPeriod = react.useCallback((billingPeriod) => {
@@ -26237,7 +26385,7 @@ const PriceListSelector = ({ arePlanChangeOptionsLoading, areSubscriptionsLoadin
26237
26385
  }
26238
26386
  }, [selectedPriceList, priceListChangeOptions, upgradingSubscription]);
26239
26387
  const onChangeProduct = react.useCallback((product) => {
26240
- const newAvailableBillingPeriods = createAvailableBillingPeriods(priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, product);
26388
+ const newAvailableBillingPeriods = createAvailableBillingPeriods(priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, product, upgradingSubscription);
26241
26389
  if (selectedBillingPeriod &&
26242
26390
  !(newAvailableBillingPeriods === null || newAvailableBillingPeriods === void 0 ? void 0 : newAvailableBillingPeriods.includes(billingPeriodConverter(selectedBillingPeriod)))) {
26243
26391
  onChangeBillingPeriod(periodMonthsConverter((newAvailableBillingPeriods === null || newAvailableBillingPeriods === void 0 ? void 0 : newAvailableBillingPeriods[0]) !== undefined ? newAvailableBillingPeriods[0] : 1));
@@ -26248,7 +26396,7 @@ const PriceListSelector = ({ arePlanChangeOptionsLoading, areSubscriptionsLoadin
26248
26396
  const initialProduct = (_a = priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.products) === null || _a === void 0 ? void 0 : _a[0];
26249
26397
  const initialBillingPeriod = react.useMemo(() => {
26250
26398
  var _a, _b, _c;
26251
- const initialAvailableBillingPeriods = createAvailableBillingPeriods(priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, initialProduct);
26399
+ const initialAvailableBillingPeriods = createAvailableBillingPeriods(priceListChangeOptions === null || priceListChangeOptions === void 0 ? void 0 : priceListChangeOptions.priceLists, initialProduct, upgradingSubscription);
26252
26400
  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
26401
  if ((upgradingSubscription === null || upgradingSubscription === void 0 ? void 0 : upgradingSubscription.priceList) &&
26254
26402
  periodMonthsConverted &&
@@ -26904,80 +27052,177 @@ const PageSubTitle = ({ title }) => {
26904
27052
  return (jsxRuntime.jsx("div", { className: "bunny-shrink-0", style: { color: secondaryColor }, children: title }));
26905
27053
  };
26906
27054
 
26907
- const MUTATION = `
26908
- mutation BillingDetailsUpdate(
26909
- $attributes: BillingDetailsAttributes!) {
26910
- billingDetailsUpdate(
26911
- attributes: $attributes
26912
- ) {
26913
- billingDetails {
26914
- billingCity
26915
- billingContact {
26916
- email
27055
+ const AccountContactsFragment = t(`
27056
+ fragment AccountContactsFragment on Contact {
27057
+ id
27058
+ email
27059
+ firstName
27060
+ }
27061
+ `, []);
27062
+
27063
+ const AddContactButton = ({ onClick }) => {
27064
+ 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" }) }));
27065
+ };
27066
+
27067
+ const useSetAccountContactsQueryData = () => {
27068
+ const token = useToken();
27069
+ const queryClient = reactQuery.useQueryClient();
27070
+ const setAccountContactsQueryData = (accountId, updater) => {
27071
+ queryClient.setQueryData(QueryKeyFactory.accountContactsKey({ accountId, token }), updater);
27072
+ };
27073
+ return { setAccountContactsQueryData };
27074
+ };
27075
+
27076
+ const mutation$1 = t(`
27077
+ mutation ContactCreate($attributes: ContactAttributes!) {
27078
+ contactCreate(attributes: $attributes) {
27079
+ contact {
27080
+ id
27081
+ account {
27082
+ contacts {
27083
+ ...AccountContactsFragment
27084
+ }
26917
27085
  }
26918
- billingCountry
26919
- billingState
26920
- billingStreet
26921
- billingZip
26922
- name
26923
- taxNumber
26924
27086
  }
26925
27087
  errors
26926
27088
  }
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,
27089
+ }
27090
+ `, [AccountContactsFragment]);
27091
+ const contactCreate = async ({ attributes, apiHost, token }) => {
27092
+ var _a, _b;
27093
+ const response = await execute(mutation$1, { apiHost, token }, { attributes });
27094
+ if ((_a = response.contactCreate) === null || _a === void 0 ? void 0 : _a.errors) {
27095
+ throw new Error(response.contactCreate.errors[0]);
27096
+ }
27097
+ return (_b = response.contactCreate) === null || _b === void 0 ? void 0 : _b.contact;
27098
+ };
27099
+
27100
+ const AddContactModal = ({ open, onClose, accountId, onContactCreated, }) => {
27101
+ const [form] = antd.Form.useForm();
27102
+ const { apiHost } = react.useContext(BunnyContext);
27103
+ const token = useToken();
27104
+ const showErrorNotification = common.useErrorNotification();
27105
+ const showSuccessNotification = common.useSuccessNotification();
27106
+ const { setAccountContactsQueryData } = useSetAccountContactsQueryData();
27107
+ const { mutate: createContact, isPending: isCreatingContact } = reactQuery.useMutation({
27108
+ mutationFn: (attributes) => contactCreate({ attributes, apiHost, token }),
27109
+ onSuccess: newContact => {
27110
+ var _a, _b;
27111
+ showSuccessNotification('Contact created successfully');
27112
+ // Add the new contact to the cache
27113
+ if (newContact && accountId) {
27114
+ 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);
27115
+ }
27116
+ onClose();
27117
+ form.resetFields();
27118
+ const newContactData = newContact ? readFragment(AccountContactsFragment, newContact) : null;
27119
+ if (newContactData === null || newContactData === void 0 ? void 0 : newContactData.id) {
27120
+ onContactCreated === null || onContactCreated === void 0 ? void 0 : onContactCreated(newContactData.id);
27121
+ }
27122
+ },
26937
27123
  });
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;
27124
+ const handleAddContact = () => {
27125
+ if (!accountId) {
27126
+ showErrorNotification('Account ID is required to create a contact');
27127
+ return;
27128
+ }
27129
+ form.validateFields().then(values => {
27130
+ createContact({
27131
+ email: values.email || null,
27132
+ firstName: values.firstName || null,
27133
+ lastName: values.lastName || null,
27134
+ accountId: accountId,
27135
+ portalAccess: true,
27136
+ });
27137
+ });
27138
+ };
27139
+ return (jsxRuntime.jsx(antd.Modal, { title: "Add new contact", open: open, onCancel: () => {
27140
+ onClose();
27141
+ form.resetFields();
27142
+ }, footer: [
27143
+ jsxRuntime.jsx(antd.Button, { onClick: () => {
27144
+ onClose();
27145
+ form.resetFields();
27146
+ }, children: "Cancel" }, "cancel"),
27147
+ jsxRuntime.jsx(antd.Button, { type: "primary", loading: isCreatingContact, onClick: handleAddContact, children: "Add contact" }, "submit"),
27148
+ ], 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: [
27149
+ { required: true, message: 'Email is required' },
27150
+ { type: 'email', message: 'Please enter a valid email' },
27151
+ ], children: jsxRuntime.jsx(antd.Input, { placeholder: "Enter email" }) })] }) }));
26942
27152
  };
26943
27153
 
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 {
27154
+ const BillingDetailsSection_AccountFragment = t(`
27155
+ fragment BillingDetailsSection_AccountFragment on Account {
26958
27156
  id
27157
+ name
27158
+ billingStreet
27159
+ billingCity
27160
+ billingState
27161
+ billingZip
27162
+ billingCountry
27163
+ taxNumber
27164
+ billingContactId
27165
+ secondaryBillingContactIds
27166
+ billingContact {
27167
+ email
27168
+ firstName
27169
+ }
26959
27170
  }
26960
- }
26961
- }`;
26962
- const getBillingDetails = async ({ token, apiHost }) => {
27171
+ `, []);
27172
+
27173
+ const mutation = t(`
27174
+ mutation AccountUpdate($id: ID!, $attributes: AccountAttributes!) {
27175
+ accountUpdate(id: $id, attributes: $attributes) {
27176
+ account {
27177
+ ...BillingDetailsSection_AccountFragment
27178
+ }
27179
+ errors
27180
+ }
27181
+ }
27182
+ `, [BillingDetailsSection_AccountFragment]);
27183
+ const accountUpdate = async ({ accountId, attributes, apiHost, token, }) => {
26963
27184
  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);
27185
+ const response = await execute(mutation, { apiHost, token }, { id: accountId, attributes });
27186
+ return (_a = response.accountUpdate) === null || _a === void 0 ? void 0 : _a.account;
27187
+ };
27188
+
27189
+ const query$1 = t(`
27190
+ query GetAccount($id: ID!) {
27191
+ account(id: $id) {
27192
+ ...BillingDetailsSection_AccountFragment
27193
+ }
27194
+ }
27195
+ `, [BillingDetailsSection_AccountFragment]);
27196
+ const getAccount = async ({ accountId, apiHost, token, }) => {
27197
+ const response = await execute(query$1, { apiHost, token }, { id: accountId });
27198
+ return response.account;
27199
+ };
27200
+
27201
+ const query = t(`
27202
+ query GetAccountContacts($accountId: ID!) {
27203
+ account(id: $accountId) {
27204
+ id
27205
+ contacts {
27206
+ ...AccountContactsFragment
27207
+ }
27208
+ }
26971
27209
  }
26972
- return response === null || response === void 0 ? void 0 : response.billingDetails;
27210
+ `, [AccountContactsFragment]);
27211
+ const getAccountContacts = async ({ accountId, apiHost, token, }) => {
27212
+ var _a;
27213
+ const response = await execute(query, { apiHost, token }, { accountId });
27214
+ return (_a = response.account) === null || _a === void 0 ? void 0 : _a.contacts;
26973
27215
  };
26974
27216
 
26975
27217
  const { Text } = antd.Typography;
26976
27218
  function BillingDetailsSection({ hidePaymentMethodForm, countryListFilter, }) {
27219
+ var _a, _b, _c;
26977
27220
  // State
26978
27221
  const [isFormEdited, setIsFormEdited] = react.useState(false);
26979
27222
  const [form] = antd.Form.useForm();
26980
27223
  const values = antd.Form.useWatch([], form);
27224
+ const [isAddContactModalOpen, setIsAddContactModalOpen] = react.useState(false);
27225
+ const [contactFieldType, setContactFieldType] = react.useState(null);
26981
27226
  // Context
26982
27227
  const { apiHost } = react.useContext(BunnyContext);
26983
27228
  const token = useToken();
@@ -26986,14 +27231,37 @@ function BillingDetailsSection({ hidePaymentMethodForm, countryListFilter, }) {
26986
27231
  const queryClient = reactQuery.useQueryClient();
26987
27232
  const showErrorNotification = common.useErrorNotification();
26988
27233
  const showSuccessNotification = common.useSuccessNotification();
27234
+ const { currentUser } = useCurrentUserData(token);
27235
+ const accountId = (_a = currentUser === null || currentUser === void 0 ? void 0 : currentUser.account) === null || _a === void 0 ? void 0 : _a.id;
26989
27236
  // Queries
26990
- const { data: billingDetails, isLoading: isLoadingBillingDetails } = reactQuery.useQuery({
26991
- queryKey: common.QueryKeyFactory.default.billingDetailsKey({ token }),
26992
- queryFn: () => getBillingDetails({ token, apiHost }),
27237
+ const { data: maskedAccount, isLoading: isLoadingAccount } = reactQuery.useQuery({
27238
+ queryKey: QueryKeyFactory.accountBillingDetailsKey({ accountId, token }),
27239
+ queryFn: () => {
27240
+ if (!accountId) {
27241
+ throw new Error('Account ID is required');
27242
+ }
27243
+ return getAccount({ accountId, apiHost, token });
27244
+ },
27245
+ enabled: !!accountId,
27246
+ });
27247
+ const account = readFragment(BillingDetailsSection_AccountFragment, maskedAccount);
27248
+ const { data: contacts, isLoading: isLoadingContacts } = reactQuery.useQuery({
27249
+ queryKey: QueryKeyFactory.accountContactsKey({ accountId, token }),
27250
+ queryFn: () => {
27251
+ if (!accountId) {
27252
+ throw new Error('Account ID is required');
27253
+ }
27254
+ return getAccountContacts({ accountId, apiHost, token });
27255
+ },
27256
+ enabled: !!accountId,
26993
27257
  });
26994
- const { mutate: updateBillingDetails, isPending: isUpdatingBillingDetails } = reactQuery.useMutation({
27258
+ const { mutate: updateAccount, isPending: isUpdatingAccount } = reactQuery.useMutation({
26995
27259
  mutationFn: async (changedFormData) => {
26996
- const updatedBillingDetails = await billingDetailsUpdate({
27260
+ if (!accountId) {
27261
+ throw new Error('Account ID is required');
27262
+ }
27263
+ const updatedAccount = await accountUpdate({
27264
+ accountId,
26997
27265
  attributes: {
26998
27266
  name: changedFormData.name,
26999
27267
  billingStreet: changedFormData.billingStreet,
@@ -27001,77 +27269,92 @@ function BillingDetailsSection({ hidePaymentMethodForm, countryListFilter, }) {
27001
27269
  billingZip: changedFormData.billingZip,
27002
27270
  billingState: changedFormData.billingState,
27003
27271
  billingCountry: changedFormData.billingCountry,
27004
- billingContactEmail: changedFormData.billingContactEmail,
27005
27272
  taxNumber: changedFormData.taxNumber,
27273
+ billingContactId: changedFormData.billingContactId || null,
27274
+ secondaryBillingContactIds: Array.isArray(changedFormData.secondaryBillingContactIds)
27275
+ ? changedFormData.secondaryBillingContactIds
27276
+ : null,
27006
27277
  },
27007
27278
  token,
27008
27279
  apiHost,
27009
27280
  });
27010
- queryClient.setQueryData(common.QueryKeyFactory.default.billingDetailsKey({ token }), (old) => {
27011
- return {
27012
- ...old,
27013
- ...updatedBillingDetails.billingDetails,
27014
- };
27015
- });
27016
- return updatedBillingDetails;
27281
+ queryClient.setQueryData(QueryKeyFactory.accountBillingDetailsKey({ accountId, token }), updatedAccount);
27282
+ return updatedAccount;
27017
27283
  },
27018
27284
  onSuccess: () => {
27019
27285
  showSuccessNotification('Your account details have been saved');
27020
27286
  queryClient.invalidateQueries({
27021
- queryKey: common.QueryKeyFactory.default.taxationRequiredAccountFieldsKey({
27287
+ queryKey: QueryKeyFactory.taxationRequiredAccountFieldsKey({
27022
27288
  token,
27023
27289
  }),
27024
27290
  });
27025
27291
  },
27026
27292
  });
27027
- // Set form values when billing details are loaded
27293
+ // Set form values when account is loaded
27028
27294
  react.useEffect(() => {
27029
- var _a;
27030
- if (billingDetails) {
27295
+ if (account) {
27031
27296
  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,
27297
+ billingStreet: account.billingStreet,
27298
+ billingCity: account.billingCity,
27299
+ billingZip: account.billingZip,
27300
+ billingState: account.billingState,
27301
+ billingCountry: account.billingCountry,
27302
+ billingContactId: account.billingContactId,
27303
+ secondaryBillingContactIds: account.secondaryBillingContactIds,
27304
+ taxNumber: account.taxNumber,
27039
27305
  });
27040
27306
  }
27041
- }, [billingDetails]);
27307
+ }, [account]);
27042
27308
  react.useEffect(() => {
27043
27309
  form.validateFields({ validateOnly: true });
27044
27310
  const isFormEdited = () => {
27045
- var _a;
27046
- if (!billingDetails)
27311
+ if (!account)
27047
27312
  return false;
27048
27313
  const currentValues = form.getFieldsValue();
27049
27314
  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,
27315
+ billingStreet: account.billingStreet,
27316
+ billingCity: account.billingCity,
27317
+ billingZip: account.billingZip,
27318
+ billingState: account.billingState,
27319
+ billingCountry: account.billingCountry,
27320
+ billingContactId: account.billingContactId,
27321
+ secondaryBillingContactIds: account.secondaryBillingContactIds,
27322
+ taxNumber: account.taxNumber,
27057
27323
  };
27058
- return Object.keys(currentValues).some(key => {
27324
+ return Object.keys(accountValues).some(key => {
27059
27325
  const value = accountValues[key];
27060
- return currentValues[key] !== value;
27326
+ const currentValue = currentValues[key];
27327
+ // Handle array comparison for secondaryBillingContactIds
27328
+ if (Array.isArray(value) && Array.isArray(currentValue)) {
27329
+ return JSON.stringify(value === null || value === void 0 ? void 0 : value.sort()) !== JSON.stringify(currentValue === null || currentValue === void 0 ? void 0 : currentValue.sort());
27330
+ }
27331
+ return currentValue !== value;
27061
27332
  });
27062
27333
  };
27063
27334
  setIsFormEdited(isFormEdited());
27064
- }, [form, values, billingDetails]);
27335
+ }, [form, values, account]);
27065
27336
  // Validate form fields when isFormEdited changes
27066
27337
  react.useEffect(() => {
27067
27338
  const validateOnly = isFormEdited ? false : true;
27068
27339
  form.validateFields({ validateOnly: validateOnly });
27069
27340
  }, [isFormEdited]);
27341
+ const handleContactCreated = (contactId) => {
27342
+ if (contactFieldType === 'primary') {
27343
+ form.setFieldValue('billingContactId', contactId);
27344
+ }
27345
+ else if (contactFieldType === 'secondary') {
27346
+ const currentSecondaryContacts = form.getFieldValue('secondaryBillingContactIds') || [];
27347
+ if (!currentSecondaryContacts.includes(contactId)) {
27348
+ form.setFieldValue('secondaryBillingContactIds', [...currentSecondaryContacts, contactId]);
27349
+ }
27350
+ }
27351
+ setContactFieldType(null);
27352
+ };
27070
27353
  const saveBillingDetails = async () => {
27071
27354
  form.validateFields({ validateOnly: false }).then(async () => {
27072
27355
  try {
27073
27356
  await form.validateFields();
27074
- updateBillingDetails(form.getFieldsValue());
27357
+ updateAccount(form.getFieldsValue());
27075
27358
  }
27076
27359
  catch (error) {
27077
27360
  if (error instanceof Error) {
@@ -27089,21 +27372,38 @@ function BillingDetailsSection({ hidePaymentMethodForm, countryListFilter, }) {
27089
27372
  const filteredCountryList = react.useMemo(() => {
27090
27373
  return countryListFilter ? common.Lists.COUNTRY_LIST.filter(countryListFilter) : common.Lists.COUNTRY_LIST;
27091
27374
  }, [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" })] }) }));
27375
+ const isLoading = isLoadingAccount || isLoadingContacts;
27376
+ 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: [
27377
+ {
27378
+ required: false,
27379
+ },
27380
+ ], 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) => {
27381
+ var _a, _b;
27382
+ return ((_a = option === null || option === void 0 ? void 0 : option.label) !== null && _a !== void 0 ? _a : '').toLowerCase().includes(input.toLowerCase()) ||
27383
+ ((_b = option === null || option === void 0 ? void 0 : option.value) !== null && _b !== void 0 ? _b : '').toLowerCase().includes(input.toLowerCase());
27384
+ } }) }) })] }), 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 => {
27385
+ const contactData = readFragment(AccountContactsFragment, contact);
27386
+ return {
27387
+ label: (contactData === null || contactData === void 0 ? void 0 : contactData.firstName)
27388
+ ? `${contactData.firstName}`
27389
+ : contactData === null || contactData === void 0 ? void 0 : contactData.email,
27390
+ value: contactData === null || contactData === void 0 ? void 0 : contactData.id,
27391
+ };
27392
+ })) !== 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 => {
27393
+ const contactData = readFragment(AccountContactsFragment, contact);
27394
+ return {
27395
+ label: (contactData === null || contactData === void 0 ? void 0 : contactData.firstName)
27396
+ ? `${contactData.firstName}`
27397
+ : contactData === null || contactData === void 0 ? void 0 : contactData.email,
27398
+ value: contactData === null || contactData === void 0 ? void 0 : contactData.id,
27399
+ };
27400
+ })) !== null && _c !== void 0 ? _c : [], popupRender: menu => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [menu, jsxRuntime.jsx(AddContactButton, { onClick: () => {
27401
+ setContactFieldType('secondary');
27402
+ setIsAddContactModalOpen(true);
27403
+ } })] })) }) }), 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: () => {
27404
+ setIsAddContactModalOpen(false);
27405
+ setContactFieldType(null);
27406
+ }, accountId: accountId, onContactCreated: handleContactCreated })] }));
27107
27407
  }
27108
27408
 
27109
27409
  const BillingDetails = ({ className, countryListFilter, hideBillingDetailsForm = false, hidePaymentMethodForm = false, isCardEnabled = true, isUpgradeFromTrial = false, shadow = 'shadow-md', onSavePaymentMethod, }) => {