style: padroniza widgets e listas do dashboard

This commit is contained in:
Felipe Coutinho
2026-03-15 23:23:12 +00:00
parent 64eb29d807
commit 2712d4919a
18 changed files with 169 additions and 182 deletions

View File

@@ -56,8 +56,6 @@ const VARIANT_CONFIG = {
increase: "text-success", increase: "text-success",
decrease: "text-destructive", decrease: "text-destructive",
}, },
listItemClassName:
"flex flex-col gap-1.5 py-2 border-b border-dashed last:border-0",
includeBudgetAmount: true, includeBudgetAmount: true,
}, },
expense: { expense: {
@@ -70,8 +68,6 @@ const VARIANT_CONFIG = {
increase: "text-destructive", increase: "text-destructive",
decrease: "text-success", decrease: "text-success",
}, },
listItemClassName:
"flex flex-col py-2 border-b border-dashed last:border-0",
includeBudgetAmount: false, includeBudgetAmount: false,
}, },
} as const; } as const;
@@ -194,7 +190,7 @@ export function CategoryBreakdownWidgetView({
</div> </div>
<TabsContent value="list" className="mt-0"> <TabsContent value="list" className="mt-0">
<div className="flex flex-col px-0"> <div>
{data.categories.map((category, index) => { {data.categories.map((category, index) => {
const hasIncrease = const hasIncrease =
category.percentageChange !== null && category.percentageChange !== null &&
@@ -218,11 +214,8 @@ export function CategoryBreakdownWidgetView({
: "text-muted-foreground"; : "text-muted-foreground";
return ( return (
<div <div key={category.categoryId}>
key={category.categoryId} <div className="flex items-center justify-between gap-3 transition-all duration-300 py-2">
className={config.listItemClassName}
>
<div className="flex items-center justify-between gap-3">
<div className="flex min-w-0 flex-1 items-center gap-2"> <div className="flex min-w-0 flex-1 items-center gap-2">
<CategoryIconBadge <CategoryIconBadge
icon={category.categoryIcon} icon={category.categoryIcon}
@@ -245,7 +238,7 @@ export function CategoryBreakdownWidgetView({
/> />
</Link> </Link>
</div> </div>
<div className="flex items-center gap-2 text-xs text-muted-foreground"> <div className="flex flex-wrap items-center gap-x-2 gap-y-0.5 text-xs text-muted-foreground">
<span> <span>
{formatPercentage( {formatPercentage(
category.percentageOfTotal, category.percentageOfTotal,
@@ -253,6 +246,36 @@ export function CategoryBreakdownWidgetView({
)}{" "} )}{" "}
da {config.shareLabel} da {config.shareLabel}
</span> </span>
{hasBudget && category.budgetUsedPercentage !== null ? (
<>
<span aria-hidden>·</span>
<span
className={`flex items-center gap-1 ${budgetExceeded ? "text-destructive" : "text-info"}`}
>
<RiWallet3Line className="size-3 shrink-0" />
{budgetExceeded ? (
<>
excedeu{" "}
<span className="font-medium">
{formatCurrency(exceededAmount)}
</span>
</>
) : (
<>
{formatPercentage(
category.budgetUsedPercentage,
config.percentageDigits,
)}{" "}
do limite
{config.includeBudgetAmount &&
category.budgetAmount !== null
? ` ${formatCurrency(category.budgetAmount)}`
: ""}
</>
)}
</span>
</>
) : null}
</div> </div>
</div> </div>
</div> </div>
@@ -280,48 +303,6 @@ export function CategoryBreakdownWidgetView({
) : null} ) : null}
</div> </div>
</div> </div>
{hasBudget && category.budgetUsedPercentage !== null ? (
<div className="ml-11 flex items-center gap-1.5 text-xs">
<RiWallet3Line
className={`size-3 ${
budgetExceeded ? "text-destructive" : "text-info"
}`}
/>
<span
className={
budgetExceeded ? "text-destructive" : "text-info"
}
>
{budgetExceeded ? (
<>
{formatPercentage(
category.budgetUsedPercentage,
config.percentageDigits,
)}{" "}
do limite
{config.includeBudgetAmount &&
category.budgetAmount !== null
? ` ${formatCurrency(category.budgetAmount)}`
: ""}{" "}
- excedeu em {formatCurrency(exceededAmount)}
</>
) : (
<>
{formatPercentage(
category.budgetUsedPercentage,
config.percentageDigits,
)}{" "}
do limite
{config.includeBudgetAmount &&
category.budgetAmount !== null
? ` ${formatCurrency(category.budgetAmount)}`
: ""}
</>
)}
</span>
</div>
) : null}
</div> </div>
); );
})} })}

View File

@@ -3,15 +3,14 @@ import {
RiArrowDownSFill, RiArrowDownSFill,
RiArrowUpLine, RiArrowUpLine,
RiArrowUpSFill, RiArrowUpSFill,
RiCashLine, RiCalendarCheckLine,
RiIncreaseDecreaseLine, RiScalesLine,
RiSubtractLine, RiSubtractLine,
} from "@remixicon/react"; } from "@remixicon/react";
import type { DashboardCardMetrics } from "@/features/dashboard/dashboard-metrics-queries"; import type { DashboardCardMetrics } from "@/features/dashboard/dashboard-metrics-queries";
import MoneyValues from "@/shared/components/money-values"; import MoneyValues from "@/shared/components/money-values";
import { import {
Card, Card,
CardAction,
CardFooter, CardFooter,
CardHeader, CardHeader,
CardTitle, CardTitle,
@@ -32,20 +31,33 @@ const CARDS = [
key: "receitas", key: "receitas",
icon: RiArrowUpLine, icon: RiArrowUpLine,
invertTrend: false, invertTrend: false,
cardClass: "",
iconClass: "text-success",
}, },
{ {
label: "Despesas", label: "Despesas",
key: "despesas", key: "despesas",
icon: RiArrowDownLine, icon: RiArrowDownLine,
invertTrend: true, invertTrend: true,
cardClass: "",
iconClass: "text-destructive",
}, },
{ {
label: "Balanço", label: "Balanço",
key: "balanco", key: "balanco",
icon: RiIncreaseDecreaseLine, icon: RiScalesLine,
invertTrend: false, invertTrend: false,
cardClass: "",
iconClass: "text-amber-500",
},
{
label: "Previsto",
key: "previsto",
icon: RiCalendarCheckLine,
invertTrend: false,
cardClass: "border border-dashed",
iconClass: "",
}, },
{ label: "Previsto", key: "previsto", icon: RiCashLine, invertTrend: false },
] as const; ] as const;
const TREND_ICONS = { const TREND_ICONS = {
@@ -62,7 +74,7 @@ const getTrend = (current: number, previous: number): Trend => {
}; };
const getPercentChange = (current: number, previous: number): string => { const getPercentChange = (current: number, previous: number): string => {
const EPSILON = 0.01; // Considera valores menores que 1 centavo como zero const EPSILON = 0.01;
if (Math.abs(previous) < EPSILON) { if (Math.abs(previous) < EPSILON) {
if (Math.abs(current) < EPSILON) return "0%"; if (Math.abs(current) < EPSILON) return "0%";
@@ -80,48 +92,49 @@ const getPercentChange = (current: number, previous: number): string => {
}; };
const getTrendColor = (trend: Trend, invertTrend: boolean): string => { const getTrendColor = (trend: Trend, invertTrend: boolean): string => {
if (trend === "flat") return ""; if (trend === "flat") return "text-muted-foreground";
const isPositive = invertTrend ? trend === "down" : trend === "up"; const isPositive = invertTrend ? trend === "down" : trend === "up";
return isPositive return isPositive ? "text-success" : "text-destructive";
? "text-success border-success"
: "text-destructive border-destructive";
}; };
export function DashboardMetricsCards({ metrics }: DashboardMetricsCardsProps) { export function DashboardMetricsCards({ metrics }: DashboardMetricsCardsProps) {
return ( return (
<div className="*:data-[slot=card]:from-primary/5 *:data-[slot=card]:to-card dark:*:data-[slot=card]:bg-card grid grid-cols-1 gap-3 @xl/main:grid-cols-2 @5xl/main:grid-cols-4"> <div className="grid grid-cols-1 gap-3 @xl/main:grid-cols-2 @5xl/main:grid-cols-4">
{CARDS.map(({ label, key, icon: Icon, invertTrend }) => { {CARDS.map(
const metric = metrics[key]; ({ label, key, icon: Icon, invertTrend, cardClass, iconClass }) => {
const trend = getTrend(metric.current, metric.previous); const metric = metrics[key];
const TrendIcon = TREND_ICONS[trend]; const trend = getTrend(metric.current, metric.previous);
const trendColor = getTrendColor(trend, invertTrend); const TrendIcon = TREND_ICONS[trend];
const trendColor = getTrendColor(trend, invertTrend);
return ( return (
<Card key={label} className="@container/card gap-2"> <Card
<CardHeader> key={label}
<CardTitle className="flex items-center gap-1 tracking-tighter lowercase"> className={`@container/card flex flex-col justify-between min-h-34 ${cardClass}`}
<Icon className="size-4" /> >
{label} <CardHeader>
</CardTitle> <CardTitle className="flex items-center gap-1 tracking-tight lowercase">
<MoneyValues className="text-2xl" amount={metric.current} /> <Icon className={`size-4 ${iconClass}`} />
<CardAction> {label}
<div className={`flex items-center text-xs ${trendColor}`}> </CardTitle>
<TrendIcon size={16} /> <div className="flex items-baseline gap-2 mt-auto pt-2">
{getPercentChange(metric.current, metric.previous)} <MoneyValues className="text-2xl" amount={metric.current} />
<div className={`flex items-center text-xs ${trendColor}`}>
<TrendIcon size={14} />
{getPercentChange(metric.current, metric.previous)}
</div>
</div> </div>
</CardAction> </CardHeader>
</CardHeader> <CardFooter className="text-sm">
<CardFooter className="flex-col items-start gap-2 text-sm"> <div className="flex items-center gap-1 text-xs text-muted-foreground">
<div className="line-clamp-1 flex gap-2 text-xs"> <span>vs. mês anterior</span>
mês anterior <MoneyValues amount={metric.previous} />
</div> </div>
<div className="text-foreground"> </CardFooter>
<MoneyValues amount={metric.previous} /> </Card>
</div> );
</CardFooter> },
</Card> )}
);
})}
</div> </div>
); );
} }

View File

@@ -9,9 +9,9 @@ export function DashboardWelcome({ name }: { name?: string | null }) {
<section className="p-2"> <section className="p-2">
<div className="tracking-tight"> <div className="tracking-tight">
<h1 className="text-xl"> <h1 className="text-xl">
{greeting}, {displayName} {greeting}, <span className="text-primary">{displayName}</span>
</h1> </h1>
<p className="text-sm mt-1">{formattedDate}</p> <p className="text-sm mt-1 text-muted-foreground">{formattedDate}</p>
</div> </div>
</section> </section>
); );

View File

@@ -26,7 +26,7 @@ export function GoalProgressItem({
const percentageDelta = item.usedPercentage - 100; const percentageDelta = item.usedPercentage - 100;
return ( return (
<li className="border-b border-dashed py-2 last:border-b-0 last:pb-0"> <div className="transition-all duration-300 py-2">
<div className="flex items-start justify-between gap-3"> <div className="flex items-start justify-between gap-3">
<div className="flex min-w-0 flex-1 items-start gap-2"> <div className="flex min-w-0 flex-1 items-start gap-2">
<CategoryIconBadge <CategoryIconBadge
@@ -52,9 +52,9 @@ export function GoalProgressItem({
</span> </span>
<Button <Button
type="button" type="button"
variant="ghost" variant="outline"
size="icon-sm" size="icon-sm"
className="size-7 text-muted-foreground hover:text-foreground" className="text-muted-foreground hover:text-foreground"
onClick={() => onEdit(item)} onClick={() => onEdit(item)}
aria-label={`Editar orçamento de ${item.categoryName}`} aria-label={`Editar orçamento de ${item.categoryName}`}
> >
@@ -65,6 +65,6 @@ export function GoalProgressItem({
<div className="ml-11 mt-1.5"> <div className="ml-11 mt-1.5">
<Progress value={progressValue} /> <Progress value={progressValue} />
</div> </div>
</li> </div>
); );
} }

View File

@@ -26,7 +26,7 @@ export function InstallmentExpenseListItem({
} = buildInstallmentExpenseDisplay(expense); } = buildInstallmentExpenseDisplay(expense);
return ( return (
<li className="flex items-center gap-3 border-b border-dashed pb-3 last:border-b-0 last:pb-0"> <div className="flex items-center gap-3 transition-all duration-300 py-2">
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<div className="flex items-center justify-between gap-3"> <div className="flex items-center justify-between gap-3">
<div className="flex min-w-0 items-center gap-2"> <div className="flex min-w-0 items-center gap-2">
@@ -71,6 +71,6 @@ export function InstallmentExpenseListItem({
<Progress value={progress} className="mt-1 h-2" /> <Progress value={progress} className="mt-1 h-2" />
</div> </div>
</li> </div>
); );
} }

View File

@@ -21,7 +21,7 @@ export function InstallmentExpensesList({
} }
return ( return (
<ul className="flex flex-col gap-2"> <ul className="flex flex-col">
{expenses.map((expense) => ( {expenses.map((expense) => (
<InstallmentExpenseListItem key={expense.id} expense={expense} /> <InstallmentExpenseListItem key={expense.id} expense={expense} />
))} ))}

View File

@@ -9,7 +9,7 @@ export function InstallmentExpensesWidgetView({
data, data,
}: InstallmentExpensesWidgetViewProps) { }: InstallmentExpensesWidgetViewProps) {
return ( return (
<div className="flex flex-col gap-4 px-0"> <div className="flex flex-col">
<InstallmentExpensesList expenses={data.expenses} /> <InstallmentExpensesList expenses={data.expenses} />
</div> </div>
); );

View File

@@ -27,12 +27,12 @@ export function MyAccountsWidget({
return ( return (
<> <>
<div className="flex justify-between py-2"> <div className="flex justify-between py-1">
Saldo Total Saldo Total
<MoneyValues className="text-2xl" amount={totalBalance} /> <MoneyValues className="text-2xl" amount={totalBalance} />
</div> </div>
<div className="py-2 px-0"> <div>
{displayedAccounts.length === 0 ? ( {displayedAccounts.length === 0 ? (
<div className="-mt-10"> <div className="-mt-10">
<WidgetEmptyState <WidgetEmptyState
@@ -49,12 +49,12 @@ export function MyAccountsWidget({
const logoSrc = resolveLogoSrc(account.logo); const logoSrc = resolveLogoSrc(account.logo);
return ( return (
<li <div
key={account.id} key={account.id}
className="flex items-center justify-between gap-2 border-b border-dashed py-2 last:border-0" className="flex items-center justify-between transition-all duration-300 py-1.5 "
> >
<div className="flex min-w-0 flex-1 items-center gap-3"> <div className="flex min-w-0 flex-1 items-center gap-2 py-1">
<div className="relative size-10 overflow-hidden"> <div className="relative size-9.5 overflow-hidden">
{logoSrc ? ( {logoSrc ? (
<Image <Image
src={logoSrc} src={logoSrc}
@@ -88,7 +88,7 @@ export function MyAccountsWidget({
<div className="flex flex-col items-end gap-0.5 text-right"> <div className="flex flex-col items-end gap-0.5 text-right">
<MoneyValues amount={account.balance} /> <MoneyValues amount={account.balance} />
</div> </div>
</li> </div>
); );
})} })}
</ul> </ul>

View File

@@ -23,7 +23,7 @@ export function NoteListItem({
const createdAtLabel = formatNoteCreatedAt(note.createdAt); const createdAtLabel = formatNoteCreatedAt(note.createdAt);
return ( return (
<li className="flex items-center justify-between gap-2 border-b border-dashed py-2 last:border-b-0 last:pb-0"> <div className="flex items-center justify-between gap-2 transition-all duration-300 py-2">
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<p className="truncate text-sm font-medium text-foreground"> <p className="truncate text-sm font-medium text-foreground">
{displayTitle} {displayTitle}
@@ -40,9 +40,9 @@ export function NoteListItem({
</div> </div>
</div> </div>
<div className="flex shrink-0 items-center"> <div className="flex shrink-0 items-center gap-1">
<Button <Button
variant="ghost" variant="outline"
size="icon-sm" size="icon-sm"
className="text-muted-foreground hover:text-foreground" className="text-muted-foreground hover:text-foreground"
onClick={() => onOpenEdit(note)} onClick={() => onOpenEdit(note)}
@@ -51,7 +51,7 @@ export function NoteListItem({
<RiPencilLine className="size-4" /> <RiPencilLine className="size-4" />
</Button> </Button>
<Button <Button
variant="ghost" variant="outline"
size="icon-sm" size="icon-sm"
className="text-muted-foreground hover:text-foreground" className="text-muted-foreground hover:text-foreground"
onClick={() => onOpenDetails(note)} onClick={() => onOpenDetails(note)}
@@ -60,6 +60,6 @@ export function NoteListItem({
<RiFileList2Line className="size-4" /> <RiFileList2Line className="size-4" />
</Button> </Button>
</div> </div>
</li> </div>
); );
} }

View File

@@ -48,7 +48,7 @@ export function PayersWidget({ payers }: PayersWidgetProps) {
description="Quando houver despesas associadas a pagadores, eles aparecerão aqui." description="Quando houver despesas associadas a pagadores, eles aparecerão aqui."
/> />
) : ( ) : (
<ul className="flex flex-col"> <div className="flex flex-col">
{payers.map((payer) => { {payers.map((payer) => {
const initials = buildInitials(payer.name); const initials = buildInitials(payer.name);
const hasValidPercentageChange = const hasValidPercentageChange =
@@ -59,12 +59,12 @@ export function PayersWidget({ payers }: PayersWidgetProps) {
: null; : null;
return ( return (
<li <div
key={payer.id} key={payer.id}
className="flex items-center justify-between border-b border-dashed last:border-b-0 last:pb-0" className="flex items-center justify-between transition-all duration-300 py-1.5"
> >
<div className="flex min-w-0 flex-1 items-center gap-2 py-2"> <div className="flex min-w-0 flex-1 items-center gap-2 py-1">
<Avatar className="size-10 shrink-0"> <Avatar className="size-9.5 shrink-0">
<AvatarImage <AvatarImage
src={getAvatarSrc(payer.avatarUrl)} src={getAvatarSrc(payer.avatarUrl)}
alt={`Avatar de ${payer.name}`} alt={`Avatar de ${payer.name}`}
@@ -118,10 +118,10 @@ export function PayersWidget({ payers }: PayersWidgetProps) {
</span> </span>
)} )}
</div> </div>
</li> </div>
); );
})} })}
</ul> </div>
)} )}
</CardContent> </CardContent>
); );

View File

@@ -26,7 +26,7 @@ export function PaymentBreakdownListItem({
item, item,
}: PaymentBreakdownListItemProps) { }: PaymentBreakdownListItemProps) {
return ( return (
<li className="flex items-center gap-3 border-b border-dashed pb-3 last:border-b-0 last:pb-0"> <div className="flex items-center gap-3 transition-all duration-300 py-1.5">
<div className={ICON_WRAPPER_CLASS}>{item.icon}</div> <div className={ICON_WRAPPER_CLASS}>{item.icon}</div>
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
@@ -46,6 +46,6 @@ export function PaymentBreakdownListItem({
<Progress value={item.percentage} /> <Progress value={item.percentage} />
</div> </div>
</div> </div>
</li> </div>
); );
} }

View File

@@ -34,7 +34,7 @@ export function PaymentStatusWidgetView({
pending={data.income.pending} pending={data.income.pending}
/> />
<div className="border-t border-dashed" /> <div className="border-t" />
<PaymentStatusCategorySection <PaymentStatusCategorySection
title="A Pagar" title="A Pagar"

View File

@@ -170,12 +170,12 @@ export function PurchasesByCategoryWidget({
} }
/> />
) : ( ) : (
<ul className="flex flex-col"> <div className="flex flex-col">
{currentTransactions.map((transaction) => { {currentTransactions.map((transaction) => {
return ( return (
<li <div
key={transaction.id} key={transaction.id}
className="flex items-center justify-between gap-3 border-b border-dashed py-2 last:border-b-0 last:pb-0" className="flex items-center justify-between gap-3 transition-all duration-300 py-2"
> >
<div className="flex min-w-0 flex-1 items-center gap-3"> <div className="flex min-w-0 flex-1 items-center gap-3">
<EstabelecimentoLogo name={transaction.name} size={37} /> <EstabelecimentoLogo name={transaction.name} size={37} />
@@ -193,10 +193,10 @@ export function PurchasesByCategoryWidget({
<div className="shrink-0 text-foreground"> <div className="shrink-0 text-foreground">
<MoneyValues amount={transaction.amount} /> <MoneyValues amount={transaction.amount} />
</div> </div>
</li> </div>
); );
})} })}
</ul> </div>
)} )}
</div> </div>
); );

View File

@@ -30,36 +30,34 @@ export function RecurringExpensesWidget({
} }
return ( return (
<div className="flex flex-col gap-4 px-0"> <div className="flex flex-col">
<ul className="flex flex-col gap-2"> {data.expenses.map((expense) => {
{data.expenses.map((expense) => { return (
return ( <div
<li key={expense.id}
key={expense.id} className="flex items-center gap-2 transition-all duration-300 py-1.5"
className="flex items-center gap-3 border-b border-dashed pb-2 last:border-b-0 last:pb-0" >
> <EstabelecimentoLogo name={expense.name} size={37} />
<EstabelecimentoLogo name={expense.name} size={37} />
<div className="min-w-0 flex-1"> <div className="min-w-0 flex-1">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<p className="truncate text-foreground text-sm font-medium"> <p className="truncate text-foreground text-sm font-medium">
{expense.name} {expense.name}
</p> </p>
<MoneyValues amount={expense.amount} /> <MoneyValues amount={expense.amount} />
</div>
<div className="flex items-center justify-between text-xs text-muted-foreground">
<span className="inline-flex items-center gap-1">
{expense.paymentMethod}
</span>
<span>{formatOccurrences(expense.recurrenceCount)}</span>
</div>
</div> </div>
</li>
); <div className="flex items-center justify-between text-xs text-muted-foreground">
})} <span className="inline-flex items-center gap-1">
</ul> {expense.paymentMethod}
</span>
<span>{formatOccurrences(expense.recurrenceCount)}</span>
</div>
</div>
</div>
);
})}
</div> </div>
); );
} }

View File

@@ -27,12 +27,12 @@ export function TopEstablishmentsWidget({
description="Quando houver despesas registradas, elas aparecerão aqui." description="Quando houver despesas registradas, elas aparecerão aqui."
/> />
) : ( ) : (
<ul className="flex flex-col"> <div className="flex flex-col">
{data.establishments.map((establishment) => { {data.establishments.map((establishment) => {
return ( return (
<li <div
key={establishment.id} key={establishment.id}
className="flex items-center justify-between gap-3 border-b border-dashed py-2 last:border-b-0 last:pb-0" className="flex items-center justify-between gap-3 transition-all duration-300 py-2"
> >
<div className="flex min-w-0 flex-1 items-center gap-3"> <div className="flex min-w-0 flex-1 items-center gap-3">
<EstabelecimentoLogo name={establishment.name} size={37} /> <EstabelecimentoLogo name={establishment.name} size={37} />
@@ -50,10 +50,10 @@ export function TopEstablishmentsWidget({
<div className="shrink-0 text-foreground"> <div className="shrink-0 text-foreground">
<MoneyValues amount={establishment.amount} /> <MoneyValues amount={establishment.amount} />
</div> </div>
</li> </div>
); );
})} })}
</ul> </div>
)} )}
</div> </div>
); );

View File

@@ -85,9 +85,7 @@ export function TopExpensesWidget({
htmlFor="card-only-toggle" htmlFor="card-only-toggle"
className="text-sm text-muted-foreground" className="text-sm text-muted-foreground"
> >
{cardOnly Apenas cartões
? "Somente cartões de crédito ou débito."
: "Todas as despesas"}
</label> </label>
<Switch <Switch
id="card-only-toggle" id="card-only-toggle"
@@ -107,12 +105,12 @@ export function TopExpensesWidget({
/> />
</div> </div>
) : ( ) : (
<ul className="flex flex-col"> <div className="flex flex-col">
{data.expenses.map((expense) => { {data.expenses.map((expense) => {
return ( return (
<li <div
key={expense.id} key={expense.id}
className="flex items-center justify-between gap-3 border-b border-dashed py-2 last:border-b-0 last:pb-0" className="flex items-center justify-between gap-3 transition-all duration-300 py-2"
> >
<div className="flex min-w-0 flex-1 items-center gap-3"> <div className="flex min-w-0 flex-1 items-center gap-3">
<EstabelecimentoLogo name={expense.name} size={37} /> <EstabelecimentoLogo name={expense.name} size={37} />
@@ -130,10 +128,10 @@ export function TopExpensesWidget({
<div className="shrink-0 text-foreground"> <div className="shrink-0 text-foreground">
<MoneyValues amount={expense.amount} /> <MoneyValues amount={expense.amount} />
</div> </div>
</li> </div>
); );
})} })}
</ul> </div>
)} )}
</div> </div>
); );

View File

@@ -42,10 +42,7 @@ export function PayerCardUsageCard({ items }: PagadorCardUsageCardProps) {
const logoPath = resolveLogoSrc(item.logo); const logoPath = resolveLogoSrc(item.logo);
const initials = buildInitials(item.name); const initials = buildInitials(item.name);
return ( return (
<li <div key={item.id} className="flex items-center justify-between">
key={item.id}
className="flex items-center justify-between border-b border-dashed last:border-b-0 last:pb-0"
>
<div className="flex min-w-0 flex-1 items-center gap-2 py-2"> <div className="flex min-w-0 flex-1 items-center gap-2 py-2">
<div className="flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-full"> <div className="flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-full">
{logoPath ? ( {logoPath ? (
@@ -72,7 +69,7 @@ export function PayerCardUsageCard({ items }: PagadorCardUsageCardProps) {
</div> </div>
</div> </div>
<MoneyValues amount={item.amount} /> <MoneyValues amount={item.amount} />
</li> </div>
); );
})} })}
</ul> </ul>

View File

@@ -9,6 +9,7 @@ import { EstabelecimentoLogo } from "@/features/transactions/components/shared/e
import MoneyValues from "@/shared/components/money-values"; import MoneyValues from "@/shared/components/money-values";
import { CardContent } from "@/shared/components/ui/card"; import { CardContent } from "@/shared/components/ui/card";
import { Progress } from "@/shared/components/ui/progress"; import { Progress } from "@/shared/components/ui/progress";
import { Separator } from "@/shared/components/ui/separator";
import { WidgetEmptyState } from "@/shared/components/widget-empty-state"; import { WidgetEmptyState } from "@/shared/components/widget-empty-state";
import type { import type {
PayerBoletoItem, PayerBoletoItem,
@@ -41,10 +42,7 @@ export function PayerBoletoCard({ items }: PagadorBoletoCardProps) {
{items.map((item) => { {items.map((item) => {
const statusLabel = buildBillStatusLabel(item); const statusLabel = buildBillStatusLabel(item);
return ( return (
<li <div key={item.id} className="flex items-center justify-between">
key={item.id}
className="flex items-center justify-between border-b border-dashed last:border-b-0 last:pb-0"
>
<div className="flex min-w-0 flex-1 items-center gap-3 py-2"> <div className="flex min-w-0 flex-1 items-center gap-3 py-2">
<EstabelecimentoLogo name={item.name} size={36} /> <EstabelecimentoLogo name={item.name} size={36} />
<div className="min-w-0"> <div className="min-w-0">
@@ -64,7 +62,7 @@ export function PayerBoletoCard({ items }: PagadorBoletoCardProps) {
</div> </div>
</div> </div>
<MoneyValues amount={item.amount} /> <MoneyValues amount={item.amount} />
</li> </div>
); );
})} })}
</ul> </ul>
@@ -105,7 +103,9 @@ export function PayerPaymentStatusCard({
<span className="text-sm font-medium text-foreground">Pago</span> <span className="text-sm font-medium text-foreground">Pago</span>
<MoneyValues amount={paidAmount} /> <MoneyValues amount={paidAmount} />
</div> </div>
<Progress value={paidPercentage} className="h-2" /> <Progress value={paidPercentage} className="h-2" />
<div className="flex items-center justify-between gap-4 text-sm"> <div className="flex items-center justify-between gap-4 text-sm">
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<RiCheckboxCircleLine className="size-3 text-success" /> <RiCheckboxCircleLine className="size-3 text-success" />
@@ -117,7 +117,7 @@ export function PayerPaymentStatusCard({
</div> </div>
</div> </div>
<div className="border-t border-dashed" /> <Separator />
<div className="space-y-2"> <div className="space-y-2">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">