Added question editing
This commit is contained in:
parent
4a95c72a6f
commit
1e04f2e070
@ -104,7 +104,7 @@ const capitalize = (str: string): string => {
|
||||
};
|
||||
|
||||
// Main component
|
||||
const JobAnalysisPage: React.FC<BackstoryPageProps> = (_props: BackstoryPageProps) => {
|
||||
const JobAnalysisPage: React.FC<BackstoryPageProps> = () => {
|
||||
const theme = useTheme();
|
||||
const { user, guest } = useAuth();
|
||||
const { selectedCandidate, setSelectedCandidate } = useSelectedCandidate();
|
||||
|
@ -13,7 +13,6 @@ import {
|
||||
Tab,
|
||||
useMediaQuery,
|
||||
CircularProgress,
|
||||
Snackbar,
|
||||
Alert,
|
||||
Card,
|
||||
CardContent,
|
||||
@ -49,7 +48,6 @@ import {
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { useAuth } from 'hooks/AuthContext';
|
||||
import * as Types from 'types/types';
|
||||
import { ComingSoon } from 'components/ui/ComingSoon';
|
||||
import { BackstoryPageProps } from 'components/BackstoryTab';
|
||||
import { useAppState } from 'hooks/GlobalContext';
|
||||
|
||||
@ -98,9 +96,9 @@ function TabPanel(props: TabPanelProps): JSX.Element {
|
||||
);
|
||||
}
|
||||
|
||||
const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPageProps) => {
|
||||
const { setSnack } = useAppState();
|
||||
const CandidateProfile: React.FC = () => {
|
||||
const theme = useTheme();
|
||||
const { setSnack } = useAppState();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
||||
const { user, updateUserData, apiClient } = useAuth();
|
||||
|
||||
@ -111,15 +109,6 @@ const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPagePro
|
||||
const [tabValue, setTabValue] = useState<string>('info');
|
||||
const [editMode, setEditMode] = useState<{ [key: string]: boolean }>({});
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [snackbar, setSnackbar] = useState<{
|
||||
open: boolean;
|
||||
message: string;
|
||||
severity: 'success' | 'error' | 'info' | 'warning';
|
||||
}>({
|
||||
open: false,
|
||||
message: '',
|
||||
severity: 'success',
|
||||
});
|
||||
|
||||
// Form data state
|
||||
const [formData, setFormData] = useState<Partial<Types.Candidate>>({});
|
||||
@ -137,6 +126,11 @@ const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPagePro
|
||||
level: 'beginner',
|
||||
yearsOfExperience: 0,
|
||||
});
|
||||
|
||||
const [newQuestion, setNewQuestion] = useState<Partial<Types.CandidateQuestion>>({
|
||||
question: '',
|
||||
});
|
||||
|
||||
const [newExperience, setNewExperience] = useState<Partial<Types.WorkExperience>>({
|
||||
companyName: '',
|
||||
position: '',
|
||||
@ -155,7 +149,6 @@ const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPagePro
|
||||
} else {
|
||||
setProfileImage('');
|
||||
}
|
||||
console.log({ isPublic: candidate.isPublic });
|
||||
}
|
||||
}, [candidate]);
|
||||
|
||||
@ -195,19 +188,11 @@ const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPagePro
|
||||
console.log(`Set profile image to: ${candidate.profileImage}`);
|
||||
updateUserData(candidate);
|
||||
} else {
|
||||
setSnackbar({
|
||||
open: true,
|
||||
message: 'Failed to upload profile image. Please try again.',
|
||||
severity: 'error',
|
||||
});
|
||||
setSnack('Failed to upload profile image. Please try again.', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error uploading profile image:', error);
|
||||
setSnackbar({
|
||||
open: true,
|
||||
message: 'Failed to upload profile image. Please try again.',
|
||||
severity: 'error',
|
||||
});
|
||||
setSnack('Failed to upload profile image. Please try again.', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
@ -230,11 +215,7 @@ const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPagePro
|
||||
toggleEditMode(section);
|
||||
}
|
||||
} catch (error) {
|
||||
setSnackbar({
|
||||
open: true,
|
||||
message: 'Failed to update profile. Please try again.',
|
||||
severity: 'error',
|
||||
});
|
||||
setSnack('Failed to update profile. Please try again.', 'error');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@ -258,6 +239,7 @@ const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPagePro
|
||||
yearsOfExperience: 0,
|
||||
});
|
||||
setSkillDialog(false);
|
||||
setSnack('Skill added successfully!');
|
||||
}
|
||||
};
|
||||
|
||||
@ -265,6 +247,30 @@ const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPagePro
|
||||
const handleRemoveSkill = (index: number): void => {
|
||||
const updatedSkills = (formData.skills || []).filter((_, i) => i !== index);
|
||||
setFormData({ ...formData, skills: updatedSkills });
|
||||
setSnack('Skill removed successfully!');
|
||||
};
|
||||
|
||||
// Add new question
|
||||
const handleAddQuestion = (): void => {
|
||||
if (newQuestion.question?.trim()) {
|
||||
const questionToAdd: Types.CandidateQuestion = {
|
||||
question: newQuestion.question.trim(),
|
||||
};
|
||||
const updatedQuestions = [...(formData.questions || []), questionToAdd];
|
||||
setFormData({ ...formData, questions: updatedQuestions });
|
||||
setNewQuestion({
|
||||
question: '',
|
||||
});
|
||||
setQuestionDialog(false);
|
||||
setSnack('Question added successfully!');
|
||||
}
|
||||
};
|
||||
|
||||
// Remove question
|
||||
const handleRemoveQuestion = (index: number): void => {
|
||||
const updatedQuestions = (formData.questions || []).filter((_, i) => i !== index);
|
||||
setFormData({ ...formData, questions: updatedQuestions });
|
||||
setSnack('Question removed successfully!');
|
||||
};
|
||||
|
||||
// Add new work experience
|
||||
@ -285,6 +291,7 @@ const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPagePro
|
||||
location: { city: '', country: '' },
|
||||
});
|
||||
setExperienceDialog(false);
|
||||
setSnack('Experience added successfully!');
|
||||
}
|
||||
};
|
||||
|
||||
@ -292,6 +299,7 @@ const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPagePro
|
||||
const handleRemoveExperience = (index: number): void => {
|
||||
const updatedExperience = (formData.experience || []).filter((_, i) => i !== index);
|
||||
setFormData({ ...formData, experience: updatedExperience });
|
||||
setSnack('Experience removed successfully!');
|
||||
};
|
||||
|
||||
// Basic Information Tab
|
||||
@ -676,14 +684,27 @@ const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPagePro
|
||||
sx={{
|
||||
fontSize: { xs: '0.9rem', sm: '1.25rem' },
|
||||
wordBreak: 'break-word',
|
||||
mb: 1,
|
||||
}}
|
||||
>
|
||||
{question.question}
|
||||
</Typography>
|
||||
{/* {question.category && (
|
||||
<Chip
|
||||
size="small"
|
||||
label={question.category}
|
||||
color="secondary"
|
||||
variant="outlined"
|
||||
sx={{
|
||||
fontSize: { xs: '0.65rem', sm: '0.75rem' },
|
||||
height: { xs: 20, sm: 24 },
|
||||
}}
|
||||
/>
|
||||
)} */}
|
||||
</Box>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={(): void => handleRemoveSkill(index)}
|
||||
onClick={(): void => handleRemoveQuestion(index)}
|
||||
color="error"
|
||||
sx={{ ml: 1 }}
|
||||
>
|
||||
@ -696,7 +717,7 @@ const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPagePro
|
||||
))}
|
||||
</Grid>
|
||||
|
||||
{(!formData.skills || formData.skills.length === 0) && (
|
||||
{(!formData.questions || formData.questions.length === 0) && (
|
||||
<Typography variant="body2" color="text.secondary" sx={{ textAlign: 'center', py: 4 }}>
|
||||
No questions added yet. Click "Add Question" to get started.
|
||||
</Typography>
|
||||
@ -855,19 +876,17 @@ const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPagePro
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
{(!formData.experience || formData.experience.length === 0) && (
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
sx={{
|
||||
textAlign: 'center',
|
||||
py: { xs: 2, sm: 4 },
|
||||
fontSize: { xs: '0.8rem', sm: '0.875rem' },
|
||||
}}
|
||||
>
|
||||
No work experience added yet. Click "Add Experience" to get started.
|
||||
</Typography>
|
||||
)}
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
sx={{
|
||||
textAlign: 'center',
|
||||
py: { xs: 2, sm: 4 },
|
||||
fontSize: { xs: '0.8rem', sm: '0.875rem' },
|
||||
}}
|
||||
>
|
||||
No education added yet. Click "Add Education" to get started.
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@ -947,15 +966,15 @@ const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPagePro
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel value="skills" active={tabValue}>
|
||||
<ComingSoon>{renderSkills()}</ComingSoon>
|
||||
{renderSkills()}
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel value="experience" active={tabValue}>
|
||||
<ComingSoon>{renderExperience()}</ComingSoon>
|
||||
{renderExperience()}
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel value="education" active={tabValue}>
|
||||
<ComingSoon>{renderEducation()}</ComingSoon>
|
||||
{renderEducation()}
|
||||
</TabPanel>
|
||||
</Paper>
|
||||
|
||||
@ -1012,7 +1031,7 @@ const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPagePro
|
||||
onChange={(e): void =>
|
||||
setNewSkill({
|
||||
...newSkill,
|
||||
level: e.target.value as Types.SkillLevel,
|
||||
level: e.target.value as 'beginner' | 'intermediate' | 'advanced' | 'expert',
|
||||
})
|
||||
}
|
||||
label="Proficiency Level"
|
||||
@ -1066,6 +1085,104 @@ const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPagePro
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
{/* Add Question Dialog */}
|
||||
<Dialog
|
||||
open={questionDialog}
|
||||
onClose={(): void => setQuestionDialog(false)}
|
||||
maxWidth="sm"
|
||||
fullWidth
|
||||
fullScreen={isMobile}
|
||||
PaperProps={{
|
||||
sx: {
|
||||
...(isMobile && {
|
||||
margin: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
maxHeight: '100%',
|
||||
}),
|
||||
},
|
||||
}}
|
||||
>
|
||||
<DialogTitle sx={{ pb: { xs: 1, sm: 2 } }}>Add New Question</DialogTitle>
|
||||
<DialogContent
|
||||
sx={{
|
||||
overflow: 'auto',
|
||||
pt: { xs: 1, sm: 2 },
|
||||
}}
|
||||
>
|
||||
<Grid container spacing={{ xs: 1.5, sm: 2 }} sx={{ mt: 0.5, maxWidth: '100%' }}>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<TextField
|
||||
fullWidth
|
||||
multiline
|
||||
rows={isMobile ? 3 : 4}
|
||||
label="Question"
|
||||
value={newQuestion.question || ''}
|
||||
onChange={(e): void => setNewQuestion({ ...newQuestion, question: e.target.value })}
|
||||
placeholder="What would you potential employers to ask about you?"
|
||||
size={isMobile ? 'small' : 'medium'}
|
||||
/>
|
||||
</Grid>
|
||||
{/* <Grid size={{ xs: 12, sm: 8 }}>
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Category (Optional)"
|
||||
value={newQuestion.category || ''}
|
||||
onChange={(e): void => setNewQuestion({ ...newQuestion, category: e.target.value })}
|
||||
placeholder="e.g., General, Technical, Behavioral"
|
||||
size={isMobile ? 'small' : 'medium'}
|
||||
/>
|
||||
</Grid> */}
|
||||
{/* <Grid size={{ xs: 12, sm: 4 }}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={newQuestion.isActive !== false}
|
||||
onChange={(e): void =>
|
||||
setNewQuestion({
|
||||
...newQuestion,
|
||||
isActive: e.target.checked,
|
||||
})
|
||||
}
|
||||
size={isMobile ? 'small' : 'medium'}
|
||||
/>
|
||||
}
|
||||
label="Active"
|
||||
sx={{
|
||||
'& .MuiFormControlLabel-label': {
|
||||
fontSize: { xs: '0.875rem', sm: '1rem' },
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Grid> */}
|
||||
</Grid>
|
||||
</DialogContent>
|
||||
<DialogActions
|
||||
sx={{
|
||||
p: { xs: 1.5, sm: 3 },
|
||||
flexDirection: { xs: 'column', sm: 'row' },
|
||||
gap: { xs: 1, sm: 0 },
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
onClick={(): void => setQuestionDialog(false)}
|
||||
fullWidth={isMobile}
|
||||
size={isMobile ? 'small' : 'medium'}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleAddQuestion}
|
||||
variant="contained"
|
||||
fullWidth={isMobile}
|
||||
size={isMobile ? 'small' : 'medium'}
|
||||
disabled={!newQuestion.question?.trim()}
|
||||
>
|
||||
Add Question
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
{/* Add Experience Dialog */}
|
||||
<Dialog
|
||||
open={experienceDialog}
|
||||
@ -1201,21 +1318,6 @@ const CandidateProfile: React.FC<BackstoryPageProps> = (_props: BackstoryPagePro
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
{/* Snackbar for notifications */}
|
||||
<Snackbar
|
||||
open={snackbar.open}
|
||||
autoHideDuration={6000}
|
||||
onClose={(): void => setSnackbar({ ...snackbar, open: false })}
|
||||
>
|
||||
<Alert
|
||||
onClose={(): void => setSnackbar({ ...snackbar, open: false })}
|
||||
severity={snackbar.severity}
|
||||
sx={{ width: '100%' }}
|
||||
>
|
||||
{snackbar.message}
|
||||
</Alert>
|
||||
</Snackbar>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user