5180 fichiers 38.5 Mo 0 téléchargements 348 vues mis à jour il y a 7 heures ui
nitro-v36-with-renderer-v36 / src / components / catalog / views / admin / CatalogAdminDraftTree.ts
CatalogAdminDraftTree.ts 5.5 Ko Télécharger le fichier
import type { NodeData } from '@octane/renderer';
import { CatalogNode } from '../../../../api/catalog/CatalogNode';
import type { ICatalogNode } from '../../../../api/catalog/ICatalogNode';
import type { CatalogStudioCatalogType, CatalogStudioPageSnapshot } from '../../admin/studio/CatalogStudioTypes';

const toStudioCatalogType = (catalogType: string): CatalogStudioCatalogType =>
    catalogType === 'BUILDERS_CLUB' || catalogType === 'BUILDER' ? 'BUILDER' : 'NORMAL';

const collectLiveNodes = (node: ICatalogNode | null, result: Map<number, ICatalogNode>) => {
    if (!node) return;
    result.set(node.pageId, node);
    node.children.forEach((child) => collectLiveNodes(child, result));
};

const nodeData = (
    page: CatalogStudioPageSnapshot,
    liveNode: ICatalogNode | undefined
): NodeData => ({
    visible: page.visible,
    icon: page.iconImage,
    pageId: page.pageId,
    parentId: page.parentId,
    pageName: page.captionSave || liveNode?.pageName || `page-${page.pageId}`,
    localization: page.caption || liveNode?.localization || page.captionSave || `Page ${page.pageId}`,
    children: [],
    offerIds: liveNode?.offerIds ?? []
} as unknown as NodeData);

const rootData = (root: ICatalogNode): NodeData => ({
    visible: true,
    icon: root.iconId,
    pageId: root.pageId,
    parentId: root.parentId,
    pageName: root.pageName || 'root',
    localization: root.localization,
    children: [],
    offerIds: root.offerIds
} as unknown as NodeData);

export type CatalogAdminPageDropPosition = 'before' | 'inside' | 'after' | 'root';

export interface CatalogAdminPageMovePlan {
    pageId: number;
    newParentId: number;
    newIndex: number;
}

export const resolveCatalogAdminPageDropPosition = (
    pointerY: number,
    rowTop: number,
    rowHeight: number
): Exclude<CatalogAdminPageDropPosition, 'root'> => {
    const ratio = rowHeight > 0 ? (pointerY - rowTop) / rowHeight : 0.5;
    if (ratio <= 0.25) return 'before';
    if (ratio >= 0.75) return 'after';
    return 'inside';
};

const nodeContains = (ancestor: ICatalogNode, node: ICatalogNode | null) => {
    let current = node;
    while (current) {
        if (current.pageId === ancestor.pageId) return true;
        current = current.parent;
    }
    return false;
};

export const planCatalogAdminPageDrop = (
    dragged: ICatalogNode | null | undefined,
    target: ICatalogNode | null | undefined,
    position: CatalogAdminPageDropPosition,
    root: ICatalogNode | null | undefined
): CatalogAdminPageMovePlan | null => {
    if (!dragged || !root || dragged.pageId <= 0) return null;
    if (target?.pageId === dragged.pageId) return null;

    let parent = root;
    let insertionIndex = root.children.length;

    if (position !== 'root') {
        if (!target) return null;

        if (position === 'inside') {
            parent = target;
            insertionIndex = target.children.length;
        } else {
            parent = target.parent ?? root;
            const targetIndex = parent.children.indexOf(target);
            if (targetIndex < 0) return null;
            insertionIndex = targetIndex + (position === 'after' ? 1 : 0);
        }
    }

    if (nodeContains(dragged, parent)) return null;

    const sourceParent = dragged.parent;
    if (sourceParent?.pageId === parent.pageId) {
        const sourceIndex = sourceParent.children.indexOf(dragged);
        if (sourceIndex >= 0 && sourceIndex < insertionIndex) insertionIndex--;
        if (sourceIndex === insertionIndex) return null;
    }

    return {
        pageId: dragged.pageId,
        newParentId: parent === root ? -1 : parent.pageId,
        newIndex: Math.max(0, insertionIndex)
    };
};

export const buildCatalogAdminDraftTree = (
    liveRoot: ICatalogNode | null,
    pages: CatalogStudioPageSnapshot[],
    catalogType: string
): ICatalogNode | null => {
    if (!liveRoot) return null;

    const scopedPages = pages.filter((page) => page.catalogType === toStudioCatalogType(catalogType));
    if (!scopedPages.length) return liveRoot;

    const liveNodes = new Map<number, ICatalogNode>();
    collectLiveNodes(liveRoot, liveNodes);

    const pageIds = new Set(scopedPages.map((page) => page.pageId));
    const childrenByParent = new Map<number, CatalogStudioPageSnapshot[]>();
    const roots: CatalogStudioPageSnapshot[] = [];

    for (const page of scopedPages) {
        if (!pageIds.has(page.parentId)) {
            roots.push(page);
            continue;
        }

        const siblings = childrenByParent.get(page.parentId) ?? [];
        siblings.push(page);
        childrenByParent.set(page.parentId, siblings);
    }

    const sortPages = (items: CatalogStudioPageSnapshot[]) =>
        items.sort((left, right) => left.orderNum - right.orderNum || left.pageId - right.pageId);

    sortPages(roots);
    childrenByParent.forEach(sortPages);

    const draftRoot = new CatalogNode(rootData(liveRoot), 0, null);
    const visited = new Set<number>();

    const append = (page: CatalogStudioPageSnapshot, parent: ICatalogNode, depth: number): ICatalogNode | null => {
        if (visited.has(page.pageId)) return null;
        visited.add(page.pageId);

        const node = new CatalogNode(nodeData(page, liveNodes.get(page.pageId)), depth, parent);
        for (const child of childrenByParent.get(page.pageId) ?? []) {
            append(child, node, depth + 1);
        }
        parent.addChild(node);
        return node;
    };

    roots.forEach((page) => append(page, draftRoot, 1));
    scopedPages.forEach((page) => {
        if (!visited.has(page.pageId)) append(page, draftRoot, 1);
    });

    return draftRoot;
};
15Sujets
1Dépôts
20Membres
3En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser