diff --git a/src/components/sidebar/sidebarItems.tsx b/src/components/sidebar/sidebarItems.tsx index 7cec4a004..3258235a4 100644 --- a/src/components/sidebar/sidebarItems.tsx +++ b/src/components/sidebar/sidebarItems.tsx @@ -34,11 +34,6 @@ export const sidebarItems1 = [ icon: , title: "Applications", }, - { - path: "Trainee-applicants", - icon: , - title: "Trainees-Applicants", - }, { path: "cohort", icon: , diff --git a/src/pages/Applications.tsx b/src/pages/Applications.tsx index d709f9436..ec6b06add 100644 --- a/src/pages/Applications.tsx +++ b/src/pages/Applications.tsx @@ -1,19 +1,20 @@ -import React, { useEffect, useState } from 'react'; -import { ToastContainer } from 'react-toastify'; -import * as icons from 'react-icons/ai'; -import { Link } from 'react-router-dom'; -import Select from 'react-select'; -import * as AiIcons from 'react-icons/ai'; +import React, { useEffect, useState } from "react"; +import { ToastContainer } from "react-toastify"; +import * as icons from "react-icons/ai"; +import { Link } from "react-router-dom"; +import Select from "react-select"; +import * as AiIcons from "react-icons/ai"; import { deleteApplication, getMyApplications, getSingleApplication, -} from '../redux/actions/applications'; -import { useAppDispatch } from '../hooks/hooks'; -import { connect, useSelector } from 'react-redux'; -import { HiDotsVertical } from 'react-icons/hi'; -import Box from '@mui/material/Box'; -import { useCustomPagination } from 'components/Pagination/useCustomPagination'; +} from "../redux/actions/applications"; +import { useAppDispatch } from "../hooks/hooks"; +import { useNavigate } from "react-router-dom"; +import { connect, useSelector } from "react-redux"; +import { HiDotsVertical } from "react-icons/hi"; +import Box from "@mui/material/Box"; +import { useCustomPagination } from "components/Pagination/useCustomPagination"; type Props = {}; @@ -23,17 +24,20 @@ interface Update { } const Applications = (props: any) => { const dispatch = useAppDispatch(); - const { myApplications, currentApplication } = props; + const navigate = useNavigate(); - const [moredrop, setmoredrop] = useState(''); - const [filter, setFilter] = useState('submitted'); + const { myApplications, currentApplication, loading } = props; + console.log("My Applications:", myApplications); + + const [moredrop, setmoredrop] = useState(""); + const [filter, setFilter] = useState("submitted"); const [pagination, setPagination] = useState({ pageSize: 5, page: 1, }); const [deleteWarn, setDeleteWarn] = useState({ - id: '', + id: "", open: false, }); @@ -49,7 +53,7 @@ const Applications = (props: any) => { }; const handleMoreOptions = (item_id: any) => { if (!moredrop) setmoredrop(item_id); - if (moredrop) setmoredrop(''); + if (moredrop) setmoredrop(""); }; const handleDeleteApplication = (item_id: any) => { @@ -60,11 +64,20 @@ const Applications = (props: any) => { } }; const handleDateOfSubmission = (dateString: any) => { - const datePart = dateString.slice(0, dateString.indexOf('T')); + const datePart = dateString.slice(0, dateString.indexOf("T")); return datePart; }; useEffect(() => { - dispatch(getMyApplications(filter, pagination)); + const result = dispatch(getMyApplications(filter, pagination)); + + if ( + result.error === "Oops! You must be logged in to proceed" || + result.error === "Session expired. Please login again to continue." + ) { + setTimeout(() => { + navigate("/login"); + }, 5000); + } }, [filter, pagination, dispatch]); return ( @@ -77,8 +90,11 @@ const Applications = (props: any) => {
- @@ -88,21 +104,21 @@ const Applications = (props: any) => {
  • setFilter('submitted')} + onClick={() => setFilter("submitted")} > Submitted
  • setFilter('withdrawn')} + onClick={() => setFilter("withdrawn")} > Withdrawn
  • @@ -118,7 +134,7 @@ const Applications = (props: any) => { - {'Title'} + {"Title"} {/* @@ -126,133 +142,116 @@ const Applications = (props: any) => { */} - {'Date of submission'} + {"Date of submission"} { - {'status'} + {"status"} } - {'action'} + {"action"} - {myApplications.data?.applications != null - ? myApplications.data?.applications.map( - (item: any) => ( - - -
    -
    -

    - {item.associatedForm.title} -

    -
    -
    - - {/* -
    -
    -

    - { - item.associatedForm - .description - } -

    -
    + {loading ? ( + + + Processing... + + + ) : myApplications.data?.totalCount === 0 ? ( + + + Found 0 applications. + + + ) : ( + myApplications.data?.applications.map( + (item: any) => ( + + +
    +
    +

    + {item.associatedForm.title} +

    - */} - - -
    -
    -

    - {handleDateOfSubmission( - item.dateOfSubmission, - )} -

    -
    -
    - - - -
    -
    -

    - {item.status} -

    -
    -
    - - - -
    - { - e.preventDefault(); - handleMoreOptions(item?._id); - }} - /> -
- - - ), +
+ + ) - : null} + ) + )} {deleteWarn.open && (
@@ -274,7 +273,7 @@ const Applications = (props: any) => { ...deleteWarn, open: false, }); - setmoredrop(''); + setmoredrop(""); }} > Withdraw @@ -286,7 +285,7 @@ const Applications = (props: any) => { ...deleteWarn, open: false, }); - setmoredrop(''); + setmoredrop(""); }} > Cancel @@ -300,8 +299,8 @@ const Applications = (props: any) => {
@@ -332,7 +331,7 @@ const Applications = (props: any) => { First Name:

- {' '} + {" "} {currentApplication.data?.firstName}

@@ -342,7 +341,7 @@ const Applications = (props: any) => { Last Name:

- {' '} + {" "} {currentApplication.data?.lastName}

@@ -350,7 +349,7 @@ const Applications = (props: any) => {

Email:

- {' '} + {" "} {currentApplication.data?.email}

@@ -358,7 +357,7 @@ const Applications = (props: any) => {

Address:

- {' '} + {" "} {currentApplication.data?.address}

@@ -375,7 +374,7 @@ const Applications = (props: any) => {

Gender:

- {' '} + {" "} {currentApplication.data?.gender}

@@ -401,7 +400,7 @@ const Applications = (props: any) => { ?.dateOfSubmission !== undefined ? handleDateOfSubmission( currentApplication.data - ?.dateOfSubmission, + ?.dateOfSubmission ) : null}

@@ -409,8 +408,8 @@ const Applications = (props: any) => {

Status:

- {' '} - {currentApplication.data?.status}{' '} + {" "} + {currentApplication.data?.status}{" "}

@@ -430,13 +429,13 @@ const Applications = (props: any) => { menuPlacement="top" className="sm:text-sm w-13 rounded-bt-rd absolute active dark:bg-dark-frame-bg" options={[ - { value: '5', label: '5' }, - { value: '50', label: '50' }, - { value: '100', label: '100' }, - { value: '500', label: '500' }, - { value: '1000', label: '1000' }, + { value: "5", label: "5" }, + { value: "50", label: "50" }, + { value: "100", label: "100" }, + { value: "500", label: "500" }, + { value: "1000", label: "1000" }, ]} - defaultValue={{ value: '', label: '5' }} + defaultValue={{ value: "", label: "5" }} onChange={(e: any) => setPagination({ page: 1, @@ -495,7 +494,7 @@ const Applications = (props: any) => { pagination.page >= Math.ceil( myApplications?.data?.totalCount / - pagination.pageSize, + pagination.pageSize ) } > @@ -508,7 +507,7 @@ const Applications = (props: any) => { pageSize: pagination.pageSize, page: Math.ceil( myApplications?.data?.totalCount / - pagination.pageSize, + pagination.pageSize ), }) } @@ -516,7 +515,7 @@ const Applications = (props: any) => { pagination.page >= Math.ceil( myApplications?.data?.totalCount / - pagination.pageSize, + pagination.pageSize ) } > @@ -542,6 +541,7 @@ const Applications = (props: any) => { const mapState = (state: any) => ({ myApplications: state.myApplications, currentApplication: state.currentApplication, + loading: state.myApplications.loading, }); export default connect(mapState, { diff --git a/src/pages/Applications/AdminViewApplications.tsx b/src/pages/Applications/AdminViewApplications.tsx index d29d6dc1d..3d2921e9c 100644 --- a/src/pages/Applications/AdminViewApplications.tsx +++ b/src/pages/Applications/AdminViewApplications.tsx @@ -1,11 +1,12 @@ import React, { useState, useEffect } from 'react'; -import { Link } from 'react-router-dom'; +import { Link, useNavigate } from 'react-router-dom'; import NavBar from '../../components/sidebar/navHeader'; import { fetchApplications } from '../../redux/actions/adminListApplications'; import { HiDotsVertical } from 'react-icons/hi'; import { Pagination } from 'flowbite-react'; const ListApplications = () => { + const navigate = useNavigate(); const [applications, setApplications]: any = useState(); const [activePage, setActivePage] = useState(1); @@ -20,8 +21,15 @@ const ListApplications = () => { useEffect(() => { const applicationsData = async () => { - const data = await fetchApplications(); - const slicedData = data?.applications.slice( + const { data, error } = await fetchApplications(); + console.log(error); + // if(error){ + // setTimeout(() => { + // navigate('/login'); + // }, 5000); + // return; + // } + const slicedData = data?.data?.applications.slice( (activePage - 1) * itemsCountPerPage, activePage * itemsCountPerPage ); diff --git a/src/pages/programs/Programs.tsx b/src/pages/programs/Programs.tsx index 8d123e0d9..c81298807 100644 --- a/src/pages/programs/Programs.tsx +++ b/src/pages/programs/Programs.tsx @@ -5,7 +5,7 @@ import { connect } from "react-redux"; import { createProgramAction } from "../../redux/actions/createProgramAction"; import { useAppDispatch, useAppSelector } from "../../hooks/hooks"; import programSchema from "../../validation/programSchema"; -import { Link } from "react-router-dom"; +import { Link, useNavigate } from "react-router-dom"; import { HiDotsVertical } from "react-icons/hi"; import * as AiIcons from "react-icons/ai"; import { @@ -23,6 +23,7 @@ import { useTheme } from "../../hooks/darkmode"; import {debounce} from "lodash" const Programs = (props: any) => { + const navigate = useNavigate(); const { createProgramStates, fetchProgramStates, deleteProgramStates } = props; const { theme, setTheme } = useTheme(); @@ -249,7 +250,13 @@ const Programs = (props: any) => { }; useEffect(() => { - props.fetchPrograms(input); + const { data, error } = props.fetchPrograms(input); + // if (error) { + // setTimeout(() => { + // navigate('/login'); + // }, 5000); + // return; + // } }, [page, itemsPerPage]); diff --git a/src/redux/actions/adminListApplications.ts b/src/redux/actions/adminListApplications.ts index 9350dbcbe..f95ae1db6 100644 --- a/src/redux/actions/adminListApplications.ts +++ b/src/redux/actions/adminListApplications.ts @@ -3,74 +3,81 @@ import { toast } from 'react-toastify'; export const fetchApplications = async () => { - const response = await axios({ - url: process.env.BACKEND_URL, - method: 'post', - data: { - query: ` - query AdminViewApplications { - adminViewApplications { - applications { - _id - firstName - lastName - email - telephone - availability_for_interview - gender - resume - comments - address - status - formUrl - dateOfSubmission - associatedFormData { + try{ + + const response = await axios({ + url: process.env.BACKEND_URL, + method: 'post', + data: { + query: ` + query AdminViewApplications { + adminViewApplications { + applications { _id - title - description - link - jobpost { + firstName + lastName + email + telephone + availability_for_interview + gender + resume + comments + address + status + formUrl + dateOfSubmission + associatedFormData { _id title - cycle { - id - name - startDate - endDate - } - program { + description + link + jobpost { _id title + cycle { + id + name + startDate + endDate + } + program { + _id + title + description + mainObjective + requirements + modeOfExecution + duration + } + cohort { + id + title + start + end + } + link description - mainObjective - requirements - modeOfExecution - duration - } - cohort { - id - title - start - end + label } - link - description - label } } } } - } - `, - }, - }); - - if (response.data.errors) { - toast.error('Error fetching applications'); - return; + `, + }, + }); + + if (response.data.errors) { + console.log(response.data.errors); + toast.error(response.data.errors[0].message); + return {data: null, error:response.data.errors[0].message }; + } + + return { data: response.data.data.adminViewApplications, error: null }; + } catch (error: any) { + toast.error("An unexpected error occurred"); + return { data: null, error: error.message }; } - - return response.data.data.adminViewApplications; }; type Status = { diff --git a/src/redux/actions/applications.ts b/src/redux/actions/applications.ts index 511a74d51..4f66c5401 100644 --- a/src/redux/actions/applications.ts +++ b/src/redux/actions/applications.ts @@ -1,3 +1,4 @@ +import { ViewSingleApplication } from './adminListApplications'; import { fetchMyApplications, deleteOwnApplication, @@ -19,6 +20,7 @@ export const getMyApplications = const response = await axios.post('/', { query: `query ViewAllOwnApplications($filter: ApplicationFilter, $pagination: PaginationInput) { viewAllOwnApplications(filter: $filter, pagination: $pagination) { + message totalCount applications { _id @@ -55,23 +57,24 @@ export const getMyApplications = }, }); if (response.data.data.viewAllOwnApplications != null) { + let toastShown = false dispatch({ type: fetchMyApplications.FETCH_MYAPPLICATIONS_SUCCESS, data: response.data.data.viewAllOwnApplications, - message: 'success', + message: response.data.data.viewAllOwnApplications.message, }); + toast.success(response.data.data.viewAllOwnApplications.message) return response.data.data; } else { dispatch({ type: fetchMyApplications.FETCH_MYAPPLICATIONS_FAIL, error: response.data.errors[0].message, }); - toast.error(response.data.errors[0].message); - + toast.error(response.data.errors[0].message); return response.data.data; } } catch (err: any) { - toast.error(err.message); + console.error(err.message); } }; diff --git a/src/redux/actions/fetchProgramsAction.ts b/src/redux/actions/fetchProgramsAction.ts index 6ae088e99..806c75e98 100644 --- a/src/redux/actions/fetchProgramsAction.ts +++ b/src/redux/actions/fetchProgramsAction.ts @@ -43,7 +43,9 @@ export const fetchPrograms = (pageDetails: any) => { } if (response.data.errors) { - toast.error("Programs could not be fetched"); + console.log(response.data.errors) + toast.error(response.data.errors[0].message); + return {data: null, error:response.data.errors[0].message }; let mess; response.data.errors.map((b: any) => { @@ -55,7 +57,7 @@ export const fetchPrograms = (pageDetails: any) => { }); } } catch (error) { - toast.error("Programs could not be fetched"); + toast.error("Oops! unexpected error occured"); dispatch({ type: fetchProgramType.FETCH_PROGRAM_FAIL, diff --git a/src/redux/reducers/applicationReducer.ts b/src/redux/reducers/applicationReducer.ts index 16cf36e68..7cdaacdb7 100644 --- a/src/redux/reducers/applicationReducer.ts +++ b/src/redux/reducers/applicationReducer.ts @@ -19,15 +19,7 @@ const initialState = { success: false, error: null, message: null, - data: null, -}; - -const applicationState = { - loading: false, - success: false, - error: null, - message: null, - data: null, + data: { applications: [] }, }; export const applicationsReducer = ( @@ -37,6 +29,7 @@ export const applicationsReducer = ( switch (action.type) { case fetchMyApplications.FETCH_MYAPPLICATIONS_LOADING: return { + ...state, loading: true, success: false, error: null,