feat: add image preview functionality and improve product detail layout in ProductDetailPage
This commit is contained in:
parent
a851fc4a50
commit
afab715b56
|
|
@ -1,4 +1,6 @@
|
||||||
import { useParams, useNavigate } from 'react-router-dom';
|
import { useParams, useNavigate } from 'react-router-dom';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { Modal } from '../../../components/ui/Modal';
|
||||||
import { ArrowRight, Edit, Package, Tag, Image, Calendar, FileText, Eye, DollarSign, Hash, Layers, Settings } from 'lucide-react';
|
import { ArrowRight, Edit, Package, Tag, Image, Calendar, FileText, Eye, DollarSign, Hash, Layers, Settings } from 'lucide-react';
|
||||||
import { Button } from '../../../components/ui/Button';
|
import { Button } from '../../../components/ui/Button';
|
||||||
import { LoadingSpinner } from '../../../components/ui/LoadingSpinner';
|
import { LoadingSpinner } from '../../../components/ui/LoadingSpinner';
|
||||||
|
|
@ -20,6 +22,8 @@ const ProductDetailPage = () => {
|
||||||
return new Intl.NumberFormat('fa-IR').format(price) + ' تومان';
|
return new Intl.NumberFormat('fa-IR').format(price) + ' تومان';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const [previewImage, setPreviewImage] = useState<string | null>(null);
|
||||||
|
|
||||||
const formatNumber = (num: number) => {
|
const formatNumber = (num: number) => {
|
||||||
return new Intl.NumberFormat('fa-IR').format(num);
|
return new Intl.NumberFormat('fa-IR').format(num);
|
||||||
};
|
};
|
||||||
|
|
@ -30,6 +34,7 @@ const ProductDetailPage = () => {
|
||||||
const variants = (product.variants && product.variants.length > 0) ? product.variants : ((product as any).product_variants || []);
|
const variants = (product.variants && product.variants.length > 0) ? product.variants : ((product as any).product_variants || []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
<div className="flex items-center justify-between mb-6">
|
<div className="flex items-center justify-between mb-6">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
|
|
@ -201,7 +206,7 @@ const ProductDetailPage = () => {
|
||||||
<img
|
<img
|
||||||
src={image.url}
|
src={image.url}
|
||||||
alt={image.alt || `تصویر ${index + 1}`}
|
alt={image.alt || `تصویر ${index + 1}`}
|
||||||
className="w-full h-32 object-cover rounded-lg border border-gray-200 dark:border-gray-600"
|
className="w-full h-32 object-cover rounded-lg border border-gray-200 dark:border-gray-600 cursor-pointer" onClick={() => setPreviewImage(image.url)}
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-0 bg-black bg-opacity-50 opacity-0 group-hover:opacity-100 transition-opacity rounded-lg flex items-center justify-center">
|
<div className="absolute inset-0 bg-black bg-opacity-50 opacity-0 group-hover:opacity-100 transition-opacity rounded-lg flex items-center justify-center">
|
||||||
<Eye className="h-6 w-6 text-white" />
|
<Eye className="h-6 w-6 text-white" />
|
||||||
|
|
@ -326,18 +331,18 @@ const ProductDetailPage = () => {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* تصاویر نسخه */}
|
{/* تصاویر نسخه */}
|
||||||
{variant.file_ids && variant.file_ids.length > 0 && (
|
{(variant.file_ids && variant.file_ids.length > 0 || (variant as any).files?.length > 0) && (
|
||||||
<div>
|
<div>
|
||||||
<h5 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
<h5 className="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||||
تصاویر نسخه
|
تصاویر نسخه
|
||||||
</h5>
|
</h5>
|
||||||
<div className="grid grid-cols-4 gap-2">
|
<div className="grid grid-cols-4 gap-2">
|
||||||
{variant.file_ids.map((image, imgIndex) => (
|
{((variant.file_ids && variant.file_ids.length > 0 ? variant.file_ids : (variant as any).files) as any[]).map((image: any, imgIndex: number) => (
|
||||||
<img
|
<img
|
||||||
key={image.id || imgIndex}
|
key={image.id || imgIndex}
|
||||||
src={image.url}
|
src={image.url}
|
||||||
alt={image.alt || `تصویر نسخه ${imgIndex + 1}`}
|
alt={image.alt || `تصویر نسخه ${imgIndex + 1}`}
|
||||||
className="w-full h-16 object-cover rounded border border-gray-200 dark:border-gray-600"
|
className="w-full h-16 object-cover rounded border border-gray-200 dark:border-gray-600 cursor-pointer" onClick={() => setPreviewImage(image.url)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -510,6 +515,12 @@ const ProductDetailPage = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
|
{previewImage && (
|
||||||
|
<Modal isOpen={true} onClose={() => setPreviewImage(null)} title="پیشنمایش تصویر" size="xl">
|
||||||
|
<img src={previewImage} alt="تصویر" className="w-full h-auto object-contain" />
|
||||||
|
</Modal>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,8 +100,8 @@ const ProductFormPage = () => {
|
||||||
console.log('✅ Successfully extracted category IDs:', categoryIds);
|
console.log('✅ Successfully extracted category IDs:', categoryIds);
|
||||||
|
|
||||||
// تبدیل variants از ProductVariant به ProductVariantFormData - handle both variants and product_variants
|
// تبدیل variants از ProductVariant به ProductVariantFormData - handle both variants and product_variants
|
||||||
const variants = product.variants || product.product_variants || [];
|
const variants = product.variants && product.variants.length > 0 ? product.variants : ((product as any).product_variants || []);
|
||||||
const formVariants = variants.map(variant => ({
|
const formVariants = variants.map((variant: any) => ({
|
||||||
id: variant.id,
|
id: variant.id,
|
||||||
enabled: variant.enabled,
|
enabled: variant.enabled,
|
||||||
fee_percentage: variant.fee_percentage,
|
fee_percentage: variant.fee_percentage,
|
||||||
|
|
@ -113,7 +113,7 @@ const ProductFormPage = () => {
|
||||||
product_option_id: variant.product_option_id || undefined,
|
product_option_id: variant.product_option_id || undefined,
|
||||||
attributes: variant.attributes || {},
|
attributes: variant.attributes || {},
|
||||||
meta: variant.meta || {},
|
meta: variant.meta || {},
|
||||||
file_ids: variant.file_ids || []
|
file_ids: (variant.file_ids && variant.file_ids.length > 0 ? variant.file_ids : (variant as any).files || [])
|
||||||
}));
|
}));
|
||||||
|
|
||||||
console.log('✅ Successfully processed variants:', formVariants.length);
|
console.log('✅ Successfully processed variants:', formVariants.length);
|
||||||
|
|
@ -128,10 +128,12 @@ const ProductFormPage = () => {
|
||||||
category_ids: categoryIds,
|
category_ids: categoryIds,
|
||||||
product_option_id: product.product_option_id || undefined,
|
product_option_id: product.product_option_id || undefined,
|
||||||
attributes: product.attributes || {},
|
attributes: product.attributes || {},
|
||||||
file_ids: product.file_ids || [],
|
file_ids: (product.file_ids && product.file_ids.length > 0 ? product.file_ids : (product as any).files || []),
|
||||||
variants: formVariants
|
variants: formVariants
|
||||||
});
|
});
|
||||||
setUploadedImages(product.file_ids || []);
|
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 });
|
||||||
setAttributes(product.attributes || {});
|
setAttributes(product.attributes || {});
|
||||||
}
|
}
|
||||||
}, [isEdit, product, reset]);
|
}, [isEdit, product, reset]);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue