@@ -242,8 +246,8 @@ const AdminUsersListPage = () => {
{user.status === 'active' ? 'فعال' : 'غیرفعال'}
@@ -297,8 +301,8 @@ const AdminUsersListPage = () => {
{user.status === 'active' ? 'فعال' : 'غیرفعال'}
@@ -363,7 +367,7 @@ const AdminUsersListPage = () => {
-
+
);
};
diff --git a/src/pages/permissions/permission-form/PermissionFormPage.tsx b/src/pages/permissions/permission-form/PermissionFormPage.tsx
index 8192a4a..701a373 100644
--- a/src/pages/permissions/permission-form/PermissionFormPage.tsx
+++ b/src/pages/permissions/permission-form/PermissionFormPage.tsx
@@ -9,6 +9,7 @@ import { Button } from "@/components/ui/Button";
import { Input } from "@/components/ui/Input";
import { LoadingSpinner } from "@/components/ui/LoadingSpinner";
import { ArrowRight } from "lucide-react";
+import { FormHeader, PageContainer, Label } from '../../../components/ui/Typography';
const permissionSchema = yup.object({
title: yup.string().required('عنوان الزامی است').min(3, 'عنوان باید حداقل 3 کاراکتر باشد'),
@@ -87,26 +88,22 @@ const PermissionFormPage = () => {
}
return (
-
+
{/* Header */}
-
-
-
-
- {isEdit ? 'ویرایش دسترسی' : 'ایجاد دسترسی جدید'}
-
-
- {isEdit ? 'ویرایش اطلاعات دسترسی' : 'اطلاعات دسترسی جدید را وارد کنید'}
-
-
-
+
+
+ بازگشت
+
+ }
+ />
{/* Form */}
@@ -119,9 +116,9 @@ const PermissionFormPage = () => {
/>
-
-
+
);
};
diff --git a/src/pages/permissions/permissions-list/PermissionsListPage.tsx b/src/pages/permissions/permissions-list/PermissionsListPage.tsx
index 98d22a9..73d3b45 100644
--- a/src/pages/permissions/permissions-list/PermissionsListPage.tsx
+++ b/src/pages/permissions/permissions-list/PermissionsListPage.tsx
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { usePermissions } from '../core/_hooks';
import { Permission } from '../core/_models';
import { LoadingSpinner } from "@/components/ui/LoadingSpinner";
-import { Shield } from "lucide-react";
+import { Shield, Plus } from "lucide-react";
// Skeleton Loading Component
const PermissionsTableSkeleton = () => (
@@ -102,6 +102,13 @@ const PermissionsListPage = () => {
نمایش دسترسیهای سیستم
+
{/* Filters */}
diff --git a/src/pages/product-options/product-option-form/ProductOptionFormPage.tsx b/src/pages/product-options/product-option-form/ProductOptionFormPage.tsx
index 5058df1..b966f68 100644
--- a/src/pages/product-options/product-option-form/ProductOptionFormPage.tsx
+++ b/src/pages/product-options/product-option-form/ProductOptionFormPage.tsx
@@ -9,6 +9,7 @@ import { Button } from "@/components/ui/Button";
import { Input } from "@/components/ui/Input";
import { LoadingSpinner } from "@/components/ui/LoadingSpinner";
import { ArrowRight, Settings, Plus, Trash2 } from "lucide-react";
+import { FormHeader, PageContainer, SectionTitle, Label } from '../../../components/ui/Typography';
const maintenanceSchema = yup.object({
title: yup.string().required('عنوان نگهداری الزامی است'),
@@ -115,26 +116,28 @@ const ProductOptionFormPage = () => {
);
}
+ const backButton = (
+
+ );
+
return (
-
-
-
-
-
-
-
-
- {isEdit ? 'ویرایش گزینه محصول' : 'ایجاد گزینه محصول جدید'}
-
-
-
+
+
+
+
- اطلاعات نگهداری
+ اطلاعات نگهداری
+
);
};
diff --git a/src/pages/product-options/product-options-list/ProductOptionsListPage.tsx b/src/pages/product-options/product-options-list/ProductOptionsListPage.tsx
index 23f3b28..98d4f15 100644
--- a/src/pages/product-options/product-options-list/ProductOptionsListPage.tsx
+++ b/src/pages/product-options/product-options-list/ProductOptionsListPage.tsx
@@ -100,20 +100,23 @@ const ProductOptionsListPage = () => {
return (
{/* Header */}
-
+
مدیریت گزینههای محصول
- مدیریت گزینههایی مثل رنگ، سایز، جنس و غیره
+ تنظیمات گزینههای قابل انتخاب برای محصولات
-
+
{/* Filters */}
diff --git a/src/pages/products/core/_models.ts b/src/pages/products/core/_models.ts
index 0c5ea3b..fd473a2 100644
--- a/src/pages/products/core/_models.ts
+++ b/src/pages/products/core/_models.ts
@@ -91,6 +91,7 @@ export interface CreateProductRequest {
total_sold: number;
type: number;
attributes?: Record ;
+ images?: number[];
variants?: CreateVariantRequest[];
}
@@ -105,6 +106,7 @@ export interface UpdateProductRequest {
total_sold: number;
type: number;
attributes?: Record;
+ images?: number[];
variants?: UpdateVariantRequest[];
}
diff --git a/src/pages/products/product-detail/ProductDetailPage.tsx b/src/pages/products/product-detail/ProductDetailPage.tsx
new file mode 100644
index 0000000..cb4f34e
--- /dev/null
+++ b/src/pages/products/product-detail/ProductDetailPage.tsx
@@ -0,0 +1,324 @@
+import { useParams, useNavigate } from 'react-router-dom';
+import { ArrowRight, Edit, Package, Tag, Image, Calendar, FileText, Eye, DollarSign } from 'lucide-react';
+import { Button } from '../../../components/ui/Button';
+import { LoadingSpinner } from '../../../components/ui/LoadingSpinner';
+import { useProduct } from '../core/_hooks';
+import { PRODUCT_TYPE_LABELS } from '../core/_models';
+
+const ProductDetailPage = () => {
+ const navigate = useNavigate();
+ const { id = "" } = useParams();
+
+ const { data: product, isLoading, error } = useProduct(id);
+
+ if (isLoading) return ;
+ if (error) return خطا در بارگذاری اطلاعات محصول ;
+ if (!product) return محصول یافت نشد ;
+
+ const formatPrice = (price: number) => {
+ return new Intl.NumberFormat('fa-IR').format(price) + ' تومان';
+ };
+
+ return (
+
+
+
+
+
+
+ جزئیات محصول
+
+
+
+
+
+
+
+
+
+
+ {/* اطلاعات اصلی */}
+
+
+
+ اطلاعات محصول
+
+
+
+
+
+ {product.description && (
+
+
+ توضیحات
+
+
+
+ {product.description}
+
+
+
+ )}
+
+ {product.design_style && (
+
+
+ سبک طراحی
+
+
+
+ {product.design_style}
+
+
+
+ )}
+
+
+
+
+ نوع محصول
+
+
+
+ {PRODUCT_TYPE_LABELS[product.type] || 'نامشخص'}
+
+
+
+
+
+
+ وضعیت
+
+
+
+ {product.enabled ? 'فعال' : 'غیرفعال'}
+
+
+
+
+
+
+
+ {/* تصاویر محصول */}
+ {product.images && product.images.length > 0 && (
+
+
+ تصاویر محصول
+
+
+ {product.images.map((image, index) => (
+
+ 
+
+
+
+
+ ))}
+
+
+ )}
+
+ {/* محصول متغیر */}
+ {product.variants && product.variants.length > 0 && (
+
+
+ نسخههای محصول
+
+
+ {product.variants.map((variant, index) => (
+
+
+
+ وضعیت:
+
+ {variant.enabled ? 'فعال' : 'غیرفعال'}
+
+
+
+ موجودی:
+
+ {variant.stock_number}
+
+
+
+ وزن:
+
+ {variant.weight} گرم
+
+
+
+ درصد سود:
+
+ {variant.profit_percentage}%
+
+
+
+
+ ))}
+
+
+ )}
+
+
+ {/* اطلاعات جانبی */}
+
+ {/* آمار */}
+
+
+ آمار
+
+
+
+
+
+
+ تعداد فروش
+
+
+
+ {product.total_sold || 0}
+
+
+
+ {product.variants && (
+
+
+
+ {product.variants.length}
+
+
+ )}
+
+ {product.images && (
+
+
+
+
+ تعداد تصاویر
+
+
+
+ {product.images.length}
+
+
+ )}
+
+
+
+ {/* دستهبندیها */}
+ {product.categories && product.categories.length > 0 && (
+
+
+ دستهبندیها
+
+
+ {product.categories.map((category) => (
+
+
+
+ {category.name}
+
+
+ ))}
+
+
+ )}
+
+ {/* گزینه محصول */}
+ {product.product_option && (
+
+
+ گزینه محصول
+
+
+
+ {product.product_option.name}
+
+ {product.product_option.description && (
+
+ {product.product_option.description}
+
+ )}
+
+
+ )}
+
+ {/* اطلاعات زمانی */}
+
+
+ اطلاعات زمانی
+
+
+
+
+
+
+ تاریخ ایجاد
+
+
+
+ {new Date(product.created_at).toLocaleDateString('fa-IR')}
+
+
+
+
+
+
+
+ آخرین بهروزرسانی
+
+
+
+ {new Date(product.updated_at).toLocaleDateString('fa-IR')}
+
+
+
+
+
+
+
+ );
+};
+
+export default ProductDetailPage;
\ No newline at end of file
diff --git a/src/pages/products/product-form/ProductFormPage.tsx b/src/pages/products/product-form/ProductFormPage.tsx
index d6012ea..ae0cdb6 100644
--- a/src/pages/products/product-form/ProductFormPage.tsx
+++ b/src/pages/products/product-form/ProductFormPage.tsx
@@ -15,6 +15,7 @@ import { LoadingSpinner } from "@/components/ui/LoadingSpinner";
import { FileUploader } from "@/components/ui/FileUploader";
import { VariantManager } from "@/components/ui/VariantManager";
import { ArrowRight, Package, X, Plus, Trash2 } from "lucide-react";
+import { FormHeader, PageContainer, SectionTitle, Label } from '../../../components/ui/Typography';
const productSchema = yup.object({
name: yup.string().required('نام محصول الزامی است').min(2, 'نام محصول باید حداقل 2 کاراکتر باشد'),
@@ -67,7 +68,7 @@ const ProductFormPage = () => {
design_style: '',
enabled: true,
total_sold: 0,
- type: 0,
+ type: 1, // هارد کد شده به VARIABLE
category_ids: [],
product_option_id: undefined,
attributes: {},
@@ -80,18 +81,33 @@ const ProductFormPage = () => {
useEffect(() => {
if (isEdit && product) {
+ // تبدیل variants از ProductVariant به ProductVariantFormData
+ const formVariants = product.variants?.map(variant => ({
+ id: variant.id,
+ enabled: variant.enabled,
+ fee_percentage: variant.fee_percentage,
+ profit_percentage: variant.profit_percentage,
+ stock_limit: variant.stock_limit,
+ stock_managed: variant.stock_managed,
+ stock_number: variant.stock_number,
+ weight: variant.weight,
+ attributes: variant.attributes || {},
+ meta: variant.meta || {},
+ images: variant.images || []
+ })) || [];
+
reset({
name: product.name,
description: product.description || '',
design_style: product.design_style || '',
enabled: product.enabled,
total_sold: product.total_sold || 0,
- type: product.type || 0,
+ type: 1, // هارد کد شده به VARIABLE
category_ids: product.category_ids || [],
product_option_id: product.product_option_id || undefined,
attributes: product.attributes || {},
images: product.images || [],
- variants: []
+ variants: formVariants
});
setUploadedImages(product.images || []);
setAttributes(product.attributes || {});
@@ -147,27 +163,63 @@ const ProductFormPage = () => {
};
const onSubmit = (data: ProductFormData) => {
- const submitData = {
- ...data,
+ const baseSubmitData = {
+ name: data.name,
+ description: data.description,
+ design_style: data.design_style,
+ enabled: data.enabled,
+ total_sold: data.total_sold,
+ type: 1, // هارد کد شده به VARIABLE
attributes,
category_ids: data.category_ids.length > 0 ? data.category_ids : [],
product_option_id: data.product_option_id || undefined,
- variants: data.variants || []
+ images: uploadedImages.map(img => parseInt(img.id)) // فقط ID های تصاویر به صورت عدد ارسال میشود
};
- console.log('Submitting product data:', submitData);
+ console.log('Submitting product data:', baseSubmitData);
if (isEdit && id) {
+ // برای update، variants باید شامل ID باشه
+ const updateVariants = data.variants?.map(variant => ({
+ id: variant.id || 0, // اگر ID نداره، 0 بذار (برای variant جدید)
+ enabled: variant.enabled,
+ fee_percentage: variant.fee_percentage,
+ profit_percentage: variant.profit_percentage,
+ stock_limit: variant.stock_limit,
+ stock_managed: variant.stock_managed,
+ stock_number: variant.stock_number,
+ weight: variant.weight,
+ attributes: variant.attributes && Object.keys(variant.attributes).length > 0 ? variant.attributes : {},
+ meta: variant.meta && Object.keys(variant.meta).length > 0 ? variant.meta : {}
+ })) || [];
+
updateProduct({
id: parseInt(id),
- ...submitData
+ ...baseSubmitData,
+ variants: updateVariants
}, {
onSuccess: () => {
navigate('/products');
}
});
} else {
- createProduct(submitData, {
+ // برای create، variants نباید ID داشته باشه
+ const createVariants = data.variants?.map(variant => ({
+ enabled: variant.enabled,
+ fee_percentage: variant.fee_percentage,
+ profit_percentage: variant.profit_percentage,
+ stock_limit: variant.stock_limit,
+ stock_managed: variant.stock_managed,
+ stock_number: variant.stock_number,
+ weight: variant.weight,
+ attributes: variant.attributes && Object.keys(variant.attributes).length > 0 ? variant.attributes : {},
+ meta: variant.meta && Object.keys(variant.meta).length > 0 ? variant.meta : {}
+ })) || [];
+
+ createProduct({
+ ...baseSubmitData,
+ variants: createVariants
+ }, {
onSuccess: () => {
navigate('/products');
}
@@ -199,28 +251,24 @@ const ProductFormPage = () => {
description: `تعداد گزینهها: ${(option.options || []).length}`
}));
+ const backButton = (
+
+ );
+
return (
-
- {/* Header */}
-
-
-
-
-
- {isEdit ? 'ویرایش محصول' : 'ایجاد محصول جدید'}
-
-
- {isEdit ? 'ویرایش اطلاعات محصول' : 'اطلاعات محصول جدید را وارد کنید'}
-
-
-
+
+
{/* Form */}
@@ -251,24 +299,7 @@ const ProductFormPage = () => {
-
-
- نوع محصول
-
-
- {errors.type && (
- {errors.type.message}
- )}
-
+
{
• اولین تصویر به عنوان تصویر اصلی محصول استفاده میشود
-
+
);
};
diff --git a/src/pages/products/products-list/ProductsListPage.tsx b/src/pages/products/products-list/ProductsListPage.tsx
index e4fb54f..ba6ed10 100644
--- a/src/pages/products/products-list/ProductsListPage.tsx
+++ b/src/pages/products/products-list/ProductsListPage.tsx
@@ -143,7 +143,7 @@ const ProductsListPage = () => {
return (
{/* Header */}
-
+
@@ -153,10 +153,13 @@ const ProductsListPage = () => {
مدیریت محصولات، قیمتها و موجودی
-
+
{/* Filters */}
|