import { create } from "zustand"; import { v4 as uuidv4 } from "uuid"; import { PersonalityStore, PersonalityDataType, SectionItemType, TextType, ButtonType, ImageType, SocialType, HorizontalAlignment, VerticalAlignment, SelectedElement, } from "../types/Types"; // Helper function to get sections sorted by sortNumber export const getSortedSectionKeys = (data: PersonalityDataType): string[] => { return Object.keys(data).sort((a, b) => { const sortA = data[a].sortNumber || 0; const sortB = data[b].sortNumber || 0; return sortA - sortB; }); }; export const usePersonalityStore = create((set, get) => ({ data: { header: { name: "هدر", columnsCount: 1, items: [], sortNumber: 1 }, content: { name: "محتوا", columnsCount: 1, items: [], isContent: true, sortNumber: 2, }, footer: { name: "فوتر", columnsCount: 1, items: [], sortNumber: 3 }, }, activeSection: "", activeItemIndex: 0, selectedElement: null, isEditMode: false, setData: (data: PersonalityDataType) => set(() => { // Normalize data to ensure all sections have names const normalizedData: PersonalityDataType = {}; Object.entries(data).forEach(([key, section]) => { normalizedData[key] = { ...section, name: section.name || (key === "header" ? "هدر" : key === "content" ? "محتوا" : key === "footer" ? "فوتر" : `سکشن ${key}`), }; }); return { data: normalizedData }; }), setActiveSection: (section: string) => set((state) => { const sectionData = state.data[section]; if (!sectionData) { return state; } // اگر بخش آیتم ندارد و تعداد ستون‌ها بیشتر از صفر است، یک آیتم پیش‌فرض بساز if (sectionData.items.length === 0 && sectionData.columnsCount > 0) { const defaultItem = { id: uuidv4(), backgroundColor: "#ffffff", texts: [], buttons: [], images: [], socials: [], alignment: HorizontalAlignment.CENTER, verticalAlignment: VerticalAlignment.MIDDLE, }; return { activeSection: section, activeItemIndex: 0, selectedElement: null, isEditMode: false, data: { ...state.data, [section]: { ...sectionData, items: [defaultItem], }, }, }; } return { activeSection: section, activeItemIndex: 0, selectedElement: null, isEditMode: false, }; }), setActiveItemIndex: (index: number) => set(() => { return { activeItemIndex: index, selectedElement: null, isEditMode: false, }; }), setSelectedElement: (element: SelectedElement) => set({ selectedElement: element, isEditMode: !!element }), setEditMode: (isEdit: boolean) => set({ isEditMode: isEdit }), addSection: (afterSectionKey?: string) => set((state) => { // Generate automatic section name const existingSectionNumbers = Object.values(state.data) .map((section) => { if (!section.name) return 0; const match = section.name.match(/سکشن (\d+)/); return match ? parseInt(match[1]) : 0; }) .filter((num) => num > 0); const nextNumber = existingSectionNumbers.length > 0 ? Math.max(...existingSectionNumbers) + 1 : 1; const sectionName = `سکشن ${nextNumber}`; const sectionKey = `section_${nextNumber}`; if (state.data[sectionKey]) { return state; // Section already exists } // Calculate the sortNumber for the new section let newSortNumber = 1; if (afterSectionKey) { const afterSection = state.data[afterSectionKey]; if (afterSection) { // Insert after the specified section, so sortNumber should be higher newSortNumber = afterSection.sortNumber + 1; // Update sortNumbers of sections that come after Object.keys(state.data).forEach((key) => { if (state.data[key].sortNumber > afterSection.sortNumber) { state.data[key].sortNumber += 1; } }); } } else { // Add at the end - find the highest sortNumber and add 1 const maxSortNumber = Math.max( ...Object.values(state.data).map((section) => section.sortNumber || 0) ); newSortNumber = maxSortNumber + 1; } // Create new section data const newSection = { name: sectionName, columnsCount: 1, items: [], sortNumber: newSortNumber, }; // If afterSectionKey is provided, insert after that section if (afterSectionKey) { const keys = Object.keys(state.data); const afterIndex = keys.indexOf(afterSectionKey); // TODO all index expect that increase + if (afterIndex !== -1) { const newData: typeof state.data = {}; // Add sections before the target for (let i = 0; i <= afterIndex; i++) { newData[keys[i]] = state.data[keys[i]]; } // Add new section newData[sectionKey] = newSection; // Add remaining sections for (let i = afterIndex + 1; i < keys.length; i++) { newData[keys[i]] = state.data[keys[i]]; } return { data: newData }; } } // Default: add at the end return { data: { ...state.data, [sectionKey]: newSection, }, }; }), removeSection: (sectionKey: string) => set((state) => { // Cannot remove content section if (state.data[sectionKey]?.isContent) { return state; } const newData = { ...state.data }; delete newData[sectionKey]; return { data: newData, activeSection: state.activeSection === sectionKey ? "" : state.activeSection, selectedElement: null, isEditMode: false, }; }), setColumnsCount: (sectionKey: string, columnsCount: number) => set((state) => { const currentItems = state.data[sectionKey].items; const currentActiveItem = currentItems[state.activeItemIndex]; const newItems = Array.from({ length: columnsCount }, (_, index) => { // اگر این آیتم در حال حاضر وجود دارد، آن را حفظ کن if (currentItems[index]) { return currentItems[index]; } // اگر این اولین آیتم است و آیتم فعلی وجود دارد، از آن استفاده کن if (index === 0 && currentActiveItem) { return { ...currentActiveItem, id: currentActiveItem.id || uuidv4(), }; } // در غیر این صورت، یک آیتم جدید بساز return { id: uuidv4(), backgroundColor: "#ffffff", texts: [], buttons: [], images: [], socials: [], alignment: HorizontalAlignment.CENTER, verticalAlignment: VerticalAlignment.MIDDLE, }; }); return { data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], columnsCount, items: newItems, }, }, activeItemIndex: 0, }; }), setSectionPadding: (sectionKey: string, padding: string) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], padding, }, }, })), setSectionHeight: (sectionKey: string, height: string) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], height, }, }, })), setSectionBorder: ( sectionKey: string, border: { width?: string; color?: string; style?: "solid" | "dashed" | "dotted" | "none"; sides?: ("top" | "bottom" | "left" | "right")[]; } ) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], border, }, }, })), setItems: (sectionKey: string, items: SectionItemType[]) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items, }, }, })), addItem: (sectionKey: string, item: Omit) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: [...state.data[sectionKey].items, { ...item, id: uuidv4() }], }, }, })), updateActiveItem: (updates: Partial) => set((state) => { if (!state.activeSection) return state; const sectionKey = state.activeSection; const items = state.data[sectionKey].items; const activeIndex = state.activeItemIndex; // اگر آیتم فعال وجود ندارد، یکی بساز if (activeIndex >= items.length) { const newItem = { id: uuidv4(), backgroundColor: "#ffffff", texts: [], buttons: [], images: [], socials: [], alignment: HorizontalAlignment.CENTER, verticalAlignment: VerticalAlignment.MIDDLE, ...updates, }; const newItems = [...items]; newItems[activeIndex] = newItem; return { data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: newItems, }, }, }; } const updatedItems = items.map((item, index) => index === activeIndex ? { ...item, ...updates } : item ); return { data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: updatedItems, }, }, }; }), updateItem: ( sectionKey: string, id: string, updates: Partial ) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: state.data[sectionKey].items.map((item) => item.id === id ? { ...item, ...updates } : item ), }, }, })), removeItem: (sectionKey: string, id: string) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: state.data[sectionKey].items.filter((item) => item.id !== id), }, }, })), addText: (sectionKey: string, itemId: string, text: Omit) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: state.data[sectionKey].items.map((item) => item.id === itemId ? { ...item, texts: [...(item.texts || []), { ...text, id: uuidv4() }], } : item ), }, }, })), addTextToActiveItem: (text: Omit) => set((state) => { if (!state.activeSection) return state; const sectionKey = state.activeSection as string; const items = state.data[sectionKey].items; const activeIndex = state.activeItemIndex; if (activeIndex >= items.length) return state; const updatedItems = items.map((item, index) => index === activeIndex ? { ...item, texts: [...(item.texts || []), { ...text, id: uuidv4() }], } : item ); return { data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: updatedItems, }, }, }; }), addButton: ( sectionKey: string, itemId: string, button: Omit ) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: state.data[sectionKey].items.map((item) => item.id === itemId ? { ...item, buttons: [ ...(item.buttons || []), { ...button, id: uuidv4() }, ], } : item ), }, }, })), addButtonToActiveItem: (button: Omit) => set((state) => { if (!state.activeSection) return state; const sectionKey = state.activeSection as string; const items = state.data[sectionKey].items; const activeIndex = state.activeItemIndex; if (activeIndex >= items.length) return state; const updatedItems = items.map((item, index) => index === activeIndex ? { ...item, buttons: [...(item.buttons || []), { ...button, id: uuidv4() }], } : item ); return { data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: updatedItems, }, }, }; }), updateText: ( sectionKey: string, itemId: string, textId: string, updates: Partial ) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: state.data[sectionKey].items.map((item) => item.id === itemId ? { ...item, texts: (item.texts || []).map((text) => text.id === textId ? { ...text, ...updates } : text ), } : item ), }, }, })), updateButton: ( sectionKey: string, itemId: string, buttonId: string, updates: Partial ) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: state.data[sectionKey].items.map((item) => item.id === itemId ? { ...item, buttons: (item.buttons || []).map((button) => button.id === buttonId ? { ...button, ...updates } : button ), } : item ), }, }, })), addImage: ( sectionKey: string, itemId: string, image: Omit ) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: state.data[sectionKey].items.map((item) => item.id === itemId ? { ...item, images: [...(item.images || []), { ...image, id: uuidv4() }], } : item ), }, }, })), addImageToActiveItem: (image: Omit) => set((state) => { if (!state.activeSection) return state; const sectionKey = state.activeSection as string; const items = state.data[sectionKey].items; const activeIndex = state.activeItemIndex; if (activeIndex >= items.length) return state; const updatedItems = items.map((item, index) => index === activeIndex ? { ...item, images: [...(item.images || []), { ...image, id: uuidv4() }], } : item ); return { data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: updatedItems, }, }, }; }), updateImage: ( sectionKey: string, itemId: string, imageId: string, updates: Partial ) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: state.data[sectionKey].items.map((item) => item.id === itemId ? { ...item, images: (item.images || []).map((image) => image.id === imageId ? { ...image, ...updates } : image ), } : item ), }, }, })), deleteText: (sectionKey: string, itemId: string, textId: string) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: state.data[sectionKey].items.map((item) => item.id === itemId ? { ...item, texts: (item.texts || []).filter( (text) => text.id !== textId ), } : item ), }, }, selectedElement: null, isEditMode: false, })), deleteButton: (sectionKey: string, itemId: string, buttonId: string) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: state.data[sectionKey].items.map((item) => item.id === itemId ? { ...item, buttons: (item.buttons || []).filter( (button) => button.id !== buttonId ), } : item ), }, }, selectedElement: null, isEditMode: false, })), deleteImage: (sectionKey: string, itemId: string, imageId: string) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: state.data[sectionKey].items.map((item) => item.id === itemId ? { ...item, images: (item.images || []).filter( (image) => image.id !== imageId ), } : item ), }, }, selectedElement: null, isEditMode: false, })), addSocial: ( sectionKey: string, itemId: string, social: Omit ) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: state.data[sectionKey].items.map((item) => item.id === itemId ? { ...item, socials: [ ...(item.socials || []), { ...social, id: uuidv4() }, ], } : item ), }, }, })), addSocialToActiveItem: (social: Omit) => set((state) => { if (!state.activeSection) return state; const sectionKey = state.activeSection as string; const items = state.data[sectionKey].items; const activeIndex = state.activeItemIndex; if (activeIndex >= items.length) return state; const updatedItems = items.map((item, index) => index === activeIndex ? { ...item, socials: [...(item.socials || []), { ...social, id: uuidv4() }], } : item ); return { data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: updatedItems, }, }, }; }), updateSocial: ( sectionKey: string, itemId: string, socialId: string, updates: Partial ) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: state.data[sectionKey].items.map((item) => item.id === itemId ? { ...item, socials: (item.socials || []).map((social) => social.id === socialId ? { ...social, ...updates } : social ), } : item ), }, }, })), deleteSocial: (sectionKey: string, itemId: string, socialId: string) => set((state) => ({ data: { ...state.data, [sectionKey]: { ...state.data[sectionKey], items: state.data[sectionKey].items.map((item) => item.id === itemId ? { ...item, socials: (item.socials || []).filter( (social) => social.id !== socialId ), } : item ), }, }, selectedElement: null, isEditMode: false, })), getSortedSectionKeys: () => getSortedSectionKeys(get().data), }));