Compare commits
6 Commits
8852f62580
...
79c72517c2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79c72517c2 | ||
|
|
c4e3fcda20 | ||
|
|
0f20ad8ad2 | ||
| dc3b8f4488 | |||
| 0f50d6bed1 | |||
| 44e1f915f4 |
@ -155,25 +155,25 @@ export default function Products() {
|
|||||||
|
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
artNo: '',
|
artNo: '',
|
||||||
|
buyPrice: '' as number | string,
|
||||||
|
priceValue: '' as number | string,
|
||||||
|
wholesalePrice: '' as number | string,
|
||||||
|
priceValueMarginPercent: '' as number | string,
|
||||||
|
wholesaleMarginPercent: '' as number | string,
|
||||||
|
priceDisplay: '',
|
||||||
|
unit: '',
|
||||||
|
packageSize: '' as number | string,
|
||||||
|
dosageLogic: '',
|
||||||
|
suitableFor: 'سگ و گربه',
|
||||||
|
imageUrl: '',
|
||||||
|
metaTitle: '',
|
||||||
|
metaDescription: '',
|
||||||
nameFa: '',
|
nameFa: '',
|
||||||
nameEn: '',
|
nameEn: '',
|
||||||
scientificTagline: '',
|
scientificTagline: '',
|
||||||
description: '',
|
description: '',
|
||||||
shortDescription: '',
|
shortDescription: '',
|
||||||
categoryId: '',
|
categoryId: '',
|
||||||
buyPrice: '' as number | string,
|
|
||||||
priceValue: 0,
|
|
||||||
wholesalePrice: '' as number | string,
|
|
||||||
priceValueMarginPercent: '' as number | string,
|
|
||||||
wholesaleMarginPercent: '' as number | string,
|
|
||||||
priceDisplay: '',
|
|
||||||
unit: '',
|
|
||||||
packageSize: 0,
|
|
||||||
dosageLogic: '',
|
|
||||||
suitableFor: 'سگ و گربه',
|
|
||||||
imageUrl: '',
|
|
||||||
metaTitle: '',
|
|
||||||
metaDescription: '',
|
|
||||||
keywords: '',
|
keywords: '',
|
||||||
canonicalUrl: '',
|
canonicalUrl: '',
|
||||||
slug: '',
|
slug: '',
|
||||||
@ -195,17 +195,24 @@ export default function Products() {
|
|||||||
preorderDeposit: '' as number | string
|
preorderDeposit: '' as number | string
|
||||||
});
|
});
|
||||||
|
|
||||||
const openModal = (product: Product | null = null) => {
|
const openModal = (product?: Product) => {
|
||||||
setMediaImageError(false);
|
setMediaImageError(false);
|
||||||
if (product) {
|
if (product) {
|
||||||
setEditingProduct(product);
|
setEditingProduct(product);
|
||||||
updateUrlParams({ modal: 'edit', productId: product.id, tab: activeTab || 'general' });
|
updateUrlParams({ modal: 'edit', productId: product.id, tab: activeTab || 'general' });
|
||||||
|
|
||||||
const bPrice = product.buyPrice ? Number(product.buyPrice) : '';
|
const bPrice = product.buyPrice ? Number(product.buyPrice) : '';
|
||||||
const pPrice = Number(product.priceValue || 0);
|
const pPrice = product.priceValue !== undefined && product.priceValue !== null ? Number(product.priceValue) : '';
|
||||||
const wPrice = product.wholesalePrice ? Number(product.wholesalePrice) : '';
|
const wPrice = product.wholesalePrice !== undefined && product.wholesalePrice !== null ? Number(product.wholesalePrice) : '';
|
||||||
|
|
||||||
const pMargin = bPrice && pPrice ? Math.round(((pPrice - Number(bPrice)) / Number(bPrice)) * 100) : '';
|
let pMargin: number | string = '';
|
||||||
const wMargin = bPrice && wPrice ? Math.round(((wPrice - Number(bPrice)) / Number(bPrice)) * 100) : '';
|
let wMargin: number | string = '';
|
||||||
|
if (bPrice && pPrice !== '') {
|
||||||
|
pMargin = Math.round(((Number(pPrice) - Number(bPrice)) / Number(bPrice)) * 100);
|
||||||
|
}
|
||||||
|
if (bPrice && wPrice !== '') {
|
||||||
|
wMargin = Math.round(((Number(wPrice) - Number(bPrice)) / Number(bPrice)) * 100);
|
||||||
|
}
|
||||||
|
|
||||||
setFormData({
|
setFormData({
|
||||||
artNo: product.artNo || '',
|
artNo: product.artNo || '',
|
||||||
@ -214,7 +221,7 @@ export default function Products() {
|
|||||||
scientificTagline: product.scientificTagline || '',
|
scientificTagline: product.scientificTagline || '',
|
||||||
description: product.description || '',
|
description: product.description || '',
|
||||||
shortDescription: product.shortDescription || '',
|
shortDescription: product.shortDescription || '',
|
||||||
categoryId: product.categoryId || '',
|
categoryId: typeof product.category === 'object' && product.category !== null ? product.category.id : (product.categoryId || ''),
|
||||||
buyPrice: bPrice,
|
buyPrice: bPrice,
|
||||||
priceValue: pPrice,
|
priceValue: pPrice,
|
||||||
wholesalePrice: wPrice,
|
wholesalePrice: wPrice,
|
||||||
@ -222,7 +229,7 @@ export default function Products() {
|
|||||||
wholesaleMarginPercent: wMargin,
|
wholesaleMarginPercent: wMargin,
|
||||||
priceDisplay: product.priceDisplay || '',
|
priceDisplay: product.priceDisplay || '',
|
||||||
unit: product.unit || '',
|
unit: product.unit || '',
|
||||||
packageSize: Number(product.packageSize) || 0,
|
packageSize: product.packageSize !== undefined && product.packageSize !== null ? Number(product.packageSize) : '',
|
||||||
dosageLogic: product.dosageLogic || '',
|
dosageLogic: product.dosageLogic || '',
|
||||||
suitableFor: product.suitableFor || 'سگ و گربه',
|
suitableFor: product.suitableFor || 'سگ و گربه',
|
||||||
imageUrl: product.imageUrl || '',
|
imageUrl: product.imageUrl || '',
|
||||||
@ -246,15 +253,15 @@ export default function Products() {
|
|||||||
pdfCover: product.pdfCover || '',
|
pdfCover: product.pdfCover || '',
|
||||||
symptoms: product.symptoms ? product.symptoms.map((s: { symptom: string } | string) => typeof s === 'string' ? s : s.symptom) : [],
|
symptoms: product.symptoms ? product.symptoms.map((s: { symptom: string } | string) => typeof s === 'string' ? s : s.symptom) : [],
|
||||||
isPreorder: Boolean(product.isPreorder),
|
isPreorder: Boolean(product.isPreorder),
|
||||||
preorderDeposit: product.preorderDeposit || ''
|
preorderDeposit: product.preorderDeposit !== undefined && product.preorderDeposit !== null ? product.preorderDeposit : ''
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setEditingProduct(null);
|
setEditingProduct(null);
|
||||||
updateUrlParams({ modal: 'create', productId: undefined, tab: activeTab || 'general' });
|
updateUrlParams({ modal: 'create', productId: undefined, tab: activeTab || 'general' });
|
||||||
setFormData({
|
setFormData({
|
||||||
artNo: '', nameFa: '', nameEn: '', scientificTagline: '', description: '', shortDescription: '', categoryId: '',
|
artNo: '', nameFa: '', nameEn: '', scientificTagline: '', description: '', shortDescription: '', categoryId: '',
|
||||||
buyPrice: '', priceValue: 0, wholesalePrice: '', priceValueMarginPercent: '', wholesaleMarginPercent: '',
|
buyPrice: '', priceValue: '', wholesalePrice: '', priceValueMarginPercent: '', wholesaleMarginPercent: '',
|
||||||
priceDisplay: '', unit: '', packageSize: 0, dosageLogic: '', suitableFor: 'سگ و گربه',
|
priceDisplay: '', unit: '', packageSize: '', dosageLogic: '', suitableFor: 'سگ و گربه',
|
||||||
imageUrl: '', metaTitle: '', metaDescription: '', keywords: '', canonicalUrl: '', slug: '',
|
imageUrl: '', metaTitle: '', metaDescription: '', keywords: '', canonicalUrl: '', slug: '',
|
||||||
images: [],
|
images: [],
|
||||||
podcastUrl: '', podcastTitle: '', podcastDescription: '', podcastCover: '',
|
podcastUrl: '', podcastTitle: '', podcastDescription: '', podcastCover: '',
|
||||||
@ -1111,7 +1118,16 @@ export default function Products() {
|
|||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 pt-2">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 pt-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-bold text-gray-700">موجودی *</label>
|
<label className="text-sm font-bold text-gray-700">موجودی *</label>
|
||||||
<input required type="number" min="0" value={formData.packageSize} onChange={(e) => setFormData({ ...formData, packageSize: Number(e.target.value) })} className="w-full px-4 py-3 rounded-xl border border-gray-200 focus:border-purple-500 outline-none" dir="ltr" />
|
<input
|
||||||
|
required
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
placeholder="0"
|
||||||
|
value={formData.packageSize === '' ? '' : formData.packageSize}
|
||||||
|
onChange={(e) => setFormData({ ...formData, packageSize: e.target.value === '' ? '' : Number(e.target.value) })}
|
||||||
|
className="w-full px-4 py-3 rounded-xl border border-gray-200 focus:border-purple-500 outline-none text-left font-mono font-bold"
|
||||||
|
dir="ltr"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-bold text-gray-700">واحد سنجش</label>
|
<label className="text-sm font-bold text-gray-700">واحد سنجش</label>
|
||||||
|
|||||||
@ -178,7 +178,18 @@ export default function ZibalPortalPage() {
|
|||||||
try {
|
try {
|
||||||
setLoadingQueue(true);
|
setLoadingQueue(true);
|
||||||
const res = await api.get('/payment/admin/checkout-queue');
|
const res = await api.get('/payment/admin/checkout-queue');
|
||||||
const items = Array.isArray(res.data) ? res.data : (res.data?.data || []);
|
let items: any[] = [];
|
||||||
|
if (Array.isArray(res.data)) {
|
||||||
|
items = res.data;
|
||||||
|
} else if (res.data?.data && Array.isArray(res.data.data)) {
|
||||||
|
items = res.data.data;
|
||||||
|
} else if (res.data?.queue && Array.isArray(res.data.queue)) {
|
||||||
|
items = res.data.queue;
|
||||||
|
} else if (res.data?.checkouts && Array.isArray(res.data.checkouts)) {
|
||||||
|
items = res.data.checkouts;
|
||||||
|
} else if (res.data?.checkoutList && Array.isArray(res.data.checkoutList)) {
|
||||||
|
items = res.data.checkoutList;
|
||||||
|
}
|
||||||
setQueueItems(items);
|
setQueueItems(items);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
toast.error('خطا در دریافت صف تسویههای در انتظار');
|
toast.error('خطا در دریافت صف تسویههای در انتظار');
|
||||||
|
|||||||
@ -170,7 +170,11 @@ const ArchiveProductCard: React.FC<{ product: Product }> = ({ product }) => {
|
|||||||
) : (
|
) : (
|
||||||
<span className="text-xs font-bold text-amber-600 bg-amber-50 px-2 py-1 rounded-md">تماس جهت استعلام قیمت</span>
|
<span className="text-xs font-bold text-amber-600 bg-amber-50 px-2 py-1 rounded-md">تماس جهت استعلام قیمت</span>
|
||||||
)}
|
)}
|
||||||
{!useSettingsStore.getState().getText("catalog_disable_cart", "false").includes("true") && (() => {
|
{(product.packageSize !== undefined && product.packageSize !== null ? Number(product.packageSize) : 100) <= 0 ? (
|
||||||
|
<span className="px-2.5 py-1.5 rounded-xl bg-rose-50 text-rose-600 border border-rose-100 text-[11px] font-bold font-vazir">
|
||||||
|
ناموجود
|
||||||
|
</span>
|
||||||
|
) : !useSettingsStore.getState().getText("catalog_disable_cart", "false").includes("true") && (() => {
|
||||||
const cartItem = useCartStore.getState().items.find(i => i.product.id === product.id);
|
const cartItem = useCartStore.getState().items.find(i => i.product.id === product.id);
|
||||||
if (cartItem && cartItem.quantity > 0) {
|
if (cartItem && cartItem.quantity > 0) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -85,7 +85,7 @@ function ProductCard({ product }: { product: Product }) {
|
|||||||
>
|
>
|
||||||
<Eye className="w-5 h-5" />
|
<Eye className="w-5 h-5" />
|
||||||
</div>
|
</div>
|
||||||
{allowCart && (
|
{allowCart && (product.packageSize !== undefined && product.packageSize !== null ? Number(product.packageSize) : 100) > 0 && (
|
||||||
<div
|
<div
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|||||||
@ -143,7 +143,7 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...apiProduct,
|
...apiProduct,
|
||||||
packageSize: apiProduct.packageSize || 100,
|
packageSize: apiProduct.packageSize !== undefined && apiProduct.packageSize !== null ? Number(apiProduct.packageSize) : 100,
|
||||||
};
|
};
|
||||||
}, [product, allProducts]);
|
}, [product, allProducts]);
|
||||||
|
|
||||||
@ -185,8 +185,8 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
|
|||||||
dailyDose = Math.max(1, Math.round(weight * factor));
|
dailyDose = Math.max(1, Math.round(weight * factor));
|
||||||
}
|
}
|
||||||
|
|
||||||
const packageSize = fullProduct.packageSize || 100;
|
const packageSize = fullProduct.packageSize !== undefined && fullProduct.packageSize !== null ? Number(fullProduct.packageSize) : 100;
|
||||||
const duration = Math.max(1, Math.floor(packageSize / (dailyDose || 1)));
|
const duration = Math.max(1, Math.floor((packageSize || 100) / (dailyDose || 1)));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dailyDose,
|
dailyDose,
|
||||||
@ -220,6 +220,8 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
|
|||||||
);
|
);
|
||||||
if (!product || !fullProduct || !calculation) return <div className="min-h-screen flex items-center justify-center">محصول یافت نشد</div>;
|
if (!product || !fullProduct || !calculation) return <div className="min-h-screen flex items-center justify-center">محصول یافت نشد</div>;
|
||||||
|
|
||||||
|
const isOutOfStock = (product.packageSize !== undefined && product.packageSize !== null ? Number(product.packageSize) : 100) <= 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-medical-gray-50 pt-2 pb-36 sm:pb-20 px-4 sm:px-6 lg:px-8 font-vazir" dir="rtl">
|
<div className="min-h-screen bg-medical-gray-50 pt-2 pb-36 sm:pb-20 px-4 sm:px-6 lg:px-8 font-vazir" dir="rtl">
|
||||||
<div className="max-w-7xl mx-auto w-full">
|
<div className="max-w-7xl mx-auto w-full">
|
||||||
@ -274,10 +276,16 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
|
|||||||
title="کلیک برای مشاهده تصویر بزرگتر"
|
title="کلیک برای مشاهده تصویر بزرگتر"
|
||||||
>
|
>
|
||||||
<div className="absolute top-4 left-4 sm:top-6 sm:left-6 flex flex-col gap-1.5 sm:gap-2 z-10 items-start">
|
<div className="absolute top-4 left-4 sm:top-6 sm:left-6 flex flex-col gap-1.5 sm:gap-2 z-10 items-start">
|
||||||
<div className="px-2.5 py-1 bg-green-500 text-white rounded-full text-[9px] sm:text-[10px] font-black uppercase tracking-widest flex items-center gap-1 font-vazir shadow-sm">
|
{isOutOfStock ? (
|
||||||
<CheckCircle2 className="w-3 h-3" />
|
<div className="px-2.5 py-1 bg-rose-500 text-white rounded-full text-[9px] sm:text-[10px] font-black uppercase tracking-widest flex items-center gap-1 font-vazir shadow-sm">
|
||||||
موجود در انبار
|
ناموجود در انبار
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="px-2.5 py-1 bg-green-500 text-white rounded-full text-[9px] sm:text-[10px] font-black uppercase tracking-widest flex items-center gap-1 font-vazir shadow-sm">
|
||||||
|
<CheckCircle2 className="w-3 h-3" />
|
||||||
|
موجود در انبار
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="px-2.5 py-1 bg-canina-blue text-white rounded-full text-[9px] sm:text-[10px] font-black uppercase tracking-widest font-vazir whitespace-nowrap shadow-sm">
|
<div className="px-2.5 py-1 bg-canina-blue text-white rounded-full text-[9px] sm:text-[10px] font-black uppercase tracking-widest font-vazir whitespace-nowrap shadow-sm">
|
||||||
گرید دارویی اختصاصی
|
گرید دارویی اختصاصی
|
||||||
</div>
|
</div>
|
||||||
@ -1060,6 +1068,14 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
|
|||||||
<Phone className="w-4 h-4" />
|
<Phone className="w-4 h-4" />
|
||||||
استعلام و مشاوره
|
استعلام و مشاوره
|
||||||
</a>
|
</a>
|
||||||
|
) : isOutOfStock ? (
|
||||||
|
<button
|
||||||
|
onClick={() => toast.info("درخواست اطلاعرسانی موجودی ثبت شد")}
|
||||||
|
className="flex-1 bg-amber-500 text-white py-2.5 px-3 rounded-xl font-black text-xs hover:bg-amber-600 transition-all flex items-center justify-center gap-1.5 shadow-md shadow-amber-500/20 whitespace-nowrap"
|
||||||
|
>
|
||||||
|
<Bell className="w-4 h-4" />
|
||||||
|
موجود شد خبر بده
|
||||||
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<div className="flex items-center gap-1 bg-medical-gray-50 border border-medical-gray-200 rounded-xl p-1 h-11">
|
<div className="flex items-center gap-1 bg-medical-gray-50 border border-medical-gray-200 rounded-xl p-1 h-11">
|
||||||
|
|||||||
@ -124,7 +124,7 @@ export class ProductService {
|
|||||||
category: categoryName || '',
|
category: categoryName || '',
|
||||||
categorySlug: data.categorySlug || '',
|
categorySlug: data.categorySlug || '',
|
||||||
unit: data.unit || 'عدد',
|
unit: data.unit || 'عدد',
|
||||||
packageSize: Number(data.packageSize || 100),
|
packageSize: data.packageSize !== undefined && data.packageSize !== null ? Number(data.packageSize) : 100,
|
||||||
dosage_logic: data.dosageLogic || '',
|
dosage_logic: data.dosageLogic || '',
|
||||||
benefits: data.benefits || '',
|
benefits: data.benefits || '',
|
||||||
suitableFor: (data.suitableFor as PetType) || 'سگ',
|
suitableFor: (data.suitableFor as PetType) || 'سگ',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user