refactor(ui): unificar páginas ativas/arquivadas com tabs (v1.3.1)

Substitui rotas separadas de inativos/arquivados por tabs inline em
Cartões, Contas e Anotações, seguindo o padrão já usado em Categorias.
Remove sub-links da sidebar e padroniza nomenclatura para "Arquivados".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Felipe Coutinho
2026-02-06 13:20:15 +00:00
parent 6f5c41a4cf
commit 4152a27f4d
15 changed files with 330 additions and 278 deletions

View File

@@ -10,6 +10,7 @@ import {
import { ConfirmActionDialog } from "@/components/confirm-action-dialog";
import { EmptyState } from "@/components/empty-state";
import { Button } from "@/components/ui/button";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Card } from "../ui/card";
import { NoteCard } from "./note-card";
import { NoteDetailsDialog } from "./note-details-dialog";
@@ -18,10 +19,11 @@ import type { Note } from "./types";
interface NotesPageProps {
notes: Note[];
isArquivadas?: boolean;
archivedNotes: Note[];
}
export function NotesPage({ notes, isArquivadas = false }: NotesPageProps) {
export function NotesPage({ notes, archivedNotes }: NotesPageProps) {
const [activeTab, setActiveTab] = useState("ativas");
const [createOpen, setCreateOpen] = useState(false);
const [editOpen, setEditOpen] = useState(false);
const [noteToEdit, setNoteToEdit] = useState<Note | null>(null);
@@ -32,15 +34,23 @@ export function NotesPage({ notes, isArquivadas = false }: NotesPageProps) {
const [arquivarOpen, setArquivarOpen] = useState(false);
const [noteToArquivar, setNoteToArquivar] = useState<Note | null>(null);
const sortedNotes = useMemo(
() =>
[...notes].sort(
const sortNotes = useCallback(
(list: Note[]) =>
[...list].sort(
(a, b) =>
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
),
[notes],
[],
);
const sortedNotes = useMemo(() => sortNotes(notes), [notes, sortNotes]);
const sortedArchivedNotes = useMemo(
() => sortNotes(archivedNotes),
[archivedNotes, sortNotes],
);
const isArquivadas = activeTab === "arquivadas";
const handleCreateOpenChange = useCallback((open: boolean) => {
setCreateOpen(open);
}, []);
@@ -146,56 +156,75 @@ export function NotesPage({ notes, isArquivadas = false }: NotesPageProps) {
? "Desarquivar anotação?"
: "Arquivar anotação?";
const renderNoteList = (list: Note[], isArchived: boolean) => {
if (list.length === 0) {
return (
<Card className="flex min-h-[50vh] w-full items-center justify-center py-12">
<EmptyState
media={<RiTodoLine className="size-6 text-primary" />}
title={
isArchived
? "Nenhuma anotação arquivada"
: "Nenhuma anotação registrada"
}
description={
isArchived
? "As anotações arquivadas aparecerão aqui."
: "Crie anotações personalizadas para acompanhar lembretes, decisões ou observações financeiras importantes."
}
/>
</Card>
);
}
return (
<div className="flex flex-wrap gap-4">
{list.map((note) => (
<NoteCard
key={note.id}
note={note}
onEdit={handleEditRequest}
onDetails={handleDetailsRequest}
onRemove={handleRemoveRequest}
onArquivar={handleArquivarRequest}
isArquivadas={isArchived}
/>
))}
</div>
);
};
return (
<>
<div className="flex w-full flex-col gap-6">
{!isArquivadas && (
<div className="flex justify-start">
<NoteDialog
mode="create"
open={createOpen}
onOpenChange={handleCreateOpenChange}
trigger={
<Button>
<RiAddCircleLine className="size-4" />
Nova anotação
</Button>
}
/>
</div>
)}
<div className="flex justify-start">
<NoteDialog
mode="create"
open={createOpen}
onOpenChange={handleCreateOpenChange}
trigger={
<Button>
<RiAddCircleLine className="size-4" />
Nova anotação
</Button>
}
/>
</div>
{sortedNotes.length === 0 ? (
<Card className="flex min-h-[50vh] w-full items-center justify-center py-12">
<EmptyState
media={<RiTodoLine className="size-6 text-primary" />}
title={
isArquivadas
? "Nenhuma anotação arquivada"
: "Nenhuma anotação registrada"
}
description={
isArquivadas
? "As anotações arquivadas aparecerão aqui."
: "Crie anotações personalizadas para acompanhar lembretes, decisões ou observações financeiras importantes."
}
/>
</Card>
) : (
<div className="flex flex-wrap gap-4">
{sortedNotes.map((note) => (
<NoteCard
key={note.id}
note={note}
onEdit={handleEditRequest}
onDetails={handleDetailsRequest}
onRemove={handleRemoveRequest}
onArquivar={handleArquivarRequest}
isArquivadas={isArquivadas}
/>
))}
</div>
)}
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
<TabsList>
<TabsTrigger value="ativas">Ativas</TabsTrigger>
<TabsTrigger value="arquivadas">Arquivadas</TabsTrigger>
</TabsList>
<TabsContent value="ativas" className="mt-4">
{renderNoteList(sortedNotes, false)}
</TabsContent>
<TabsContent value="arquivadas" className="mt-4">
{renderNoteList(sortedArchivedNotes, true)}
</TabsContent>
</Tabs>
</div>
<NoteDialog