refactor: integrate ProtectedRoute component across dashboard pages

- Added the ProtectedRoute component to various dashboard pages to enforce authentication and role-based access control.
- Updated allowedRoles and maxLevel parameters for specific routes to align with the new permission management structure.
- Enhanced user experience by ensuring consistent access checks across the application.
This commit is contained in:
2025-11-14 16:15:21 -03:00
parent 3c371bc35c
commit b503045b41
15 changed files with 95 additions and 71 deletions

View File

@@ -1,16 +1,15 @@
<script lang="ts"> <script lang="ts">
import { useQuery } from "convex-svelte"; import { useQuery } from 'convex-svelte';
import { api } from "@sgse-app/backend/convex/_generated/api"; import { api } from '@sgse-app/backend/convex/_generated/api';
import { onMount } from "svelte"; import { onMount } from 'svelte';
import { page } from "$app/stores"; import type { Snippet } from 'svelte';
import type { Snippet } from "svelte";
let { let {
children, children,
requireAuth = true, requireAuth = true,
allowedRoles = [], allowedRoles = [],
maxLevel = 3, maxLevel = 3,
redirectTo = "/", redirectTo = '/'
}: { }: {
children: Snippet; children: Snippet;
requireAuth?: boolean; requireAuth?: boolean;
@@ -41,9 +40,7 @@
// Verificar roles // Verificar roles
if (allowedRoles.length > 0 && currentUser?.data) { if (allowedRoles.length > 0 && currentUser?.data) {
const hasRole = allowedRoles.includes( const hasRole = allowedRoles.includes(currentUser.data.role?.nome ?? '');
currentUser.data.role?.nome ?? "",
);
if (!hasRole) { if (!hasRole) {
const currentPath = window.location.pathname; const currentPath = window.location.pathname;
window.location.href = `${redirectTo}?error=access_denied&route=${encodeURIComponent(currentPath)}`; window.location.href = `${redirectTo}?error=access_denied&route=${encodeURIComponent(currentPath)}`;
@@ -69,10 +66,10 @@
</script> </script>
{#if isChecking} {#if isChecking}
<div class="flex justify-center items-center min-h-screen"> <div class="flex min-h-screen items-center justify-center">
<div class="text-center"> <div class="text-center">
<span class="loading loading-spinner loading-lg text-primary"></span> <span class="loading loading-spinner loading-lg text-primary"></span>
<p class="mt-4 text-base-content/70">Verificando permissões...</p> <p class="text-base-content/70 mt-4">Verificando permissões...</p>
</div> </div>
</div> </div>
{:else if hasAccess} {:else if hasAccess}

View File

@@ -7,6 +7,7 @@
import { resolve } from "$app/paths"; import { resolve } from "$app/paths";
import { UserPlus, Mail } from "lucide-svelte"; import { UserPlus, Mail } from "lucide-svelte";
import { useAuth } from "@mmailaender/convex-better-auth-svelte/svelte"; import { useAuth } from "@mmailaender/convex-better-auth-svelte/svelte";
import ProtectedRoute from "$lib/components/ProtectedRoute.svelte";
let { data } = $props(); let { data } = $props();
@@ -128,6 +129,7 @@
} }
</script> </script>
<ProtectedRoute>
<main class="container mx-auto px-4 py-4"> <main class="container mx-auto px-4 py-4">
<!-- Alerta de Acesso Negado / Autenticação --> <!-- Alerta de Acesso Negado / Autenticação -->
{#if showAlert} {#if showAlert}
@@ -823,6 +825,7 @@
</div> </div>
{/if} {/if}
</main> </main>
</ProtectedRoute>
<style> <style>
@keyframes fadeIn { @keyframes fadeIn {

View File

@@ -1,8 +1,10 @@
<script lang="ts"> <script lang="ts">
import { ShoppingCart, ShoppingBag, Plus } from "lucide-svelte"; import { ShoppingCart, ShoppingBag, Plus } from "lucide-svelte";
import { resolve } from "$app/paths"; import { resolve } from "$app/paths";
import ProtectedRoute from "$lib/components/ProtectedRoute.svelte";
</script> </script>
<ProtectedRoute>
<main class="container mx-auto px-4 py-4"> <main class="container mx-auto px-4 py-4">
<div class="text-sm breadcrumbs mb-4"> <div class="text-sm breadcrumbs mb-4">
<ul> <ul>
@@ -41,4 +43,5 @@
</div> </div>
</div> </div>
</main> </main>
</ProtectedRoute>

View File

@@ -1,8 +1,10 @@
<script lang="ts"> <script lang="ts">
import { Megaphone, Edit, Plus } from "lucide-svelte"; import { Megaphone, Edit, Plus } from "lucide-svelte";
import { resolve } from "$app/paths"; import { resolve } from "$app/paths";
import ProtectedRoute from "$lib/components/ProtectedRoute.svelte";
</script> </script>
<ProtectedRoute>
<main class="container mx-auto px-4 py-4"> <main class="container mx-auto px-4 py-4">
<div class="text-sm breadcrumbs mb-4"> <div class="text-sm breadcrumbs mb-4">
<ul> <ul>
@@ -41,4 +43,5 @@
</div> </div>
</div> </div>
</main> </main>
</ProtectedRoute>

View File

@@ -1,8 +1,10 @@
<script lang="ts"> <script lang="ts">
import { BarChart3, ClipboardCheck, Plus, CheckCircle2, Clock, TrendingUp } from "lucide-svelte"; import { BarChart3, ClipboardCheck, Plus, CheckCircle2, Clock, TrendingUp } from "lucide-svelte";
import { resolve } from "$app/paths"; import { resolve } from "$app/paths";
import ProtectedRoute from "$lib/components/ProtectedRoute.svelte";
</script> </script>
<ProtectedRoute>
<main class="container mx-auto px-4 py-4"> <main class="container mx-auto px-4 py-4">
<!-- Breadcrumb --> <!-- Breadcrumb -->
<div class="text-sm breadcrumbs mb-4"> <div class="text-sm breadcrumbs mb-4">
@@ -86,4 +88,5 @@
</div> </div>
</div> </div>
</main> </main>
</ProtectedRoute>

View File

@@ -1,8 +1,10 @@
<script lang="ts"> <script lang="ts">
import { DollarSign, Building2, Plus, Calculator, TrendingUp, FileText } from "lucide-svelte"; import { DollarSign, Building2, Plus, Calculator, TrendingUp, FileText } from "lucide-svelte";
import { resolve } from "$app/paths"; import { resolve } from "$app/paths";
import ProtectedRoute from "$lib/components/ProtectedRoute.svelte";
</script> </script>
<ProtectedRoute>
<main class="container mx-auto px-4 py-4"> <main class="container mx-auto px-4 py-4">
<!-- Breadcrumb --> <!-- Breadcrumb -->
<div class="text-sm breadcrumbs mb-4"> <div class="text-sm breadcrumbs mb-4">
@@ -86,4 +88,5 @@
</div> </div>
</div> </div>
</main> </main>
</ProtectedRoute>

View File

@@ -1,8 +1,10 @@
<script lang="ts"> <script lang="ts">
import { Scale, BookOpen, Plus } from "lucide-svelte"; import { Scale, BookOpen, Plus } from "lucide-svelte";
import { resolve } from "$app/paths"; import { resolve } from "$app/paths";
import ProtectedRoute from "$lib/components/ProtectedRoute.svelte";
</script> </script>
<ProtectedRoute>
<main class="container mx-auto px-4 py-4"> <main class="container mx-auto px-4 py-4">
<div class="text-sm breadcrumbs mb-4"> <div class="text-sm breadcrumbs mb-4">
<ul> <ul>
@@ -41,4 +43,5 @@
</div> </div>
</div> </div>
</main> </main>
</ProtectedRoute>

View File

@@ -1,8 +1,10 @@
<script lang="ts"> <script lang="ts">
import { FileText, ClipboardCopy, Plus, Users, FileDoc } from "lucide-svelte"; import { FileText, ClipboardCopy, Plus, Users, FileDoc } from "lucide-svelte";
import { resolve } from "$app/paths"; import { resolve } from "$app/paths";
import ProtectedRoute from "$lib/components/ProtectedRoute.svelte";
</script> </script>
<ProtectedRoute>
<main class="container mx-auto px-4 py-4"> <main class="container mx-auto px-4 py-4">
<!-- Breadcrumb --> <!-- Breadcrumb -->
<div class="text-sm breadcrumbs mb-4"> <div class="text-sm breadcrumbs mb-4">
@@ -86,4 +88,5 @@
</div> </div>
</div> </div>
</main> </main>
</ProtectedRoute>

View File

@@ -7,6 +7,7 @@
import AprovarAusencias from '$lib/components/AprovarAusencias.svelte'; import AprovarAusencias from '$lib/components/AprovarAusencias.svelte';
import CalendarioAusencias from '$lib/components/ausencias/CalendarioAusencias.svelte'; import CalendarioAusencias from '$lib/components/ausencias/CalendarioAusencias.svelte';
import { generateAvatarGallery } from '$lib/utils/avatars'; import { generateAvatarGallery } from '$lib/utils/avatars';
import ProtectedRoute from '$lib/components/ProtectedRoute.svelte';
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel'; import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
import { X, Calendar } from 'lucide-svelte'; import { X, Calendar } from 'lucide-svelte';
import type { FunctionReturnType } from 'convex/server'; import type { FunctionReturnType } from 'convex/server';
@@ -365,6 +366,7 @@
} }
</script> </script>
<ProtectedRoute>
<main class="min-h-screen pb-12"> <main class="min-h-screen pb-12">
<!-- BANNER HERO PREMIUM --> <!-- BANNER HERO PREMIUM -->
<div class="relative mb-8 overflow-hidden"> <div class="relative mb-8 overflow-hidden">
@@ -2264,6 +2266,7 @@
</dialog> </dialog>
{/if} {/if}
</main> </main>
</ProtectedRoute>
<!-- Modal Wizard Solicitação de Férias --> <!-- Modal Wizard Solicitação de Férias -->
{#if mostrarWizard && funcionarioIdDisponivel} {#if mostrarWizard && funcionarioIdDisponivel}

View File

@@ -1,8 +1,10 @@
<script lang="ts"> <script lang="ts">
import { Trophy, Award, Plus } from "lucide-svelte"; import { Trophy, Award, Plus } from "lucide-svelte";
import { resolve } from "$app/paths"; import { resolve } from "$app/paths";
import ProtectedRoute from "$lib/components/ProtectedRoute.svelte";
</script> </script>
<ProtectedRoute>
<main class="container mx-auto px-4 py-4"> <main class="container mx-auto px-4 py-4">
<div class="text-sm breadcrumbs mb-4"> <div class="text-sm breadcrumbs mb-4">
<ul> <ul>
@@ -41,4 +43,5 @@
</div> </div>
</div> </div>
</main> </main>
</ProtectedRoute>

View File

@@ -138,7 +138,7 @@
); );
</script> </script>
<ProtectedRoute allowedRoles={['ti_master', 'admin', 'ti_usuario']} maxLevel={3}> <ProtectedRoute allowedRoles={['ti_master', 'admin', 'ti_usuario']} maxLevel={1}>
<div class="container mx-auto max-w-7xl px-4 py-6"> <div class="container mx-auto max-w-7xl px-4 py-6">
<!-- Header --> <!-- Header -->
<div class="mb-8 flex items-center justify-between"> <div class="mb-8 flex items-center justify-between">

View File

@@ -4,7 +4,7 @@
import { resolve } from '$app/paths'; import { resolve } from '$app/paths';
</script> </script>
<ProtectedRoute allowedRoles={['admin', 'ti']} maxLevel={1}> <ProtectedRoute allowedRoles={['ti_master', 'admin']} maxLevel={1}>
<!-- Breadcrumb --> <!-- Breadcrumb -->
<div class="breadcrumbs mb-4 text-sm"> <div class="breadcrumbs mb-4 text-sm">
<ul> <ul>

View File

@@ -257,7 +257,7 @@
} }
</script> </script>
<ProtectedRoute allowedRoles={['ti_master', 'admin', 'ti_usuario']} maxLevel={3}> <ProtectedRoute allowedRoles={['ti_master', 'admin', 'ti_usuario']} maxLevel={1}>
<div class="container mx-auto max-w-7xl px-4 py-6"> <div class="container mx-auto max-w-7xl px-4 py-6">
<!-- Mensagem de Feedback --> <!-- Mensagem de Feedback -->
{#if mensagem} {#if mensagem}

View File

@@ -278,7 +278,7 @@
} }
</script> </script>
<ProtectedRoute allowedRoles={['ti_master', 'admin', 'ti_usuario']} maxLevel={2}> <ProtectedRoute allowedRoles={['ti_master', 'admin', 'ti_usuario']} maxLevel={1}>
<main class="container mx-auto max-w-7xl px-4 py-6"> <main class="container mx-auto max-w-7xl px-4 py-6">
<!-- Breadcrumb --> <!-- Breadcrumb -->
<div class="breadcrumbs mb-4 text-sm"> <div class="breadcrumbs mb-4 text-sm">

View File

@@ -535,7 +535,7 @@
} }
</script> </script>
<ProtectedRoute allowedRoles={['ti_master', 'admin', 'ti_usuario']} maxLevel={3}> <ProtectedRoute allowedRoles={['ti_master', 'admin', 'ti_usuario']} maxLevel={1}>
<div class="container mx-auto max-w-7xl px-4 py-6"> <div class="container mx-auto max-w-7xl px-4 py-6">
<!-- Header --> <!-- Header -->
<div class="mb-6 flex items-center justify-between"> <div class="mb-6 flex items-center justify-between">