chore : move all to root

This commit is contained in:
Thibault Pouch
2026-02-26 16:16:44 +01:00
parent 308a758e79
commit c2d94a349c
44 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,156 @@
import React, {
createContext,
useCallback,
useContext,
useMemo,
useState,
} from 'react';
import type { User, UserRole } from '../types';
import { MOCK_USERS } from '../data/mockData';
// ── Types ──────────────────────────────────────────────────────────────────────
interface AuthContextValue {
user: User | null;
isAuthenticated: boolean;
isStaff: boolean;
isAdmin: boolean;
login: (email: string, password: string) => Promise<{ success: boolean; error?: string }>;
register: (username: string, email: string, password: string) => Promise<{ success: boolean; error?: string }>;
logout: () => void;
updateUsername: (username: string) => void;
// Dev helper: quickly switch role for testing
devSetRole: (role: UserRole) => void;
}
// ── Context ────────────────────────────────────────────────────────────────────
const AuthContext = createContext<AuthContextValue | null>(null);
// ── Provider ───────────────────────────────────────────────────────────────────
const STORAGE_KEY = 'crowmate_auth_user';
function loadUserFromStorage(): User | null {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return null;
return JSON.parse(raw) as User;
} catch {
return null;
}
}
function saveUserToStorage(user: User | null): void {
if (user) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(user));
} else {
localStorage.removeItem(STORAGE_KEY);
}
}
export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(loadUserFromStorage);
const isAuthenticated = user !== null;
const isStaff = user?.role === 'dev' || user?.role === 'com';
const isAdmin = user?.isAdmin === true;
const login = useCallback(
async (email: string, _password: string): Promise<{ success: boolean; error?: string }> => {
// Simulate network delay
await new Promise((r) => setTimeout(r, 400));
const found = MOCK_USERS.find(
(u) => u.email.toLowerCase() === email.toLowerCase()
);
if (!found) {
return { success: false, error: 'No account found with that email address.' };
}
if (found.isBanned) {
return { success: false, error: 'This account has been suspended.' };
}
setUser(found);
saveUserToStorage(found);
return { success: true };
},
[]
);
const register = useCallback(
async (username: string, email: string, _password: string): Promise<{ success: boolean; error?: string }> => {
await new Promise((r) => setTimeout(r, 500));
const emailTaken = MOCK_USERS.some(
(u) => u.email.toLowerCase() === email.toLowerCase()
);
if (emailTaken) {
return { success: false, error: 'An account with this email already exists.' };
}
const usernameTaken = MOCK_USERS.some(
(u) => u.username.toLowerCase() === username.toLowerCase()
);
if (usernameTaken) {
return { success: false, error: 'This username is already taken.' };
}
const newUser: User = {
id: `u${Date.now()}`,
username,
email,
role: 'user',
isAdmin: false,
isBanned: false,
createdAt: new Date().toISOString(),
};
setUser(newUser);
saveUserToStorage(newUser);
return { success: true };
},
[]
);
const logout = useCallback(() => {
setUser(null);
saveUserToStorage(null);
}, []);
const updateUsername = useCallback((username: string) => {
setUser((prev) => {
if (!prev) return prev;
const updated = { ...prev, username };
saveUserToStorage(updated);
return updated;
});
}, []);
const devSetRole = useCallback((role: UserRole) => {
setUser((prev) => {
if (!prev) return prev;
const updated = { ...prev, role, isAdmin: role === 'dev' };
saveUserToStorage(updated);
return updated;
});
}, []);
const value = useMemo<AuthContextValue>(
() => ({ user, isAuthenticated, isStaff, isAdmin, login, register, logout, updateUsername, devSetRole }),
[user, isAuthenticated, isStaff, isAdmin, login, register, logout, updateUsername, devSetRole]
);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
// ── Hook ───────────────────────────────────────────────────────────────────────
export function useAuth(): AuthContextValue {
const ctx = useContext(AuthContext);
if (!ctx) {
throw new Error('useAuth must be used inside <AuthProvider>');
}
return ctx;
}