refactor: integrate current user data across components

- Replaced instances of `authStore` with `currentUser` to streamline user authentication handling.
- Updated permission checks and user-related data retrieval to utilize the new `useQuery` for better performance and clarity.
- Cleaned up component structures and improved formatting for consistency and readability.
- Enhanced error handling and user feedback mechanisms in various components to improve user experience.
This commit is contained in:
2025-11-08 10:52:33 -03:00
parent 01138b3e1c
commit 9a5f2b294d
28 changed files with 2312 additions and 1235 deletions

View File

@@ -4,7 +4,6 @@
import type { Id } from "@sgse-app/backend/convex/_generated/dataModel";
import ProtectedRoute from "$lib/components/ProtectedRoute.svelte";
import UserStatusBadge from "$lib/components/ti/UserStatusBadge.svelte";
import { authStore } from "$lib/stores/auth.svelte";
import { format } from "date-fns";
import { ptBR } from "date-fns/locale";
@@ -58,63 +57,70 @@
};
const client = useConvexClient();
const currentUser = useQuery(api.auth.getCurrentUser, {});
// Usar useQuery reativo - seguindo padrão usado em ti/times/+page.svelte
const usuariosQuery = useQuery(api.usuarios.listar, {});
// Extrair dados e determinar estado de carregamento
const usuarios = $derived.by(() => {
// Se usuariosQuery é undefined ou null, está carregando
if (usuariosQuery === undefined || usuariosQuery === null) {
return [];
}
// Se usuariosQuery é um objeto vazio {}, está carregando
if (typeof usuariosQuery === "object" && Object.keys(usuariosQuery).length === 0) {
if (
typeof usuariosQuery === "object" &&
Object.keys(usuariosQuery).length === 0
) {
return [];
}
// Se tem propriedade data, usar os dados
if ("data" in usuariosQuery && usuariosQuery.data !== undefined) {
return Array.isArray(usuariosQuery.data) ? usuariosQuery.data : [];
}
// Se usuariosQuery é diretamente um array (caso não tenha .data)
if (Array.isArray(usuariosQuery)) {
return usuariosQuery;
}
// Caso padrão: ainda carregando ou sem dados
return [];
});
const carregandoUsuarios = $derived.by(() => {
// Se é undefined/null, está carregando
if (usuariosQuery === undefined || usuariosQuery === null) {
return true;
}
// Se é um objeto vazio {}, está carregando
if (typeof usuariosQuery === "object" && Object.keys(usuariosQuery).length === 0) {
if (
typeof usuariosQuery === "object" &&
Object.keys(usuariosQuery).length === 0
) {
return true;
}
// Se não tem propriedade data, está carregando
if (!("data" in usuariosQuery)) {
return true;
}
// Se data é undefined, está carregando
if (usuariosQuery.data === undefined) {
return true;
}
// Caso contrário, dados estão prontos
return false;
});
let erroUsuarios = $state<string | null>(null);
// Monitorar erros e estado da query
$effect(() => {
try {
@@ -124,7 +130,8 @@
if ("error" in usuariosQuery) {
const error = (usuariosQuery as { error?: unknown }).error;
if (error !== undefined && error !== null) {
erroUsuarios = error instanceof Error ? error.message : String(error);
erroUsuarios =
error instanceof Error ? error.message : String(error);
console.error("❌ [ERROR] Erro na query de usuários:", error);
} else {
// Se error existe mas é undefined/null, limpar erro
@@ -138,16 +145,31 @@
}
}
}
// Debug para identificar problemas (apenas em desenvolvimento)
if (typeof window !== "undefined" && window.location.hostname === "localhost") {
if (
typeof window !== "undefined" &&
window.location.hostname === "localhost"
) {
console.log("🔍 [DEBUG] usuariosQuery:", usuariosQuery);
console.log("🔍 [DEBUG] typeof usuariosQuery:", typeof usuariosQuery);
if (usuariosQuery && typeof usuariosQuery === "object") {
console.log("🔍 [DEBUG] Object.keys(usuariosQuery):", Object.keys(usuariosQuery));
console.log("🔍 [DEBUG] usuariosQuery?.data:", (usuariosQuery as { data?: unknown }).data);
console.log("🔍 [DEBUG] 'data' in usuariosQuery:", "data" in usuariosQuery);
console.log("🔍 [DEBUG] 'error' in usuariosQuery:", "error" in usuariosQuery);
console.log(
"🔍 [DEBUG] Object.keys(usuariosQuery):",
Object.keys(usuariosQuery),
);
console.log(
"🔍 [DEBUG] usuariosQuery?.data:",
(usuariosQuery as { data?: unknown }).data,
);
console.log(
"🔍 [DEBUG] 'data' in usuariosQuery:",
"data" in usuariosQuery,
);
console.log(
"🔍 [DEBUG] 'error' in usuariosQuery:",
"error" in usuariosQuery,
);
}
console.log("🔍 [DEBUG] usuarios (extraídos):", usuarios);
console.log("🔍 [DEBUG] quantidade:", usuarios.length);
@@ -179,7 +201,9 @@
let filtroNome = $state("");
let filtroMatricula = $state("");
let filtroSetor = $state("");
let filtroStatus = $state<"todos" | "ativo" | "inativo" | "bloqueado">("todos");
let filtroStatus = $state<"todos" | "ativo" | "inativo" | "bloqueado">(
"todos",
);
let filtroDataCriacaoInicio = $state("");
let filtroDataCriacaoFim = $state("");
let filtroUltimoAcessoInicio = $state("");
@@ -201,9 +225,11 @@
// Suportar ambos formatos (array direto ou objeto com .data), dependendo do hook/cliente
const lista = Array.isArray(resposta)
? resposta
: (resposta && typeof resposta === "object" && Array.isArray((resposta as { data?: unknown }).data)
? ((resposta as { data: unknown[] }).data)
: []);
: resposta &&
typeof resposta === "object" &&
Array.isArray((resposta as { data?: unknown }).data)
? (resposta as { data: unknown[] }).data
: [];
funcionarios = lista as Funcionario[];
} catch (error: unknown) {
@@ -240,7 +266,9 @@
// Verificar se há usuários com problemas
const usuariosComProblemas = $derived.by(() => {
return usuarios.filter((u) => u.role?.erro === true || (u.avisos && u.avisos.length > 0));
return usuarios.filter(
(u) => u.role?.erro === true || (u.avisos && u.avisos.length > 0),
);
});
// Lógica de filtros reativos
@@ -250,13 +278,17 @@
// Filtro por nome
if (filtroNome.trim()) {
const buscaNome = filtroNome.toLowerCase();
resultado = resultado.filter((u) => u.nome.toLowerCase().includes(buscaNome));
resultado = resultado.filter((u) =>
u.nome.toLowerCase().includes(buscaNome),
);
}
// Filtro por matrícula
if (filtroMatricula.trim()) {
const buscaMatricula = filtroMatricula.toLowerCase();
resultado = resultado.filter((u) => u.matricula.toLowerCase().includes(buscaMatricula));
resultado = resultado.filter((u) =>
u.matricula.toLowerCase().includes(buscaMatricula),
);
}
// Filtro por setor
@@ -340,7 +372,7 @@
async function ativarDesativarUsuario(usuario: Usuario) {
const confirmar = window.confirm(
`Deseja realmente ${usuario.ativo ? "desativar" : "ativar"} o usuário ${usuario.nome}?`
`Deseja realmente ${usuario.ativo ? "desativar" : "ativar"} o usuário ${usuario.nome}?`,
);
if (!confirmar) return;
@@ -351,11 +383,16 @@
ativo: !usuario.ativo,
});
mostrarMensagem("success", `Usuário ${usuario.ativo ? "desativado" : "ativado"} com sucesso!`);
mostrarMensagem(
"success",
`Usuário ${usuario.ativo ? "desativado" : "ativado"} com sucesso!`,
);
await carregarUsuarios();
} catch (error: unknown) {
const message =
error instanceof Error ? error.message : "Erro ao alterar status do usuário.";
error instanceof Error
? error.message
: "Erro ao alterar status do usuário.";
mostrarMensagem("error", message);
} finally {
processando = false;
@@ -381,7 +418,11 @@
}
async function associarFuncionario() {
if (!usuarioSelecionado || !funcionarioSelecionadoId || funcionarioSelecionadoId === "") {
if (
!usuarioSelecionado ||
!funcionarioSelecionadoId ||
funcionarioSelecionadoId === ""
) {
return;
}
@@ -412,7 +453,7 @@
}
const confirmar = window.confirm(
"Deseja realmente desassociar o funcionário deste usuário?"
"Deseja realmente desassociar o funcionário deste usuário?",
);
if (!confirmar) return;
@@ -439,14 +480,14 @@
async function bloquearUsuario(usuario: Usuario) {
const motivo = window.prompt(
"Digite o motivo do bloqueio:",
usuario.motivoBloqueio || ""
usuario.motivoBloqueio || "",
);
if (!motivo || motivo.trim() === "") {
return;
}
if (!authStore.usuario) {
if (!currentUser?.data) {
mostrarMensagem("error", "Usuário não autenticado");
return;
}
@@ -456,7 +497,7 @@
const resultado = await client.mutation(api.usuarios.bloquearUsuario, {
usuarioId: usuario._id,
motivo: motivo.trim(),
bloqueadoPorId: authStore.usuario._id as Id<"usuarios">,
bloqueadoPorId: currentUser.data._id as Id<"usuarios">,
});
if (resultado.sucesso) {
@@ -475,13 +516,13 @@
}
async function desbloquearUsuario(usuario: Usuario) {
if (!authStore.usuario) {
if (!currentUser?.data) {
mostrarMensagem("error", "Usuário não autenticado");
return;
}
const confirmar = window.confirm(
`Deseja realmente desbloquear o usuário ${usuario.nome}?`
`Deseja realmente desbloquear o usuário ${usuario.nome}?`,
);
if (!confirmar) return;
@@ -489,7 +530,7 @@
try {
const resultado = await client.mutation(api.usuarios.desbloquearUsuario, {
usuarioId: usuario._id,
desbloqueadoPorId: authStore.usuario._id as Id<"usuarios">,
desbloqueadoPorId: currentUser.data._id as Id<"usuarios">,
});
if (resultado.sucesso) {
@@ -541,25 +582,54 @@
}
</script>
<ProtectedRoute allowedRoles={["ti_master", "admin", "ti_usuario"]} maxLevel={3}>
<ProtectedRoute
allowedRoles={["ti_master", "admin", "ti_usuario"]}
maxLevel={3}
>
<div class="container mx-auto px-4 py-6 max-w-7xl">
<!-- Header -->
<div class="flex items-center justify-between mb-6">
<div class="flex items-center gap-4">
<div class="p-3 bg-primary/10 rounded-xl">
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-8 w-8 text-primary"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"
/>
</svg>
</div>
<div>
<h1 class="text-3xl font-bold text-base-content">Gestão de Usuários</h1>
<p class="text-base-content/60 mt-1">Administre os usuários do sistema</p>
<h1 class="text-3xl font-bold text-base-content">
Gestão de Usuários
</h1>
<p class="text-base-content/60 mt-1">
Administre os usuários do sistema
</p>
</div>
</div>
<div class="flex gap-3">
<a href="/ti/usuarios/criar" class="btn btn-primary">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 4v16m8-8H4"
/>
</svg>
Criar Usuário
</a>
@@ -586,7 +656,8 @@
<h3 class="font-bold">Atenção: Usuários com Problemas Detectados</h3>
<div class="text-sm mt-2">
<p>
{usuariosComProblemas.length} usuário(s) possui(em) problemas que requerem atenção:
{usuariosComProblemas.length} usuário(s) possui(em) problemas que requerem
atenção:
</p>
<ul class="list-disc list-inside mt-2 space-y-1">
{#each usuariosComProblemas.slice(0, 3) as usuario}
@@ -598,11 +669,14 @@
</li>
{/each}
{#if usuariosComProblemas.length > 3}
<li class="text-base-content/60">... e mais {usuariosComProblemas.length - 3} usuário(s)</li>
<li class="text-base-content/60">
... e mais {usuariosComProblemas.length - 3} usuário(s)
</li>
{/if}
</ul>
<p class="mt-2 font-semibold">
Por favor, corrija os perfis desses usuários para garantir acesso adequado ao sistema.
Por favor, corrija os perfis desses usuários para garantir acesso
adequado ao sistema.
</p>
</div>
</div>
@@ -670,9 +744,24 @@
<div class="card-body">
<div class="flex items-center justify-between mb-4">
<h2 class="card-title">Filtros de Busca</h2>
<button type="button" class="btn btn-sm btn-outline" onclick={limparFiltros}>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
<button
type="button"
class="btn btn-sm btn-outline"
onclick={limparFiltros}
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
Limpar Filtros
</button>
@@ -712,7 +801,11 @@
<label class="label" for="filtro-setor">
<span class="label-text font-medium">Setor</span>
</label>
<select id="filtro-setor" bind:value={filtroSetor} class="select select-bordered select-sm">
<select
id="filtro-setor"
bind:value={filtroSetor}
class="select select-bordered select-sm"
>
<option value="">Todos os setores</option>
{#each obterSetoresDisponiveis() as setor}
<option value={setor}>{setor}</option>
@@ -725,7 +818,11 @@
<label class="label" for="filtro-status">
<span class="label-text font-medium">Status</span>
</label>
<select id="filtro-status" bind:value={filtroStatus} class="select select-bordered select-sm">
<select
id="filtro-status"
bind:value={filtroStatus}
class="select select-bordered select-sm"
>
<option value="todos">Todos</option>
<option value="ativo">Ativo</option>
<option value="inativo">Inativo</option>
@@ -736,7 +833,9 @@
<!-- Data de Criação Início -->
<div class="form-control">
<label class="label" for="filtro-data-criacao-inicio">
<span class="label-text font-medium">Data de Criação (Início)</span>
<span class="label-text font-medium"
>Data de Criação (Início)</span
>
</label>
<input
id="filtro-data-criacao-inicio"
@@ -749,7 +848,8 @@
<!-- Data de Criação Fim -->
<div class="form-control">
<label class="label" for="filtro-data-criacao-fim">
<span class="label-text font-medium">Data de Criação (Fim)</span>
<span class="label-text font-medium">Data de Criação (Fim)</span
>
</label>
<input
id="filtro-data-criacao-fim"
@@ -762,7 +862,9 @@
<!-- Último Acesso Início -->
<div class="form-control">
<label class="label" for="filtro-ultimo-acesso-inicio">
<span class="label-text font-medium">Último Acesso (Início)</span>
<span class="label-text font-medium"
>Último Acesso (Início)</span
>
</label>
<input
id="filtro-ultimo-acesso-inicio"
@@ -818,7 +920,8 @@
<h3 class="font-bold">Erro ao carregar usuários</h3>
<div class="text-sm mt-1">{erroUsuarios}</div>
<div class="text-xs mt-2">
Por favor, recarregue a página ou entre em contato com o suporte técnico se o problema persistir.
Por favor, recarregue a página ou entre em contato com o suporte
técnico se o problema persistir.
</div>
</div>
</div>
@@ -892,13 +995,19 @@
{usuario.role.descricao}
</div>
{#if usuario.avisos && usuario.avisos.length > 0}
<div class="tooltip tooltip-error" data-tip={usuario.avisos[0].mensagem}>
<div
class="tooltip tooltip-error"
data-tip={usuario.avisos[0].mensagem}
>
<button
type="button"
class="btn btn-xs btn-error btn-circle"
onclick={(e) => {
e.stopPropagation();
mostrarMensagem("error", usuario.avisos![0].mensagem);
mostrarMensagem(
"error",
usuario.avisos![0].mensagem,
);
}}
>
!
@@ -906,7 +1015,9 @@
</div>
{/if}
{:else}
<div class="badge badge-outline">{usuario.role.nome}</div>
<div class="badge badge-outline">
{usuario.role.nome}
</div>
{/if}
</div>
</td>
@@ -931,7 +1042,9 @@
</svg>
Associado
</div>
<div class="text-sm font-medium">{usuario.funcionario.nome}</div>
<div class="text-sm font-medium">
{usuario.funcionario.nome}
</div>
{#if usuario.funcionario.matricula}
<div class="text-xs text-base-content/60">
Mat: {usuario.funcionario.matricula}
@@ -959,7 +1072,10 @@
{/if}
</td>
<td>
<UserStatusBadge ativo={usuario.ativo} bloqueado={usuario.bloqueado} />
<UserStatusBadge
ativo={usuario.ativo}
bloqueado={usuario.bloqueado}
/>
</td>
<td>
{#if usuario.primeiroAcesso}
@@ -969,10 +1085,14 @@
{/if}
</td>
<td>
<span class="text-sm">{formatarData(usuario.ultimoAcesso)}</span>
<span class="text-sm"
>{formatarData(usuario.ultimoAcesso)}</span
>
</td>
<td>
<span class="text-sm">{formatarData(usuario.criadoEm)}</span>
<span class="text-sm"
>{formatarData(usuario.criadoEm)}</span
>
</td>
<td>
<div class="dropdown dropdown-end">
@@ -981,35 +1101,74 @@
class="btn btn-sm btn-ghost"
aria-label="Menu de ações"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 5v.01M12 12v.01M12 19v.01M12 6a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2z" />
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 5v.01M12 12v.01M12 19v.01M12 6a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2zm0 7a1 1 0 110-2 1 1 0 010 2z"
/>
</svg>
</button>
<ul role="menu" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-48 z-[1]">
<ul
role="menu"
class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-48 z-[1]"
>
<li>
<button type="button" onclick={() => ativarDesativarUsuario(usuario)} disabled={processando}>
<button
type="button"
onclick={() => ativarDesativarUsuario(usuario)}
disabled={processando}
>
{usuario.ativo ? "Desativar" : "Ativar"}
</button>
</li>
<li>
<button type="button" onclick={() => abrirModalAssociar(usuario)} disabled={processando}>
{usuario.funcionario ? "Alterar Funcionário" : "Associar Funcionário"}
<button
type="button"
onclick={() => abrirModalAssociar(usuario)}
disabled={processando}
>
{usuario.funcionario
? "Alterar Funcionário"
: "Associar Funcionário"}
</button>
</li>
<li>
{#if usuario.bloqueado}
<button type="button" onclick={() => desbloquearUsuario(usuario)} disabled={processando} class="text-success">
<button
type="button"
onclick={() => desbloquearUsuario(usuario)}
disabled={processando}
class="text-success"
>
Desbloquear
</button>
{:else}
<button type="button" onclick={() => bloquearUsuario(usuario)} disabled={processando} class="text-error">
<button
type="button"
onclick={() => bloquearUsuario(usuario)}
disabled={processando}
class="text-error"
>
Bloquear
</button>
{/if}
</li>
<div class="divider my-0"></div>
<li>
<button type="button" onclick={() => abrirModalExcluir(usuario)} disabled={processando} class="text-error">
<button
type="button"
onclick={() => abrirModalExcluir(usuario)}
disabled={processando}
class="text-error"
>
Excluir
</button>
</li>
@@ -1034,7 +1193,8 @@
<div class="mb-6">
<p class="text-base-content/80 mb-2">
<strong>Usuário:</strong> {usuarioSelecionado.nome} ({usuarioSelecionado.matricula})
<strong>Usuário:</strong>
{usuarioSelecionado.nome} ({usuarioSelecionado.matricula})
</p>
{#if usuarioSelecionado.funcionario}
@@ -1053,7 +1213,8 @@
></path>
</svg>
<span>
Este usuário já possui um funcionário associado. Você pode alterá-lo ou desassociá-lo.
Este usuário já possui um funcionário associado. Você pode
alterá-lo ou desassociá-lo.
</span>
</div>
{/if}
@@ -1079,7 +1240,9 @@
<div class="border rounded-lg max-h-96 overflow-y-auto">
{#if carregandoFuncionarios}
<div class="p-4 flex items-center justify-center gap-3 text-base-content/60">
<div
class="p-4 flex items-center justify-center gap-3 text-base-content/60"
>
<span class="loading loading-spinner loading-sm"></span>
Carregando funcionários disponíveis...
</div>
@@ -1110,7 +1273,9 @@
{/if}
</div>
{#if func.descricaoCargo}
<div class="text-xs text-base-content/60">{func.descricaoCargo}</div>
<div class="text-xs text-base-content/60">
{func.descricaoCargo}
</div>
{/if}
</div>
</label>
@@ -1147,7 +1312,9 @@
type="button"
class="btn btn-primary"
onclick={associarFuncionario}
disabled={processando || !funcionarioSelecionadoId || funcionarioSelecionadoId === ""}
disabled={processando ||
!funcionarioSelecionadoId ||
funcionarioSelecionadoId === ""}
>
{#if processando}
<span class="loading loading-spinner loading-sm"></span>
@@ -1157,7 +1324,13 @@
</div>
</div>
<div class="modal-backdrop">
<button type="button" onclick={fecharModalAssociar} onkeydown={(e) => e.key === "Escape" && fecharModalAssociar()} aria-label="Fechar modal" class="sr-only">Fechar</button>
<button
type="button"
onclick={fecharModalAssociar}
onkeydown={(e) => e.key === "Escape" && fecharModalAssociar()}
aria-label="Fechar modal"
class="sr-only">Fechar</button
>
</div>
</div>
{/if}
@@ -1170,7 +1343,8 @@
<div class="mb-4">
<p class="text-base-content/80 mb-2">
<strong>Usuário:</strong> {usuarioSelecionado.nome} ({usuarioSelecionado.matricula})
<strong>Usuário:</strong>
{usuarioSelecionado.nome} ({usuarioSelecionado.matricula})
</p>
<div class="alert alert-error">
<svg
@@ -1187,7 +1361,8 @@
></path>
</svg>
<span>
Esta ação não pode ser desfeita. O usuário será permanentemente excluído do sistema.
Esta ação não pode ser desfeita. O usuário será permanentemente
excluído do sistema.
</span>
</div>
</div>
@@ -1215,7 +1390,13 @@
</div>
</div>
<div class="modal-backdrop">
<button type="button" onclick={fecharModalExcluir} onkeydown={(e) => e.key === "Escape" && fecharModalExcluir()} aria-label="Fechar modal" class="sr-only">Fechar</button>
<button
type="button"
onclick={fecharModalExcluir}
onkeydown={(e) => e.key === "Escape" && fecharModalExcluir()}
aria-label="Fechar modal"
class="sr-only">Fechar</button
>
</div>
</div>
{/if}