first commit

This commit is contained in:
Michaël
2026-01-29 14:13:11 -03:00
commit 2302748c87
105 changed files with 93301 additions and 0 deletions

View File

@@ -0,0 +1,173 @@
'use client';
import React, { createContext, useContext, useState, useEffect, ReactNode, useCallback } from 'react';
interface User {
id: string;
email: string;
name: string;
role: string;
phone?: string;
languagePreference?: string;
isClaimed?: boolean;
rucNumber?: string;
accountStatus?: string;
}
interface AuthContextType {
user: User | null;
token: string | null;
isLoading: boolean;
isAdmin: boolean;
login: (email: string, password: string) => Promise<void>;
loginWithGoogle: (credential: string) => Promise<void>;
loginWithMagicLink: (token: string) => Promise<void>;
register: (data: RegisterData) => Promise<void>;
logout: () => void;
updateUser: (user: User) => void;
setAuthData: (data: { user: User; token: string }) => void;
}
interface RegisterData {
email: string;
password: string;
name: string;
phone?: string;
languagePreference?: string;
}
const AuthContext = createContext<AuthContextType | undefined>(undefined);
const TOKEN_KEY = 'spanglish-token';
const USER_KEY = 'spanglish-user';
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [token, setToken] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
// Load auth state from localStorage
const savedToken = localStorage.getItem(TOKEN_KEY);
const savedUser = localStorage.getItem(USER_KEY);
if (savedToken && savedUser) {
setToken(savedToken);
setUser(JSON.parse(savedUser));
}
setIsLoading(false);
}, []);
const setAuthData = useCallback((data: { user: User; token: string }) => {
setToken(data.token);
setUser(data.user);
localStorage.setItem(TOKEN_KEY, data.token);
localStorage.setItem(USER_KEY, JSON.stringify(data.user));
}, []);
const login = async (email: string, password: string) => {
const res = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
});
if (!res.ok) {
const error = await res.json();
throw new Error(error.error || 'Login failed');
}
const data = await res.json();
setAuthData(data);
};
const loginWithGoogle = async (credential: string) => {
const res = await fetch('/api/auth/google', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ credential }),
});
if (!res.ok) {
const error = await res.json();
throw new Error(error.error || 'Google login failed');
}
const data = await res.json();
setAuthData(data);
};
const loginWithMagicLink = async (magicToken: string) => {
const res = await fetch('/api/auth/magic-link/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: magicToken }),
});
if (!res.ok) {
const error = await res.json();
throw new Error(error.error || 'Magic link login failed');
}
const data = await res.json();
setAuthData(data);
};
const register = async (registerData: RegisterData) => {
const res = await fetch('/api/auth/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(registerData),
});
if (!res.ok) {
const error = await res.json();
throw new Error(error.error || 'Registration failed');
}
const data = await res.json();
setAuthData(data);
};
const logout = useCallback(() => {
setToken(null);
setUser(null);
localStorage.removeItem(TOKEN_KEY);
localStorage.removeItem(USER_KEY);
}, []);
const updateUser = useCallback((updatedUser: User) => {
setUser(updatedUser);
localStorage.setItem(USER_KEY, JSON.stringify(updatedUser));
}, []);
const isAdmin = user?.role === 'admin' || user?.role === 'organizer';
return (
<AuthContext.Provider
value={{
user,
token,
isLoading,
isAdmin,
login,
loginWithGoogle,
loginWithMagicLink,
register,
logout,
updateUser,
setAuthData,
}}
>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
}