diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 5fd6b74..7742e2e 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,11 +1,11 @@ -{"id":"books-1rp","title":"http://localhost:3000/kunder","status":"open","priority":2,"issue_type":"task","owner":"nhh@softwarehuset.com","created_at":"2026-01-30T14:30:29.369137+01:00","created_by":"Nicolaj Hartmann","updated_at":"2026-01-30T14:30:29.369137+01:00"} +{"id":"books-1rp","title":"http://localhost:3000/kunder","status":"in_progress","priority":2,"issue_type":"task","owner":"nhh@softwarehuset.com","created_at":"2026-01-30T14:30:29.369137+01:00","created_by":"Nicolaj Hartmann","updated_at":"2026-01-30T14:45:00.573047+01:00"} {"id":"books-5tg","title":"opret et backend job med hangfir\ne som sikrer, at bankkonto altid stemmer med den pågældende konto","status":"closed","priority":2,"issue_type":"task","owner":"nhh@softwarehuset.com","created_at":"2026-01-30T14:24:01.505911+01:00","created_by":"Nicolaj Hartmann","updated_at":"2026-01-30T14:37:08.293897+01:00","closed_at":"2026-01-30T14:37:08.293897+01:00","close_reason":"Closed"} {"id":"books-8ea","title":"fjern brugers navn fra højre hjørne ved profile ikonet","status":"closed","priority":2,"issue_type":"task","owner":"nhh@softwarehuset.com","created_at":"2026-01-30T14:20:16.406033+01:00","created_by":"Nicolaj Hartmann","updated_at":"2026-01-30T14:22:59.64468+01:00","closed_at":"2026-01-30T14:22:59.64468+01:00","close_reason":"Closed"} -{"id":"books-8lo","title":"revisit the laytoug and desig nfor kontooversigten.","status":"open","priority":2,"issue_type":"task","owner":"nhh@softwarehuset.com","created_at":"2026-01-30T14:25:06.620288+01:00","created_by":"Nicolaj Hartmann","updated_at":"2026-01-30T14:25:06.620288+01:00"} +{"id":"books-8lo","title":"revisit the laytoug and desig nfor kontooversigten.","status":"in_progress","priority":2,"issue_type":"task","owner":"nhh@softwarehuset.com","created_at":"2026-01-30T14:25:06.620288+01:00","created_by":"Nicolaj Hartmann","updated_at":"2026-01-30T14:45:00.448995+01:00"} {"id":"books-bj6","title":"Test automatisk pickup","status":"closed","priority":2,"issue_type":"task","owner":"nhh@softwarehuset.com","created_at":"2026-01-30T14:04:40.572496+01:00","created_by":"Nicolaj Hartmann","updated_at":"2026-01-30T14:05:44.401903+01:00","closed_at":"2026-01-30T14:05:44.401903+01:00","close_reason":"completed"} {"id":"books-byl","title":"opret giv et shortlink på frontenden til backend på /hangfire","status":"closed","priority":2,"issue_type":"task","owner":"nhh@softwarehuset.com","created_at":"2026-01-30T14:24:34.946139+01:00","created_by":"Nicolaj Hartmann","updated_at":"2026-01-30T14:40:44.62014+01:00","closed_at":"2026-01-30T14:40:44.62014+01:00","close_reason":"Closed"} {"id":"books-cdf","title":"opret","status":"open","priority":2,"issue_type":"task","owner":"nhh@softwarehuset.com","created_at":"2026-01-30T14:23:39.411558+01:00","created_by":"Nicolaj Hartmann","updated_at":"2026-01-30T14:23:39.411558+01:00"} -{"id":"books-ced","title":"brug smb om regnskab + fropntend designer til at sikrer at alt er godt for både balance og kontooversigt","status":"open","priority":2,"issue_type":"task","owner":"nhh@softwarehuset.com","created_at":"2026-01-30T14:25:46.484629+01:00","created_by":"Nicolaj Hartmann","updated_at":"2026-01-30T14:25:46.484629+01:00"} +{"id":"books-ced","title":"brug smb om regnskab + fropntend designer til at sikrer at alt er godt for både balance og kontooversigt","status":"in_progress","priority":2,"issue_type":"task","owner":"nhh@softwarehuset.com","created_at":"2026-01-30T14:25:46.484629+01:00","created_by":"Nicolaj Hartmann","updated_at":"2026-01-30T14:45:00.511206+01:00"} {"id":"books-h6e","title":"fjern hurtig bogføring og den visning der høre dertil","status":"closed","priority":2,"issue_type":"task","owner":"nhh@softwarehuset.com","created_at":"2026-01-30T14:14:50.436314+01:00","created_by":"Nicolaj Hartmann","updated_at":"2026-01-30T14:18:09.911294+01:00","closed_at":"2026-01-30T14:18:09.911294+01:00","close_reason":"Closed"} {"id":"books-hzt","title":"fix bug med tilføj brugere står forkert med encoded tegn","status":"closed","priority":2,"issue_type":"task","owner":"nhh@softwarehuset.com","created_at":"2026-01-30T14:21:34.556319+01:00","created_by":"Nicolaj Hartmann","updated_at":"2026-01-30T14:28:31.320973+01:00","closed_at":"2026-01-30T14:28:31.320973+01:00","close_reason":"Closed"} {"id":"books-sbm","title":"ændre navnet i venstre side til Books","status":"closed","priority":2,"issue_type":"task","owner":"nhh@softwarehuset.com","created_at":"2026-01-30T14:11:13.017202+01:00","created_by":"Nicolaj Hartmann","updated_at":"2026-01-30T14:12:14.16594+01:00","closed_at":"2026-01-30T14:12:14.16594+01:00","close_reason":"Closed"} diff --git a/frontend/src/lib/formatters.ts b/frontend/src/lib/formatters.ts index 442e86e..3be1bf2 100644 --- a/frontend/src/lib/formatters.ts +++ b/frontend/src/lib/formatters.ts @@ -112,6 +112,28 @@ export function formatCVR(cvr: string): string { return `${cleaned.slice(0, 2)} ${cleaned.slice(2, 4)} ${cleaned.slice(4, 6)} ${cleaned.slice(6, 8)}`; } +/** + * Validate a Danish CVR number using the modulus 11 algorithm + * @param cvr - 8-digit CVR number as string + * @returns true if valid, false otherwise + */ +export function validateCVRModulus11(cvr: string): boolean { + const cleaned = cvr.replace(/\D/g, ''); + if (cleaned.length !== 8) return false; + + // Weights for each position in the CVR number + const weights = [2, 7, 6, 5, 4, 3, 2, 1]; + + // Calculate weighted sum + let sum = 0; + for (let i = 0; i < 8; i++) { + sum += parseInt(cleaned[i], 10) * weights[i]; + } + + // Valid if sum is divisible by 11 + return sum % 11 === 0; +} + /** * Get CSS class for amount (positive/negative/zero) */ diff --git a/frontend/src/pages/Kontooversigt.tsx b/frontend/src/pages/Kontooversigt.tsx index fef9821..a6d9a38 100644 --- a/frontend/src/pages/Kontooversigt.tsx +++ b/frontend/src/pages/Kontooversigt.tsx @@ -16,6 +16,7 @@ import { Tabs, Statistic, message, + Grid, } from 'antd'; import { PlusOutlined, @@ -29,9 +30,13 @@ import { useCompany } from '@/hooks/useCompany'; import { formatCurrency, formatDate } from '@/lib/formatters'; import { getAccountTypeName, getAccountNumberRange } from '@/lib/accounting'; import { accountingColors } from '@/styles/theme'; +import { spacing } from '@/styles/designTokens'; +import { PageHeader } from '@/components/shared/PageHeader'; +import { EmptyState } from '@/components/shared/EmptyState'; import type { Account, AccountType } from '@/types/accounting'; -const { Title, Text } = Typography; +const { Text } = Typography; +const { useBreakpoint } = Grid; // Mock data const mockAccounts: Account[] = [ @@ -71,12 +76,15 @@ const accountTypes: AccountType[] = [ export default function Kontooversigt() { const { company } = useCompany(); + const screens = useBreakpoint(); const [selectedAccount, setSelectedAccount] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); const [editingAccount, setEditingAccount] = useState(null); const [searchText, setSearchText] = useState(''); const [form] = Form.useForm(); + const isMobile = !screens.md; + // Build tree data from accounts const buildTreeData = (): DataNode[] => { return accountTypes.map((type) => { @@ -235,29 +243,29 @@ export default function Kontooversigt() { return (
{/* Header */} -
-
- - Kontooversigt - - {company?.name} -
- -
+ } + onClick={handleCreateAccount} + aria-label="Opret ny konto" + > + Ny konto + + } + /> {/* Summary Cards */} - + - + - + - + - + {/* Main Content */} - + {/* Account Tree */} - } - value={searchText} - onChange={(e) => setSearchText(e.target.value)} - style={{ width: 200 }} - allowClear - /> - } - > + + {/* Search moved outside extra for better mobile UX */} + } + value={searchText} + onChange={(e) => setSearchText(e.target.value)} + style={{ marginBottom: spacing.md }} + allowClear + aria-label="Sog i kontoplan" + /> @@ -343,6 +352,9 @@ export default function Kontooversigt() { {selectedAccount.accountNumber} {selectedAccount.name} + {!selectedAccount.isActive && ( + Inaktiv + )} } size="small" @@ -350,10 +362,13 @@ export default function Kontooversigt() { } + role="region" + aria-label={`Detaljer for konto ${selectedAccount.accountNumber}`} > String(index)} size="small" pagination={{ pageSize: 10 }} + aria-label={`Bevaegelser for konto ${selectedAccount?.accountNumber}`} />
), @@ -435,16 +451,13 @@ export default function Kontooversigt() { ) : ( -
- -
Vælg en konto for at se detaljer
-
+ } + title="Ingen konto valgt" + description="Vaelg en konto i kontoplanen til venstre for at se detaljer og bevaegelser." + compact + />
)}