diff --git a/src/components/Accordion.tsx b/src/components/Accordion.tsx index 54d1f146..ed2fcbf4 100644 --- a/src/components/Accordion.tsx +++ b/src/components/Accordion.tsx @@ -5,10 +5,11 @@ import { cn } from "@/lib/client/utils"; interface AccordionProps { label: string; + className?: string; children?: ReactNode; } -const Accordion = ({ label, children }: AccordionProps) => { +const Accordion = ({ label, children, className = "" }: AccordionProps) => { const [isOpen, setIsOpen] = useState(true); return ( @@ -42,7 +43,12 @@ const Accordion = ({ label, children }: AccordionProps) => { : "grid-rows-[0fr] opacity-0" )} > -

+

{children}

diff --git a/src/components/Stats.tsx b/src/components/Stats.tsx new file mode 100644 index 00000000..aca7ddd0 --- /dev/null +++ b/src/components/Stats.tsx @@ -0,0 +1,26 @@ +interface StatsProps { + title: string; + items?: { label: string; value?: string }[]; +} +export const Stats = ({ title, items = [] }: StatsProps) => { + return ( +
+
{title}
+
+ {items?.length > 0 && ( +
+ {items?.map(({ label, value }, index) => { + return ( + + {`${label}:`} {value} + + ); + })} +
+ )} +
+ ); +}; diff --git a/src/components/Tabs.tsx b/src/components/Tabs.tsx index 0b1e5fa5..18a4b6fa 100644 --- a/src/components/Tabs.tsx +++ b/src/components/Tabs.tsx @@ -1,9 +1,10 @@ import { Tab } from "@headlessui/react"; import { classed } from "@tw-classed/react"; import { AppContent } from "./AppContent"; +import { ReactNode } from "react"; interface TabProps { - label: string; + label: ReactNode; badge?: boolean; children: React.ReactNode; } diff --git a/src/components/jobs/CandidateJobsView.tsx b/src/components/jobs/CandidateJobsView.tsx index bffcb83b..a5919e99 100644 --- a/src/components/jobs/CandidateJobsView.tsx +++ b/src/components/jobs/CandidateJobsView.tsx @@ -59,8 +59,6 @@ export default function CandidateJobsView({ const hasOpportunities = true; const hasOptedIn = true; - console.log(pendingMatches); - return ( <> - - {`We will show you opportunities that match your preferences and you can choose if you want to match with a recruiter.`} + + {`We will show you opportunities that match your preferences and you can choose if you want to match with a recruiter.`} + + } + footer={ +
+ + + Review your answers. They cannot be edited later. - } - footer={ -
- - - Review your answers. They cannot be edited later. - -
- } - > +
+ } + > +
@@ -214,7 +214,9 @@ export default function CandidatePage({ />
-
+
+
+
@@ -323,8 +325,8 @@ export default function CandidatePage({
- - +
+ ); } diff --git a/src/components/jobs/JobsEntryPage.tsx b/src/components/jobs/JobsEntryPage.tsx index 9cab3aed..dc65721d 100644 --- a/src/components/jobs/JobsEntryPage.tsx +++ b/src/components/jobs/JobsEntryPage.tsx @@ -15,11 +15,29 @@ export default function JobsEntryPage({ return ( - {`As a job searcher, enter your preferences and store them privately. As a recruiter, enter your requirements and send out a query with MPC to get private matches. Searchers have to mark “interested” in a job opportunity for the recruiter to learn anything.`} - +
+
    +
  • + Recruiters: Enter job requirements and + privately share them with folks you meet using MPC. +
  • +
  • + Candidates: Enter your job preferences and + compare them privately with opportunities to discover matches. + + Recruiters never see a match without your approval. + +
  • +
+ + This is an experimental feature that Cursive is testing at + Frontiers. Your data is encrypted using{" "} + phantom-zone, a new and + unaudited Multi-Party FHE Rust VM.{" "} + +
} className="pt-4 h-full" //onSubmit={handleSubmitWithPassword} diff --git a/src/components/jobs/RecruiterMatchView.tsx b/src/components/jobs/RecruiterMatchView.tsx index ef88b9e0..0ed3da14 100644 --- a/src/components/jobs/RecruiterMatchView.tsx +++ b/src/components/jobs/RecruiterMatchView.tsx @@ -12,6 +12,7 @@ import { Banner } from "../Banner"; import { ArtworkSnapshot } from "../artwork/ArtworkSnapshot"; import { Accordion } from "../Accordion"; import { CandidateJobMatch } from "@/pages/api/jobs/get_candidate_matches"; +import { Stats } from "../Stats"; const Title = classed.span("text-white text-xs font-normal font-inter"); const Description = classed.h5("text-white/50 font-inter font-normal text-sm"); @@ -78,8 +79,6 @@ export default function RecruiterMatchView({ const hasOptedIn = true; const isBookmarked = false; - console.log(matches); - return ( <> - + + + @@ -155,7 +188,7 @@ export default function RecruiterMatchView({ Respondents, children: (
{!hasOpportunities ? ( diff --git a/src/components/jobs/RecruiterPage.tsx b/src/components/jobs/RecruiterPage.tsx index 2f543f29..69e6273e 100644 --- a/src/components/jobs/RecruiterPage.tsx +++ b/src/components/jobs/RecruiterPage.tsx @@ -145,182 +145,183 @@ export default function RecruiterPage({ }; return ( - - - {`We will show your opportunity to qualifying job seekers who will have the option to match with you.`} - - } - actions={} - > -
-
- -
-
- -
-
- -
-
-
-
- { - setValue("education", "high-school"); - }} - /> - { - setValue("education", "bachelor"); - }} - /> - { - setValue("education", "master"); - }} - /> - { - setValue("education", "phd"); - }} - /> -
-
-
- { - setValue("experience", e?.target?.value); + + {`We will show your opportunity to qualifying job seekers who will have the option to match with you.`} + + } + footer={ +
+ +
+ } + > +
+
+ +
+
+ +
+
+ +
+
+
+
+ { + setValue("education", "high-school"); }} /> -
-
-
- { - setValue("tagZk", checked); - }} - label="ZK/MPC" - /> - { - setValue("tagDefi", checked); - }} - /> - { - setValue("tagConsumer", checked); - }} - /> - { - setValue("tagInfra", checked); - }} - /> -
-
-
-
- { - setValue("salary", e?.target?.value); + { + setValue("education", "bachelor"); }} /> -
-
-
- { - setValue("stageParadigm", checked); - }} - label="Paradigm project" - /> - { - setValue("stageGrant", checked); - }} - /> - { - setValue("stageSeed", checked); - }} - /> - { - setValue("stageSeriesA", checked); - }} - /> -
-
- -
+ { + setValue("education", "master"); + }} + /> + { + setValue("education", "phd"); + }} + /> +
+
+
+ { + setValue("experience", e?.target?.value); + }} + /> +
+
+
{ - setValue("partTime", checked); + setValue("tagZk", checked); }} + label="ZK/MPC" /> -
-
-
-
+ { + setValue("tagDefi", checked); + }} + /> + { + setValue("tagConsumer", checked); + }} + /> + { + setValue("tagInfra", checked); + }} + /> +
+
+
+
+ { + setValue("salary", e?.target?.value); + }} + /> +
+
+
+ { + setValue("stageParadigm", checked); + }} + label="Paradigm project" + /> + { + setValue("stageGrant", checked); + }} + /> + { + setValue("stageSeed", checked); + }} + /> + { + setValue("stageSeriesA", checked); + }} + /> +
+
+ +
+ { + setValue("partTime", checked); + }} + /> +
+
+
); } diff --git a/src/components/modals/Modal.tsx b/src/components/modals/Modal.tsx index 0ef84425..c1cee562 100644 --- a/src/components/modals/Modal.tsx +++ b/src/components/modals/Modal.tsx @@ -91,7 +91,7 @@ const Modal = ({ )} {actions} -
+
{children}
diff --git a/src/layouts/FormStepLayout.tsx b/src/layouts/FormStepLayout.tsx index 511a3863..47e9a4a5 100644 --- a/src/layouts/FormStepLayout.tsx +++ b/src/layouts/FormStepLayout.tsx @@ -69,7 +69,7 @@ const FormStepLayout = ({ {(children || footer) && (
@@ -78,7 +78,7 @@ const FormStepLayout = ({
)} {actions && ( -
+
{actions}
)} diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index c414e852..dfa2ae8d 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -97,7 +97,7 @@ export default function App({ Component, pageProps }: AppProps) { position="top-center" toastOptions={{ duration: 5000, - className: "font-inter text-white", + className: "font-inter text-black", }} /> diff --git a/src/pages/jobs/index.tsx b/src/pages/jobs/index.tsx index e74b90f7..aecd6169 100644 --- a/src/pages/jobs/index.tsx +++ b/src/pages/jobs/index.tsx @@ -9,8 +9,9 @@ import RecruiterPage, { } from "@/components/jobs/RecruiterPage"; import { getAuthToken } from "@/lib/client/localStorage"; import { getJobs, saveJobs } from "@/lib/client/localStorage/jobs"; -import React, { useEffect, useState } from "react"; +import React, { ReactNode, useEffect, useState } from "react"; import { CandidateJobMatch } from "../api/jobs/get_candidate_matches"; +import { Modal } from "@/components/modals/Modal"; enum JobsDisplayState { SELECT_ROLE = "SELECT_ROLE", @@ -21,6 +22,8 @@ enum JobsDisplayState { } const Jobs: React.FC = () => { + const [candidateModal, setCandidateModal] = useState(false); + const [recruiterModal, setRecruiterModal] = useState(false); const [displayState, setDisplayState] = useState( JobsDisplayState.SELECT_ROLE ); @@ -68,48 +71,63 @@ const Jobs: React.FC = () => { }, []); const handleIsCandidate = () => { - setDisplayState(JobsDisplayState.CANDIDATE_FORM); + setCandidateModal(true); }; const handleIsRecruiter = () => { - setDisplayState(JobsDisplayState.RECRUITER_FORM); + setRecruiterModal(true); }; const handleSubmitCandidateInput = (candidateInput: JobCandidateInput) => { saveJobs({ candidateInput }); + setCandidateModal(false); setDisplayState(JobsDisplayState.CANDIDATE_MATCHES); }; const handleSubmitRecruiterInput = (recruiterInput: JobRecruiterInput) => { saveJobs({ recruiterInput }); + setRecruiterModal(false); setDisplayState(JobsDisplayState.RECRUITER_MATCHES); }; - switch (displayState) { - case JobsDisplayState.SELECT_ROLE: - return ( - > = { + [JobsDisplayState.SELECT_ROLE]: ( + + ), + [JobsDisplayState.CANDIDATE_MATCHES]: ( + + ), + [JobsDisplayState.RECRUITER_MATCHES]: ( + + ), + }; + + return ( + <> + + - ); - case JobsDisplayState.CANDIDATE_FORM: - return ( + + - ); - case JobsDisplayState.RECRUITER_FORM: - return ( - - ); - case JobsDisplayState.CANDIDATE_MATCHES: - return ; - case JobsDisplayState.RECRUITER_MATCHES: - return ; - } + + {JobViewMapping[displayState]} + + ); }; export default Jobs;