diff --git a/.env b/.env index cbb7fa7..3c7d2df 100644 --- a/.env +++ b/.env @@ -1,7 +1,7 @@ VITE_TOKEN_NAME = 'dsc_token' VITE_REFRESH_TOKEN_NAME = 'dsc_refresh_token' VITE_DANAK_BASE_URL ='https://api.danakcorp.com' -# VITE_BASE_URL = 'http://192.168.1.113:4000' +# VITE_BASE_URL = 'http://192.168.1.117:4000' VITE_BASE_URL = 'https://dmail-api.danakcorp.com' VITE_SERVICE_ID = 'e51afdc3-ea0b-49cf-8f49-2a6f131b024e' diff --git a/src/pages/setting/address/components/AddressForm.tsx b/src/pages/setting/address/components/AddressForm.tsx index 62f5817..02b2407 100644 --- a/src/pages/setting/address/components/AddressForm.tsx +++ b/src/pages/setting/address/components/AddressForm.tsx @@ -88,6 +88,7 @@ const AddressForm: FC = ({ selectedAddress, isEditMode, onCanc password: params.password || undefined, quota: params.quotaMB ? params.quotaMB * 1024 * 1024 : undefined, forwarders: forwarders, + templateId: params.templateId, } updateAddress({ id: selectedAddress.id, params: updateParams }, { onSuccess: (data) => { diff --git a/src/pages/setting/address/types/Types.ts b/src/pages/setting/address/types/Types.ts index 8f287a9..6ae8378 100644 --- a/src/pages/setting/address/types/Types.ts +++ b/src/pages/setting/address/types/Types.ts @@ -15,6 +15,7 @@ export type UpdateAddressType = { aliases?: string[]; title?: string; forwarders?: string[]; + templateId?: string; }; export interface AddressData extends Record { diff --git a/src/pages/setting/personality/Personality.tsx b/src/pages/setting/personality/Personality.tsx index 78f2551..c8de904 100644 --- a/src/pages/setting/personality/Personality.tsx +++ b/src/pages/setting/personality/Personality.tsx @@ -2,13 +2,16 @@ import { FC, useEffect } from 'react' import HeaderSection from './components/HeaderSection' import ContentSection from './components/ContentSection' import FooterSection from './components/FooterSection' +import GenericSection from './components/GenericSection' import { useParams } from 'react-router-dom' import { usePersonalityStore } from './store/Store' import { useGetTemplate } from './hooks/usePersonalityData' +import { Add } from 'iconsax-react' +import { toast } from '@/components/Toast' const Personality: FC = () => { const { id } = useParams() - const { setData } = usePersonalityStore() + const { setData, data, addSection } = usePersonalityStore() const { data: template } = useGetTemplate(id || '') useEffect(() => { @@ -17,13 +20,71 @@ const Personality: FC = () => { } }, [id, template, setData]) + const handleAddSection = (afterSectionKey: string) => { + addSection(afterSectionKey) + toast('سکشن جدید با موفقیت اضافه شد', 'success') + } + + const renderSection = (sectionKey: string) => { + if (sectionKey === 'header') { + return + } else if (sectionKey === 'content') { + return + } else if (sectionKey === 'footer') { + return + } + + // For custom sections, use GenericSection with full functionality + return + } + + const renderPlusButton = (afterSectionKey: string) => { + return ( + + +
+ +
+ + + ) + } + return (
- - - + {Object.keys(data).map((sectionKey, index) => { + const sections = Object.keys(data); + const elements = []; + + // Add the section + elements.push(renderSection(sectionKey)); + + // Add plus button after each section except the last one + if (index < sections.length - 1) { + elements.push(renderPlusButton(sectionKey)); + } + + return elements; + }).flat()} + + {/* Plus button at the end */} + {Object.keys(data).length > 0 && renderPlusButton(Object.keys(data)[Object.keys(data).length - 1])}
diff --git a/src/pages/setting/personality/SideBar.tsx b/src/pages/setting/personality/SideBar.tsx index 72ffd67..916832a 100644 --- a/src/pages/setting/personality/SideBar.tsx +++ b/src/pages/setting/personality/SideBar.tsx @@ -9,7 +9,7 @@ import ImageSideBar from './components/ImageSideBar' import SocialSidebar from './components/SocialSidebar' import { clx } from '@/helpers/utils' import { usePersonalityStore } from './store/Store' -import { ElementType, SectionName } from './types/Types' +import { ElementType } from './types/Types' const PersonalitySidebar: FC = () => { @@ -94,7 +94,7 @@ const PersonalitySidebar: FC = () => { className='cursor-pointer' /> { - activeSection !== SectionName.CONTENT && <> + activeSection !== 'content' && <> = ({ buttons, itemId, sectionKey } type: ElementType.BUTTON, elementId: buttonId, itemId, - sectionKey, + sectionKey: sectionKey as SectionName, }) } diff --git a/src/pages/setting/personality/components/ContentSection.tsx b/src/pages/setting/personality/components/ContentSection.tsx index cf713f5..098678e 100644 --- a/src/pages/setting/personality/components/ContentSection.tsx +++ b/src/pages/setting/personality/components/ContentSection.tsx @@ -148,6 +148,14 @@ const ContentSection: FC = () => { onClick={(e) => handleItemClick(index, e)} > {/* محتوای خالی برای columns خالی */} +
+ {/* {'{{content}}'} */} +
) : ( @@ -164,6 +172,14 @@ const ContentSection: FC = () => { padding: '8px' }} > +
+ {'{{content}}'} +
{ itemId={item?.id || ''} sectionKey="content" /> + {(!item?.texts || item.texts.length === 0) && + (!item?.images || item.images.length === 0) && + (!item?.socials || item.socials.length === 0) && ( +
+ {'{{content}}'} +
+ )} {/* ردیف دکمه‌ها */} diff --git a/src/pages/setting/personality/components/GenericSection.tsx b/src/pages/setting/personality/components/GenericSection.tsx new file mode 100644 index 0000000..56d33c8 --- /dev/null +++ b/src/pages/setting/personality/components/GenericSection.tsx @@ -0,0 +1,271 @@ +import { FC } from 'react' +import { usePersonalityStore } from '../store/Store' +import { AddCircle } from 'iconsax-react' +import TextRenderer from './TextRenderer' +import ButtonRenderer from './ButtonRenderer' +import ImageRenderer from './ImageRenderer' +import SocialRenderer from './SocialRenderer' +import { VerticalAlignment, HorizontalAlignment } from '../types/Types' + +interface GenericSectionProps { + sectionKey: string +} + +const GenericSection: FC = ({ sectionKey }) => { + + const { activeSection, activeItemIndex, data, setActiveSection, setActiveItemIndex } = usePersonalityStore() + + // Early return if data is not available + if (!data || !data[sectionKey]) { + return ( + + +
در حال بارگذاری...
+ + + ) + } + + const sectionData = data[sectionKey] + + const handleSectionClick = (section: string, e: React.MouseEvent) => { + + // اگر کلیک روی فضای خالی باشد (نه روی content elements) + const target = e.target as HTMLElement; + const isClickOnContent = target.closest('[data-element-type]') !== null; + + if (!isClickOnContent) { + setActiveSection(section) + } + } + + const handleItemClick = (index: number, e: React.MouseEvent) => { + + // Check if click is on a content element (text, button, image, social) + const target = e.target as HTMLElement; + const isClickOnContent = target.closest('[data-element-type]') !== null; + + + // Only select column if not clicking on content elements + if (!isClickOnContent) { + + e.stopPropagation() + + // Only set active section if we're not already in this section + if (activeSection !== sectionKey) { + + setActiveSection(sectionKey) + } + + // Always set the active item index + setActiveItemIndex(index) + } + } + + // تابع‌های helper برای تعیین alignment دکمه‌ها + const getButtonHorizontalAlign = (button?: { alignment?: HorizontalAlignment }) => { + if (!button || !button.alignment) return 'center' + switch (button.alignment) { + case HorizontalAlignment.LEFT: + return 'left' + case HorizontalAlignment.RIGHT: + return 'right' + case HorizontalAlignment.CENTER: + default: + return 'center' + } + } + + const getButtonVerticalAlign = (button?: { verticalAlignment?: VerticalAlignment }) => { + if (!button || !button.verticalAlignment) return 'middle' + switch (button.verticalAlignment) { + case VerticalAlignment.TOP: + return 'top' + case VerticalAlignment.BOTTOM: + return 'bottom' + case VerticalAlignment.MIDDLE: + default: + return 'middle' + } + } + + return ( + handleSectionClick(sectionKey, e)}> + { + sectionData.columnsCount > 0 ? + + + + + { + Array.from({ length: sectionData.columnsCount }, (_, index) => { + const item = sectionData.items[index]; + const isActive = activeSection === sectionKey && activeItemIndex === index; + + return ( + <> + + {index < sectionData.columnsCount - 1 && ( + + )} + + ) + }) + } + + +
handleItemClick(index, e)} + style={{ + width: `${100 / sectionData.columnsCount}%`, + height: '123px', + border: isActive ? '1px dashed #0038FF' : '1px dashed #EAECF4', + backgroundColor: item?.backgroundColor || '#ffffff', + backgroundImage: item?.backgroundImage ? `url(${item.backgroundImage})` : 'none', + backgroundSize: item?.style?.backgroundSize || 'cover', + backgroundRepeat: item?.style?.backgroundRepeat || 'no-repeat', + backgroundPosition: item?.style?.backgroundPosition || 'center', + cursor: 'pointer', + // padding: '8px', + verticalAlign: 'top', + borderRadius: '8px', + position: 'relative' + }} + > + + + {/* اگر column خالی است */} + {(!item?.texts || item.texts.length === 0) && + (!item?.buttons || item.buttons.length === 0) && + (!item?.images || item.images.length === 0) && + (!item?.socials || item.socials.length === 0) ? ( + + + + ) : ( + <> + {/* اگر فقط دکمه داریم و متن نداریم */} + {(!item?.texts || item.texts.length === 0) && item?.buttons && item.buttons.length > 0 ? ( + + + + ) : ( + <> + {/* ردیف اصلی برای متن */} + + + + {/* ردیف دکمه‌ها */} + {item?.buttons && item.buttons.length > 0 && ( + + + + )} + + )} + + )} + +
handleItemClick(index, e)} + > + {/* محتوای خالی برای columns خالی */} +
+ +
0 ? "60" : "87"} + align={item?.texts?.[0]?.alignment || 'center'} + valign={item?.texts?.[0]?.verticalAlignment === VerticalAlignment.TOP ? 'top' : + item?.texts?.[0]?.verticalAlignment === VerticalAlignment.BOTTOM ? 'bottom' : 'middle'} + style={{ + padding: '8px', + fontSize: '14px', + lineHeight: '1.4' + }} + > + + + +
+ +
+
+ + : + handleSectionClick(sectionKey, e)} + style={{ + height: '123px', + border: activeSection === sectionKey ? '1px dashed #0038FF' : '1px dashed #E5E7EB', + borderRadius: '24px', + textAlign: 'center', + verticalAlign: 'middle', + padding: '10px', + cursor: 'pointer' + }} + > +
+ {data[sectionKey]?.name || sectionKey} +
+
+ +
+ + } + + ) +} + +export default GenericSection \ No newline at end of file diff --git a/src/pages/setting/personality/components/ImageRenderer.tsx b/src/pages/setting/personality/components/ImageRenderer.tsx index 9308508..1d165a9 100644 --- a/src/pages/setting/personality/components/ImageRenderer.tsx +++ b/src/pages/setting/personality/components/ImageRenderer.tsx @@ -1,5 +1,5 @@ import { FC } from 'react' -import { ImageType, ImageSize, HorizontalAlignment, VerticalAlignment, ElementType, PersonalityDataType } from '../types/Types' +import { ImageType, ImageSize, HorizontalAlignment, VerticalAlignment, ElementType, PersonalityDataType, SectionName } from '../types/Types' import { usePersonalityStore } from '../store/Store' interface ImageRendererProps { @@ -21,7 +21,7 @@ const ImageRenderer: FC = ({ images, itemId, sectionKey }) = type: ElementType.IMAGE, elementId: imageId, itemId, - sectionKey, + sectionKey: sectionKey as SectionName, }) } diff --git a/src/pages/setting/personality/components/SettingSideBar.tsx b/src/pages/setting/personality/components/SettingSideBar.tsx index 7fcbd07..a301919 100644 --- a/src/pages/setting/personality/components/SettingSideBar.tsx +++ b/src/pages/setting/personality/components/SettingSideBar.tsx @@ -3,14 +3,16 @@ import { useTranslation } from 'react-i18next' import UploadBoxDraggble from '@/components/UploadBoxDraggble'; import ColorPicker from '@/components/ColorPicker'; import { usePersonalityStore } from '../store/Store'; -import { SectionItemType, BackgroundSize, BackgroundPosition, SectionName } from '../types/Types'; +import { SectionItemType, BackgroundSize, BackgroundPosition } from '../types/Types'; import Select from '@/components/Select'; import { useSingleUpload } from '../hooks/usePersonalityData'; import { toast } from '@/components/Toast'; +import Button from '@/components/Button'; +import { Trash } from 'iconsax-react'; const SettingSideBar: FC = () => { const { t } = useTranslation() - const { activeSection, setColumnsCount, updateActiveItem, data, activeItemIndex } = usePersonalityStore() + const { activeSection, setColumnsCount, updateActiveItem, data, activeItemIndex, removeSection } = usePersonalityStore() const [color, setColor] = useState("#aabbcc"); const [backgroundSize, setBackgroundSize] = useState(BackgroundSize.COVER) const [backgroundPosition, setBackgroundPosition] = useState(BackgroundPosition.CENTER) @@ -54,11 +56,22 @@ const SettingSideBar: FC = () => { const handleColumnClick = (columns: number) => { if (activeSection) { - if (activeSection === SectionName.CONTENT && columns > 1) { + if (data[activeSection]?.isContent && columns > 1) { toast('این بخش فقط می تواند یک ستون داشته باشد', 'error') return } - setColumnsCount(activeSection as SectionName, columns); + setColumnsCount(activeSection, columns); + } + } + + + + const handleRemoveSection = () => { + if (activeSection && !data[activeSection]?.isContent) { + removeSection(activeSection) + toast('سکشن با موفقیت حذف شد', 'success') + } else { + toast('نمی‌توانید سکشن محتوا را حذف کنید', 'error') } } @@ -167,6 +180,20 @@ const SettingSideBar: FC = () => {
{t('setting.setting')}
+ {/* Section Delete */} + {activeSection && !data[activeSection]?.isContent && ( +
+ +
+ )} +
= ({ socials, itemId, sectionKey } type: ElementType.SOCIAL, elementId: socialId, itemId, - sectionKey, + sectionKey: sectionKey as SectionName, }) } diff --git a/src/pages/setting/personality/components/TextRenderer.tsx b/src/pages/setting/personality/components/TextRenderer.tsx index f977e16..a09bd65 100644 --- a/src/pages/setting/personality/components/TextRenderer.tsx +++ b/src/pages/setting/personality/components/TextRenderer.tsx @@ -1,5 +1,5 @@ import { FC } from 'react' -import { TextType, ElementType, PersonalityDataType } from '../types/Types' +import { TextType, ElementType, PersonalityDataType, SectionName } from '../types/Types' import { usePersonalityStore } from '../store/Store' interface TextRendererProps { @@ -20,7 +20,7 @@ const TextRenderer: FC = ({ texts, itemId, sectionKey }) => { type: ElementType.TEXT, elementId: textId, itemId, - sectionKey, + sectionKey: sectionKey as SectionName, }) } diff --git a/src/pages/setting/personality/store/Store.ts b/src/pages/setting/personality/store/Store.ts index 9a13f8c..254e498 100644 --- a/src/pages/setting/personality/store/Store.ts +++ b/src/pages/setting/personality/store/Store.ts @@ -8,7 +8,6 @@ import { ButtonType, ImageType, SocialType, - SectionName, HorizontalAlignment, VerticalAlignment, SelectedElement, @@ -16,9 +15,9 @@ import { export const usePersonalityStore = create((set) => ({ data: { - header: { columnsCount: 1, items: [] }, - content: { columnsCount: 1, items: [] }, - footer: { columnsCount: 1, items: [] }, + header: { name: "هدر", columnsCount: 1, items: [] }, + content: { name: "محتوا", columnsCount: 1, items: [], isContent: true }, + footer: { name: "فوتر", columnsCount: 1, items: [] }, }, activeSection: "", @@ -27,13 +26,35 @@ export const usePersonalityStore = create((set) => ({ isEditMode: false, setData: (data: PersonalityDataType) => - set(() => ({ - data, - })), + set(() => { + // Normalize data to ensure all sections have names + const normalizedData: PersonalityDataType = {}; - setActiveSection: (section: SectionName) => + 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 as keyof PersonalityDataType]; + const sectionData = state.data[section]; + + if (!sectionData) { + return state; + } // اگر بخش آیتم ندارد و تعداد ستون‌ها بیشتر از صفر است، یک آیتم پیش‌فرض بساز if (sectionData.items.length === 0 && sectionData.columnsCount > 0) { @@ -85,10 +106,90 @@ export const usePersonalityStore = create((set) => ({ setEditMode: (isEdit: boolean) => set({ isEditMode: isEdit }), - setColumnsCount: ( - sectionKey: keyof PersonalityDataType, - columnsCount: number - ) => + 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 + } + + // Create new section data + const newSection = { + name: sectionName, + columnsCount: 1, + items: [], + }; + + // If afterSectionKey is provided, insert after that section + if (afterSectionKey) { + const keys = Object.keys(state.data); + const afterIndex = keys.indexOf(afterSectionKey); + + 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]; @@ -124,6 +225,7 @@ export const usePersonalityStore = create((set) => ({ data: { ...state.data, [sectionKey]: { + ...state.data[sectionKey], columnsCount, items: newItems, }, @@ -132,7 +234,7 @@ export const usePersonalityStore = create((set) => ({ }; }), - setItems: (sectionKey: keyof PersonalityDataType, items: SectionItemType[]) => + setItems: (sectionKey: string, items: SectionItemType[]) => set((state) => ({ data: { ...state.data, @@ -143,10 +245,7 @@ export const usePersonalityStore = create((set) => ({ }, })), - addItem: ( - sectionKey: keyof PersonalityDataType, - item: Omit - ) => + addItem: (sectionKey: string, item: Omit) => set((state) => ({ data: { ...state.data, @@ -161,7 +260,7 @@ export const usePersonalityStore = create((set) => ({ set((state) => { if (!state.activeSection) return state; - const sectionKey = state.activeSection as keyof PersonalityDataType; + const sectionKey = state.activeSection; const items = state.data[sectionKey].items; const activeIndex = state.activeItemIndex; @@ -209,7 +308,7 @@ export const usePersonalityStore = create((set) => ({ }), updateItem: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, id: string, updates: Partial ) => @@ -225,7 +324,7 @@ export const usePersonalityStore = create((set) => ({ }, })), - removeItem: (sectionKey: keyof PersonalityDataType, id: string) => + removeItem: (sectionKey: string, id: string) => set((state) => ({ data: { ...state.data, @@ -236,11 +335,7 @@ export const usePersonalityStore = create((set) => ({ }, })), - addText: ( - sectionKey: keyof PersonalityDataType, - itemId: string, - text: Omit - ) => + addText: (sectionKey: string, itemId: string, text: Omit) => set((state) => ({ data: { ...state.data, @@ -262,7 +357,7 @@ export const usePersonalityStore = create((set) => ({ set((state) => { if (!state.activeSection) return state; - const sectionKey = state.activeSection as keyof PersonalityDataType; + const sectionKey = state.activeSection as string; const items = state.data[sectionKey].items; const activeIndex = state.activeItemIndex; @@ -289,7 +384,7 @@ export const usePersonalityStore = create((set) => ({ }), addButton: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, itemId: string, button: Omit ) => @@ -317,7 +412,7 @@ export const usePersonalityStore = create((set) => ({ set((state) => { if (!state.activeSection) return state; - const sectionKey = state.activeSection as keyof PersonalityDataType; + const sectionKey = state.activeSection as string; const items = state.data[sectionKey].items; const activeIndex = state.activeItemIndex; @@ -344,7 +439,7 @@ export const usePersonalityStore = create((set) => ({ }), updateText: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, itemId: string, textId: string, updates: Partial @@ -369,7 +464,7 @@ export const usePersonalityStore = create((set) => ({ })), updateButton: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, itemId: string, buttonId: string, updates: Partial @@ -394,7 +489,7 @@ export const usePersonalityStore = create((set) => ({ })), addImage: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, itemId: string, image: Omit ) => @@ -419,7 +514,7 @@ export const usePersonalityStore = create((set) => ({ set((state) => { if (!state.activeSection) return state; - const sectionKey = state.activeSection as keyof PersonalityDataType; + const sectionKey = state.activeSection as string; const items = state.data[sectionKey].items; const activeIndex = state.activeItemIndex; @@ -446,7 +541,7 @@ export const usePersonalityStore = create((set) => ({ }), updateImage: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, itemId: string, imageId: string, updates: Partial @@ -470,11 +565,7 @@ export const usePersonalityStore = create((set) => ({ }, })), - deleteText: ( - sectionKey: keyof PersonalityDataType, - itemId: string, - textId: string - ) => + deleteText: (sectionKey: string, itemId: string, textId: string) => set((state) => ({ data: { ...state.data, @@ -496,11 +587,7 @@ export const usePersonalityStore = create((set) => ({ isEditMode: false, })), - deleteButton: ( - sectionKey: keyof PersonalityDataType, - itemId: string, - buttonId: string - ) => + deleteButton: (sectionKey: string, itemId: string, buttonId: string) => set((state) => ({ data: { ...state.data, @@ -522,11 +609,7 @@ export const usePersonalityStore = create((set) => ({ isEditMode: false, })), - deleteImage: ( - sectionKey: keyof PersonalityDataType, - itemId: string, - imageId: string - ) => + deleteImage: (sectionKey: string, itemId: string, imageId: string) => set((state) => ({ data: { ...state.data, @@ -549,7 +632,7 @@ export const usePersonalityStore = create((set) => ({ })), addSocial: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, itemId: string, social: Omit ) => @@ -577,7 +660,7 @@ export const usePersonalityStore = create((set) => ({ set((state) => { if (!state.activeSection) return state; - const sectionKey = state.activeSection as keyof PersonalityDataType; + const sectionKey = state.activeSection as string; const items = state.data[sectionKey].items; const activeIndex = state.activeItemIndex; @@ -604,7 +687,7 @@ export const usePersonalityStore = create((set) => ({ }), updateSocial: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, itemId: string, socialId: string, updates: Partial @@ -628,11 +711,7 @@ export const usePersonalityStore = create((set) => ({ }, })), - deleteSocial: ( - sectionKey: keyof PersonalityDataType, - itemId: string, - socialId: string - ) => + deleteSocial: (sectionKey: string, itemId: string, socialId: string) => set((state) => ({ data: { ...state.data, diff --git a/src/pages/setting/personality/types/Types.ts b/src/pages/setting/personality/types/Types.ts index ff5e9c2..51bedde 100644 --- a/src/pages/setting/personality/types/Types.ts +++ b/src/pages/setting/personality/types/Types.ts @@ -92,13 +92,11 @@ export type SelectedElement = { type: ElementType; elementId: string; itemId: string; - sectionKey: keyof PersonalityDataType; + sectionKey: string; } | null; export type PersonalityDataType = { - header: SectionType; - content: SectionType; - footer: SectionType; + [key: string]: SectionType & { name: string; isContent?: boolean }; }; export type SectionType = { @@ -175,106 +173,85 @@ export type SocialType = { export type PersonalityStore = { data: PersonalityDataType; - activeSection: SectionName | ""; + activeSection: string; activeItemIndex: number; selectedElement: SelectedElement; // New field for element selection isEditMode: boolean; // New field for edit mode setData: (data: PersonalityDataType) => void; - setActiveSection: (section: SectionName) => void; + setActiveSection: (section: string) => void; setActiveItemIndex: (index: number) => void; setSelectedElement: (element: SelectedElement) => void; // New method setEditMode: (isEdit: boolean) => void; // New method - setItems: ( - sectionKey: keyof PersonalityDataType, - items: SectionItemType[] - ) => void; - addItem: ( - sectionKey: keyof PersonalityDataType, - item: Omit - ) => void; + // Section management methods + addSection: (afterSectionKey?: string) => void; + removeSection: (sectionKey: string) => void; + + setItems: (sectionKey: string, items: SectionItemType[]) => void; + addItem: (sectionKey: string, item: Omit) => void; updateItem: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, id: string, updates: Partial ) => void; updateActiveItem: (updates: Partial) => void; - removeItem: (sectionKey: keyof PersonalityDataType, id: string) => void; - setColumnsCount: ( - sectionKey: keyof PersonalityDataType, - columnsCount: number - ) => void; + removeItem: (sectionKey: string, id: string) => void; + setColumnsCount: (sectionKey: string, columnsCount: number) => void; addText: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, itemId: string, text: Omit ) => void; addTextToActiveItem: (text: Omit) => void; addButton: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, itemId: string, button: Omit ) => void; addButtonToActiveItem: (button: Omit) => void; updateText: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, itemId: string, textId: string, updates: Partial ) => void; updateButton: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, itemId: string, buttonId: string, updates: Partial ) => void; addImage: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, itemId: string, image: Omit ) => void; addImageToActiveItem: (image: Omit) => void; updateImage: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, itemId: string, imageId: string, updates: Partial ) => void; // Social network methods addSocial: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, itemId: string, social: Omit ) => void; addSocialToActiveItem: (social: Omit) => void; updateSocial: ( - sectionKey: keyof PersonalityDataType, + sectionKey: string, itemId: string, socialId: string, updates: Partial ) => void; - deleteSocial: ( - sectionKey: keyof PersonalityDataType, - itemId: string, - socialId: string - ) => void; + deleteSocial: (sectionKey: string, itemId: string, socialId: string) => void; // New methods for deleting elements - deleteText: ( - sectionKey: keyof PersonalityDataType, - itemId: string, - textId: string - ) => void; - deleteButton: ( - sectionKey: keyof PersonalityDataType, - itemId: string, - buttonId: string - ) => void; - deleteImage: ( - sectionKey: keyof PersonalityDataType, - itemId: string, - imageId: string - ) => void; + deleteText: (sectionKey: string, itemId: string, textId: string) => void; + deleteButton: (sectionKey: string, itemId: string, buttonId: string) => void; + deleteImage: (sectionKey: string, itemId: string, imageId: string) => void; }; export type TemplateType = { diff --git a/src/pages/setting/personality/utils/ExportHTML.ts b/src/pages/setting/personality/utils/ExportHTML.ts index 109e913..bbacd36 100644 --- a/src/pages/setting/personality/utils/ExportHTML.ts +++ b/src/pages/setting/personality/utils/ExportHTML.ts @@ -505,14 +505,22 @@ export const exportPersonalityToHTML = async ( } else { // اگر هیچ محتوایی نداریم و content section است console.log( - "🔥 [ExportHTML] Empty content section detected, adding {{content}} placeholder" + "🔥 [ExportHTML] Empty content section detected, sectionHeight:", + sectionHeight ); if (sectionHeight === "246px") { + console.log( + "🔥 [ExportHTML] Adding {{content}} placeholder to empty content" + ); result += `
{{content}}
`; + } else { + console.log( + "🔥 [ExportHTML] Not content section, skipping {{content}}" + ); } } @@ -567,18 +575,92 @@ export const exportPersonalityToHTML = async ( } }; + // Helper function to determine section height + const getSectionHeight = ( + sectionKey: string, + sectionData: PersonalityDataType[string] + ) => { + console.log(`🔥 [ExportHTML] Getting height for section: ${sectionKey}`, { + isContent: sectionData?.isContent, + }); + if (sectionKey === "content" || sectionData?.isContent) { + return "246px"; + } + // header, footer و سکشن‌های جدید همه 123px ارتفاع دارند + return "123px"; + }; + // Generate complete HTML exactly like Personality.tsx structure + console.log("🔥 [ExportHTML] Available sections:", Object.keys(data)); + console.log( + "🔥 [ExportHTML] Full data structure:", + JSON.stringify(data, null, 2) + ); + + // Render all sections in the same order as they appear in the object + const sectionsHtml = Object.keys(data) + .map((sectionKey) => { + const sectionData = data[sectionKey]; + const height = getSectionHeight(sectionKey, sectionData); + + console.log(`🔥 [ExportHTML] Processing section: ${sectionKey}`, { + name: sectionData.name, + columnsCount: sectionData.columnsCount, + itemsLength: sectionData.items?.length || 0, + height: height, + isContent: sectionData.isContent, + }); + + // Pass only the section structure (without name and isContent) + const sectionStructure = { + columnsCount: sectionData.columnsCount, + items: sectionData.items || [], + }; + + const renderedSection = renderSection(sectionStructure, height, ""); + console.log( + `🔥 [ExportHTML] Section ${sectionKey} rendered, HTML length:`, + renderedSection.length + ); + + return renderedSection; + }) + .join(""); + + console.log( + "🔥 [ExportHTML] Total sections rendered:", + Object.keys(data).length + ); + console.log( + "🔥 [ExportHTML] Combined sections HTML length:", + sectionsHtml.length + ); + const html = `
- ${renderSection(data.header, "123px")} - ${renderSection(data.content, "246px", "")} - ${renderSection(data.footer, "123px", "")} + ${sectionsHtml}
`; - console.log("🔥 [ExportHTML] Final HTML generated:", html); + console.log("🔥 [ExportHTML] Final HTML generated (length):", html.length); + console.log( + "🔥 [ExportHTML] HTML contains {{content}}:", + html.includes("{{content}}") + ); + + // نمایش قسمت‌هایی از HTML که شامل content است + const contentMatch = html.match(/]*>{{content}}<\/div>/g); + if (contentMatch) { + console.log( + "🔥 [ExportHTML] Found {{content}} placeholders:", + contentMatch + ); + } else { + console.log("🔥 [ExportHTML] NO {{content}} placeholders found in HTML!"); + } + return html; };