diff --git a/src/pages/setting/personality/components/ContentSection.tsx b/src/pages/setting/personality/components/ContentSection.tsx
new file mode 100644
index 0000000..32302f0
--- /dev/null
+++ b/src/pages/setting/personality/components/ContentSection.tsx
@@ -0,0 +1,118 @@
+import { FC } from 'react'
+import { usePersonalityStore } from '../store/Store'
+import { useTranslation } from 'react-i18next'
+import { AddCircle } from 'iconsax-react'
+
+const ContentSection: FC = () => {
+
+ const { t } = useTranslation()
+ const { activeSection, activeItemIndex, data, setActiveSection, setActiveItemIndex } = usePersonalityStore()
+
+ const handleSectionClick = (section: "header" | "content" | "footer") => {
+ setActiveSection(section)
+ }
+
+ const handleItemClick = (index: number) => {
+ setActiveItemIndex(index)
+ }
+
+ return (
+
handleSectionClick("content")}>
+
+ {
+ data.content.columnsCount > 0 ?
+
+
+
+
+
+
+
+ {
+ Array.from({ length: data.content.columnsCount }, (_, index) => {
+ const item = data.content.items[index];
+ const isActive = activeSection === "content" && activeItemIndex === index;
+
+ return (
+ <>
+ | {
+ e.stopPropagation();
+ handleItemClick(index);
+ }}
+ key={index}
+ style={{
+ height: '246px',
+ border: isActive ? '1px dashed #0038FF' : '1px dashed #EAECF4',
+ backgroundColor: item?.backgroundColor || '#ffffff',
+ backgroundImage: item?.backgroundImage ? `url(${item.backgroundImage})` : 'none',
+ backgroundSize: 'cover',
+ backgroundPosition: 'center',
+ cursor: 'pointer'
+ }}
+ >
+ {/* محتوای آیتم */}
+ {item?.texts?.map(text => (
+
+ {text.text}
+
+ ))}
+ {item?.buttons?.map(button => (
+
+ ))}
+ |
+ {index < data.content.columnsCount - 1 && (
+ |
+ )}
+ >
+ )
+ })
+ }
+
+
+
+ |
+
+
+
+ :
+
+
+
+ |
+
+ {t('setting.content_email')}
+
+
+ |
+
+
+
+ }
+ |
+
+ )
+}
+
+export default ContentSection
\ No newline at end of file
diff --git a/src/pages/setting/personality/components/FooterSection.tsx b/src/pages/setting/personality/components/FooterSection.tsx
new file mode 100644
index 0000000..b68c9b7
--- /dev/null
+++ b/src/pages/setting/personality/components/FooterSection.tsx
@@ -0,0 +1,118 @@
+import { FC } from 'react'
+import { usePersonalityStore } from '../store/Store'
+import { useTranslation } from 'react-i18next'
+import { AddCircle } from 'iconsax-react'
+
+const FooterSection: FC = () => {
+
+ const { t } = useTranslation()
+ const { activeSection, activeItemIndex, data, setActiveSection, setActiveItemIndex } = usePersonalityStore()
+
+ const handleSectionClick = (section: "header" | "content" | "footer") => {
+ setActiveSection(section)
+ }
+
+ const handleItemClick = (index: number) => {
+ setActiveItemIndex(index)
+ }
+
+ return (
+
handleSectionClick("footer")}>
+
+ {
+ data.footer.columnsCount > 0 ?
+
+
+
+
+
+
+
+ {
+ Array.from({ length: data.footer.columnsCount }, (_, index) => {
+ const item = data.footer.items[index];
+ const isActive = activeSection === "footer" && activeItemIndex === index;
+
+ return (
+ <>
+ | {
+ e.stopPropagation();
+ handleItemClick(index);
+ }}
+ key={index}
+ style={{
+ height: '83px',
+ border: isActive ? '1px dashed #0038FF' : '1px dashed #EAECF4',
+ backgroundColor: item?.backgroundColor || '#ffffff',
+ backgroundImage: item?.backgroundImage ? `url(${item.backgroundImage})` : 'none',
+ backgroundSize: 'cover',
+ backgroundPosition: 'center',
+ cursor: 'pointer'
+ }}
+ >
+ {/* محتوای آیتم */}
+ {item?.texts?.map(text => (
+
+ {text.text}
+
+ ))}
+ {item?.buttons?.map(button => (
+
+ ))}
+ |
+ {index < data.footer.columnsCount - 1 && (
+ |
+ )}
+ >
+ )
+ })
+ }
+
+
+
+ |
+
+
+
+ :
+
+
+
+ |
+
+ {t('setting.footer_email')}
+
+
+ |
+
+
+
+ }
+ |
+
+ )
+}
+
+export default FooterSection
\ No newline at end of file
diff --git a/src/pages/setting/personality/components/HeaderSection.tsx b/src/pages/setting/personality/components/HeaderSection.tsx
new file mode 100644
index 0000000..4f8a94c
--- /dev/null
+++ b/src/pages/setting/personality/components/HeaderSection.tsx
@@ -0,0 +1,104 @@
+import { FC } from 'react'
+import { usePersonalityStore } from '../store/Store'
+import { useTranslation } from 'react-i18next'
+import { AddCircle } from 'iconsax-react'
+
+const HeaderSection: FC = () => {
+
+ const { t } = useTranslation()
+ const { activeSection, activeItemIndex, data, setActiveSection, setActiveItemIndex } = usePersonalityStore()
+
+ const handleSectionClick = (section: "header" | "content" | "footer") => {
+ setActiveSection(section)
+ }
+
+ const handleItemClick = (index: number) => {
+ setActiveItemIndex(index)
+ }
+
+ return (
+
handleSectionClick("header")}>
+ {
+ data.header.columnsCount > 0 ?
+
+
+
+
+ {
+ Array.from({ length: data.header.columnsCount }, (_, index) => {
+ const item = data.header.items[index];
+ const isActive = activeSection === "header" && activeItemIndex === index;
+
+ return (
+ <>
+ | {
+ e.stopPropagation();
+ handleItemClick(index);
+ }}
+ key={index}
+ style={{
+ height: '103px',
+ border: isActive ? '1px dashed #0038FF' : '1px dashed #EAECF4',
+ backgroundColor: item?.backgroundColor || '#ffffff',
+ backgroundImage: item?.backgroundImage ? `url(${item.backgroundImage})` : 'none',
+ backgroundSize: 'cover',
+ backgroundPosition: 'center',
+ cursor: 'pointer'
+ }}
+ >
+ {/* محتوای آیتم */}
+ {item?.texts?.map(text => (
+
+ {text.text}
+
+ ))}
+ {item?.buttons?.map(button => (
+
+ ))}
+ |
+ {index < data.header.columnsCount - 1 && (
+ |
+ )}
+ >
+ )
+ })
+ }
+
+
+
+ |
+ :
+
+
+ {t('setting.header_email')}
+
+
+ |
+ }
+
+ )
+}
+
+export default HeaderSection
\ No newline at end of file
diff --git a/src/pages/setting/personality/components/SettingSideBar.tsx b/src/pages/setting/personality/components/SettingSideBar.tsx
index 2a0c9f4..c766405 100644
--- a/src/pages/setting/personality/components/SettingSideBar.tsx
+++ b/src/pages/setting/personality/components/SettingSideBar.tsx
@@ -4,35 +4,75 @@ import UploadBoxDraggble from '@/components/UploadBoxDraggble';
import Select from '@/components/Select';
import { AlignBottom, AlignHorizontally, AlignLeft, AlignRight, AlignTop, AlignVertically } from 'iconsax-react';
import ColorPicker from '@/components/ColorPicker';
-
+import { usePersonalityStore } from '../store/Store';
const SettingSideBar: FC = () => {
-
const { t } = useTranslation()
+ const { activeSection, setColumnsCount, updateActiveItem } = usePersonalityStore()
const [color, setColor] = useState("#aabbcc");
+ const handleColumnClick = (columns: number) => {
+ if (activeSection) {
+ setColumnsCount(activeSection as "header" | "content" | "footer", columns);
+ }
+ }
+
+ const handleColorChange = (color: string) => {
+ setColor(color)
+ updateActiveItem({ backgroundColor: color })
+ }
+
+ const handleUploadBackground = (file: File[]) => {
+ if (activeSection && file.length > 0) {
+ const imageUrl = URL.createObjectURL(file[0])
+ console.log('Setting background image:', imageUrl)
+ updateActiveItem({ backgroundImage: imageUrl })
+ }
+ }
+
+ if (!activeSection) {
+ return (
+
+ {t('setting.select_section')}
+
+ )
+ }
+
return (
{t('setting.setting')}
-
-
-
-
+
handleColumnClick(1)}
+ >
+
handleColumnClick(2)}
+ >
+
+
+
-
-
-
-
+
handleColumnClick(3)}
+ >
+
+
+
-
-
-
-
-
+
handleColumnClick(4)}
+ >
+
+
+
+
@@ -40,14 +80,14 @@ const SettingSideBar: FC = () => {
null}
+ onChange={handleUploadBackground}
/>
@@ -65,20 +105,50 @@ const SettingSideBar: FC = () => {
{t('setting.horizontal_position')}
-
-
-
+
updateActiveItem({ alignment: 'right' })}
+ />
+ updateActiveItem({ alignment: 'center' })}
+ />
+ updateActiveItem({ alignment: 'left' })}
+ />
- {t('setting.horizontal_position')}
+ {t('setting.vertical_position')}
-
-
-
+
updateActiveItem({ verticalAlignment: 'bottom' })}
+ />
+ updateActiveItem({ verticalAlignment: 'middle' })}
+ />
+ updateActiveItem({ verticalAlignment: 'top' })}
+ />
diff --git a/src/pages/setting/personality/store/Store.ts b/src/pages/setting/personality/store/Store.ts
new file mode 100644
index 0000000..c755126
--- /dev/null
+++ b/src/pages/setting/personality/store/Store.ts
@@ -0,0 +1,294 @@
+import { create } from "zustand";
+import { v4 as uuidv4 } from "uuid";
+import {
+ PersonalityStore,
+ PersonalityDataType,
+ SectionItemType,
+ TextType,
+ ButtonType,
+} from "../types/Types";
+
+export const usePersonalityStore = create
((set) => ({
+ data: {
+ header: { columnsCount: 0, items: [] },
+ content: { columnsCount: 0, items: [] },
+ footer: { columnsCount: 0, items: [] },
+ },
+
+ activeSection: "",
+ activeItemIndex: 0,
+
+ setActiveSection: (section: "header" | "content" | "footer") =>
+ set({ activeSection: section, activeItemIndex: 0 }),
+
+ setActiveItemIndex: (index: number) => set({ activeItemIndex: index }),
+
+ setColumnsCount: (
+ sectionKey: keyof PersonalityDataType,
+ columnsCount: number
+ ) =>
+ set((state) => {
+ const currentItems = state.data[sectionKey].items;
+ const newItems = Array.from(
+ { length: columnsCount },
+ (_, index) =>
+ currentItems[index] || {
+ id: uuidv4(),
+ backgroundColor: "#ffffff",
+ texts: [],
+ buttons: [],
+ alignment: "center" as const,
+ verticalAlignment: "middle" as const,
+ }
+ );
+
+ return {
+ data: {
+ ...state.data,
+ [sectionKey]: {
+ columnsCount,
+ items: newItems,
+ },
+ },
+ activeItemIndex: 0,
+ };
+ }),
+
+ setItems: (sectionKey: keyof PersonalityDataType, items: SectionItemType[]) =>
+ set((state) => ({
+ data: {
+ ...state.data,
+ [sectionKey]: {
+ ...state.data[sectionKey],
+ items,
+ },
+ },
+ })),
+
+ addItem: (
+ sectionKey: keyof PersonalityDataType,
+ 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 as keyof PersonalityDataType;
+ const items = state.data[sectionKey].items;
+ const activeIndex = state.activeItemIndex;
+
+ if (activeIndex >= items.length) return state;
+
+ console.log("Updating active item:", {
+ sectionKey,
+ activeIndex,
+ updates,
+ });
+
+ const updatedItems = items.map((item, index) =>
+ index === activeIndex ? { ...item, ...updates } : item
+ );
+
+ return {
+ data: {
+ ...state.data,
+ [sectionKey]: {
+ ...state.data[sectionKey],
+ items: updatedItems,
+ },
+ },
+ };
+ }),
+
+ updateItem: (
+ sectionKey: keyof PersonalityDataType,
+ 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: keyof PersonalityDataType, id: string) =>
+ set((state) => ({
+ data: {
+ ...state.data,
+ [sectionKey]: {
+ ...state.data[sectionKey],
+ items: state.data[sectionKey].items.filter((item) => item.id !== id),
+ },
+ },
+ })),
+
+ addText: (
+ sectionKey: keyof PersonalityDataType,
+ 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 keyof PersonalityDataType;
+ 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: keyof PersonalityDataType,
+ 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 keyof PersonalityDataType;
+ 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: keyof PersonalityDataType,
+ 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: keyof PersonalityDataType,
+ 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
+ ),
+ },
+ },
+ })),
+}));
diff --git a/src/pages/setting/personality/types/Types.ts b/src/pages/setting/personality/types/Types.ts
new file mode 100644
index 0000000..875ee4c
--- /dev/null
+++ b/src/pages/setting/personality/types/Types.ts
@@ -0,0 +1,102 @@
+export type PersonalityDataType = {
+ header: SectionType;
+ content: SectionType;
+ footer: SectionType;
+};
+
+export type SectionType = {
+ columnsCount: number;
+ items: SectionItemType[];
+};
+
+export type SectionItemType = {
+ id: string;
+ backgroundColor: string;
+ backgroundImage?: string;
+ texts: TextType[];
+ buttons: ButtonType[];
+ alignment?: "left" | "center" | "right";
+ verticalAlignment?: "top" | "middle" | "bottom";
+ style?: {
+ borderRadius?: number;
+ padding?: string;
+ fontFamily?: string;
+ };
+};
+
+export type TextType = {
+ id: string;
+ text: string;
+ fontSize?: number;
+ fontFamily?: string;
+ color?: string;
+ alignment?: "left" | "center" | "right";
+ verticalAlignment?: "top" | "middle" | "bottom";
+};
+
+export type ButtonType = {
+ id: string;
+ text: string;
+ link: string;
+ size: "small" | "medium" | "large";
+ isBorder: boolean;
+ borderSize: number;
+ textColor: string;
+ backgroundColor: string;
+ borderColor: string;
+ alignment?: "left" | "center" | "right";
+ verticalAlignment?: "top" | "middle" | "bottom";
+};
+
+export type PersonalityStore = {
+ data: PersonalityDataType;
+ activeSection: "header" | "content" | "footer" | "";
+ activeItemIndex: number;
+
+ setActiveSection: (section: "header" | "content" | "footer") => void;
+ setActiveItemIndex: (index: number) => void;
+
+ setItems: (
+ sectionKey: keyof PersonalityDataType,
+ items: SectionItemType[]
+ ) => void;
+ addItem: (
+ sectionKey: keyof PersonalityDataType,
+ item: Omit
+ ) => void;
+ updateItem: (
+ sectionKey: keyof PersonalityDataType,
+ id: string,
+ updates: Partial
+ ) => void;
+ updateActiveItem: (updates: Partial) => void;
+ removeItem: (sectionKey: keyof PersonalityDataType, id: string) => void;
+ setColumnsCount: (
+ sectionKey: keyof PersonalityDataType,
+ columnsCount: number
+ ) => void;
+ addText: (
+ sectionKey: keyof PersonalityDataType,
+ itemId: string,
+ text: Omit
+ ) => void;
+ addTextToActiveItem: (text: Omit) => void;
+ addButton: (
+ sectionKey: keyof PersonalityDataType,
+ itemId: string,
+ button: Omit
+ ) => void;
+ addButtonToActiveItem: (button: Omit) => void;
+ updateText: (
+ sectionKey: keyof PersonalityDataType,
+ itemId: string,
+ textId: string,
+ updates: Partial
+ ) => void;
+ updateButton: (
+ sectionKey: keyof PersonalityDataType,
+ itemId: string,
+ buttonId: string,
+ updates: Partial
+ ) => void;
+};