admin/src/contexts/AuthContext.tsx

160 lines
5.5 KiB
TypeScript

import React, { createContext, useContext, useReducer, useEffect } from 'react';
import { AuthState, AdminUser, Permission, LoginRequest } from '../types/auth';
import toast from 'react-hot-toast';
interface AuthContextType {
isAuthenticated: boolean;
isLoading: boolean;
user: AdminUser | null;
permissions: Permission[];
allPermissions: Permission[];
token: string | null;
refreshToken: string | null;
logout: () => void;
restoreSession: () => void;
hasPermission: (permissionId: number) => boolean;
hasPermissionByTitle: (title: string) => boolean;
}
const AuthContext = createContext<AuthContextType | undefined>(undefined);
type AuthAction =
| { type: 'LOGIN'; payload: { user: AdminUser; permissions: Permission[]; allPermissions: Permission[]; token: string; refreshToken: string } }
| { type: 'LOGOUT' }
| { type: 'RESTORE_SESSION'; payload: { user: AdminUser; permissions: Permission[]; allPermissions: Permission[]; token: string; refreshToken: string } }
| { type: 'SET_LOADING'; payload: boolean };
const authReducer = (state: AuthState, action: AuthAction): AuthState => {
switch (action.type) {
case 'LOGIN':
case 'RESTORE_SESSION':
return {
...state,
isAuthenticated: true,
isLoading: false,
user: action.payload.user,
permissions: action.payload.permissions,
allPermissions: action.payload.allPermissions,
token: action.payload.token,
refreshToken: action.payload.refreshToken,
};
case 'LOGOUT':
return {
...state,
isAuthenticated: false,
isLoading: false,
user: null,
permissions: [],
allPermissions: [],
token: null,
refreshToken: null,
};
case 'SET_LOADING':
return {
...state,
isLoading: action.payload,
};
default:
return state;
}
};
const initialState: AuthState = {
isAuthenticated: false,
isLoading: true,
user: null,
permissions: [],
allPermissions: [],
token: null,
refreshToken: null,
};
export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
const [state, dispatch] = useReducer(authReducer, initialState);
const restoreSession = () => {
dispatch({ type: 'SET_LOADING', payload: true });
const token = localStorage.getItem('admin_token');
const refreshToken = localStorage.getItem('admin_refresh_token');
const userStr = localStorage.getItem('admin_user');
const permissionsStr = localStorage.getItem('admin_permissions');
if (token && userStr && permissionsStr) {
try {
const user = JSON.parse(userStr);
const permissions = JSON.parse(permissionsStr);
dispatch({
type: 'RESTORE_SESSION',
payload: {
user,
permissions,
allPermissions: permissions,
token,
refreshToken: refreshToken || ''
}
});
} catch (error) {
localStorage.removeItem('admin_token');
localStorage.removeItem('admin_refresh_token');
localStorage.removeItem('admin_user');
localStorage.removeItem('admin_permissions');
dispatch({ type: 'SET_LOADING', payload: false });
}
} else {
dispatch({ type: 'SET_LOADING', payload: false });
}
};
useEffect(() => {
restoreSession();
}, []);
const logout = () => {
localStorage.removeItem('admin_token');
localStorage.removeItem('admin_refresh_token');
localStorage.removeItem('admin_user');
localStorage.removeItem('admin_permissions');
dispatch({ type: 'LOGOUT' });
toast.success('خروج موفقیت‌آمیز بود');
};
const hasPermission = (permissionId: number): boolean => {
// اگر Super Admin (id=1) باشد، به همه چیز دسترسی دارد
const isSuperAdmin = state.permissions.some(permission => permission.id === 1);
if (isSuperAdmin) return true;
// در غیر اینصورت چک کن permission مورد نیاز را دارد یا نه
return state.permissions.some(permission => permission.id === permissionId);
};
const hasPermissionByTitle = (title: string): boolean => {
// اگر Super Admin (AdminAll) باشد، به همه چیز دسترسی دارد
const isSuperAdmin = state.permissions.some(permission => permission.title === "AdminAll");
if (isSuperAdmin) return true;
// در غیر اینصورت چک کن permission مورد نیاز را دارد یا نه
return state.permissions.some(permission => permission.title === title);
};
return (
<AuthContext.Provider value={{
...state,
logout,
restoreSession,
hasPermission,
hasPermissionByTitle,
}}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
};