232 lines
8.3 KiB
Vue
232 lines
8.3 KiB
Vue
<template>
|
||
<div class="admin-layout min-h-screen bg-gray-900 text-gray-100">
|
||
<!-- Sidebar -->
|
||
<aside class="fixed inset-y-0 left-0 w-64 bg-gray-800 border-r border-gray-700 z-50">
|
||
<div class="flex flex-col h-full">
|
||
<!-- Logo -->
|
||
<div class="p-6 border-b border-gray-700">
|
||
<div class="flex items-center space-x-3">
|
||
<div class="w-10 h-10 rounded-lg bg-gradient-to-br from-blue-500 to-indigo-600 flex items-center justify-center">
|
||
<span class="text-xl font-bold">SF</span>
|
||
</div>
|
||
<div>
|
||
<div class="text-xl font-bold">Service Finder</div>
|
||
<div class="text-xs text-gray-400">Admin Panel</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Navigation -->
|
||
<nav class="flex-1 p-4 space-y-2">
|
||
<router-link
|
||
to="/admin"
|
||
class="flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-gray-700 transition-colors"
|
||
:class="{ 'bg-blue-900/50 hover:bg-blue-900/70': $route.path === '/admin' }"
|
||
>
|
||
<span class="text-xl">📊</span>
|
||
<span class="font-medium">Dashboard</span>
|
||
</router-link>
|
||
|
||
<router-link
|
||
to="/admin/users"
|
||
class="flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-gray-700 transition-colors"
|
||
:class="{ 'bg-blue-900/50 hover:bg-blue-900/70': $route.path.startsWith('/admin/users') }"
|
||
>
|
||
<span class="text-xl">👥</span>
|
||
<span class="font-medium">User Management</span>
|
||
</router-link>
|
||
|
||
<router-link
|
||
to="/admin/packages"
|
||
class="flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-gray-700 transition-colors"
|
||
:class="{ 'bg-blue-900/50 hover:bg-blue-900/70': $route.path.startsWith('/admin/packages') }"
|
||
>
|
||
<span class="text-xl">📦</span>
|
||
<span class="font-medium">Subscription Packages</span>
|
||
</router-link>
|
||
|
||
<router-link
|
||
to="/admin/services"
|
||
class="flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-gray-700 transition-colors"
|
||
:class="{ 'bg-blue-900/50 hover:bg-blue-900/70': $route.path.startsWith('/admin/services') }"
|
||
>
|
||
<span class="text-xl">🛠️</span>
|
||
<span class="font-medium">Services</span>
|
||
</router-link>
|
||
|
||
<router-link
|
||
to="/admin/vehicles"
|
||
class="flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-gray-700 transition-colors"
|
||
>
|
||
<span class="text-xl">🚗</span>
|
||
<span class="font-medium">Vehicle Catalog</span>
|
||
</router-link>
|
||
|
||
<router-link
|
||
to="/admin/translations"
|
||
class="flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-gray-700 transition-colors"
|
||
>
|
||
<span class="text-xl">🌐</span>
|
||
<span class="font-medium">i18n Manager</span>
|
||
</router-link>
|
||
|
||
<router-link
|
||
to="/admin/system"
|
||
class="flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-gray-700 transition-colors"
|
||
>
|
||
<span class="text-xl">⚙️</span>
|
||
<span class="font-medium">System Settings</span>
|
||
</router-link>
|
||
|
||
<router-link
|
||
to="/admin/audit"
|
||
class="flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-gray-700 transition-colors"
|
||
>
|
||
<span class="text-xl">📋</span>
|
||
<span class="font-medium">Audit Logs</span>
|
||
</router-link>
|
||
|
||
<div class="pt-6 border-t border-gray-700">
|
||
<div class="px-4 py-2 text-xs text-gray-500 uppercase tracking-wider">Navigation</div>
|
||
<router-link
|
||
to="/dashboard"
|
||
class="flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-gray-700 transition-colors"
|
||
>
|
||
<span class="text-xl">🏠</span>
|
||
<span class="font-medium">Back to Dashboard</span>
|
||
</router-link>
|
||
</div>
|
||
</nav>
|
||
|
||
<!-- User Profile -->
|
||
<div class="p-4 border-t border-gray-700">
|
||
<div class="flex items-center space-x-3">
|
||
<div class="w-10 h-10 rounded-full bg-gradient-to-br from-gray-600 to-gray-800 flex items-center justify-center">
|
||
<span class="text-lg">{{ userInitials }}</span>
|
||
</div>
|
||
<div class="flex-1">
|
||
<div class="font-medium truncate">{{ userName }}</div>
|
||
<div class="text-xs text-gray-400 capitalize">{{ userRoleLabel }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- Main Content -->
|
||
<div class="pl-64">
|
||
<!-- Top Bar -->
|
||
<header class="sticky top-0 z-40 bg-gray-800/90 backdrop-blur-sm border-b border-gray-700">
|
||
<div class="flex justify-between items-center px-8 py-4">
|
||
<div class="flex items-center space-x-4">
|
||
<h1 class="text-2xl font-bold">{{ pageTitle }}</h1>
|
||
<div class="text-sm px-3 py-1 bg-gray-700 rounded-full">
|
||
{{ currentTime }}
|
||
</div>
|
||
</div>
|
||
|
||
<div class="flex items-center space-x-4">
|
||
<slot name="header-controls">
|
||
<LanguageSwitcher />
|
||
<ModeSwitcher />
|
||
</slot>
|
||
|
||
<!-- HeaderProfile komponens: profil, admin center, kilépés -->
|
||
<HeaderProfile />
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- Content Area -->
|
||
<main class="p-8">
|
||
<div class="bg-gray-800/50 rounded-xl border border-gray-700 p-6">
|
||
<router-view />
|
||
</div>
|
||
|
||
<!-- Footer Stats -->
|
||
<div class="mt-8 grid grid-cols-4 gap-4">
|
||
<div class="bg-gray-800/50 rounded-lg p-4 border border-gray-700">
|
||
<div class="text-sm text-gray-400">System Status</div>
|
||
<div class="text-2xl font-bold text-green-400">Operational</div>
|
||
</div>
|
||
<div class="bg-gray-800/50 rounded-lg p-4 border border-gray-700">
|
||
<div class="text-sm text-gray-400">API Response</div>
|
||
<div class="text-2xl font-bold">42ms</div>
|
||
</div>
|
||
<div class="bg-gray-800/50 rounded-lg p-4 border border-gray-700">
|
||
<div class="text-sm text-gray-400">Active Sessions</div>
|
||
<div class="text-2xl font-bold">127</div>
|
||
</div>
|
||
<div class="bg-gray-800/50 rounded-lg p-4 border border-gray-700">
|
||
<div class="text-sm text-gray-400">Uptime</div>
|
||
<div class="text-2xl font-bold">99.8%</div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||
import { useRoute } from 'vue-router'
|
||
import { useAuthStore } from '../stores/auth'
|
||
import LanguageSwitcher from '../components/LanguageSwitcher.vue'
|
||
import ModeSwitcher from '../components/ModeSwitcher.vue'
|
||
import HeaderProfile from '../components/header/HeaderProfile.vue'
|
||
|
||
const route = useRoute()
|
||
const authStore = useAuthStore()
|
||
const currentTime = ref('')
|
||
|
||
const pageTitle = computed(() => {
|
||
const name = route.name?.toString() || 'Dashboard'
|
||
return name.charAt(0).toUpperCase() + name.slice(1)
|
||
})
|
||
|
||
const userName = computed(() => {
|
||
if (!authStore.user) return 'Admin User'
|
||
const { first_name, last_name } = authStore.user
|
||
if (first_name && last_name) return `${first_name} ${last_name}`
|
||
return authStore.user.email || 'Admin User'
|
||
})
|
||
|
||
const userInitials = computed(() => {
|
||
if (!authStore.user) return 'AD'
|
||
const { first_name, last_name } = authStore.user
|
||
if (first_name && last_name) {
|
||
return (first_name[0] + last_name[0]).toUpperCase()
|
||
}
|
||
return authStore.user.email?.[0]?.toUpperCase() || 'A'
|
||
})
|
||
|
||
const userRoleLabel = computed(() => {
|
||
return authStore.user?.role?.replace(/_/g, ' ') || 'Administrator'
|
||
})
|
||
|
||
function updateTime() {
|
||
const now = new Date()
|
||
currentTime.value = now.toLocaleTimeString('en-US', {
|
||
hour12: false,
|
||
hour: '2-digit',
|
||
minute: '2-digit'
|
||
})
|
||
}
|
||
|
||
let intervalId: number
|
||
|
||
onMounted(() => {
|
||
updateTime()
|
||
intervalId = setInterval(updateTime, 1000)
|
||
})
|
||
|
||
onUnmounted(() => {
|
||
clearInterval(intervalId)
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.admin-layout {
|
||
font-family: 'Inter', sans-serif;
|
||
}
|
||
</style> |