Files
service-finder/frontend/src/layouts/AdminLayout.vue

232 lines
8.3 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>