commerce/framework/vendure/lib/array-to-tree.ts
Michael Bromley da4371090d
Vendure provider (#223)
* Minimal list/detail views working with Vendure

* Implement useCart/useAddItem

* Implement useUpdateItem & useRemoveItem

* Implement useSearch

* Add operations codegen, tidy up

* Dummy checkout page

* Implement auth/customer hooks

* Use env var for Shop API url

* Add some documentation

* Improve error handling

* Optimize preview image size

* Fix accidental change

* Update Vendure provider to latest changes

* Vendure provider: split out gql operations, remove unused files

* Update Vendure provider readme

* Add local next.config to Vendure provider, update docs

* Update to use demo server

* Fix build errors

* Use proxy for vendure api

* Simplify instructions in Vendure readme

* Refactor Vendure checkout api handler

* Improve image quality
2021-05-27 18:06:56 -03:00

68 lines
2.0 KiB
TypeScript

export type HasParent = { id: string; parent?: { id: string } | null }
export type TreeNode<T extends HasParent> = T & {
children: Array<TreeNode<T>>
expanded: boolean
}
export type RootNode<T extends HasParent> = {
id?: string
children: Array<TreeNode<T>>
}
export function arrayToTree<T extends HasParent>(
nodes: T[],
currentState?: RootNode<T>
): RootNode<T> {
const topLevelNodes: Array<TreeNode<T>> = []
const mappedArr: { [id: string]: TreeNode<T> } = {}
const currentStateMap = treeToMap(currentState)
// First map the nodes of the array to an object -> create a hash table.
for (const node of nodes) {
mappedArr[node.id] = { ...(node as any), children: [] }
}
for (const id of nodes.map((n) => n.id)) {
if (mappedArr.hasOwnProperty(id)) {
const mappedElem = mappedArr[id]
mappedElem.expanded = currentStateMap.get(id)?.expanded ?? false
const parent = mappedElem.parent
if (!parent) {
continue
}
// If the element is not at the root level, add it to its parent array of children.
const parentIsRoot = !mappedArr[parent.id]
if (!parentIsRoot) {
if (mappedArr[parent.id]) {
mappedArr[parent.id].children.push(mappedElem)
} else {
mappedArr[parent.id] = { children: [mappedElem] } as any
}
} else {
topLevelNodes.push(mappedElem)
}
}
}
// tslint:disable-next-line:no-non-null-assertion
const rootId = topLevelNodes.length ? topLevelNodes[0].parent!.id : undefined
return { id: rootId, children: topLevelNodes }
}
/**
* Converts an existing tree (as generated by the arrayToTree function) into a flat
* Map. This is used to persist certain states (e.g. `expanded`) when re-building the
* tree.
*/
function treeToMap<T extends HasParent>(
tree?: RootNode<T>
): Map<string, TreeNode<T>> {
const nodeMap = new Map<string, TreeNode<T>>()
function visit(node: TreeNode<T>) {
nodeMap.set(node.id, node)
node.children.forEach(visit)
}
if (tree) {
visit(tree as TreeNode<T>)
}
return nodeMap
}