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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user