fix footer upload
This commit is contained in:
@@ -52,9 +52,9 @@ const SiteSetting: FC = () => {
|
||||
const { data: shopData, isLoading: isShopLoading } = 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 singleUpload = useSingleUpload()
|
||||
const [logoFile, setLogoFile] = useState<File[]>([])
|
||||
const [postalCodeFile, setPostalCodeFile] = useState<File[]>([])
|
||||
|
||||
|
||||
|
||||
@@ -73,34 +73,31 @@ const SiteSetting: FC = () => {
|
||||
validateOnChange: false,
|
||||
validateOnBlur: false,
|
||||
onSubmit: async (values) => {
|
||||
let finalDownloadAppDetails = values.downloadAppDetails
|
||||
let finalSocialMediaLinks = values.socialMediaLinks
|
||||
let siteLogo = values.siteLogo
|
||||
let shopPostalCode = values.shopPostalCode
|
||||
|
||||
// اول همه فایلهای pending رو آپلود کن
|
||||
if (Object.keys(pendingFiles).length > 0) {
|
||||
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({})
|
||||
// آپلود لوگو سایت اگر فایل جدید انتخاب شده
|
||||
if (logoFile.length > 0) {
|
||||
const logoResponse = await singleUpload.mutateAsync(logoFile[0])
|
||||
siteLogo = logoResponse.results?.url?.url || undefined
|
||||
}
|
||||
|
||||
// آپلود کد پستی فروشگاه اگر فایل جدید انتخاب شده
|
||||
if (postalCodeFile.length > 0) {
|
||||
const postalResponse = await singleUpload.mutateAsync(postalCodeFile[0])
|
||||
shopPostalCode = postalResponse.results?.url?.url || undefined
|
||||
}
|
||||
|
||||
// transform data برای ارسال به API (حذف id)
|
||||
const transformedValues = {
|
||||
...values,
|
||||
downloadAppDetails: finalDownloadAppDetails.map((item) => ({
|
||||
siteLogo,
|
||||
shopPostalCode,
|
||||
downloadAppDetails: values.downloadAppDetails.map((item) => ({
|
||||
pic: item.pic,
|
||||
url: item.url
|
||||
})),
|
||||
socialMediaLinks: finalSocialMediaLinks.map((item) => ({
|
||||
socialMediaLinks: values.socialMediaLinks.map((item) => ({
|
||||
icon: item.icon,
|
||||
url: item.url
|
||||
}))
|
||||
@@ -110,8 +107,8 @@ const SiteSetting: FC = () => {
|
||||
updateSiteSetting.mutate(transformedValues, {
|
||||
onSuccess: () => {
|
||||
toast.success('تنظیمات سایت با موفقیت بروزرسانی شد')
|
||||
// پاک کردن pending files بعد از submit موفق
|
||||
setPendingFiles({})
|
||||
setLogoFile([])
|
||||
setPostalCodeFile([])
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(extractErrorMessage(error))
|
||||
@@ -151,64 +148,6 @@ const SiteSetting: FC = () => {
|
||||
}, [data, shopData, isLoading, isShopLoading])
|
||||
|
||||
|
||||
const uploadAllPendingFiles = async (): Promise<{ [key: string]: string }> => {
|
||||
const uploadedUrls: { [key: string]: string } = {}
|
||||
|
||||
for (const [id, file] of Object.entries(pendingFiles)) {
|
||||
// پیدا کردن 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 singleUpload.mutateAsync(file)
|
||||
const imageUrl = uploadResponse.results.url.url
|
||||
|
||||
uploadedUrls[id] = imageUrl
|
||||
|
||||
// بروزرسانی formik
|
||||
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) {
|
||||
const itemType = isDownloadApp ? 'تصویر دانلود اپ' : 'آیکون رسانه اجتماعی'
|
||||
toast.error(`خطا در آپلود ${itemType} آیتم ${index + 1}`)
|
||||
throw error
|
||||
} finally {
|
||||
setUploadingIndexes(prev => {
|
||||
const newSet = new Set(prev)
|
||||
newSet.delete(index)
|
||||
return newSet
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return uploadedUrls
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (isLoading || isShopLoading) {
|
||||
return <div className="flex justify-center items-center h-64">در حال بارگذاری...</div>
|
||||
}
|
||||
@@ -237,24 +176,18 @@ const SiteSetting: FC = () => {
|
||||
|
||||
<div className='flex gap-6 xl:mt-8 mt-6'>
|
||||
<MainInfoSection formik={formik} isDataLoaded={isDataLoaded} />
|
||||
<FilesSection formik={formik} />
|
||||
<FilesSection
|
||||
formik={formik}
|
||||
logoFile={logoFile}
|
||||
setLogoFile={setLogoFile}
|
||||
postalCodeFile={postalCodeFile}
|
||||
setPostalCodeFile={setPostalCodeFile}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<DownloadAppSection
|
||||
formik={formik}
|
||||
pendingFiles={pendingFiles}
|
||||
setPendingFiles={setPendingFiles}
|
||||
uploadingIndexes={uploadingIndexes}
|
||||
setUploadingIndexes={setUploadingIndexes}
|
||||
/>
|
||||
<DownloadAppSection formik={formik} />
|
||||
|
||||
<SocialMediaSection
|
||||
formik={formik}
|
||||
pendingFiles={pendingFiles}
|
||||
setPendingFiles={setPendingFiles}
|
||||
uploadingIndexes={uploadingIndexes}
|
||||
setUploadingIndexes={setUploadingIndexes}
|
||||
/>
|
||||
<SocialMediaSection formik={formik} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { type FC } from 'react'
|
||||
import { type FC, useState } 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'
|
||||
import { useSingleUpload } from '../../category/hooks/useCategoryData'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
type DownloadAppDetail = {
|
||||
id: string
|
||||
@@ -30,17 +32,13 @@ type FormValues = {
|
||||
|
||||
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,
|
||||
setPendingFiles,
|
||||
uploadingIndexes,
|
||||
}) => {
|
||||
const singleUpload = useSingleUpload()
|
||||
const [uploadingIndexes, setUploadingIndexes] = useState<Set<number>>(new Set())
|
||||
const addDownloadAppDetail = () => {
|
||||
const currentDetails = formik.values.downloadAppDetails || []
|
||||
const newId = Date.now().toString()
|
||||
@@ -49,18 +47,7 @@ const DownloadAppSection: FC<Props> = ({
|
||||
|
||||
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) => {
|
||||
@@ -71,20 +58,26 @@ const DownloadAppSection: FC<Props> = ({
|
||||
formik.setFieldValue('downloadAppDetails', updatedDetails)
|
||||
}
|
||||
|
||||
const handleDownloadAppImageUpload = (index: number, files: File[]) => {
|
||||
const handleDownloadAppImageUpload = async (index: number, files: File[]) => {
|
||||
if (files.length === 0) return
|
||||
|
||||
const item = formik.values.downloadAppDetails?.[index]
|
||||
if (!item) return
|
||||
try {
|
||||
setUploadingIndexes(prev => new Set(prev).add(index))
|
||||
|
||||
// ذخیره فایل برای آپلود بعدی
|
||||
setPendingFiles(prev => ({
|
||||
...prev,
|
||||
[item.id]: files[0]
|
||||
}))
|
||||
const uploadResponse = await singleUpload.mutateAsync(files[0])
|
||||
const imageUrl = uploadResponse.results.url.url
|
||||
|
||||
// نمایش preview
|
||||
updateDownloadAppDetail(index, 'pic', URL.createObjectURL(files[0]))
|
||||
updateDownloadAppDetail(index, 'pic', imageUrl)
|
||||
toast.success('تصویر با موفقیت آپلود شد')
|
||||
} catch {
|
||||
toast.error('خطا در آپلود تصویر')
|
||||
} finally {
|
||||
setUploadingIndexes(prev => {
|
||||
const newSet = new Set(prev)
|
||||
newSet.delete(index)
|
||||
return newSet
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -21,9 +21,19 @@ type FormValues = {
|
||||
|
||||
type Props = {
|
||||
formik: FormikProps<FormValues>
|
||||
logoFile: File[]
|
||||
setLogoFile: React.Dispatch<React.SetStateAction<File[]>>
|
||||
postalCodeFile: File[]
|
||||
setPostalCodeFile: React.Dispatch<React.SetStateAction<File[]>>
|
||||
}
|
||||
|
||||
const FilesSection: FC<Props> = ({ formik }) => {
|
||||
const FilesSection: FC<Props> = ({
|
||||
formik,
|
||||
logoFile,
|
||||
setLogoFile,
|
||||
postalCodeFile,
|
||||
setPostalCodeFile
|
||||
}) => {
|
||||
return (
|
||||
<div className='w-80 space-y-6'>
|
||||
<div className='text-sm bg-white py-8 px-6 rounded-3xl'>
|
||||
@@ -35,14 +45,14 @@ const FilesSection: FC<Props> = ({ formik }) => {
|
||||
<UploadBox
|
||||
label=""
|
||||
isMultiple={false}
|
||||
onChange={(files) => {
|
||||
if (files.length > 0) {
|
||||
formik.setFieldValue('siteLogo', URL.createObjectURL(files[0]))
|
||||
}
|
||||
}}
|
||||
onChange={(files) => setLogoFile(files)}
|
||||
/>
|
||||
{(logoFile.length > 0 || formik.values.siteLogo) && (
|
||||
<img
|
||||
src={logoFile.length > 0 ? URL.createObjectURL(logoFile[0]) : formik.values.siteLogo}
|
||||
alt="لوگو سایت"
|
||||
className="mt-2 w-20 h-20 object-contain rounded"
|
||||
/>
|
||||
{formik.values.siteLogo && (
|
||||
<img src={formik.values.siteLogo} alt="لوگو سایت" className="mt-2 w-20 h-20 object-contain rounded" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -51,14 +61,14 @@ const FilesSection: FC<Props> = ({ formik }) => {
|
||||
<UploadBox
|
||||
label=""
|
||||
isMultiple={false}
|
||||
onChange={(files) => {
|
||||
if (files.length > 0) {
|
||||
formik.setFieldValue('shopPostalCode', URL.createObjectURL(files[0]))
|
||||
}
|
||||
}}
|
||||
onChange={(files) => setPostalCodeFile(files)}
|
||||
/>
|
||||
{(postalCodeFile.length > 0 || formik.values.shopPostalCode) && (
|
||||
<img
|
||||
src={postalCodeFile.length > 0 ? URL.createObjectURL(postalCodeFile[0]) : formik.values.shopPostalCode}
|
||||
alt="کد پستی فروشگاه"
|
||||
className="mt-2 w-20 h-20 object-contain rounded"
|
||||
/>
|
||||
{formik.values.shopPostalCode && (
|
||||
<img src={formik.values.shopPostalCode} alt="کد پستی فروشگاه" className="mt-2 w-20 h-20 object-contain rounded" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { type FC } from 'react'
|
||||
import { type FC, useState } 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'
|
||||
import { useSingleUpload } from '../../category/hooks/useCategoryData'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
type SocialMediaLink = {
|
||||
id: string
|
||||
@@ -24,17 +26,13 @@ type FormValues = {
|
||||
|
||||
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 SocialMediaSection: FC<Props> = ({
|
||||
formik,
|
||||
setPendingFiles,
|
||||
uploadingIndexes,
|
||||
}) => {
|
||||
const singleUpload = useSingleUpload()
|
||||
const [uploadingIndexes, setUploadingIndexes] = useState<Set<number>>(new Set())
|
||||
const addSocialMediaLink = () => {
|
||||
const currentLinks = formik.values.socialMediaLinks || []
|
||||
const newId = Date.now().toString()
|
||||
@@ -43,18 +41,7 @@ const SocialMediaSection: FC<Props> = ({
|
||||
|
||||
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: 'url', value: string) => {
|
||||
@@ -65,20 +52,26 @@ const SocialMediaSection: FC<Props> = ({
|
||||
formik.setFieldValue('socialMediaLinks', updatedLinks)
|
||||
}
|
||||
|
||||
const handleSocialMediaIconUpload = (index: number, files: File[]) => {
|
||||
const handleSocialMediaIconUpload = async (index: number, files: File[]) => {
|
||||
if (files.length === 0) return
|
||||
|
||||
const item = formik.values.socialMediaLinks?.[index]
|
||||
if (!item) return
|
||||
try {
|
||||
setUploadingIndexes(prev => new Set(prev).add(index))
|
||||
|
||||
// ذخیره فایل برای آپلود بعدی
|
||||
setPendingFiles(prev => ({
|
||||
...prev,
|
||||
[item.id]: files[0]
|
||||
}))
|
||||
const uploadResponse = await singleUpload.mutateAsync(files[0])
|
||||
const imageUrl = uploadResponse.results.url.url
|
||||
|
||||
// نمایش preview
|
||||
updateSocialMediaLinkIcon(index, URL.createObjectURL(files[0]))
|
||||
updateSocialMediaLinkIcon(index, imageUrl)
|
||||
toast.success('آیکون با موفقیت آپلود شد')
|
||||
} catch {
|
||||
toast.error('خطا در آپلود آیکون')
|
||||
} finally {
|
||||
setUploadingIndexes(prev => {
|
||||
const newSet = new Set(prev)
|
||||
newSet.delete(index)
|
||||
return newSet
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const updateSocialMediaLinkIcon = (index: number, iconUrl: string) => {
|
||||
|
||||
Reference in New Issue
Block a user