add protected route
This commit is contained in:
parent
ee5a3b7b14
commit
a5f54f1794
|
|
@ -5,11 +5,13 @@ import { Spin } from "antd";
|
||||||
import { hasAbility } from "./utils/hasAbility";
|
import { hasAbility } from "./utils/hasAbility";
|
||||||
import { renderRoutesRecursively } from "./Components/Routes/RenderRoutesRecursively";
|
import { renderRoutesRecursively } from "./Components/Routes/RenderRoutesRecursively";
|
||||||
import { RenderRouteElement } from "./Components/Routes/RenderRouteElement";
|
import { RenderRouteElement } from "./Components/Routes/RenderRouteElement";
|
||||||
|
import { UserTypeEnum } from "./enums/UserType";
|
||||||
|
import { RoleByType } from "./utils/RoleByType";
|
||||||
|
|
||||||
const Page404 = lazy(() => import("./Layout/Ui/NotFoundPage"));
|
const Page404 = lazy(() => import("./Layout/Ui/NotFoundPage"));
|
||||||
const Auth = lazy(() => import("./Pages/Auth/Page"));
|
const Auth = lazy(() => import("./Pages/Auth/Page"));
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route
|
<Route
|
||||||
|
|
@ -31,10 +33,14 @@ const App = () => {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
{renderRoutesRecursively(menuItems)}
|
{renderRoutesRecursively(menuItems)}
|
||||||
|
|
||||||
{CrudRoute.map((route) => {
|
{CrudRoute.map((route) => {
|
||||||
const useAbility = hasAbility(route.abilities, route.abilities_value);
|
const useAbility = hasAbility(route.abilities, route.abilities_value);
|
||||||
|
if(!RoleByType(route)){
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
if (!useAbility) {
|
if (!useAbility) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,17 @@ import { TMenuItem } from "../../types/App";
|
||||||
import { hasAbility } from "../../utils/hasAbility";
|
import { hasAbility } from "../../utils/hasAbility";
|
||||||
import { Route } from "react-router-dom";
|
import { Route } from "react-router-dom";
|
||||||
import { RenderRouteElement } from "./RenderRouteElement";
|
import { RenderRouteElement } from "./RenderRouteElement";
|
||||||
|
import { UserTypeEnum } from "../../enums/UserType";
|
||||||
|
import Item from "antd/es/list/Item";
|
||||||
|
import { RoleByType } from "../../utils/RoleByType";
|
||||||
|
|
||||||
export const renderRoutesRecursively = (routes: TMenuItem[]) =>
|
export const renderRoutesRecursively = (routes: TMenuItem[]) =>
|
||||||
routes.map((route: TMenuItem) => {
|
routes.map((route: TMenuItem) => {
|
||||||
const useAbility = hasAbility(route.abilities, route.abilities_value);
|
const useAbility = hasAbility(route.abilities, route.abilities_value);
|
||||||
|
if(!RoleByType(route)){
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
|
||||||
if (!useAbility) {
|
if (!useAbility) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import { useTranslation } from "react-i18next";
|
||||||
import { getLocalStorage } from "../../utils/LocalStorage";
|
import { getLocalStorage } from "../../utils/LocalStorage";
|
||||||
import { BRANCH_OBJECT_KEY } from "../../config/AppKey";
|
import { BRANCH_OBJECT_KEY } from "../../config/AppKey";
|
||||||
import { MenuItem } from "../../Components/Layout/SideBar/MenuItem";
|
import { MenuItem } from "../../Components/Layout/SideBar/MenuItem";
|
||||||
|
import { UserTypeEnum } from "../../enums/UserType";
|
||||||
|
import { RoleByType } from "../../utils/RoleByType";
|
||||||
|
|
||||||
const SideBar = () => {
|
const SideBar = () => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
@ -17,7 +19,6 @@ const SideBar = () => {
|
||||||
const { logout } = useAuthState();
|
const { logout } = useAuthState();
|
||||||
const [t] = useTranslation();
|
const [t] = useTranslation();
|
||||||
const branch_name = getLocalStorage(BRANCH_OBJECT_KEY)?.name;
|
const branch_name = getLocalStorage(BRANCH_OBJECT_KEY)?.name;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="side_bar">
|
<div className="side_bar">
|
||||||
<h1>
|
<h1>
|
||||||
|
|
@ -31,6 +32,11 @@ const SideBar = () => {
|
||||||
if (!useAbility) {
|
if (!useAbility) {
|
||||||
return <React.Fragment key={index}></React.Fragment>;
|
return <React.Fragment key={index}></React.Fragment>;
|
||||||
}
|
}
|
||||||
|
if(!RoleByType(item)){
|
||||||
|
|
||||||
|
return <React.Fragment key={index}></React.Fragment> ;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={index}
|
key={index}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Formik } from "formik";
|
import { Formik } from "formik";
|
||||||
import useAuthState from "../../zustand/AuthState";
|
import useAuthState from "../../zustand/AuthState";
|
||||||
import useNavigateOnSuccess from "../../Hooks/useNavigateOnSuccess";
|
import useNavigateOnSuccess from "../../Hooks/useNavigateOnSuccess";
|
||||||
|
|
@ -8,6 +8,9 @@ import { initialValues } from "./formutils";
|
||||||
import { FormValues } from "../../types/Auth";
|
import { FormValues } from "../../types/Auth";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { getLocalStorage } from "../../utils/LocalStorage";
|
||||||
|
import { USER_KEY } from "../../config/AppKey";
|
||||||
|
|
||||||
const LoginForm = () => {
|
const LoginForm = () => {
|
||||||
const { mutate, isLoading, isSuccess, data } = useLoginAdmin();
|
const { mutate, isLoading, isSuccess, data } = useLoginAdmin();
|
||||||
|
|
@ -16,11 +19,27 @@ const LoginForm = () => {
|
||||||
mutate(values);
|
mutate(values);
|
||||||
};
|
};
|
||||||
|
|
||||||
const { login } = useAuthState();
|
const { login,isAuthenticated} = useAuthState();
|
||||||
const LoginData = {
|
const LoginData = {
|
||||||
...data,
|
...data,
|
||||||
|
|
||||||
} as any;
|
} as any;
|
||||||
useNavigateOnSuccess(isSuccess, "/", () => login(LoginData?.data as any));
|
const navigate = useNavigate()
|
||||||
|
const LocalType = getLocalStorage(USER_KEY)?.type ?? false ;
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
if(isSuccess){
|
||||||
|
login(LoginData?.data as any)
|
||||||
|
|
||||||
|
}
|
||||||
|
}, [isSuccess])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(LocalType ){
|
||||||
|
window.location.href = ("/")
|
||||||
|
}
|
||||||
|
}, [LocalType])
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="LoginForm">
|
<div className="LoginForm">
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,10 @@ const Form = ({ isEdit = false }: { isEdit?: boolean }) => {
|
||||||
const canChangeGradePage = !!Grade?.links?.next;
|
const canChangeGradePage = !!Grade?.links?.next;
|
||||||
const GradePage = Grade?.meta?.currentPage;
|
const GradePage = Grade?.meta?.currentPage;
|
||||||
|
|
||||||
|
const sex = [
|
||||||
|
{name:"male" , id :"male"},
|
||||||
|
{name:"female" , id :"female"}
|
||||||
|
]
|
||||||
return (
|
return (
|
||||||
<Row className="w-100">
|
<Row className="w-100">
|
||||||
<Col>
|
<Col>
|
||||||
|
|
@ -45,6 +48,7 @@ const Form = ({ isEdit = false }: { isEdit?: boolean }) => {
|
||||||
page={GradePage}
|
page={GradePage}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
|
<ValidationField type="Select" name="sex" option={sex} />
|
||||||
|
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,23 @@ export const getInitialValues = (
|
||||||
objectToEdit: Partial<Student>,
|
objectToEdit: Partial<Student>,
|
||||||
): StudentInitialValues => {
|
): StudentInitialValues => {
|
||||||
return {
|
return {
|
||||||
id: objectToEdit?.id,
|
id: objectToEdit?.user_id,
|
||||||
first_name: objectToEdit?.first_name ?? "",
|
first_name: objectToEdit?.first_name ?? "",
|
||||||
last_name: objectToEdit?.last_name ?? "",
|
last_name: objectToEdit?.last_name ?? "",
|
||||||
username: objectToEdit?.user?.username ?? null ,
|
// address: objectToEdit?.address ?? "",
|
||||||
password: null ,
|
// birthday: objectToEdit?.birthday ?? "",
|
||||||
|
// city: objectToEdit?.city ?? "",
|
||||||
|
grade_id: objectToEdit?.grade_id ,
|
||||||
|
// image: objectToEdit?.image ?? "",
|
||||||
|
sex: objectToEdit?.sex ,
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getValidationSchema = () => {
|
export const getValidationSchema = () => {
|
||||||
// validate input
|
// validate input
|
||||||
return Yup.object().shape({
|
return Yup.object().shape({
|
||||||
name: Yup.string().required("validation.required"),
|
first_name: Yup.string().required("validation.required"),
|
||||||
|
last_name: Yup.string().required("validation.required"),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ import {
|
||||||
canShowStudent,
|
canShowStudent,
|
||||||
} from "../../utils/hasAbilityFn";
|
} from "../../utils/hasAbilityFn";
|
||||||
import ActionButtons from "../../Components/Table/ActionButtons";
|
import ActionButtons from "../../Components/Table/ActionButtons";
|
||||||
import ColumnsImage from "../../Components/Columns/ColumnsImage";
|
|
||||||
|
|
||||||
export const useColumns = () => {
|
export const useColumns = () => {
|
||||||
const { handel_open_model } = useModalHandler();
|
const { handel_open_model } = useModalHandler();
|
||||||
|
|
@ -22,7 +21,7 @@ export const useColumns = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const handelShow = (record: Student) => {
|
const handelShow = (record: Student) => {
|
||||||
navigate(`${record?.id}`);
|
navigate(`${record?.user_id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handelDelete = (data: Student) => {
|
const handelDelete = (data: Student) => {
|
||||||
|
|
@ -42,15 +41,31 @@ export const useColumns = () => {
|
||||||
dataIndex: "id",
|
dataIndex: "id",
|
||||||
key: "id",
|
key: "id",
|
||||||
align: "center",
|
align: "center",
|
||||||
render: (_text, record) => record?.id,
|
render: (_text, record) => record?.user_id,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: `${t("columns.name")}`,
|
title: `${t("columns.first_name")}`,
|
||||||
dataIndex: "name",
|
dataIndex: "first_name",
|
||||||
key: "name",
|
key: "first_name",
|
||||||
align: "center",
|
align: "center",
|
||||||
render: (_text, record) => record?.first_name,
|
render: (_text, record) => record?.first_name,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: `${t("columns.last_name")}`,
|
||||||
|
dataIndex: "last_name",
|
||||||
|
key: "last_name",
|
||||||
|
align: "center",
|
||||||
|
render: (_text, record) => record?.last_name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: `${t("columns.sex")}`,
|
||||||
|
dataIndex: "sex",
|
||||||
|
key: "sex",
|
||||||
|
align: "center",
|
||||||
|
render: (_text, record) => record?.sex,
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
title: canAddStudent ? (
|
title: canAddStudent ? (
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import { hasAbility } from "./utils/hasAbility";
|
||||||
import { ABILITIES_ENUM, ABILITIES_VALUES_ENUM } from "./enums/abilities";
|
import { ABILITIES_ENUM, ABILITIES_VALUES_ENUM } from "./enums/abilities";
|
||||||
import { ParamsEnum } from "./enums/params";
|
import { ParamsEnum } from "./enums/params";
|
||||||
import { BsPeople } from "react-icons/bs";
|
import { BsPeople } from "react-icons/bs";
|
||||||
|
import { UserTypeEnum } from "./enums/UserType";
|
||||||
|
|
||||||
export const menuItems: TMenuItem[] = [
|
export const menuItems: TMenuItem[] = [
|
||||||
{
|
{
|
||||||
|
|
@ -42,6 +43,7 @@ export const menuItems: TMenuItem[] = [
|
||||||
abilities: ABILITIES_ENUM?.PASS,
|
abilities: ABILITIES_ENUM?.PASS,
|
||||||
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||||
prevPath: 0,
|
prevPath: 0,
|
||||||
|
type:UserTypeEnum?.PASS
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -105,16 +107,17 @@ export const menuItems: TMenuItem[] = [
|
||||||
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||||
prevPath: 0,
|
prevPath: 0,
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// header: "page_header.studentPackage",
|
header: "page_header.studentPackage",
|
||||||
// element: <StudentPackage />,
|
element: <StudentPackage />,
|
||||||
// icon: <BsPeople />,
|
icon: <BsPeople />,
|
||||||
// text: "sidebar.studentPackage",
|
text: "sidebar.studentPackage",
|
||||||
// path: `/${ABILITIES_ENUM?.STUDENT_PACKAGE}`,
|
path: `/${ABILITIES_ENUM?.STUDENT_PACKAGE}`,
|
||||||
// abilities: ABILITIES_ENUM?.STUDENT_PACKAGE,
|
abilities: ABILITIES_ENUM?.STUDENT_PACKAGE,
|
||||||
// abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||||
// prevPath: 0,
|
prevPath: 0,
|
||||||
// },
|
type:UserTypeEnum.RE_SELLER
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const CrudRoute: TCrudRoute[] = [
|
export const CrudRoute: TCrudRoute[] = [
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
export enum UserTypeEnum {
|
export enum UserTypeEnum {
|
||||||
ADMIN = "ADMIN",
|
ADMIN = "admin",
|
||||||
RE_SELLER = "RE_SELLER",
|
RE_SELLER = "reseller",
|
||||||
|
PASS="pass"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,7 +40,7 @@ export type TCrudRoute = {
|
||||||
element: ReactElement | LazyExoticComponent<any>;
|
element: ReactElement | LazyExoticComponent<any>;
|
||||||
abilities: ABILITIES_ENUM;
|
abilities: ABILITIES_ENUM;
|
||||||
abilities_value: ABILITIES_VALUES_ENUM;
|
abilities_value: ABILITIES_VALUES_ENUM;
|
||||||
type?:ABILITIES_ENUM
|
type?:UserTypeEnum
|
||||||
prevPath: number;
|
prevPath: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,34 @@
|
||||||
import { Nullable } from "./App";
|
import { DateType, Nullable } from "./App";
|
||||||
|
|
||||||
// Define the Teacher interface
|
// Define the Teacher interface
|
||||||
|
|
||||||
|
|
||||||
interface StudentUser {
|
|
||||||
id: number;
|
|
||||||
username: string;
|
|
||||||
phone_number: string | null;
|
|
||||||
type: 'Student' | 'other'; // Specify other types if needed
|
|
||||||
}
|
|
||||||
|
|
||||||
interface StudentLocation {
|
|
||||||
lat: string;
|
|
||||||
lng: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ContactInfo {
|
|
||||||
contact_number1: string;
|
|
||||||
contact_number2: string;
|
|
||||||
card_number: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface Student {
|
export interface Student {
|
||||||
id: number;
|
first_name: string; // The first name of the user
|
||||||
user: StudentUser;
|
last_name: string; // The last name of the user
|
||||||
first_name: string;
|
city: string | null; // The city of the user, can be null
|
||||||
last_name: string;
|
sex: string; // The sex of the user, using a union type for possible values
|
||||||
location: StudentLocation;
|
image: string | null; // The URL of the user's image, can be null
|
||||||
contact_info: ContactInfo;
|
address: string | null; // The address of the user, can be null
|
||||||
contact_number1 : string | number
|
card: string | null; // The card information, can be null
|
||||||
contact_number2 : string | number
|
birthday: DateType; // The birthday of the user, can be null
|
||||||
|
grade_id: number | string; // The ID of the user's grade
|
||||||
|
user_id: number; // The unique ID of the user
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InitialValues {
|
export interface InitialValues {
|
||||||
id: number;
|
id: number;
|
||||||
user: StudentUser;
|
first_name: string; // The first name of the user
|
||||||
first_name: string;
|
last_name: string; // The last name of the user
|
||||||
last_name: string;
|
city: string | null; // The city of the user, can be null
|
||||||
location: StudentLocation;
|
sex: string; // The sex of the user, using a union type for possible values
|
||||||
lat: string | Number;
|
image: string | null; // The URL of the user's image, can be null
|
||||||
lng: string | Number;
|
address: string | null; // The address of the user, can be null
|
||||||
contact_info: ContactInfo;
|
card: string | null; // The card information, can be null
|
||||||
contact_number1 : string | number
|
birthday: DateType; // The birthday of the user, can be null
|
||||||
contact_number2 : string | number
|
grade_id: number | string; // The ID of the user's grade
|
||||||
username : string;
|
user_id: number; // The unique ID of the user
|
||||||
password:any
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type StudentInitialValues = Partial<Nullable<InitialValues>>;
|
export type StudentInitialValues = Partial<Nullable<InitialValues>>;
|
||||||
|
|
|
||||||
28
src/utils/RoleByType.ts
Normal file
28
src/utils/RoleByType.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { USER_KEY } from "../config/AppKey";
|
||||||
|
import { UserTypeEnum } from "../enums/UserType";
|
||||||
|
import { getLocalStorage } from "./LocalStorage";
|
||||||
|
|
||||||
|
export const RoleByType = (item: { type?: string }):boolean=>{
|
||||||
|
const type = item?.type ?? UserTypeEnum.ADMIN;
|
||||||
|
const LocalType = getLocalStorage(USER_KEY)?.type ?? undefined ;
|
||||||
|
const isAdmin = LocalType === UserTypeEnum.ADMIN ;
|
||||||
|
const isReSeller = LocalType === UserTypeEnum.RE_SELLER;
|
||||||
|
const isAdminRoute = type === UserTypeEnum.ADMIN ;
|
||||||
|
const isReSellerRoute = type === UserTypeEnum.RE_SELLER;
|
||||||
|
console.log(LocalType);
|
||||||
|
|
||||||
|
if(!LocalType){
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if(type === UserTypeEnum.PASS) { return true } ;
|
||||||
|
|
||||||
|
if(isAdmin && isReSellerRoute ){
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isReSeller && !isReSellerRoute ){
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { ABILITIES_KEY, TOKEN_KEY, USER_KEY } from "../config/AppKey";
|
import { ABILITIES_KEY, TOKEN_KEY, USER_KEY } from "../config/AppKey";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { RoleByType } from "../utils/RoleByType";
|
||||||
|
import { getLocalStorage } from "../utils/LocalStorage";
|
||||||
interface AuthStore {
|
interface AuthStore {
|
||||||
token: string | null | undefined;
|
token: string | null | undefined;
|
||||||
abilities: any;
|
abilities: any;
|
||||||
isAuthenticated: boolean;
|
isAuthenticated: boolean;
|
||||||
|
|
||||||
login: (Data: any) => Promise<void>;
|
login: (Data: any) => Promise<void>;
|
||||||
logout: () => Promise<void>;
|
logout: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
@ -14,9 +13,11 @@ interface AuthStore {
|
||||||
const useAuthState = create<AuthStore>((set) => {
|
const useAuthState = create<AuthStore>((set) => {
|
||||||
const storedToken = localStorage.getItem(TOKEN_KEY);
|
const storedToken = localStorage.getItem(TOKEN_KEY);
|
||||||
const storedAbilities = localStorage.getItem(ABILITIES_KEY);
|
const storedAbilities = localStorage.getItem(ABILITIES_KEY);
|
||||||
|
const storedType = getLocalStorage(USER_KEY) ;
|
||||||
|
console.log(RoleByType(storedType));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isAuthenticated: true,
|
isAuthenticated: !!storedToken,
|
||||||
token: storedToken,
|
token: storedToken,
|
||||||
abilities: storedAbilities,
|
abilities: storedAbilities,
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user