ui: substitui confirm() por Dialog na exclusão de template
Melhora UX da exclusão de templates de checklist usando modal estilizado ao invés do alert nativo do navegador. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
cf7ff01e34
commit
3c939f9ce4
1 changed files with 30 additions and 7 deletions
|
|
@ -13,7 +13,7 @@ import { Badge } from "@/components/ui/badge"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||||
import { Checkbox } from "@/components/ui/checkbox"
|
import { Checkbox } from "@/components/ui/checkbox"
|
||||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"
|
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"
|
||||||
import { Input } from "@/components/ui/input"
|
import { Input } from "@/components/ui/input"
|
||||||
import { Label } from "@/components/ui/label"
|
import { Label } from "@/components/ui/label"
|
||||||
import { SearchableCombobox, type SearchableComboboxOption } from "@/components/ui/searchable-combobox"
|
import { SearchableCombobox, type SearchableComboboxOption } from "@/components/ui/searchable-combobox"
|
||||||
|
|
@ -254,6 +254,8 @@ export function ChecklistTemplatesManager() {
|
||||||
const [includeArchived, setIncludeArchived] = useState(false)
|
const [includeArchived, setIncludeArchived] = useState(false)
|
||||||
const [editorOpen, setEditorOpen] = useState(false)
|
const [editorOpen, setEditorOpen] = useState(false)
|
||||||
const [editing, setEditing] = useState<ChecklistTemplateRow | null>(null)
|
const [editing, setEditing] = useState<ChecklistTemplateRow | null>(null)
|
||||||
|
const [deleteTarget, setDeleteTarget] = useState<ChecklistTemplateRow | null>(null)
|
||||||
|
const [deleting, setDeleting] = useState(false)
|
||||||
|
|
||||||
const templates = useQuery(
|
const templates = useQuery(
|
||||||
api.checklistTemplates.list,
|
api.checklistTemplates.list,
|
||||||
|
|
@ -304,19 +306,21 @@ export function ChecklistTemplatesManager() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDelete = async (tpl: ChecklistTemplateRow) => {
|
const handleDeleteConfirm = async () => {
|
||||||
if (!viewerId) return
|
if (!viewerId || !deleteTarget) return
|
||||||
const ok = confirm(`Excluir o template "${tpl.name}"? Esta ação não pode ser desfeita.`)
|
setDeleting(true)
|
||||||
if (!ok) return
|
|
||||||
try {
|
try {
|
||||||
await removeTemplate({
|
await removeTemplate({
|
||||||
tenantId,
|
tenantId,
|
||||||
actorId: viewerId,
|
actorId: viewerId,
|
||||||
templateId: tpl.id,
|
templateId: deleteTarget.id,
|
||||||
})
|
})
|
||||||
toast.success("Template excluído.")
|
toast.success("Template excluído.")
|
||||||
|
setDeleteTarget(null)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error(error instanceof Error ? error.message : "Falha ao excluir template.")
|
toast.error(error instanceof Error ? error.message : "Falha ao excluir template.")
|
||||||
|
} finally {
|
||||||
|
setDeleting(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -394,7 +398,7 @@ export function ChecklistTemplatesManager() {
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="text-slate-500 hover:bg-red-50 hover:text-red-700"
|
className="text-slate-500 hover:bg-red-50 hover:text-red-700"
|
||||||
onClick={() => handleDelete(tpl)}
|
onClick={() => setDeleteTarget(tpl)}
|
||||||
title="Excluir template"
|
title="Excluir template"
|
||||||
>
|
>
|
||||||
<Trash2 className="size-4" />
|
<Trash2 className="size-4" />
|
||||||
|
|
@ -414,6 +418,25 @@ export function ChecklistTemplatesManager() {
|
||||||
template={editing}
|
template={editing}
|
||||||
companies={companyOptions}
|
companies={companyOptions}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Dialog open={Boolean(deleteTarget)} onOpenChange={(open) => !open && setDeleteTarget(null)}>
|
||||||
|
<DialogContent className="max-w-md">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Excluir template</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
Tem certeza que deseja excluir o template <strong>"{deleteTarget?.name}"</strong>? Esta ação não pode ser desfeita.
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<DialogFooter className="gap-2 sm:gap-0">
|
||||||
|
<Button type="button" variant="outline" onClick={() => setDeleteTarget(null)} disabled={deleting}>
|
||||||
|
Cancelar
|
||||||
|
</Button>
|
||||||
|
<Button type="button" variant="destructive" onClick={handleDeleteConfirm} disabled={deleting}>
|
||||||
|
{deleting ? "Excluindo..." : "Excluir"}
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue