539 lines
17 KiB
TypeScript
539 lines
17 KiB
TypeScript
import React from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import {
|
|
Box,
|
|
Button,
|
|
Container,
|
|
Paper,
|
|
Typography,
|
|
Grid,
|
|
Card,
|
|
CardContent,
|
|
Chip,
|
|
Step,
|
|
StepLabel,
|
|
Stepper,
|
|
Stack,
|
|
ButtonProps,
|
|
useMediaQuery,
|
|
useTheme,
|
|
} from '@mui/material';
|
|
import { styled } from '@mui/material/styles';
|
|
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
|
|
import AssessmentIcon from '@mui/icons-material/Assessment';
|
|
import PersonIcon from '@mui/icons-material/Person';
|
|
import WorkIcon from '@mui/icons-material/Work';
|
|
import AutoAwesomeIcon from '@mui/icons-material/AutoAwesome';
|
|
import DescriptionIcon from '@mui/icons-material/Description';
|
|
import professionalConversationPng from 'assets/Conversation.png';
|
|
import selectAJobPng from 'assets/select-a-job.png';
|
|
import selectJobAnalysisPng from 'assets/select-job-analysis.png';
|
|
import selectACandidatePng from 'assets/select-a-candidate.png';
|
|
import selectStartAnalysisPng from 'assets/select-start-analysis.png';
|
|
import waitPng from 'assets/wait.png';
|
|
import finalResumePng from 'assets/final-resume.png';
|
|
|
|
import { Beta } from 'components/ui/Beta';
|
|
|
|
// Styled components matching HomePage patterns
|
|
const HeroSection = styled(Box)(({ theme }) => ({
|
|
padding: theme.spacing(3, 0),
|
|
backgroundColor: theme.palette.primary.main,
|
|
color: theme.palette.primary.contrastText,
|
|
[theme.breakpoints.down('md')]: {
|
|
padding: theme.spacing(2, 0),
|
|
},
|
|
}));
|
|
|
|
const StepSection = styled(Box)(({ theme }) => ({
|
|
padding: theme.spacing(6, 0),
|
|
'&:nth-of-type(even)': {
|
|
backgroundColor: theme.palette.background.default,
|
|
},
|
|
}));
|
|
|
|
const StepNumber = styled(Box)(({ theme }) => ({
|
|
backgroundColor: theme.palette.action.active,
|
|
color: theme.palette.background.paper,
|
|
borderRadius: '50%',
|
|
width: 60,
|
|
height: 60,
|
|
display: 'flex',
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
fontSize: '1.5rem',
|
|
fontWeight: 'bold',
|
|
margin: '0 auto 1rem auto',
|
|
[theme.breakpoints.up('md')]: {
|
|
margin: 0,
|
|
},
|
|
}));
|
|
|
|
const ImageContainer = styled(Box)(({ theme }) => ({
|
|
textAlign: 'center',
|
|
'& img': {
|
|
maxWidth: '100%',
|
|
height: 'auto',
|
|
borderRadius: theme.spacing(1),
|
|
boxShadow: theme.shadows[3],
|
|
border: `2px solid ${theme.palette.action.active}`,
|
|
},
|
|
}));
|
|
|
|
const StepCard = styled(Card)(({ theme }) => ({
|
|
height: '100%',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
border: `1px solid ${theme.palette.action.active}`,
|
|
'&:hover': {
|
|
boxShadow: theme.shadows[4],
|
|
},
|
|
}));
|
|
|
|
const steps = [
|
|
'Select Job Analysis',
|
|
'Choose a Job',
|
|
'Select a Candidate',
|
|
'Start Assessment',
|
|
'Review Results',
|
|
'Generate Resume',
|
|
];
|
|
|
|
interface StepContentProps {
|
|
stepNumber: number;
|
|
title: string;
|
|
subtitle: string;
|
|
icon: React.ReactNode;
|
|
description: string[];
|
|
imageSrc: string;
|
|
imageAlt: string;
|
|
note?: string;
|
|
success?: string;
|
|
reversed?: boolean;
|
|
}
|
|
|
|
const StepContent: React.FC<StepContentProps> = ({
|
|
stepNumber,
|
|
title,
|
|
subtitle,
|
|
icon,
|
|
description,
|
|
imageSrc,
|
|
imageAlt,
|
|
note,
|
|
success,
|
|
reversed = false,
|
|
}) => {
|
|
const textContent = (
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<Box sx={{ display: 'flex', alignItems: 'center', mb: 3 }}>
|
|
<StepNumber>{stepNumber}</StepNumber>
|
|
<Box sx={{ ml: { xs: 0, md: 3 }, textAlign: { xs: 'center', md: 'left' } }}>
|
|
<Typography variant="h3" component="h2" sx={{ color: 'primary.main', mb: 1 }}>
|
|
{title}
|
|
</Typography>
|
|
<Box
|
|
sx={{
|
|
display: 'flex',
|
|
gap: 1,
|
|
alignItems: 'center',
|
|
justifyContent: { xs: 'center', md: 'flex-start' },
|
|
}}
|
|
>
|
|
{icon}
|
|
<Typography variant="body2" color="text.secondary">
|
|
{subtitle}
|
|
</Typography>
|
|
</Box>
|
|
</Box>
|
|
</Box>
|
|
{description.map((paragraph, index) => (
|
|
<Typography key={index} variant="body1" paragraph>
|
|
{paragraph}
|
|
</Typography>
|
|
))}
|
|
{note && (
|
|
<Paper
|
|
sx={{
|
|
p: 2,
|
|
backgroundColor: 'action.hover',
|
|
border: '1px solid',
|
|
borderColor: 'action.active',
|
|
mt: 2,
|
|
}}
|
|
>
|
|
<Typography variant="body2" sx={{ fontStyle: 'italic' }}>
|
|
<strong>Note:</strong> {note}
|
|
</Typography>
|
|
</Paper>
|
|
)}
|
|
{success && (
|
|
<Paper
|
|
sx={{
|
|
p: 2,
|
|
backgroundColor: 'secondary.main',
|
|
color: 'secondary.contrastText',
|
|
mt: 2,
|
|
}}
|
|
>
|
|
<Typography variant="body1" sx={{ fontWeight: 'bold' }}>
|
|
🎉 {success}
|
|
</Typography>
|
|
</Paper>
|
|
)}
|
|
</Grid>
|
|
);
|
|
|
|
const imageContent = (
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<ImageContainer>
|
|
<img src={imageSrc} alt={imageAlt} />
|
|
</ImageContainer>
|
|
</Grid>
|
|
);
|
|
|
|
return (
|
|
<Grid container spacing={4} alignItems="center">
|
|
{reversed ? (
|
|
<>
|
|
{imageContent}
|
|
{textContent}
|
|
</>
|
|
) : (
|
|
<>
|
|
{textContent}
|
|
{imageContent}
|
|
</>
|
|
)}
|
|
</Grid>
|
|
);
|
|
};
|
|
interface HeroButtonProps extends ButtonProps {
|
|
children?: string;
|
|
path: string;
|
|
}
|
|
const HeroButton = (props: HeroButtonProps) => {
|
|
const { children, onClick, path, ...rest } = props;
|
|
|
|
const navigate = useNavigate();
|
|
|
|
const handleClick = () => {
|
|
navigate(path);
|
|
};
|
|
|
|
const HeroStyledButton = styled(Button)(({ theme }) => ({
|
|
marginTop: theme.spacing(2),
|
|
padding: theme.spacing(1, 3),
|
|
fontWeight: 500,
|
|
backgroundColor: theme.palette.action.active,
|
|
color: theme.palette.background.paper,
|
|
'&:hover': {
|
|
backgroundColor: theme.palette.action.active,
|
|
opacity: 0.9,
|
|
},
|
|
}));
|
|
return (
|
|
<HeroStyledButton onClick={onClick ? onClick : handleClick} {...rest}>
|
|
{children}
|
|
</HeroStyledButton>
|
|
);
|
|
};
|
|
|
|
const HowItWorks: React.FC = () => {
|
|
const navigate = useNavigate();
|
|
const theme = useTheme();
|
|
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
|
|
|
const handleGetStarted = () => {
|
|
navigate('/job-analysis');
|
|
};
|
|
|
|
return (
|
|
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
|
|
{/* Hero Section */}
|
|
{/* Hero Section */}
|
|
<HeroSection>
|
|
<Container>
|
|
<Box
|
|
sx={{
|
|
display: 'flex',
|
|
flexDirection: { xs: 'column', md: 'row' },
|
|
gap: 4,
|
|
alignItems: 'center',
|
|
flexGrow: 1,
|
|
maxWidth: '1024px',
|
|
}}
|
|
>
|
|
<Box sx={{ flex: 1, flexGrow: 1 }}>
|
|
<Typography
|
|
variant="h2"
|
|
component="h1"
|
|
sx={{
|
|
fontWeight: 700,
|
|
fontSize: { xs: '2rem', md: '3rem' },
|
|
mb: 2,
|
|
color: 'white',
|
|
}}
|
|
>
|
|
Your complete professional story, beyond a single page
|
|
</Typography>
|
|
<Typography variant="h5" sx={{ mb: 3, fontWeight: 400 }}>
|
|
Let potential employers discover the depth of your experience through interactive
|
|
Q&A and tailored resumes
|
|
</Typography>
|
|
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={2}>
|
|
<HeroButton variant="contained" size="large" path="/login/register">
|
|
Get Started as Candidate
|
|
</HeroButton>
|
|
{/* <HeroButton
|
|
variant="outlined"
|
|
size="large"
|
|
sx={{
|
|
backgroundColor: 'transparent',
|
|
border: '2px solid',
|
|
borderColor: 'action.active'
|
|
}}
|
|
>
|
|
Recruit Talent
|
|
</HeroButton> */}
|
|
</Stack>
|
|
</Box>
|
|
<Box
|
|
sx={{
|
|
justifyContent: 'center',
|
|
display: { xs: 'none', md: 'block' },
|
|
}}
|
|
>
|
|
<Box
|
|
component="img"
|
|
src={professionalConversationPng}
|
|
alt="Professional conversation"
|
|
sx={{
|
|
width: '100%',
|
|
maxWidth: 200,
|
|
height: 'auto',
|
|
borderRadius: 2,
|
|
boxShadow: 3,
|
|
}}
|
|
/>
|
|
</Box>
|
|
</Box>
|
|
</Container>
|
|
</HeroSection>
|
|
<HeroSection
|
|
sx={{
|
|
display: 'flex',
|
|
position: 'relative',
|
|
overflow: 'hidden',
|
|
border: '2px solid orange',
|
|
}}
|
|
>
|
|
<Beta adaptive={false} sx={{ left: '-90px' }} />
|
|
<Container sx={{ display: 'flex', position: 'relative' }}>
|
|
<Box
|
|
sx={{
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
textAlign: 'center',
|
|
maxWidth: 800,
|
|
mx: 'auto',
|
|
position: 'relative',
|
|
}}
|
|
>
|
|
<Typography
|
|
variant="h2"
|
|
component="h1"
|
|
sx={{
|
|
fontWeight: 700,
|
|
fontSize: { xs: '2rem', md: '2.5rem' },
|
|
mb: 2,
|
|
color: 'white',
|
|
}}
|
|
>
|
|
Welcome to the Backstory Beta!
|
|
</Typography>
|
|
<Typography variant="h5" sx={{ mb: 3, fontWeight: 400 }}>
|
|
Here are your steps from zero-to-hero to see Backstory in action
|
|
</Typography>
|
|
</Box>
|
|
</Container>
|
|
</HeroSection>
|
|
|
|
{/* Progress Overview */}
|
|
<Container sx={{ py: 4 }}>
|
|
<Box sx={{ display: { xs: 'none', md: 'block' } }}>
|
|
<Stepper alternativeLabel sx={{ mb: 4 }}>
|
|
{steps.map(label => (
|
|
<Step key={label}>
|
|
<StepLabel>{label}</StepLabel>
|
|
</Step>
|
|
))}
|
|
</Stepper>
|
|
</Box>
|
|
</Container>
|
|
|
|
{/* Step 1: Select Job Analysis */}
|
|
<StepSection>
|
|
<Container>
|
|
<StepContent
|
|
stepNumber={1}
|
|
title="Select Job Analysis"
|
|
subtitle="Navigate to the main feature"
|
|
icon={<AssessmentIcon sx={{ color: 'action.active' }} />}
|
|
description={[
|
|
"Select 'Job Analysis' from the menu. This takes you to the interactive Job Analysis page, where you will get to evaluate a candidate for a selected job.",
|
|
]}
|
|
imageSrc={selectJobAnalysisPng}
|
|
imageAlt="Select Job Analysis from menu"
|
|
/>
|
|
</Container>
|
|
</StepSection>
|
|
|
|
{/* Step 2: Select a Job */}
|
|
<StepSection>
|
|
<Container>
|
|
<StepContent
|
|
stepNumber={2}
|
|
title="Choose a Job"
|
|
subtitle="Pick from existing job postings"
|
|
icon={<WorkIcon sx={{ color: 'action.active' }} />}
|
|
description={[
|
|
'Once on the Job Analysis Page, explore a little bit and then select one of the jobs. The requirements and information provided on Backstory are extracted from job postings that users have pasted as a job description or uploaded from a PDF.',
|
|
]}
|
|
imageSrc={selectAJobPng}
|
|
imageAlt="Select a job from the available options"
|
|
note="You can create your own job postings once you create an account. Until then, you need to select one that already exists."
|
|
reversed={true}
|
|
/>
|
|
</Container>
|
|
</StepSection>
|
|
|
|
{/* Step 3: Select a Candidate */}
|
|
<StepSection>
|
|
<Container>
|
|
<StepContent
|
|
stepNumber={3}
|
|
title="Select a Candidate"
|
|
subtitle="Choose from available profiles"
|
|
icon={<PersonIcon sx={{ color: 'action.active' }} />}
|
|
description={[
|
|
'Now that you have a Job selected, you need to select a candidate. In addition to myself (James), there are several candidates which AI has generated. Each has a unique skillset and can be used to test out the system.',
|
|
]}
|
|
imageSrc={selectACandidatePng}
|
|
imageAlt="Select a candidate from the available profiles"
|
|
note="If you create an account, you can opt-in to have your account show up for others to view as well, or keep it private for just your own resume generation and job research."
|
|
/>
|
|
</Container>
|
|
</StepSection>
|
|
|
|
{/* Step 4: Start Assessment */}
|
|
<StepSection>
|
|
<Container>
|
|
<StepContent
|
|
stepNumber={4}
|
|
title="Start Assessment"
|
|
subtitle="Begin the AI analysis"
|
|
icon={<PlayArrowIcon sx={{ color: 'action.active' }} />}
|
|
description={[
|
|
'After selecting a candidate, you are ready to have Backstory perform the Job Analysis. During this phase, Backstory will take each of requirements extracted from the Job and match it against information about the selected candidate.',
|
|
'This could be as little as a simple resume, or as complete as a full work history. Backstory performs similarity searches to identify key elements from the candidate that pertain to a given skill and provides a graded response.',
|
|
'To see that in action, click the "Start Skill Assessment" button.',
|
|
]}
|
|
imageSrc={selectStartAnalysisPng}
|
|
imageAlt="Start the skill assessment process"
|
|
reversed={true}
|
|
/>
|
|
</Container>
|
|
</StepSection>
|
|
|
|
{/* Step 5: Wait and Review */}
|
|
<StepSection>
|
|
<Container>
|
|
<StepContent
|
|
stepNumber={5}
|
|
title="Review Results"
|
|
subtitle="Watch the magic happen"
|
|
icon={<AutoAwesomeIcon sx={{ color: 'action.active' }} />}
|
|
description={[
|
|
'Once you begin that action, the Start Skill Assessment button will grey out and the page will begin updating as it collates information about the candidate. As Backstory performs its magic, you can monitor the progress and explore the different identified skills to see how or why a candidate does or does not have that skill.',
|
|
'Once it is done, you can see the final Overall Match. This is a weighted score based on amount of evidence a skill had, whether the skill was required or preferred, and other metrics.',
|
|
]}
|
|
imageSrc={waitPng}
|
|
imageAlt="Wait for the analysis to complete and review results"
|
|
/>
|
|
</Container>
|
|
</StepSection>
|
|
|
|
{/* Step 6: Generate Resume */}
|
|
<StepSection>
|
|
<Container>
|
|
<StepContent
|
|
stepNumber={6}
|
|
title="Generate Resume"
|
|
subtitle="Create your tailored resume"
|
|
icon={<DescriptionIcon sx={{ color: 'action.active' }} />}
|
|
description={[
|
|
'The final step is creating the custom resume for the Candidate tailored to the particular Job. On the bottom right you can click "Next" to have Backstory generate the custom resume.',
|
|
"Note that the resume focuses on identifying key areas from the Candidate's work history that align with skills which were extracted from the original job posting.",
|
|
]}
|
|
imageSrc={finalResumePng}
|
|
imageAlt="Generated custom resume tailored to the job"
|
|
success="Success! You can then click the Copy button to copy the resume into your editor, adjust, and apply for your dream job!"
|
|
reversed={true}
|
|
/>
|
|
</Container>
|
|
</StepSection>
|
|
|
|
{/* CTA Section */}
|
|
<Box
|
|
sx={{
|
|
backgroundColor: 'primary.main',
|
|
color: 'primary.contrastText',
|
|
py: 6,
|
|
}}
|
|
>
|
|
<Container>
|
|
<Box
|
|
sx={{
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
alignItems: 'center',
|
|
textAlign: 'center',
|
|
maxWidth: 600,
|
|
mx: 'auto',
|
|
}}
|
|
>
|
|
<Typography variant="h3" component="h2" gutterBottom sx={{ color: 'white' }}>
|
|
Ready to try Backstory?
|
|
</Typography>
|
|
<Typography variant="h6" sx={{ mb: 4 }}>
|
|
Experience the future of job matching and resume generation today.
|
|
</Typography>
|
|
<Button
|
|
variant="contained"
|
|
size="large"
|
|
startIcon={<PlayArrowIcon />}
|
|
onClick={handleGetStarted}
|
|
sx={{
|
|
backgroundColor: 'action.active',
|
|
color: 'background.paper',
|
|
fontWeight: 'bold',
|
|
px: 4,
|
|
py: 1.5,
|
|
'&:hover': {
|
|
backgroundColor: 'action.active',
|
|
opacity: 0.9,
|
|
},
|
|
}}
|
|
>
|
|
Get Started Now
|
|
</Button>
|
|
</Box>
|
|
</Container>
|
|
</Box>
|
|
</Box>
|
|
);
|
|
};
|
|
|
|
export { HowItWorks };
|