feat: initialisation complète du projet CESIZen

- Backend Laravel 11 (API REST, JWT auth, PostgreSQL)
- Frontend Next.js 14 (React, TypeScript, Tailwind CSS)
- Docker Compose (PostgreSQL, backend, frontend)
- Modules : auth, profil, tracker émotions, informations, admin
This commit is contained in:
Azmog
2026-03-11 16:27:01 +01:00
commit e3da625927
158 changed files with 25139 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
import axios from 'axios';
const api = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api/v1',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
});
// Intercepteur de requête : ajouter le token JWT si présent
api.interceptors.request.use(
(config) => {
if (typeof window !== 'undefined') {
const token = localStorage.getItem('cesizen_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
}
return config;
},
(error) => Promise.reject(error)
);
// Intercepteur de réponse : gérer les erreurs 401
api.interceptors.response.use(
(response) => response,
(error) => {
if (
error.response?.status === 401 &&
typeof window !== 'undefined' &&
!window.location.pathname.includes('/connexion')
) {
localStorage.removeItem('cesizen_token');
window.location.href = '/connexion';
}
return Promise.reject(error);
}
);
export default api;
+103
View File
@@ -0,0 +1,103 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import api from './api';
import type { Utilisateur } from '@/types';
function syncCookie(user: Utilisateur | null, token: string | null) {
if (typeof document === 'undefined') return;
if (token) {
const value = JSON.stringify({
state: {
token,
isAuthenticated: true,
user: user ? { role: { nom: user.role?.nom } } : null,
},
});
document.cookie = `cesizen-auth=${encodeURIComponent(value)};path=/;max-age=${60 * 60 * 24 * 7};SameSite=Lax`;
} else {
document.cookie = 'cesizen-auth=;path=/;max-age=0';
}
}
interface AuthState {
user: Utilisateur | null;
token: string | null;
isAuthenticated: boolean;
login: (email: string, password: string) => Promise<void>;
register: (data: {
nom: string;
prenom: string;
email: string;
password: string;
password_confirmation: string;
}) => Promise<void>;
logout: () => Promise<void>;
fetchUser: () => Promise<void>;
setAuth: (user: Utilisateur | null, token: string | null) => void;
}
export const useAuthStore = create<AuthState>()(
persist(
(set, get) => ({
user: null,
token: null,
isAuthenticated: false,
login: async (email: string, password: string) => {
const response = await api.post('/auth/login', { email, password });
const { utilisateur, token } = response.data;
localStorage.setItem('cesizen_token', token);
syncCookie(utilisateur, token);
set({ user: utilisateur, token, isAuthenticated: true });
},
register: async (data) => {
const response = await api.post('/auth/register', data);
const { utilisateur, token } = response.data;
localStorage.setItem('cesizen_token', token);
syncCookie(utilisateur, token);
set({ user: utilisateur, token, isAuthenticated: true });
},
logout: async () => {
try {
await api.post('/auth/logout');
} catch {
// Ignorer les erreurs de déconnexion
}
localStorage.removeItem('cesizen_token');
syncCookie(null, null);
set({ user: null, token: null, isAuthenticated: false });
},
fetchUser: async () => {
const response = await api.get('/auth/me');
set({ user: response.data });
},
setAuth: (user: Utilisateur | null, token: string | null) => {
if (token) {
localStorage.setItem('cesizen_token', token);
} else {
localStorage.removeItem('cesizen_token');
}
set({ user, token, isAuthenticated: !!token });
},
}),
{
name: 'cesizen-auth',
partialize: (state) => ({
user: state.user,
token: state.token,
isAuthenticated: state.isAuthenticated,
}),
onRehydrateStorage: () => {
return (state) => {
if (state) {
syncCookie(state.user, state.token);
}
};
},
}
)
);