diff --git a/package.json b/package.json index 1c08570..a21cfb9 100644 --- a/package.json +++ b/package.json @@ -35,8 +35,8 @@ "react-datepicker": "4.21.0", "react-dom": "18.2.0", "react-dropzone": "14.2.3", - "react-popper": "2.3.0", "react-hook-form": "7.48.2", + "react-popper": "2.3.0", "react-quill": "2.0.0", "react-select": "5.7.3" }, diff --git a/pages/app-manager/[jobId].jsx b/pages/app-manager/[jobId].jsx index e950a03..ad77832 100644 --- a/pages/app-manager/[jobId].jsx +++ b/pages/app-manager/[jobId].jsx @@ -10,7 +10,7 @@ import { useState, useEffect, useMemo } from 'react'; import { ChevronRightIcon, ChevronLeftIcon } from '@heroicons/react/20/solid'; import { ArrowDownIcon, ArrowUpIcon, MagnifyingGlassIcon } from '@heroicons/react/24/outline'; import { useQuery, QueryClient, useQueryClient, QueryClientProvider } from '@tanstack/react-query'; - +import ResearcherSidebar from '../../components/ResearcherSidebar.jsx'; import { Table as ReactTable, useReactTable, @@ -19,7 +19,7 @@ import { getFilteredRowModel, getSortedRowModel, } from '@tanstack/react-table'; - +//&pageSize=${pageSize} async function fetchApplicants(router, pageIndex, pageSize) { if (!router.isReady) { return; @@ -36,15 +36,15 @@ async function fetchApplicants(router, pageIndex, pageSize) { } ); if (res.status === 200) { + const data = await res.json(); + // console.log(data); + return data; } - const data = await res.json(); - // console.log(data); - return data; } catch (e) { - throw e; + throw new Promise.reject(Error('Network response was not OK')); } } - +//${profileId} async function fetchResume(router, profileId) { if (!router.isReady) { return; @@ -57,15 +57,15 @@ async function fetchResume(router, profileId) { }, }); if (res.status === 200) { + const data = await res.json(); + //console.log(data); + return data; } - const data = await res.json(); - //console.log(data); - return data; } catch (e) { throw e; } } - +//${jobId}/ async function fetchApplicantCount(router) { if (!router.isReady) { return; @@ -79,10 +79,10 @@ async function fetchApplicantCount(router) { }, }); if (res.status === 200) { + const data = await res.json(); + //console.log(data); + return data; } - const data = await res.json(); - // console.log({ data }); - return data; } catch (e) { throw e; } @@ -91,7 +91,7 @@ const queryClient = new QueryClient({ defaultOptions: { queries: { refetchOnWindowFocus: false, - refetchOnReconnect: false, + refetchOnMount: true, retry: false, staleTime: 1000 * 60 * 60, //1 hour -- could make it more or less }, @@ -99,20 +99,25 @@ const queryClient = new QueryClient({ }); //Applicant Manager page export default function ApplicantManager() { - //Main page display - //ml-28 mt-8 mb-8 return ( - - - Manage Applicants - -
-

Manage Applicants

-
- + <> + + + Manage Applicants + +
+ +
+

+ Manage Applicants +

+
+ +
+
-
- + + ); } @@ -128,6 +133,7 @@ const ApplicantTable = () => { pageIndex: 0, pageSize: 5, }); + const defaultData = useMemo(() => [], []); //TODO: Update all page sections to use cursor instead, set pageSize to negative when requesting previous page and abs when setting next page @@ -142,8 +148,8 @@ const ApplicantTable = () => { const applicantCountQuery = useQuery({ queryKey: ['applicants-count', router], queryFn: () => fetchApplicantCount(router), - keepPreviousData: true, staleTime: Infinity, + placeholderData: 0, }); const applicantQuery = useQuery({ @@ -153,6 +159,7 @@ const ApplicantTable = () => { staleTime: 60 * 60 * 1000, keepPreviousData: true, enabled: !!applicantCount, + placeholderData: defaultData, }); const columns = useMemo( @@ -301,7 +308,10 @@ const ApplicantTable = () => { queryFn: () => fetchResume(router, id), }); //Ensure Profile IDs and Resumes are 1:1 matched - if (profileIds[id] === null) { + if (!resumeData) { + //add toast error + } + if (profileIds[id] === null && resumeData) { profileIds[id] = resumeData.url; resumesRetrieved += 1; } @@ -323,7 +333,14 @@ const ApplicantTable = () => { }; useEffect(() => { - if (applicantQuery.data) { + if (applicantQuery.status === 'error') { + queryClient.setQueryData(['applicants', router, pageIndex, pageSize], defaultData); //TODO: add toast + } + if (applicantCountQuery.status === 'error') { + queryClient.setQueryData(['applicants-count', router], 0); //TODO: add toast + } + if (applicantQuery.status === 'success') { + //console.log(applicantQuery); let dataForTable = applicantQuery.data; /*Fetching Resume Links from Profile IDs and add to applicant data for table */ //Loop to get all profile IDs @@ -355,7 +372,6 @@ const ApplicantTable = () => { } }, [applicantCountQuery, pageSize, applicantQuery]); - const defaultData = useMemo(() => [], []); const table = useReactTable({ data: data ?? defaultData, columns, @@ -414,14 +430,14 @@ const ApplicantTable = () => { setGlobalFilter(String(value))} - className="p-2 text-base text-[#8b8b8b] outline-none" + className="p-2 text-lg text-[#8b8b8b] outline-none" placeholder="Search..." />
- - +
+ {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( @@ -490,14 +506,12 @@ const ApplicantTable = () => { ? 1 + table.getState().pagination.pageIndex * table.getState().pagination.pageSize : '0'} - - {table.getCanNextPage() ? ( - (table.getState().pagination.pageIndex + 1) * table.getState().pagination.pageSize - ) : applicantCountQuery?.isLoading ? ( -
Loading...
- ) : ( - applicantCount - )}{' '} - of {applicantCountQuery?.isLoading ?
Loading...
: applicantCount} + {table.getCanNextPage() + ? (table.getState().pagination.pageIndex + 1) * table.getState().pagination.pageSize + : applicantCountQuery?.isError + ? 0 + : applicantCount}{' '} + of {applicantCountQuery?.isError ? 0 : applicantCount} + +

+ {pdfError || + (pdf ? ( + `Successfully attached ${pdf.name}` + ) : ( + <> + Click to Upload or Drag and Drop +
+ PDF File up to 100 KB + + ))} +

+ + + - -
-
- - {/* https://stackoverflow.com/questions/50229792/adding-a-new-line-in-a-jsx-string-inside-a-paragraph-react */} - s} - // onCreateOption={(s) => { - // setSkills((sk) => { - // return [...sk, s]; - // }); - // }} - // getNewOptionData={(inputVal) => { - // console.log({ inputVal }, 'getNew'); - // }} - isValidNewOption={(s) => s.trim().length > 0} - onChange={(opt, meta) => { - // console.log({ opt, meta }); - if (meta.action === 'create-option') { - setSkills((sk) => [...sk, meta.option.value]); - } else if (meta.action === 'pop-value') { - setSkills((sk) => sk.slice(0, -1)); - } else if (meta.action === 'remove-value') { - setSkills((sk) => { - const skillsCopy = [...sk]; - const index = skillsCopy.indexOf(meta.removedValue.value); - if (index >= 0) { - skillsCopy.splice(index, 1); - } - return skillsCopy; - }); - } else if (meta.action === 'clear') { - setSkills([]); - } - }} - // max={3} - /> -
- - {/* TODO: Use this instead of only using react-select */} - {/* {skills.map((s) => ( +
+
+ + {/* https://stackoverflow.com/questions/50229792/adding-a-new-line-in-a-jsx-string-inside-a-paragraph-react */} + s} + // onCreateOption={(s) => { + // setSkills((sk) => { + // return [...sk, s]; + // }); + // }} + // getNewOptionData={(inputVal) => { + // console.log({ inputVal }, 'getNew'); + // }} + isValidNewOption={(s) => s.trim().length > 0} + onChange={(opt, meta) => { + // console.log({ opt, meta }); + if (meta.action === 'create-option') { + setSkills((sk) => [...sk, meta.option.value]); + } else if (meta.action === 'pop-value') { + setSkills((sk) => sk.slice(0, -1)); + } else if (meta.action === 'remove-value') { + setSkills((sk) => { + const skillsCopy = [...sk]; + const index = skillsCopy.indexOf(meta.removedValue.value); + if (index >= 0) { + skillsCopy.splice(index, 1); + } + return skillsCopy; + }); + } else if (meta.action === 'clear') { + setSkills([]); + } + }} + // max={3} + /> +
+ + {/* TODO: Use this instead of only using react-select */} + {/* {skills.map((s) => (
    {s}
))} */} -
-
-
- - {/* https://stackoverflow.com/questions/50229792/adding-a-new-line-in-a-jsx-string-inside-a-paragraph-react */} -
- -
-
-
- - +
+
+ + {/* https://stackoverflow.com/questions/50229792/adding-a-new-line-in-a-jsx-string-inside-a-paragraph-react */} + +
+
- -
-
-
- - - value.startsWith('http') ? value : `https://${value}` - } - formatCreateLabel={(s) => (s.startsWith('http') ? s : `https://${s}`)} - isValidNewOption={(s) => { - if (s.trim().length === 0) { - return false; - } - let { error } = SecondProfileCreationValidator.validate({ - skills: [], - links: [s], - }); - if (error) { - ({ error } = SecondProfileCreationValidator.validate({ - skills: [], - links: [`https://${s}`], - })); +
+
+ + +
+ +
+
+
+ + + value.startsWith('http') ? value : `https://${value}` } - return !error; - }} - onChange={(opt, meta) => { - // console.log({ opt, meta }); - if (meta.action === 'create-option') { + formatCreateLabel={(s) => (s.startsWith('http') ? s : `https://${s}`)} + isValidNewOption={(s) => { + if (s.trim().length === 0) { + return false; + } let { error } = SecondProfileCreationValidator.validate({ skills: [], - links: [meta.option.value], + links: [s], }); if (error) { ({ error } = SecondProfileCreationValidator.validate({ skills: [], - links: [`https://${meta.option.value}`], + links: [`https://${s}`], })); } - if (error) { - return; - } - if (meta.option.value.startsWith('http')) { - setLinks((l) => [...l, meta.option.value]); - } else { - setLinks((l) => [...l, `https://${meta.option.value}`]); - } - } else if (meta.action === 'pop-value') { - setLinks((l) => l.slice(0, -1)); - } else if (meta.action === 'remove-value') { - setLinks((l) => { - const linksCopy = [...l]; - const index = linksCopy.indexOf(meta.removedValue.value); - if (index >= 0) { - linksCopy.splice(index, 1); + return !error; + }} + onChange={(opt, meta) => { + // console.log({ opt, meta }); + if (meta.action === 'create-option') { + let { error } = SecondProfileCreationValidator.validate({ + skills: [], + links: [meta.option.value], + }); + if (error) { + ({ error } = SecondProfileCreationValidator.validate({ + skills: [], + links: [`https://${meta.option.value}`], + })); } - return linksCopy; - }); - } else if (meta.action === 'clear') { - setLinks([]); - } - }} - /> + if (error) { + return; + } + if (meta.option.value.startsWith('http')) { + setLinks((l) => [...l, meta.option.value]); + } else { + setLinks((l) => [...l, `https://${meta.option.value}`]); + } + } else if (meta.action === 'pop-value') { + setLinks((l) => l.slice(0, -1)); + } else if (meta.action === 'remove-value') { + setLinks((l) => { + const linksCopy = [...l]; + const index = linksCopy.indexOf(meta.removedValue.value); + if (index >= 0) { + linksCopy.splice(index, 1); + } + return linksCopy; + }); + } else if (meta.action === 'clear') { + setLinks([]); + } + }} + /> +
+
- -
-
- - Skip for now - - -
- - -
+
+ + Skip for now + + +
+ + +
); } diff --git a/styles/globals.css b/styles/globals.css index 0c13239..e3260db 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -8,7 +8,6 @@ body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; - background-color: #f5f5f5; } a {