forked from git.gladyson/openmonetis
chore: snapshot sidebar layout antes de experimentar topbar
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
|||||||
cartoes,
|
cartoes,
|
||||||
categorias,
|
categorias,
|
||||||
contas,
|
contas,
|
||||||
|
faturas,
|
||||||
lancamentos,
|
lancamentos,
|
||||||
pagadores,
|
pagadores,
|
||||||
} from "@/db/schema";
|
} from "@/db/schema";
|
||||||
@@ -32,6 +33,7 @@ import {
|
|||||||
import { noteSchema, uuidSchema } from "@/lib/schemas/common";
|
import { noteSchema, uuidSchema } from "@/lib/schemas/common";
|
||||||
import { formatDecimalForDbRequired } from "@/lib/utils/currency";
|
import { formatDecimalForDbRequired } from "@/lib/utils/currency";
|
||||||
import { getTodayDate, parseLocalDateString } from "@/lib/utils/date";
|
import { getTodayDate, parseLocalDateString } from "@/lib/utils/date";
|
||||||
|
import { getNextPeriod } from "@/lib/utils/period";
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Authorization Validation Functions
|
// Authorization Validation Functions
|
||||||
@@ -1639,6 +1641,59 @@ export async function deleteMultipleLancamentosAction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check fatura payment status and card closing day for the given period
|
||||||
|
export async function checkFaturaStatusAction(
|
||||||
|
cartaoId: string,
|
||||||
|
period: string,
|
||||||
|
): Promise<{
|
||||||
|
shouldSuggestNext: boolean;
|
||||||
|
isPaid: boolean;
|
||||||
|
isAfterClosing: boolean;
|
||||||
|
closingDay: string | null;
|
||||||
|
cardName: string;
|
||||||
|
nextPeriod: string;
|
||||||
|
} | null> {
|
||||||
|
try {
|
||||||
|
const user = await getUser();
|
||||||
|
|
||||||
|
const cartao = await db.query.cartoes.findFirst({
|
||||||
|
where: and(eq(cartoes.id, cartaoId), eq(cartoes.userId, user.id)),
|
||||||
|
columns: { id: true, name: true, closingDay: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!cartao) return null;
|
||||||
|
|
||||||
|
const fatura = await db.query.faturas.findFirst({
|
||||||
|
where: and(
|
||||||
|
eq(faturas.cartaoId, cartaoId),
|
||||||
|
eq(faturas.userId, user.id),
|
||||||
|
eq(faturas.period, period),
|
||||||
|
),
|
||||||
|
columns: { paymentStatus: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
const isPaid = fatura?.paymentStatus === "pago";
|
||||||
|
const today = new Date();
|
||||||
|
const currentPeriod = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}`;
|
||||||
|
const closingDayNum = Number.parseInt(cartao.closingDay ?? "", 10);
|
||||||
|
const isAfterClosing =
|
||||||
|
period === currentPeriod &&
|
||||||
|
!Number.isNaN(closingDayNum) &&
|
||||||
|
today.getDate() > closingDayNum;
|
||||||
|
|
||||||
|
return {
|
||||||
|
shouldSuggestNext: isPaid || isAfterClosing,
|
||||||
|
isPaid,
|
||||||
|
isAfterClosing,
|
||||||
|
closingDay: cartao.closingDay,
|
||||||
|
cardName: cartao.name,
|
||||||
|
nextPeriod: getNextPeriod(period),
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get unique establishment names from the last 3 months
|
// Get unique establishment names from the last 3 months
|
||||||
export async function getRecentEstablishmentsAction(): Promise<string[]> {
|
export async function getRecentEstablishmentsAction(): Promise<string[]> {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export default async function DashboardLayout({
|
|||||||
<SiteHeader notificationsSnapshot={notificationsSnapshot} />
|
<SiteHeader notificationsSnapshot={notificationsSnapshot} />
|
||||||
<div className="flex flex-1 flex-col pt-12 md:pt-0">
|
<div className="flex flex-1 flex-col pt-12 md:pt-0">
|
||||||
<div className="@container/main flex flex-1 flex-col gap-2">
|
<div className="@container/main flex flex-1 flex-col gap-2">
|
||||||
<div className="flex flex-col gap-4 py-4 md:gap-6">
|
<div className="flex flex-col gap-4 py-4 md:gap-6 w-full max-w-8xl mx-auto">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
@theme {
|
@theme {
|
||||||
--spacing-custom-height-1: 30rem;
|
--spacing-custom-height-1: 30rem;
|
||||||
|
--spacing-8xl: 88rem; /* 1408px */
|
||||||
|
--spacing-9xl: 96rem; /* 1536px */
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
|||||||
84
components/lancamentos/dialogs/fatura-warning-dialog.tsx
Normal file
84
components/lancamentos/dialogs/fatura-warning-dialog.tsx
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import {
|
||||||
|
AlertDialog,
|
||||||
|
AlertDialogAction,
|
||||||
|
AlertDialogCancel,
|
||||||
|
AlertDialogContent,
|
||||||
|
AlertDialogDescription,
|
||||||
|
AlertDialogFooter,
|
||||||
|
AlertDialogHeader,
|
||||||
|
AlertDialogTitle,
|
||||||
|
} from "@/components/ui/alert-dialog";
|
||||||
|
import { MONTH_NAMES } from "@/lib/utils/period";
|
||||||
|
|
||||||
|
export type FaturaWarning = {
|
||||||
|
nextPeriod: string;
|
||||||
|
cardName: string;
|
||||||
|
isPaid: boolean;
|
||||||
|
isAfterClosing: boolean;
|
||||||
|
closingDay: string | null;
|
||||||
|
currentPeriod: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function formatPeriodDisplay(period: string): string {
|
||||||
|
const [yearStr, monthStr] = period.split("-");
|
||||||
|
const monthIndex = Number.parseInt(monthStr ?? "1", 10) - 1;
|
||||||
|
const monthName = MONTH_NAMES[monthIndex] ?? monthStr;
|
||||||
|
return `${monthName}/${yearStr}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildWarningMessage(warning: FaturaWarning): string {
|
||||||
|
const currentDisplay = formatPeriodDisplay(warning.currentPeriod);
|
||||||
|
if (warning.isPaid && warning.isAfterClosing) {
|
||||||
|
return `A fatura do ${warning.cardName} em ${currentDisplay} já está paga e fechou no dia ${warning.closingDay}.`;
|
||||||
|
}
|
||||||
|
if (warning.isPaid) {
|
||||||
|
return `A fatura do ${warning.cardName} em ${currentDisplay} já está paga.`;
|
||||||
|
}
|
||||||
|
return `A fatura do ${warning.cardName} fechou no dia ${warning.closingDay}.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FaturaWarningDialogProps {
|
||||||
|
warning: FaturaWarning | null;
|
||||||
|
onConfirm: (nextPeriod: string) => void;
|
||||||
|
onCancel: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function FaturaWarningDialog({
|
||||||
|
warning,
|
||||||
|
onConfirm,
|
||||||
|
onCancel,
|
||||||
|
}: FaturaWarningDialogProps) {
|
||||||
|
if (!warning) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AlertDialog
|
||||||
|
open
|
||||||
|
onOpenChange={(open) => {
|
||||||
|
if (!open) onCancel();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AlertDialogContent className="sm:max-w-md">
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>Fatura indisponível</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>
|
||||||
|
{buildWarningMessage(warning)} Deseja registrá-lo em{" "}
|
||||||
|
<span className="font-medium text-foreground">
|
||||||
|
{formatPeriodDisplay(warning.nextPeriod)}
|
||||||
|
</span>
|
||||||
|
?
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter className="flex-col gap-2 sm:flex-col">
|
||||||
|
<AlertDialogAction onClick={() => onConfirm(warning.nextPeriod)}>
|
||||||
|
Mover para {formatPeriodDisplay(warning.nextPeriod)}
|
||||||
|
</AlertDialogAction>
|
||||||
|
<AlertDialogCancel onClick={onCancel}>
|
||||||
|
Manter em {formatPeriodDisplay(warning.currentPeriod)}
|
||||||
|
</AlertDialogCancel>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -3,11 +3,13 @@ import {
|
|||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
useTransition,
|
useTransition,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import {
|
import {
|
||||||
|
checkFaturaStatusAction,
|
||||||
createLancamentoAction,
|
createLancamentoAction,
|
||||||
updateLancamentoAction,
|
updateLancamentoAction,
|
||||||
} from "@/app/(dashboard)/lancamentos/actions";
|
} from "@/app/(dashboard)/lancamentos/actions";
|
||||||
@@ -30,6 +32,10 @@ import {
|
|||||||
applyFieldDependencies,
|
applyFieldDependencies,
|
||||||
buildLancamentoInitialState,
|
buildLancamentoInitialState,
|
||||||
} from "@/lib/lancamentos/form-helpers";
|
} from "@/lib/lancamentos/form-helpers";
|
||||||
|
import {
|
||||||
|
type FaturaWarning,
|
||||||
|
FaturaWarningDialog,
|
||||||
|
} from "../fatura-warning-dialog";
|
||||||
import { BasicFieldsSection } from "./basic-fields-section";
|
import { BasicFieldsSection } from "./basic-fields-section";
|
||||||
import { BoletoFieldsSection } from "./boleto-fields-section";
|
import { BoletoFieldsSection } from "./boleto-fields-section";
|
||||||
import { CategorySection } from "./category-section";
|
import { CategorySection } from "./category-section";
|
||||||
@@ -90,6 +96,10 @@ export function LancamentoDialog({
|
|||||||
const [periodDirty, setPeriodDirty] = useState(false);
|
const [periodDirty, setPeriodDirty] = useState(false);
|
||||||
const [isPending, startTransition] = useTransition();
|
const [isPending, startTransition] = useTransition();
|
||||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||||
|
const [faturaWarning, setFaturaWarning] = useState<FaturaWarning | null>(
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
const lastCheckedRef = useRef<string | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (dialogOpen) {
|
if (dialogOpen) {
|
||||||
@@ -111,6 +121,10 @@ export function LancamentoDialog({
|
|||||||
);
|
);
|
||||||
setErrorMessage(null);
|
setErrorMessage(null);
|
||||||
setPeriodDirty(false);
|
setPeriodDirty(false);
|
||||||
|
setFaturaWarning(null);
|
||||||
|
lastCheckedRef.current = null;
|
||||||
|
} else {
|
||||||
|
setFaturaWarning(null);
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
dialogOpen,
|
dialogOpen,
|
||||||
@@ -126,6 +140,40 @@ export function LancamentoDialog({
|
|||||||
isImporting,
|
isImporting,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (mode !== "create") return;
|
||||||
|
if (!dialogOpen) return;
|
||||||
|
if (formState.paymentMethod !== "Cartão de crédito") return;
|
||||||
|
if (!formState.cartaoId) return;
|
||||||
|
|
||||||
|
const checkKey = `${formState.cartaoId}:${formState.period}`;
|
||||||
|
if (checkKey === lastCheckedRef.current) return;
|
||||||
|
lastCheckedRef.current = checkKey;
|
||||||
|
|
||||||
|
checkFaturaStatusAction(formState.cartaoId, formState.period).then(
|
||||||
|
(result) => {
|
||||||
|
if (result?.shouldSuggestNext) {
|
||||||
|
setFaturaWarning({
|
||||||
|
nextPeriod: result.nextPeriod,
|
||||||
|
cardName: result.cardName,
|
||||||
|
isPaid: result.isPaid,
|
||||||
|
isAfterClosing: result.isAfterClosing,
|
||||||
|
closingDay: result.closingDay,
|
||||||
|
currentPeriod: formState.period,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setFaturaWarning(null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}, [
|
||||||
|
mode,
|
||||||
|
dialogOpen,
|
||||||
|
formState.paymentMethod,
|
||||||
|
formState.cartaoId,
|
||||||
|
formState.period,
|
||||||
|
]);
|
||||||
|
|
||||||
const primaryPagador = formState.pagadorId;
|
const primaryPagador = formState.pagadorId;
|
||||||
|
|
||||||
const secondaryPagadorOptions = useMemo(
|
const secondaryPagadorOptions = useMemo(
|
||||||
@@ -392,6 +440,7 @@ export function LancamentoDialog({
|
|||||||
const disableCartaoSelect = Boolean(lockCartaoSelection && mode === "create");
|
const disableCartaoSelect = Boolean(lockCartaoSelection && mode === "create");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
||||||
{trigger ? <DialogTrigger asChild>{trigger}</DialogTrigger> : null}
|
{trigger ? <DialogTrigger asChild>{trigger}</DialogTrigger> : null}
|
||||||
<DialogContent className="sm:max-w-xl p-6 sm:px-8">
|
<DialogContent className="sm:max-w-xl p-6 sm:px-8">
|
||||||
@@ -490,5 +539,15 @@ export function LancamentoDialog({
|
|||||||
</form>
|
</form>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
|
<FaturaWarningDialog
|
||||||
|
warning={faturaWarning}
|
||||||
|
onConfirm={(nextPeriod) => {
|
||||||
|
handleFieldChange("period", nextPeriod);
|
||||||
|
setFaturaWarning(null);
|
||||||
|
}}
|
||||||
|
onCancel={() => setFaturaWarning(null)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { RiAddLine, RiDeleteBinLine } from "@remixicon/react";
|
import { RiAddLine, RiDeleteBinLine } from "@remixicon/react";
|
||||||
import { useMemo, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
import { checkFaturaStatusAction } from "@/app/(dashboard)/lancamentos/actions";
|
||||||
import { PeriodPicker } from "@/components/period-picker";
|
import { PeriodPicker } from "@/components/period-picker";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { CurrencyInput } from "@/components/ui/currency-input";
|
import { CurrencyInput } from "@/components/ui/currency-input";
|
||||||
@@ -39,6 +40,10 @@ import {
|
|||||||
TransactionTypeSelectContent,
|
TransactionTypeSelectContent,
|
||||||
} from "../select-items";
|
} from "../select-items";
|
||||||
import { EstabelecimentoInput } from "../shared/estabelecimento-input";
|
import { EstabelecimentoInput } from "../shared/estabelecimento-input";
|
||||||
|
import {
|
||||||
|
type FaturaWarning,
|
||||||
|
FaturaWarningDialog,
|
||||||
|
} from "./fatura-warning-dialog";
|
||||||
|
|
||||||
interface MassAddDialogProps {
|
interface MassAddDialogProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@@ -119,6 +124,39 @@ export function MassAddDialog({
|
|||||||
? contaCartaoId.replace("cartao:", "")
|
? contaCartaoId.replace("cartao:", "")
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
const [faturaWarning, setFaturaWarning] = useState<FaturaWarning | null>(
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
const lastCheckedRef = useRef<string | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!open) {
|
||||||
|
setFaturaWarning(null);
|
||||||
|
lastCheckedRef.current = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isCartaoSelected || !cartaoId) return;
|
||||||
|
|
||||||
|
const checkKey = `${cartaoId}:${period}`;
|
||||||
|
if (checkKey === lastCheckedRef.current) return;
|
||||||
|
lastCheckedRef.current = checkKey;
|
||||||
|
|
||||||
|
checkFaturaStatusAction(cartaoId, period).then((result) => {
|
||||||
|
if (result?.shouldSuggestNext) {
|
||||||
|
setFaturaWarning({
|
||||||
|
nextPeriod: result.nextPeriod,
|
||||||
|
cardName: result.cardName,
|
||||||
|
isPaid: result.isPaid,
|
||||||
|
isAfterClosing: result.isAfterClosing,
|
||||||
|
closingDay: result.closingDay,
|
||||||
|
currentPeriod: period,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setFaturaWarning(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [open, isCartaoSelected, cartaoId, period]);
|
||||||
|
|
||||||
// Transaction rows
|
// Transaction rows
|
||||||
const [transactions, setTransactions] = useState<TransactionRow[]>([
|
const [transactions, setTransactions] = useState<TransactionRow[]>([
|
||||||
{
|
{
|
||||||
@@ -238,13 +276,14 @@ export function MassAddDialog({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||||
<DialogContent className="sm:max-w-3xl max-h-[90vh] overflow-y-auto p-6 sm:px-8">
|
<DialogContent className="sm:max-w-3xl max-h-[90vh] overflow-y-auto p-6 sm:px-8">
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Adicionar múltiplos lançamentos</DialogTitle>
|
<DialogTitle>Adicionar múltiplos lançamentos</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
Configure os valores padrão e adicione várias transações de uma vez.
|
Configure os valores padrão e adicione várias transações de uma
|
||||||
Todos os lançamentos adicionados aqui são{" "}
|
vez. Todos os lançamentos adicionados aqui são{" "}
|
||||||
<span className="font-bold">sempre à vista</span>.
|
<span className="font-bold">sempre à vista</span>.
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
@@ -264,7 +303,9 @@ export function MassAddDialog({
|
|||||||
<SelectTrigger id="transaction-type" className="w-full">
|
<SelectTrigger id="transaction-type" className="w-full">
|
||||||
<SelectValue>
|
<SelectValue>
|
||||||
{transactionType && (
|
{transactionType && (
|
||||||
<TransactionTypeSelectContent label={transactionType} />
|
<TransactionTypeSelectContent
|
||||||
|
label={transactionType}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</SelectValue>
|
</SelectValue>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
@@ -492,7 +533,11 @@ export function MassAddDialog({
|
|||||||
<Select
|
<Select
|
||||||
value={transaction.pagadorId}
|
value={transaction.pagadorId}
|
||||||
onValueChange={(value) =>
|
onValueChange={(value) =>
|
||||||
updateTransaction(transaction.id, "pagadorId", value)
|
updateTransaction(
|
||||||
|
transaction.id,
|
||||||
|
"pagadorId",
|
||||||
|
value,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SelectTrigger
|
<SelectTrigger
|
||||||
@@ -503,7 +548,8 @@ export function MassAddDialog({
|
|||||||
{transaction.pagadorId &&
|
{transaction.pagadorId &&
|
||||||
(() => {
|
(() => {
|
||||||
const selectedOption = pagadorOptions.find(
|
const selectedOption = pagadorOptions.find(
|
||||||
(opt) => opt.value === transaction.pagadorId,
|
(opt) =>
|
||||||
|
opt.value === transaction.pagadorId,
|
||||||
);
|
);
|
||||||
return selectedOption ? (
|
return selectedOption ? (
|
||||||
<PagadorSelectContent
|
<PagadorSelectContent
|
||||||
@@ -516,7 +562,10 @@ export function MassAddDialog({
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{pagadorOptions.map((option) => (
|
{pagadorOptions.map((option) => (
|
||||||
<SelectItem key={option.value} value={option.value}>
|
<SelectItem
|
||||||
|
key={option.value}
|
||||||
|
value={option.value}
|
||||||
|
>
|
||||||
<PagadorSelectContent
|
<PagadorSelectContent
|
||||||
label={option.label}
|
label={option.label}
|
||||||
avatarUrl={option.avatarUrl}
|
avatarUrl={option.avatarUrl}
|
||||||
@@ -614,5 +663,15 @@ export function MassAddDialog({
|
|||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
|
<FaturaWarningDialog
|
||||||
|
warning={faturaWarning}
|
||||||
|
onConfirm={(nextPeriod) => {
|
||||||
|
setPeriod(nextPeriod);
|
||||||
|
setFaturaWarning(null);
|
||||||
|
}}
|
||||||
|
onCancel={() => setFaturaWarning(null)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user