UI badge cleanup + /chart-of-accounts route + loop skills (#850)

Bundles three separable concerns:

- style(ui): badge audit + cleanup across 45 files — real-status chips use Badge variants (raw Tailwind colors dropped), non-status count/type/label chips demoted to muted text, clustered badges consolidated; 20 unused imports removed.
- feat(bookkeeping): Kontoplan moved to a dedicated /chart-of-accounts route (nav + command palette wired); /bookkeeping shows the journal list only.
- chore(skills): loop-* automation skills + design-scan workflow under .claude/.

fix(reports): restored the destructive count badge on blocking errors in the periodisk sammanställning (EC Sales List) — a genuine status cue the audit had wrongly flattened; flagged by the PR reviewer and Swedish compliance bot, now clean.

All CI green; compliance bots report no findings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-07-01 14:29:23 +02:00
committed by GitHub
co-authored by Claude Opus 4.8
parent d63d2aecf0
commit 2da9c71eb3
57 changed files with 613 additions and 315 deletions
@@ -72,7 +72,7 @@ export default function BankSyncSinceLastVisit() {
}
return (
<div className="inline-flex items-center gap-2 rounded-md border border-success/30 bg-success/5 px-2.5 py-1 text-xs text-success">
<div className="inline-flex items-center gap-2 rounded-md border border-border bg-secondary px-2.5 py-1 text-xs text-foreground">
<span>
{count === 1
? t('bank_sync_new_since_last_visit_one')
+2 -3
View File
@@ -17,7 +17,6 @@ import {
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Badge } from '@/components/ui/badge'
import { Skeleton } from '@/components/ui/skeleton'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { useToast } from '@/components/ui/use-toast'
@@ -463,9 +462,9 @@ export default function BulkBookDialog({
<FileText className="h-3.5 w-3.5 text-muted-foreground flex-shrink-0" />
<span className="text-sm font-medium truncate">{tpl.name}</span>
{tpl.is_system && (
<Badge variant="outline" className="text-[10px]">
<span className="flex-shrink-0 text-[10px] text-muted-foreground">
{t('system_badge')}
</Badge>
</span>
)}
</div>
{tpl.description && (
@@ -3,7 +3,6 @@
import { useState, useEffect, useCallback } from 'react'
import { useTranslations } from 'next-intl'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog'
import { useToast } from '@/components/ui/use-toast'
import { formatCurrency, formatDate } from '@/lib/utils'
@@ -316,9 +315,9 @@ export default function QuickReviewDialog({
{isCounterpartyTemplate ? t('label_counterparty_template') : template ? t('label_template') : t('label_category')}
</label>
<div className="mt-1 flex items-center gap-2">
<Badge variant="outline" className="text-sm py-1 px-3">
<span className="text-sm font-medium text-foreground">
{template ? template.name_sv : categoryLabel}
</Badge>
</span>
{onChangeTemplate && !isCounterpartyTemplate && (
<button
type="button"
@@ -151,10 +151,10 @@ export default function SkattekontoInboxCard({
<DataListMeta>
<span className="tabular-nums">{formatDate(row.transaktionsdatum)}</span>
<DataListMetaSeparator />
<Badge variant="outline" className="h-4 gap-1 px-1.5 py-0 text-[10px]">
<span className="inline-flex items-center gap-1 text-muted-foreground">
<Landmark className="h-3 w-3" />
{t('skv_badge')}
</Badge>
</span>
{matchSuggestion && (
<>
<DataListMetaSeparator />
+15 -16
View File
@@ -5,7 +5,7 @@ import { useTranslations } from 'next-intl'
import { Input } from '@/components/ui/input'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Search, ChevronDown, ChevronUp, AlertTriangle, Info, Building2 } from 'lucide-react'
import { Search, ChevronDown, ChevronUp, AlertTriangle, Info, Building2, PenLine } from 'lucide-react'
import {
getCommonTemplates,
getAdvancedTemplates,
@@ -60,6 +60,12 @@ function getVatLabelKey(template: BookingTemplate): string | null {
}
}
// Reverse charge (omvänd moms) carries the ochre emphasis via the sanctioned
// `warning` variant; every other VAT treatment uses the neutral `secondary`.
function getVatBadgeVariant(vatTreatment: string | null | undefined): 'secondary' | 'warning' {
return vatTreatment === 'reverse_charge' ? 'warning' : 'secondary'
}
function groupTemplates(templates: BookingTemplate[]): Map<TemplateGroup, BookingTemplate[]> {
const grouped = new Map<TemplateGroup, BookingTemplate[]>()
for (const t of templates) {
@@ -117,20 +123,17 @@ function LibraryTemplateCard({ raw, converted, selected, onClick }: LibraryTempl
)}
{vatLabelKey && (
<Badge
variant="secondary"
className={`text-[10px] px-1.5 py-0 ${
converted?.vat_treatment === 'reverse_charge'
? 'bg-warning/10 text-warning-foreground'
: ''
}`}
variant={getVatBadgeVariant(converted?.vat_treatment)}
className="text-[10px] px-1.5 py-0"
>
{t(vatLabelKey)}
</Badge>
)}
{!converted && (
<Badge variant="outline" className="text-[10px] px-1.5 py-0">
<span className="inline-flex items-center gap-1 text-[10px] text-muted-foreground">
<PenLine className="h-3 w-3" />
{t('opens_editor_badge')}
</Badge>
</span>
)}
</div>
</div>
@@ -169,18 +172,14 @@ function TemplateCard({ template, selected, onClick, compact }: TemplateCardProp
</span>
{vatLabelKey && (
<Badge
variant="secondary"
className={`text-[10px] px-1.5 py-0 ${
template.vat_treatment === 'reverse_charge'
? 'bg-warning/10 text-warning-foreground'
: ''
}`}
variant={getVatBadgeVariant(template.vat_treatment)}
className="text-[10px] px-1.5 py-0"
>
{t(vatLabelKey)}
</Badge>
)}
{template.requires_vat_registration_data && (
<Badge variant="outline" className="text-[10px] px-1.5 py-0 border-warning/30 text-warning-foreground gap-0.5">
<Badge variant="warning" className="text-[10px] px-1.5 py-0 gap-0.5">
<AlertTriangle className="h-2.5 w-2.5" />
{t('requires_vat_reg')}
</Badge>
@@ -473,13 +473,12 @@ export default function TransactionInboxCard({
{transaction.title_edited_at && (
<>
<DataListMetaSeparator />
<Badge
variant="secondary"
className="h-4 px-1.5 py-0 text-[10px]"
<span
className="text-muted-foreground"
title={originalName ? t('original_name_tooltip', { name: originalName }) : undefined}
>
{t('edited_badge')}
</Badge>
</span>
</>
)}
{skvCounterpartDate && (