diff --git a/.githooks/pre-push b/.githooks/pre-push old mode 100644 new mode 100755 diff --git a/components/admin/products/ProductForm.tsx b/components/admin/products/ProductForm.tsx index 6893cef..bf98f2a 100644 --- a/components/admin/products/ProductForm.tsx +++ b/components/admin/products/ProductForm.tsx @@ -17,6 +17,11 @@ export default function ProductForm({ product, packageName, onSubmit, onCancel, title: '', price: 0, type: 4, // Default to monthly + discounted_price: '', + daily_price: '', + discount: '', + is_best_seller: false, + sort_order: 0, }); const [descriptions, setDescriptions] = useState([]); @@ -28,16 +33,26 @@ export default function ProductForm({ product, packageName, onSubmit, onCancel, title: product.title || '', price: product.price || 0, type: product.type || 4, + discounted_price: product.discounted_price || '', + daily_price: product.daily_price || '', + discount: product.discount || '', + is_best_seller: product.is_best_seller || false, + sort_order: product.sort_order || 0, }); setDescriptions(product.descriptions || []); } }, [product]); const handleInputChange = (e: React.ChangeEvent) => { - const { name, value } = e.target; + const { name, value, type } = e.target; + if (type === 'checkbox') { + const { checked } = e.target as HTMLInputElement; + setFormData(prev => ({ ...prev, [name]: checked })); + return; + } setFormData(prev => ({ ...prev, - [name]: name === 'price' ? parseInt(value) || 0 : value, + [name]: name === 'price' || name === 'sort_order' ? parseInt(value) || 0 : value, })); }; @@ -127,6 +142,91 @@ export default function ProductForm({ product, packageName, onSubmit, onCancel, ))} + + {/* Discounted price (display only) */} +
+ + +
+ + {/* Daily price (display only) */} +
+ + +
+ + {/* Discount (display only) */} +
+ + +
+ + {/* Sort order */} +
+ + +
+ + {/* Best seller */} +
+ +
{/* Descriptions */} diff --git a/components/admin/products/ProductList.tsx b/components/admin/products/ProductList.tsx index 252b448..bb47966 100644 --- a/components/admin/products/ProductList.tsx +++ b/components/admin/products/ProductList.tsx @@ -43,17 +43,42 @@ export default function ProductList({ products, packageName, onEdit, onDelete, i
-

- {product.title || 'بدون عنوان'} -

- - {getProductTypeLabel(product.type)} - +
+

+ {product.title || 'بدون عنوان'} +

+ {product.is_best_seller && ( + + پرفروش‌ترین + + )} +
+
+ + ترتیب: {product.sort_order ?? 0} + + + {getProductTypeLabel(product.type)} + +

قیمت: {formatPrice(product.price)} تومان

+ {(product.discounted_price || product.daily_price || product.discount) && ( +
+ {product.discounted_price && ( + قیمت تخفیف‌خورده: {product.discounted_price} + )} + {product.daily_price && ( + قیمت روزانه: {product.daily_price} + )} + {product.discount && ( + تخفیف: {product.discount} + )} +
+ )} {product.descriptions && product.descriptions.length > 0 && (

ویژگی‌ها:

diff --git a/lib/api/products.ts b/lib/api/products.ts index e65c63e..24b305e 100644 --- a/lib/api/products.ts +++ b/lib/api/products.ts @@ -24,6 +24,9 @@ export const productsApi = { value.forEach((desc, index) => { formData.append(`descriptions[${index}]`, desc); }); + } else if (typeof value === 'boolean') { + // Laravel's boolean rule accepts "1"/"0", not "true"/"false" + formData.append(key, value ? '1' : '0'); } else { formData.append(key, String(value)); } @@ -58,6 +61,9 @@ export const productsApi = { value.forEach((desc, index) => { formData.append(`descriptions[${index}]`, desc); }); + } else if (typeof value === 'boolean') { + // Laravel's boolean rule accepts "1"/"0", not "true"/"false" + formData.append(key, value ? '1' : '0'); } else { formData.append(key, String(value)); } diff --git a/scripts/deploy.sh b/scripts/deploy.sh old mode 100644 new mode 100755 diff --git a/types/product.ts b/types/product.ts index 09373e7..b3e59c0 100644 --- a/types/product.ts +++ b/types/product.ts @@ -8,6 +8,12 @@ export interface Product { created_at: string; updated_at: string; descriptions: string[] | null; + // Display-only text fields (no calculation) + discounted_price: string | null; // قیمت کلی تخفیف خورده + daily_price: string | null; // قیمت روزانه + discount: string | null; // تخفیف + is_best_seller: boolean; // پرفروش‌ترین + sort_order: number; // ترتیب (۰ بالاترین) } export interface CreateProductData { @@ -15,6 +21,11 @@ export interface CreateProductData { price: number; type: number; descriptions?: string[]; + discounted_price?: string; + daily_price?: string; + discount?: string; + is_best_seller?: boolean; + sort_order?: number; } export interface UpdateProductData { @@ -22,6 +33,11 @@ export interface UpdateProductData { price?: number; type?: number; descriptions?: string[]; + discounted_price?: string; + daily_price?: string; + discount?: string; + is_best_seller?: boolean; + sort_order?: number; } export interface ApiResponse {