199 lines
5.8 KiB
TypeScript
199 lines
5.8 KiB
TypeScript
"use client";
|
|
|
|
import React, { useState, useEffect, useMemo } from "react";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
} from "@/components/ui/dialog";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
import { Label } from "@/components/ui/label";
|
|
import { Alert, AlertDescription } from "@/components/ui/alert";
|
|
import { Loader2, ShieldCheck } from "lucide-react";
|
|
import type { AuthorizationRole } from "@/lib/api";
|
|
|
|
export type AuthorizationState = {
|
|
paciente: boolean;
|
|
medico: boolean;
|
|
};
|
|
|
|
export interface UpdateAuthorizationsDialogProperties {
|
|
open: boolean;
|
|
entityType: "paciente" | "medico";
|
|
entityName?: string | null;
|
|
initialRoles?: Partial<AuthorizationState> | null;
|
|
loading?: boolean;
|
|
error?: string | null;
|
|
disableSubmit?: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
onConfirm: (roles: AuthorizationState) => void;
|
|
}
|
|
|
|
const DEFAULT_ROLES: AuthorizationState = { paciente: false, medico: false };
|
|
|
|
export function UpdateAuthorizationsDialog({
|
|
open,
|
|
entityType,
|
|
entityName,
|
|
initialRoles,
|
|
loading = false,
|
|
error,
|
|
disableSubmit = false,
|
|
onOpenChange,
|
|
onConfirm,
|
|
}: UpdateAuthorizationsDialogProperties) {
|
|
const [roles, setRoles] = useState<AuthorizationState>(DEFAULT_ROLES);
|
|
console.log("[Dialog] render", {
|
|
open,
|
|
initialRoles,
|
|
loading,
|
|
disableSubmit,
|
|
roles,
|
|
});
|
|
|
|
useEffect(() => {
|
|
console.log("[Dialog] useEffect open change", open, initialRoles);
|
|
if (open) {
|
|
setRoles({
|
|
paciente: initialRoles?.paciente ?? entityType === "paciente",
|
|
medico: initialRoles?.medico ?? entityType === "medico",
|
|
});
|
|
}
|
|
}, [open, initialRoles, entityType]);
|
|
|
|
// Debug: log when roles state changes
|
|
useEffect(() => {
|
|
console.log("[Dialog] roles updated", roles);
|
|
}, [roles]);
|
|
|
|
const title = useMemo(
|
|
() =>
|
|
entityType === "paciente"
|
|
? "Atualizar autorizações do paciente"
|
|
: "Atualizar autorizações do médico",
|
|
[entityType],
|
|
);
|
|
|
|
const description = useMemo(
|
|
() =>
|
|
entityName
|
|
? `Defina quais tipos de acesso ${entityName} poderá utilizar no sistema.`
|
|
: "Defina quem pode acessar este perfil.",
|
|
[entityName],
|
|
);
|
|
|
|
function handleToggle(
|
|
role: AuthorizationRole,
|
|
value: boolean | "indeterminate",
|
|
) {
|
|
console.log("[Dialog] toggle", role, value);
|
|
setRoles((previous) => ({ ...previous, [role]: value === true }));
|
|
}
|
|
|
|
const handleSave = () => {
|
|
console.log("[Dialog] handleSave called with roles:", roles);
|
|
console.log(
|
|
"[Dialog] About to call onConfirm. Typeof onConfirm is:",
|
|
typeof onConfirm,
|
|
);
|
|
if (typeof onConfirm === "function") {
|
|
onConfirm(roles);
|
|
// Não fecha aqui - deixa o componente pai fechar após processar
|
|
} else {
|
|
console.error("[Dialog] onConfirm is NOT a function! It is:", onConfirm);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent className="sm:max-w-lg">
|
|
<DialogHeader>
|
|
<DialogTitle className="flex items-center gap-2">
|
|
<ShieldCheck className="h-5 w-5" />
|
|
{title}
|
|
</DialogTitle>
|
|
<DialogDescription>{description}</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div className="space-y-6">
|
|
<div className="space-y-4">
|
|
<div className="flex items-start gap-3 rounded-lg border p-4">
|
|
<Checkbox
|
|
id="auth-paciente"
|
|
checked={roles.paciente}
|
|
disabled={loading}
|
|
onCheckedChange={(value) => handleToggle("paciente", value)}
|
|
/>
|
|
<div>
|
|
<Label htmlFor="auth-paciente">Acesso como paciente</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
Permite que este usuário acesse o portal do paciente.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-start gap-3 rounded-lg border p-4">
|
|
<Checkbox
|
|
id="auth-medico"
|
|
checked={roles.medico}
|
|
disabled={loading}
|
|
onCheckedChange={(value) => handleToggle("medico", value)}
|
|
/>
|
|
<div>
|
|
<Label htmlFor="auth-medico">Acesso como médico</Label>
|
|
<p className="text-sm text-muted-foreground">
|
|
Permite que este usuário acesse o portal profissional.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<Alert>
|
|
<AlertDescription>
|
|
Você pode habilitar as duas opções para permitir login como
|
|
paciente e médico usando as mesmas credenciais.
|
|
</AlertDescription>
|
|
</Alert>
|
|
|
|
{error && (
|
|
<Alert variant="destructive">
|
|
<AlertDescription>{error}</AlertDescription>
|
|
</Alert>
|
|
)}
|
|
</div>
|
|
|
|
<DialogFooter className="gap-4">
|
|
<Button
|
|
variant="outline"
|
|
onClick={() => onOpenChange(false)}
|
|
disabled={loading}
|
|
>
|
|
Cancelar
|
|
</Button>
|
|
{/* Debug: botão nativo para garantir onClick */}
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
console.log("[Debug Save] native button clicked", {
|
|
loading,
|
|
disableSubmit,
|
|
roles,
|
|
});
|
|
handleSave();
|
|
}}
|
|
disabled={loading}
|
|
className="inline-flex items-center justify-center rounded-md bg-primary text-primary-foreground px-4 py-2 disabled:opacity-50"
|
|
>
|
|
{loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}Salvar
|
|
alterações
|
|
</button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|