{"version":3,"names":["scCheckoutStockAlertCss","wp","i18n","__","additionalErrors","length","join","h","slot","hasOutOfStockItems","style","width","textAlign","stockErrors","map","item","index","name","this","busy","spinner","ScFormErrorProvider","componentWillLoad","maybeAddErrorsComponent","el","querySelector","errorsComponent","document","createElement","_b","_a","prepend","call","render","scLoginProviderCss","loggedIn","label","open","onScRequestClose","ref","loginForm","onScFormSubmit","e","type","required","autofocus","full","loading","submit","scOrderConfirmProviderCss","_e","_d","state$1","text","success","description","manualPaymentMethod","instructions"],"sources":["./src/components/controllers/checkout-form/checkout/checkout-stock-alert/sc-checkout-stock-alert.scss?tag=sc-checkout-stock-alert&encapsulation=shadow","./src/components/controllers/checkout-form/checkout/checkout-stock-alert/sc-checkout-stock-alert.tsx","./src/components/providers/checkout-unsaved-changes-warning/sc-checkout-unsaved-changes-warning.tsx","./src/components/providers/form-components-validator/sc-form-components-validator.tsx","./src/components/providers/form-error-provider/sc-form-error-provider.tsx","./src/components/providers/form-state-provider/sc-form-state-provider.tsx","./src/components/providers/sc-login-provider/sc-login-provider.css?tag=sc-login-provider&encapsulation=shadow","./src/components/providers/sc-login-provider/sc-login-provider.tsx","./src/components/providers/order-confirm-provider/sc-order-confirm-provider.scss?tag=sc-order-confirm-provider&encapsulation=shadow","./src/components/providers/order-confirm-provider/sc-order-confirm-provider.tsx","./src/components/providers/session-provider/sc-session-provider.tsx"],"sourcesContent":[":host {\n display: block;\n}\n\nsc-table {\n height: auto;\n}\n\nh4 {\n display: block;\n margin: 0;\n font-weight: var(--sc-font-weight-bold);\n font-size: var(--sc-font-size-medium);\n}\n\n.stock-alert {\n &__image {\n width: 50px;\n height: 50px;\n object-fit: cover;\n margin-right: 10px;\n display: block;\n }\n &__quantity {\n color: var(--sc-color-gray-500);\n font-weight: var(--sc-font-weight-bold);\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--sc-spacing-xx-small);\n }\n}\n","import { Component, Host, h, State, EventEmitter, Event } from '@stencil/core';\nimport { __ } from '@wordpress/i18n';\nimport { Checkout, LineItemData, Product } from 'src/types';\nimport { state as checkoutState } from '@store/checkout';\nimport { updateCheckout } from '@services/session';\nimport { currentFormState } from '@store/form/getters';\n\n/**\n * This component listens for stock requirements and displays a dialog to the user.\n */\n@Component({\n tag: 'sc-checkout-stock-alert',\n styleUrl: 'sc-checkout-stock-alert.scss',\n shadow: true,\n})\nexport class ScCheckoutStockAlert {\n /** Stock errors */\n @State() stockErrors: Array = [];\n\n /** Toggle line item event */\n @Event() scUpdateLineItem: EventEmitter;\n\n /** Is it busy */\n @State() busy: boolean;\n\n /** Update stock error. */\n @State() error: string;\n\n /** Get the out of stock line items. */\n getOutOfStockLineItems() {\n return (checkoutState.checkout?.line_items?.data || []).filter(lineItem => {\n const product = lineItem.price?.product as Product;\n // no stock handling.\n if (!product?.stock_enabled || product?.allow_out_of_stock_purchases) return;\n\n // check the variant stock.\n if (lineItem?.variant?.id) {\n return lineItem?.variant?.available_stock < lineItem.quantity;\n }\n\n return product?.available_stock < lineItem.quantity;\n });\n }\n\n /**\n * Update the checkout line items stock to the max available.\n */\n async onSubmit() {\n const lineItems = this.getOutOfStockLineItems().map(lineItem => {\n const product = lineItem.price?.product as Product;\n\n if (lineItem?.variant?.id) {\n return {\n ...lineItem,\n quantity: Math.max(lineItem?.variant?.available_stock || 0, 0),\n };\n }\n\n return {\n ...lineItem,\n quantity: Math.max(product?.available_stock || 0, 0),\n };\n });\n\n try {\n this.busy = true;\n checkoutState.checkout = (await updateCheckout({\n id: checkoutState.checkout.id,\n data: {\n line_items: (lineItems || [])\n .filter(lineItem => !!lineItem.quantity)\n .map(lineItem => {\n return {\n id: lineItem.id,\n price_id: lineItem.price?.id,\n quantity: lineItem.quantity,\n ...(lineItem?.variant?.id ? { variant: lineItem.variant.id } : {}),\n };\n }),\n },\n })) as Checkout;\n } catch (error) {\n const additionalErrors = (error?.additional_errors || []).map(error => error?.message).filter(n => n);\n this.error = `${error?.message || __('Something went wrong.', 'surecart')} ${additionalErrors?.length && ` ${additionalErrors.join('. ')}`}`;\n } finally {\n this.busy = false;\n }\n }\n\n render() {\n // stock errors.\n const stockErrors = (this.getOutOfStockLineItems() || []).map(lineItem => {\n const product = lineItem.price?.product as Product;\n const variantImage = typeof lineItem?.variant?.image !== 'string' ? lineItem?.variant?.image?.url : null;\n\n const available_stock = lineItem?.variant?.id ? lineItem?.variant?.available_stock : product?.available_stock;\n\n return {\n name: product?.name,\n image_url: variantImage || product?.image_url,\n quantity: lineItem.quantity,\n available_stock,\n };\n });\n\n // we have at least one quantity change.\n const hasOutOfStockItems = stockErrors?.some(item => item?.available_stock < 1);\n\n return (\n \n e.preventDefault()}\n >\n \n \n \n {hasOutOfStockItems ? __('Out of Stock', 'surecart') : __('Quantity Update', 'surecart')}\n \n\n \n {hasOutOfStockItems\n ? __('Some items are no longer available. Your cart will be updated.', 'surecart')\n : __('Available quantities for these items have changed. Your cart will be updated.', 'surecart')}\n \n\n \n \n {__('Description', 'surecart')}\n \n {__('Quantity', 'surecart')}\n \n\n {stockErrors.map((item, index) => {\n const isLastChild = index === stockErrors.length - 1;\n return (\n \n \n \n \n

{item.name}

\n
\n
\n \n \n {item?.quantity} {Math.max(item?.available_stock, 0)}\n \n \n
\n );\n })}\n
\n
\n
\n\n this.onSubmit()}>\n {__('Continue', 'surecart')}\n \n \n\n {this.busy && }\n \n
\n );\n }\n}\n","import { Component, Prop } from '@stencil/core';\nimport { __ } from '@wordpress/i18n';\nimport { FormState } from '../../../types';\n\n@Component({\n tag: 'sc-checkout-unsaved-changes-warning',\n shadow: true,\n})\nexport class ScCheckoutUnsavedChangesWarning {\n @Prop() state: FormState;\n\n /**\n * Add event listener for beforeunload.\n */\n componentDidLoad() {\n window.addEventListener('beforeunload', e => this.warnIfUnsavedChanges(e), { capture: true });\n }\n\n /**\n * Warn if status is updaing, finalizing, paying or confirming.\n */\n warnIfUnsavedChanges(e) {\n if (['updating', 'finalizing', 'confirming'].includes(this.state)) {\n console.log({ e });\n e.preventDefault();\n e.returnValue = __('Your payment is processing. Exiting this page could cause an error in your order. Please do not navigate away from this page.', 'surecart');\n return e.returnValue;\n }\n }\n}\n","import { Component, Element, h, Prop, State, Watch } from '@stencil/core';\nimport { __ } from '@wordpress/i18n';\nimport { state as checkoutState, onChange as onCheckoutChange } from '@store/checkout';\nimport { TaxProtocol } from '../../../types';\n\n@Component({\n tag: 'sc-form-components-validator',\n shadow: true,\n})\nexport class ScFormComponentsValidator {\n @Element() el: HTMLScFormComponentsValidatorElement;\n\n private removeCheckoutListener: () => void;\n\n /** Disable validation? */\n @Prop() disabled: boolean;\n\n /** The tax protocol */\n @Prop() taxProtocol: TaxProtocol;\n\n /** Is there an address field? */\n @State() hasAddress: boolean;\n\n /** Is there a tax id field? */\n @State() hasTaxIDField: boolean;\n\n /** Is there a bumps field? */\n @State() hasBumpsField: boolean;\n\n /** Is there a tax line? */\n @State() hasTaxLine: boolean;\n\n /** Is there a bump line? */\n @State() hasBumpLine: boolean;\n\n /** Is there shipping choices */\n @State() hasShippingChoices: boolean;\n /** Is there a shipping amount */\n @State() hasShippingAmount: boolean;\n\n handleOrderChange() {\n // bail if we don't have address invalid error or disabled.\n if (this.disabled) return;\n\n // make sure to add the address field if it's not there.\n if (checkoutState.checkout?.tax_status === 'address_invalid' || checkoutState.checkout?.shipping_enabled || checkoutState.checkout?.shipping_address_required) {\n this.addAddressField();\n }\n\n // add order bumps.\n if (checkoutState.checkout?.recommended_bumps?.data?.length) {\n this.addBumps();\n }\n if (!!checkoutState.checkout?.tax_amount) {\n this.addTaxLine();\n }\n\n // add shipping choices.\n if (checkoutState.checkout?.shipping_enabled && checkoutState.checkout?.selected_shipping_choice_required) {\n this.addShippingChoices();\n }\n\n if (!!checkoutState.checkout?.shipping_amount) {\n this.addShippingAmount();\n }\n }\n\n @Watch('hasAddress')\n handleHasAddressChange() {\n if (!this.hasAddress) return;\n this.handleShippingAddressRequired();\n }\n\n componentWillLoad() {\n this.hasAddress = !!this.el.querySelector('sc-order-shipping-address');\n this.hasTaxIDField = !!this.el.querySelector('sc-order-tax-id-input');\n this.hasBumpsField = !!this.el.querySelector('sc-order-bumps');\n this.hasTaxLine = !!this.el.querySelector('sc-line-item-tax');\n this.hasShippingChoices = !!this.el.querySelector('sc-shipping-choices');\n this.hasShippingAmount = !!this.el.querySelector('sc-line-item-shipping');\n\n // automatically add address field if tax is enabled.\n if (this.taxProtocol?.tax_enabled) {\n this.addAddressField();\n\n // if eu vat is required, add the tax id field.\n if (this.taxProtocol?.eu_vat_required) {\n this.addTaxIDField();\n }\n }\n\n this.removeCheckoutListener = onCheckoutChange('checkout', () => this.handleOrderChange());\n }\n\n disconnectedCallback() {\n this.removeCheckoutListener();\n }\n\n handleShippingAddressRequired() {\n if (!checkoutState.checkout?.shipping_address_required) return;\n\n // get the address\n const address = this.el.querySelector('sc-order-shipping-address');\n if (!address) return;\n\n // require the address.\n address.required = true;\n\n // if we have a customer name field, require that.\n const customerName = this.el.querySelector('sc-customer-name');\n if (!!customerName) {\n customerName.required = true;\n return;\n }\n\n // require the name and show the name input.\n address.requireName = true;\n address.showName = true;\n }\n\n addAddressField() {\n if (this.hasAddress) {\n return;\n }\n\n const payment = this.el.querySelector('sc-payment');\n const address = document.createElement('sc-order-shipping-address');\n address.label = __('Address', 'surecart');\n payment.parentNode.insertBefore(address, payment);\n this.hasAddress = true;\n }\n\n addTaxIDField() {\n if (this.hasTaxIDField) return;\n const payment = this.el.querySelector('sc-payment');\n const taxInput = document.createElement('sc-order-tax-id-input');\n payment.parentNode.insertBefore(taxInput, payment);\n this.hasTaxIDField = true;\n }\n\n addBumps() {\n if (this.hasBumpsField) return;\n const payment = this.el.querySelector('sc-payment');\n const bumps = document.createElement('sc-order-bumps');\n payment.parentNode.insertBefore(bumps, payment.nextSibling);\n this.hasBumpsField = true;\n }\n\n addTaxLine() {\n if (this.hasTaxLine) return;\n const total = this.el.querySelector('sc-line-item-total[total=total]');\n const tax = document.createElement('sc-line-item-tax');\n if (total?.previousElementSibling?.tagName === 'SC-DIVIDER') {\n total.parentNode.insertBefore(tax, total.previousElementSibling);\n } else {\n total.parentNode.insertBefore(tax, total);\n }\n this.hasTaxLine = true;\n }\n\n addShippingChoices() {\n if (this.hasShippingChoices) return;\n\n const payment = this.el.querySelector('sc-payment');\n const shippingChoices = document.createElement('sc-shipping-choices');\n payment.parentNode.insertBefore(shippingChoices, payment);\n this.hasShippingChoices = true;\n }\n\n addShippingAmount() {\n if (this.hasShippingAmount) return;\n\n let insertBeforeElement: Element = this.el.querySelector('sc-line-item-tax');\n const total = this.el.querySelector('sc-line-item-total[total=total]');\n\n if (!insertBeforeElement) {\n insertBeforeElement = total?.previousElementSibling?.tagName === 'SC-DIVIDER' ? total.previousElementSibling : total;\n }\n\n const shippingAmount = document.createElement('sc-line-item-shipping');\n insertBeforeElement.parentNode.insertBefore(shippingAmount, insertBeforeElement);\n this.hasShippingAmount = true;\n }\n\n render() {\n return ;\n }\n}\n","/**\n * External dependencies.\n */\nimport { Component, h, Element } from '@stencil/core';\nimport { __ } from '@wordpress/i18n';\n\n/**\n * This component checks to make sure there is an error component\n * and adds one if it's missing.\n */\n@Component({\n tag: 'sc-form-error-provider',\n shadow: true,\n})\nexport class ScFormErrorProvider {\n /** The element. */\n @Element() el: HTMLScFormErrorProviderElement;\n\n componentWillLoad() {\n this.maybeAddErrorsComponent();\n }\n\n maybeAddErrorsComponent() {\n if (!!this.el.querySelector('sc-checkout-form-errors')) return;\n const errorsComponent = document.createElement('sc-checkout-form-errors');\n this.el.querySelector('sc-form')?.prepend?.(errorsComponent);\n }\n\n render() {\n return ;\n }\n}\n","import { Component, h, State, Event, EventEmitter, Listen, Watch } from '@stencil/core';\nimport { checkoutMachine } from './checkout-machine';\nimport { interpret } from '@xstate/fsm';\nimport { __ } from '@wordpress/i18n';\nimport { FormState, FormStateSetter } from '../../../types';\nimport { updateFormState } from '@store/form/mutations';\n\n/**\n * This component listens for a confirmed event and redirects to the success url.\n */\n@Component({\n tag: 'sc-form-state-provider',\n shadow: true,\n})\nexport class ScFormStateProvider {\n /** Holds our state machine service */\n private _stateService = interpret(checkoutMachine);\n\n /** Loading states for different parts of the form. */\n @State() checkoutState = checkoutMachine.initialState;\n\n /** Set the state. */\n @Event() scSetCheckoutFormState: EventEmitter;\n\n /** Set the state. */\n setState(name) {\n const { send } = this._stateService;\n updateFormState(name);\n return send(name);\n }\n\n /** Watch for checkout state changes and emit to listeners. */\n @Watch('checkoutState')\n handleCheckoutStateChange(state) {\n this.scSetCheckoutFormState.emit(state.value);\n }\n\n /** Init the state service. */\n componentWillLoad() {\n // Start state machine.\n this._stateService.subscribe(state => (this.checkoutState = state));\n this._stateService.start();\n }\n\n /** Remove state machine on disconnect. */\n disconnectedCallback() {\n this._stateService.stop();\n }\n\n /** Allow children to set the form state. */\n @Listen('scSetState')\n handleSetStateEvent(e) {\n this.setState(e.detail as FormStateSetter);\n }\n\n /** Update the state when the order is paid. */\n @Listen('scPaid')\n async handlePaid() {\n this.setState('PAID');\n }\n\n render() {\n // handle expired.\n if (this.checkoutState.value === 'expired') {\n return (\n \n
{__('Please refresh the page.', 'surecart')}
\n
\n );\n }\n\n return ;\n }\n}\n",":host {\n display: block;\n}\n","import { Component, Prop, h, Watch, State, Host, Listen, Event, EventEmitter } from '@stencil/core';\nimport { __ } from '@wordpress/i18n';\nimport apiFetch from '../../../functions/fetch';\nimport { Checkout } from '../../../types';\n\n@Component({\n tag: 'sc-login-provider',\n styleUrl: 'sc-login-provider.css',\n shadow: true,\n})\nexport class ScLoginProvider {\n private loginForm: HTMLScFormElement;\n\n /** Is the user logged in. */\n @Prop() loggedIn: boolean;\n @Prop() order: Checkout;\n\n @Event() scSetLoggedIn: EventEmitter;\n @Event() scSetCustomer: EventEmitter<{ email: string; name?: string }>;\n\n @State() notice: boolean;\n @State() open: boolean;\n @State() loading: boolean;\n @State() error: string;\n\n /** Listen for open event. */\n @Listen('scLoginPrompt')\n handleLoginPrompt() {\n this.open = true;\n }\n\n /** Focus on first input. */\n @Watch('open')\n handleLoginDialogChange(val) {\n if (val) {\n setTimeout(() => {\n this.loginForm.querySelector('sc-input').triggerFocus();\n }, 100);\n }\n }\n\n @Watch('loggedIn')\n handleLoggedInChange(val, prev) {\n if (prev === false && val) {\n this.notice = true;\n }\n }\n\n @Watch('order')\n handleOrderChange(val, prev) {\n if (val?.updated_at !== prev?.updated_at) {\n this.notice = false;\n }\n }\n\n /** Handle form submit. */\n async handleFormSubmit(e) {\n e.preventDefault();\n e.stopImmediatePropagation();\n this.error = null;\n\n const { login, password } = await e.target.getFormJson();\n\n try {\n this.loading = true;\n const { name, email } = (await apiFetch({\n method: 'POST',\n path: 'surecart/v1/login',\n data: {\n login,\n password,\n },\n })) as { name: string; email: string };\n this.scSetLoggedIn.emit(true);\n this.scSetCustomer.emit({ name, email });\n this.open = false;\n } catch (e) {\n console.error(e);\n this.error = e?.message || __('Something went wrong', 'surecart');\n } finally {\n this.loading = false;\n }\n }\n\n render() {\n return (\n \n {!!this.notice && (\n \n {__('Welcome back!', 'surecart')}\n {__('You have logged in successfully.', 'surecart')}\n \n )}\n\n \n\n {!this.loggedIn && (\n (this.open = false)}>\n (this.loginForm = el as HTMLScFormElement)}\n onScFormSubmit={e => {\n e.preventDefault();\n e.stopImmediatePropagation();\n }}\n onScSubmit={e => this.handleFormSubmit(e)}\n >\n {!!this.error && (\n \n {this.error}\n \n )}\n \n \n \n {__('Login', 'surecart')}\n \n \n \n )}\n \n );\n }\n}\n",".confirm {\n &__icon {\n margin-bottom: var(--sc-spacing-medium);\n display: flex;\n justify-content: center;\n }\n\n &__icon-container {\n background: var(--sc-color-primary-500);\n width: 55px;\n height: 55px;\n border-radius: 999999px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 26px;\n line-height: 1;\n color: white;\n }\n}\n\nsc-dialog::part(overlay) {\n backdrop-filter: blur(4px);\n}\n","import { Component, Element, Event, EventEmitter, h, Host, Watch, Prop, State } from '@stencil/core';\nimport { __ } from '@wordpress/i18n';\nimport { addQueryArgs } from '@wordpress/url';\nimport { speak } from '@wordpress/a11y';\n\nimport apiFetch from '../../../functions/fetch';\nimport { expand } from '../../../services/session';\nimport { state as checkoutState } from '@store/checkout';\nimport { state as formState } from '@store/form';\nimport { Checkout, ManualPaymentMethod } from '../../../types';\nimport { clearCheckout } from '@store/checkout/mutations';\nimport { createErrorNotice } from '@store/notices/mutations';\n/**\n * This component listens to the order status\n * and confirms the order when payment is successful.\n */\n@Component({\n tag: 'sc-order-confirm-provider',\n styleUrl: 'sc-order-confirm-provider.scss',\n shadow: true,\n})\nexport class ScOrderConfirmProvider {\n private continueButton: HTMLScButtonElement;\n /** The order confirm provider element */\n @Element() el: HTMLScOrderConfirmProviderElement;\n\n /** Whether to show success modal */\n @State() showSuccessModal: boolean = false;\n\n /** Checkout status to listen and do payment related stuff. */\n @Prop() checkoutStatus: string;\n\n /** Success url. */\n @Prop() successUrl: string;\n\n /** The order is paid event. */\n @Event() scOrderPaid: EventEmitter;\n\n @Event() scSetState: EventEmitter;\n\n /**\n * Watch for paid checkout machine state.\n * This is triggered by Stripe, Paypal or Paystack when payment succeeds.\n */\n @Watch('checkoutStatus')\n handleConfirmOrderEvent() {\n if (this.checkoutStatus === 'confirming') {\n this.confirmOrder();\n } else if (this.checkoutStatus === 'confirmed') {\n speak(__('Order has been confirmed. Please select continue to go to the next step.', 'surecart'));\n }\n }\n\n /** Confirm the order. */\n async confirmOrder() {\n try {\n checkoutState.checkout = (await apiFetch({\n method: 'PATCH',\n path: addQueryArgs(`surecart/v1/checkouts/${checkoutState?.checkout?.id}/confirm`, { expand }),\n })) as Checkout;\n this.scSetState.emit('CONFIRMED');\n } catch (e) {\n console.error(e);\n createErrorNotice(e);\n } finally {\n // always clear the checkout.\n clearCheckout();\n // get success url.\n const successUrl = checkoutState.checkout?.metadata?.success_url || this.successUrl;\n if (successUrl) {\n // set state to redirecting.\n this.scSetState.emit('REDIRECT');\n setTimeout(() => window.location.assign(addQueryArgs(successUrl, { sc_order: checkoutState.checkout?.id })), 50);\n } else {\n this.showSuccessModal = true;\n }\n }\n }\n\n getSuccessUrl() {\n const url = checkoutState.checkout?.metadata?.success_url || this.successUrl;\n return url ? addQueryArgs(url, { sc_order: checkoutState.checkout?.id }) : window?.scData?.pages?.dashboard;\n }\n\n @Watch('showSuccessModal')\n handleSuccessModal() {\n if (this.showSuccessModal) {\n setTimeout(() => {\n this.continueButton?.focus();\n }, 50);\n }\n }\n\n render() {\n const manualPaymentMethod = checkoutState.checkout?.manual_payment_method as ManualPaymentMethod;\n\n return (\n \n \n e.preventDefault()}>\n
\n
\n \n
\n
\n \n {formState?.text?.success?.description || __('Your payment was successful. A receipt is on its way to your inbox.', 'surecart')}\n {!!manualPaymentMethod?.name && !!manualPaymentMethod?.instructions && (\n \n {manualPaymentMethod?.name}\n {manualPaymentMethod?.instructions.split('\\n').map(i => {\n return

{i}

;\n })}\n
\n )}\n (this.continueButton = el as HTMLScButtonElement)}>\n {formState?.text?.success?.button || __('Continue', 'surecart')}\n \n \n \n
\n
\n );\n }\n}\n","import { Component, Element, Event, EventEmitter, h, Listen, Method, Prop, Watch } from '@stencil/core';\nimport { state as checkoutState } from '@store/checkout';\nimport { clearCheckout } from '@store/checkout/mutations';\nimport { state as selectedProcessor } from '@store/selected-processor';\nimport { __ } from '@wordpress/i18n';\nimport { addQueryArgs, getQueryArg, getQueryArgs, removeQueryArgs } from '@wordpress/url';\nimport { updateFormState } from '@store/form/mutations';\n\nimport { parseFormData } from '../../../functions/form-data';\nimport { createOrUpdateCheckout, fetchCheckout, finalizeCheckout } from '../../../services/session';\nimport { Checkout, FormStateSetter, LineItemData, PriceChoice } from '../../../types';\nimport { createErrorNotice, createInfoNotice, removeNotice } from '@store/notices/mutations';\n\n@Component({\n tag: 'sc-session-provider',\n shadow: true,\n})\nexport class ScSessionProvider {\n /** Element */\n @Element() el: HTMLElement;\n\n /** An array of prices to pre-fill in the form. */\n @Prop() prices: Array = [];\n\n /** Should we persist the session. */\n @Prop() persist: boolean = true;\n\n /** Update line items event */\n @Event() scUpdateOrderState: EventEmitter;\n\n /** Update line items event */\n @Event() scUpdateDraftState: EventEmitter;\n\n @Event() scPaid: EventEmitter;\n\n /** Set the state */\n @Event() scSetState: EventEmitter;\n\n @Watch('prices')\n handlePricesChange() {\n let line_items = this.addInitialPrices() || [];\n // line_items = this.addPriceChoices(line_items);\n if (!line_items?.length) {\n return;\n }\n return this.loadUpdate({ line_items });\n }\n\n /**\n * Finalize the order.\n *\n * @returns {Promise}\n */\n @Method()\n async finalize() {\n return await this.handleFormSubmit();\n }\n\n async getFormData() {\n let data = {};\n const form = this.el.querySelector('sc-form');\n if (form) {\n const json = await form.getFormJson();\n data = parseFormData(json);\n }\n return data;\n }\n\n /**\n * Handles the form submission.\n * @param e\n */\n @Listen('scFormSubmit')\n async handleFormSubmit() {\n removeNotice();\n\n updateFormState('FINALIZE');\n\n // Get current form state.\n let data = await this.getFormData();\n\n if (window?.scData?.recaptcha_site_key && window?.grecaptcha) {\n try {\n data['grecaptcha'] = await window.grecaptcha.execute(window.scData.recaptcha_site_key, { action: 'surecart_checkout_submit' });\n } catch (e) {\n console.error(e);\n updateFormState('REJECT');\n this.handleErrorResponse(e);\n return new Error(e?.message);\n }\n }\n\n // first lets make sure the session is updated before we process it.\n try {\n await this.update(data);\n } catch (e) {\n console.error(e);\n updateFormState('REJECT');\n this.handleErrorResponse(e);\n }\n\n // first validate server-side and get key\n try {\n checkoutState.checkout = await finalizeCheckout({\n id: checkoutState?.checkout?.id,\n query: {\n ...(selectedProcessor?.method ? { payment_method_type: selectedProcessor?.method } : {}),\n return_url: addQueryArgs(window.location.href, {\n ...(checkoutState?.checkout?.id ? { checkout_id: checkoutState?.checkout?.id } : {}),\n is_surecart_payment_redirect: true,\n }),\n },\n data,\n processor: {\n id: selectedProcessor.id,\n manual: selectedProcessor.manual,\n },\n });\n\n // the checkout is paid.\n if (['paid', 'processing'].includes(checkoutState.checkout?.status)) {\n this.scPaid.emit();\n }\n\n if (checkoutState.checkout?.payment_intent?.processor_data?.mollie?.checkout_url) {\n updateFormState('PAYING');\n return setTimeout(() => window.location.assign(checkoutState.checkout?.payment_intent?.processor_data?.mollie?.checkout_url), 50);\n }\n\n setTimeout(() => {\n updateFormState('PAYING');\n }, 50);\n\n return checkoutState.checkout;\n } catch (e) {\n console.error(e);\n this.handleErrorResponse(e);\n return new Error(e?.message);\n }\n }\n\n /**\n * Handle paid event and update the\n */\n @Listen('scPaid')\n async handlePaid() {\n updateFormState('PAID');\n }\n\n @Listen('scUpdateAbandonedCart')\n async handleAbandonedCartUpdate(e) {\n const abandoned_checkout_enabled = e.detail;\n this.loadUpdate({\n abandoned_checkout_enabled,\n });\n }\n\n /** Handles coupon updates. */\n @Listen('scApplyCoupon')\n async handleCouponApply(e) {\n const promotion_code = e.detail;\n removeNotice();\n this.loadUpdate({\n discount: {\n ...(promotion_code ? { promotion_code } : {}),\n },\n });\n }\n\n /** Find or create session on load. */\n componentDidLoad() {\n this.findOrCreateOrder();\n }\n\n /** Find or create an order */\n async findOrCreateOrder() {\n // get URL params.\n const { redirect_status, checkout_id, line_items, coupon, is_surecart_payment_redirect } = getQueryArgs(window.location.href);\n // remove params we don't want.\n window.history.replaceState(\n {},\n document.title,\n removeQueryArgs(window.location.href, 'redirect_status', 'coupon', 'line_items', 'confirm_checkout_id', 'checkout_id', 'no_cart'),\n );\n\n // handle abandoned checkout.\n if (!!is_surecart_payment_redirect && !!checkout_id) {\n updateFormState('FINALIZE');\n updateFormState('PAYING');\n return this.handleCheckoutIdFromUrl(checkout_id, coupon as string);\n }\n\n // handle redirect status.\n if (!!redirect_status) {\n return this.handleRedirectStatus(redirect_status, checkout_id);\n }\n\n // handle abandoned checkout.\n if (!!checkout_id) {\n return this.handleCheckoutIdFromUrl(checkout_id, coupon as string);\n }\n\n // handle initial line items.\n if (!!line_items) {\n return this.handleInitialLineItems(line_items, coupon as string);\n }\n\n // we have an existing saved checkout id in the session, and we are persisting.\n const id = checkoutState?.checkout?.id;\n if (id && this.persist) {\n return this.handleExistingCheckout(id, coupon as string);\n }\n\n return this.handleNewCheckout(coupon as string);\n }\n\n /** Handle payment instrument redirect status */\n async handleRedirectStatus(status, id) {\n console.info('Handling payment redirect.');\n // status failed.\n if (status === 'failed') {\n createErrorNotice(__('Payment unsuccessful. Please try again.', 'surecart'));\n return;\n }\n\n // get the\n if (!id) {\n createErrorNotice(__('Could not find checkout. Please contact us before attempting to purchase again.', 'surecart'));\n return;\n }\n\n // success, refetch the checkout\n try {\n updateFormState('FINALIZE');\n updateFormState('PAID');\n checkoutState.checkout = (await fetchCheckout({\n id,\n query: {\n refresh_status: true,\n },\n })) as Checkout;\n\n // TODO: should we even check this?\n if (checkoutState.checkout?.status && ['paid', 'processing'].includes(checkoutState.checkout?.status)) {\n setTimeout(() => {\n this.scPaid.emit();\n }, 100);\n }\n } catch (e) {\n this.handleErrorResponse(e);\n }\n }\n\n /** Handle abandoned checkout from URL */\n async handleCheckoutIdFromUrl(id, promotion_code = '') {\n console.info('Handling existing checkout from url.', promotion_code, id);\n\n // if coupon code, load the checkout with the code.\n if (promotion_code) {\n return this.loadUpdate({\n id,\n discount: { promotion_code },\n refresh_price_versions: true,\n });\n }\n\n try {\n updateFormState('FETCH');\n checkoutState.checkout = (await fetchCheckout({\n id,\n query: {\n refresh_status: true,\n },\n })) as Checkout;\n\n const isModeMismatch = checkoutState.mode !== (checkoutState.checkout?.live_mode ? 'live' : 'test');\n\n if (isModeMismatch) {\n console.info('Mode mismatch, creating new checkout.');\n clearCheckout();\n checkoutState.checkout = null;\n await this.handleNewCheckout(promotion_code);\n return;\n }\n\n updateFormState('RESOLVE');\n } catch (e) {\n this.handleErrorResponse(e);\n }\n\n // handle status.\n switch (checkoutState.checkout?.status) {\n case 'paid':\n case 'processing':\n return setTimeout(() => {\n updateFormState('FINALIZE');\n updateFormState('PAID');\n this.scPaid.emit();\n }, 100);\n\n case 'payment_failed':\n clearCheckout();\n createErrorNotice({\n message: __('Payment unsuccessful. Please try again.', 'surecart'),\n });\n return;\n\n case 'payment_intent_canceled':\n case 'canceled':\n clearCheckout();\n createErrorNotice({\n message: __('Payment canceled. Please try again.', 'surecart'),\n });\n return;\n\n case 'finalized':\n createErrorNotice({\n message: __('Payment unsuccessful. Please try again.', 'surecart'),\n });\n updateFormState('REJECT');\n return;\n }\n }\n\n /** Handle line items (and maybe ) */\n async handleInitialLineItems(line_items, promotion_code) {\n console.info('Handling initial line items.');\n // TODO: move this to central store.\n const address = this.el.querySelector('sc-order-shipping-address');\n clearCheckout();\n return this.loadUpdate({\n line_items,\n refresh_price_versions: true,\n ...(promotion_code ? { discount: { promotion_code } } : {}),\n ...(address?.defaultCountry\n ? {\n shipping_address: {\n country: address?.defaultCountry,\n },\n }\n : {}),\n });\n }\n\n /** Handle a brand new checkout. */\n async handleNewCheckout(promotion_code) {\n // get existing form data from defaults (default country selection, etc).\n const data = this.getFormData();\n let line_items = checkoutState.initialLineItems || [];\n const address = this.el.querySelector('sc-order-shipping-address');\n\n try {\n updateFormState('FETCH');\n checkoutState.checkout = (await createOrUpdateCheckout({\n data: {\n ...data,\n ...(promotion_code ? { discount: { promotion_code } } : {}),\n ...(address?.defaultCountry\n ? {\n shipping_address: {\n country: address?.defaultCountry,\n },\n }\n : {}),\n line_items,\n ...(checkoutState.taxProtocol?.eu_vat_required ? { tax_identifier: { number_type: 'eu_vat' } } : {}),\n },\n })) as Checkout;\n updateFormState('RESOLVE');\n } catch (e) {\n console.error(e);\n this.handleErrorResponse(e);\n }\n }\n\n /** Handle existing checkout */\n async handleExistingCheckout(id, promotion_code) {\n if (!id) return this.handleNewCheckout(promotion_code);\n console.info('Handling existing checkout.');\n try {\n updateFormState('FETCH');\n checkoutState.checkout = (await createOrUpdateCheckout({\n id,\n data: {\n ...(promotion_code ? { discount: { promotion_code } } : {}),\n refresh_price_versions: true,\n ...(checkoutState.taxProtocol?.eu_vat_required ? { tax_identifier: { number_type: 'eu_vat' } } : {}),\n },\n })) as Checkout;\n updateFormState('RESOLVE');\n } catch (e) {\n console.error(e);\n this.handleErrorResponse(e);\n }\n }\n\n /** Handle the error response. */\n async handleErrorResponse(e) {\n // reinitalize if order not found.\n if (['checkout.not_found'].includes(e?.code)) {\n window.history.replaceState({}, document.title, removeQueryArgs(window.location.href, 'checkout_id'));\n clearCheckout();\n return this.handleNewCheckout(false);\n }\n\n // one of these is an old price version error.\n if ((e?.additional_errors || []).some(error => error?.code == 'checkout.price.old_version')) {\n await this.loadUpdate({\n id: checkoutState?.checkout?.id,\n data: {\n status: 'draft',\n refresh_price_versions: true,\n },\n });\n createInfoNotice(__('The price a product in your order has changed. We have adjusted your order to the new price.', 'surecart'));\n return;\n }\n\n // If got Product out of stock error, then fetch the checkout again.\n if (e?.additional_errors?.[0]?.code === 'checkout.product.out_of_stock') {\n this.fetch();\n updateFormState('REJECT');\n return;\n }\n\n if (['order.invalid_status_transition'].includes(e?.code)) {\n await this.loadUpdate({\n id: checkoutState?.checkout?.id,\n data: {\n status: 'draft',\n },\n });\n this.handleFormSubmit();\n return;\n }\n\n // expired\n if (e?.code === 'rest_cookie_invalid_nonce') {\n updateFormState('EXPIRE');\n return;\n }\n\n // paid\n if (e?.code === 'readonly') {\n clearCheckout();\n window.location.assign(removeQueryArgs(window.location.href, 'order'));\n return;\n }\n\n createErrorNotice(e);\n updateFormState('REJECT');\n }\n\n /** Looks through children and finds items needed for initial session. */\n async initialize(args = {}) {\n let line_items = checkoutState.initialLineItems || [];\n return this.loadUpdate({ ...(line_items?.length ? { line_items } : {}), ...args });\n }\n\n /** Add prices that are passed into the component. */\n addInitialPrices() {\n if (!this?.prices?.length) return [];\n\n // check for id\n if (this.prices.some(p => !p?.id)) {\n return;\n }\n\n // add prices that are passed into this component.\n return this.prices.map(price => {\n return {\n price_id: price.id,\n quantity: price.quantity,\n variant: price.variant,\n };\n });\n }\n\n // /** Add default prices that may be selected in form. */\n // addPriceChoices(line_items = []) {\n // // const elements = this.el.querySelectorAll('[price-id]') as any;\n // // elements.forEach(el => {\n // // // handle price choices.\n // // if (el.checked) {\n // // line_items.push({\n // // quantity: el.quantity || 1,\n // // price_id: el.priceId,\n // // ...(el.defaultAmount ? { ad_hoc_amount: el.defaultAmount } : {}),\n // // });\n // // }\n // // // handle donation default amount.\n // // if (el.defaultAmount) {\n // // line_items.push({\n // // quantity: el.quantity || 1,\n // // price_id: el.priceId,\n // // ad_hoc_amount: el.defaultAmount,\n // // });\n // // }\n // // });\n // // return line_items;\n // }\n\n getSessionId() {\n // check url first.\n const checkoutId = getQueryArg(window.location.href, 'checkout_id');\n if (!!checkoutId) {\n return checkoutId;\n }\n\n // check existing order.\n if (checkoutState?.checkout?.id) {\n return checkoutState?.checkout?.id;\n }\n\n // we don't have and order id.\n return null;\n }\n\n async fetchCheckout(id, { query = {}, data = {} } = {}) {\n try {\n updateFormState('FETCH');\n const checkout = (await createOrUpdateCheckout({\n id,\n query,\n data,\n })) as Checkout;\n updateFormState('RESOLVE');\n return checkout;\n } catch (e) {\n this.handleErrorResponse(e);\n }\n }\n\n /** Fetch a session. */\n async fetch(query = {}) {\n try {\n updateFormState('FETCH');\n checkoutState.checkout = (await fetchCheckout({\n id: this.getSessionId(),\n query,\n })) as Checkout;\n updateFormState('RESOLVE');\n } catch (e) {\n this.handleErrorResponse(e);\n }\n }\n\n /** Update a session */\n async update(data: any = {}, query = {}) {\n try {\n checkoutState.checkout = (await createOrUpdateCheckout({\n id: data?.id ? data.id : this.getSessionId(),\n data,\n query,\n })) as Checkout;\n } catch (e) {\n // reinitalize if order not found.\n if (['checkout.not_found'].includes(e?.code)) {\n clearCheckout();\n return this.initialize();\n }\n console.error(e);\n throw e;\n }\n }\n\n /** Updates a session with loading status changes. */\n async loadUpdate(data = {}) {\n try {\n updateFormState('FETCH');\n await this.update(data);\n updateFormState('RESOLVE');\n } catch (e) {\n this.handleErrorResponse(e);\n }\n }\n\n render() {\n return (\n this.loadUpdate({ line_items: e.detail as Array })}>\n \n \n );\n }\n}\n"],"mappings":"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"}