refactor(libra): drop status icons, add Income/Expense badges

Per the iteration: the title-row status icons (green check / yellow
clock / red X) were doing the same job as the new status badges and
amount color, so each row had three signals fighting for the same
meaning. Drop the icons and lean on badges instead.

Badge row order (left-to-right): Voided > Income/Expense > Pending >
user tags. Type badge sits between the high-attention Voided marker
and the secondary Pending marker, so the type chip is easy to spot
on every row.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-06-06 23:05:55 +02:00
commit 58cf5cb762

View file

@ -12,10 +12,6 @@ import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import { Input } from '@/components/ui/input'
import {
CheckCircle2,
Clock,
Flag,
XCircle,
RefreshCw,
Calendar,
Filter
@ -137,25 +133,6 @@ function formatAmount(amount: number): string {
return new Intl.NumberFormat('en-US').format(amount)
}
// Get status icon and color. Voided entries (per libra convention) keep
// flag='!' and carry a 'voided' tag surface that as the icon regardless
// of the underlying flag.
function getStatusInfo(transaction: Transaction) {
if (isVoided(transaction)) {
return { icon: XCircle, color: 'text-muted-foreground', label: 'Voided' }
}
switch (transaction.flag) {
case '*':
return { icon: CheckCircle2, color: 'text-green-600', label: 'Cleared' }
case '!':
return { icon: Clock, color: 'text-yellow-500', label: 'Pending' }
case '#':
return { icon: Flag, color: 'text-red-600', label: 'Flagged' }
default:
return null
}
}
// Income gets a leading '+', expense a leading '-'.
function getAmountSign(t: Transaction): string {
if (isIncome(t)) return '+'
@ -380,25 +357,14 @@ onMounted(() => {
<!-- Transaction Header -->
<div class="flex items-start justify-between gap-3 mb-2">
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2 mb-1">
<!-- Status Icon -->
<component
v-if="getStatusInfo(transaction)"
:is="getStatusInfo(transaction)!.icon"
:class="[
'h-4 w-4 flex-shrink-0',
getStatusInfo(transaction)!.color
]"
/>
<h3
:class="[
'font-medium text-sm sm:text-base truncate',
isVoided(transaction) && 'line-through text-muted-foreground'
]"
>
{{ transaction.description }}
</h3>
</div>
<h3
:class="[
'font-medium text-sm sm:text-base truncate mb-1',
isVoided(transaction) && 'line-through text-muted-foreground'
]"
>
{{ transaction.description }}
</h3>
<p class="text-xs sm:text-sm text-muted-foreground">
{{ formatDate(transaction.date) }}
</p>
@ -433,13 +399,9 @@ onMounted(() => {
<span class="font-medium">Ref:</span> {{ transaction.reference }}
</div>
<!-- Tags: status badge (Voided / Pending) + any user-added tags.
Type tags (income-entry / expense-entry) are intentionally
suppressed they're encoded by the signed amount. -->
<div
v-if="isVoided(transaction) || isPending(transaction) || getDisplayTags(transaction).length > 0"
class="flex flex-wrap gap-1 mt-2"
>
<!-- Badges: Voided (leftmost, high-signal) + type (Income /
Expense) + Pending (after type) + any user-added tags. -->
<div class="flex flex-wrap gap-1 mt-2">
<Badge
v-if="isVoided(transaction)"
variant="secondary"
@ -448,7 +410,21 @@ onMounted(() => {
Voided
</Badge>
<Badge
v-else-if="isPending(transaction)"
v-if="isIncome(transaction)"
variant="secondary"
class="text-xs bg-green-100 dark:bg-green-900/20 text-green-700 dark:text-green-300"
>
Income
</Badge>
<Badge
v-else-if="isExpense(transaction)"
variant="secondary"
class="text-xs bg-red-100 dark:bg-red-900/20 text-red-700 dark:text-red-300"
>
Expense
</Badge>
<Badge
v-if="isPending(transaction)"
variant="secondary"
class="text-xs bg-yellow-100 dark:bg-yellow-900/20 text-yellow-700 dark:text-yellow-300"
>