Fix usuarios page #6

Merged
killer-cf merged 28 commits from fix-usuarios-page into master 2025-11-04 17:42:21 +00:00
65 changed files with 9391 additions and 7115 deletions
Showing only changes of commit 372b2b5bf9 - Show all commits

View File

@@ -2,6 +2,7 @@
import { useQuery, useConvexClient } from "convex-svelte"; import { useQuery, useConvexClient } from "convex-svelte";
import { api } from "@sgse-app/backend/convex/_generated/api"; import { api } from "@sgse-app/backend/convex/_generated/api";
import ProtectedRoute from "$lib/components/ProtectedRoute.svelte"; import ProtectedRoute from "$lib/components/ProtectedRoute.svelte";
import StatsCard from "$lib/components/ti/StatsCard.svelte";
import type { Id } from "@sgse-app/backend/convex/_generated/dataModel"; import type { Id } from "@sgse-app/backend/convex/_generated/dataModel";
import { format } from "date-fns"; import { format } from "date-fns";
import { ptBR } from "date-fns/locale"; import { ptBR } from "date-fns/locale";
@@ -22,6 +23,7 @@
let busca = $state(""); let busca = $state("");
let filtroSetor = $state(""); let filtroSetor = $state("");
let filtroNivel = $state<number | "">("");
let roleSelecionada = $state<Role | null>(null); let roleSelecionada = $state<Role | null>(null);
let modalDetalhesAberto = $state(false); let modalDetalhesAberto = $state(false);
@@ -33,6 +35,27 @@
return Array.from(setores).sort(); return Array.from(setores).sort();
}); });
// Estatísticas
const stats = $derived.by(() => {
if (carregando) return null;
const porNivel = {
0: roles.filter(r => r.nivel === 0).length,
1: roles.filter(r => r.nivel === 1).length,
2: roles.filter(r => r.nivel === 2).length,
3: roles.filter(r => r.nivel >= 3).length,
};
return {
total: roles.length,
nivelMaximo: porNivel[0],
nivelAlto: porNivel[1],
nivelMedio: porNivel[2],
nivelBaixo: porNivel[3],
comSetor: roles.filter(r => r.setor).length,
};
});
const rolesFiltradas = $derived.by(() => { const rolesFiltradas = $derived.by(() => {
let resultado = roles; let resultado = roles;
@@ -51,6 +74,15 @@
resultado = resultado.filter((r) => r.setor === filtroSetor); resultado = resultado.filter((r) => r.setor === filtroSetor);
} }
// Filtro por nível
if (filtroNivel !== "") {
if (filtroNivel === 3) {
resultado = resultado.filter((r) => r.nivel >= 3);
} else {
resultado = resultado.filter((r) => r.nivel === filtroNivel);
}
}
return resultado.sort((a, b) => { return resultado.sort((a, b) => {
// Ordenar por nível primeiro (menor nível = maior privilégio) // Ordenar por nível primeiro (menor nível = maior privilégio)
if (a.nivel !== b.nivel) return a.nivel - b.nivel; if (a.nivel !== b.nivel) return a.nivel - b.nivel;
@@ -74,6 +106,13 @@
return `Nível ${nivel}`; return `Nível ${nivel}`;
} }
function obterCorCardNivel(nivel: number): string {
if (nivel === 0) return "border-l-4 border-error";
if (nivel === 1) return "border-l-4 border-warning";
if (nivel === 2) return "border-l-4 border-info";
return "border-l-4 border-base-300";
}
function abrirDetalhes(role: Role) { function abrirDetalhes(role: Role) {
roleSelecionada = role; roleSelecionada = role;
modalDetalhesAberto = true; modalDetalhesAberto = true;
@@ -95,13 +134,16 @@
function limparFiltros() { function limparFiltros() {
busca = ""; busca = "";
filtroSetor = ""; filtroSetor = "";
filtroNivel = "";
} }
const temFiltrosAtivos = $derived(busca.trim() !== "" || filtroSetor !== "" || filtroNivel !== "");
</script> </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"> <div class="container mx-auto px-4 py-6 max-w-7xl">
<!-- Header --> <!-- Header -->
<div class="flex items-center justify-between mb-6"> <div class="flex items-center justify-between mb-8">
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
<div class="p-3 bg-primary/10 rounded-xl"> <div class="p-3 bg-primary/10 rounded-xl">
<svg <svg
@@ -126,16 +168,55 @@
</div> </div>
</div> </div>
<!-- Estatísticas -->
{#if stats}
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4 mb-8">
<StatsCard
title="Total de Perfis"
value={stats.total}
icon='<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" />'
color="primary"
/>
<StatsCard
title="Nível Máximo"
value={stats.nivelMaximo}
description="Acesso total"
icon='<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />'
color="error"
/>
<StatsCard
title="Nível Alto"
value={stats.nivelAlto}
description="Acesso elevado"
icon='<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />'
color="warning"
/>
<StatsCard
title="Nível Médio"
value={stats.nivelMedio}
description="Acesso padrão"
icon='<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />'
color="info"
/>
<StatsCard
title="Com Setor"
value={stats.comSetor}
description="{stats.total > 0 ? ((stats.comSetor / stats.total) * 100).toFixed(0) + '% do total' : '0%'}"
icon='<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />'
color="secondary"
/>
</div>
{/if}
<!-- Filtros --> <!-- Filtros -->
{#if !carregando && roles.length > 0} {#if !carregando && roles.length > 0}
<div class="card bg-base-100 shadow-xl mb-6"> <div class="card bg-base-100 shadow-xl mb-6 border border-base-300">
<div class="card-body"> <div class="card-body">
<div class="flex items-center justify-between mb-4"> <div class="flex flex-wrap items-center justify-between gap-4 mb-4">
<h2 class="card-title">Filtros de Busca</h2> <div class="flex items-center gap-2">
<button type="button" class="btn btn-sm btn-outline" onclick={limparFiltros}>
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4" class="h-5 w-5 text-primary"
fill="none" fill="none"
viewBox="0 0 24 24" viewBox="0 0 24 24"
stroke="currentColor" stroke="currentColor"
@@ -144,26 +225,61 @@
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"
stroke-width="2" stroke-width="2"
d="M6 18L18 6M6 6l12 12" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z"
/> />
</svg> </svg>
Limpar Filtros <h2 class="card-title text-lg">Filtros de Busca</h2>
</button> </div>
{#if temFiltrosAtivos}
<button type="button" class="btn btn-sm btn-outline btn-error" 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>
{/if}
</div> </div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4"> <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<!-- Busca --> <!-- Busca -->
<div class="form-control"> <div class="form-control">
<label class="label" for="busca"> <label class="label" for="busca">
<span class="label-text font-medium">Buscar</span> <span class="label-text font-medium">Buscar</span>
</label> </label>
<input <div class="relative">
id="busca" <input
type="text" id="busca"
bind:value={busca} type="text"
placeholder="Buscar por nome ou descrição..." bind:value={busca}
class="input input-bordered input-sm" placeholder="Buscar por nome ou descrição..."
/> class="input input-bordered w-full pl-10"
/>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5 absolute left-3 top-1/2 transform -translate-y-1/2 text-base-content/40"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
/>
</svg>
</div>
</div> </div>
<!-- Setor --> <!-- Setor -->
@@ -171,17 +287,36 @@
<label class="label" for="filtro-setor"> <label class="label" for="filtro-setor">
<span class="label-text font-medium">Setor</span> <span class="label-text font-medium">Setor</span>
</label> </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">
<option value="">Todos os setores</option> <option value="">Todos os setores</option>
{#each setoresDisponiveis as setor} {#each setoresDisponiveis as setor}
<option value={setor}>{setor}</option> <option value={setor}>{setor}</option>
{/each} {/each}
</select> </select>
</div> </div>
<!-- Nível -->
<div class="form-control">
<label class="label" for="filtro-nivel">
<span class="label-text font-medium">Nível de Acesso</span>
</label>
<select id="filtro-nivel" bind:value={filtroNivel} class="select select-bordered">
<option value="">Todos os níveis</option>
<option value={0}>Máximo (0)</option>
<option value={1}>Alto (1)</option>
<option value={2}>Médio (2)</option>
<option value={3}>Baixo (3+)</option>
</select>
</div>
</div> </div>
<div class="mt-4 text-sm text-base-content/60"> <div class="mt-4 flex items-center justify-between">
Mostrando {rolesFiltradas.length} de {roles.length} perfil(is) <div class="text-sm text-base-content/60">
<span class="font-medium text-base-content">{rolesFiltradas.length}</span> de <span class="font-medium text-base-content">{roles.length}</span> perfil(is)
{#if temFiltrosAtivos}
<span class="badge badge-primary badge-sm ml-2">Filtrado</span>
{/if}
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -211,37 +346,145 @@
<h3 class="text-xl font-semibold mt-4">Nenhum perfil encontrado</h3> <h3 class="text-xl font-semibold mt-4">Nenhum perfil encontrado</h3>
<p class="text-base-content/60 mt-2">Não há perfis cadastrados no sistema.</p> <p class="text-base-content/60 mt-2">Não há perfis cadastrados no sistema.</p>
</div> </div>
{:else if rolesFiltradas.length === 0}
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<div class="flex flex-col items-center justify-center py-16 text-center">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-16 w-16 text-base-content/30 mb-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<h3 class="text-xl font-semibold mt-4">Nenhum perfil encontrado</h3>
<p class="text-base-content/60 mt-2">Nenhum perfil corresponde aos filtros aplicados.</p>
{#if temFiltrosAtivos}
<button class="btn btn-primary btn-sm mt-4" onclick={limparFiltros}>
Limpar Filtros
</button>
{/if}
</div>
</div>
</div>
{:else} {:else}
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{#each rolesFiltradas as role} {#each rolesFiltradas as role}
<div class="card bg-base-100 shadow-xl hover:shadow-2xl transition-shadow cursor-pointer" onclick={() => abrirDetalhes(role)}> <div class="card bg-base-100 shadow-xl hover:shadow-2xl transition-all duration-300 cursor-pointer border border-base-300 {obterCorCardNivel(role.nivel)} hover:scale-[1.02]" onclick={() => abrirDetalhes(role)}>
<div class="card-body"> <div class="card-body">
<div class="flex items-start justify-between mb-4"> <div class="flex items-start justify-between mb-4">
<h2 class="card-title text-lg">{role.descricao}</h2> <div class="flex-1">
<div class="badge {obterCorNivel(role.nivel)}">{obterTextoNivel(role.nivel)}</div> <h2 class="card-title text-lg mb-1">{role.descricao}</h2>
<div class="badge {obterCorNivel(role.nivel)} badge-sm">{obterTextoNivel(role.nivel)}</div>
</div>
<div class="p-2 bg-base-200 rounded-lg">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6 text-primary"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
/>
</svg>
</div>
</div> </div>
<div class="space-y-2 text-sm"> <div class="space-y-3 text-sm">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2 p-2 bg-base-200 rounded-lg">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4 text-base-content/40"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"
/>
</svg>
<span class="font-medium text-base-content/60">Nome técnico:</span> <span class="font-medium text-base-content/60">Nome técnico:</span>
<code class="text-xs bg-base-200 px-2 py-1 rounded">{role.nome}</code> <code class="text-xs bg-base-100 px-2 py-1 rounded font-mono">{role.nome}</code>
</div> </div>
{#if role.setor} {#if role.setor}
<div class="flex items-center gap-2"> <div class="flex items-center gap-2 p-2 bg-base-200 rounded-lg">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4 text-base-content/40"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"
/>
</svg>
<span class="font-medium text-base-content/60">Setor:</span> <span class="font-medium text-base-content/60">Setor:</span>
<span>{role.setor}</span> <span class="font-medium">{role.setor}</span>
</div> </div>
{/if} {/if}
<div class="flex items-center gap-2"> <div class="flex items-center gap-2 p-2 bg-base-200 rounded-lg">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4 text-base-content/40"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"
/>
</svg>
<span class="font-medium text-base-content/60">Nível:</span> <span class="font-medium text-base-content/60">Nível:</span>
<span>{role.nivel}</span> <span class="font-bold text-lg">{role.nivel}</span>
</div> </div>
</div> </div>
<div class="card-actions justify-end mt-4"> <div class="card-actions justify-end mt-4 pt-4 border-t border-base-300">
<button class="btn btn-sm btn-primary" onclick={(e) => { e.stopPropagation(); abrirDetalhes(role); }}> <button class="btn btn-sm btn-primary btn-outline" onclick={(e) => { e.stopPropagation(); abrirDetalhes(role); }}>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4 mr-1"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
/>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
/>
</svg>
Ver Detalhes Ver Detalhes
</button> </button>
</div> </div>
@@ -255,58 +498,132 @@
<!-- Modal Detalhes --> <!-- Modal Detalhes -->
{#if modalDetalhesAberto && roleSelecionada} {#if modalDetalhesAberto && roleSelecionada}
<div class="modal modal-open"> <div class="modal modal-open">
<div class="modal-box max-w-2xl"> <div class="modal-box max-w-3xl">
<h3 class="font-bold text-lg mb-4">Detalhes do Perfil</h3> <div class="flex items-center justify-between mb-6">
<h3 class="font-bold text-2xl">Detalhes do Perfil</h3>
<button type="button" class="btn btn-sm btn-circle btn-ghost" onclick={fecharDetalhes}>
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" 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>
</button>
</div>
<div class="space-y-4"> <div class="space-y-6">
<div class="grid grid-cols-2 gap-4"> <!-- Header do Perfil -->
<div> <div class="card bg-gradient-to-r from-primary/10 to-secondary/10 border border-primary/20">
<label class="label"> <div class="card-body">
<span class="label-text font-medium">Nome Técnico</span> <div class="flex items-start justify-between">
</label> <div class="flex-1">
<code class="block bg-base-200 px-3 py-2 rounded text-sm">{roleSelecionada.nome}</code> <h2 class="text-2xl font-bold mb-2">{roleSelecionada.descricao}</h2>
</div> <div class="flex items-center gap-3">
<div class="badge {obterCorNivel(roleSelecionada.nivel)} badge-lg">{obterTextoNivel(roleSelecionada.nivel)}</div>
<div> <span class="text-sm text-base-content/60">Nível {roleSelecionada.nivel}</span>
<label class="label"> </div>
<span class="label-text font-medium">Descrição</span> </div>
</label> <div class="p-3 bg-base-100 rounded-lg shadow-sm">
<p class="text-base-content">{roleSelecionada.descricao}</p> <svg
</div> xmlns="http://www.w3.org/2000/svg"
</div> class="h-8 w-8 text-primary"
fill="none"
<div class="grid grid-cols-2 gap-4"> viewBox="0 0 24 24"
<div> stroke="currentColor"
<label class="label"> >
<span class="label-text font-medium">Nível de Acesso</span> <path
</label> stroke-linecap="round"
<div class="flex items-center gap-2"> stroke-linejoin="round"
<span class="text-lg font-bold">{roleSelecionada.nivel}</span> stroke-width="2"
<div class="badge {obterCorNivel(roleSelecionada.nivel)}">{obterTextoNivel(roleSelecionada.nivel)}</div> d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
/>
</svg>
</div>
</div>
</div>
</div>
<!-- Informações Principais -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="card bg-base-100 border border-base-300">
<div class="card-body">
<label class="label">
<span class="label-text font-semibold flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
</svg>
Nome Técnico
</span>
</label>
<code class="block bg-base-200 px-4 py-3 rounded-lg text-sm font-mono mt-2">{roleSelecionada.nome}</code>
</div> </div>
<p class="text-xs text-base-content/60 mt-1">
{roleSelecionada.nivel === 0 && "Acesso total irrestrito ao sistema"}
{roleSelecionada.nivel === 1 && "Acesso alto com algumas restrições"}
{roleSelecionada.nivel === 2 && "Acesso médio com permissões configuráveis"}
{roleSelecionada.nivel >= 3 && "Acesso limitado com permissões específicas"}
</p>
</div> </div>
<div> <div class="card bg-base-100 border border-base-300">
<label class="label"> <div class="card-body">
<span class="label-text font-medium">Setor</span> <label class="label">
</label> <span class="label-text font-semibold flex items-center gap-2">
<p class="text-base-content">{roleSelecionada.setor || "Não especificado"}</p> <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
</svg>
Setor
</span>
</label>
<p class="text-lg font-medium mt-2">
{#if roleSelecionada.setor}
{roleSelecionada.setor}
{:else}
<span class="text-base-content/40 italic">Não especificado</span>
{/if}
</p>
</div>
</div> </div>
</div> </div>
<div> <!-- Nível de Acesso -->
<label class="label"> <div class="card bg-base-100 border border-base-300">
<span class="label-text font-medium">Data de Criação</span> <div class="card-body">
</label> <label class="label">
<p class="text-base-content">{formatarData(roleSelecionada._creationTime)}</p> <span class="label-text font-semibold flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
</svg>
Nível de Acesso
</span>
</label>
<div class="mt-4">
<div class="flex items-center gap-4 mb-3">
<span class="text-4xl font-bold">{roleSelecionada.nivel}</span>
<div class="badge {obterCorNivel(roleSelecionada.nivel)} badge-lg">{obterTextoNivel(roleSelecionada.nivel)}</div>
</div>
<div class="alert alert-info">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="stroke-current shrink-0 w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<span class="text-sm">
{roleSelecionada.nivel === 0 && "Acesso total irrestrito ao sistema. Pode realizar todas as operações sem restrições."}
{roleSelecionada.nivel === 1 && "Acesso alto com algumas restrições. Pode realizar a maioria das operações administrativas."}
{roleSelecionada.nivel === 2 && "Acesso médio com permissões configuráveis. Pode realizar operações padrão do sistema."}
{roleSelecionada.nivel >= 3 && "Acesso limitado com permissões específicas. Operações restritas conforme configuração."}
</span>
</div>
</div>
</div>
</div> </div>
<!-- Data de Criação -->
<div class="card bg-base-100 border border-base-300">
<div class="card-body">
<label class="label">
<span class="label-text font-semibold flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
Data de Criação
</span>
</label>
<p class="text-lg font-medium mt-2">{formatarData(roleSelecionada._creationTime)}</p>
</div>
</div>
<!-- Informação sobre Permissões -->
<div class="alert alert-info"> <div class="alert alert-info">
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@@ -321,17 +638,24 @@
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
></path> ></path>
</svg> </svg>
<span> <div>
Para configurar permissões específicas deste perfil, acesse o <a href="/ti/painel-permissoes" class="link link-primary">Painel de Permissões</a>. <h4 class="font-semibold mb-1">Configuração de Permissões</h4>
</span> <p class="text-sm">
Para configurar permissões específicas deste perfil, acesse o <a href="/ti/painel-permissoes" class="link link-primary font-semibold">Painel de Permissões</a>.
</p>
</div>
</div> </div>
</div> </div>
<div class="modal-action"> <div class="modal-action mt-6">
<button type="button" class="btn btn-ghost" onclick={fecharDetalhes}> <button type="button" class="btn btn-ghost" onclick={fecharDetalhes}>
Fechar Fechar
</button> </button>
<a href="/ti/painel-permissoes" class="btn btn-primary"> <a href="/ti/painel-permissoes" class="btn btn-primary">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
Configurar Permissões Configurar Permissões
</a> </a>
</div> </div>