import {NodesStore, OfferData, useNodesStore} from "./store"; import {generateIdForType} from "./NodeHelpers"; import {cloneDeep, mergeWith, isArray} from "lodash"; import {CouponsPlus} from "../globals"; export const getOffers = () => { const state = useNodesStore.getState(); return new Offers(state); }; export type OffersState = Pick export class Offers { constructor(private readonly state: OffersState) {} get(id: string): OfferData | undefined { return this.state.offers.find((offer) => offer.id === id); } add(offers: (OfferData | Omit)[]): void { // only add the offers that are not already in the state offers.forEach((offer) => { // @ts-ignore if (!('id' in offer)) { // @ts-ignore offer.id = generateIdForType('offers') } const offerWithId: OfferData = offer as OfferData if (!this.get(offerWithId.id)) { this.state.offers.push(this.mergeWithDefaultCardData(offerWithId)); } }) } update(offer: OfferData): void { const offerIndex = this.state.offers.findIndex(({id}) => id === offer.id); if (offerIndex === -1) { return; } // we had: merge(this.state.offers[offerIndex], offer) // but fckass immer had a problem when merging arrays deeply nested in the object structure this.state.offers[offerIndex] = offer; } remove(offerId: string): void { const index = this.state.offers.findIndex((offer) => offer.id === offerId); if (index !== -1) { this.state.offers.splice(index, 1); } } mergeWithDefaultCardData(offerData: OfferData) { // we cannot use getComponentMetaData() unfortunately because of the god damn circular dependency issues const customizer = (objValue: any, srcValue: any) => { // If source value is defined and types don't match (e.g., array vs object), replace instead of merge if (srcValue !== undefined && ((isArray(objValue) && !isArray(srcValue)) || (!isArray(objValue) && isArray(srcValue)))) { return srcValue; } // For other cases, let mergeWith handle it (undefined means use default behavior) return undefined; }; const offerComponentDefinition = CouponsPlus.components.offers[offerData.type] || CouponsPlus?.stubs?.offers?.[offerData.type] return mergeWith({options: cloneDeep(offerComponentDefinition?.defaultOptions || {})}, offerData, customizer); } }