diff --git a/apps/web/src/routes/(dashboard)/ti/perfis/+page.svelte b/apps/web/src/routes/(dashboard)/ti/perfis/+page.svelte index 91cf110..e61b8e5 100644 --- a/apps/web/src/routes/(dashboard)/ti/perfis/+page.svelte +++ b/apps/web/src/routes/(dashboard)/ti/perfis/+page.svelte @@ -2,6 +2,7 @@ import { useQuery, useConvexClient } from "convex-svelte"; import { api } from "@sgse-app/backend/convex/_generated/api"; 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 { format } from "date-fns"; import { ptBR } from "date-fns/locale"; @@ -22,6 +23,7 @@ let busca = $state(""); let filtroSetor = $state(""); + let filtroNivel = $state(""); let roleSelecionada = $state(null); let modalDetalhesAberto = $state(false); @@ -33,6 +35,27 @@ 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(() => { let resultado = roles; @@ -51,6 +74,15 @@ 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) => { // Ordenar por nível primeiro (menor nível = maior privilégio) if (a.nivel !== b.nivel) return a.nivel - b.nivel; @@ -74,6 +106,13 @@ 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) { roleSelecionada = role; modalDetalhesAberto = true; @@ -95,13 +134,16 @@ function limparFiltros() { busca = ""; filtroSetor = ""; + filtroNivel = ""; } + + const temFiltrosAtivos = $derived(busca.trim() !== "" || filtroSetor !== "" || filtroNivel !== "");
-
+
+ + {#if stats} +
+ + + + + +
+ {/if} + {#if !carregando && roles.length > 0} -
+
-
-

Filtros de Busca

- +

Filtros de Busca

+
+ {#if temFiltrosAtivos} + + {/if}
-
+
- +
+ + + + +
@@ -171,17 +287,36 @@ - {#each setoresDisponiveis as setor} {/each}
+ + +
+ + +
-
- Mostrando {rolesFiltradas.length} de {roles.length} perfil(is) +
+
+ {rolesFiltradas.length} de {roles.length} perfil(is) + {#if temFiltrosAtivos} + Filtrado + {/if} +
@@ -211,37 +346,145 @@

Nenhum perfil encontrado

Não há perfis cadastrados no sistema.

+ {:else if rolesFiltradas.length === 0} +
+
+
+ + + +

Nenhum perfil encontrado

+

Nenhum perfil corresponde aos filtros aplicados.

+ {#if temFiltrosAtivos} + + {/if} +
+
+
{:else}
{#each rolesFiltradas as role} -
abrirDetalhes(role)}> +
abrirDetalhes(role)}>
-

{role.descricao}

-
{obterTextoNivel(role.nivel)}
+
+

{role.descricao}

+
{obterTextoNivel(role.nivel)}
+
+
+ + + +
-
-
+
+
+ + + Nome técnico: - {role.nome} + {role.nome}
{#if role.setor} -
+
+ + + Setor: - {role.setor} + {role.setor}
{/if} -
+
+ + + Nível: - {role.nivel} + {role.nivel}
-
-
@@ -255,58 +498,132 @@ {#if modalDetalhesAberto && roleSelecionada}