style: padronizar note-dialog com Labels e scroll apenas no conteúdo
Adiciona Labels (Título, Conteúdo, Tipo de anotação, Adicionar tarefa) seguindo o padrão dos demais dialogs do projeto (space-y-1 + Label). DialogDescription visível novamente com texto contextual. Scroll apenas no form (-mx-6 max-h-[80vh] overflow-y-auto px-6), header e footer fixos — mesmo padrão do lancamento-dialog. Footer movido para fora do form; submit via requestSubmit(). Corrige useMemo antes do early return no note-details-dialog. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -45,13 +45,14 @@ export function NoteDetailsDialog({
|
||||
};
|
||||
}, [note]);
|
||||
|
||||
const tasks = note?.tasks || [];
|
||||
const sortedTasks = useMemo(() => sortTasksByStatus(tasks), [tasks]);
|
||||
|
||||
if (!note) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isTask = note.type === "tarefa";
|
||||
const tasks = note.tasks || [];
|
||||
const sortedTasks = useMemo(() => sortTasksByStatus(tasks), [tasks]);
|
||||
const completedCount = tasks.filter((t) => t.completed).length;
|
||||
const totalCount = tasks.length;
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { useControlledState } from "@/hooks/use-controlled-state";
|
||||
@@ -76,7 +77,6 @@ export function NoteDialog({
|
||||
const descRef = useRef<HTMLTextAreaElement>(null);
|
||||
const newTaskRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
// Use controlled state hook for dialog open state
|
||||
const [dialogOpen, setDialogOpen] = useControlledState(
|
||||
open,
|
||||
false,
|
||||
@@ -85,7 +85,6 @@ export function NoteDialog({
|
||||
|
||||
const initialState = buildInitialValues(note);
|
||||
|
||||
// Use form state hook for form management
|
||||
const { formState, updateField, setFormState } =
|
||||
useFormState<NoteFormValues>(initialState);
|
||||
|
||||
@@ -98,7 +97,11 @@ export function NoteDialog({
|
||||
}
|
||||
}, [dialogOpen, note, setFormState]);
|
||||
|
||||
const title = mode === "create" ? "Nova anotação" : "Editar anotação";
|
||||
const dialogTitle = mode === "create" ? "Nova anotação" : "Editar anotação";
|
||||
const description =
|
||||
mode === "create"
|
||||
? "Crie uma nota simples ou uma lista de tarefas."
|
||||
: "Altere o conteúdo desta anotação.";
|
||||
const submitLabel = mode === "create" ? "Salvar" : "Atualizar";
|
||||
|
||||
const titleCount = formState.title.length;
|
||||
@@ -224,23 +227,21 @@ export function NoteDialog({
|
||||
return (
|
||||
<Dialog open={dialogOpen} onOpenChange={handleOpenChange}>
|
||||
{trigger ? <DialogTrigger asChild>{trigger}</DialogTrigger> : null}
|
||||
<DialogContent className="max-h-[90vh] overflow-y-auto">
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{title}</DialogTitle>
|
||||
<DialogDescription className="sr-only">
|
||||
{mode === "create"
|
||||
? "Criar nova anotação"
|
||||
: "Editar anotação existente"}
|
||||
</DialogDescription>
|
||||
<DialogTitle>{dialogTitle}</DialogTitle>
|
||||
<DialogDescription>{description}</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<form
|
||||
className="space-y-3"
|
||||
className="space-y-3 -mx-6 max-h-[80vh] overflow-y-auto px-6 pb-1"
|
||||
onSubmit={handleSubmit}
|
||||
onKeyDown={handleKeyDown}
|
||||
noValidate
|
||||
>
|
||||
{mode === "create" && (
|
||||
<div className="space-y-1">
|
||||
<Label>Tipo de anotação</Label>
|
||||
<RadioGroup
|
||||
value={formState.type}
|
||||
onValueChange={(value) =>
|
||||
@@ -251,53 +252,64 @@ export function NoteDialog({
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="nota" id="tipo-nota" />
|
||||
<label
|
||||
<Label
|
||||
htmlFor="tipo-nota"
|
||||
className="text-sm cursor-pointer select-none"
|
||||
className="font-normal cursor-pointer"
|
||||
>
|
||||
Nota
|
||||
</label>
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<RadioGroupItem value="tarefa" id="tipo-tarefa" />
|
||||
<label
|
||||
<Label
|
||||
htmlFor="tipo-tarefa"
|
||||
className="text-sm cursor-pointer select-none"
|
||||
className="font-normal cursor-pointer"
|
||||
>
|
||||
Tarefas
|
||||
</label>
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="note-title">Título</Label>
|
||||
<Input
|
||||
id="note-title"
|
||||
ref={titleRef}
|
||||
value={formState.title}
|
||||
onChange={(e) => updateField("title", e.target.value)}
|
||||
placeholder="Título"
|
||||
placeholder={
|
||||
isNote ? "Ex.: Revisar metas do mês" : "Ex.: Tarefas da semana"
|
||||
}
|
||||
maxLength={MAX_TITLE}
|
||||
disabled={isPending}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{isNote && (
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="note-description">Conteúdo</Label>
|
||||
<Textarea
|
||||
id="note-description"
|
||||
className="field-sizing-fixed"
|
||||
ref={descRef}
|
||||
value={formState.description}
|
||||
onChange={(e) => updateField("description", e.target.value)}
|
||||
placeholder="Escreva sua anotação..."
|
||||
placeholder="Detalhe sua anotação..."
|
||||
rows={5}
|
||||
maxLength={MAX_DESC}
|
||||
disabled={isPending}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isNote && (
|
||||
<div className="space-y-2">
|
||||
<div className="space-y-1">
|
||||
<Label htmlFor="new-task-input">Adicionar tarefa</Label>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
id="new-task-input"
|
||||
@@ -323,6 +335,7 @@ export function NoteDialog({
|
||||
<RiAddLine className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{sortedTasks.length > 0 && (
|
||||
<div className="space-y-1 max-h-[240px] overflow-y-auto pr-1">
|
||||
@@ -370,6 +383,7 @@ export function NoteDialog({
|
||||
{errorMessage}
|
||||
</p>
|
||||
) : null}
|
||||
</form>
|
||||
|
||||
<DialogFooter>
|
||||
<Button
|
||||
@@ -380,11 +394,22 @@ export function NoteDialog({
|
||||
>
|
||||
Cancelar
|
||||
</Button>
|
||||
<Button type="submit" disabled={disableSubmit}>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={disableSubmit}
|
||||
onClick={(e) => {
|
||||
const form = (
|
||||
e.currentTarget.closest("[role=dialog]") as HTMLElement
|
||||
)?.querySelector("form");
|
||||
if (form) {
|
||||
e.preventDefault();
|
||||
form.requestSubmit();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{isPending ? "Salvando..." : submitLabel}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user