All files / js/pages/Errors PermissionDenied.vue

0% Statements 0/19
0% Branches 0/28
0% Functions 0/5
0% Lines 0/19

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107                                                                                                                                                                                                                     
<script setup lang="ts">
import AppLayout from '@/layouts/AppLayout.vue';
import { Head, Link } from '@inertiajs/vue3';
import { ShieldX, ArrowLeft } from 'lucide-vue-next';
 
const props = defineProps<{
    module: string;
    ability: string;
    message: string;
    user?: any;
    requestedUrl?: string;
}>();
 
// Convert module and ability to more user-friendly text
const getModuleDisplayName = (module: string) => {
    const moduleNames: Record<string, string> = {
        'customers': 'Customers',
        'users': 'Users',
        'groups': 'Groups',
        'contacts': 'Contacts',
        'products': 'Products & Services',
        'jobcards': 'Jobcards',
        'quotes': 'Quotes',
        'invoices': 'Invoices',
    };
    return moduleNames[module] || module.charAt(0).toUpperCase() + module.slice(1);
};
 
const getAbilityDisplayName = (ability: string) => {
    const abilityNames: Record<string, string> = {
        'list': 'view the list of',
        'view': 'view',
        'create': 'create',
        'edit': 'edit',
        'delete': 'delete',
        'edit_completed': 'edit completed',
        'edit_salesperson': 'edit salesperson',
    };
    return abilityNames[ability] || ability;
};
 
const moduleDisplayName = getModuleDisplayName(props.module);
const abilityDisplayName = getAbilityDisplayName(props.ability);
</script>
 
<template>
    <Head title="Access Denied" />
 
    <AppLayout>
        <div class="flex min-h-[60vh] items-center justify-center p-4">
            <div class="max-w-md text-center">
                <!-- Icon -->
                <div class="mx-auto mb-6 flex h-20 w-20 items-center justify-center rounded-full bg-red-100">
                    <ShieldX class="h-10 w-10 text-red-600" />
                </div>
 
                <!-- Title -->
                <h1 class="mb-4 text-2xl font-bold text-gray-900">Access Denied</h1>
 
                <!-- Message -->
                <p class="mb-6 text-gray-600">
                    You don't have permission to {{ abilityDisplayName }} {{ moduleDisplayName }}.
                </p>
 
                <!-- Additional Info -->
                <div class="mb-8 rounded-lg bg-yellow-50 border border-yellow-200 p-4">
                    <p class="text-sm text-yellow-800">
                        <strong>Need access?</strong> Contact your administrator to request permission for this feature.
                    </p>
                </div>
 
                <!-- Actions -->
                <div class="flex flex-col gap-3 sm:flex-row sm:justify-center">
                    <Link
                        href="/dashboard"
                        class="inline-flex items-center justify-center rounded-md bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
                    >
                        <ArrowLeft class="mr-2 h-4 w-4" />
                        Go to Dashboard
                    </Link>
                    
                    <button
                        @click="$inertia.reload()"
                        class="inline-flex items-center justify-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
                    >
                        Try Again
                    </button>
                </div>
 
                <!-- Technical Details (for debugging) -->
                <details class="mt-8 text-left">
                    <summary class="cursor-pointer text-sm text-gray-500 hover:text-gray-700">
                        Technical Details
                    </summary>
                    <div class="mt-2 rounded bg-gray-100 p-3 text-xs text-gray-600">
                        <p><strong>Module:</strong> {{ module }}</p>
                        <p><strong>Ability:</strong> {{ ability }}</p>
                        <p><strong>Message:</strong> {{ message }}</p>
                        <p v-if="requestedUrl"><strong>Requested URL:</strong> {{ requestedUrl }}</p>
                        <p v-if="user"><strong>User:</strong> {{ user.name }} ({{ user.email }})</p>
                    </div>
                </details>
            </div>
        </div>
    </AppLayout>
</template>