| NCC |
- Liên hệ |
+ SĐT |
+ Email |
Điều khoản TT |
File báo giá |
Số tiền |
@@ -1355,11 +1419,13 @@ function HangMucCard({
{s.displayName && {s.displayName}
}
{s.note && {s.note}
}
+
+ {s.contactPhone || —}
+ |
- {s.contactName && {s.contactName} }
- {s.contactPhone && {s.contactPhone} }
- {s.contactEmail && {s.contactEmail} }
- {!s.contactName && !s.contactPhone && !s.contactEmail && —}
+ {s.contactEmail
+ ? {s.contactEmail}
+ : —}
|
{s.paymentTermText ?? —}
@@ -1578,12 +1644,19 @@ function QuoteDialog({
Hạng mục: {itemName}
diff --git a/fe-user/src/components/pe/PeDetailTabs.tsx b/fe-user/src/components/pe/PeDetailTabs.tsx
index 4af4413..c853b99 100644
--- a/fe-user/src/components/pe/PeDetailTabs.tsx
+++ b/fe-user/src/components/pe/PeDetailTabs.tsx
@@ -42,6 +42,19 @@ import type { Paged, Supplier } from '@/types/master'
const fmtMoney = (v: number) => v.toLocaleString('vi-VN')
+// Session 20 turn 4 — input helpers cho NCC/Quote inline form.
+// VND format dùng convention VN dấu chấm ngàn (1.000.000). Strip non-digit
+// khi parse user input → number. Empty/0 → empty string để placeholder hiện.
+const parseVnd = (s: string): number => Number(s.replace(/[^\d]/g, '')) || 0
+const formatVndInput = (n: number): string => (n > 0 ? n.toLocaleString('vi-VN') : '')
+
+// Validation cơ bản FE — empty OK (optional fields). BE FluentValidation
+// chưa enforce, FE check để user nhập sai biết ngay.
+const PHONE_RE = /^0\d{9,10}$/ // VN: bắt đầu 0, 10-11 digits sau khi strip space/dash/dot
+const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
+const isValidPhone = (s: string): boolean => !s || PHONE_RE.test(s.replace(/[\s\-.]/g, ''))
+const isValidEmail = (s: string): boolean => !s || EMAIL_RE.test(s)
+
// Main detail content — flat render 3 section không tabs.
// Tên giữ PeDetailTabs để không break callsite (rename gây churn).
//
@@ -1062,6 +1075,10 @@ function AddSupplierDialog({ evaluationId, onClose }: { evaluationId: string; on
paymentTermText: '',
note: '',
})
+ const phoneError = !isValidPhone(form.contactPhone) ? 'SĐT không hợp lệ (cần 10-11 số bắt đầu 0)' : ''
+ const emailError = !isValidEmail(form.contactEmail) ? 'Email không hợp lệ' : ''
+ const hasError = !!(phoneError || emailError)
+
const mut = useMutation({
mutationFn: async () => api.post(`/purchase-evaluations/${evaluationId}/suppliers`, form),
onSuccess: () => { toast.success('Đã thêm NCC.'); qc.invalidateQueries({ queryKey: ['pe-detail', evaluationId] }); onClose() },
@@ -1075,7 +1092,7 @@ function AddSupplierDialog({ evaluationId, onClose }: { evaluationId: string; on
title="Thêm NCC vào phiếu"
footer={<>
-
+
>}
>
@@ -1092,8 +1109,29 @@ function AddSupplierDialog({ evaluationId, onClose }: { evaluationId: string; on
setForm({ ...form, displayName: e.target.value })} placeholder="vd TGN-30 ngày" />
setForm({ ...form, paymentTermText: e.target.value })} placeholder="vd 30 ngày, 300tr" />
setForm({ ...form, contactName: e.target.value })} />
- setForm({ ...form, contactPhone: e.target.value })} />
- setForm({ ...form, contactEmail: e.target.value })} />
+
+
+ setForm({ ...form, contactPhone: e.target.value })}
+ placeholder="0987654321"
+ className={phoneError ? 'border-red-300' : undefined}
+ />
+ {phoneError && {phoneError} }
+
+
+
+ setForm({ ...form, contactEmail: e.target.value })}
+ placeholder="name@example.com"
+ className={emailError ? 'border-red-300' : undefined}
+ />
+ {emailError && {emailError} }
+
setForm({ ...form, note: e.target.value })} placeholder="ĐÃ CHỐT SO SÁNH LẦN 1 / ĐÀM PHÁN THÊM..." />
@@ -1112,6 +1150,10 @@ function EditSupplierDialog({ evaluationId, row, onClose }: { evaluationId: stri
paymentTermText: row.paymentTermText ?? '',
note: row.note ?? '',
})
+ const phoneError = !isValidPhone(form.contactPhone) ? 'SĐT không hợp lệ (cần 10-11 số bắt đầu 0)' : ''
+ const emailError = !isValidEmail(form.contactEmail) ? 'Email không hợp lệ' : ''
+ const hasError = !!(phoneError || emailError)
+
const mut = useMutation({
mutationFn: async () => api.put(`/purchase-evaluations/${evaluationId}/suppliers/${row.id}`, form),
onSuccess: () => { toast.success('Đã cập nhật.'); qc.invalidateQueries({ queryKey: ['pe-detail', evaluationId] }); onClose() },
@@ -1124,15 +1166,36 @@ function EditSupplierDialog({ evaluationId, row, onClose }: { evaluationId: stri
title={`Sửa NCC — ${row.supplierName}`}
footer={<>
-
+
>}
>
@@ -1331,7 +1394,8 @@ function HangMucCard({
| NCC |
- Liên hệ |
+ SĐT |
+ Email |
Điều khoản TT |
File báo giá |
Số tiền |
@@ -1355,11 +1419,13 @@ function HangMucCard({
{s.displayName && {s.displayName} }
{s.note && {s.note} }
+
+ {s.contactPhone || —}
+ |
- {s.contactName && {s.contactName} }
- {s.contactPhone && {s.contactPhone} }
- {s.contactEmail && {s.contactEmail} }
- {!s.contactName && !s.contactPhone && !s.contactEmail && —}
+ {s.contactEmail
+ ? {s.contactEmail}
+ : —}
|
{s.paymentTermText ?? —}
@@ -1578,12 +1644,19 @@ function QuoteDialog({
Hạng mục: {itemName}
| |