feat(cash-floats): show balance green at or above the limit

The balance was red under the card's limit and plain otherwise. It is now
green when the card is set up and at or above its limit, so healthy cards
stand out. Cards without an opening balance stay plain.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DEls 2026-11-09 10:34:42 +02:00
parent dda421effa
commit 9c3a6e7f39
2 changed files with 18 additions and 3 deletions

View file

@ -1,7 +1,7 @@
// @vitest-environment jsdom
import * as React from "react";
import { cleanup, fireEvent, render, screen } from "@testing-library/react";
import { afterEach, beforeEach, expect, it, vi } from "vitest";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { ReactNode } from "react";
import type { CashFloatCard } from "@/lib/cash-float-server";
@ -108,3 +108,12 @@ it("opens the card's movements from its card number", () => {
fireEvent.click(screen.getByRole("button", { name: "Movements for card 3" }));
expect(screen.getByText("Movements sheet for 3")).toBeTruthy();
});
describe("balance colour", () => {
it("is red under the limit, green at or above it, and plain before set-up", async () => {
const { balanceTone } = await import("./cash-floats-view");
expect(balanceTone({ low: true, hasOpening: true })).toContain("text-destructive");
expect(balanceTone({ low: false, hasOpening: true })).toContain("text-emerald-600");
expect(balanceTone({ low: false, hasOpening: false })).toBe("");
});
});

View file

@ -178,7 +178,7 @@ export function CashFloatsView({ cards, users, sites = [] }: { cards: CashFloatC
</td>
<td className="text-left">{card.holder}</td>
<td>{card.assignedOn || "—"}</td>
<td className={card.low ? "font-semibold text-destructive" : ""}>{formatCents(card.balance)}</td>
<td className={balanceTone(card)}>{formatCents(card.balance)}</td>
<td>{formatCents(card.spentSinceTopup)}</td>
<td>{formatCents(card.spentThisMonth)}</td>
<td>
@ -263,7 +263,7 @@ function CardRow({ card, onOpen, actions }: {
<Figure label="This month" value={formatCents(card.spentThisMonth)} />
<div className="w-28 shrink-0 text-right">
<p className="text-[10px] uppercase tracking-wider text-muted-foreground">Balance</p>
<p className={`text-sm font-semibold tabular-nums ${card.low ? "text-destructive" : ""}`}>{formatCents(card.balance)}</p>
<p className={`text-sm font-semibold tabular-nums ${balanceTone(card)}`}>{formatCents(card.balance)}</p>
</div>
<button type="button" aria-expanded={open} aria-label={`Spend per month for card ${card.cardNumber}`} onClick={() => setOpen(o => !o)} className="grid h-9 w-9 shrink-0 place-items-center rounded-md hover:bg-muted">
<ChevronRight className={`h-4 w-4 text-muted-foreground transition-transform ${open ? "rotate-90" : ""}`} />
@ -297,3 +297,9 @@ function Figure({ label, value }: { label: string; value: string }) {
</div>
);
}
/** Red under the limit, green at or above it; a card not set up yet stays plain. */
export function balanceTone(card: { low: boolean; hasOpening?: boolean }): string {
if (card.low) return "font-semibold text-destructive";
return card.hasOpening ? "font-semibold text-emerald-600 dark:text-emerald-400" : "";
}