From de177f352026364ba104133ef3e9b64e183b4491 Mon Sep 17 00:00:00 2001 From: Behrad Date: Sat, 19 Sep 2026 18:57:18 +0330 Subject: [PATCH] style(dashboard): redesign EditModal with solid light theme and tabs --- frontend/src/pages/Dashboard/EditModal.tsx | 798 ++++++++++++--------- 1 file changed, 476 insertions(+), 322 deletions(-) diff --git a/frontend/src/pages/Dashboard/EditModal.tsx b/frontend/src/pages/Dashboard/EditModal.tsx index 76ecb31..fbe49bd 100644 --- a/frontend/src/pages/Dashboard/EditModal.tsx +++ b/frontend/src/pages/Dashboard/EditModal.tsx @@ -1,5 +1,5 @@ import { useEffect, useMemo, useState } from "react"; -import { Trash2, AlertCircle } from "lucide-react"; +import { Trash2, AlertCircle, Plus, Package, CreditCard, Calendar } from "lucide-react"; import { toast } from "sonner"; import type { Attachment, LineItem, Milestone, Quote, Termsheet } from "../../lib/types"; import { api, nextDashedId, nextId } from "../../lib/api"; @@ -52,7 +52,7 @@ interface EditItemRow { interface EditTsCard { key: string; - domId: string; // "" یا "new-ts-..." برای کارت جدید + domId: string; milestones: Milestone[]; } @@ -61,7 +61,6 @@ export interface EditModalProps { onClose: () => void; } -// مودال ویرایش کامل پیشنهاد — بهینه‌شده برای صفحات موبایل export function EditModal({ quoteId, onClose }: EditModalProps) { const quotes = useQuotes(); const suppliers = useSuppliers(); @@ -83,6 +82,7 @@ export function EditModal({ quoteId, onClose }: EditModalProps) { }, [q]); const [ready, setReady] = useState(false); + const [activeTab, setActiveTab] = useState<"items" | "terms" | "dates">("items"); const [supplierName, setSupplierName] = useState(""); const [selectedProjects, setSelectedProjects] = useState([]); const [notes, setNotes] = useState(""); @@ -112,7 +112,6 @@ export function EditModal({ quoteId, onClose }: EditModalProps) { } }; - // گزینه‌های مشخصه const [globalSpecs, setGlobalSpecs] = useState([]); useEffect(() => { let alive = true; @@ -133,7 +132,6 @@ export function EditModal({ quoteId, onClose }: EditModalProps) { return [...set].sort((a, b) => a.localeCompare(b, "fa")); }, [materials, itemRows, globalSpecs]); - // گزینه‌های پروژه const projectOptions = useMemo(() => { const set = new Set(); projects.forEach((p) => p.name && set.add(p.name)); @@ -185,7 +183,6 @@ export function EditModal({ quoteId, onClose }: EditModalProps) { setReady(true); }, [q, suppliers, materials]); - // بارگذاری فاکتورها useEffect(() => { if (!quoteId) return; let alive = true; @@ -221,7 +218,7 @@ export function EditModal({ quoteId, onClose }: EditModalProps) { unit: "", price: null, total: null, - tsDomIds: [], + tsDomIds: tsCards[0] ? [tsCards[0].domId || tsCards[0].key] : [], acceptedTsId: null, rejected: false, restore: true, @@ -252,7 +249,6 @@ export function EditModal({ quoteId, onClose }: EditModalProps) { const next: Quote = JSON.parse(JSON.stringify(q)); - // تأمین‌کننده if (supplierName.trim()) { const norm = normalize(supplierName); const exist = suppliers.find((s) => normalize(s.name) === norm); @@ -270,7 +266,6 @@ export function EditModal({ quoteId, onClose }: EditModalProps) { next.notes = notes.trim(); next.invoices = invoices; - // termsheetها const tsIdMap: Record = {}; const newTermsheets: Termsheet[] = []; tsCards.forEach((card, i) => { @@ -287,7 +282,6 @@ export function EditModal({ quoteId, onClose }: EditModalProps) { }); next.termsheets = newTermsheets; - // اقلام const newItems: LineItem[] = []; const materialsCopy = [...materials]; for (const row of itemRows) { @@ -376,7 +370,6 @@ export function EditModal({ quoteId, onClose }: EditModalProps) { } }); - // تاریخ‌ها و وضعیت next.quote_date = quoteDate || q.quote_date; next.expiry_date = expiryDate ? (expiryDate.length > 10 ? expiryDate.slice(0, 10) : expiryDate) : ""; next.accepted_date = acceptedDate; @@ -416,358 +409,517 @@ export function EditModal({ quoteId, onClose }: EditModalProps) { return ( <> !o && onClose()}> - - - ویرایش پیشنهاد + + {/* هدر سفید و تمیز */} + + ویرایش پیشنهاد خرید +
+ {supplierName ? `تأمین‌کننده: ${supplierName}` : "تنظیم اقلام، مبالغ و شرایط پرداخت"} +
{hasReceipts && ( -
- +
+ این پیشنهاد به‌دلیل ثبت رسید در انبار، غیرقابل ویرایش یا بازگشت است.
)} - {/* اطلاعات بالایی — تک‌ستونه در موبایل، ۲ ستونه در دسکتاپ */} -
-
- -
- setSupplierName(it.label)} - items={suppliers.map((s) => ({ id: s.id, name: s.name }))} - allowAdd - addSuffix="به عنوان تأمین‌کنندهٔ جدید" - placeholder="نام تأمین‌کننده" - onInputChange={(v) => setSupplierName(v)} - /> -
-
+ {/* تب‌بار سفید و استاندارد */} +
+ -
- -
- -
-
+ -
- -