import {BranchData, BranchNode, StateBranchNode, TieredData, TieredExtraData} from "./StateBranchNode"; import {Testable} from "./Testable"; import {TestableNode} from "./TestableNode"; import {TreeNode} from "./TreeNode"; import {BeforeAddingToGroveHook, NestedTreeNodeData, TreeNodeData} from "./Grove"; import {Offers} from "./Offers"; import {OfferData, TestableData} from "./store"; import {Testables} from "./testables"; import {addIdToComponent, generateIdForType} from "./NodeHelpers"; import {InMemoryTestableNode} from "./InMemoryTestableNode"; import {pickBy} from "lodash"; import {exporterImporters} from "./export/CustomImportersAndExporters"; export type NestedBranchData = { id: string, type: BranchData['type'], data?: ExtraData, /** * They could be an array of offer objects or an array of tree nodes, for example * NOT an array of strings */ children: ChildrenType[] } export type NestedTieredData = { baseTestable: TestableData | Omit, } & Pick /** * Because of time constraints and fatigue, I am not going to implement the full functionality of this class * I'm only going to implement the methods that are needed right now */ export class MemoryBranchNode implements BranchNode, BeforeAddingToGroveHook { // @ts-ignore private treeNode: TreeNode; // @ts-ignore testableNode: TestableNode; constructor( public nestedBranchData: NestedBranchData, private readonly offers: Offers, private readonly testables: Testables ) { } addChildren(childrenData: ChildrenType[]): void { throw new Error("Method not implemented."); } beforeAddingToGrove() { // this is where we'll add the offers to the state // and deal with tiered state // this should probably be done in a different class for each type of branch // but for now, let's do it here this.beforeAddingToTreeNode() } /** * Logic should be here because beforeAddingToGrove() only works when adding first level branches to groves * Here it works when changing a tree node branch directly from an existing tree node object, this includes dnested tree nodes */ beforeAddingToTreeNode() { /** * This method is a mess and should be refactored */ if (this.isOffers()) { // add the Discount testables to the state if any const offers = this.getChildren() as OfferData[]; offers.forEach(offer => { const importer = exporterImporters[offer.type]; importer?.importData?.(offer, {testables: this.testables}) }) this.offers.add(offers) } // let's add the testable base if this is a tiered branch if (this.isTiered()) { const baseTestable = (this.nestedBranchData.data as NestedTieredData).baseTestable; if (baseTestable && typeof baseTestable !== 'string') { const baseTestableWithId = addIdToComponent(baseTestable) as TestableData this.testables.addTestables([baseTestable], undefined, false); ;(this.nestedBranchData.data as TieredData) = { baseTestableId: baseTestableWithId.id, tierType: (this.nestedBranchData.data as NestedTieredData).tierType, } } // now we should ass the testables from all descendants //n so let's take each children tree node and create memory objects for them the } // the do the swap to the real branch node const mapBranchChild = (nestedTreeNodeData: NestedTreeNodeData, parentBranchData?: NestedBranchData): NestedTreeNodeData | TreeNodeData => { nestedTreeNodeData.id = nestedTreeNodeData.id || generateIdForType('tree.node') // only if it's a partial const optionalParentBaseTestableid = parentBranchData?.type === 'tiered' ? (parentBranchData.data as TieredData).baseTestableId : undefined const memoryTestableNode = new InMemoryTestableNode((nestedTreeNodeData as NestedTreeNodeData).testable, this.testables, optionalParentBaseTestableid) const memoryBranchNode = new MemoryBranchNode((nestedTreeNodeData as NestedTreeNodeData).branch, this.offers, this.testables) // let's call the events here manually memoryTestableNode.beforeAddingToGrove() memoryBranchNode.beforeAddingToTreeNode() console.log('adding', memoryTestableNode, memoryTestableNode.getId()) return { id: (nestedTreeNodeData as NestedTreeNodeData).id, testableId: memoryTestableNode.getId(), // @ts-ignore branch: pickBy({ id: memoryBranchNode.getId(), type: memoryBranchNode.getType(), data: memoryBranchNode.isTiered() ? pickBy({ baseTestableId: nestedTreeNodeData.branch.data?.baseTestableId, tierType: nestedTreeNodeData.branch.data?.tierType, }, v => v !== undefined) as TieredExtraData : undefined, children: memoryBranchNode.isTiered() ? memoryBranchNode.getChildren().map(child => mapBranchChild(child)) : memoryBranchNode.getChildrenIds() }, v => v !== undefined), } }; return (new StateBranchNode( this.offers, { ...this.nestedBranchData, // @ts-ignore children: this.isTiered() ? this.nestedBranchData.children.map(child => mapBranchChild(child, this.nestedBranchData)) : this.getChildrenIds() }, this.testables, )) } getId(): string { return this.nestedBranchData.id; } getSourceRenderNodeId(): string { return this.testableNode.getId(); } setTreeNode(treeNode: TreeNode): void { this.treeNode = treeNode; } getTreeNode(): TreeNode { return this.treeNode; } setTestable(testable: TestableNode): void { this.testableNode = testable; } // @ts-ignore getChildren(): ChildrenType[] { return this.nestedBranchData.children as ChildrenType[] } getChildrenIds(): string[] { return this.nestedBranchData.children.map((child: any) => child.id) } getType(): BranchData["type"] { return this.nestedBranchData.type; } isOffers(): boolean { return this.nestedBranchData.type === 'offers'; } isSelectAction(): boolean { return this.nestedBranchData.type === 'select-action'; } isTiered(): boolean { return this.nestedBranchData.type === 'tiered'; } isSimple(): boolean { return this.isOffers() || this.isSelectAction(); } isInsideAnotherBranch(): boolean { throw new Error("Method not implemented."); } }