fix(ux): replace confirm() with ConfirmModal, fix dark-mode colors, add currency format

- Add reusable ConfirmModal component (themed, Escape key, focus trap)
- Replace all native confirm() calls in Orders, ProductLibrary, Materials, Admin, Billing
- Fix ValidationDialog (Upload.tsx) hardcoded bg-white/text-gray-* → semantic tokens
- Fix NewInvoiceModal (Billing.tsx) hardcoded colors → semantic tokens
- Add formatCurrency (Intl.NumberFormat de-DE/EUR) to NewProductOrder wizard
- Resolves audit issues C1, C3, M3

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 19:59:13 +01:00
parent 9f54bc3ab1
commit 915abe9d74
8 changed files with 307 additions and 45 deletions
+19 -2
View File
@@ -11,6 +11,7 @@ import { toast } from 'sonner'
import { listOrders, searchOrders, deleteOrder } from '../api/orders'
import { fetchThumbnailBlob } from '../api/cad'
import type { Order, OrderDetail, OrderItem } from '../api/orders'
import ConfirmModal from '../components/ConfirmModal'
// ── Constants ────────────────────────────────────────────────────────────────
const STATUSES = ['draft', 'submitted', 'processing', 'completed', 'rejected'] as const
@@ -49,6 +50,7 @@ export default function OrdersPage() {
const [dateTo, setDateTo] = useState('')
const [showFilters, setShowFilters] = useState(false)
const [selected, setSelected] = useState<Set<string>>(new Set())
const [confirmState, setConfirmState] = useState<{ open: boolean; title: string; message: string; onConfirm: () => void }>({ open: false, title: '', message: '', onConfirm: () => {} })
// Debounce the search input (400 ms)
useEffect(() => {
@@ -161,8 +163,15 @@ export default function OrdersPage() {
const handleDeleteSelected = () => {
const ids = [...selected]
if (!ids.length) return
if (!confirm(`Delete ${ids.length} order${ids.length > 1 ? 's' : ''}? This cannot be undone.`)) return
deleteMut.mutate(ids)
setConfirmState({
open: true,
title: `Delete ${ids.length} order${ids.length > 1 ? 's' : ''}`,
message: 'This cannot be undone.',
onConfirm: () => {
deleteMut.mutate(ids)
setConfirmState((s) => ({ ...s, open: false }))
},
})
}
// ── Render ───────────────────────────────────────────────────────────────
@@ -351,6 +360,14 @@ export default function OrdersPage() {
/>
)}
<ConfirmModal
open={confirmState.open}
title={confirmState.title}
message={confirmState.message}
onConfirm={confirmState.onConfirm}
onCancel={() => setConfirmState((s) => ({ ...s, open: false }))}
/>
{/* ── Bulk delete bar ───────────────────────────────────────────────── */}
{selected.size > 0 && (
<div className="fixed bottom-6 left-1/2 -translate-x-1/2 ml-[120px] z-50