diff --git a/CLAUDE.md b/CLAUDE.md index 43c9f916..844596d8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -406,3 +406,48 @@ Hosted on **Vercel**. Cron jobs in `vercel.json` (banking sync daily 05:00, dead ## Other Never create a NUL/nul file: \gnubok\NUL + +--- + +## Design Context + +### Users + +Swedish sole traders (enskild firma) and small business owners (aktiebolag) who need to manage their own bookkeeping. They are not accountants — they are professionals (consultants, freelancers, shop owners) who want to stay compliant without hiring one. They use gnubok in short, focused sessions: sending an invoice, categorizing bank transactions, filing a VAT declaration. Speed and clarity matter — every second spent in the app is a second away from their real work. + +### Brand Personality + +**Minimal. Sharp. Efficient.** + +gnubok is the tool that makes accounting feel handled. It doesn't try to be fun — it earns trust through precision, clarity, and speed. The interface should feel like a well-made instrument: considered, quiet, and confident. Think Mercury's calm authority applied to Swedish bookkeeping. + +### Aesthetic Direction + +- **Palette**: Grayscale foundation with restrained semantic colors — sage green (success/balance), terracotta (errors/overdue), ochre (warnings/attention). No loud brand color. The absence of color *is* the brand. +- **Typography**: Fraunces (serif) for display headings — adds warmth and distinction to an otherwise minimal interface. Geist (sans) for body — clean, modern, excellent for tabular data. Tabular numbers everywhere financial data appears. +- **Surfaces**: White/near-white cards on light gray backgrounds. Subtle borders (60% opacity). Soft shadows that suggest depth without drama. Dark mode follows the same restraint. +- **Spacing**: Generous whitespace. Let content breathe. Dense data (tables, ledgers) should use tighter spacing but never feel cramped. +- **Motion**: Subtle and purposeful. Stagger animations for list entry, spring easing for interactive feedback. Never decorative — always communicates state change. +- **Icons**: Lucide — consistent 15px in navigation, slightly larger in empty states and actions. +- **Reference**: Mercury (banking) — calm, trustworthy, clean data presentation, financial precision. +- **Anti-reference**: Enterprise software (SAP/Oracle density, overwhelming dashboards with 50 widgets, toolbar soup). + +### Design Principles + +1. **Clarity over cleverness.** Every element should be immediately understandable. Accounting is complex enough — the UI must never add confusion. Use familiar patterns, clear labels (in Swedish), and obvious hierarchy. + +2. **Earned minimalism.** Remove everything that doesn't serve the user's task. But don't strip away context that prevents errors — in accounting, a missing detail can mean a compliance violation. Minimal means *considered*, not *sparse*. + +3. **Numbers are first-class.** Financial data deserves typographic care: tabular-nums, proper alignment, adequate contrast, clear positive/negative distinction. A journal entry grid should feel as precise as a printed ledger. + +4. **Trust through consistency.** Same patterns, same spacing, same behavior everywhere. Buttons work the same way. Cards look the same way. When the user learns one screen, they've learned them all. + +5. **Speed is a feature.** Fast load, fast interaction, fast comprehension. Users are here to get a job done and leave. Optimize for the 90-second session: open app, categorize three transactions, close app. + +### Accessibility + +- Target: **WCAG AA** compliance +- Minimum contrast ratio: 4.5:1 for text, 3:1 for UI components +- All interactive elements keyboard-navigable with visible focus rings +- Respect `prefers-reduced-motion` for users who disable animations +- Color is never the sole indicator of state — always pair with icons, text, or shape diff --git a/app/(dashboard)/bookkeeping/page.tsx b/app/(dashboard)/bookkeeping/page.tsx index 0bfc0e85..baa9f30c 100644 --- a/app/(dashboard)/bookkeeping/page.tsx +++ b/app/(dashboard)/bookkeeping/page.tsx @@ -16,9 +16,9 @@ export default function BookkeepingPage() {
- Verifikationer, kontoplan och manuella bokföringsorder + Skapa verifikationer, hantera kontoplanen och bifoga underlag
Hantera dina kunder och deras faktureringsuppgifter
diff --git a/app/(dashboard)/deadlines/page.tsx b/app/(dashboard)/deadlines/page.tsx index 19149859..4e6797c2 100644 --- a/app/(dashboard)/deadlines/page.tsx +++ b/app/(dashboard)/deadlines/page.tsx @@ -47,8 +47,8 @@ export default function DeadlinesPage() { setOverdueInvoices({ count: overdueCount, total: overdueTotal }) } catch { toast({ - title: 'Fel', - description: 'Kunde inte hamta data', + title: 'Kunde inte ladda deadlines', + description: 'Kontrollera din anslutning och försök igen.', variant: 'destructive', }) } finally { @@ -83,8 +83,8 @@ export default function DeadlinesPage() { fetchData() } catch (error) { toast({ - title: 'Fel', - description: error instanceof Error ? error.message : 'Kunde inte skapa deadline', + title: 'Kunde inte skapa deadline', + description: error instanceof Error ? error.message : 'Försök igen.', variant: 'destructive', }) throw error @@ -111,8 +111,8 @@ export default function DeadlinesPage() { fetchData() } catch (error) { toast({ - title: 'Fel', - description: error instanceof Error ? error.message : 'Kunde inte uppdatera deadline', + title: 'Kunde inte uppdatera status', + description: error instanceof Error ? error.message : 'Försök igen.', variant: 'destructive', }) } @@ -139,8 +139,8 @@ export default function DeadlinesPage() { fetchData() } catch (error) { toast({ - title: 'Fel', - description: error instanceof Error ? error.message : 'Kunde inte uppdatera deadline', + title: 'Kunde inte spara ändringar', + description: error instanceof Error ? error.message : 'Försök igen.', variant: 'destructive', }) } @@ -164,8 +164,8 @@ export default function DeadlinesPage() { fetchData() } catch (error) { toast({ - title: 'Fel', - description: error instanceof Error ? error.message : 'Kunde inte ta bort deadline', + title: 'Kunde inte ta bort deadline', + description: error instanceof Error ? error.message : 'Försök igen.', variant: 'destructive', }) } @@ -175,7 +175,7 @@ export default function DeadlinesPage() { return (Registrera en inkommande faktura
diff --git a/app/(dashboard)/expenses/page.tsx b/app/(dashboard)/expenses/page.tsx index 8b1ef7b1..72dadde2 100644 --- a/app/(dashboard)/expenses/page.tsx +++ b/app/(dashboard)/expenses/page.tsx @@ -75,7 +75,7 @@ export default function ExpensesPage() { .order('due_date', { ascending: true }) if (error) { - toast({ title: 'Fel', description: 'Kunde inte hämta utgifter', variant: 'destructive' }) + toast({ title: 'Kunde inte ladda utgifter', description: 'Kontrollera din anslutning och försök igen.', variant: 'destructive' }) } else { setInvoices(data || []) } @@ -134,7 +134,7 @@ export default function ExpensesPage() {Att betala
-{formatCurrency(stats.unpaidAmount)}
+{formatCurrency(stats.unpaidAmount)}
{stats.unpaidCount} utgifter
Förfallet
-{formatCurrency(stats.overdueAmount)}
+{formatCurrency(stats.overdueAmount)}
{stats.overdueCount} utgifter
> ) : ( <>Totalt antal
-{invoices.length}
+{invoices.length}
> )}Importera banktransaktioner eller bokföringsdata till ditt företag
diff --git a/app/(dashboard)/invoices/[id]/credit/page.tsx b/app/(dashboard)/invoices/[id]/credit/page.tsx index dff488b4..93f89c02 100644 --- a/app/(dashboard)/invoices/[id]/credit/page.tsx +++ b/app/(dashboard)/invoices/[id]/credit/page.tsx @@ -51,8 +51,8 @@ export default function CreateCreditNotePage({ params }: { params: Promise<{ id: if (error || !data) { toast({ - title: 'Fel', - description: 'Kunde inte hämta faktura', + title: 'Kunde inte ladda faktura', + description: 'Fakturan hittades inte.', variant: 'destructive', }) router.push('/invoices') @@ -120,8 +120,8 @@ export default function CreateCreditNotePage({ params }: { params: Promise<{ id: router.push(`/invoices/${creditNote.id}`) } catch (error) { toast({ - title: 'Fel', - description: error instanceof Error ? error.message : 'Kunde inte skapa kreditfaktura', + title: 'Kunde inte skapa kreditfaktura', + description: error instanceof Error ? error.message : 'Försök igen.', variant: 'destructive', }) } @@ -151,7 +151,7 @@ export default function CreateCreditNotePage({ params }: { params: Promise<{ id:Krediterar faktura {invoice.invoice_number}
diff --git a/app/(dashboard)/invoices/[id]/page.tsx b/app/(dashboard)/invoices/[id]/page.tsx index d6882dc9..89c4d2dc 100644 --- a/app/(dashboard)/invoices/[id]/page.tsx +++ b/app/(dashboard)/invoices/[id]/page.tsx @@ -90,8 +90,8 @@ export default function InvoiceDetailPage({ params }: { params: Promise<{ id: st if (error || !data) { toast({ - title: 'Fel', - description: 'Kunde inte hämta faktura', + title: 'Kunde inte ladda faktura', + description: 'Fakturan hittades inte.', variant: 'destructive', }) router.push('/invoices') @@ -211,8 +211,8 @@ export default function InvoiceDetailPage({ params }: { params: Promise<{ id: st fetchInvoice() } catch (error) { toast({ - title: 'Fel', - description: error instanceof Error ? error.message : 'Kunde inte uppdatera status', + title: 'Statusuppdatering misslyckades', + description: error instanceof Error ? error.message : 'Försök igen.', variant: 'destructive', }) } @@ -255,8 +255,8 @@ export default function InvoiceDetailPage({ params }: { params: Promise<{ id: st fetchInvoice() } catch (error) { toast({ - title: 'Fel', - description: error instanceof Error ? error.message : 'Kunde inte skicka fakturan', + title: 'Kunde inte skicka faktura', + description: error instanceof Error ? error.message : 'Försök igen.', variant: 'destructive', }) } @@ -287,8 +287,8 @@ export default function InvoiceDetailPage({ params }: { params: Promise<{ id: st router.push(`/invoices/${data.data.id}`) } catch (error) { toast({ - title: 'Fel', - description: error instanceof Error ? error.message : 'Kunde inte konvertera', + title: 'Konvertering misslyckades', + description: error instanceof Error ? error.message : 'Försök igen.', variant: 'destructive', }) } @@ -324,8 +324,8 @@ export default function InvoiceDetailPage({ params }: { params: Promise<{ id: st }) } catch (error) { toast({ - title: 'Fel', - description: error instanceof Error ? error.message : 'Kunde inte ladda ner PDF', + title: 'Kunde inte ladda ner PDF', + description: error instanceof Error ? error.message : 'Försök igen.', variant: 'destructive', }) } @@ -363,12 +363,12 @@ export default function InvoiceDetailPage({ params }: { params: Promise<{ id: st
diff --git a/app/(dashboard)/invoices/page.tsx b/app/(dashboard)/invoices/page.tsx
index a6cb9a6d..cf038e53 100644
--- a/app/(dashboard)/invoices/page.tsx
+++ b/app/(dashboard)/invoices/page.tsx
@@ -11,17 +11,18 @@ import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { PageHeader } from '@/components/ui/page-header'
import { useToast } from '@/components/ui/use-toast'
import { formatCurrency, formatDate } from '@/lib/utils'
+import { cn } from '@/lib/utils'
import { Plus, Search, Receipt, FileText, Send, CheckCircle, Clock, XCircle, ReceiptText, FileQuestion, Truck } from 'lucide-react'
import { EmptyInvoices } from '@/components/ui/empty-state'
import type { Invoice, InvoiceStatus } from '@/types'
const statusConfig: Record Totalt antal {invoices.length} {invoices.length}
Obetalda
{stats.unpaid}
+{stats.unpaid}
{stats.overdue > 0 && (Att få in
-{formatCurrency(stats.unpaidAmount)}
+{formatCurrency(stats.unpaidAmount)}
Hantera och granska dina kvitton
diff --git a/app/(dashboard)/reports/page.tsx b/app/(dashboard)/reports/page.tsx index 1e07517c..216e7756 100644 --- a/app/(dashboard)/reports/page.tsx +++ b/app/(dashboard)/reports/page.tsx @@ -69,9 +69,9 @@ export default function ReportsPage() {- Huvudbok, grundbok, kundreskontra, saldobalans, resultaträkning, balansräkning, momsdeklaration och mer + Generera skattedeklarationer, resultaträkningar och exportera till Skatteverket
{formatAmount(ledger.total_outstanding)} kr
+{formatAmount(ledger.total_outstanding)} kr
{ledger.unpaid_count} fakturor
{formatAmount(ledger.total_current)} kr
+{formatAmount(ledger.total_current)} kr
{formatAmount(ledger.total_overdue)} kr
+{formatAmount(ledger.total_overdue)} kr
{formatAmount(ledger.total_outstanding)} kr
+{formatAmount(ledger.total_outstanding)} kr
{ledger.unpaid_count} fakturor
{formatAmount(ledger.total_current)} kr
+{formatAmount(ledger.total_current)} kr
{formatAmount(ledger.total_overdue)} kr
+{formatAmount(ledger.total_overdue)} kr
Hantera dina företags- och kontoinställningar
diff --git a/app/(dashboard)/supplier-invoices/[id]/page.tsx b/app/(dashboard)/supplier-invoices/[id]/page.tsx index b7dd37fd..b56e1ac2 100644 --- a/app/(dashboard)/supplier-invoices/[id]/page.tsx +++ b/app/(dashboard)/supplier-invoices/[id]/page.tsx @@ -55,7 +55,7 @@ export default function SupplierInvoiceDetailPage() { const res = await fetch(`/api/supplier-invoices/${params.id}`) const { data, error } = await res.json() if (error) { - toast({ title: 'Fel', description: error, variant: 'destructive' }) + toast({ title: 'Kunde inte ladda leverantörsfaktura', description: error, variant: 'destructive' }) } else { setInvoice(data) setPayAmount(String(data.remaining_amount)) @@ -72,7 +72,7 @@ export default function SupplierInvoiceDetailPage() { const res = await fetch(`/api/supplier-invoices/${params.id}/approve`, { method: 'POST' }) const result = await res.json() if (!res.ok) { - toast({ title: 'Fel', description: result.error, variant: 'destructive' }) + toast({ title: 'Godkännande misslyckades', description: result.error, variant: 'destructive' }) } else { toast({ title: 'Godkänd', description: 'Fakturan har godkänts' }) fetchInvoice() @@ -89,7 +89,7 @@ export default function SupplierInvoiceDetailPage() { }) const result = await res.json() if (!res.ok) { - toast({ title: 'Fel', description: result.error, variant: 'destructive' }) + toast({ title: 'Betalning misslyckades', description: result.error, variant: 'destructive' }) } else { toast({ title: result.status === 'paid' ? 'Betald' : 'Delbetalning registrerad', @@ -113,7 +113,7 @@ export default function SupplierInvoiceDetailPage() { const res = await fetch(`/api/supplier-invoices/${params.id}/credit`, { method: 'POST' }) const result = await res.json() if (!res.ok) { - toast({ title: 'Fel', description: result.error, variant: 'destructive' }) + toast({ title: 'Kreditering misslyckades', description: result.error, variant: 'destructive' }) } else { toast({ title: 'Kreditfaktura registrerad' }) fetchInvoice() @@ -132,7 +132,7 @@ export default function SupplierInvoiceDetailPage() { const res = await fetch(`/api/supplier-invoices/${params.id}`, { method: 'DELETE' }) const result = await res.json() if (!res.ok) { - toast({ title: 'Fel', description: result.error, variant: 'destructive' }) + toast({ title: 'Kunde inte ta bort faktura', description: result.error, variant: 'destructive' }) } else { toast({ title: 'Borttagen' }) router.push('/supplier-invoices') @@ -172,7 +172,7 @@ export default function SupplierInvoiceDetailPage() {Registrera en inkommande faktura (uppfyller BFL verifikationskrav)
diff --git a/app/(dashboard)/supplier-invoices/page.tsx b/app/(dashboard)/supplier-invoices/page.tsx index a5d73c8c..07d256e5 100644 --- a/app/(dashboard)/supplier-invoices/page.tsx +++ b/app/(dashboard)/supplier-invoices/page.tsx @@ -73,7 +73,7 @@ export default function SupplierInvoicesPage() {Registrera och hantera inkommande fakturor
@@ -112,7 +112,7 @@ export default function SupplierInvoicesPage() {{formatAmount(totalUnpaid)} kr
+{formatAmount(totalUnpaid)} kr
{invoices.filter((i) => !['paid', 'credited'].includes(i.status)).length} fakturor
@@ -126,7 +126,7 @@ export default function SupplierInvoicesPage() {{formatAmount(overdueAmount)} kr
+{formatAmount(overdueAmount)} kr
{overdueCount} fakturor
{invoices.length}
+{invoices.length}
{supplierTypeLabels[supplier.supplier_type]}
{supplier.org_number && ` | Org.nr: ${supplier.org_number}`}
@@ -170,7 +170,7 @@ export default function SupplierDetailPage() {
{formatAmount(supplier.stats?.total_outstanding || 0)} kr {formatAmount(supplier.stats?.total_outstanding || 0)} kr {formatAmount(supplier.stats?.total_paid || 0)} kr {formatAmount(supplier.stats?.total_paid || 0)} kr {supplier.stats?.invoice_count || 0} {supplier.stats?.invoice_count || 0}
Hantera dina leverantörer och deras betalningsuppgifter
diff --git a/app/(dashboard)/transactions/page.tsx b/app/(dashboard)/transactions/page.tsx index b8fc63b2..1d58f604 100644 --- a/app/(dashboard)/transactions/page.tsx +++ b/app/(dashboard)/transactions/page.tsx @@ -76,6 +76,10 @@ export default function TransactionsPage() { // Entity type for tooltip context const [entityType, setEntityType] = useState+ Bokför {batchProgress.done} av {batchProgress.total}... +
+ > + ) : ( + <> +diff --git a/app/globals.css b/app/globals.css index 721efca2..d3771a0a 100644 --- a/app/globals.css +++ b/app/globals.css @@ -9,10 +9,10 @@ --background: 0 0% 97%; --foreground: 0 0% 9%; - --card: 0 0% 100%; + --card: 0 0% 99%; --card-foreground: 0 0% 9%; - --popover: 0 0% 100%; + --popover: 0 0% 99%; --popover-foreground: 0 0% 9%; --primary: 0 0% 15%; @@ -22,7 +22,7 @@ --secondary-foreground: 0 0% 9%; --muted: 0 0% 92%; - --muted-foreground: 0 0% 45%; + --muted-foreground: 0 0% 40%; --accent: 0 0% 92%; --accent-foreground: 0 0% 9%; @@ -337,3 +337,21 @@ input[type="number"] { background: hsl(var(--primary) / 0.3); color: hsl(var(--foreground)); } + +/* Respect reduced motion preference */ +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } + + .stagger-enter > * { + animation: none; + opacity: 1; + } + + .hover-lift:hover { + transform: none; + } +} diff --git a/components/bookkeeping/AddAccountDialog.tsx b/components/bookkeeping/AddAccountDialog.tsx index 9ae8d025..a98d0e0e 100644 --- a/components/bookkeeping/AddAccountDialog.tsx +++ b/components/bookkeeping/AddAccountDialog.tsx @@ -118,9 +118,9 @@ export function AddAccountDialog({ open, onOpenChange, onCreated }: AddAccountDi
+
Kontonummer {accountNumber} finns i BAS-standarden. Använd "BAS-katalog"-fliken för att aktivera standardkonton istället.
Inget underlag bifogat
Enligt bokföringslagen (BFL 5 kap. 6-7 §§) ska varje bokföringspost ha en verifikation som
diff --git a/components/bookkeeping/JournalEntryList.tsx b/components/bookkeeping/JournalEntryList.tsx
index f4f5c273..a4519338 100644
--- a/components/bookkeeping/JournalEntryList.tsx
+++ b/components/bookkeeping/JournalEntryList.tsx
@@ -6,7 +6,7 @@ import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Label } from '@/components/ui/label'
import { Switch } from '@/components/ui/switch'
-import { ArrowDownNarrowWide, ArrowUpNarrowWide, ChevronDown, ChevronRight, Paperclip, AlertTriangle, X } from 'lucide-react'
+import { ArrowDownNarrowWide, ArrowUpNarrowWide, ChevronDown, ChevronRight, Paperclip, AlertTriangle, Loader2, BookOpen, X } from 'lucide-react'
import { Input } from '@/components/ui/input'
import { AccountNumber } from '@/components/ui/account-number'
import JournalEntryAttachments from '@/components/bookkeeping/JournalEntryAttachments'
@@ -53,7 +53,7 @@ export default function JournalEntryList({ periodId }: Props) {
const { data } = await res.json()
setAttachmentCounts(data || {})
} catch {
- console.error('Failed to fetch attachment counts')
+ // Non-critical — silently ignore
}
}, [])
@@ -69,6 +69,10 @@ export default function JournalEntryList({ periodId }: Props) {
if (dateTo) params.set('date_to', dateTo)
const res = await fetch(`/api/bookkeeping/journal-entries?${params}`)
+ if (!res.ok) {
+ setLoading(false)
+ return
+ }
const { data, count: total } = await res.json()
const loadedEntries = data || []
setEntries(loadedEntries)
@@ -95,8 +99,9 @@ export default function JournalEntryList({ periodId }: Props) {
if (loading) {
return (
Laddar verifikationer...
+ Verifikationer skapas automatiskt vid fakturering och transaktionsbokföring, eller manuellt via fliken "Ny verifikation".
+ Resultat = 0 ? 'text-success' : 'text-destructive'
+ )}>
+ {formatLargeNumber(summary.mtd.net)}
+ kr
+
+ {formatCurrency(summary.ytd.net)} i år
+ Att få betalt
+ {summary.unpaidInvoicesCount}
+ st
+
+ {formatCurrency(summary.unpaidInvoicesTotal)}
+ Banksaldo
+ {formatLargeNumber(summary.bankBalance)}
+ kr
+ Resultat = 0 ? 'text-success' : 'text-destructive'
- )}>
- {formatLargeNumber(summary.mtd.net)}
- kr
-
- {formatCurrency(summary.ytd.net)} i år
- Banksaldo Koppla bank Importera transaktioner Att få betalt
- {summary.unpaidInvoicesCount}
+ {/* Card 4: Att göra */}
+ Att göra
+ {todoCount}
st
- {formatCurrency(summary.unpaidInvoicesTotal)}
+
+ Behöver åtgärdas
Banksaldo
- {formatLargeNumber(summary.bankBalance)}
- kr
- Banksaldo Koppla bank Importera transaktioner Att göra
- {todoCount}
- st
-
- Åtgärder att hantera
- Allt klart! Allt klart! {action.desc} {action.desc}
{action.description} {action.description}
{action.description} {action.description}Inga verifikationer
+
{line.line_description || ''}
-
+
{Number(line.debit_amount) > 0
? Number(line.debit_amount).toLocaleString('sv-SE', {
minimumFractionDigits: 2,
})
: ''}
-
+
{Number(line.credit_amount) > 0
? Number(line.credit_amount).toLocaleString('sv-SE', {
minimumFractionDigits: 2,
diff --git a/components/dashboard/DashboardContent.tsx b/components/dashboard/DashboardContent.tsx
index 4564521c..e025f1ab 100644
--- a/components/dashboard/DashboardContent.tsx
+++ b/components/dashboard/DashboardContent.tsx
@@ -2,8 +2,7 @@
import { useState, useEffect } from 'react'
import Link from 'next/link'
-import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
-import { Button } from '@/components/ui/button'
+import { Card, CardContent } from '@/components/ui/card'
import { cn, formatCurrency } from '@/lib/utils'
import { UpcomingDeadlinesWidget } from '@/components/deadlines/UpcomingDeadlinesWidget'
import { TaxTodoWidget } from '@/components/deadlines/TaxTodoWidget'
@@ -12,7 +11,7 @@ import {
Receipt,
ArrowLeftRight,
ChevronDown,
- ChevronUp,
+ ChevronRight,
Camera,
Users,
Landmark,
@@ -22,7 +21,7 @@ import {
import { getExtensionDefinition } from '@/lib/extensions/sectors'
import { resolveIcon } from '@/lib/extensions/icon-resolver'
import type { QuickActionDefinition } from '@/lib/extensions/types'
-import type { CompanySettings, EntityType, Deadline, ReceiptQueueSummary, OnboardingProgress } from '@/types'
+import type { CompanySettings, Deadline, ReceiptQueueSummary, OnboardingProgress } from '@/types'
interface DashboardContentProps {
firstName?: string | null
@@ -70,8 +69,6 @@ export default function DashboardContent({ firstName, settings, summary, onboard
return () => window.removeEventListener('extension-toggle-changed', handler)
}, [])
- const entityType = (settings?.entity_type as EntityType) || 'enskild_firma'
-
const formatLargeNumber = (amount: number) => {
return new Intl.NumberFormat('sv-SE', {
style: 'decimal',
@@ -80,15 +77,13 @@ export default function DashboardContent({ firstName, settings, summary, onboard
}).format(amount)
}
- const isNewUser = onboardingProgress && !onboardingProgress.hasInvoices && !onboardingProgress.hasCustomers
-
// Build alert items for "Att hantera" section
const alertItems: React.ReactNode[] = []
if (summary.overdueInvoicesCount > 0) {
alertItems.push(
-
- {(() => {
- const hour = new Date().getHours()
- if (hour < 5) return 'God natt'
- if (hour < 10) return 'Godmorgon'
- if (hour < 14) return 'Hej'
- if (hour < 18) return 'God eftermiddag'
- return 'God kväll'
- })()}{firstName ? `, ${firstName}` : ''}
+ {greeting}{firstName ? `, ${firstName}` : ''}
Att hantera
-