mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-05-09 11:01:45 +00:00
feat(dashboard/boletos): nome do boleto como link para lançamentos do período
- nome do boleto virou link para /transactions?q=<nome> - quando o período selecionado não é o atual, inclui ?periodo=<mes-ano> na URL - ícone RiExternalLinkLine ao lado do nome, mesmo padrão do widget de faturas Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { RiCheckboxCircleFill } from "@remixicon/react";
|
import { RiCheckboxCircleFill, RiExternalLinkLine } from "@remixicon/react";
|
||||||
|
import Link from "next/link";
|
||||||
import {
|
import {
|
||||||
buildBillStatusLabel,
|
buildBillStatusLabel,
|
||||||
buildBillWidgetStatusLabel,
|
buildBillWidgetStatusLabel,
|
||||||
@@ -13,14 +14,25 @@ import {
|
|||||||
TooltipContent,
|
TooltipContent,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/shared/components/ui/tooltip";
|
} from "@/shared/components/ui/tooltip";
|
||||||
|
import { getCurrentPeriod, formatPeriodForUrl } from "@/shared/utils/period";
|
||||||
import { cn } from "@/shared/utils/ui";
|
import { cn } from "@/shared/utils/ui";
|
||||||
|
|
||||||
type BillListItemProps = {
|
type BillListItemProps = {
|
||||||
bill: DashboardBill;
|
bill: DashboardBill;
|
||||||
|
period?: string;
|
||||||
onPay: (billId: string) => void;
|
onPay: (billId: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function BillListItem({ bill, onPay }: BillListItemProps) {
|
function buildTransactionsHref(name: string, period?: string): string {
|
||||||
|
const params = new URLSearchParams({ q: name });
|
||||||
|
const current = getCurrentPeriod();
|
||||||
|
if (period && period !== current) {
|
||||||
|
params.set("periodo", formatPeriodForUrl(period));
|
||||||
|
}
|
||||||
|
return `/transactions?${params.toString()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function BillListItem({ bill, period, onPay }: BillListItemProps) {
|
||||||
const statusLabel = buildBillWidgetStatusLabel(bill);
|
const statusLabel = buildBillWidgetStatusLabel(bill);
|
||||||
const absoluteStatusLabel = buildBillStatusLabel(bill);
|
const absoluteStatusLabel = buildBillStatusLabel(bill);
|
||||||
const overdue = isBillOverdue(bill);
|
const overdue = isBillOverdue(bill);
|
||||||
@@ -28,6 +40,7 @@ export function BillListItem({ bill, onPay }: BillListItemProps) {
|
|||||||
statusLabel && statusLabel !== absoluteStatusLabel
|
statusLabel && statusLabel !== absoluteStatusLabel
|
||||||
? absoluteStatusLabel
|
? absoluteStatusLabel
|
||||||
: null;
|
: null;
|
||||||
|
const href = buildTransactionsHref(bill.name, period);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li className="flex items-center justify-between transition-all duration-300 py-1.5">
|
<li className="flex items-center justify-between transition-all duration-300 py-1.5">
|
||||||
@@ -35,9 +48,16 @@ export function BillListItem({ bill, onPay }: BillListItemProps) {
|
|||||||
<EstablishmentLogo name={bill.name} size={37} />
|
<EstablishmentLogo name={bill.name} size={37} />
|
||||||
|
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<span className="block truncate text-sm font-medium text-foreground">
|
<Link
|
||||||
{bill.name}
|
href={href}
|
||||||
</span>
|
className="inline-flex max-w-full items-center gap-1 text-sm font-medium text-foreground underline-offset-2 hover:text-primary hover:underline"
|
||||||
|
>
|
||||||
|
<span className="truncate">{bill.name}</span>
|
||||||
|
<RiExternalLinkLine
|
||||||
|
className="size-3 shrink-0 text-muted-foreground"
|
||||||
|
aria-hidden
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
<div className="flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
|
<div className="flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
|
||||||
{statusLabel ? (
|
{statusLabel ? (
|
||||||
statusTooltipLabel ? (
|
statusTooltipLabel ? (
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ import { BillListItem } from "./bill-list-item";
|
|||||||
|
|
||||||
type BillsListProps = {
|
type BillsListProps = {
|
||||||
bills: DashboardBill[];
|
bills: DashboardBill[];
|
||||||
|
period?: string;
|
||||||
onPay: (billId: string) => void;
|
onPay: (billId: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function BillsList({ bills, onPay }: BillsListProps) {
|
export function BillsList({ bills, period, onPay }: BillsListProps) {
|
||||||
if (bills.length === 0) {
|
if (bills.length === 0) {
|
||||||
return (
|
return (
|
||||||
<WidgetEmptyState
|
<WidgetEmptyState
|
||||||
@@ -22,7 +23,7 @@ export function BillsList({ bills, onPay }: BillsListProps) {
|
|||||||
return (
|
return (
|
||||||
<ul className="flex flex-col">
|
<ul className="flex flex-col">
|
||||||
{bills.map((bill) => (
|
{bills.map((bill) => (
|
||||||
<BillListItem key={bill.id} bill={bill} onPay={onPay} />
|
<BillListItem key={bill.id} bill={bill} period={period} onPay={onPay} />
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,14 +1,23 @@
|
|||||||
import type { BillDialogState } from "@/features/dashboard/bills/bills-helpers";
|
import type { BillDialogState } from "@/features/dashboard/bills/bills-helpers";
|
||||||
import type { DashboardBill } from "@/features/dashboard/bills/bills-queries";
|
import type {
|
||||||
|
BillPaymentAccountOption,
|
||||||
|
DashboardBill,
|
||||||
|
} from "@/features/dashboard/bills/bills-queries";
|
||||||
import { BillPaymentDialog } from "./bill-payment-dialog";
|
import { BillPaymentDialog } from "./bill-payment-dialog";
|
||||||
import { BillsList } from "./bills-list";
|
import { BillsList } from "./bills-list";
|
||||||
|
|
||||||
type BillsWidgetViewProps = {
|
type BillsWidgetViewProps = {
|
||||||
bills: DashboardBill[];
|
bills: DashboardBill[];
|
||||||
|
period?: string;
|
||||||
selectedBill: DashboardBill | null;
|
selectedBill: DashboardBill | null;
|
||||||
isModalOpen: boolean;
|
isModalOpen: boolean;
|
||||||
modalState: BillDialogState;
|
modalState: BillDialogState;
|
||||||
isPending: boolean;
|
isPending: boolean;
|
||||||
|
paymentAccountId: string;
|
||||||
|
onPaymentAccountChange: (accountId: string) => void;
|
||||||
|
paymentDate: Date;
|
||||||
|
onPaymentDateChange: (date: Date) => void;
|
||||||
|
paymentAccountOptions: BillPaymentAccountOption[];
|
||||||
onOpenPaymentDialog: (billId: string) => void;
|
onOpenPaymentDialog: (billId: string) => void;
|
||||||
onClosePaymentDialog: () => void;
|
onClosePaymentDialog: () => void;
|
||||||
onConfirmPayment: () => void;
|
onConfirmPayment: () => void;
|
||||||
@@ -16,10 +25,16 @@ type BillsWidgetViewProps = {
|
|||||||
|
|
||||||
export function BillsWidgetView({
|
export function BillsWidgetView({
|
||||||
bills,
|
bills,
|
||||||
|
period,
|
||||||
selectedBill,
|
selectedBill,
|
||||||
isModalOpen,
|
isModalOpen,
|
||||||
modalState,
|
modalState,
|
||||||
isPending,
|
isPending,
|
||||||
|
paymentAccountId,
|
||||||
|
onPaymentAccountChange,
|
||||||
|
paymentDate,
|
||||||
|
onPaymentDateChange,
|
||||||
|
paymentAccountOptions,
|
||||||
onOpenPaymentDialog,
|
onOpenPaymentDialog,
|
||||||
onClosePaymentDialog,
|
onClosePaymentDialog,
|
||||||
onConfirmPayment,
|
onConfirmPayment,
|
||||||
@@ -27,7 +42,7 @@ export function BillsWidgetView({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<BillsList bills={bills} onPay={onOpenPaymentDialog} />
|
<BillsList bills={bills} period={period} onPay={onOpenPaymentDialog} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<BillPaymentDialog
|
<BillPaymentDialog
|
||||||
@@ -35,6 +50,11 @@ export function BillsWidgetView({
|
|||||||
open={isModalOpen}
|
open={isModalOpen}
|
||||||
modalState={modalState}
|
modalState={modalState}
|
||||||
isPending={isPending}
|
isPending={isPending}
|
||||||
|
paymentAccountId={paymentAccountId}
|
||||||
|
onPaymentAccountChange={onPaymentAccountChange}
|
||||||
|
paymentDate={paymentDate}
|
||||||
|
onPaymentDateChange={onPaymentDateChange}
|
||||||
|
paymentAccountOptions={paymentAccountOptions}
|
||||||
onClose={onClosePaymentDialog}
|
onClose={onClosePaymentDialog}
|
||||||
onConfirm={onConfirmPayment}
|
onConfirm={onConfirmPayment}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,20 +1,35 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import type { DashboardBill } from "@/features/dashboard/bills/bills-queries";
|
import type {
|
||||||
|
BillPaymentAccountOption,
|
||||||
|
DashboardBill,
|
||||||
|
} from "@/features/dashboard/bills/bills-queries";
|
||||||
import { useBillWidgetController } from "@/features/dashboard/bills/use-bill-widget-controller";
|
import { useBillWidgetController } from "@/features/dashboard/bills/use-bill-widget-controller";
|
||||||
import { BillsWidgetView } from "../bills/bills-widget-view";
|
import { BillsWidgetView } from "../bills/bills-widget-view";
|
||||||
|
|
||||||
type BillWidgetProps = {
|
type BillWidgetProps = {
|
||||||
bills?: DashboardBill[];
|
bills?: DashboardBill[];
|
||||||
|
paymentAccountOptions?: BillPaymentAccountOption[];
|
||||||
|
period?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function BillWidget({ bills }: BillWidgetProps) {
|
const EMPTY_OPTIONS: BillPaymentAccountOption[] = [];
|
||||||
|
|
||||||
|
export function BillWidget({
|
||||||
|
bills,
|
||||||
|
paymentAccountOptions = EMPTY_OPTIONS,
|
||||||
|
period,
|
||||||
|
}: BillWidgetProps) {
|
||||||
const {
|
const {
|
||||||
items,
|
items,
|
||||||
selectedBill,
|
selectedBill,
|
||||||
isModalOpen,
|
isModalOpen,
|
||||||
modalState,
|
modalState,
|
||||||
isPending,
|
isPending,
|
||||||
|
paymentAccountId,
|
||||||
|
setPaymentAccountId,
|
||||||
|
paymentDate,
|
||||||
|
setPaymentDate,
|
||||||
openPaymentDialog,
|
openPaymentDialog,
|
||||||
closePaymentDialog,
|
closePaymentDialog,
|
||||||
confirmPayment,
|
confirmPayment,
|
||||||
@@ -23,10 +38,16 @@ export function BillWidget({ bills }: BillWidgetProps) {
|
|||||||
return (
|
return (
|
||||||
<BillsWidgetView
|
<BillsWidgetView
|
||||||
bills={items}
|
bills={items}
|
||||||
|
period={period}
|
||||||
selectedBill={selectedBill}
|
selectedBill={selectedBill}
|
||||||
isModalOpen={isModalOpen}
|
isModalOpen={isModalOpen}
|
||||||
modalState={modalState}
|
modalState={modalState}
|
||||||
isPending={isPending}
|
isPending={isPending}
|
||||||
|
paymentAccountId={paymentAccountId}
|
||||||
|
onPaymentAccountChange={setPaymentAccountId}
|
||||||
|
paymentDate={paymentDate}
|
||||||
|
onPaymentDateChange={setPaymentDate}
|
||||||
|
paymentAccountOptions={paymentAccountOptions}
|
||||||
onOpenPaymentDialog={openPaymentDialog}
|
onOpenPaymentDialog={openPaymentDialog}
|
||||||
onClosePaymentDialog={closePaymentDialog}
|
onClosePaymentDialog={closePaymentDialog}
|
||||||
onConfirmPayment={confirmPayment}
|
onConfirmPayment={confirmPayment}
|
||||||
|
|||||||
@@ -93,7 +93,10 @@ export const widgetsConfig: WidgetConfig[] = [
|
|||||||
subtitle: "Resumo das faturas do período",
|
subtitle: "Resumo das faturas do período",
|
||||||
icon: <RiBillLine className="size-4" />,
|
icon: <RiBillLine className="size-4" />,
|
||||||
component: ({ data }) => (
|
component: ({ data }) => (
|
||||||
<InvoicesWidget invoices={data.invoicesSnapshot.invoices} />
|
<InvoicesWidget
|
||||||
|
invoices={data.invoicesSnapshot.invoices}
|
||||||
|
paymentAccountOptions={data.invoicesSnapshot.paymentAccountOptions}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -101,7 +104,13 @@ export const widgetsConfig: WidgetConfig[] = [
|
|||||||
title: "Boletos",
|
title: "Boletos",
|
||||||
subtitle: "Controle de boletos do período",
|
subtitle: "Controle de boletos do período",
|
||||||
icon: <RiBarcodeLine className="size-4" />,
|
icon: <RiBarcodeLine className="size-4" />,
|
||||||
component: ({ data }) => <BillWidget bills={data.billsSnapshot.bills} />,
|
component: ({ data, period }) => (
|
||||||
|
<BillWidget
|
||||||
|
bills={data.billsSnapshot.bills}
|
||||||
|
paymentAccountOptions={data.invoicesSnapshot.paymentAccountOptions}
|
||||||
|
period={period}
|
||||||
|
/>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "payment-status",
|
id: "payment-status",
|
||||||
|
|||||||
Reference in New Issue
Block a user