diff --git a/src/pages/setting/SiteSetting.tsx b/src/pages/setting/SiteSetting.tsx index b53332d..7920ce6 100644 --- a/src/pages/setting/SiteSetting.tsx +++ b/src/pages/setting/SiteSetting.tsx @@ -2,7 +2,6 @@ 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 @@ -10,6 +9,12 @@ type DownloadAppDetail = { url: string } +type SocialMediaLink = { + id: string + icon: string + url: string +} + type FormValues = { siteLogo?: string footerPhone: string @@ -18,7 +23,7 @@ type FormValues = { footerDescription: string shopPostalCode?: string downloadAppDetails: DownloadAppDetail[] - socialMediaLinks: { icon: string; url: string }[] + socialMediaLinks: SocialMediaLink[] } import Button from '../../components/Button' import { TickCircle } from 'iconsax-react' @@ -28,6 +33,7 @@ import DownloadAppSection from './components/DownloadAppSection' import SocialMediaSection from './components/SocialMediaSection' import { toast } from 'react-toastify' import { extractErrorMessage } from '../../helpers/utils' +import { useSingleUpload } from '../category/hooks/useCategoryData' const validationSchema = Yup.object().shape({ footerPhone: Yup.string().trim().required('تلفن فوتر الزامی است'), @@ -41,12 +47,14 @@ const validationSchema = Yup.object().shape({ }) const SiteSetting: FC = () => { + const { data, isLoading } = useGetSiteSetting() const { data: shopData } = useGetShop() const updateSiteSetting = useUpdateSiteSetting() const [isDataLoaded, setIsDataLoaded] = useState(false) const [uploadingIndexes, setUploadingIndexes] = useState>(new Set()) const [pendingFiles, setPendingFiles] = useState<{ [key: string]: File }>({}) + const singleUpload = useSingleUpload() const formik = useFormik({ initialValues: { @@ -57,15 +65,28 @@ const SiteSetting: FC = () => { footerDescription: '', shopPostalCode: '', downloadAppDetails: [], - socialMediaLinks: [] + socialMediaLinks: [] as SocialMediaLink[] }, validationSchema, validateOnChange: false, validateOnBlur: false, onSubmit: async (values) => { + let finalDownloadAppDetails = values.downloadAppDetails + let finalSocialMediaLinks = values.socialMediaLinks + // اول همه فایل‌های pending رو آپلود کن if (Object.keys(pendingFiles).length > 0) { - await uploadAllPendingFiles() + const uploadedData = await uploadAllPendingFiles() + // بروزرسانی downloadAppDetails با URL های واقعی + finalDownloadAppDetails = values.downloadAppDetails.map(item => { + const uploadedUrl = uploadedData[item.id] + return uploadedUrl ? { ...item, pic: uploadedUrl } : item + }) + // بروزرسانی socialMediaLinks با URL های واقعی + finalSocialMediaLinks = values.socialMediaLinks.map(item => { + const uploadedUrl = uploadedData[item.id] + return uploadedUrl ? { ...item, icon: uploadedUrl } : item + }) // پاک کردن pending files بعد از آپلود موفق setPendingFiles({}) } @@ -73,9 +94,13 @@ const SiteSetting: FC = () => { // transform data برای ارسال به API (حذف id) const transformedValues = { ...values, - downloadAppDetails: values.downloadAppDetails.map((item) => ({ + downloadAppDetails: finalDownloadAppDetails.map((item) => ({ pic: item.pic, url: item.url + })), + socialMediaLinks: finalSocialMediaLinks.map((item) => ({ + icon: item.icon, + url: item.url })) } @@ -107,7 +132,11 @@ const SiteSetting: FC = () => { pic: item.pic, url: item.url })), - socialMediaLinks: data.results.siteSetting.socialMediaLinks || [] + socialMediaLinks: (data.results.siteSetting.socialMediaLinks || []).map((item: { icon: string; url: string }, index: number) => ({ + id: `existing-${index}-${Date.now()}`, + icon: item.icon, + url: item.url + })) }, false) setIsDataLoaded(true) } @@ -119,27 +148,44 @@ const SiteSetting: FC = () => { 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) + // پیدا کردن index آیتم در downloadAppDetails + let index = formik.values.downloadAppDetails?.findIndex(item => item.id === id) + let isDownloadApp = true + + if (index === undefined || index === -1) { + // اگر در downloadAppDetails نبود، در socialMediaLinks جستجو کن + index = formik.values.socialMediaLinks?.findIndex(item => item.id === id) + isDownloadApp = false + } + if (index === undefined || index === -1) continue try { setUploadingIndexes(prev => new Set(prev).add(index)) - const uploadResponse = await uploadSingle(file) - const imageUrl = uploadResponse.results.url + const uploadResponse = await singleUpload.mutateAsync(file) + const imageUrl = uploadResponse.results.url.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) + if (isDownloadApp) { + const currentDetails = formik.values.downloadAppDetails || [] + const updatedDetails = currentDetails.map((item, i) => + i === index ? { ...item, pic: imageUrl } : item + ) + formik.setFieldValue('downloadAppDetails', updatedDetails) + } else { + const currentLinks = formik.values.socialMediaLinks || [] + const updatedLinks = currentLinks.map((item, i) => + i === index ? { ...item, icon: imageUrl } : item + ) + formik.setFieldValue('socialMediaLinks', updatedLinks) + } } catch (error) { - toast.error(`خطا در آپلود تصویر آیتم ${index + 1}`) + const itemType = isDownloadApp ? 'تصویر دانلود اپ' : 'آیکون رسانه اجتماعی' + toast.error(`خطا در آپلود ${itemType} آیتم ${index + 1}`) throw error } finally { setUploadingIndexes(prev => { @@ -192,7 +238,13 @@ const SiteSetting: FC = () => { setUploadingIndexes={setUploadingIndexes} /> - + ) } diff --git a/src/pages/setting/components/DownloadAppSection.tsx b/src/pages/setting/components/DownloadAppSection.tsx index 56d7d9f..9cf1d69 100644 --- a/src/pages/setting/components/DownloadAppSection.tsx +++ b/src/pages/setting/components/DownloadAppSection.tsx @@ -11,6 +11,12 @@ type DownloadAppDetail = { url: string } +type SocialMediaLink = { + id: string + icon: string + url: string +} + type FormValues = { siteLogo?: string footerPhone: string @@ -19,7 +25,7 @@ type FormValues = { footerDescription: string shopPostalCode?: string downloadAppDetails: DownloadAppDetail[] - socialMediaLinks: { icon: string; url: string }[] + socialMediaLinks: SocialMediaLink[] } type Props = { @@ -32,10 +38,8 @@ type Props = { const DownloadAppSection: FC = ({ formik, - pendingFiles, setPendingFiles, uploadingIndexes, - setUploadingIndexes }) => { const addDownloadAppDetail = () => { const currentDetails = formik.values.downloadAppDetails || [] diff --git a/src/pages/setting/components/FilesSection.tsx b/src/pages/setting/components/FilesSection.tsx index f46f042..14c8fe1 100644 --- a/src/pages/setting/components/FilesSection.tsx +++ b/src/pages/setting/components/FilesSection.tsx @@ -2,6 +2,12 @@ import { type FC } from 'react' import type { FormikProps } from 'formik' import UploadBox from '../../../components/UploadBox' +type SocialMediaLink = { + id: string + icon: string + url: string +} + type FormValues = { siteLogo?: string footerPhone: string @@ -10,7 +16,7 @@ type FormValues = { footerDescription: string shopPostalCode?: string downloadAppDetails: { id: string; pic: string; url: string }[] - socialMediaLinks: { icon: string; url: string }[] + socialMediaLinks: SocialMediaLink[] } type Props = { diff --git a/src/pages/setting/components/MainInfoSection.tsx b/src/pages/setting/components/MainInfoSection.tsx index ab5fb15..8f4e90e 100644 --- a/src/pages/setting/components/MainInfoSection.tsx +++ b/src/pages/setting/components/MainInfoSection.tsx @@ -4,6 +4,12 @@ import Input from '../../../components/Input' import Textarea from '../../../components/Textarea' import TextEditor from '../../../components/TextEditor' +type SocialMediaLink = { + id: string + icon: string + url: string +} + type FormValues = { siteLogo?: string footerPhone: string @@ -12,7 +18,7 @@ type FormValues = { footerDescription: string shopPostalCode?: string downloadAppDetails: { id: string; pic: string; url: string }[] - socialMediaLinks: { icon: string; url: string }[] + socialMediaLinks: SocialMediaLink[] } type Props = { diff --git a/src/pages/setting/components/SocialMediaSection.tsx b/src/pages/setting/components/SocialMediaSection.tsx index 59e4a80..05dd344 100644 --- a/src/pages/setting/components/SocialMediaSection.tsx +++ b/src/pages/setting/components/SocialMediaSection.tsx @@ -3,6 +3,13 @@ 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 SocialMediaLink = { + id: string + icon: string + url: string +} type FormValues = { siteLogo?: string @@ -12,25 +19,45 @@ type FormValues = { footerDescription: string shopPostalCode?: string downloadAppDetails: { id: string; pic: string; url: string }[] - socialMediaLinks: { icon: string; url: string }[] + socialMediaLinks: SocialMediaLink[] } type Props = { formik: FormikProps + pendingFiles: { [key: string]: File } + setPendingFiles: React.Dispatch> + uploadingIndexes: Set + setUploadingIndexes: React.Dispatch>> } -const SocialMediaSection: FC = ({ formik }) => { +const SocialMediaSection: FC = ({ + formik, + setPendingFiles, + uploadingIndexes, +}) => { const addSocialMediaLink = () => { const currentLinks = formik.values.socialMediaLinks || [] - formik.setFieldValue('socialMediaLinks', [...currentLinks, { icon: '', url: '' }]) + const newId = Date.now().toString() + formik.setFieldValue('socialMediaLinks', [...currentLinks, { id: newId, icon: '', url: '' }]) } const removeSocialMediaLink = (index: number) => { const currentLinks = formik.values.socialMediaLinks || [] + const itemToRemove = currentLinks[index] + formik.setFieldValue('socialMediaLinks', currentLinks.filter((_, i) => i !== index)) + + // پاک کردن pending file مربوطه + if (itemToRemove) { + setPendingFiles(prev => { + const newPending = { ...prev } + delete newPending[itemToRemove.id] + return newPending + }) + } } - const updateSocialMediaLink = (index: number, field: 'icon' | 'url', value: string) => { + const updateSocialMediaLink = (index: number, field: 'url', value: string) => { const currentLinks = formik.values.socialMediaLinks || [] const updatedLinks = currentLinks.map((item, i) => i === index ? { ...item, [field]: value } : item @@ -38,6 +65,30 @@ const SocialMediaSection: FC = ({ formik }) => { formik.setFieldValue('socialMediaLinks', updatedLinks) } + const handleSocialMediaIconUpload = (index: number, files: File[]) => { + if (files.length === 0) return + + const item = formik.values.socialMediaLinks?.[index] + if (!item) return + + // ذخیره فایل برای آپلود بعدی + setPendingFiles(prev => ({ + ...prev, + [item.id]: files[0] + })) + + // نمایش preview + updateSocialMediaLinkIcon(index, URL.createObjectURL(files[0])) + } + + const updateSocialMediaLinkIcon = (index: number, iconUrl: string) => { + const currentLinks = formik.values.socialMediaLinks || [] + const updatedLinks = currentLinks.map((item, i) => + i === index ? { ...item, icon: iconUrl } : item + ) + formik.setFieldValue('socialMediaLinks', updatedLinks) + } + return (
@@ -63,12 +114,21 @@ const SocialMediaSection: FC = ({ formik }) => {
- updateSocialMediaLink(index, 'icon', e.target.value)} - placeholder="مثال: telegram" - /> +
+ + handleSocialMediaIconUpload(index, files)} + isReset={false} + /> + {item.icon && ( + {`آیکون + )} + {uploadingIndexes.has(index) && ( +
در حال آپلود...
+ )} +