Changeset b248810 for jobvista-frontend


Ignore:
Timestamp:
06/10/24 22:34:32 (3 weeks ago)
Author:
223021 <daniel.ilievski.2@…>
Branches:
main
Children:
befb988
Parents:
28b3398
Message:

Added no access page for new recruiters and admin panel for granting access

Location:
jobvista-frontend
Files:
7 added
12 edited

Legend:

Unmodified
Added
Removed
  • jobvista-frontend/package-lock.json

    r28b3398 rb248810  
    1919        "axios": "^1.6.8",
    2020        "formik": "^2.4.6",
     21        "jwt-decode": "^4.0.0",
    2122        "primereact": "^10.6.6",
    2223        "quill": "^2.0.2",
     
    1296312964      }
    1296412965    },
     12966    "node_modules/jwt-decode": {
     12967      "version": "4.0.0",
     12968      "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
     12969      "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==",
     12970      "engines": {
     12971        "node": ">=18"
     12972      }
     12973    },
    1296512974    "node_modules/keyv": {
    1296612975      "version": "4.5.4",
  • jobvista-frontend/package.json

    r28b3398 rb248810  
    1414    "axios": "^1.6.8",
    1515    "formik": "^2.4.6",
     16    "jwt-decode": "^4.0.0",
    1617    "primereact": "^10.6.6",
    1718    "quill": "^2.0.2",
  • jobvista-frontend/src/App.js

    r28b3398 rb248810  
    11import logo from './logo.svg';
    22import './App.css';
    3 import {useDispatch} from "react-redux";
     3import {useDispatch, useSelector} from "react-redux";
    44import {BrowserRouter} from "react-router-dom";
    55import {Header} from "./views/static/Header";
    66import {RoutesConfig} from "./auth/RoutesConfig";
    7 import {useEffect} from "react";
     7import {useEffect, useState} from "react";
    88import {AuthActions} from "./redux/actions/authActions";
    99import {AUTH_TOKEN} from "./axios/axiosInstance";
     10import {jwtDecode} from "jwt-decode";
     11import {NoAccess} from "./views/static/NoAccess";
    1012
    1113function App() {
     
    1618    }, [dispatch])
    1719
     20    const [user, setUser] = useState(null);
     21    const [loading, setLoading] = useState(true);
     22    const auth = useSelector(state => state.auth);
     23
     24    useEffect(() => {
     25        const token = localStorage.getItem(AUTH_TOKEN);
     26        if (token !== null) {
     27            try {
     28                const decodedToken = jwtDecode(token);
     29                setUser({
     30                    name: decodedToken.name,
     31                    role: decodedToken.role,
     32                    hasAccess: auth.currentUser.access,
     33                });
     34                setLoading(false);
     35            } catch (error) {
     36                console.error('Failed to decode token', error);
     37                setLoading(false);
     38            }
     39        } else {
     40            setLoading(false);
     41        }
     42    }, [auth]);
     43
     44    if (loading) {
     45        return <NoAccess />; // Replace LoadingSpinner with your loading indicator component
     46    }
     47
    1848  return (
    1949      <div className="App">
    2050          <BrowserRouter>
    21               <Header/>
    22               <RoutesConfig/>
     51              {user === null ? (
     52                  <>
     53                      <Header />
     54                      <RoutesConfig />
     55                  </>
     56              ) : user.hasAccess ? (
     57                  <>
     58                      <Header />
     59                      <RoutesConfig />
     60                  </>
     61              ) : (
     62                  <NoAccess user={user}/>
     63              )}
     64
     65
    2366          </BrowserRouter>
    2467      </div>
  • jobvista-frontend/src/auth/RoutesConfig.js

    r28b3398 rb248810  
    99import {ApplicationsByJobAd} from "../views/applications/ApplicationsByJobAd";
    1010import {ApplicationsByJobSeeker} from "../views/applications/ApplicationsByJobSeeker";
     11import {useEffect, useState} from "react";
     12import {AUTH_TOKEN} from "../axios/axiosInstance";
     13import {jwtDecode} from "jwt-decode";
     14import {useSelector} from "react-redux";
     15import {AdminPanel} from "../views/admin_panel/AdminPanel";
    1116export const RoutesConfig = () => {
    1217
     
    2126                <Route path="/job-advertisements/:id" element={<JobAdDetails/>}></Route>
    2227                <Route path="/my-job-advertisements/:advertisement_id/applications" element={<ApplicationsByJobAd/>}></Route>
     28                <Route path="/admin-panel" element={<AdminPanel/>}></Route>
    2329            </Routes>
    2430    )
  • jobvista-frontend/src/redux/actionTypes.js

    r28b3398 rb248810  
    1818export const DOWNLOAD_RESUME = "DOWNLOAD_RESUME"
    1919
     20export const FETCH_RECRUITERS = "FETCH_RECRUITERS"
     21export const CHANGE_ACCESS = "CHANGE_ACCESS"
    2022
     23
  • jobvista-frontend/src/redux/actions/authActions.js

    r28b3398 rb248810  
    4848                    email: response.email,
    4949                    name: response.name,
    50                     role: response.role
     50                    role: response.role,
     51                    access: response.hasAccess,
    5152                };
    5253                dispatch({
  • jobvista-frontend/src/redux/reducers/jobAdvertisementReducer.js

    r28b3398 rb248810  
    55    FETCH_JOB_ADVERTISEMENTS_BY_RECRUITER, FILTER_JOB_ADVERTISEMENTS, FILTER_JOB_ADVERTISEMENTS_BY_RECRUITER
    66} from "../actionTypes";
    7 import {sortElementsByDateCreated} from "../../utils/utils";
     7import {sortElementsBy} from "../../utils/utils";
    88import {useSelector} from "react-redux";
    99
     
    2222            return {
    2323                ...state,
    24                 jobAdvertisements: sortElementsByDateCreated([...state.jobAdvertisements, action.jobAdvertisement]),
    25                 jobAdvertisementsByRecruiter: sortElementsByDateCreated([...state.jobAdvertisementsByRecruiter, action.jobAdvertisement])
     24                jobAdvertisements: sortElementsBy([...state.jobAdvertisements, action.jobAdvertisement]),
     25                jobAdvertisementsByRecruiter: sortElementsBy([...state.jobAdvertisementsByRecruiter, action.jobAdvertisement], "postedOn")
    2626            }
    2727        case EDIT_JOB_ADVERTISEMENT:
     
    3030
    3131            return {
    32                 jobAdvertisements: sortElementsByDateCreated([...jobAdvertisements, action.jobAdvertisement]),
    33                 jobAdvertisementsByRecruiter: sortElementsByDateCreated([...jobAdvertisementsByRecruiter, action.jobAdvertisement])
     32                jobAdvertisements: sortElementsBy([...jobAdvertisements, action.jobAdvertisement], "postedOn"),
     33                jobAdvertisementsByRecruiter: sortElementsBy([...jobAdvertisementsByRecruiter, action.jobAdvertisement], "postedOn")
    3434            }
    3535        case DELETE_JOB_ADVERTISEMENT:
     
    3838
    3939            return {
    40                 jobAdvertisements: sortElementsByDateCreated([...jobAdvertisements]),
    41                 jobAdvertisementsByRecruiter: sortElementsByDateCreated([...jobAdvertisementsByRecruiter])
     40                jobAdvertisements: sortElementsBy([...jobAdvertisements], "postedOn"),
     41                jobAdvertisementsByRecruiter: sortElementsBy([...jobAdvertisementsByRecruiter], "postedOn")
    4242            }
    4343
     
    4545            return {
    4646                ...state,
    47                 jobAdvertisements: sortElementsByDateCreated(action.jobAdvertisements)
     47                jobAdvertisements: sortElementsBy(action.jobAdvertisements, "postedOn")
    4848            }
    4949
     
    5252            return {
    5353                ...state,
    54                 jobAdvertisementsByRecruiter: sortElementsByDateCreated(action.jobAdvertisementsByRecruiter)
     54                jobAdvertisementsByRecruiter: sortElementsBy(action.jobAdvertisementsByRecruiter, "postedOn")
    5555            }
    5656
  • jobvista-frontend/src/redux/store.js

    r28b3398 rb248810  
    44import jobAdReducer from "./reducers/jobAdvertisementReducer";
    55import applicationReducer from "./reducers/applicationReducer"
     6import adminReducer from "./reducers/adminReducer"
     7import {AdminActions} from "./actions/adminActions";
    68
    79// const rootReducer = combineReducers({
     
    1820        auth: authReducer,
    1921        jobAd: jobAdReducer,
    20         appl: applicationReducer
     22        appl: applicationReducer,
     23        admin: adminReducer
    2124    },
    2225});
  • jobvista-frontend/src/utils/utils.js

    r28b3398 rb248810  
    11
    22
    3 export const sortElementsByDateCreated = (array) => {
     3export const sortElementsBy = (array, column) => {
    44    return array.slice().sort((a, b) => {
    5         return new Date(b.postedOn).getTime() - new Date(a.postedOn).getTime()
     5        return new Date(b[column]).getTime() - new Date(a[column]).getTime()
    66    });
    77}
     
    99export const sortElementsBySubmissionDate = (array) => {
    1010    return array.slice().sort((a, b) => {
    11         return new Date(b.postedOn).getTime() - new Date(a.postedOn).getTime()
     11        return new Date(b).getTime() - new Date(a.postedOn).getTime()
    1212    });
    1313}
  • jobvista-frontend/src/views/dashboard/Dashboard.js

    r28b3398 rb248810  
    44import {useEffect, useState} from "react";
    55import {JobAdvertisementActions} from "../../redux/actions/jobAdvertisementActions";
    6 import {formatRelativeTime, sortElementsByDateCreated} from "../../utils/utils";
     6import {formatRelativeTime, sortElementsBy} from "../../utils/utils";
    77import {dataRangeOptions, industryOptions, industryOptionsFilter, sortOptions} from "../selectOptions";
    88import Select from "react-select";
     
    1010import {Link} from "react-router-dom";
    1111import JobType from "../../enumerations/JobType";
     12import {AUTH_TOKEN} from "../../axios/axiosInstance";
     13import {jwtDecode} from "jwt-decode";
    1214
    13 export const Dashboard = () => {
     15export const Dashboard = (props) => {
    1416
    1517    const dispatch = useDispatch();
     
    1719    const [jobAdvertisements, setJobAdvertisements] = useState([]);
    1820    let jobAdvertisementsState = useSelector(state => state.jobAd.jobAdvertisements)
    19     const auth = useSelector(state => state.auth.currentUser);
     21    const auth = useSelector(state => state.auth);
    2022
    21     const [role, setRole] = useState("");
     23    // const [role, setRole] = useState("");
    2224    const [selectedSortOrder, setSelectedSortOrder] = useState("date_newest");
    2325    const [selectedIndustry, setSelectedIndustry] = useState("all");
     
    2527    const [dispatched, setDispatched] = useState(false)
    2628
    27     useEffect(() => {
    28         if (auth) {
    29             setRole(auth.role);
    30         }
    31     }, [auth]);
     29    // const [user, setUser] = useState(null);
     30    //
     31    // useEffect(() => {
     32    //     const token = localStorage.getItem(AUTH_TOKEN);
     33    //     if (token!=null) {
     34    //         try {
     35    //             const decodedToken = jwtDecode(token);
     36    //             setUser({
     37    //                 name: decodedToken.name,
     38    //                 role: decodedToken.role,
     39    //                 hasAccess: decodedToken.access,
     40    //             });
     41    //         } catch (error) {
     42    //             console.error('Failed to decode token', error);
     43    //         }
     44    //     }
     45    //     console.log(user)
     46    // }, [auth]);
     47
     48    // useEffect(() => {
     49    //     if (auth) {
     50    //         setRole(auth.role);
     51    //     }
     52    //     console.log(props)
     53    // }, [auth]);
    3254
    3355    useEffect(() => {
     
    3557            dispatch(JobAdvertisementActions.fetchJobAdvertisements((success, response) => {
    3658                if (success && response.data.length > 0) {
    37                     setJobAdvertisements(sortElementsByDateCreated(response.data))
     59                    setJobAdvertisements(sortElementsBy(response.data))
    3860                }
    3961                setDispatched(true)
     
    6284
    6385    return (
     86
    6487        <div className="container">
    6588            <div className="head-dashboard-box">
  • jobvista-frontend/src/views/job_advertisements/JobAdvertisements.js

    r28b3398 rb248810  
    55import {useEffect, useState} from "react";
    66import {JobAdvertisementActions} from "../../redux/actions/jobAdvertisementActions";
    7 import {formatRelativeTime, sortElementsByDateCreated} from "../../utils/utils";
     7import {formatRelativeTime, sortElementsBy} from "../../utils/utils";
    88import {dataRangeOptions, industryOptions, industryOptionsFilter, sortOptions} from "../selectOptions";
    99import Select from "react-select";
     
    3737            dispatch(JobAdvertisementActions.fetchJobAdvertisementsByRecruiter((success, response) => {
    3838                if (success && response.data.length > 0) {
    39                     setJobAdvertisementsByRecruiter(sortElementsByDateCreated(response.data))
     39                    setJobAdvertisementsByRecruiter(sortElementsBy(response.data))
    4040                }
    4141                console.log("Fetch job advertisements by recruiter GET")
  • jobvista-frontend/src/views/static/Header.js

    r28b3398 rb248810  
    11import {Link, NavLink} from "react-router-dom";
    22import "./Header.css"
     3import { jwtDecode } from "jwt-decode";
    34import {useDispatch, useSelector} from 'react-redux';
    45import {useEffect, useState} from "react";
     
    67import Roles from "../../enumerations/Roles";
    78import {useNavigate} from "react-router";
     9import {AUTH_TOKEN} from "../../axios/axiosInstance";
    810
    911export const Header = (props) => {
     
    1618    const [username, setUsername] = useState("");
    1719
     20    const [user, setUser] = useState("");
     21
    1822    const signOut = () => {
    1923        dispatch(AuthActions.signOut());
    2024        window.location = "/";
    2125    }
     26
     27    useEffect(() => {
     28        const token = localStorage.getItem(AUTH_TOKEN);
     29        if (token!=null) {
     30            try {
     31                const decodedToken = jwtDecode(token);
     32                setUser({
     33                    name: decodedToken.name,
     34                    role: decodedToken.role,
     35                    hasAccess: decodedToken.hasAccess,
     36                });
     37            } catch (error) {
     38                console.error('Failed to decode token', error);
     39            }
     40        }
     41    }, [auth]);
    2242
    2343    useEffect(() => {
     
    4969                            </>
    5070                        }
     71                        {role===Roles.ADMIN &&
     72                            <>
     73                                <NavLink to="/admin-panel" className="nav-item nav-link">Admin Panel</NavLink>
     74                            </>
     75
     76                        }
    5177                        <NavLink to="/about" className="nav-item nav-link">About</NavLink>
    5278                        <NavLink to="/contact" className="nav-item nav-link">Support</NavLink>
     
    5783                            <img src="/images/user.png" width="45" height="45"/>
    5884                            <div className="auth-box">
    59                                 <p className="user"><b>{username}</b></p>
    60                                 <p className="role">{role==Roles.RECRUITER ? "Recruiter" : "Job Seeker"}</p>
     85                                <p className="user"><b>{user.name}</b></p>
     86                                {user.role==Roles.RECRUITER && <p className="role">Recruiter</p>}
     87                                {user.role==Roles.JOBSEEKER && <p className="role">Job Seeker</p>}
     88                                {user.role==Roles.ADMIN && <p className="role">Admin</p>}
     89                                {/*<p className="role">{user.role==Roles.RECRUITER ? "Recruiter" : "Job Seeker"}</p>*/}
    6190                            </div>
    6291
Note: See TracChangeset for help on using the changeset viewer.