Added admin page
This commit is contained in:
@@ -5,9 +5,23 @@ import apiClient from '../api/client';
|
||||
import { useTheme } from 'react-native-paper';
|
||||
import { getAccessToken, getRefreshToken, storeTokens, clearTokens } from '../api/client';
|
||||
|
||||
// Define UserRole enum matching the backend
|
||||
enum UserRole {
|
||||
USER = 'user',
|
||||
ADMIN = 'admin',
|
||||
}
|
||||
|
||||
interface UserData {
|
||||
username: string;
|
||||
name: string;
|
||||
role: UserRole;
|
||||
// Add other user fields if needed
|
||||
}
|
||||
|
||||
interface AuthContextData {
|
||||
isAuthenticated: boolean;
|
||||
isLoading: boolean;
|
||||
user: UserData | null; // Add user data to context
|
||||
login: (username: string, password: string) => Promise<void>;
|
||||
logout: () => Promise<void>;
|
||||
}
|
||||
@@ -15,6 +29,7 @@ interface AuthContextData {
|
||||
const AuthContext = createContext<AuthContextData>({
|
||||
isAuthenticated: false,
|
||||
isLoading: true,
|
||||
user: null, // Initialize user as null
|
||||
login: async () => { throw new Error('AuthContext not initialized'); },
|
||||
logout: async () => { throw new Error('AuthContext not initialized'); },
|
||||
});
|
||||
@@ -26,15 +41,45 @@ interface AuthProviderProps {
|
||||
export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
const [isAuthenticatedState, setIsAuthenticatedState] = useState<boolean>(false);
|
||||
const [userState, setUserState] = useState<UserData | null>(null); // State for user data
|
||||
|
||||
// Function to fetch user data
|
||||
const fetchUserData = useCallback(async () => {
|
||||
try {
|
||||
console.log("[AuthContext] fetchUserData: Fetching /user/me");
|
||||
const response = await apiClient.get<UserData>('/user/me');
|
||||
console.log("[AuthContext] fetchUserData: User data received:", response.data);
|
||||
setUserState(response.data);
|
||||
return response.data;
|
||||
} catch (error: any) {
|
||||
console.error("[AuthContext] fetchUserData: Error fetching user data:", error.response?.data || error.message);
|
||||
// If fetching user fails (e.g., token expired mid-session), log out
|
||||
await clearTokens();
|
||||
setIsAuthenticatedState(false);
|
||||
setUserState(null);
|
||||
return null;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const checkAuthStatus = useCallback(async () => {
|
||||
const token = await getAccessToken();
|
||||
const hasToken = !!token;
|
||||
if (hasToken !== isAuthenticatedState) {
|
||||
setIsAuthenticatedState(hasToken);
|
||||
if (hasToken) {
|
||||
console.log("[AuthContext] checkAuthStatus: Token found, fetching user data.");
|
||||
const userData = await fetchUserData();
|
||||
if (userData) {
|
||||
setIsAuthenticatedState(true);
|
||||
} else {
|
||||
// Fetch failed, already handled logout in fetchUserData
|
||||
setIsAuthenticatedState(false);
|
||||
}
|
||||
} else {
|
||||
console.log("[AuthContext] checkAuthStatus: No token found.");
|
||||
setIsAuthenticatedState(false);
|
||||
setUserState(null);
|
||||
}
|
||||
return hasToken;
|
||||
}, [isAuthenticatedState]);
|
||||
return isAuthenticatedState; // Return the updated state
|
||||
}, [fetchUserData, isAuthenticatedState]); // Added isAuthenticatedState dependency
|
||||
|
||||
const loadInitialAuth = useCallback(async () => {
|
||||
setIsLoading(true);
|
||||
@@ -43,9 +88,10 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
|
||||
await checkAuthStatus();
|
||||
console.log("[AuthContext] loadInitialAuth: Initial check complete.");
|
||||
} catch (error) {
|
||||
console.error("[AuthContext] loadInitialAuth: Error loading initial token:", error);
|
||||
console.error("[AuthContext] loadInitialAuth: Error during initial auth check:", error);
|
||||
await clearTokens();
|
||||
setIsAuthenticatedState(false);
|
||||
setUserState(null);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
@@ -58,7 +104,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
|
||||
const login = useCallback(async (username: string, password: string) => {
|
||||
console.log("[AuthContext] login: Function called with:", username);
|
||||
try {
|
||||
console.log("[AuthContext] login: Preparing to call apiClient.post for /auth/login");
|
||||
// ... (existing login API call) ...
|
||||
const response = await apiClient.post(
|
||||
'/auth/login',
|
||||
'grant_type=password&username=' + encodeURIComponent(username) + '&password=' + encodeURIComponent(password) + '&scope=&client_id=&client_secret=',
|
||||
@@ -70,10 +116,8 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
|
||||
}
|
||||
);
|
||||
|
||||
console.log("[AuthContext] login: apiClient.post successful, response status:", response?.status);
|
||||
const { access_token, refresh_token } = response.data;
|
||||
console.log("[AuthContext] login: Response data received.");
|
||||
|
||||
// ... (existing token validation) ...
|
||||
if (!access_token || typeof access_token !== 'string' || !refresh_token) {
|
||||
console.error("[AuthContext] login: Invalid token structure received:", response.data);
|
||||
throw new Error('Invalid token received from server.');
|
||||
@@ -81,29 +125,30 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
|
||||
|
||||
console.log('[AuthContext] login: Login successful, storing tokens.');
|
||||
await storeTokens(access_token, refresh_token);
|
||||
setIsAuthenticatedState(true);
|
||||
|
||||
// Fetch user data immediately after successful login
|
||||
const userData = await fetchUserData();
|
||||
if (userData) {
|
||||
setIsAuthenticatedState(true);
|
||||
} else {
|
||||
// Should not happen if login succeeded, but handle defensively
|
||||
throw new Error('Failed to fetch user data after login.');
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
// ... (existing error handling) ...
|
||||
console.error("[AuthContext] login: Caught Error Object:", error);
|
||||
if (error.isAxiosError) {
|
||||
console.error("[AuthContext] login: Axios Error Details:");
|
||||
console.error(" Request Config:", error.config);
|
||||
console.error(" Response:", error.response?.status, error.response?.data);
|
||||
console.error(" Message:", error.message);
|
||||
}
|
||||
await clearTokens();
|
||||
setIsAuthenticatedState(false);
|
||||
setUserState(null);
|
||||
throw error;
|
||||
}
|
||||
}, []);
|
||||
}, [fetchUserData]); // Added fetchUserData dependency
|
||||
|
||||
const logout = useCallback(async () => {
|
||||
console.log('[AuthContext] logout: Logging out.');
|
||||
const refreshToken = await getRefreshToken();
|
||||
if (!refreshToken) {
|
||||
console.warn('[AuthContext] logout: No refresh token found to send to backend.');
|
||||
}
|
||||
|
||||
// ... (existing backend logout call) ...
|
||||
try {
|
||||
if (refreshToken) {
|
||||
console.log('[AuthContext] logout: Calling backend /auth/logout');
|
||||
@@ -115,6 +160,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
|
||||
} finally {
|
||||
await clearTokens();
|
||||
setIsAuthenticatedState(false);
|
||||
setUserState(null); // Clear user data on logout
|
||||
console.log('[AuthContext] logout: Local tokens cleared and state updated.');
|
||||
}
|
||||
}, []);
|
||||
@@ -122,10 +168,12 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
|
||||
const contextValue = useMemo(() => ({
|
||||
isAuthenticated: isAuthenticatedState,
|
||||
isLoading,
|
||||
user: userState, // Provide user state
|
||||
login,
|
||||
logout,
|
||||
}), [isAuthenticatedState, isLoading, login, logout]);
|
||||
}), [isAuthenticatedState, isLoading, userState, login, logout]); // Added userState dependency
|
||||
|
||||
// ... (rest of the component: Provider, useAuth, AuthLoadingScreen) ...
|
||||
return (
|
||||
<AuthContext.Provider value={contextValue}>
|
||||
{children}
|
||||
@@ -147,4 +195,7 @@ export const AuthLoadingScreen: React.FC = () => {
|
||||
container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: theme.colors.background }
|
||||
});
|
||||
return (<View style={styles.container}><ActivityIndicator size="large" color={theme.colors.primary} /></View>);
|
||||
}
|
||||
}
|
||||
|
||||
// Export UserRole if needed elsewhere
|
||||
export { UserRole };
|
||||
Reference in New Issue
Block a user