Duffer Derek

Current Path : /var/www/uibuilder.cmshelp.dk/httpdocs/src/app/_components/context/
Upload File :
Current File : /var/www/uibuilder.cmshelp.dk/httpdocs/src/app/_components/context/CanvasContext.tsx

import React, { createContext, useContext, useState, useEffect } from 'react';
import { headerConfig } from '../config/headerConfig';
import { footerConfig } from '../config/footerConfig';
import umbracoService from '../services/umbracoService';
import { mapUmbracoToHeaderProperties } from '../mappers/headerMapper';
import { mapUmbracoToFooterProperties } from '../mappers/footerMapper';
import { mapUmbracoToComponentData } from '../mappers/pageMapper';
import { v4 as uuidv4 } from 'uuid';

export interface DroppedItem {
  id: string;
  html: string;
  uniqueId: string;
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
  properties: { [key: string]: any };
}

export interface Page {
  id: string;
  name: string;
  url: string; // Add url property
  isProtected: boolean;
  documentType: {
    id: string;
    icon: string;
  };
  variants: {
    state: string;
    name: string;
     // eslint-disable-next-line @typescript-eslint/no-explicit-any
    culture: any;
  }[];
  noAccess: boolean;
  isTrashed: boolean;
  parent: string;
  hasChildren: boolean;
}

export const GRID_TYPES = {
  DEFAULT: {
    id: '99740655-b76b-4d34-aaac-aace495a39b6',
    documentId: '99740655-b76b-4d34-aaac-aace495a39b6',
    columns: 1
  },
  ONE_COLUMN: {
    id: 'c996b4ec-1a0d-4a7c-b99d-466c2b153da4',
    documentId: 'c996b4ec-1a0d-4a7c-b99d-466c2b153da4',
    columns: 1
  },
  TWO_COLUMN: {
    id: 'd6dbc5f5-510a-4020-be64-ef32b741be22',
    documentId: 'd6dbc5f5-510a-4020-be64-ef32b741be22',
    columns: 2
  },
  THREE_COLUMN: {
    id: 'bfe13a0c-ab38-4f4f-8720-dcf34f8475d1',
    documentId: 'bfe13a0c-ab38-4f4f-8720-dcf34f8475d1',
    columns: 3
  }
};

export interface GridLayout {
  id: string;
  documentId: string;
  columns: (DroppedItem | GridLayout)[][];
  parentId?: string;
}

interface GridState {
  layouts: GridLayout[];
  components: { [gridId: string]: DroppedItem[] };
}

interface CanvasContextProps {
  droppedItems: { [pageId: string]: DroppedItem[] };
  setDroppedItems: (pageId: string, items: DroppedItem[]) => void;
  headerItem: DroppedItem;
  setHeaderItem: React.Dispatch<React.SetStateAction<DroppedItem>>;
  footerItem: DroppedItem;
  setFooterItem: React.Dispatch<React.SetStateAction<DroppedItem>>;
  pages: Page[];
  setPages: React.Dispatch<React.SetStateAction<Page[]>>;
  currentPage: Page | null;
  setCurrentPage: React.Dispatch<React.SetStateAction<Page | null>>;
  gridState: { [pageId: string]: GridState };
  setGridState: (pageId: string, state: GridState) => void;
  updateGridLayout: (pageId: string, gridId: string, updatedGrid: GridLayout) => void;
  addGridLayout: (pageId: string, columns: number, parentId?: string) => void;
  removeGridLayout: (pageId: string, gridId: string) => void;
  addComponentToGrid: (pageId: string, gridId: string, columnIndex: number, component: DroppedItem) => void;
  removeComponentFromGrid: (pageId: string, gridId: string, columnIndex: number, componentId: string) => void;
}

const CanvasContext = createContext<CanvasContextProps | undefined>(undefined);

export const CanvasProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const [droppedItems, setDroppedItemsState] = useState<{ [pageId: string]: DroppedItem[] }>({});
  const [headerItem, setHeaderItem] = useState<DroppedItem>({
    id: 'header',
    html: headerConfig.htmlTemplate(headerConfig.defaultProperties),
    uniqueId: 'header',
    properties: headerConfig.defaultProperties,
  });
  const [footerItem, setFooterItem] = useState<DroppedItem>({
    id: 'footer',
    html: footerConfig.htmlTemplate(footerConfig.defaultProperties),
    uniqueId: 'footer',
    properties: footerConfig.defaultProperties,
  });
  const [pages, setPages] = useState<Page[]>([]);
  const [currentPage, setCurrentPage] = useState<Page | null>(null);
  const [gridState, setGridStateInternal] = useState<{ [pageId: string]: GridState }>({});

  // Add similar mapping functions for other components here...
// eslint-disable-next-line @typescript-eslint/no-explicit-any
  const getComponentData = async (umbracoData:any) => {
    try {
      return mapUmbracoToComponentData(umbracoData);
    } catch (error) {
      console.error('Failed to fetch component data:', error);
      return {};
    }
  };

  const fetchHeaderAndFooter = async () => {
    try {
      const commonNodeId = umbracoService.getCommonNodeId();
      const commonNodeData = await umbracoService.fetchPageById(commonNodeId);
      const headerProperties = mapUmbracoToHeaderProperties(commonNodeData);
      const footerProperties = mapUmbracoToFooterProperties(commonNodeData);
      setHeaderItem({
        id: 'header',
        html: headerConfig.htmlTemplate(headerProperties),
        uniqueId: 'header',
        properties: headerProperties,
      });
      setFooterItem({
        id: 'footer',
        html: footerConfig.htmlTemplate(footerProperties),
        uniqueId: 'footer',
        properties: footerProperties,
      });
    } catch (error) {
      console.error('Failed to fetch header and footer data:', error);
    }
  };

  useEffect(() => {
    const fetchPages = async () => {
      try {
        const fetchedPages = await umbracoService.fetchPages();
        setPages(fetchedPages);
        
        if (fetchedPages && fetchedPages.length > 0) {
          const firstPage = fetchedPages[0];
          const currentPageData = await umbracoService.fetchPageById(firstPage.id);
          debugger
          if (currentPageData) {
            const componentData = await getComponentData(currentPageData);
            setCurrentPage({ ...firstPage, ...currentPageData });
            
            if (componentData && firstPage.id) {
              // Replace setDroppedItems with setGridState
              setGridState(firstPage.id, componentData[firstPage.id] || { layouts: [], components: {} });
            }
          }
        }
        
        await fetchHeaderAndFooter();
      } catch (error) {
        console.error('Failed to fetch pages:', error);
      }
    };

    fetchPages();
  }, []);

  const setDroppedItems = (pageId: string, items: DroppedItem[]) => {
    if (!pageId) return;
    
    setDroppedItemsState(prevState => ({
      ...prevState,
      [pageId]: Array.isArray(items) ? items : []
    }));
  };

  const setGridState = (pageId: string, state: GridState) => {
    setGridStateInternal(prev => ({
      ...prev,
      [pageId]: state
    }));
  };

  const updateGridLayout = (pageId: string, gridId: string, updatedGrid: GridLayout) => {
    setGridStateInternal(prev => {
      const pageGrids = prev[pageId] || { layouts: [], components: {} };
      const updateGridRecursively = (layouts: GridLayout[]): GridLayout[] => {
        return layouts.map(grid => {
          if (grid.id === gridId) {
            return updatedGrid;
          }
          return {
            ...grid,
            columns: grid.columns.map(column =>
              column.map(item => {
                if ('columns' in item) {
                  return {
                    ...item,
                    columns: updateGridRecursively([item])[0].columns
                  };
                }
                return item;
              })
            )
          };
        });
      };

      return {
        ...prev,
        [pageId]: {
          ...pageGrids,
          layouts: updateGridRecursively(pageGrids.layouts)
        }
      };
    });
  };

  const addGridLayout = (pageId: string, columns: number, parentId?: string) => {
    let gridType;
    switch (columns) {
      case 1:
        gridType = GRID_TYPES.ONE_COLUMN;
        break;
      case 2:
        gridType = GRID_TYPES.TWO_COLUMN;
        break;
      case 3:
        gridType = GRID_TYPES.THREE_COLUMN;
        break;
      default:
        gridType = GRID_TYPES.DEFAULT;
    }
  
    const newGrid: GridLayout = {
      id: `${gridType.id}-${uuidv4()}`, // Add unique identifier to the grid ID
      documentId: gridType.id, // Keep the original content type key in documentId
      columns: new Array(columns).fill(null).map(() => []),
      parentId
    };
  
    setGridStateInternal(prev => {
      const pageGrids = prev[pageId] || { layouts: [], components: {} };
      
      if (!parentId) {
        return {
          ...prev,
          [pageId]: {
            ...pageGrids,
            layouts: [...pageGrids.layouts, newGrid]
          }
        };
      }
  
      const updateParentGrid = (layouts: GridLayout[]): GridLayout[] => {
        return layouts.map(grid => {
          if (grid.id === parentId) {
            return {
              ...grid,
              columns: grid.columns.map(col => [...col, newGrid])
            };
          }
          if (grid.columns) {
            return {
              ...grid,
              columns: grid.columns.map(col =>
                col.map(item => {
                  if ('columns' in item) {
                    return updateParentGrid([item])[0];
                  }
                  return item;
                })
              )
            };
          }
          return grid;
        });
      };
  
      return {
        ...prev,
        [pageId]: {
          ...pageGrids,
          layouts: updateParentGrid(pageGrids.layouts)
        }
      };
    });
  };

  const removeGridLayout = (pageId: string, gridId: string) => {
    setGridStateInternal(prev => {
      const pageGrids = prev[pageId] || { layouts: [], components: {} };
      
      const removeGridRecursively = (layouts: GridLayout[]): GridLayout[] => {
        return layouts
          .filter(grid => grid.id !== gridId)
          .map(grid => ({
            ...grid,
            columns: grid.columns?.map(column =>
              column?.filter(item => {
                if (item && 'columns' in item) {
                  const updatedItem = removeGridRecursively([item as GridLayout])[0];
                  return updatedItem !== undefined;
                }
                return true;
              })
            ) || []
          }));
      };

      const newLayouts = removeGridRecursively(pageGrids.layouts);
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      const { [gridId]: removedComponents, ...remainingComponents } = pageGrids.components;

      return {
        ...prev,
        [pageId]: {
          ...pageGrids,
          layouts: newLayouts,
          components: remainingComponents
        }
      };
    });
  };

  const addComponentToGrid = (
    pageId: string, 
    gridId: string, 
    columnIndex: number, 
    component: DroppedItem
  ) => {
    setGridStateInternal(prev => {
      const pageGrids = prev[pageId] || { layouts: [], components: {} };
      
      const updateGridRecursively = (layouts: GridLayout[]): GridLayout[] => {
        return layouts.map(grid => {
          if (grid.id === gridId) {
            const newColumns = [...grid.columns];
            newColumns[columnIndex] = [...(newColumns[columnIndex] || []), component];
            return { ...grid, columns: newColumns };
          }
          return {
            ...grid,
            columns: grid.columns.map(column =>
              column.map(item => {
                if ('columns' in item) {
                  return {
                    ...item,
                    columns: updateGridRecursively([item])[0].columns
                  };
                }
                return item;
              })
            )
          };
        });
      };

      return {
        ...prev,
        [pageId]: {
          ...pageGrids,
          layouts: updateGridRecursively(pageGrids.layouts),
          components: {
            ...pageGrids.components,
            [gridId]: [...(pageGrids.components[gridId] || []), component]
          }
        }
      };
    });
  };

  const removeComponentFromGrid = (
    pageId: string, 
    gridId: string, 
    columnIndex: number, 
    componentId: string
  ) => {
    setGridStateInternal(prev => {
      const pageGrids = prev[pageId] || { layouts: [], components: {} };
      
      const updateGridRecursively = (layouts: GridLayout[]): GridLayout[] => {
        return layouts.map(grid => {
          if (grid.id === gridId) {
            const newColumns = [...grid.columns];
            newColumns[columnIndex] = newColumns[columnIndex].filter(
              item => !('uniqueId' in item) || item.uniqueId !== componentId
            );
            return { ...grid, columns: newColumns };
          }
          return {
            ...grid,
            columns: grid.columns.map(column =>
              column.map(item => {
                if ('columns' in item) {
                  return {
                    ...item,
                    columns: updateGridRecursively([item])[0].columns
                  };
                }
                return item;
              })
            )
          };
        });
      };

      return {
        ...prev,
        [pageId]: {
          ...pageGrids,
          layouts: updateGridRecursively(pageGrids.layouts),
          components: {
            ...pageGrids.components,
            [gridId]: (pageGrids.components[gridId] || []).filter(
              comp => comp.uniqueId !== componentId
            )
          }
        }
      };
    });
  };

  // Initialize grid state for new pages
  useEffect(() => {
    const initializeGridState = () => {
      if (pages.length > 0) {
        pages.forEach(page => {
          setGridState(page.id, {
            layouts: [{
              id: GRID_TYPES.DEFAULT.id,
              documentId: GRID_TYPES.DEFAULT.documentId,
              columns: [[]]
            }],
            components: {}
          });
        });
      }
    };

    initializeGridState();
  }, [pages]);

  return (
    <CanvasContext.Provider value={{ droppedItems, setDroppedItems, headerItem, setHeaderItem, footerItem, setFooterItem, pages, setPages, currentPage, setCurrentPage, gridState, setGridState, updateGridLayout, addGridLayout, removeGridLayout, addComponentToGrid, removeComponentFromGrid }}>
      {children}
    </CanvasContext.Provider>
  );
};

export const useCanvasContext = () => {
  const context = useContext(CanvasContext);
  if (!context) {
    throw new Error('useCanvasContext must be used within a CanvasProvider');
  }
  return context;
};

Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists