UI: reemplazar diálogos nativos del navegador por modales/avisos propios de la plataforma

Los confirm()/alert()/prompt() nativos se veían fuera de la marca ("<dominio> dice…").
Se agrega un DialogProvider (montado en el layout autenticado) con su estilo visual y se
consume via hooks useConfirm / usePrompt / useToast:
- confirmaciones -> modal propio (con variante "peligro" para eliminaciones)
- prompts (crear paquete / fase) -> modal con input
- alerts de error/éxito -> toasts

Reemplazados todos los diálogos nativos: RegistroHorasPanel, CatalogoClient,
ConfiguracionClient, CotizacionForm, ExportButtons, ListDeleteButton, DeleteButton,
CambiarEstadoButtons. Validado E2E (Playwright): al revertir una partida pagada aparece
el modal propio y NO se dispara el confirm nativo.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
urieljareth
2026-07-11 14:51:22 -06:00
co-authored by Claude Opus 4.8
parent 1aab45f29c
commit 26e6d3a9bf
10 changed files with 394 additions and 35 deletions
@@ -2,20 +2,29 @@
import { useState } from "react";
import { useRouter } from "next/navigation";
import { useConfirm, useToast } from "@/components/ui/DialogProvider";
export function ListDeleteButton({ id }: { id: string }) {
const [deleting, setDeleting] = useState(false);
const router = useRouter();
const showConfirm = useConfirm();
const showToast = useToast();
const handleDelete = async () => {
if (!confirm("Eliminar esta cotizacion?")) return;
const ok = await showConfirm({
title: "Eliminar cotización",
message: "¿Eliminar esta cotización?",
confirmText: "Eliminar",
danger: true,
});
if (!ok) return;
setDeleting(true);
try {
const res = await fetch(`/api/cotizaciones/${id}`, { method: "DELETE" });
if (res.ok) router.refresh();
else alert("Error al eliminar");
else showToast("Error al eliminar", "error");
} catch {
alert("Error al eliminar");
showToast("Error al eliminar", "error");
} finally {
setDeleting(false);
}