admin felület különválasztva

This commit is contained in:
Roo
2026-06-24 11:29:45 +00:00
parent 71ef33bb85
commit 80a5d67f79
462 changed files with 87873 additions and 312 deletions

View File

@@ -0,0 +1,128 @@
<template>
<div>
<!-- Page Header -->
<div class="mb-8">
<h1 class="text-2xl font-bold text-white">Dashboard</h1>
<p class="text-slate-400 mt-1">ServiceFinder administration overview</p>
</div>
<!-- Stat Tiles Grid -->
<div class="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-6 mb-8">
<!-- Active Users -->
<div class="bg-slate-800 rounded-xl border border-slate-700 p-6 hover:border-indigo-500/50 transition group">
<div class="flex items-center justify-between mb-4">
<div class="p-2 rounded-lg bg-indigo-500/10 text-indigo-400 group-hover:bg-indigo-500/20 transition">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197m13.5-9a2.25 2.25 0 11-4.5 0 2.25 2.25 0 014.5 0z" />
</svg>
</div>
<span class="text-xs font-medium text-emerald-400 bg-emerald-400/10 px-2 py-1 rounded-full">+12%</span>
</div>
<h3 class="text-sm font-medium text-slate-400 uppercase tracking-wider">Active Users</h3>
<p class="text-3xl font-bold text-white mt-2">2,847</p>
<p class="text-xs text-slate-500 mt-1">1,240 new this month</p>
</div>
<!-- Total Vehicles -->
<div class="bg-slate-800 rounded-xl border border-slate-700 p-6 hover:border-cyan-500/50 transition group">
<div class="flex items-center justify-between mb-4">
<div class="p-2 rounded-lg bg-cyan-500/10 text-cyan-400 group-hover:bg-cyan-500/20 transition">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.5 21v-7.5a.75.75 0 01.75-.75h3a.75.75 0 01.75.75V21m-4.5 0H2.36m11.14 0H18m0 0h3.64m-1.39 0V9.349m-16.5 11.65V9.35m0 0a3.001 3.001 0 003.75-.615A2.993 2.993 0 009.75 9.75c.896 0 1.7-.393 2.25-1.016a2.993 2.993 0 002.25 1.016c.896 0 1.7-.393 2.25-1.016a3.001 3.001 0 003.75.614m-16.5 0a3.004 3.004 0 01-.621-4.72L4.318 3.44A1.5 1.5 0 015.378 3h13.243a1.5 1.5 0 011.06.44l1.19 1.189a3 3 0 01-.621 4.72m-13.5 8.65h3.75a.75.75 0 00.75-.75V13.5a.75.75 0 00-.75-.75H6.75a.75.75 0 00-.75.75v3.75c0 .415.336.75.75.75z" />
</svg>
</div>
<span class="text-xs font-medium text-emerald-400 bg-emerald-400/10 px-2 py-1 rounded-full">+5%</span>
</div>
<h3 class="text-sm font-medium text-slate-400 uppercase tracking-wider">Total Vehicles</h3>
<p class="text-3xl font-bold text-white mt-2">12,493</p>
<p class="text-xs text-slate-500 mt-1">342 added this month</p>
</div>
<!-- Monthly Revenue -->
<div class="bg-slate-800 rounded-xl border border-slate-700 p-6 hover:border-emerald-500/50 transition group">
<div class="flex items-center justify-between mb-4">
<div class="p-2 rounded-lg bg-emerald-500/10 text-emerald-400 group-hover:bg-emerald-500/20 transition">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v12m-3-2.818l.879.659c1.171.879 3.07.879 4.242 0 1.172-.879 1.172-2.303 0-3.182C13.536 12.219 12.768 12 12 12c-.725 0-1.45-.22-2.003-.659-1.106-.879-1.106-2.303 0-3.182s2.9-.879 4.006 0l.415.33M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
<span class="text-xs font-medium text-emerald-400 bg-emerald-400/10 px-2 py-1 rounded-full">+18%</span>
</div>
<h3 class="text-sm font-medium text-slate-400 uppercase tracking-wider">Monthly Revenue</h3>
<p class="text-3xl font-bold text-white mt-2">48,250</p>
<p class="text-xs text-slate-500 mt-1">6,200 from premium</p>
</div>
<!-- Error Logs -->
<div class="bg-slate-800 rounded-xl border border-slate-700 p-6 hover:border-rose-500/50 transition group">
<div class="flex items-center justify-between mb-4">
<div class="p-2 rounded-lg bg-rose-500/10 text-rose-400 group-hover:bg-rose-500/20 transition">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" />
</svg>
</div>
<span class="text-xs font-medium text-rose-400 bg-rose-400/10 px-2 py-1 rounded-full">+3</span>
</div>
<h3 class="text-sm font-medium text-slate-400 uppercase tracking-wider">Error Logs</h3>
<p class="text-3xl font-bold text-white mt-2">23</p>
<p class="text-xs text-slate-500 mt-1">3 critical today</p>
</div>
</div>
<!-- Quick Actions & Recent Activity -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Quick Actions -->
<div class="bg-slate-800 rounded-xl border border-slate-700 p-6">
<h2 class="text-lg font-semibold text-white mb-4">Quick Actions</h2>
<div class="space-y-3">
<button class="w-full flex items-center gap-3 px-4 py-3 bg-slate-700/50 hover:bg-slate-700 rounded-lg text-sm text-slate-300 hover:text-white transition text-left">
<svg class="w-5 h-5 text-indigo-400 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197m13.5-9a2.25 2.25 0 11-4.5 0 2.25 2.25 0 014.5 0z" />
</svg>
Invite New Admin User
</button>
<button class="w-full flex items-center gap-3 px-4 py-3 bg-slate-700/50 hover:bg-slate-700 rounded-lg text-sm text-slate-300 hover:text-white transition text-left">
<svg class="w-5 h-5 text-cyan-400 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.5 21v-7.5a.75.75 0 01.75-.75h3a.75.75 0 01.75.75V21m-4.5 0H2.36m11.14 0H18m0 0h3.64m-1.39 0V9.349m-16.5 11.65V9.35m0 0a3.001 3.001 0 003.75-.615A2.993 2.993 0 009.75 9.75c.896 0 1.7-.393 2.25-1.016a2.993 2.993 0 002.25 1.016c.896 0 1.7-.393 2.25-1.016a3.001 3.001 0 003.75.614m-16.5 0a3.004 3.004 0 01-.621-4.72L4.318 3.44A1.5 1.5 0 015.378 3h13.243a1.5 1.5 0 011.06.44l1.19 1.189a3 3 0 01-.621 4.72m-13.5 8.65h3.75a.75.75 0 00.75-.75V13.5a.75.75 0 00-.75-.75H6.75a.75.75 0 00-.75.75v3.75c0 .415.336.75.75.75z" />
</svg>
Add New Vehicle
</button>
<button class="w-full flex items-center gap-3 px-4 py-3 bg-slate-700/50 hover:bg-slate-700 rounded-lg text-sm text-slate-300 hover:text-white transition text-left">
<svg class="w-5 h-5 text-emerald-400 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h3.75M9 15h3.75M9 18h3.75m3 .75H18a2.25 2.25 0 002.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 00-1.123-.08m-5.801 0c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75 2.25 2.25 0 00-.1-.664m-5.8 0A2.251 2.251 0 0113.5 2.25H15a2.25 2.25 0 012.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m0 0H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V9.375c0-.621-.504-1.125-1.125-1.125H8.25zM6.75 12h.008v.008H6.75V12zm0 3h.008v.008H6.75V15zm0 3h.008v.008H6.75V18z" />
</svg>
View Service Reports
</button>
</div>
</div>
<!-- Recent Activity -->
<div class="bg-slate-800 rounded-xl border border-slate-700 p-6">
<h2 class="text-lg font-semibold text-white mb-4">Recent Activity</h2>
<div class="space-y-4">
<div v-for="(activity, index) in recentActivities" :key="index" class="flex items-start gap-3">
<div class="w-2 h-2 mt-2 rounded-full flex-shrink-0" :class="activity.dotColor" />
<div class="flex-1 min-w-0">
<p class="text-sm text-slate-300">{{ activity.text }}</p>
<p class="text-xs text-slate-500 mt-0.5">{{ activity.time }}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
definePageMeta({
middleware: 'auth',
})
const recentActivities = [
{ text: 'New user registered: john.doe@example.com', time: '2 minutes ago', dotColor: 'bg-emerald-400' },
{ text: 'Vehicle #V-8842 added to catalog', time: '15 minutes ago', dotColor: 'bg-cyan-400' },
{ text: 'Payment received: €120.00 from Garage XYZ', time: '1 hour ago', dotColor: 'bg-emerald-400' },
{ text: 'System error: DVLA API timeout on request #4421', time: '2 hours ago', dotColor: 'bg-rose-400' },
{ text: 'Permission updated for user: superadmin@sf.hu', time: '3 hours ago', dotColor: 'bg-indigo-400' },
]
</script>

View File

@@ -0,0 +1,112 @@
<template>
<div class="min-h-screen bg-slate-900 flex items-center justify-center px-4">
<div class="w-full max-w-md">
<!-- Logo / Branding -->
<div class="text-center mb-8">
<div class="flex items-center justify-center gap-3 mb-4">
<img
src="/sf_logo.png"
class="h-12 w-auto drop-shadow-md"
alt="ServiceFinder Logo"
/>
<span class="text-3xl font-extrabold tracking-wider">
<span class="text-white">SERVICE</span>
<span class="text-cyan-400">FINDER</span>
</span>
</div>
<h1 class="text-xl font-semibold text-slate-300">Staff Portal</h1>
<p class="text-sm text-slate-500 mt-1">Authorised personnel only</p>
</div>
<!-- Login Card -->
<div class="bg-slate-800 rounded-xl shadow-2xl border border-slate-700 p-8">
<!-- Error Alert -->
<div
v-if="authStore.error"
class="mb-6 p-3 rounded-lg bg-red-900/40 border border-red-700 text-red-300 text-sm"
>
{{ authStore.error }}
</div>
<form @submit.prevent="handleLogin" class="space-y-5">
<!-- Email -->
<div>
<label for="email" class="block text-sm font-medium text-slate-300 mb-1.5">
Email Address
</label>
<input
id="email"
v-model="email"
type="email"
autocomplete="email"
required
placeholder="admin@example.com"
class="w-full px-4 py-2.5 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-cyan-500 focus:border-transparent transition"
/>
</div>
<!-- Password -->
<div>
<label for="password" class="block text-sm font-medium text-slate-300 mb-1.5">
Password
</label>
<input
id="password"
v-model="password"
type="password"
autocomplete="current-password"
required
placeholder="••••••••"
class="w-full px-4 py-2.5 bg-slate-700 border border-slate-600 rounded-lg text-white placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-cyan-500 focus:border-transparent transition"
/>
</div>
<!-- Submit Button -->
<button
type="submit"
:disabled="authStore.isLoading"
class="w-full py-2.5 px-4 bg-cyan-600 hover:bg-cyan-500 disabled:bg-cyan-800 disabled:cursor-not-allowed text-white font-semibold rounded-lg transition duration-200 flex items-center justify-center gap-2"
>
<svg
v-if="authStore.isLoading"
class="animate-spin h-5 w-5 text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" />
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
</svg>
<span>{{ authStore.isLoading ? 'Signing in...' : 'Sign In' }}</span>
</button>
</form>
<!-- Back to main site -->
<div class="mt-6 text-center">
<NuxtLink to="/" class="text-sm text-slate-500 hover:text-cyan-400 transition">
&larr; Back to ServiceFinder
</NuxtLink>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
const email = ref('')
const password = ref('')
const router = useRouter()
const authStore = useAuthStore()
async function handleLogin() {
try {
await authStore.login(email.value, password.value)
// On success, redirect to admin dashboard
router.push('/')
} catch (err: any) {
// Error is already stored in authStore.error
console.error('Login failed:', err)
}
}
</script>

View File

@@ -0,0 +1,141 @@
<template>
<div>
<!-- Page Header -->
<div class="mb-8">
<h1 class="text-2xl font-bold text-white">Jogosultság Kezelés</h1>
<p class="text-slate-400 mt-1">Permissions Management Role-based access control matrix</p>
</div>
<!-- Info Banner -->
<div class="bg-indigo-500/10 border border-indigo-500/20 rounded-xl p-4 mb-8 flex items-start gap-3">
<svg class="w-5 h-5 text-indigo-400 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<p class="text-sm text-indigo-300">
This is the permissions management interface. The 3D Capability Matrix UI (Superadmin, Garages, and Packages toggles) will be implemented here in the next iteration.
</p>
</div>
<!-- Permission Groups Grid -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-8">
<!-- Superadmin Permissions -->
<div class="bg-slate-800 rounded-xl border border-slate-700 p-6">
<div class="flex items-center gap-3 mb-4">
<div class="p-2 rounded-lg bg-purple-500/10 text-purple-400">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12.75L11.25 15 15 9.75m-3-7.036A11.959 11.959 0 013.598 6 11.99 11.99 0 003 9.749c0 5.592 3.824 10.29 9 11.623 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285z" />
</svg>
</div>
<h2 class="text-lg font-semibold text-white">Superadmin</h2>
</div>
<p class="text-sm text-slate-400 mb-4">Full system access user management, billing, robots, and system configuration.</p>
<div class="space-y-3">
<div v-for="perm in superadminPerms" :key="perm.key" class="flex items-center justify-between py-2 border-b border-slate-700/50 last:border-0">
<span class="text-sm text-slate-300">{{ perm.label }}</span>
<span class="text-xs px-2 py-0.5 rounded-full" :class="perm.enabled ? 'bg-emerald-400/10 text-emerald-400' : 'bg-slate-700 text-slate-500'">
{{ perm.enabled ? 'Enabled' : 'Disabled' }}
</span>
</div>
</div>
<div class="mt-4 pt-4 border-t border-slate-700">
<button class="w-full px-4 py-2 text-sm bg-purple-600 hover:bg-purple-500 text-white rounded-lg transition">
Configure Superadmin
</button>
</div>
</div>
<!-- Garage Permissions -->
<div class="bg-slate-800 rounded-xl border border-slate-700 p-6">
<div class="flex items-center gap-3 mb-4">
<div class="p-2 rounded-lg bg-cyan-500/10 text-cyan-400">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.25 18.75a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m3 0h6m-9 0H3.375a1.125 1.125 0 01-1.125-1.125V14.25m17.25 4.5a1.5 1.5 0 01-3 0m3 0a1.5 1.5 0 00-3 0m3 0h1.125c.621 0 1.129-.504 1.09-1.124a17.902 17.902 0 00-3.213-9.193 2.056 2.056 0 00-1.58-.86H14.25M16.5 18.75h-2.25m0-11.177v-.958c0-.568-.422-1.048-.987-1.106a48.554 48.554 0 00-10.026 0 1.106 1.106 0 00-.987 1.106v7.635m12-6.677v6.677m0 4.5v-4.5m0 0h-12" />
</svg>
</div>
<h2 class="text-lg font-semibold text-white">Garages</h2>
</div>
<p class="text-sm text-slate-400 mb-4">Garage-level access vehicle management, service booking, customer data.</p>
<div class="space-y-3">
<div v-for="perm in garagePerms" :key="perm.key" class="flex items-center justify-between py-2 border-b border-slate-700/50 last:border-0">
<span class="text-sm text-slate-300">{{ perm.label }}</span>
<span class="text-xs px-2 py-0.5 rounded-full" :class="perm.enabled ? 'bg-emerald-400/10 text-emerald-400' : 'bg-slate-700 text-slate-500'">
{{ perm.enabled ? 'Enabled' : 'Disabled' }}
</span>
</div>
</div>
<div class="mt-4 pt-4 border-t border-slate-700">
<button class="w-full px-4 py-2 text-sm bg-cyan-600 hover:bg-cyan-500 text-white rounded-lg transition">
Configure Garages
</button>
</div>
</div>
<!-- Package Permissions -->
<div class="bg-slate-800 rounded-xl border border-slate-700 p-6">
<div class="flex items-center gap-3 mb-4">
<div class="p-2 rounded-lg bg-amber-500/10 text-amber-400">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.25 7.5l-.625 10.632a2.25 2.25 0 01-2.247 2.118H6.622a2.25 2.25 0 01-2.247-2.118L3.75 7.5m8.25 3v6.75m0 0l-3-3m3 3l3-3M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125z" />
</svg>
</div>
<h2 class="text-lg font-semibold text-white">Packages</h2>
</div>
<p class="text-sm text-slate-400 mb-4">Subscription package permissions feature toggles per plan tier.</p>
<div class="space-y-3">
<div v-for="perm in packagePerms" :key="perm.key" class="flex items-center justify-between py-2 border-b border-slate-700/50 last:border-0">
<span class="text-sm text-slate-300">{{ perm.label }}</span>
<span class="text-xs px-2 py-0.5 rounded-full" :class="perm.enabled ? 'bg-emerald-400/10 text-emerald-400' : 'bg-slate-700 text-slate-500'">
{{ perm.enabled ? 'Enabled' : 'Disabled' }}
</span>
</div>
</div>
<div class="mt-4 pt-4 border-t border-slate-700">
<button class="w-full px-4 py-2 text-sm bg-amber-600 hover:bg-amber-500 text-white rounded-lg transition">
Configure Packages
</button>
</div>
</div>
</div>
<!-- Placeholder for 3D Capability Matrix -->
<div class="bg-slate-800/50 border-2 border-dashed border-slate-600 rounded-xl p-12 text-center">
<svg class="w-12 h-12 mx-auto text-slate-600 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 17.25v1.007a3 3 0 01-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0115 18.257V17.25m6-12V15a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 15V5.25m18 0A2.25 2.25 0 0018.75 3H5.25A2.25 2.25 0 003 5.25m18 0V12a2.25 2.25 0 01-2.25 2.25H5.25A2.25 2.25 0 013 12V5.25" />
</svg>
<h3 class="text-lg font-semibold text-slate-400 mb-2">3D Capability Matrix</h3>
<p class="text-sm text-slate-500 max-w-md mx-auto">
The interactive permission matrix UI with toggles for Superadmin, Garages, and Packages will be rendered here in the next development phase.
</p>
</div>
</div>
</template>
<script setup lang="ts">
definePageMeta({
middleware: 'auth',
})
const superadminPerms = [
{ key: 'user_mgmt', label: 'User Management', enabled: true },
{ key: 'billing_admin', label: 'Billing Administration', enabled: true },
{ key: 'robot_config', label: 'Robot Configuration', enabled: true },
{ key: 'system_logs', label: 'System Logs Access', enabled: true },
{ key: 'api_keys', label: 'API Key Management', enabled: false },
]
const garagePerms = [
{ key: 'vehicle_crud', label: 'Vehicle CRUD', enabled: true },
{ key: 'service_booking', label: 'Service Booking', enabled: true },
{ key: 'customer_view', label: 'Customer Data View', enabled: true },
{ key: 'report_export', label: 'Report Export', enabled: false },
{ key: 'bulk_import', label: 'Bulk Import', enabled: false },
]
const packagePerms = [
{ key: 'premium_features', label: 'Premium Features', enabled: true },
{ key: 'analytics', label: 'Analytics Dashboard', enabled: true },
{ key: 'multi_garage', label: 'Multi-Garage Support', enabled: false },
{ key: 'white_label', label: 'White Label Branding', enabled: false },
{ key: 'api_access', label: 'API Access', enabled: true },
]
</script>