From b800dcd40319bb434e11a516611bfb5c466d43cd Mon Sep 17 00:00:00 2001 From: Jakob Wennberg <149234542+jakobwennberg@users.noreply.github.com> Date: Tue, 30 Jun 2026 13:14:13 +0200 Subject: [PATCH] =?UTF-8?q?style(ui):=20system-wide=20UX/UI=20polish=20pas?= =?UTF-8?q?s=20=E2=80=94=20design-system=20conformance=20+=20copy=20cleanu?= =?UTF-8?q?p=20(#835)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * style(ui): system-wide UX/UI polish pass — design-system conformance + copy cleanup Multi-agent scan of all 404 UI files against the locked design system, then 141 verified surgical fixes across 109 files (net -32 lines): - Remove forbidden elevation/motion: shadow-* and rounded-xl on cards, active:scale bounce, hover:shadow on list items, transition-all -> transition-colors. - Drop font-medium from single-weight Hedvig display headings/numerals. - Replace raw rainbow Tailwind status colors with Badge variants / brand tokens / neutral surfaces (achromatic chrome, semantic colors stay data-only). - Route raw dates through formatDate(), hand-rolled currency through formatCurrency(), add tabular-nums to financial figures; text-gray-* -> text-foreground tokens. - Swap hand-rolled skeletons for the Skeleton primitive; off-scale spacing -> token scale. - Fix copy: mislabeled "Leverantörsfakturor" -> "Utgifter" on bank-import outflow total, collapse no-op identical-branch ternaries, broken Swedish diacritics (mojibake), correct mismatch-password toast, correct supplier currency-field label. - Remove PII-leaking debug console.log on register, stray console.logs. Verified: tsc clean on all changed files, eslint clean, production build passes. Co-Authored-By: Claude Opus 4.8 (1M context) * fix(auth): sanitize residual error logs in register flow Follow-up to PR review (compliance swarm V16 / GDPR Art.5(1)(f)): the remaining console.error calls in the register flow passed raw error objects, which Supabase may populate with PII (email) in nested fields. Log only sanitized message strings instead. Co-Authored-By: Claude Opus 4.8 (1M context) --------- Co-authored-by: Claude Opus 4.8 (1M context) --- app/(auth)/login/page.tsx | 6 +- app/(auth)/mfa/enroll/page.tsx | 4 +- app/(auth)/mfa/verify/page.tsx | 2 +- app/(auth)/register/page.tsx | 56 +++---------------- app/(auth)/reset-password/page.tsx | 4 +- app/(dashboard)/articles/[id]/page.tsx | 2 +- app/(dashboard)/bookkeeping/[id]/page.tsx | 4 +- .../year-end/periodisering/page.tsx | 2 +- app/(dashboard)/customers/[id]/page.tsx | 2 +- app/(dashboard)/deadlines/page.tsx | 7 ++- app/(dashboard)/error.tsx | 2 +- app/(dashboard)/help/page.tsx | 14 ++--- app/(dashboard)/import/page.tsx | 22 ++++---- app/(dashboard)/invoices/[id]/credit/page.tsx | 2 +- app/(dashboard)/kpi/page.tsx | 2 +- app/(dashboard)/loading.tsx | 8 +-- .../salary/employees/[id]/page.tsx | 2 +- app/(dashboard)/salary/employees/new/page.tsx | 2 +- app/(dashboard)/salary/employees/page.tsx | 2 +- .../runs/[id]/employees/[employeeId]/page.tsx | 4 +- app/(dashboard)/salary/runs/[id]/page.tsx | 4 +- app/(dashboard)/salary/runs/new/page.tsx | 2 +- .../supplier-invoices/[id]/page.tsx | 2 +- .../supplier-invoices/new/page.tsx | 2 +- app/(dashboard)/suppliers/[id]/page.tsx | 8 +-- app/(dashboard)/suppliers/page.tsx | 17 +++--- app/(dashboard)/transactions/page.tsx | 6 +- app/(onboarding)/layout.tsx | 2 +- app/(public)/dpa/page.tsx | 8 +-- app/(public)/invoice-action/[token]/page.tsx | 4 +- app/(public)/privacy/page.tsx | 4 +- app/companies/new/page.tsx | 3 +- app/invite/[token]/page.tsx | 2 +- components/agent/ChatIntakeStarter.tsx | 2 +- components/agent/ChatNewStarter.tsx | 2 +- components/auth/BankIdAuth.tsx | 4 +- components/bookkeeping/CorrectionChain.tsx | 4 +- components/bookkeeping/DocumentUploadZone.tsx | 3 +- .../bookkeeping/JournalEntryReviewContent.tsx | 7 ++- .../bookkeeping/year-end/AccrualsStep.tsx | 2 +- components/dashboard/AgentSetupBanner.tsx | 2 +- components/dashboard/CompanySwitcher.tsx | 4 +- components/dashboard/ConsultantEmptyState.tsx | 6 +- components/dashboard/DashboardContent.tsx | 2 +- components/dashboard/WelcomeOnboarding.tsx | 9 ++- components/deadlines/DeadlineCard.tsx | 2 +- .../general/ArcimMigrationWorkspace.tsx | 6 +- .../extensions/general/BookDirectlyDialog.tsx | 2 +- .../extensions/general/CalendarWorkspace.tsx | 2 +- .../general/InvoiceInboxWorkspace.tsx | 4 +- .../extensions/shared/CsvImportWizard.tsx | 10 ++-- .../shared/ExtensionLoadingSkeleton.tsx | 4 +- components/extensions/shared/KPICard.tsx | 2 +- .../extensions/shared/MonthlyTrendTable.tsx | 4 +- components/extensions/shared/SetupPrompt.tsx | 2 +- components/import/AccountMappingStep.tsx | 2 +- components/import/ArticlesEditStep.tsx | 1 + components/import/BankFileConfirmStep.tsx | 8 +-- components/import/BankFilePreviewStep.tsx | 12 ++-- components/import/ImportResultStep.tsx | 12 ++-- components/import/ImportReviewStep.tsx | 8 +-- components/import/SIEPreviewStep.tsx | 10 ++-- components/import/SuppliersEditStep.tsx | 3 +- components/invoices/InvoiceEditor.tsx | 2 +- components/invoices/InvoiceReviewContent.tsx | 6 +- components/kpi/KPIExpenseMixChart.tsx | 2 +- components/kpi/KPIHeroCards.tsx | 2 +- components/kpi/KPISettingsDialog.tsx | 4 +- components/onboarding/BankIdCompanyPicker.tsx | 2 +- components/onboarding/Step1EntityType.tsx | 4 +- components/onboarding/Step2CompanyDetails.tsx | 2 +- .../onboarding/Step2SectorSelection.tsx | 4 +- .../onboarding/Step3TaxRegistration.tsx | 4 +- components/onboarding/Step4VatAccounting.tsx | 2 +- components/reports/BankReconciliationView.tsx | 4 +- components/reports/INK2DeclarationView.tsx | 12 ++-- components/reports/NEDeclarationView.tsx | 18 +++--- .../reports/PeriodiskSammanstallningView.tsx | 8 +-- components/reports/SkatteverketPanel.tsx | 4 +- components/reports/views/index.tsx | 26 ++++----- components/salary/AGIPanel.tsx | 4 +- components/salary/PaymentFilePanel.tsx | 4 +- components/salary/TaxPaymentPanel.tsx | 4 +- components/settings/AccountDangerZone.tsx | 6 +- components/settings/ApiKeysPanel.tsx | 4 +- components/settings/BackupDownloadForm.tsx | 2 +- components/settings/BankIdSettings.tsx | 2 +- components/settings/BankNameCombobox.tsx | 2 +- components/settings/CompanyDangerZone.tsx | 2 +- .../settings/CounterpartyTemplatesPanel.tsx | 4 +- components/settings/FiscalPeriodEditor.tsx | 4 +- components/settings/LogoUpload.tsx | 4 +- components/settings/SecuritySettings.tsx | 8 +-- components/settings/SettingsRail.tsx | 2 +- .../settings/SkatteverketConnectPanel.tsx | 4 +- components/settings/TaxSettingsForm.tsx | 8 +-- .../sections/AccountSettingsContent.tsx | 4 +- .../skattekonto/SkattekontoMatchDialog.tsx | 6 +- components/suppliers/SupplierForm.tsx | 2 +- .../SupplierInvoiceReviewContent.tsx | 16 +++--- components/transactions/QuickReviewDialog.tsx | 2 +- .../TransactionAttachDocumentDialog.tsx | 4 +- components/ui/data-list.tsx | 2 +- components/ui/empty-state.tsx | 2 +- components/ui/info-tooltip.tsx | 2 +- components/ui/success-animation.tsx | 2 +- components/ui/tag-input.tsx | 2 +- messages/en.json | 2 + messages/sv.json | 2 + 109 files changed, 270 insertions(+), 302 deletions(-) diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx index 2582262d..e3a0e5c6 100644 --- a/app/(auth)/login/page.tsx +++ b/app/(auth)/login/page.tsx @@ -276,7 +276,7 @@ function LoginPageContent() {

-
+

{showResetPassword ? tAuth('email_sent_hint_reset') : tAuth('email_sent_hint_login')}

@@ -327,7 +327,7 @@ function LoginPageContent() {

-
+
@@ -382,7 +382,7 @@ function LoginPageContent() {

-
+
{callbackError === 'auth_error' && (

diff --git a/app/(auth)/mfa/enroll/page.tsx b/app/(auth)/mfa/enroll/page.tsx index eed9c2f8..33ab7808 100644 --- a/app/(auth)/mfa/enroll/page.tsx +++ b/app/(auth)/mfa/enroll/page.tsx @@ -188,7 +188,7 @@ function MfaEnrollContent() {

-
+

@@ -242,7 +242,7 @@ function MfaEnrollContent() {

-
+
{/* QR Code */}
-
+
diff --git a/app/(auth)/register/page.tsx b/app/(auth)/register/page.tsx index 0fe8221f..ab4d685e 100644 --- a/app/(auth)/register/page.tsx +++ b/app/(auth)/register/page.tsx @@ -140,7 +140,7 @@ function RegisterPageContent() { }) if (error) { - console.error('[register] BankID verifyOtp failed', error) + console.error('[register] BankID verifyOtp failed', error.message) toast({ title: t('register_failed_complete'), description: getErrorMessage(error, { context: 'auth', locale: errorLocale }), @@ -152,7 +152,7 @@ function RegisterPageContent() { router.push('/select-company') router.refresh() } catch (error) { - console.error('[register] BankID signup error', error) + console.error('[register] BankID signup error', error instanceof Error ? error.message : String(error)) toast({ title: t('register_failed_title'), description: getErrorMessage(error, { context: 'auth', locale: errorLocale }), @@ -201,14 +201,6 @@ function RegisterPageContent() { } try { - console.log('[register] attempting signUp', { - email: emailValue, - hasPassword: !!passwordValue, - passwordLength: passwordValue.length, - redirectTo: `${window.location.origin}/auth/callback`, - supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL, - }) - const { data, error } = await supabase.auth.signUp({ email: emailValue, password: passwordValue, @@ -218,15 +210,7 @@ function RegisterPageContent() { }) if (error) { - console.error('[register] signUp error', { - message: error.message, - code: error.code, - status: error.status, - name: error.name, - stack: error.stack, - cause: error.cause, - fullError: JSON.stringify(error, Object.getOwnPropertyNames(error)), - }) + console.error('[register] signUp error', error.message) toast({ title: t('register_failed_title'), description: getErrorMessage(error, { context: 'auth', locale: errorLocale }), @@ -235,16 +219,6 @@ function RegisterPageContent() { return } - console.log('[register] signUp response', { - userId: data.user?.id, - email: data.user?.email, - isAnonymous: data.user?.is_anonymous, - identities: data.user?.identities?.length, - hasSession: !!data.session, - confirmationSentAt: data.user?.confirmation_sent_at, - provider: data.user?.app_metadata?.provider, - }) - // If auto-confirmed (local dev), process invite immediately and redirect if (data.session) { const cookieMatch = document.cookie.match(/gnubok-invite-token=([^;]+)/) @@ -260,19 +234,11 @@ function RegisterPageContent() { if (res.ok) { document.cookie = 'gnubok-invite-token=; path=/; max-age=0' - console.log('[register] invite accepted after auto-confirm — redirecting') window.location.href = '/' return } - - // Log the error response so we can diagnose invite failures - const errBody = await res.json().catch(() => ({})) - console.error('[register] invite acceptance returned non-ok', { - status: res.status, - error: errBody.error, - }) } catch (err) { - console.error('[register] invite acceptance failed:', err) + console.error('[register] invite acceptance failed:', err instanceof Error ? err.message : String(err)) } } @@ -294,13 +260,7 @@ function RegisterPageContent() { setEmail(emailValue) setIsRegistered(true) } catch (error) { - console.error('[register] unexpected exception', { - error, - message: error instanceof Error ? error.message : String(error), - stack: error instanceof Error ? error.stack : undefined, - type: typeof error, - constructor: error?.constructor?.name, - }) + console.error('[register] unexpected exception', error instanceof Error ? error.message : String(error)) toast({ title: t('register_failed_title'), description: getErrorMessage(error, { context: 'auth', locale: errorLocale }), @@ -329,7 +289,7 @@ function RegisterPageContent() {

-
+

{t('duplicate_hint')}

@@ -377,7 +337,7 @@ function RegisterPageContent() {

-
+

{t('confirm_email_hint')}

@@ -416,7 +376,7 @@ function RegisterPageContent() {

-
+
{bankIdEnabled && !bankIdUser && ( <>
diff --git a/app/(auth)/reset-password/page.tsx b/app/(auth)/reset-password/page.tsx index aa589f05..446c1ac2 100644 --- a/app/(auth)/reset-password/page.tsx +++ b/app/(auth)/reset-password/page.tsx @@ -40,7 +40,7 @@ export default function ResetPasswordPage() { if (password !== confirmPassword) { toast({ title: t('mismatch_title'), - description: t('weak_description'), + description: t('mismatch_description'), variant: 'destructive', }) setIsLoading(false) @@ -102,7 +102,7 @@ export default function ResetPasswordPage() {

-
+
diff --git a/app/(dashboard)/articles/[id]/page.tsx b/app/(dashboard)/articles/[id]/page.tsx index ab4f3e1c..39461828 100644 --- a/app/(dashboard)/articles/[id]/page.tsx +++ b/app/(dashboard)/articles/[id]/page.tsx @@ -189,7 +189,7 @@ export default function ArticleDetailPage({
-

{article.name}

+

{article.name}

{t(ARTICLE_TYPE_KEY[article.type])} {article.article_number && ( diff --git a/app/(dashboard)/bookkeeping/[id]/page.tsx b/app/(dashboard)/bookkeeping/[id]/page.tsx index f5c2d4d0..458d8dfb 100644 --- a/app/(dashboard)/bookkeeping/[id]/page.tsx +++ b/app/(dashboard)/bookkeeping/[id]/page.tsx @@ -255,7 +255,7 @@ export default function JournalEntryDetailPage({ params }: { params: Promise<{ i
-

+

{formatVoucher(entry)}

@@ -366,7 +366,7 @@ export default function JournalEntryDetailPage({ params }: { params: Promise<{ i {entry.committed_at && (
{t('field_posted_at')} - {new Date(entry.committed_at).toLocaleDateString('sv-SE')} + {formatDate(entry.committed_at)}
)}
diff --git a/app/(dashboard)/bookkeeping/year-end/periodisering/page.tsx b/app/(dashboard)/bookkeeping/year-end/periodisering/page.tsx index c7151a86..ff74a7c8 100644 --- a/app/(dashboard)/bookkeeping/year-end/periodisering/page.tsx +++ b/app/(dashboard)/bookkeeping/year-end/periodisering/page.tsx @@ -808,7 +808,7 @@ function ManualEntryEditor({

{template.name}

-
diff --git a/app/(dashboard)/customers/[id]/page.tsx b/app/(dashboard)/customers/[id]/page.tsx index a7c7b6f3..7c8824d3 100644 --- a/app/(dashboard)/customers/[id]/page.tsx +++ b/app/(dashboard)/customers/[id]/page.tsx @@ -203,7 +203,7 @@ export default function CustomerDetailPage({
-

{customer.name}

+

{customer.name}

{t(CUSTOMER_TYPE_KEY[customer.customer_type])}
diff --git a/app/(dashboard)/deadlines/page.tsx b/app/(dashboard)/deadlines/page.tsx index dbd418ac..db3c87bf 100644 --- a/app/(dashboard)/deadlines/page.tsx +++ b/app/(dashboard)/deadlines/page.tsx @@ -10,6 +10,7 @@ import { DeadlineList } from '@/components/deadlines/DeadlineList' import { PageHeader } from '@/components/ui/page-header' import { AlertTriangle, ArrowRight } from 'lucide-react' import { useCompany } from '@/contexts/CompanyContext' +import { formatCurrency } from '@/lib/utils' import type { Deadline } from '@/types' const supabase = createClient() @@ -224,7 +225,7 @@ export default function DeadlinesPage() { } return ( -
+
{/* Overdue invoices alert */} @@ -235,8 +236,8 @@ export default function DeadlinesPage() {

{t('overdue_invoices', { count: overdueInvoices.count })} - - {overdueInvoices.total.toLocaleString('sv-SE')} kr + + {formatCurrency(overdueInvoices.total)}

diff --git a/app/(dashboard)/error.tsx b/app/(dashboard)/error.tsx index 08adf3e7..38a962c4 100644 --- a/app/(dashboard)/error.tsx +++ b/app/(dashboard)/error.tsx @@ -17,7 +17,7 @@ export default function DashboardError({ return (
-

Nagot gick fel

+

Något gick fel

Ett oväntat fel uppstod. Försök igen eller{' '} kontakta support{' '} diff --git a/app/(dashboard)/help/page.tsx b/app/(dashboard)/help/page.tsx index e886b386..d496ffd1 100644 --- a/app/(dashboard)/help/page.tsx +++ b/app/(dashboard)/help/page.tsx @@ -210,12 +210,12 @@ const glossaryTerms: GlossaryTerm[] = [ ] const categoryConfig = { - skatt: { labelKey: 'category_skatt', icon: Calculator, color: 'bg-orange-500/10 text-orange-600' }, - moms: { labelKey: 'category_moms', icon: Receipt, color: 'bg-blue-500/10 text-blue-600' }, - faktura: { labelKey: 'category_faktura', icon: FileText, color: 'bg-success/10 text-success' }, - bokföring: { labelKey: 'category_bokforing', icon: BookOpen, color: 'bg-purple-500/10 text-purple-600' }, - bank: { labelKey: 'category_bank', icon: Building2, color: 'bg-pink-500/10 text-pink-600' }, - företag: { labelKey: 'category_foretag', icon: Building2, color: 'bg-cyan-500/10 text-cyan-600' }, + skatt: { labelKey: 'category_skatt', icon: Calculator, color: 'bg-secondary text-muted-foreground' }, + moms: { labelKey: 'category_moms', icon: Receipt, color: 'bg-secondary text-muted-foreground' }, + faktura: { labelKey: 'category_faktura', icon: FileText, color: 'bg-secondary text-muted-foreground' }, + bokföring: { labelKey: 'category_bokforing', icon: BookOpen, color: 'bg-secondary text-muted-foreground' }, + bank: { labelKey: 'category_bank', icon: Building2, color: 'bg-secondary text-muted-foreground' }, + företag: { labelKey: 'category_foretag', icon: Building2, color: 'bg-secondary text-muted-foreground' }, } function TermCard({ term, isExpanded, onToggle }: { term: GlossaryTerm; isExpanded: boolean; onToggle: () => void }) { @@ -224,7 +224,7 @@ function TermCard({ term, isExpanded, onToggle }: { term: GlossaryTerm; isExpand const CategoryIcon = config.icon return ( - +

-

{t('title')}

+

{t('title')}

{t('subtitle', { number: invoice.invoice_number ?? '' })}

diff --git a/app/(dashboard)/kpi/page.tsx b/app/(dashboard)/kpi/page.tsx index e1b238b3..2c390256 100644 --- a/app/(dashboard)/kpi/page.tsx +++ b/app/(dashboard)/kpi/page.tsx @@ -82,7 +82,7 @@ export default function KpiPage() { return (
-

{t('title')}

+

{t('title')}

{[1, 2, 3, 4].map((i) => ( -
+
@@ -17,7 +17,7 @@ export default function DashboardLoading() { {/* Income / Expenses */}
{[1, 2].map((i) => ( -
+
@@ -27,12 +27,12 @@ export default function DashboardLoading() { {/* Alerts + deadlines */}
-
+
-
+
{[1, 2, 3].map((i) => (
diff --git a/app/(dashboard)/salary/employees/[id]/page.tsx b/app/(dashboard)/salary/employees/[id]/page.tsx index e73d074a..d3eec73f 100644 --- a/app/(dashboard)/salary/employees/[id]/page.tsx +++ b/app/(dashboard)/salary/employees/[id]/page.tsx @@ -144,7 +144,7 @@ export default function EmployeeDetailPage({ params }: { params: Promise<{ id: s
-

+

{employee.first_name} {employee.last_name}

diff --git a/app/(dashboard)/salary/employees/new/page.tsx b/app/(dashboard)/salary/employees/new/page.tsx index 00018c35..c6206a3d 100644 --- a/app/(dashboard)/salary/employees/new/page.tsx +++ b/app/(dashboard)/salary/employees/new/page.tsx @@ -92,7 +92,7 @@ export default function NewEmployeePage() { -

Ny anställd

+

Ny anställd

diff --git a/app/(dashboard)/salary/employees/page.tsx b/app/(dashboard)/salary/employees/page.tsx index 08c8f923..25ef1783 100644 --- a/app/(dashboard)/salary/employees/page.tsx +++ b/app/(dashboard)/salary/employees/page.tsx @@ -45,7 +45,7 @@ export default function EmployeesPage() {
-

{t('title')}

+

{t('title')}

{t('registered_count', { count: employees.length })}

diff --git a/app/(dashboard)/salary/runs/[id]/employees/[employeeId]/page.tsx b/app/(dashboard)/salary/runs/[id]/employees/[employeeId]/page.tsx index 527a4204..13324de6 100644 --- a/app/(dashboard)/salary/runs/[id]/employees/[employeeId]/page.tsx +++ b/app/(dashboard)/salary/runs/[id]/employees/[employeeId]/page.tsx @@ -168,7 +168,7 @@ export default function SalaryRunEmployeeDetailPage({
-

+

{employee.first_name} {employee.last_name}

@@ -312,7 +312,7 @@ function SummaryCard({ label, value, accent, overridden }: { label: string; valu function AbsenceCount({ label, days }: { label: string; days: number }) { return ( -

+
{label}
{days} dagar
diff --git a/app/(dashboard)/salary/runs/[id]/page.tsx b/app/(dashboard)/salary/runs/[id]/page.tsx index 88bc5069..84911301 100644 --- a/app/(dashboard)/salary/runs/[id]/page.tsx +++ b/app/(dashboard)/salary/runs/[id]/page.tsx @@ -387,7 +387,7 @@ export default function SalaryRunDetailPage({ params }: { params: Promise<{ id:
-

+

Lönekörning {periodLabel}

@@ -426,7 +426,7 @@ export default function SalaryRunDetailPage({ params }: { params: Promise<{ id:

{label}

-

+

{formatCurrency(value)}

diff --git a/app/(dashboard)/salary/runs/new/page.tsx b/app/(dashboard)/salary/runs/new/page.tsx index 97e47090..fe22bbec 100644 --- a/app/(dashboard)/salary/runs/new/page.tsx +++ b/app/(dashboard)/salary/runs/new/page.tsx @@ -61,7 +61,7 @@ export default function NewSalaryRunPage() { -

Ny lönekörning

+

Ny lönekörning

diff --git a/app/(dashboard)/supplier-invoices/[id]/page.tsx b/app/(dashboard)/supplier-invoices/[id]/page.tsx index a83310fb..a0ab53ab 100644 --- a/app/(dashboard)/supplier-invoices/[id]/page.tsx +++ b/app/(dashboard)/supplier-invoices/[id]/page.tsx @@ -581,7 +581,7 @@ export default function SupplierInvoiceDetailPage() { {invoice.delivery_date && (
{t('delivery_date_label')} - {invoice.delivery_date} + {formatDate(invoice.delivery_date)}
)} {invoice.payment_reference && ( diff --git a/app/(dashboard)/supplier-invoices/new/page.tsx b/app/(dashboard)/supplier-invoices/new/page.tsx index 300d954f..c1e54d47 100644 --- a/app/(dashboard)/supplier-invoices/new/page.tsx +++ b/app/(dashboard)/supplier-invoices/new/page.tsx @@ -1439,7 +1439,7 @@ export default function NewSupplierInvoicePage() { {/* Valuta & moms — kept inline with the line items because they drive how each row is interpreted. Hidden defaults (SEK + normal moms) collapse to nothing so most users don't see this. */} -
+
-

{supplier.name}

+

{supplier.name}

{supplierTypeLabels[supplier.supplier_type]} {supplier.org_number && t('org_number_inline', { number: supplier.org_number })} @@ -189,7 +189,7 @@ export default function SupplierDetailPage() { {t('outstanding')} -

{formatAmount(supplier.stats?.total_outstanding || 0)} kr

+

{formatAmount(supplier.stats?.total_outstanding || 0)} kr

@@ -197,7 +197,7 @@ export default function SupplierDetailPage() { {t('total_paid')} -

{formatAmount(supplier.stats?.total_paid || 0)} kr

+

{formatAmount(supplier.stats?.total_paid || 0)} kr

@@ -205,7 +205,7 @@ export default function SupplierDetailPage() { {t('invoice_count')} -

{supplier.stats?.invoice_count || 0}

+

{supplier.stats?.invoice_count || 0}

diff --git a/app/(dashboard)/suppliers/page.tsx b/app/(dashboard)/suppliers/page.tsx index 364d4d93..881d0cdf 100644 --- a/app/(dashboard)/suppliers/page.tsx +++ b/app/(dashboard)/suppliers/page.tsx @@ -8,6 +8,7 @@ import { Card, CardContent } from '@/components/ui/card' import { Input } from '@/components/ui/input' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog' import { EmptyState } from '@/components/ui/empty-state' +import { Skeleton } from '@/components/ui/skeleton' import { ReportExportMenu } from '@/components/reports/ReportExportMenu' import { useToast } from '@/components/ui/use-toast' import { Plus, Search, Building2, Lock } from 'lucide-react' @@ -114,7 +115,7 @@ export default function SuppliersPage() {
-

{t('title')}

+

{t('title')}

{t('subtitle')}

@@ -168,13 +169,13 @@ export default function SuppliersPage() { {isLoading ? (
{[1, 2, 3].map((i) => ( - + -
-
+ +
-
-
+ + ))} @@ -206,7 +207,7 @@ export default function SuppliersPage() { const location = formatLocation(supplier) return ( - +

@@ -217,7 +218,7 @@ export default function SuppliersPage() {

-
+
{supplier.org_number && (
{t('label_org_number')}
diff --git a/app/(dashboard)/transactions/page.tsx b/app/(dashboard)/transactions/page.tsx index ff6c46d7..33877330 100644 --- a/app/(dashboard)/transactions/page.tsx +++ b/app/(dashboard)/transactions/page.tsx @@ -2061,7 +2061,7 @@ export default function TransactionsPage() { } return ( -
+
{/* Status bar */} - )} @@ -449,7 +449,7 @@ export function BankIdAuth({ mode, onComplete }: BankIdAuthProps) { {isMobile() && (
-

Oppnar BankID-appen...

+

Öppnar BankID-appen...

)} diff --git a/components/bookkeeping/CorrectionChain.tsx b/components/bookkeeping/CorrectionChain.tsx index 2be6db95..bf8dac98 100644 --- a/components/bookkeeping/CorrectionChain.tsx +++ b/components/bookkeeping/CorrectionChain.tsx @@ -5,7 +5,7 @@ import { useTranslations } from 'next-intl' import { Badge } from '@/components/ui/badge' import { Info } from 'lucide-react' import JournalEntryStatusBadge from '@/components/bookkeeping/JournalEntryStatusBadge' -import { formatDate } from '@/lib/utils' +import { formatDate, formatCurrency } from '@/lib/utils' import { formatVoucher } from '@/lib/bookkeeping/voucher-series-resolver' import type { JournalEntry, JournalEntryLine } from '@/types' @@ -89,7 +89,7 @@ export default function CorrectionChain({ currentEntryId, chain }: Props) { )} - {total.toLocaleString('sv-SE', { minimumFractionDigits: 2 })} kr + {formatCurrency(total)}
{entry.description && ( diff --git a/components/bookkeeping/DocumentUploadZone.tsx b/components/bookkeeping/DocumentUploadZone.tsx index 8aeb29f2..535ca0dc 100644 --- a/components/bookkeeping/DocumentUploadZone.tsx +++ b/components/bookkeeping/DocumentUploadZone.tsx @@ -207,7 +207,7 @@ export default function DocumentUploadZone({
{ e.stopPropagation() diff --git a/components/bookkeeping/JournalEntryReviewContent.tsx b/components/bookkeeping/JournalEntryReviewContent.tsx index 0eb87ee0..cab9524f 100644 --- a/components/bookkeeping/JournalEntryReviewContent.tsx +++ b/components/bookkeeping/JournalEntryReviewContent.tsx @@ -3,6 +3,7 @@ import { Badge } from '@/components/ui/badge' import { AccountNumber } from '@/components/ui/account-number' import { CheckCircle2, Paperclip } from 'lucide-react' +import { formatDate } from '@/lib/utils' interface ReviewLine { account_number: string @@ -58,7 +59,7 @@ export function JournalEntryReviewContent({ {!hideDate && (
Datum -

{entryDate}

+

{formatDate(entryDate)}

)} {voucherSeries && ( @@ -84,7 +85,7 @@ export function JournalEntryReviewContent({ {(showBalanceBadge || (attachmentCount != null && attachmentCount > 0)) && (
{showBalanceBadge && ( - + Debet = Kredit @@ -92,7 +93,7 @@ export function JournalEntryReviewContent({ {attachmentCount != null && attachmentCount > 0 && ( - {attachmentCount} {attachmentCount === 1 ? 'underlag' : 'underlag'} + {attachmentCount} underlag )}
diff --git a/components/bookkeeping/year-end/AccrualsStep.tsx b/components/bookkeeping/year-end/AccrualsStep.tsx index ec6feba6..b9c08aff 100644 --- a/components/bookkeeping/year-end/AccrualsStep.tsx +++ b/components/bookkeeping/year-end/AccrualsStep.tsx @@ -308,7 +308,7 @@ function ManualEntryEditor({ {entry.kind === 'manual_prepaid_expense' && 'Förutbetald kostnad'} {entry.kind === 'manual_accrued_expense' && 'Upplupen kostnad'}

-
diff --git a/components/dashboard/AgentSetupBanner.tsx b/components/dashboard/AgentSetupBanner.tsx index 9c46f300..00568615 100644 --- a/components/dashboard/AgentSetupBanner.tsx +++ b/components/dashboard/AgentSetupBanner.tsx @@ -18,7 +18,7 @@ export default function AgentSetupBanner({ companyName }: Props) { href="/onboarding/agent" className="group block rounded-lg border border-border bg-card hover:bg-secondary/60 transition-colors duration-150 mb-8" > -
+
diff --git a/components/dashboard/CompanySwitcher.tsx b/components/dashboard/CompanySwitcher.tsx index f7afb267..e6f211b6 100644 --- a/components/dashboard/CompanySwitcher.tsx +++ b/components/dashboard/CompanySwitcher.tsx @@ -120,7 +120,7 @@ export default function CompanySwitcher() { return ( {t('add_company')} @@ -133,7 +133,7 @@ export default function CompanySwitcher() { @@ -270,7 +269,7 @@ export default function WelcomeOnboarding({
{/* Greeting header */}
-

+

{greeting}{firstName ? `, ${firstName}` : ''}

@@ -319,7 +318,7 @@ export default function WelcomeOnboarding({

-

+

{stepInfo.title}

diff --git a/components/deadlines/DeadlineCard.tsx b/components/deadlines/DeadlineCard.tsx index 06f7130a..fa3e65f0 100644 --- a/components/deadlines/DeadlineCard.tsx +++ b/components/deadlines/DeadlineCard.tsx @@ -151,7 +151,7 @@ export function DeadlineCard({ {/* Date block */}

{dayNum} diff --git a/components/extensions/general/ArcimMigrationWorkspace.tsx b/components/extensions/general/ArcimMigrationWorkspace.tsx index b234c9e6..7fc4e5bc 100644 --- a/components/extensions/general/ArcimMigrationWorkspace.tsx +++ b/components/extensions/general/ArcimMigrationWorkspace.tsx @@ -395,10 +395,10 @@ function ProviderStep({ setMappings(prev => ({ ...prev, [field.key]: val }))} > - + {headers.map(h => ( @@ -218,7 +218,7 @@ export default function CsvImportWizard({

{importCount} rader importerades

- Fran {fileName} + Från {fileName}