/* eslint-disable @typescript-eslint/no-explicit-any */ import _get from 'lodash/get' import _identity from 'lodash/identity' import _map from 'lodash/map' import { useEffect, useMemo, useState } from 'react' import { getAddons, getCart, getCheckoutPageConfigs, postOnCheckout } from '../../api' import { ICheckoutPageConfigs } from '../../types' import { createCheckoutDataBodyWithDefaultHolder, isBrowser } from '../../utils' import { addonsWithGroupsAdapter, cartAdapter } from './adapters' import { generateSelectOptions, getAddonSelectOptions, getSortedAddons, getTicketRelatedAddons, } from './utils' interface ObjectLiteral { [key: string]: any; } export interface IUseAddonsOptions { enableBillingInfoAutoCreate?: boolean; addOnDataWithCustomFields?: any; onGetAddonsPageInfoSuccess?: (res: any) => void; onGetAddonsPageInfoError?: (error: any) => void; onPostCheckoutSuccess?: (res: any) => void; onPostCheckoutError?: (error: any) => void; onConfirmSelectionSuccess?: (res: any) => void; onConfirmSelectionError?: (error: any) => void; } export const useAddons = (eventId: string | null, options: IUseAddonsOptions = {}) => { const { enableBillingInfoAutoCreate = true, addOnDataWithCustomFields, onGetAddonsPageInfoSuccess = _identity, onGetAddonsPageInfoError = _identity, onPostCheckoutSuccess = _identity, onPostCheckoutError = _identity, onConfirmSelectionSuccess = _identity, onConfirmSelectionError = _identity, } = options const [addons, setAddons] = useState([]) const [addonsOptions, setAddonsOptions] = useState({}) const [groupsWithSelectedVariants, setGroupsWithSelectedVariants] = useState({}) const [groupsWithInitialVariantsValues, setGroupsWithInitialVariantsValues] = useState({}) const [loading, setLoading] = useState(true) const [cartExpirationTime, setCartExpirationTime] = useState(0) const [pendingVerificationMessage, setPendingVerificationMessage] = useState() useEffect(() => { const getAddonsPageInfo = async () => { try { if (eventId) { setLoading(true) const cart = await getCart() const { id: choosedTicketID, quantity, expiresAt } = cartAdapter(cart) const choosedTicketCount = Number(quantity) setCartExpirationTime(expiresAt) const addonsData = await getAddons(eventId) const adaptedAddons = addonsWithGroupsAdapter(addonsData) const ticketRelatedAddons = getTicketRelatedAddons(adaptedAddons, choosedTicketID) const sortedTicketAddons = getSortedAddons(ticketRelatedAddons) setAddons(sortedTicketAddons) const { addonsWithOptions, groupsWithSelectedVariantsInfo, groupsWithVariants, } = getAddonSelectOptions(adaptedAddons, choosedTicketCount) setAddonsOptions(addonsWithOptions) setGroupsWithSelectedVariants(groupsWithSelectedVariantsInfo) setGroupsWithInitialVariantsValues(groupsWithVariants) onGetAddonsPageInfoSuccess(addonsData) } } catch (e) { onGetAddonsPageInfoError(e) } finally { setLoading(false) } } getAddonsPageInfo() }, [eventId]) const recreateGroupVariantsSelectOptions = (groupId: any, changedGroup: any) => { const { choosedVariants, limit, selectedCount } = changedGroup const remainingGroupStock = limit - selectedCount const recreatedVariantsOptions: ObjectLiteral = {} for (const variant in choosedVariants) { const variantId = variant const variantCurrSelectedValue = choosedVariants[variant] let allowedOptionCount if ( remainingGroupStock >= groupsWithInitialVariantsValues[groupId][variantId] - variantCurrSelectedValue ) { allowedOptionCount = groupsWithInitialVariantsValues[groupId][variantId] } else { allowedOptionCount = remainingGroupStock + variantCurrSelectedValue } recreatedVariantsOptions[variantId] = generateSelectOptions(0, allowedOptionCount) } setAddonsOptions((prevState: any) => Object.assign({}, prevState, recreatedVariantsOptions)) } const onFieldChange = (id: any, value: any, addon: any) => { const changeableGroup = groupsWithSelectedVariants[addon.id] if (changeableGroup) { const currGroupId = addon.id const currSelectedVariantId = id const currSelectedVariantCount = Number(value) const currSelectedVariantPrevCount = groupsWithSelectedVariants[currGroupId].choosedVariants[currSelectedVariantId] const currSelectedGroupCount = changeableGroup.selectedCount + (currSelectedVariantCount - currSelectedVariantPrevCount) const updatedGroupsWithSelectedVariants = { ...groupsWithSelectedVariants, [currGroupId]: { ...groupsWithSelectedVariants[currGroupId], selectedCount: currSelectedGroupCount, choosedVariants: { ...groupsWithSelectedVariants[currGroupId].choosedVariants, [currSelectedVariantId]: currSelectedVariantCount, }, }, } setGroupsWithSelectedVariants(updatedGroupsWithSelectedVariants) recreateGroupVariantsSelectOptions( currGroupId, updatedGroupsWithSelectedVariants[currGroupId] ) } } const handleConfirm = async (values: any, skipAddonPage?: boolean) => { try { const pageConfigsDataResponse = await getCheckoutPageConfigs() const pageConfigsData: ICheckoutPageConfigs = _get(pageConfigsDataResponse, 'data.attributes') || {} const skipBillingPage = pageConfigsData.skip_billing_page ?? false if (skipBillingPage && enableBillingInfoAutoCreate) { const ticketsQuantity = window.localStorage.getItem('quantity') const userData = JSON.parse(window.localStorage.getItem('user_data') || '{}') const checkoutBody = createCheckoutDataBodyWithDefaultHolder( Number(ticketsQuantity) || 0, userData ) try { const checkoutResponse = await postOnCheckout({ ...checkoutBody, attributes: { ...checkoutBody.attributes, ...(!skipAddonPage && { add_ons: values }), }, }) const hash = checkoutResponse?.data?.attributes?.hash || '' const total = checkoutResponse?.data?.attributes?.total || '' isBrowser && window.localStorage.removeItem('quantity') isBrowser && window.localStorage.removeItem('add_ons') onPostCheckoutSuccess(checkoutResponse?.data.attributes) onConfirmSelectionSuccess({ skip_billing_page: skipBillingPage, event_id: String(eventId), hash, total, }) } catch (error) { if ((error as any).response?.data?.data?.hasUnverifiedOrder) { setPendingVerificationMessage((error as any).response?.data?.message) } else { onPostCheckoutError(error) onConfirmSelectionError(error) } } } else { if (isBrowser) { if (!skipAddonPage) { window.localStorage.setItem('add_ons', JSON.stringify(values)) } onConfirmSelectionSuccess({ skip_billing_page: skipBillingPage && enableBillingInfoAutoCreate, event_id: String(eventId), }) } else { onConfirmSelectionError({ error: true, message: 'Window is not defined' }) } } } catch (e) { onConfirmSelectionError(e) } } const handleClearAddons = () => { window.localStorage.removeItem('add_ons') } const initialValues = useMemo(() => { const addOnsData: any = {} if (addons?.length > 0 && addOnDataWithCustomFields?.fields?.length > 0) { _map(addons, addon => { _map(addOnDataWithCustomFields.fields, field => { const { id, groupItems } = field _map(groupItems, item => { addOnsData[`${addon.id}-${id}-${item.name}`] = item.value }) }) }) } return addOnsData }, [addons, addOnDataWithCustomFields]) return { addons, addonsOptions, loading, cartExpirationTime, pendingVerificationMessage, setPendingVerificationMessage, initialValues, onFieldChange, handleConfirm, handleClearAddons, } }