setting footer
This commit is contained in:
@@ -68,6 +68,7 @@ export const Pages = {
|
||||
setting: {
|
||||
shop: "/settings/shop",
|
||||
banners: "/settings/banners",
|
||||
siteSetting: "/settings/site-setting",
|
||||
},
|
||||
wallet: "/wallet",
|
||||
profile: "/profile",
|
||||
|
||||
@@ -64,7 +64,7 @@ const Banners: FC = () => {
|
||||
<div>
|
||||
<div className="flex justify-between items-center gap-4 mb-5">
|
||||
<div className='flex items-center gap-3'>
|
||||
<h1 className='text-xl font-semibold'>مدیریت بنرها</h1>
|
||||
<h1>مدیریت بنرها</h1>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => setIsCreateModalOpen(true)}
|
||||
@@ -139,17 +139,12 @@ const Banners: FC = () => {
|
||||
</a>
|
||||
</div>
|
||||
</Td>
|
||||
<Td text="">
|
||||
<div className="flex items-center">
|
||||
<span className="font-medium text-lg">{banner.order}</span>
|
||||
</div>
|
||||
</Td>
|
||||
<Td text={banner.order.toString()} />
|
||||
<Td text="">
|
||||
<Switch
|
||||
active={banner.isActive}
|
||||
onChange={() => handleStatusToggle(banner)}
|
||||
isLoading={updateBanner.isPending}
|
||||
label={banner.isActive ? 'فعال' : 'غیرفعال'}
|
||||
/>
|
||||
</Td>
|
||||
<Td text="">
|
||||
|
||||
@@ -1,8 +1,199 @@
|
||||
import { type FC } from 'react'
|
||||
import { type FC, useEffect, useState } from 'react'
|
||||
import { useFormik } from 'formik'
|
||||
import * as Yup from 'yup'
|
||||
import { useGetSiteSetting, useUpdateSiteSetting, useGetShop } from './hooks/useSettingData'
|
||||
import { uploadSingle } from '../uploader/service/UploaderService'
|
||||
|
||||
type DownloadAppDetail = {
|
||||
id: string
|
||||
pic: string
|
||||
url: string
|
||||
}
|
||||
|
||||
type FormValues = {
|
||||
siteLogo?: string
|
||||
footerPhone: string
|
||||
footerEmail: string
|
||||
footerAddress: string
|
||||
footerDescription: string
|
||||
shopPostalCode?: string
|
||||
downloadAppDetails: DownloadAppDetail[]
|
||||
socialMediaLinks: { icon: string; url: string }[]
|
||||
}
|
||||
import Button from '../../components/Button'
|
||||
import { TickCircle } from 'iconsax-react'
|
||||
import MainInfoSection from './components/MainInfoSection'
|
||||
import FilesSection from './components/FilesSection'
|
||||
import DownloadAppSection from './components/DownloadAppSection'
|
||||
import SocialMediaSection from './components/SocialMediaSection'
|
||||
import { toast } from 'react-toastify'
|
||||
import { extractErrorMessage } from '../../helpers/utils'
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
footerPhone: Yup.string().trim().required('تلفن فوتر الزامی است'),
|
||||
footerEmail: Yup.string().email('ایمیل معتبر نیست').required('ایمیل فوتر الزامی است'),
|
||||
footerAddress: Yup.string().trim().required('آدرس فوتر الزامی است'),
|
||||
footerDescription: Yup.string().trim().required('توضیحات فوتر الزامی است'),
|
||||
shopPostalCode: Yup.string().trim(),
|
||||
siteLogo: Yup.string(),
|
||||
downloadAppDetails: Yup.array(),
|
||||
socialMediaLinks: Yup.array()
|
||||
})
|
||||
|
||||
const SiteSetting: FC = () => {
|
||||
const { data, isLoading } = useGetSiteSetting()
|
||||
const { data: shopData } = useGetShop()
|
||||
const updateSiteSetting = useUpdateSiteSetting()
|
||||
const [isDataLoaded, setIsDataLoaded] = useState(false)
|
||||
const [uploadingIndexes, setUploadingIndexes] = useState<Set<number>>(new Set())
|
||||
const [pendingFiles, setPendingFiles] = useState<{ [key: string]: File }>({})
|
||||
|
||||
const formik = useFormik<FormValues>({
|
||||
initialValues: {
|
||||
siteLogo: undefined,
|
||||
footerPhone: '',
|
||||
footerEmail: '',
|
||||
footerAddress: '',
|
||||
footerDescription: '',
|
||||
shopPostalCode: '',
|
||||
downloadAppDetails: [],
|
||||
socialMediaLinks: []
|
||||
},
|
||||
validationSchema,
|
||||
validateOnChange: false,
|
||||
validateOnBlur: false,
|
||||
onSubmit: async (values) => {
|
||||
// اول همه فایلهای pending رو آپلود کن
|
||||
if (Object.keys(pendingFiles).length > 0) {
|
||||
await uploadAllPendingFiles()
|
||||
// پاک کردن pending files بعد از آپلود موفق
|
||||
setPendingFiles({})
|
||||
}
|
||||
|
||||
// transform data برای ارسال به API (حذف id)
|
||||
const transformedValues = {
|
||||
...values,
|
||||
downloadAppDetails: values.downloadAppDetails.map((item) => ({
|
||||
pic: item.pic,
|
||||
url: item.url
|
||||
}))
|
||||
}
|
||||
|
||||
// حالا فرم رو submit کن
|
||||
updateSiteSetting.mutate(transformedValues, {
|
||||
onSuccess: () => {
|
||||
toast.success('تنظیمات سایت با موفقیت بروزرسانی شد')
|
||||
// پاک کردن pending files بعد از submit موفق
|
||||
setPendingFiles({})
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(extractErrorMessage(error))
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (data?.results?.siteSetting && shopData?.results?.shop) {
|
||||
formik.setValues({
|
||||
siteLogo: data.results.siteSetting.siteLogo || undefined,
|
||||
footerPhone: data.results.siteSetting.footerPhone || '',
|
||||
footerEmail: data.results.siteSetting.footerEmail || '',
|
||||
footerAddress: data.results.siteSetting.footerAddress || '',
|
||||
footerDescription: data.results.siteSetting.footerDescription || '',
|
||||
shopPostalCode: shopData.results.shop.shopPostalCode || '',
|
||||
downloadAppDetails: (data.results.siteSetting.downloadAppDetails || []).map((item: { _id?: string; pic: string; url: string }, index: number) => ({
|
||||
id: item._id || `existing-${index}-${Date.now()}`,
|
||||
pic: item.pic,
|
||||
url: item.url
|
||||
})),
|
||||
socialMediaLinks: data.results.siteSetting.socialMediaLinks || []
|
||||
}, false)
|
||||
setIsDataLoaded(true)
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [data, shopData])
|
||||
|
||||
|
||||
const uploadAllPendingFiles = async (): Promise<{ [key: string]: string }> => {
|
||||
const uploadedUrls: { [key: string]: string } = {}
|
||||
|
||||
for (const [id, file] of Object.entries(pendingFiles)) {
|
||||
// پیدا کردن index آیتم بر اساس id
|
||||
const index = formik.values.downloadAppDetails?.findIndex(item => item.id === id)
|
||||
if (index === undefined || index === -1) continue
|
||||
|
||||
try {
|
||||
setUploadingIndexes(prev => new Set(prev).add(index))
|
||||
|
||||
const uploadResponse = await uploadSingle(file)
|
||||
const imageUrl = uploadResponse.results.url
|
||||
|
||||
uploadedUrls[id] = imageUrl
|
||||
|
||||
// بروزرسانی formik
|
||||
const currentDetails = formik.values.downloadAppDetails || []
|
||||
const updatedDetails = currentDetails.map((item, i) =>
|
||||
i === index ? { ...item, pic: imageUrl } : item
|
||||
)
|
||||
formik.setFieldValue('downloadAppDetails', updatedDetails)
|
||||
|
||||
} catch (error) {
|
||||
toast.error(`خطا در آپلود تصویر آیتم ${index + 1}`)
|
||||
throw error
|
||||
} finally {
|
||||
setUploadingIndexes(prev => {
|
||||
const newSet = new Set(prev)
|
||||
newSet.delete(index)
|
||||
return newSet
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return uploadedUrls
|
||||
}
|
||||
|
||||
|
||||
if (isLoading) {
|
||||
return <div className="flex justify-center items-center h-64">در حال بارگذاری...</div>
|
||||
}
|
||||
|
||||
return (
|
||||
<div>SiteSetting</div>
|
||||
<div className='mt-4'>
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='flex items-center gap-3'>
|
||||
<h1>تنظیمات سایت</h1>
|
||||
</div>
|
||||
<div>
|
||||
<Button
|
||||
className='px-6'
|
||||
onClick={() => formik.handleSubmit()}
|
||||
isLoading={updateSiteSetting.isPending}
|
||||
disabled={(!isDataLoaded || !formik.isValid) || updateSiteSetting.isPending}
|
||||
>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<TickCircle size={16} color='#fff' />
|
||||
<div>بروزرسانی تنظیمات</div>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex gap-6 xl:mt-8 mt-6'>
|
||||
<MainInfoSection formik={formik} isDataLoaded={isDataLoaded} />
|
||||
<FilesSection formik={formik} />
|
||||
</div>
|
||||
|
||||
<DownloadAppSection
|
||||
formik={formik}
|
||||
pendingFiles={pendingFiles}
|
||||
setPendingFiles={setPendingFiles}
|
||||
uploadingIndexes={uploadingIndexes}
|
||||
setUploadingIndexes={setUploadingIndexes}
|
||||
/>
|
||||
|
||||
<SocialMediaSection formik={formik} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
import { type FC } from 'react'
|
||||
import type { FormikProps } from 'formik'
|
||||
import { Add, Trash } from 'iconsax-react'
|
||||
import Button from '../../../components/Button'
|
||||
import Input from '../../../components/Input'
|
||||
import UploadBox from '../../../components/UploadBox'
|
||||
|
||||
type DownloadAppDetail = {
|
||||
id: string
|
||||
pic: string
|
||||
url: string
|
||||
}
|
||||
|
||||
type FormValues = {
|
||||
siteLogo?: string
|
||||
footerPhone: string
|
||||
footerEmail: string
|
||||
footerAddress: string
|
||||
footerDescription: string
|
||||
shopPostalCode?: string
|
||||
downloadAppDetails: DownloadAppDetail[]
|
||||
socialMediaLinks: { icon: string; url: string }[]
|
||||
}
|
||||
|
||||
type Props = {
|
||||
formik: FormikProps<FormValues>
|
||||
pendingFiles: { [key: string]: File }
|
||||
setPendingFiles: React.Dispatch<React.SetStateAction<{ [key: string]: File }>>
|
||||
uploadingIndexes: Set<number>
|
||||
setUploadingIndexes: React.Dispatch<React.SetStateAction<Set<number>>>
|
||||
}
|
||||
|
||||
const DownloadAppSection: FC<Props> = ({
|
||||
formik,
|
||||
pendingFiles,
|
||||
setPendingFiles,
|
||||
uploadingIndexes,
|
||||
setUploadingIndexes
|
||||
}) => {
|
||||
const addDownloadAppDetail = () => {
|
||||
const currentDetails = formik.values.downloadAppDetails || []
|
||||
const newId = Date.now().toString()
|
||||
formik.setFieldValue('downloadAppDetails', [...currentDetails, { id: newId, pic: '', url: '' }])
|
||||
}
|
||||
|
||||
const removeDownloadAppDetail = (index: number) => {
|
||||
const currentDetails = formik.values.downloadAppDetails || []
|
||||
const itemToRemove = currentDetails[index]
|
||||
|
||||
formik.setFieldValue('downloadAppDetails', currentDetails.filter((_, i) => i !== index))
|
||||
|
||||
// پاک کردن pending file مربوطه
|
||||
if (itemToRemove) {
|
||||
setPendingFiles(prev => {
|
||||
const newPending = { ...prev }
|
||||
delete newPending[itemToRemove.id]
|
||||
return newPending
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const updateDownloadAppDetail = (index: number, field: 'pic' | 'url', value: string) => {
|
||||
const currentDetails = formik.values.downloadAppDetails || []
|
||||
const updatedDetails = currentDetails.map((item, i) =>
|
||||
i === index ? { ...item, [field]: value } : item
|
||||
)
|
||||
formik.setFieldValue('downloadAppDetails', updatedDetails)
|
||||
}
|
||||
|
||||
const handleDownloadAppImageUpload = (index: number, files: File[]) => {
|
||||
if (files.length === 0) return
|
||||
|
||||
const item = formik.values.downloadAppDetails?.[index]
|
||||
if (!item) return
|
||||
|
||||
// ذخیره فایل برای آپلود بعدی
|
||||
setPendingFiles(prev => ({
|
||||
...prev,
|
||||
[item.id]: files[0]
|
||||
}))
|
||||
|
||||
// نمایش preview
|
||||
updateDownloadAppDetail(index, 'pic', URL.createObjectURL(files[0]))
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='mt-6 bg-white py-8 xl:px-10 px-6 rounded-3xl'>
|
||||
<div className='flex justify-between items-center mb-6'>
|
||||
<h2 className='text-lg font-medium'>جزئیات دانلود اپ</h2>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={addDownloadAppDetail}
|
||||
className="flex items-center gap-2 w-fit"
|
||||
>
|
||||
<Add size={16} color='#6B7280' />
|
||||
افزودن
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{formik.values.downloadAppDetails?.map((item, index) => (
|
||||
<div key={index} className="border border-gray-200 rounded-lg p-4">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<span className="text-sm font-medium">آیتم {index + 1}</span>
|
||||
<Button className='w-fit' size="sm" variant="danger" onClick={() => removeDownloadAppDetail(index)}>
|
||||
<Trash size={16} color='white' />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2">تصویر</label>
|
||||
<UploadBox
|
||||
label=""
|
||||
isMultiple={false}
|
||||
onChange={(files) => handleDownloadAppImageUpload(index, files)}
|
||||
isReset={false}
|
||||
/>
|
||||
{item.pic && (
|
||||
<img src={item.pic} alt={`تصویر ${index + 1}`} className="mt-2 w-20 h-20 object-contain rounded" />
|
||||
)}
|
||||
{uploadingIndexes.has(index) && (
|
||||
<div className="mt-2 text-sm text-blue-600">در حال آپلود...</div>
|
||||
)}
|
||||
</div>
|
||||
<Input
|
||||
label="لینک"
|
||||
value={item.url}
|
||||
onChange={(e) => updateDownloadAppDetail(index, 'url', e.target.value)}
|
||||
placeholder="URL دانلود"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DownloadAppSection
|
||||
@@ -0,0 +1,64 @@
|
||||
import { type FC } from 'react'
|
||||
import type { FormikProps } from 'formik'
|
||||
import UploadBox from '../../../components/UploadBox'
|
||||
|
||||
type FormValues = {
|
||||
siteLogo?: string
|
||||
footerPhone: string
|
||||
footerEmail: string
|
||||
footerAddress: string
|
||||
footerDescription: string
|
||||
shopPostalCode?: string
|
||||
downloadAppDetails: { id: string; pic: string; url: string }[]
|
||||
socialMediaLinks: { icon: string; url: string }[]
|
||||
}
|
||||
|
||||
type Props = {
|
||||
formik: FormikProps<FormValues>
|
||||
}
|
||||
|
||||
const FilesSection: FC<Props> = ({ formik }) => {
|
||||
return (
|
||||
<div className='w-80 space-y-6'>
|
||||
<div className='text-sm bg-white py-8 px-6 rounded-3xl'>
|
||||
<h2 className='text-lg font-medium mb-6'>فایلها</h2>
|
||||
|
||||
<div className='space-y-6'>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2">لوگو سایت</label>
|
||||
<UploadBox
|
||||
label=""
|
||||
isMultiple={false}
|
||||
onChange={(files) => {
|
||||
if (files.length > 0) {
|
||||
formik.setFieldValue('siteLogo', URL.createObjectURL(files[0]))
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{formik.values.siteLogo && (
|
||||
<img src={formik.values.siteLogo} alt="لوگو سایت" className="mt-2 w-20 h-20 object-contain rounded" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2">کد پستی فروشگاه</label>
|
||||
<UploadBox
|
||||
label=""
|
||||
isMultiple={false}
|
||||
onChange={(files) => {
|
||||
if (files.length > 0) {
|
||||
formik.setFieldValue('shopPostalCode', URL.createObjectURL(files[0]))
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{formik.values.shopPostalCode && (
|
||||
<img src={formik.values.shopPostalCode} alt="کد پستی فروشگاه" className="mt-2 w-20 h-20 object-contain rounded" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default FilesSection
|
||||
@@ -0,0 +1,64 @@
|
||||
import { type FC } from 'react'
|
||||
import type { FormikProps } from 'formik'
|
||||
import Input from '../../../components/Input'
|
||||
import Textarea from '../../../components/Textarea'
|
||||
import TextEditor from '../../../components/TextEditor'
|
||||
|
||||
type FormValues = {
|
||||
siteLogo?: string
|
||||
footerPhone: string
|
||||
footerEmail: string
|
||||
footerAddress: string
|
||||
footerDescription: string
|
||||
shopPostalCode?: string
|
||||
downloadAppDetails: { id: string; pic: string; url: string }[]
|
||||
socialMediaLinks: { icon: string; url: string }[]
|
||||
}
|
||||
|
||||
type Props = {
|
||||
formik: FormikProps<FormValues>
|
||||
isDataLoaded: boolean
|
||||
}
|
||||
|
||||
const MainInfoSection: FC<Props> = ({ formik, isDataLoaded }) => {
|
||||
return (
|
||||
<div className='flex-1 text-sm bg-white py-8 xl:px-10 px-6 rounded-3xl'>
|
||||
<h2 className='text-lg font-medium mb-6'>اطلاعات اصلی</h2>
|
||||
|
||||
<div className='space-y-6'>
|
||||
<div className='grid grid-cols-1 md:grid-cols-2 gap-6'>
|
||||
<Input
|
||||
label='تلفن فوتر'
|
||||
placeholder='مثال: ۵۷۲۷ - ۹۴۵ - ۰۹۳۹'
|
||||
{...formik.getFieldProps('footerPhone')}
|
||||
error_text={isDataLoaded && formik.touched.footerPhone && formik.errors.footerPhone ? formik.errors.footerPhone : ''}
|
||||
/>
|
||||
<Input
|
||||
label='ایمیل فوتر'
|
||||
placeholder='مثال: info@shinan.ir'
|
||||
{...formik.getFieldProps('footerEmail')}
|
||||
error_text={isDataLoaded && formik.touched.footerEmail && formik.errors.footerEmail ? formik.errors.footerEmail : ''}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Textarea
|
||||
label='آدرس فوتر'
|
||||
placeholder='آدرس کامل را وارد کنید...'
|
||||
{...formik.getFieldProps('footerAddress')}
|
||||
error_text={isDataLoaded && formik.touched.footerAddress && formik.errors.footerAddress ? formik.errors.footerAddress : ''}
|
||||
/>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2">توضیحات فوتر</label>
|
||||
<TextEditor
|
||||
value={formik.values.footerDescription || ''}
|
||||
onChange={(value) => formik.setFieldValue('footerDescription', value)}
|
||||
height="h-32"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default MainInfoSection
|
||||
@@ -0,0 +1,86 @@
|
||||
import { type FC } from 'react'
|
||||
import type { FormikProps } from 'formik'
|
||||
import { Add, Trash } from 'iconsax-react'
|
||||
import Button from '../../../components/Button'
|
||||
import Input from '../../../components/Input'
|
||||
|
||||
type FormValues = {
|
||||
siteLogo?: string
|
||||
footerPhone: string
|
||||
footerEmail: string
|
||||
footerAddress: string
|
||||
footerDescription: string
|
||||
shopPostalCode?: string
|
||||
downloadAppDetails: { id: string; pic: string; url: string }[]
|
||||
socialMediaLinks: { icon: string; url: string }[]
|
||||
}
|
||||
|
||||
type Props = {
|
||||
formik: FormikProps<FormValues>
|
||||
}
|
||||
|
||||
const SocialMediaSection: FC<Props> = ({ formik }) => {
|
||||
const addSocialMediaLink = () => {
|
||||
const currentLinks = formik.values.socialMediaLinks || []
|
||||
formik.setFieldValue('socialMediaLinks', [...currentLinks, { icon: '', url: '' }])
|
||||
}
|
||||
|
||||
const removeSocialMediaLink = (index: number) => {
|
||||
const currentLinks = formik.values.socialMediaLinks || []
|
||||
formik.setFieldValue('socialMediaLinks', currentLinks.filter((_, i) => i !== index))
|
||||
}
|
||||
|
||||
const updateSocialMediaLink = (index: number, field: 'icon' | 'url', value: string) => {
|
||||
const currentLinks = formik.values.socialMediaLinks || []
|
||||
const updatedLinks = currentLinks.map((item, i) =>
|
||||
i === index ? { ...item, [field]: value } : item
|
||||
)
|
||||
formik.setFieldValue('socialMediaLinks', updatedLinks)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='mt-6 bg-white py-8 xl:px-10 px-6 rounded-3xl'>
|
||||
<div className='flex justify-between items-center mb-6'>
|
||||
<h2 className='text-lg font-medium'>لینکهای رسانههای اجتماعی</h2>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={addSocialMediaLink}
|
||||
className="flex items-center gap-2 w-fit"
|
||||
>
|
||||
<Add size={16} color='#6B7280' />
|
||||
افزودن
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{formik.values.socialMediaLinks?.map((item, index) => (
|
||||
<div key={index} className="border border-gray-200 rounded-lg p-4">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<span className="text-sm font-medium">لینک {index + 1}</span>
|
||||
<Button className='w-fit' size="sm" variant="danger" onClick={() => removeSocialMediaLink(index)}>
|
||||
<Trash size={16} color='white' />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<Input
|
||||
label="آیکون"
|
||||
value={item.icon}
|
||||
onChange={(e) => updateSocialMediaLink(index, 'icon', e.target.value)}
|
||||
placeholder="مثال: telegram"
|
||||
/>
|
||||
<Input
|
||||
label="لینک"
|
||||
value={item.url}
|
||||
onChange={(e) => updateSocialMediaLink(index, 'url', e.target.value)}
|
||||
placeholder="URL صفحه"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SocialMediaSection
|
||||
@@ -59,11 +59,11 @@ export const useUpdateFaq = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetSiteSetting = (page: SiteSettingPageEnum) => {
|
||||
export const useGetSiteSetting = (page?: SiteSettingPageEnum) => {
|
||||
return useQuery({
|
||||
queryKey: ["siteSetting", page],
|
||||
queryKey: page ? ["siteSetting", page] : ["siteSetting"],
|
||||
queryFn: () => api.getSiteSetting(page),
|
||||
enabled: !!page,
|
||||
enabled: true,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -61,10 +61,11 @@ export const updateFaq = async (id: string, params: CreateFaqType) => {
|
||||
};
|
||||
|
||||
export const getSiteSetting = async (
|
||||
page: SiteSettingPageEnum
|
||||
page?: SiteSettingPageEnum
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
): Promise<any> => {
|
||||
const { data } = await axios.get(`/site-setting?name=${page}`);
|
||||
const url = page ? `/site-setting?name=${page}` : `/site-setting`;
|
||||
const { data } = await axios.get(url);
|
||||
return data;
|
||||
};
|
||||
|
||||
|
||||
@@ -75,11 +75,16 @@ export interface SiteSetting {
|
||||
downloadAppDetails?: {
|
||||
pic: string;
|
||||
url: string;
|
||||
_id?: string;
|
||||
id?: string;
|
||||
}[];
|
||||
socialMediaLinks?: {
|
||||
icon: string;
|
||||
url: string;
|
||||
_id?: string;
|
||||
id?: string;
|
||||
}[];
|
||||
shopPostalCode?: string;
|
||||
}
|
||||
|
||||
export interface SiteSettingResults {
|
||||
@@ -106,11 +111,16 @@ export interface UpdateSiteSetting {
|
||||
downloadAppDetails?: {
|
||||
pic: string;
|
||||
url: string;
|
||||
_id?: string;
|
||||
id?: string;
|
||||
}[];
|
||||
socialMediaLinks?: {
|
||||
icon: string;
|
||||
url: string;
|
||||
_id?: string;
|
||||
id?: string;
|
||||
}[];
|
||||
shopPostalCode?: string;
|
||||
}
|
||||
|
||||
export interface CreateDocumentType {
|
||||
|
||||
@@ -57,6 +57,7 @@ import ManageDocument from '@/pages/setting/ManageDocument'
|
||||
import Pricing from '@/pages/setting/Pricing'
|
||||
import Shop from '@/pages/setting/Shop'
|
||||
import Banners from '@/pages/setting/Banners'
|
||||
import SiteSetting from '@/pages/setting/SiteSetting'
|
||||
|
||||
const MainRouter: FC = () => {
|
||||
|
||||
@@ -139,6 +140,7 @@ const MainRouter: FC = () => {
|
||||
<Route path={Pages.pages.incomeTariff} element={<Pricing />} />
|
||||
<Route path={Pages.setting.shop} element={<Shop />} />
|
||||
<Route path={Pages.setting.banners} element={<Banners />} />
|
||||
<Route path={Pages.setting.siteSetting} element={<SiteSetting />} />
|
||||
</Routes>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -766,8 +766,8 @@ const SettingsSubMenu: FC = () => {
|
||||
/>
|
||||
<SubMenuItem
|
||||
title={'تنظیمات فوتر'}
|
||||
isActive={isActive('footer')}
|
||||
link="/settings/footer"
|
||||
isActive={isActive('site-setting')}
|
||||
link={Pages.setting.siteSetting}
|
||||
/>
|
||||
<SubMenuItem
|
||||
title={'تنظیمات بنرها'}
|
||||
|
||||
Reference in New Issue
Block a user