delete a template + update template
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { FC, useState, useEffect } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import { useLocation, useParams } from 'react-router-dom'
|
||||
import { SettingTabEnum } from './enum/SettingEnum'
|
||||
import Personality from './personality/Personality'
|
||||
import Domain from './domain/Domain'
|
||||
@@ -14,17 +14,30 @@ import { TickCircle } from 'iconsax-react'
|
||||
import { usePersonalityStore } from './personality/store/Store'
|
||||
import { exportPersonalityToHTML } from './personality/utils/ExportHTML'
|
||||
import Input from '@/components/Input'
|
||||
import { useSaveTemplate } from './personality/hooks/usePersonalityData'
|
||||
import { useSaveTemplate, useUpdateTemplate, useGetTemplate } from './personality/hooks/usePersonalityData'
|
||||
import { toast } from '@/components/Toast'
|
||||
|
||||
const Setting: FC = () => {
|
||||
|
||||
const { t } = useTranslation()
|
||||
const { id } = useParams()
|
||||
const { data } = usePersonalityStore()
|
||||
const location = useLocation()
|
||||
const [activeTab, setActiveTab] = useState<SettingTabEnum>(SettingTabEnum.SETTING_DOMAIN)
|
||||
const [templateName, setTemplateName] = useState('')
|
||||
const { mutate: saveTemplate, isPending } = useSaveTemplate()
|
||||
const { mutate: saveTemplate, isPending: isSaving } = useSaveTemplate()
|
||||
const { mutate: updateTemplate, isPending: isUpdating } = useUpdateTemplate()
|
||||
const { data: template } = useGetTemplate(id || '')
|
||||
|
||||
const isEditMode = !!id
|
||||
const isLoading = isSaving || isUpdating
|
||||
|
||||
// پر کردن نام قالب در حالت edit
|
||||
useEffect(() => {
|
||||
if (isEditMode && template?.data?.template?.name) {
|
||||
setTemplateName(template.data.template.name)
|
||||
}
|
||||
}, [isEditMode, template])
|
||||
|
||||
const getTabFromPath = (pathname: string): SettingTabEnum => {
|
||||
switch (pathname) {
|
||||
@@ -39,6 +52,10 @@ const Setting: FC = () => {
|
||||
case Paths.settingSignature:
|
||||
return SettingTabEnum.SETTING_SIGNATURE
|
||||
default:
|
||||
// بررسی personality با id
|
||||
if (pathname.startsWith(Paths.settingPersonality + '/')) {
|
||||
return SettingTabEnum.SETTING_PERSONALITY
|
||||
}
|
||||
return SettingTabEnum.SETTING_DOMAIN
|
||||
}
|
||||
}
|
||||
@@ -84,15 +101,39 @@ const Setting: FC = () => {
|
||||
}
|
||||
|
||||
const html = await exportPersonalityToHTML(data)
|
||||
saveTemplate({
|
||||
name: templateName,
|
||||
rawHtml: html,
|
||||
structure: data
|
||||
}, {
|
||||
onSuccess: (data) => {
|
||||
toast(data?.data?.message, 'success')
|
||||
}
|
||||
})
|
||||
|
||||
if (isEditMode) {
|
||||
// حالت edit - استفاده از updateTemplate
|
||||
updateTemplate({
|
||||
id: id!,
|
||||
params: {
|
||||
name: templateName,
|
||||
rawHtml: html,
|
||||
structure: data
|
||||
}
|
||||
}, {
|
||||
onSuccess: (data) => {
|
||||
toast(data?.data?.message || 'قالب با موفقیت بروزرسانی شد', 'success')
|
||||
},
|
||||
onError: () => {
|
||||
toast('خطا در بروزرسانی قالب', 'error')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// حالت جدید - استفاده از saveTemplate
|
||||
saveTemplate({
|
||||
name: templateName,
|
||||
rawHtml: html,
|
||||
structure: data
|
||||
}, {
|
||||
onSuccess: (data) => {
|
||||
toast(data?.data?.message || 'قالب با موفقیت ایجاد شد', 'success')
|
||||
},
|
||||
onError: () => {
|
||||
toast('خطا در ایجاد قالب', 'error')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// const handleExportHTML = async () => {
|
||||
@@ -124,11 +165,11 @@ const Setting: FC = () => {
|
||||
variant='secondary'
|
||||
className='border border-black w-fit px-7'
|
||||
onClick={handleSave}
|
||||
loading={isPending}
|
||||
loading={isLoading}
|
||||
>
|
||||
<div className='flex items-center gap-2'>
|
||||
<TickCircle size={18} color='black' />
|
||||
{t('save')}
|
||||
{isEditMode ? 'بروزرسانی' : t('save')}
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
import { FC } from 'react'
|
||||
import { FC, useEffect } from 'react'
|
||||
import HeaderSection from './components/HeaderSection'
|
||||
import ContentSection from './components/ContentSection'
|
||||
import FooterSection from './components/FooterSection'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { usePersonalityStore } from './store/Store'
|
||||
import { useGetTemplate } from './hooks/usePersonalityData'
|
||||
|
||||
const Personality: FC = () => {
|
||||
const { id } = useParams()
|
||||
const { setData } = usePersonalityStore()
|
||||
const { data: template } = useGetTemplate(id || '')
|
||||
|
||||
useEffect(() => {
|
||||
if (id && template?.data?.template?.structure) {
|
||||
setData(template.data.template.structure)
|
||||
}
|
||||
}, [id, template, setData])
|
||||
|
||||
return (
|
||||
<div className='flex-1 bg-white rounded-4xl p-8'>
|
||||
<table width="100%" cellPadding="0" cellSpacing="0" border={0} style={{ borderCollapse: 'collapse' }}>
|
||||
|
||||
@@ -98,28 +98,28 @@ const PersonalitySidebar: FC = () => {
|
||||
/>
|
||||
<Text
|
||||
size={22}
|
||||
color={selectedElement?.type === ElementType.TEXT ? '#0038FF' : 'black'}
|
||||
color={'black'}
|
||||
variant={SideBarTab.TEXT === active ? 'Bold' : 'Outline'}
|
||||
onClick={() => setActive(SideBarTab.TEXT)}
|
||||
className='cursor-pointer'
|
||||
/>
|
||||
<LinkSquare
|
||||
size={22}
|
||||
color={selectedElement?.type === ElementType.BUTTON ? '#0038FF' : 'black'}
|
||||
color={'black'}
|
||||
variant={SideBarTab.BUTTON === active ? 'Bold' : 'Outline'}
|
||||
onClick={() => setActive(SideBarTab.BUTTON)}
|
||||
className='cursor-pointer'
|
||||
/>
|
||||
<Gallery
|
||||
size={22}
|
||||
color={selectedElement?.type === ElementType.IMAGE ? '#0038FF' : 'black'}
|
||||
color={'black'}
|
||||
variant={SideBarTab.IMAGE === active ? 'Bold' : 'Outline'}
|
||||
onClick={() => setActive(SideBarTab.IMAGE)}
|
||||
className='cursor-pointer'
|
||||
/>
|
||||
<Profile2User
|
||||
size={22}
|
||||
color={selectedElement?.type === ElementType.SOCIAL ? '#0038FF' : 'black'}
|
||||
color={'black'}
|
||||
variant={SideBarTab.SOCIAL === active ? 'Bold' : 'Outline'}
|
||||
onClick={() => setActive(SideBarTab.SOCIAL)}
|
||||
className='cursor-pointer'
|
||||
|
||||
@@ -13,80 +13,47 @@ const ContentSection: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const { activeSection, activeItemIndex, data, setActiveSection, setActiveItemIndex } = usePersonalityStore()
|
||||
|
||||
console.log('🟢 ContentSection - Current state:', {
|
||||
activeSection,
|
||||
activeItemIndex,
|
||||
contentColumnsCount: data.content.columnsCount,
|
||||
contentItemsLength: data.content.items.length
|
||||
});
|
||||
// Early return if data is not available
|
||||
if (!data || !data.content) {
|
||||
return (
|
||||
<tr>
|
||||
<td style={{ height: '246px', textAlign: 'center', verticalAlign: 'middle', paddingTop: '16px' }}>
|
||||
<div>در حال بارگذاری...</div>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
const handleSectionClick = (section: SectionName, e: React.MouseEvent) => {
|
||||
console.log('🟢 ContentSection - handleSectionClick called:', {
|
||||
section,
|
||||
event: e,
|
||||
target: e.target,
|
||||
currentTarget: e.currentTarget
|
||||
});
|
||||
|
||||
// اگر کلیک روی فضای خالی باشد (نه روی content elements)
|
||||
const target = e.target as HTMLElement;
|
||||
const isClickOnContent = target.closest('[data-element-type]') !== null;
|
||||
|
||||
console.log('🟢 ContentSection - Section click analysis:', {
|
||||
isClickOnContent,
|
||||
targetTagName: target.tagName,
|
||||
targetClasses: target.className
|
||||
});
|
||||
|
||||
if (!isClickOnContent) {
|
||||
console.log('🟢 ContentSection - Setting active section:', section);
|
||||
setActiveSection(section)
|
||||
} else {
|
||||
console.log('🟢 ContentSection - Click on content element, not setting section');
|
||||
}
|
||||
}
|
||||
|
||||
const handleItemClick = (index: number, e: React.MouseEvent) => {
|
||||
console.log('🟢 ContentSection - handleItemClick called:', {
|
||||
index,
|
||||
event: e,
|
||||
target: e.target,
|
||||
currentTarget: e.currentTarget
|
||||
});
|
||||
|
||||
// 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;
|
||||
|
||||
console.log('🟢 ContentSection - Click analysis:', {
|
||||
isClickOnContent,
|
||||
targetTagName: target.tagName,
|
||||
targetClasses: target.className,
|
||||
closestDataElement: target.closest('[data-element-type]')
|
||||
});
|
||||
|
||||
// Only select column if not clicking on content elements
|
||||
if (!isClickOnContent) {
|
||||
console.log('🟢 ContentSection - Selecting column:', {
|
||||
index,
|
||||
section: SectionName.CONTENT,
|
||||
currentActiveSection: activeSection,
|
||||
currentActiveItemIndex: activeItemIndex
|
||||
});
|
||||
|
||||
|
||||
e.stopPropagation()
|
||||
|
||||
// Only set active section if we're not already in content section
|
||||
if (activeSection !== SectionName.CONTENT) {
|
||||
console.log('🟢 ContentSection - Switching to content section');
|
||||
setActiveSection(SectionName.CONTENT)
|
||||
}
|
||||
|
||||
// Always set the active item index
|
||||
console.log('🟢 ContentSection - Setting active item index to:', index);
|
||||
setActiveItemIndex(index)
|
||||
} else {
|
||||
console.log('🟢 ContentSection - Click on content element, not selecting column');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,17 @@ const FooterSection: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const { activeSection, activeItemIndex, data, setActiveSection, setActiveItemIndex } = usePersonalityStore()
|
||||
|
||||
// Early return if data is not available
|
||||
if (!data || !data.footer) {
|
||||
return (
|
||||
<tr>
|
||||
<td style={{ height: '123px', textAlign: 'center', verticalAlign: 'middle', paddingTop: '16px' }}>
|
||||
<div>در حال بارگذاری...</div>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
console.log('🔴 FooterSection - Current state:', {
|
||||
activeSection,
|
||||
activeItemIndex,
|
||||
|
||||
@@ -13,80 +13,50 @@ const HeaderSection: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const { activeSection, activeItemIndex, data, setActiveSection, setActiveItemIndex } = usePersonalityStore()
|
||||
|
||||
console.log('🔵 HeaderSection - Current state:', {
|
||||
activeSection,
|
||||
activeItemIndex,
|
||||
headerColumnsCount: data.header.columnsCount,
|
||||
headerItemsLength: data.header.items.length
|
||||
});
|
||||
// Early return if data is not available
|
||||
if (!data || !data.header) {
|
||||
return (
|
||||
<tr>
|
||||
<td style={{ height: '123px', textAlign: 'center', verticalAlign: 'middle' }}>
|
||||
<div>در حال بارگذاری...</div>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const handleSectionClick = (section: SectionName, e: React.MouseEvent) => {
|
||||
console.log('🔵 HeaderSection - handleSectionClick called:', {
|
||||
section,
|
||||
event: e,
|
||||
target: e.target,
|
||||
currentTarget: e.currentTarget
|
||||
});
|
||||
|
||||
// اگر کلیک روی فضای خالی باشد (نه روی content elements)
|
||||
const target = e.target as HTMLElement;
|
||||
const isClickOnContent = target.closest('[data-element-type]') !== null;
|
||||
|
||||
console.log('🔵 HeaderSection - Section click analysis:', {
|
||||
isClickOnContent,
|
||||
targetTagName: target.tagName,
|
||||
targetClasses: target.className
|
||||
});
|
||||
|
||||
if (!isClickOnContent) {
|
||||
console.log('🔵 HeaderSection - Setting active section:', section);
|
||||
setActiveSection(section)
|
||||
} else {
|
||||
console.log('🔵 HeaderSection - Click on content element, not setting section');
|
||||
}
|
||||
}
|
||||
|
||||
const handleItemClick = (index: number, e: React.MouseEvent) => {
|
||||
console.log('🔵 HeaderSection - handleItemClick called:', {
|
||||
index,
|
||||
event: e,
|
||||
target: e.target,
|
||||
currentTarget: e.currentTarget
|
||||
});
|
||||
|
||||
// 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;
|
||||
|
||||
console.log('🔵 HeaderSection - Click analysis:', {
|
||||
isClickOnContent,
|
||||
targetTagName: target.tagName,
|
||||
targetClasses: target.className,
|
||||
closestDataElement: target.closest('[data-element-type]')
|
||||
});
|
||||
|
||||
// Only select column if not clicking on content elements
|
||||
if (!isClickOnContent) {
|
||||
console.log('🔵 HeaderSection - Selecting column:', {
|
||||
index,
|
||||
section: SectionName.HEADER,
|
||||
currentActiveSection: activeSection,
|
||||
currentActiveItemIndex: activeItemIndex
|
||||
});
|
||||
|
||||
e.stopPropagation()
|
||||
|
||||
// Only set active section if we're not already in header section
|
||||
if (activeSection !== SectionName.HEADER) {
|
||||
console.log('🔵 HeaderSection - Switching to header section');
|
||||
|
||||
setActiveSection(SectionName.HEADER)
|
||||
}
|
||||
|
||||
// Always set the active item index
|
||||
console.log('🔵 HeaderSection - Setting active item index to:', index);
|
||||
setActiveItemIndex(index)
|
||||
} else {
|
||||
console.log('🔵 HeaderSection - Click on content element, not selecting column');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,10 @@ import { FC, useEffect, useState } from 'react'
|
||||
import { TemplateResponseType } from '../types/Types'
|
||||
import Radio from '@/components/Radio'
|
||||
import { Brush2, Trash } from 'iconsax-react'
|
||||
import { useSetSelectedTemplate } from '../hooks/usePersonalityData'
|
||||
import { useSetSelectedTemplate, useDeleteTemplate } from '../hooks/usePersonalityData'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Paths } from '@/utils/Paths'
|
||||
import ModalConfrim from '@/components/ModalConfrim'
|
||||
|
||||
const Templete: FC<{
|
||||
item: TemplateResponseType
|
||||
@@ -10,14 +13,24 @@ const Templete: FC<{
|
||||
}> = ({ item, selectedTemplateId }) => {
|
||||
|
||||
const [isActive, setIsActive] = useState(item.selected)
|
||||
const [isShowDeleteModal, setIsShowDeleteModal] = useState(false)
|
||||
|
||||
const { mutate: setSelectedTemplate } = useSetSelectedTemplate()
|
||||
const { mutate: deleteTemplate, isPending: isDeleting } = useDeleteTemplate()
|
||||
|
||||
const handleChangeSelectedTemplate = (id: string) => {
|
||||
setSelectedTemplate(id, {
|
||||
})
|
||||
}
|
||||
|
||||
const handleDeleteTemplate = () => {
|
||||
deleteTemplate(item.id, {
|
||||
onSuccess: () => {
|
||||
setIsShowDeleteModal(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedTemplateId) {
|
||||
setIsActive(selectedTemplateId === item.id)
|
||||
@@ -27,19 +40,34 @@ const Templete: FC<{
|
||||
}, [item.selected, selectedTemplateId, item.id])
|
||||
|
||||
return (
|
||||
<div key={item.id} className='flex-1 bg-white rounded-3xl p-4'>
|
||||
<div className='h-[140px] bg-gray-200 rounded-3xl'></div>
|
||||
<div className='mt-4 flex justify-between items-center'>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<Radio isActive={isActive} onChange={handleChangeSelectedTemplate} value={item.id} />
|
||||
<div className='text-sm'>{item.name}</div>
|
||||
</div>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<Brush2 size={20} color='black' />
|
||||
<Trash size={20} color='red' />
|
||||
<>
|
||||
<div key={item.id} className='flex-1 bg-white rounded-3xl p-4'>
|
||||
<div className='h-[140px] bg-gray-200 rounded-3xl'></div>
|
||||
<div className='mt-4 flex justify-between items-center'>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<Radio isActive={isActive} onChange={handleChangeSelectedTemplate} value={item.id} />
|
||||
<div className='text-sm'>{item.name}</div>
|
||||
</div>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<Link to={`${Paths.settingPersonality}/${item.id}`}>
|
||||
<Brush2 size={20} color='black' />
|
||||
</Link>
|
||||
<button onClick={() => setIsShowDeleteModal(true)} className='p-1'>
|
||||
<Trash size={20} color='red' />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ModalConfrim
|
||||
isOpen={isShowDeleteModal}
|
||||
close={() => setIsShowDeleteModal(false)}
|
||||
onConfrim={handleDeleteTemplate}
|
||||
isLoading={isDeleting}
|
||||
title="حذف قالب"
|
||||
label={`آیا از حذف قالب "${item.name}" اطمینان دارید؟`}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -228,7 +228,6 @@ const TextSidebar: FC = () => {
|
||||
<div className='space-y-3'>
|
||||
<Button
|
||||
onClick={handleUpdateText}
|
||||
className='bg-[#0038FF] text-white w-full'
|
||||
disabled={!value.trim()}
|
||||
>
|
||||
<div className='flex justify-center items-center gap-2'>
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import * as api from "../service/Service";
|
||||
import { TemplateType, TemplatesResponseType } from "../types/Types";
|
||||
import {
|
||||
TemplateType,
|
||||
TemplatesResponseType,
|
||||
GetTemplateResponse,
|
||||
} from "../types/Types";
|
||||
|
||||
export const useSaveTemplate = () => {
|
||||
return useMutation({
|
||||
@@ -20,3 +24,29 @@ export const useSetSelectedTemplate = () => {
|
||||
mutationFn: (id: string) => api.setSelectedTemplate(id),
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetTemplate = (id: string) => {
|
||||
return useQuery<GetTemplateResponse>({
|
||||
queryKey: ["template", id],
|
||||
queryFn: () => api.getTemplate(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateTemplate = () => {
|
||||
return useMutation({
|
||||
mutationFn: ({ id, params }: { id: string; params: TemplateType }) =>
|
||||
api.updateTemplate({ id, params }),
|
||||
});
|
||||
};
|
||||
|
||||
export const useDeleteTemplate = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (id: string) => api.deleteTemplate(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["templates"] });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -15,3 +15,24 @@ export const setSelectedTemplate = async (id: string) => {
|
||||
const { data } = await axios.patch(`/templates/${id}/set-selected`);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getTemplate = async (id: string) => {
|
||||
const { data } = await axios.get(`/templates/${id}`);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const updateTemplate = async ({
|
||||
id,
|
||||
params,
|
||||
}: {
|
||||
id: string;
|
||||
params: TemplateType;
|
||||
}) => {
|
||||
const { data } = await axios.patch(`/templates/${id}`, params);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const deleteTemplate = async (id: string) => {
|
||||
const { data } = await axios.delete(`/templates/${id}`);
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -26,6 +26,11 @@ export const usePersonalityStore = create<PersonalityStore>((set) => ({
|
||||
selectedElement: null,
|
||||
isEditMode: false,
|
||||
|
||||
setData: (data: PersonalityDataType) =>
|
||||
set(() => ({
|
||||
data,
|
||||
})),
|
||||
|
||||
setActiveSection: (section: SectionName) =>
|
||||
set((state) => {
|
||||
console.log("🏪 Store - setActiveSection called:", {
|
||||
|
||||
@@ -168,6 +168,7 @@ export type PersonalityStore = {
|
||||
selectedElement: SelectedElement; // New field for element selection
|
||||
isEditMode: boolean; // New field for edit mode
|
||||
|
||||
setData: (data: PersonalityDataType) => void;
|
||||
setActiveSection: (section: SectionName) => void;
|
||||
setActiveItemIndex: (index: number) => void;
|
||||
setSelectedElement: (element: SelectedElement) => void; // New method
|
||||
@@ -270,6 +271,24 @@ export type TemplateType = {
|
||||
structure: PersonalityDataType;
|
||||
};
|
||||
|
||||
export type GetTemplateResponse = {
|
||||
statusCode: number;
|
||||
success: boolean;
|
||||
data: {
|
||||
template: {
|
||||
id: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt: string | null;
|
||||
name: string;
|
||||
structure: PersonalityDataType;
|
||||
currentVersion: string;
|
||||
selected: boolean;
|
||||
business: BusinessType;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// API Response Types
|
||||
export type BusinessType = {
|
||||
id: string;
|
||||
|
||||
@@ -16,6 +16,7 @@ const AppRouter: FC = () => {
|
||||
<Route path={Paths.settingPersonality} element={<Setting />} />
|
||||
<Route path={Paths.settingSignature} element={<Setting />} />
|
||||
<Route path={Paths.settingPersonalityList} element={<List />} />
|
||||
<Route path={`${Paths.settingPersonality}/:id`} element={<Setting />} />
|
||||
<Route path={Paths.emailBuilder} element={<EmailBuilder />} />
|
||||
</Routes>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user