import * as constants from '../../core/constants'; import { getFirstSellingPlan, isOgFrequency, mapFrequencyToSellingPlan, safeProductId } from '../../core/utils'; import type { ConfigState, ReceiveMerchantSettingsPayload, ReceiveOfferPayload, SetupProductPayload } from '../../core/types/reducer'; import { getPayAsYouGoSellingPlanGroup, sellingPlansToEveryPeriod, sellingPlansToFrequencies, getPrepaidShipments } from '../utils'; import { ShopifyProductEntity, ShopifySellingPlanGroupsEntity, ShopifyVariantsEntity } from '../types/shopify'; const config = ( state: ConfigState = { offerType: 'radio', productFrequencies: {}, frequencies: [], frequenciesEveryPeriod: [] }, action ): ConfigState => { if (constants.SETUP_PRODUCT === action.type) { const { payload: { product, currency } } = action as { payload: SetupProductPayload }; let configToAdd: ConfigState = {}; let productFrequencies: ConfigState['productFrequencies'] = product.variants?.reduce( (acc, variant) => reduceSellingPlansToFrequencies(acc, variant, product.selling_plan_groups, state), {} ); let updatedProductFrequencies = { ...state.productFrequencies, ...productFrequencies }; configToAdd = { ...configToAdd, productFrequencies: updatedProductFrequencies, // populate the old frequency fields for backwards compatibility // these are only needed if someone was reading our config state directly, which shouldn't be common but is possible ...Object.values(updatedProductFrequencies)[0] }; // prepaid selling plans const prepaidSellingPlans = getPrepaidSellingPlans(product); if (Object.keys(prepaidSellingPlans).length) { configToAdd = { ...configToAdd, prepaidSellingPlans: { ...state.prepaidSellingPlans, ...prepaidSellingPlans } }; } return { ...state, ...configToAdd, storeCurrency: currency }; } if (constants.RECEIVE_OFFER === action.type) { const { payload: { offer: offerEl } } = action as { payload: ReceiveOfferPayload }; const { defaultFrequency, product } = offerEl || {}; const { prepaidSellingPlans = {} } = state; // productFrequencies does not have entries for the cart ID // eligible frequencies apply to cart entries for the product const productId = safeProductId(product?.id); const currentProductFrequencies = state.productFrequencies[productId]; let updatedProductFrequencies: ConfigState['productFrequencies'] = { ...state.productFrequencies, [productId]: { ...currentProductFrequencies, defaultFrequency: getUpdatedDefaultFrequency( productId, defaultFrequency, prepaidSellingPlans, currentProductFrequencies?.frequencies, currentProductFrequencies?.frequenciesEveryPeriod ) } }; return { ...state, productFrequencies: updatedProductFrequencies, // populate the old frequency fields for backwards compatibility ...Object.values(updatedProductFrequencies)[0] }; } if (constants.RECEIVE_MERCHANT_SETTINGS === action.type) { return { ...state, merchantSettings: { ...(action.payload as ReceiveMerchantSettingsPayload) } }; } return state; }; function getFrequencies( productSellingPlanGroups: ShopifySellingPlanGroupsEntity[], state: { defaultFrequency?: string } ) { const sellingPlanGroup = getPayAsYouGoSellingPlanGroup(productSellingPlanGroups); const frequencies = sellingPlansToFrequencies(sellingPlanGroup); if (frequencies?.length) { const frequenciesEveryPeriod = sellingPlansToEveryPeriod(sellingPlanGroup); const frequenciesText = sellingPlanGroup.options?.[0]?.values || frequencies; let defaultFrequency = state?.defaultFrequency; if (defaultFrequency && isOgFrequency(defaultFrequency)) { defaultFrequency = mapFrequencyToSellingPlan(frequencies, frequenciesEveryPeriod, defaultFrequency) || getFirstSellingPlan(frequencies) || defaultFrequency; } return { frequencies, frequenciesEveryPeriod, frequenciesText, ...(defaultFrequency ? { defaultFrequency } : {}) }; } return null; } function reduceSellingPlansToFrequencies( acc: ConfigState['productFrequencies'], variant: ShopifyVariantsEntity, sellingPlanGroups: ShopifySellingPlanGroupsEntity[], state: ConfigState ) { const sellingPlanGroupIdsForProduct = variant.selling_plan_allocations.map( allocation => allocation.selling_plan_group_id ); const applicableSellingPlanGroups = sellingPlanGroups.filter(group => sellingPlanGroupIdsForProduct.includes(group.id) ); const frequencies = getFrequencies(applicableSellingPlanGroups, state.productFrequencies[variant.id]); if (frequencies) { acc[variant.id] = frequencies; } return acc; } function getUpdatedDefaultFrequency( productId: string, offerElementDefaultFrequency: string, prepaidSellingPlans: ConfigState['prepaidSellingPlans'], frequencies: string[] | undefined = [], frequenciesEveryPeriod: string[] | undefined = [] ) { // We don't want to be setting the default frequency to a prepaid selling plan if (prepaidSellingPlans[productId]?.some(({ sellingPlan }) => sellingPlan === offerElementDefaultFrequency)) { return getFirstSellingPlan(frequencies) || offerElementDefaultFrequency; } if (!isOgFrequency(offerElementDefaultFrequency)) { return offerElementDefaultFrequency; } return ( mapFrequencyToSellingPlan(frequencies, frequenciesEveryPeriod, offerElementDefaultFrequency) || getFirstSellingPlan(frequencies) || offerElementDefaultFrequency ); } export function getPrepaidSellingPlans( product: ShopifyProductEntity ): Record { const prepaidSellingPlanGroups = product?.selling_plan_groups.filter(group => /^Prepaid-.*/.test(group.name)); if (!prepaidSellingPlanGroups.length) { return {}; } return prepaidSellingPlanGroups.reduce((acc, cur) => { const variant = cur.name.split('-')[1]; const sellingPlanInfo = cur.selling_plans.map(sellingPlanObject => { return { numberShipments: getPrepaidShipments(sellingPlanObject), sellingPlan: String(sellingPlanObject.id) }; }); return { ...acc, [variant]: sellingPlanInfo }; }, {}); } export default config;