Add OAth flow for Gmail and update tables and UI
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
DialogTitle,
|
||||
Tab,
|
||||
Tabs,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
|
||||
@@ -55,12 +56,16 @@ export default function JobDetailsDialog({ open, jobId, onClose }: Props) {
|
||||
const [isAdmin, setIsAdmin] = useState(false);
|
||||
const [followUpDraft, setFollowUpDraft] = useState<FollowUpDraft | null>(null);
|
||||
const [loadingDraft, setLoadingDraft] = useState(false);
|
||||
const [sendingDraft, setSendingDraft] = useState(false);
|
||||
const [draftRecipient, setDraftRecipient] = useState("");
|
||||
const [draftSubject, setDraftSubject] = useState("");
|
||||
const [draftBody, setDraftBody] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
if (!open || !jobId) return;
|
||||
setTab(0);
|
||||
setFollowUpDraft(null);
|
||||
api.get<JobApplication>(`/jobapplications/${jobId}`).then((r) => setJob(r.data));
|
||||
api.get<JobApplication>(`/jobapplications/${jobId}`).then((r) => { setJob(r.data); setDraftRecipient(r.data.company?.recruiterEmail ?? ""); });
|
||||
api
|
||||
.get(`/auth/me`)
|
||||
.then((r) => setIsAdmin(Boolean(r.data?.roles?.includes("Admin"))))
|
||||
@@ -76,7 +81,7 @@ export default function JobDetailsDialog({ open, jobId, onClose }: Props) {
|
||||
setLoadingDraft(true);
|
||||
api
|
||||
.get<FollowUpDraft>(`/jobapplications/${jobId}/followup-draft`)
|
||||
.then((r) => setFollowUpDraft(r.data))
|
||||
.then((r) => { setFollowUpDraft(r.data); setDraftSubject(r.data.subject); setDraftBody(r.data.body); })
|
||||
.catch(() => setFollowUpDraft(null))
|
||||
.finally(() => setLoadingDraft(false));
|
||||
}, [open, jobId, tab, followUpDraft]);
|
||||
@@ -216,17 +221,31 @@ export default function JobDetailsDialog({ open, jobId, onClose }: Props) {
|
||||
<Typography variant="overline">Suggested send date</Typography>
|
||||
<Typography>{new Date(followUpDraft.suggestedSendOn).toLocaleDateString()}</Typography>
|
||||
</Box>
|
||||
<Box>
|
||||
<Typography variant="overline">Subject</Typography>
|
||||
<Typography sx={{ fontWeight: 700 }}>{followUpDraft.subject}</Typography>
|
||||
</Box>
|
||||
<Box>
|
||||
<Typography variant="overline">Draft</Typography>
|
||||
<Typography sx={{ whiteSpace: "pre-wrap" }}>{followUpDraft.body}</Typography>
|
||||
</Box>
|
||||
<Box sx={{ display: "flex", justifyContent: "flex-end" }}>
|
||||
<Button variant="contained" onClick={() => navigator.clipboard.writeText(`${followUpDraft.subject}\n\n${followUpDraft.body}`)}>
|
||||
Copy draft
|
||||
<TextField label="Recipient" value={draftRecipient} onChange={(e) => setDraftRecipient(e.target.value)} helperText="Defaults to the company recruiter email when available." />
|
||||
<TextField label="Subject" value={draftSubject} onChange={(e) => setDraftSubject(e.target.value)} />
|
||||
<TextField label="Draft" multiline minRows={8} value={draftBody} onChange={(e) => setDraftBody(e.target.value)} />
|
||||
<Box sx={{ display: "flex", justifyContent: "space-between", gap: 1, flexWrap: "wrap" }}>
|
||||
<Button variant="outlined" onClick={() => navigator.clipboard.writeText(`${draftSubject}\n\n${draftBody}`)}>Copy draft</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
disabled={sendingDraft || !draftSubject.trim() || !draftBody.trim()}
|
||||
onClick={async () => {
|
||||
if (!jobId) return;
|
||||
setSendingDraft(true);
|
||||
try {
|
||||
await api.post(`/jobapplications/${jobId}/send-followup`, {
|
||||
toEmail: draftRecipient || null,
|
||||
subject: draftSubject,
|
||||
body: draftBody,
|
||||
nextFollowUpAt: followUpDraft.suggestedSendOn || null,
|
||||
});
|
||||
setJob((prev) => prev ? { ...prev, followUpAt: followUpDraft.suggestedSendOn } : prev);
|
||||
} finally {
|
||||
setSendingDraft(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{sendingDraft ? "Sending..." : "Send and log email"}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
Reference in New Issue
Block a user