From 88ee42e4349c81891f9738dab86afb78c047c899 Mon Sep 17 00:00:00 2001 From: hossein taromi Date: Mon, 11 Aug 2025 12:53:05 +0330 Subject: [PATCH] feat(products): fix image preview by using public file URL and normalizing edit data --- src/components/ui/VariantManager.tsx | 21 +++++++++++++++- .../products/product-form/ProductFormPage.tsx | 24 +++++++++++++++++-- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/components/ui/VariantManager.tsx b/src/components/ui/VariantManager.tsx index 86126f1..bcff4a8 100644 --- a/src/components/ui/VariantManager.tsx +++ b/src/components/ui/VariantManager.tsx @@ -5,6 +5,25 @@ import { Button } from './Button'; import { FileUploader } from './FileUploader'; import { useFileUpload, useFileDelete } from '../../hooks/useFileUpload'; import { persianToEnglish, convertPersianNumbersInObject } from '../../utils/numberUtils'; +import { API_GATE_WAY, API_ROUTES } from '@/constant/routes'; + +const toPublicUrl = (img: any): ProductImage => { + const rawUrl: string = img?.url || ''; + const serveKey: string | undefined = (img && img.serve_key) || undefined; + const url = serveKey + ? `${API_GATE_WAY}/${API_ROUTES.DOWNLOAD_FILE(serveKey)}` + : rawUrl?.startsWith('http') + ? rawUrl + : rawUrl + ? `${API_GATE_WAY}${rawUrl.startsWith('/') ? '' : '/'}${rawUrl}` + : ''; + return { + id: (img?.id ?? img).toString(), + url, + alt: img?.alt || '', + order: img?.order ?? 0, + }; +}; interface ProductOption { id: number; @@ -47,7 +66,7 @@ const VariantForm: React.FC = ({ variant, onSave, onCancel, is const [uploadedImages, setUploadedImages] = useState( Array.isArray(variant?.file_ids) && variant.file_ids.length > 0 && typeof variant.file_ids[0] === 'object' - ? variant.file_ids + ? variant.file_ids.map(toPublicUrl) : [] ); const [variantAttributeValue, setVariantAttributeValue] = useState(''); diff --git a/src/pages/products/product-form/ProductFormPage.tsx b/src/pages/products/product-form/ProductFormPage.tsx index c132d24..865a3f3 100644 --- a/src/pages/products/product-form/ProductFormPage.tsx +++ b/src/pages/products/product-form/ProductFormPage.tsx @@ -17,6 +17,7 @@ import { VariantManager } from "@/components/ui/VariantManager"; import { ArrowRight, Package, X, Plus, Trash2 } from "lucide-react"; import { FormHeader, PageContainer, SectionTitle, Label } from '../../../components/ui/Typography'; import { createNumberTransform, createOptionalNumberTransform, convertPersianNumbersInObject } from '../../../utils/numberUtils'; +import { API_GATE_WAY, API_ROUTES } from '@/constant/routes'; const productSchema = yup.object({ name: yup.string().required('نام محصول الزامی است').min(2, 'نام محصول باید حداقل 2 کاراکتر باشد'), @@ -35,6 +36,24 @@ const productSchema = yup.object({ variants: yup.array().default([]), }); +const toPublicUrl = (img: any): ProductImage => { + const rawUrl: string = img?.url || ''; + const serveKey: string | undefined = (img && img.serve_key) || undefined; + const url = serveKey + ? `${API_GATE_WAY}/${API_ROUTES.DOWNLOAD_FILE(serveKey)}` + : rawUrl?.startsWith('http') + ? rawUrl + : rawUrl + ? `${API_GATE_WAY}${rawUrl.startsWith('/') ? '' : '/'}${rawUrl}` + : ''; + return { + id: (img?.id ?? img).toString(), + url, + alt: img?.alt || '', + order: img?.order ?? 0, + }; +}; + const ProductFormPage = () => { const navigate = useNavigate(); const { id } = useParams<{ id: string }>(); @@ -143,8 +162,9 @@ const ProductFormPage = () => { variants: formVariants }); const initialImages = (product.file_ids && product.file_ids.length > 0 ? product.file_ids : (product as any).files || []); - setUploadedImages(initialImages); - setValue('file_ids', initialImages, { shouldValidate: true, shouldDirty: false }); + const normalizedImages: ProductImage[] = (initialImages || []).map(toPublicUrl); + setUploadedImages(normalizedImages); + setValue('file_ids', normalizedImages, { shouldValidate: true, shouldDirty: false }); } }, [isEdit, product, reset]);