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