From 8cdf057ab3da3169607786267a949fc5d0e02178 Mon Sep 17 00:00:00 2001 From: BOHA Date: Fri, 27 Mar 2026 13:44:53 +0100 Subject: [PATCH] feat: CNB exchange rates, multi-currency KPI stats, invoice PDF VAT in CZK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ČNB exchange rate service with date-specific rates and caching - Invoice/received invoice stats convert foreign currencies to CZK - Dashboard revenue converts all currencies to CZK - Invoice PDF: VAT recap table always in CZK with CNB rate footer - Inline styles replaced with utility classes (step 4 cleanup) - Spinner animation exempt from prefers-reduced-motion Co-Authored-By: Claude Opus 4.6 (1M context) --- src/admin/base.css | 5 +++ src/admin/pages/Attendance.tsx | 37 +++++---------- src/admin/pages/InvoiceDetail.tsx | 37 +++++---------- src/admin/pages/Invoices.tsx | 2 +- src/admin/pages/OfferDetail.tsx | 24 +++------- src/admin/pages/Offers.tsx | 14 +++--- src/admin/pages/ReceivedInvoices.tsx | 13 +++--- src/admin/pages/Settings.tsx | 27 +++++------ src/routes/admin/dashboard.ts | 12 +++-- src/routes/admin/invoices-pdf.ts | 20 ++++++++- src/routes/admin/received-invoices.ts | 14 +++--- src/services/exchange-rates.ts | 65 +++++++++++++++++++++++++++ src/services/invoices.service.ts | 20 ++++++--- 13 files changed, 173 insertions(+), 117 deletions(-) create mode 100644 src/services/exchange-rates.ts diff --git a/src/admin/base.css b/src/admin/base.css index 17081f6..f9724d5 100644 --- a/src/admin/base.css +++ b/src/admin/base.css @@ -412,4 +412,9 @@ img { transition-duration: 0.01ms !important; scroll-behavior: auto !important; } + + .admin-spinner { + animation-duration: 0.8s !important; + animation-iteration-count: infinite !important; + } } diff --git a/src/admin/pages/Attendance.tsx b/src/admin/pages/Attendance.tsx index 81d6b28..8f2c514 100644 --- a/src/admin/pages/Attendance.tsx +++ b/src/admin/pages/Attendance.tsx @@ -576,10 +576,7 @@ export default function Attendance() {
Projekt {activeProjectId ? ( - + {projects.find( (p) => String(p.id) === String(activeProjectId), ) @@ -587,12 +584,7 @@ export default function Attendance() { : `Projekt #${activeProjectId}`} ) : ( - - Žádný - + Žádný )}
) : null} - + {formatCurrency(lineTotal, currency)} @@ -354,12 +354,7 @@ function SortableInvoiceEditRow({ - - {index + 1} - + {index + 1} {form.due_date && ( - + Splatnost:{" "} {new Date(form.due_date).toLocaleDateString("cs-CZ")} @@ -1448,10 +1440,7 @@ export default function InvoiceDetail() {
-