feat: add authentication modal component and user authentication logic

- Implemented AuthModal.vue for user login and registration with form handling.
- Created useAuth composable for managing user state and authentication requests.
- Added admin route middleware to protect admin routes.
- Developed admin login page with authentication checks.
- Implemented API endpoints for user management (login, logout, fetch user, register).
- Created database migrations for users table and updated movies table.
- Added utility functions for password hashing and JWT token management.
This commit is contained in:
ngthanhvu
2026-07-22 04:26:58 -04:00
parent ad8d577493
commit d982449464
29 changed files with 1965 additions and 178 deletions
+26 -10
View File
@@ -1,6 +1,5 @@
<script setup lang="ts">
import {
BarChart3,
Film,
Home,
LogOut,
@@ -11,8 +10,13 @@ import {
} from 'lucide-vue-next'
const route = useRoute()
const router = useRouter()
const sidebarOpen = ref(false)
const { data: user } = await useFetch('/api/auth/me', {
headers: useRequestHeaders(['cookie']),
})
const navItems = [
{ label: 'Dashboard', icon: Home, to: '/admin' },
{ label: 'Phim', icon: Film, to: '/admin/phim' },
@@ -28,6 +32,14 @@ function isActive(to: string) {
function closeSidebar() {
sidebarOpen.value = false
}
async function handleLogout() {
await $fetch('/api/auth/logout', { method: 'POST' })
await navigateTo('/admin/login')
}
const displayName = computed(() => user.value?.name || user.value?.email?.split('@')[0] || 'Admin')
const displayInitial = computed(() => displayName.value.charAt(0).toUpperCase())
</script>
<template>
@@ -59,12 +71,18 @@ function closeSidebar() {
</NuxtLink>
</nav>
<div class="absolute inset-x-0 bottom-0 border-t border-white/10 p-4">
<div class="absolute inset-x-0 bottom-0 space-y-1 border-t border-white/10 p-4">
<NuxtLink to="/"
class="flex items-center gap-3 rounded-lg px-4 py-3 text-sm font-semibold text-slate-300 transition hover:bg-white/5 hover:text-white">
<Home class="size-5" />
Về trang chủ
</NuxtLink>
<button type="button"
class="flex w-full items-center gap-3 rounded-lg px-4 py-3 text-sm font-semibold text-red-400 transition hover:bg-red-400/10"
@click="handleLogout">
<LogOut class="size-5" />
Đăng xuất
</button>
</div>
</aside>
@@ -77,14 +95,12 @@ function closeSidebar() {
</button>
<div class="ml-auto flex items-center gap-3">
<div class="flex items-center gap-3">
<div class="grid size-9 place-items-center rounded-full bg-yellow-400/10">
<span class="text-sm font-black text-yellow-400">A</span>
</div>
<div class="hidden sm:block">
<p class="text-sm font-semibold text-white">Admin</p>
<p class="text-xs text-slate-400">Administrator</p>
</div>
<div class="grid size-9 place-items-center rounded-full bg-yellow-400/10">
<span class="text-sm font-black text-yellow-400">{{ displayInitial }}</span>
</div>
<div class="hidden sm:block">
<p class="text-sm font-semibold text-white">{{ displayName }}</p>
<p class="text-xs capitalize text-slate-400">{{ user?.role || 'admin' }}</p>
</div>
</div>
</header>