Remove some comments
This commit is contained in:
@@ -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'
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ const AddressForm: FC<AddressFormProps> = ({ 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) => {
|
||||
|
||||
@@ -15,6 +15,7 @@ export type UpdateAddressType = {
|
||||
aliases?: string[];
|
||||
title?: string;
|
||||
forwarders?: string[];
|
||||
templateId?: string;
|
||||
};
|
||||
|
||||
export interface AddressData extends Record<string, unknown> {
|
||||
|
||||
@@ -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 <HeaderSection key={sectionKey} />
|
||||
} else if (sectionKey === 'content') {
|
||||
return <ContentSection key={sectionKey} />
|
||||
} else if (sectionKey === 'footer') {
|
||||
return <FooterSection key={sectionKey} />
|
||||
}
|
||||
|
||||
// For custom sections, use GenericSection with full functionality
|
||||
return <GenericSection key={sectionKey} sectionKey={sectionKey} />
|
||||
}
|
||||
|
||||
const renderPlusButton = (afterSectionKey: string) => {
|
||||
return (
|
||||
<tr key={`plus-${afterSectionKey}`} style={{ position: 'relative', height: '0px' }}>
|
||||
<td style={{ position: 'relative', height: '0px' }}>
|
||||
<div
|
||||
className="absolute left-1/2 transform -translate-x-1/2 -translate-y-1/2"
|
||||
style={{ top: '0px', zIndex: 9999 }}
|
||||
>
|
||||
<button
|
||||
onClick={() => handleAddSection(afterSectionKey)}
|
||||
className="group flex items-center justify-center w-10 h-10 rounded-full border-2 border-dashed border-gray-300 hover:border-blue-500 hover:bg-blue-50 bg-white transition-all duration-200 shadow-sm hover:shadow-md"
|
||||
title="اضافه کردن سکشن جدید"
|
||||
style={{ position: 'relative', zIndex: 9999 }}
|
||||
>
|
||||
<Add
|
||||
size={20}
|
||||
color='gray'
|
||||
className="text-gray-400 group-hover:text-blue-500 transition-colors"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='flex-1 bg-white rounded-4xl p-8 personality-template'>
|
||||
<table width="100%" cellPadding="0" cellSpacing="0" border={0} style={{ borderCollapse: 'collapse' }}>
|
||||
<tbody>
|
||||
<HeaderSection />
|
||||
<ContentSection />
|
||||
<FooterSection />
|
||||
{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])}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -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' && <>
|
||||
<Text
|
||||
size={22}
|
||||
color={'black'}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { FC } from 'react'
|
||||
import { ButtonType, ButtonSize, HorizontalAlignment, VerticalAlignment, ElementType, PersonalityDataType } from '../types/Types'
|
||||
import { ButtonType, ButtonSize, HorizontalAlignment, VerticalAlignment, ElementType, PersonalityDataType, SectionName } from '../types/Types'
|
||||
import { usePersonalityStore } from '../store/Store'
|
||||
|
||||
interface ButtonRendererProps {
|
||||
@@ -22,7 +22,7 @@ const ButtonRenderer: FC<ButtonRendererProps> = ({ buttons, itemId, sectionKey }
|
||||
type: ElementType.BUTTON,
|
||||
elementId: buttonId,
|
||||
itemId,
|
||||
sectionKey,
|
||||
sectionKey: sectionKey as SectionName,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -148,6 +148,14 @@ const ContentSection: FC = () => {
|
||||
onClick={(e) => handleItemClick(index, e)}
|
||||
>
|
||||
{/* محتوای خالی برای columns خالی */}
|
||||
<div style={{
|
||||
margin: 0,
|
||||
textAlign: 'right',
|
||||
color: '#888',
|
||||
fontSize: '14px'
|
||||
}}>
|
||||
{/* {'{{content}}'} */}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
@@ -164,6 +172,14 @@ const ContentSection: FC = () => {
|
||||
padding: '8px'
|
||||
}}
|
||||
>
|
||||
<div style={{
|
||||
margin: '0 0 10px 0',
|
||||
textAlign: 'right',
|
||||
color: '#888',
|
||||
fontSize: '14px'
|
||||
}}>
|
||||
{'{{content}}'}
|
||||
</div>
|
||||
<ButtonRenderer
|
||||
buttons={item.buttons}
|
||||
itemId={item?.id || ''}
|
||||
@@ -202,6 +218,18 @@ const ContentSection: FC = () => {
|
||||
itemId={item?.id || ''}
|
||||
sectionKey="content"
|
||||
/>
|
||||
{(!item?.texts || item.texts.length === 0) &&
|
||||
(!item?.images || item.images.length === 0) &&
|
||||
(!item?.socials || item.socials.length === 0) && (
|
||||
<div style={{
|
||||
margin: 0,
|
||||
textAlign: 'right',
|
||||
color: '#888',
|
||||
fontSize: '14px'
|
||||
}}>
|
||||
{'{{content}}'}
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
{/* ردیف دکمهها */}
|
||||
|
||||
@@ -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<GenericSectionProps> = ({ sectionKey }) => {
|
||||
|
||||
const { activeSection, activeItemIndex, data, setActiveSection, setActiveItemIndex } = usePersonalityStore()
|
||||
|
||||
// Early return if data is not available
|
||||
if (!data || !data[sectionKey]) {
|
||||
return (
|
||||
<tr>
|
||||
<td style={{ height: '123px', textAlign: 'center', verticalAlign: 'middle' }}>
|
||||
<div>در حال بارگذاری...</div>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
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 (
|
||||
<tr onClick={(e) => handleSectionClick(sectionKey, e)}>
|
||||
{
|
||||
sectionData.columnsCount > 0 ?
|
||||
<td style={{
|
||||
padding: '10px',
|
||||
border: activeSection === sectionKey ? '1px dashed #0038FF' : '1px dashed #E5E7EB',
|
||||
borderRadius: '24px',
|
||||
cursor: 'pointer'
|
||||
}}>
|
||||
<table width="100%" cellPadding="0" cellSpacing="0" border={0} style={{ tableLayout: 'fixed' }}>
|
||||
<tbody>
|
||||
<tr>
|
||||
{
|
||||
Array.from({ length: sectionData.columnsCount }, (_, index) => {
|
||||
const item = sectionData.items[index];
|
||||
const isActive = activeSection === sectionKey && activeItemIndex === index;
|
||||
|
||||
return (
|
||||
<>
|
||||
<td
|
||||
key={index}
|
||||
onClick={(e) => 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'
|
||||
}}
|
||||
>
|
||||
<table width="100%" cellPadding="0" cellSpacing="0" border={0} style={{
|
||||
borderCollapse: 'collapse',
|
||||
height: '123px'
|
||||
}}>
|
||||
<tbody>
|
||||
{/* اگر 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) ? (
|
||||
<tr>
|
||||
<td
|
||||
width="100%"
|
||||
height="123"
|
||||
style={{
|
||||
padding: '8px',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
onClick={(e) => handleItemClick(index, e)}
|
||||
>
|
||||
{/* محتوای خالی برای columns خالی */}
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
<>
|
||||
{/* اگر فقط دکمه داریم و متن نداریم */}
|
||||
{(!item?.texts || item.texts.length === 0) && item?.buttons && item.buttons.length > 0 ? (
|
||||
<tr>
|
||||
<td
|
||||
width="100%"
|
||||
height="123"
|
||||
align={getButtonHorizontalAlign(item.buttons[0])}
|
||||
valign={getButtonVerticalAlign(item.buttons[0])}
|
||||
style={{
|
||||
padding: '8px'
|
||||
}}
|
||||
>
|
||||
<ButtonRenderer
|
||||
buttons={item.buttons}
|
||||
itemId={item?.id || ''}
|
||||
sectionKey={sectionKey}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
<>
|
||||
{/* ردیف اصلی برای متن */}
|
||||
<tr>
|
||||
<td
|
||||
width="100%"
|
||||
height={item?.buttons && item.buttons.length > 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'
|
||||
}}
|
||||
>
|
||||
<TextRenderer
|
||||
texts={item?.texts || []}
|
||||
itemId={item?.id || ''}
|
||||
sectionKey={sectionKey}
|
||||
/>
|
||||
<ImageRenderer
|
||||
images={item?.images || []}
|
||||
itemId={item?.id || ''}
|
||||
sectionKey={sectionKey}
|
||||
/>
|
||||
<SocialRenderer
|
||||
socials={item?.socials || []}
|
||||
itemId={item?.id || ''}
|
||||
sectionKey={sectionKey}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
{/* ردیف دکمهها */}
|
||||
{item?.buttons && item.buttons.length > 0 && (
|
||||
<tr>
|
||||
<td
|
||||
width="100%"
|
||||
height="27"
|
||||
align={getButtonHorizontalAlign(item.buttons[0])}
|
||||
valign={getButtonVerticalAlign(item.buttons[0])}
|
||||
style={{
|
||||
padding: '0 8px 8px 8px'
|
||||
}}
|
||||
>
|
||||
<ButtonRenderer
|
||||
buttons={item.buttons}
|
||||
itemId={item?.id || ''}
|
||||
sectionKey={sectionKey}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
{index < sectionData.columnsCount - 1 && (
|
||||
<td style={{ width: '16px' }}></td>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
})
|
||||
}
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
:
|
||||
<td
|
||||
onClick={(e) => 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'
|
||||
}}
|
||||
>
|
||||
<div style={{ color: '#888', fontSize: '14px', marginBottom: '8px' }}>
|
||||
{data[sectionKey]?.name || sectionKey}
|
||||
</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||
<AddCircle size={24} color='#888' />
|
||||
</div>
|
||||
</td>
|
||||
}
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
export default GenericSection
|
||||
@@ -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<ImageRendererProps> = ({ images, itemId, sectionKey }) =
|
||||
type: ElementType.IMAGE,
|
||||
elementId: imageId,
|
||||
itemId,
|
||||
sectionKey,
|
||||
sectionKey: sectionKey as SectionName,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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>(BackgroundSize.COVER)
|
||||
const [backgroundPosition, setBackgroundPosition] = useState<BackgroundPosition>(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 = () => {
|
||||
<div>
|
||||
<div className='text-lg'>{t('setting.setting')}</div>
|
||||
|
||||
{/* Section Delete */}
|
||||
{activeSection && !data[activeSection]?.isContent && (
|
||||
<div className='mt-6 border-b border-gray-200 pb-6'>
|
||||
<Button
|
||||
onClick={handleRemoveSection}
|
||||
variant='secondary'
|
||||
className='w-full flex items-center justify-center gap-2 !text-red-600 !border-red-600 hover:!bg-red-50'
|
||||
>
|
||||
<Trash size={16} />
|
||||
حذف سکشن فعلی
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className='flex h-[51px] gap-5 mt-6'>
|
||||
<div
|
||||
className={`w-[102px] h-full bg-[#EAECF4] transition-colors ${isUploading ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer hover:bg-[#d1d5db]'}`}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { FC } from 'react'
|
||||
import { SocialType, SocialNetworkType, SocialIconSize, SocialIconStyle, ElementType, PersonalityDataType, HorizontalAlignment, VerticalAlignment } from '../types/Types'
|
||||
import { SocialType, SocialNetworkType, SocialIconSize, SocialIconStyle, ElementType, PersonalityDataType, HorizontalAlignment, VerticalAlignment, SectionName } from '../types/Types'
|
||||
import { usePersonalityStore } from '../store/Store'
|
||||
import { getSocialIconPath, hasPngIcon, getSocialColor as getSocialColorFromUtils, getSocialSvgIcon } from '../utils/socialIcons'
|
||||
|
||||
@@ -22,7 +22,7 @@ const SocialRenderer: FC<SocialRendererProps> = ({ socials, itemId, sectionKey }
|
||||
type: ElementType.SOCIAL,
|
||||
elementId: socialId,
|
||||
itemId,
|
||||
sectionKey,
|
||||
sectionKey: sectionKey as SectionName,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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<TextRendererProps> = ({ texts, itemId, sectionKey }) => {
|
||||
type: ElementType.TEXT,
|
||||
elementId: textId,
|
||||
itemId,
|
||||
sectionKey,
|
||||
sectionKey: sectionKey as SectionName,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
ButtonType,
|
||||
ImageType,
|
||||
SocialType,
|
||||
SectionName,
|
||||
HorizontalAlignment,
|
||||
VerticalAlignment,
|
||||
SelectedElement,
|
||||
@@ -16,9 +15,9 @@ import {
|
||||
|
||||
export const usePersonalityStore = create<PersonalityStore>((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<PersonalityStore>((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<PersonalityStore>((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<PersonalityStore>((set) => ({
|
||||
data: {
|
||||
...state.data,
|
||||
[sectionKey]: {
|
||||
...state.data[sectionKey],
|
||||
columnsCount,
|
||||
items: newItems,
|
||||
},
|
||||
@@ -132,7 +234,7 @@ export const usePersonalityStore = create<PersonalityStore>((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<PersonalityStore>((set) => ({
|
||||
},
|
||||
})),
|
||||
|
||||
addItem: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
item: Omit<SectionItemType, "id">
|
||||
) =>
|
||||
addItem: (sectionKey: string, item: Omit<SectionItemType, "id">) =>
|
||||
set((state) => ({
|
||||
data: {
|
||||
...state.data,
|
||||
@@ -161,7 +260,7 @@ export const usePersonalityStore = create<PersonalityStore>((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<PersonalityStore>((set) => ({
|
||||
}),
|
||||
|
||||
updateItem: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
sectionKey: string,
|
||||
id: string,
|
||||
updates: Partial<SectionItemType>
|
||||
) =>
|
||||
@@ -225,7 +324,7 @@ export const usePersonalityStore = create<PersonalityStore>((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<PersonalityStore>((set) => ({
|
||||
},
|
||||
})),
|
||||
|
||||
addText: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
itemId: string,
|
||||
text: Omit<TextType, "id">
|
||||
) =>
|
||||
addText: (sectionKey: string, itemId: string, text: Omit<TextType, "id">) =>
|
||||
set((state) => ({
|
||||
data: {
|
||||
...state.data,
|
||||
@@ -262,7 +357,7 @@ export const usePersonalityStore = create<PersonalityStore>((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<PersonalityStore>((set) => ({
|
||||
}),
|
||||
|
||||
addButton: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
sectionKey: string,
|
||||
itemId: string,
|
||||
button: Omit<ButtonType, "id">
|
||||
) =>
|
||||
@@ -317,7 +412,7 @@ export const usePersonalityStore = create<PersonalityStore>((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<PersonalityStore>((set) => ({
|
||||
}),
|
||||
|
||||
updateText: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
sectionKey: string,
|
||||
itemId: string,
|
||||
textId: string,
|
||||
updates: Partial<TextType>
|
||||
@@ -369,7 +464,7 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
|
||||
})),
|
||||
|
||||
updateButton: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
sectionKey: string,
|
||||
itemId: string,
|
||||
buttonId: string,
|
||||
updates: Partial<ButtonType>
|
||||
@@ -394,7 +489,7 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
|
||||
})),
|
||||
|
||||
addImage: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
sectionKey: string,
|
||||
itemId: string,
|
||||
image: Omit<ImageType, "id">
|
||||
) =>
|
||||
@@ -419,7 +514,7 @@ export const usePersonalityStore = create<PersonalityStore>((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<PersonalityStore>((set) => ({
|
||||
}),
|
||||
|
||||
updateImage: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
sectionKey: string,
|
||||
itemId: string,
|
||||
imageId: string,
|
||||
updates: Partial<ImageType>
|
||||
@@ -470,11 +565,7 @@ export const usePersonalityStore = create<PersonalityStore>((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<PersonalityStore>((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<PersonalityStore>((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<PersonalityStore>((set) => ({
|
||||
})),
|
||||
|
||||
addSocial: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
sectionKey: string,
|
||||
itemId: string,
|
||||
social: Omit<SocialType, "id">
|
||||
) =>
|
||||
@@ -577,7 +660,7 @@ export const usePersonalityStore = create<PersonalityStore>((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<PersonalityStore>((set) => ({
|
||||
}),
|
||||
|
||||
updateSocial: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
sectionKey: string,
|
||||
itemId: string,
|
||||
socialId: string,
|
||||
updates: Partial<SocialType>
|
||||
@@ -628,11 +711,7 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
|
||||
},
|
||||
})),
|
||||
|
||||
deleteSocial: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
itemId: string,
|
||||
socialId: string
|
||||
) =>
|
||||
deleteSocial: (sectionKey: string, itemId: string, socialId: string) =>
|
||||
set((state) => ({
|
||||
data: {
|
||||
...state.data,
|
||||
|
||||
@@ -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<SectionItemType, "id">
|
||||
) => void;
|
||||
// Section management methods
|
||||
addSection: (afterSectionKey?: string) => void;
|
||||
removeSection: (sectionKey: string) => void;
|
||||
|
||||
setItems: (sectionKey: string, items: SectionItemType[]) => void;
|
||||
addItem: (sectionKey: string, item: Omit<SectionItemType, "id">) => void;
|
||||
updateItem: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
sectionKey: string,
|
||||
id: string,
|
||||
updates: Partial<SectionItemType>
|
||||
) => void;
|
||||
updateActiveItem: (updates: Partial<SectionItemType>) => 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<TextType, "id">
|
||||
) => void;
|
||||
addTextToActiveItem: (text: Omit<TextType, "id">) => void;
|
||||
addButton: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
sectionKey: string,
|
||||
itemId: string,
|
||||
button: Omit<ButtonType, "id">
|
||||
) => void;
|
||||
addButtonToActiveItem: (button: Omit<ButtonType, "id">) => void;
|
||||
updateText: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
sectionKey: string,
|
||||
itemId: string,
|
||||
textId: string,
|
||||
updates: Partial<TextType>
|
||||
) => void;
|
||||
updateButton: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
sectionKey: string,
|
||||
itemId: string,
|
||||
buttonId: string,
|
||||
updates: Partial<ButtonType>
|
||||
) => void;
|
||||
addImage: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
sectionKey: string,
|
||||
itemId: string,
|
||||
image: Omit<ImageType, "id">
|
||||
) => void;
|
||||
addImageToActiveItem: (image: Omit<ImageType, "id">) => void;
|
||||
updateImage: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
sectionKey: string,
|
||||
itemId: string,
|
||||
imageId: string,
|
||||
updates: Partial<ImageType>
|
||||
) => void;
|
||||
// Social network methods
|
||||
addSocial: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
sectionKey: string,
|
||||
itemId: string,
|
||||
social: Omit<SocialType, "id">
|
||||
) => void;
|
||||
addSocialToActiveItem: (social: Omit<SocialType, "id">) => void;
|
||||
updateSocial: (
|
||||
sectionKey: keyof PersonalityDataType,
|
||||
sectionKey: string,
|
||||
itemId: string,
|
||||
socialId: string,
|
||||
updates: Partial<SocialType>
|
||||
) => 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 = {
|
||||
|
||||
@@ -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 += `<tr>
|
||||
<td width="100%" height="230" style="padding: 20px; vertical-align: top; font-size: 15px; line-height: 1.8;">
|
||||
<div style="margin: 0; text-align: right; color: #888; font-size: 14px;">{{content}}</div>
|
||||
</td>
|
||||
</tr>`;
|
||||
} 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 = `<div style="max-width: 600px; margin: 0 auto; direction: rtl;">
|
||||
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="border-collapse: collapse;">
|
||||
<tbody>
|
||||
${renderSection(data.header, "123px")}
|
||||
${renderSection(data.content, "246px", "")}
|
||||
${renderSection(data.footer, "123px", "")}
|
||||
${sectionsHtml}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>`;
|
||||
|
||||
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(/<div[^>]*>{{content}}<\/div>/g);
|
||||
if (contentMatch) {
|
||||
console.log(
|
||||
"🔥 [ExportHTML] Found {{content}} placeholders:",
|
||||
contentMatch
|
||||
);
|
||||
} else {
|
||||
console.log("🔥 [ExportHTML] NO {{content}} placeholders found in HTML!");
|
||||
}
|
||||
|
||||
return html;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user