All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m0s
User Session 20 turn 4: NCC info cơ bản (SĐT + Email), ràng buộc format,
input tiền VND format dấu chấm 1.000.000.
FE-only mirror fe-admin + fe-user.
1. Helpers cấu hình ở top file (gần fmtMoney):
- parseVnd(s): strip non-digit → number (0 nếu rỗng)
- formatVndInput(n): n.toLocaleString('vi-VN') hoặc '' khi n=0
- PHONE_RE /^0\d{9,10}$/ — VN bắt đầu 0, 10-11 digits sau strip space/dash/dot
- EMAIL_RE /^[^\s@]+@[^\s@]+\.[^\s@]+$/
- isValidPhone(s) / isValidEmail(s) — empty OK (optional)
2. NCC inline table HangMucCard — bỏ cột "Liên hệ" tổng hợp (ContactName +
Phone + Email gộp), thay bằng 2 cột riêng:
Trước: NCC | Liên hệ | Điều khoản TT | File báo giá | Số tiền | Action
Sau: NCC | SĐT | Email | Điều khoản TT | File báo giá | Số tiền | Action
SĐT cell font-mono (đọc số rõ); Email cell truncate + title hover full.
3. AddSupplierDialog + EditSupplierDialog — validate phone + email:
- Input type="tel" / type="email" + inputMode + placeholder example
- border-red-300 khi invalid + dòng error text [10px] mt-0.5 red-600
- Disable nút Lưu/Thêm khi hasError = phoneError || emailError
- ContactName + DisplayName + Note + PaymentTermText giữ (optional fields,
backward compat — user nói "cơ bản thôi" áp cho display, dialog giữ
đầy đủ field tránh churn schema)
4. QuoteDialog "Số tiền" input format VND:
- type="text" inputMode="numeric" thay vì type="number" (để format dấu
chấm ngàn không phá bởi browser number parser)
- value={formatVndInput(form.thanhTien)} → display "1.000.000"
- onChange={parseVnd(e.target.value)} → strip non-digit → state raw number
- Suffix span "đ" tuyệt đối inset-y-0 right-3 pointer-events-none
- Hint dưới input: "VND — nhập số, tự format dấu chấm ngàn (vd 1.000.000)"
- Class font-mono text-right pr-12 (chừa chỗ suffix)
Verify:
- npm run build × fe-admin pass
- npm run build × fe-user pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
React + TypeScript + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- @vitejs/plugin-react uses Oxc
- @vitejs/plugin-react-swc uses SWC
React Compiler
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see this documentation.
Expanding the ESLint configuration
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,
// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
You can also install eslint-plugin-react-x and eslint-plugin-react-dom for React-specific lint rules:
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])