feat: add authentication system (login, users, auth middleware)
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

- server/auth.js: JWT middleware and auth routes
- src/stores/auth.js + useAuthFetch.js: client-side auth state
- src/views/LoginView.vue + UsersView.vue: login and user management UI
- router, sidebar, App.vue: guard routes behind auth
- COOLIFY.md: add real deployment IDs
This commit is contained in:
alexandrump
2026-04-22 01:22:05 +02:00
parent 0a97e51dc6
commit 898d021ae8
14 changed files with 819 additions and 123 deletions

108
src/views/LoginView.vue Normal file
View File

@@ -0,0 +1,108 @@
<script setup>
import { ref } from "vue";
import { useRouter } from "vue-router";
import { useAuthStore } from "../stores/auth";
import { LogIn, ShieldCheck } from "lucide-vue-next";
const router = useRouter();
const auth = useAuthStore();
const username = ref("");
const password = ref("");
const error = ref("");
const loading = ref(false);
async function handleLogin() {
error.value = "";
loading.value = true;
try {
await auth.login(username.value, password.value);
router.push("/");
} catch (e) {
error.value = e.message;
} finally {
loading.value = false;
}
}
</script>
<template>
<div class="min-h-screen gradient-brand flex items-center justify-center p-6">
<div class="bg-white rounded-2xl shadow-2xl w-full max-w-md p-10">
<!-- Logo -->
<div class="flex flex-col items-center mb-8">
<div class="bg-blue-900 p-4 rounded-2xl mb-4 shadow-lg">
<svg
width="48"
height="48"
viewBox="0 0 100 100"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="50" cy="50" r="45" fill="#1e40af" />
<path
d="M30 70 L45 30 L55 50 L70 20"
stroke="white"
stroke-width="8"
stroke-linecap="round"
stroke-linejoin="round"
/>
<circle cx="70" cy="20" r="5" fill="white" />
</svg>
</div>
<h1 class="text-2xl font-black text-blue-900">SB SPORT</h1>
<p class="text-xs text-gray-400 uppercase tracking-widest mt-1">
Sanae Benkhlifa
</p>
</div>
<!-- Form -->
<form @submit.prevent="handleLogin" class="flex flex-col gap-4">
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">
Utilisateur
</label>
<input
v-model="username"
type="text"
autocomplete="username"
required
placeholder="sanae"
class="w-full border border-gray-300 rounded-xl px-4 py-3 focus:outline-none focus:ring-2 focus:ring-blue-500 text-gray-800"
/>
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">
Mot de passe
</label>
<input
v-model="password"
type="password"
autocomplete="current-password"
required
class="w-full border border-gray-300 rounded-xl px-4 py-3 focus:outline-none focus:ring-2 focus:ring-blue-500 text-gray-800"
/>
</div>
<p v-if="error" class="text-red-500 text-sm text-center">{{ error }}</p>
<button
type="submit"
:disabled="loading"
class="flex items-center justify-center gap-2 bg-blue-900 hover:bg-blue-800 disabled:opacity-60 text-white font-semibold py-3 rounded-xl transition-colors mt-2"
>
<LogIn class="w-4 h-4" />
{{ loading ? "Connexion…" : "Se connecter" }}
</button>
</form>
<div
class="flex items-center justify-center gap-1 mt-6 text-xs text-gray-400"
>
<ShieldCheck class="w-3 h-3" />
Accès sécurisé
</div>
</div>
</div>
</template>