Restauração do código oficial do GPI-JWT-V3

This commit is contained in:
2026-03-18 21:55:33 +00:00
commit 405d121b0e
208 changed files with 38123 additions and 0 deletions

View File

@@ -0,0 +1,127 @@
import React, { createContext, useContext, useState, useEffect, useCallback } from 'react';
import type { AppUser } from '../types';
import { setApiToken, setApiOrganizationId, getBaseUrl } from '../services/api';
const API_URL = getBaseUrl();
export interface AuthContextType {
appUser: AppUser | null;
isLoading: boolean;
isSignedIn: boolean;
error: string | null;
token: string | null;
login: (token: string, user: AppUser) => void;
logout: () => void;
isAdmin: () => boolean;
isUser: () => boolean;
isGuest: () => boolean;
isDeveloper: () => boolean;
canEdit: () => boolean;
refetchUser: () => Promise<void>;
}
export const AuthContext = createContext<AuthContextType | undefined>(undefined);
export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [appUser, setAppUser] = useState<AppUser | null>(null);
const [token, setToken] = useState<string | null>(localStorage.getItem('jwt_token'));
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
// Initial load: se tem token, setar no interceptor e buscar dados do usuário
useEffect(() => {
if (token) {
setApiToken(token);
refetchUser();
} else {
setIsLoading(false);
}
}, [token]);
const login = useCallback((newToken: string, user: AppUser) => {
localStorage.setItem('jwt_token', newToken);
setToken(newToken);
setAppUser(user);
setApiToken(newToken);
// Se a organização existir, setar o header
if (user.organizationId) {
setApiOrganizationId(user.organizationId);
}
}, []);
const logout = useCallback(() => {
localStorage.removeItem('jwt_token');
setToken(null);
setAppUser(null);
setApiToken(null);
setApiOrganizationId(null);
}, []);
const refetchUser = useCallback(async () => {
if (!token) return;
setIsLoading(true);
try {
const response = await fetch(`${API_URL}/auth/me`, {
headers: {
'Authorization': `Bearer ${token}`
},
});
if (response.ok) {
const userData = await response.json();
setAppUser(userData);
if (userData.organizationId) {
setApiOrganizationId(userData.organizationId);
}
} else {
// Token inválido ou expirado
logout();
}
} catch (err) {
console.error('Error refetching user:', err);
setError('Falha na comunicação de autenticação.');
} finally {
setIsLoading(false);
}
}, [token, logout]);
const isDeveloper = useCallback(() => {
return appUser?.email === 'admtracksteel@gmail.com';
}, [appUser]);
const isAdmin = useCallback(() => appUser?.role === 'admin' || isDeveloper(), [appUser, isDeveloper]);
const isUser = useCallback(() => appUser?.role === 'user' || isAdmin(), [appUser, isAdmin]);
const isGuest = useCallback(() => appUser?.role === 'guest' && !isDeveloper(), [appUser, isDeveloper]);
const canEdit = useCallback(() => (appUser?.role !== 'guest' && appUser !== null) || isDeveloper(), [appUser, isDeveloper]);
return (
<AuthContext.Provider
value={{
appUser,
isLoading,
isSignedIn: !!appUser,
error,
token,
login,
logout,
isAdmin,
isUser,
isGuest,
isDeveloper,
canEdit,
refetchUser,
}}
>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
};