feat: summary overdue highlighting, tracker row visual polish, bill table cleanup
This commit is contained in:
parent
bb04966bbc
commit
88cb9d5340
|
|
@ -2,6 +2,7 @@ import { ArrowDown, ArrowUp, Copy, GripVertical, PenLine, EyeOff, Eye, Clock, Tr
|
|||
import { cn } from '@/lib/utils';
|
||||
import { scheduleLabel } from '@/lib/billingSchedule';
|
||||
import { MobileBillRow } from '@/components/MobileBillRow';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
|
||||
function ordinal(n) {
|
||||
const d = Number(n);
|
||||
|
|
@ -104,37 +105,58 @@ function BillCard({ bill, prefs = ALL_ON, onEdit, onToggle, onDelete, onHistory,
|
|||
</span>
|
||||
)}
|
||||
|
||||
{prefs.showAutopay && !!bill.autopay_enabled && (
|
||||
<span className="shrink-0 rounded bg-emerald-500/20 px-1.5 py-0.5 text-[11px] font-semibold text-emerald-300">
|
||||
Autopay
|
||||
</span>
|
||||
)}
|
||||
{prefs.show2fa && !!bill.has_2fa && (
|
||||
<span className="shrink-0 rounded bg-violet-500/20 px-1.5 py-0.5 text-[11px] font-semibold text-violet-300">
|
||||
2FA
|
||||
</span>
|
||||
)}
|
||||
{prefs.showSubscription && !!bill.is_subscription && (
|
||||
<span className="shrink-0 rounded border border-indigo-500/25 bg-indigo-500/10 px-1.5 py-0.5 text-[11px] font-semibold text-indigo-600 dark:text-indigo-300">
|
||||
S
|
||||
</span>
|
||||
)}
|
||||
{(!!bill.has_merchant_rule || !!bill.has_linked_transactions) && (
|
||||
<span
|
||||
className="shrink-0 rounded border border-emerald-500/25 bg-emerald-500/10 px-1.5 py-0.5 text-[11px] font-semibold text-emerald-600 dark:text-emerald-400"
|
||||
title="Linked to bank transactions"
|
||||
>
|
||||
L
|
||||
</span>
|
||||
)}
|
||||
{hasHistory && (
|
||||
<span
|
||||
className="inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-sky-500/25 bg-sky-500/10 text-sky-500"
|
||||
title="Historical visibility configured"
|
||||
>
|
||||
<Clock className="h-2.5 w-2.5" />
|
||||
</span>
|
||||
)}
|
||||
<TooltipProvider delayDuration={300}>
|
||||
{prefs.showAutopay && !!bill.autopay_enabled && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="shrink-0 rounded border border-sky-500/25 bg-sky-500/10 px-1.5 py-0.5 text-[11px] font-semibold text-sky-600 dark:text-sky-300 cursor-default">
|
||||
AP
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Autopay enabled</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
{prefs.show2fa && !!bill.has_2fa && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="shrink-0 rounded bg-violet-500/20 px-1.5 py-0.5 text-[11px] font-semibold text-violet-300 cursor-default">
|
||||
2FA
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Two-factor authentication configured</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
{prefs.showSubscription && !!bill.is_subscription && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="shrink-0 rounded border border-indigo-500/25 bg-indigo-500/10 px-1.5 py-0.5 text-[11px] font-semibold text-indigo-600 dark:text-indigo-300 cursor-default">
|
||||
S
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Subscription</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(!!bill.has_merchant_rule || !!bill.has_linked_transactions) && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="shrink-0 rounded border border-emerald-500/25 bg-emerald-500/10 px-1.5 py-0.5 text-[11px] font-semibold text-emerald-600 dark:text-emerald-400 cursor-default">
|
||||
L
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Linked to bank transactions</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
{hasHistory && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-sky-500/25 bg-sky-500/10 text-sky-500 cursor-default">
|
||||
<Clock className="h-2.5 w-2.5" />
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Historical visibility configured</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
|
||||
{/* Meta row */}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useState, useRef, useTransition } from 'react';
|
||||
import { ArrowDown, ArrowUp, GripVertical, Pencil, X } from 'lucide-react';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { toast } from 'sonner';
|
||||
import { api } from '@/api.js';
|
||||
import { cn, fmt, fmtDate } from '@/lib/utils';
|
||||
|
|
@ -356,30 +357,38 @@ export function TrackerRow({ row, year, month, refresh, index, onEditBill, moveC
|
|||
{row.name}
|
||||
</span>
|
||||
)}
|
||||
{row.autopay_enabled && (
|
||||
<span
|
||||
className="inline-flex shrink-0 rounded border border-sky-500/25 bg-sky-500/10 px-1.5 py-0.5 text-[10px] font-bold leading-none text-sky-600 dark:text-sky-300"
|
||||
title="Autopay"
|
||||
>
|
||||
AP
|
||||
</span>
|
||||
)}
|
||||
{(row.has_merchant_rule || row.has_linked_transactions) && (
|
||||
<span
|
||||
className="inline-flex shrink-0 rounded border border-emerald-500/25 bg-emerald-500/10 px-1.5 py-0.5 text-[10px] font-bold leading-none text-emerald-600 dark:text-emerald-400"
|
||||
title="Linked to bank transactions"
|
||||
>
|
||||
L
|
||||
</span>
|
||||
)}
|
||||
{row.is_subscription && (
|
||||
<span
|
||||
className="inline-flex shrink-0 rounded border border-indigo-500/25 bg-indigo-500/10 px-1.5 py-0.5 text-[10px] font-bold leading-none text-indigo-600 dark:text-indigo-300"
|
||||
title="Subscription"
|
||||
>
|
||||
S
|
||||
</span>
|
||||
)}
|
||||
<TooltipProvider delayDuration={300}>
|
||||
{row.autopay_enabled && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="inline-flex shrink-0 rounded border border-sky-500/25 bg-sky-500/10 px-1.5 py-0.5 text-[10px] font-bold leading-none text-sky-600 dark:text-sky-300 cursor-default">
|
||||
AP
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Autopay enabled</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(row.has_merchant_rule || row.has_linked_transactions) && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="inline-flex shrink-0 rounded border border-emerald-500/25 bg-emerald-500/10 px-1.5 py-0.5 text-[10px] font-bold leading-none text-emerald-600 dark:text-emerald-400 cursor-default">
|
||||
L
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Linked to bank transactions</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
{row.is_subscription && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="inline-flex shrink-0 rounded border border-indigo-500/25 bg-indigo-500/10 px-1.5 py-0.5 text-[10px] font-bold leading-none text-indigo-600 dark:text-indigo-300 cursor-default">
|
||||
S
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Subscription</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
</TooltipProvider>
|
||||
<Button
|
||||
size="icon" variant="ghost"
|
||||
className="h-7 w-7 opacity-100 transition-opacity text-muted-foreground hover:text-foreground hover:bg-accent lg:opacity-0 lg:group-hover:opacity-100"
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { api } from '@/api.js';
|
|||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { cn, fmt } from '@/lib/utils';
|
||||
import { moveInArray, reorderPayload } from '@/lib/reorder';
|
||||
|
||||
|
|
@ -183,7 +184,41 @@ function ExpenseRow({ expense, moveControls, dragProps }) {
|
|||
</div>
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="truncate text-sm font-semibold text-foreground">{expense.name}</div>
|
||||
<div className="flex flex-wrap items-center gap-1.5">
|
||||
<span className="truncate text-sm font-semibold text-foreground">{expense.name}</span>
|
||||
<TooltipProvider delayDuration={300}>
|
||||
{expense.autopay_enabled && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="inline-flex shrink-0 rounded border border-sky-500/25 bg-sky-500/10 px-1.5 py-0.5 text-[10px] font-bold leading-none text-sky-600 dark:text-sky-300 cursor-default">
|
||||
AP
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Autopay enabled</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
{expense.is_subscription && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="inline-flex shrink-0 rounded border border-indigo-500/25 bg-indigo-500/10 px-1.5 py-0.5 text-[10px] font-bold leading-none text-indigo-600 dark:text-indigo-300 cursor-default">
|
||||
S
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Subscription</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
{(expense.has_merchant_rule || expense.has_linked_transactions) && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="inline-flex shrink-0 rounded border border-emerald-500/25 bg-emerald-500/10 px-1.5 py-0.5 text-[10px] font-bold leading-none text-emerald-600 dark:text-emerald-400 cursor-default">
|
||||
L
|
||||
</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>Linked to bank transactions</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
<div className="mt-1 flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
|
||||
{expense.category_name && <span>{expense.category_name}</span>}
|
||||
<span>Due day {expense.due_day}</span>
|
||||
|
|
|
|||
|
|
@ -238,10 +238,16 @@ function buildSummary(db, userId, year, month) {
|
|||
c.name AS category_name,
|
||||
m.actual_amount,
|
||||
m.is_skipped,
|
||||
b.sort_order
|
||||
b.sort_order,
|
||||
b.autopay_enabled,
|
||||
b.is_subscription,
|
||||
CASE WHEN mr.bill_id IS NOT NULL THEN 1 ELSE 0 END AS has_merchant_rule,
|
||||
CASE WHEN lt.matched_bill_id IS NOT NULL THEN 1 ELSE 0 END AS has_linked_transactions
|
||||
FROM bills b
|
||||
LEFT JOIN categories c ON c.id = b.category_id AND c.user_id = b.user_id AND c.deleted_at IS NULL
|
||||
LEFT JOIN monthly_bill_state m ON m.bill_id = b.id AND m.year = ? AND m.month = ?
|
||||
LEFT JOIN (SELECT DISTINCT bill_id FROM bill_merchant_rules) mr ON mr.bill_id = b.id
|
||||
LEFT JOIN (SELECT DISTINCT matched_bill_id FROM transactions WHERE match_status = 'matched') lt ON lt.matched_bill_id = b.id
|
||||
WHERE b.user_id = ? AND b.active = 1 AND b.deleted_at IS NULL
|
||||
ORDER BY CASE WHEN b.sort_order IS NULL THEN 1 ELSE 0 END,
|
||||
b.sort_order ASC,
|
||||
|
|
@ -292,6 +298,10 @@ function buildSummary(db, userId, year, month) {
|
|||
is_skipped: !!row.is_skipped,
|
||||
due_day: row.due_day,
|
||||
category_name: row.category_name || null,
|
||||
autopay_enabled: !!row.autopay_enabled,
|
||||
is_subscription: !!row.is_subscription,
|
||||
has_merchant_rule: !!row.has_merchant_rule,
|
||||
has_linked_transactions: !!row.has_linked_transactions,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue