feat: advance phase 5 AI workflow
This commit is contained in:
@@ -7,12 +7,14 @@ import {
|
||||
Autocomplete,
|
||||
Box,
|
||||
Button,
|
||||
Checkbox,
|
||||
Chip,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
Divider,
|
||||
FormControlLabel,
|
||||
IconButton,
|
||||
List,
|
||||
ListItem,
|
||||
@@ -136,6 +138,7 @@ export default function AddJobModal({ open, onClose, onCreated, initialUrl }: Pr
|
||||
|
||||
const [tags, setTags] = useState<string[]>([]);
|
||||
const [notes, setNotes] = useState("");
|
||||
const [generateTailoredCv, setGenerateTailoredCv] = useState(false);
|
||||
const [attachments, setAttachments] = useState<AttachmentBuckets>(() => emptyAttachmentBuckets());
|
||||
|
||||
useEffect(() => {
|
||||
@@ -179,6 +182,7 @@ export default function AddJobModal({ open, onClose, onCreated, initialUrl }: Pr
|
||||
setDescriptionLanguage("");
|
||||
setTags([]);
|
||||
setNotes("");
|
||||
setGenerateTailoredCv(false);
|
||||
setAttachments(emptyAttachmentBuckets());
|
||||
setDuplicateCheck(null);
|
||||
};
|
||||
@@ -339,6 +343,14 @@ export default function AddJobModal({ open, onClose, onCreated, initialUrl }: Pr
|
||||
dateApplied,
|
||||
});
|
||||
|
||||
if (response.data?.id && generateTailoredCv) {
|
||||
try {
|
||||
await api.post(`/jobapplications/${response.data.id}/generate-tailored-cv-draft`);
|
||||
} catch (error: any) {
|
||||
toast(getApiErrorMessage(error, "Job created, but the tailored CV could not be generated."), "warning");
|
||||
}
|
||||
}
|
||||
|
||||
if (response.data?.id && attachmentCount > 0) {
|
||||
try {
|
||||
await uploadAttachments(response.data.id);
|
||||
@@ -587,7 +599,11 @@ export default function AddJobModal({ open, onClose, onCreated, initialUrl }: Pr
|
||||
{activeStep === 5 ? "Certificates, references, and other supporting documents are optional." : null}
|
||||
</Typography>
|
||||
</Box>
|
||||
{activeStep === 2 ? uploadField("resume", t("addJobModalResume"), t("addJobModalResumeHelp")) : null}
|
||||
{activeStep === 2 ? <>
|
||||
<FormControlLabel control={<Checkbox checked={generateTailoredCv} onChange={(event) => setGenerateTailoredCv(event.target.checked)} />} label="Generate a tailored CV draft after creating this job" />
|
||||
<Typography variant="caption" sx={{ color: "text.secondary", mt: -1 }}>Uses your reviewed Career Profile and keeps the result as an editable suggestion.</Typography>
|
||||
{uploadField("resume", t("addJobModalResume"), t("addJobModalResumeHelp"))}
|
||||
</> : null}
|
||||
{activeStep === 3 ? uploadField("coverLetter", t("addJobModalCoverLetter"), t("addJobModalCoverLetterHelp")) : null}
|
||||
{activeStep === 4 ? uploadField("portfolio", t("addJobModalPortfolio"), t("addJobModalPortfolioHelp")) : null}
|
||||
{activeStep === 5 ? uploadField("other", t("addJobModalOtherFiles"), t("addJobModalOtherFilesHelp")) : null}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import { ToastProvider } from './toast';
|
||||
import { I18nProvider } from './i18n/I18nProvider';
|
||||
import { api } from './api';
|
||||
@@ -68,3 +68,22 @@ test('does not auto-import when no initialUrl is given', async () => {
|
||||
expect(await screen.findByRole('dialog')).toBeInTheDocument();
|
||||
expect(mockedApi.post).not.toHaveBeenCalledWith('/jobimport/preview', expect.anything());
|
||||
});
|
||||
|
||||
|
||||
test('can generate a tailored CV after creating a job', async () => {
|
||||
mockedApi.post.mockImplementation((url: string) => {
|
||||
if (url === '/jobimport/preview') return Promise.resolve({ data: { success: true, title: 'Imported Backend Role', company: 'Acme', description: 'desc' } } as any);
|
||||
if (url === '/companies') return Promise.resolve({ data: { id: 1, name: 'Acme' } } as any);
|
||||
if (url === '/jobapplications') return Promise.resolve({ data: { id: 42 } } as any);
|
||||
return Promise.resolve({ data: {} } as any);
|
||||
});
|
||||
renderModal('https://example.com/jobs/123');
|
||||
|
||||
expect(await screen.findByDisplayValue('Imported Backend Role')).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Continue' }));
|
||||
fireEvent.click(await screen.findByLabelText('Generate a tailored CV draft after creating this job'));
|
||||
for (let step = 0; step < 3; step += 1) fireEvent.click(screen.getByRole('button', { name: 'Skip and continue' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: /create job/i }));
|
||||
|
||||
await waitFor(() => expect(mockedApi.post).toHaveBeenCalledWith('/jobapplications/42/generate-tailored-cv-draft'));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user