Track cleanup progress and polish profile/system flows

This commit is contained in:
cesnimda
2026-03-23 19:49:41 +01:00
parent fcafda6f52
commit 90fdd8e1a5
14 changed files with 156 additions and 49 deletions
@@ -37,7 +37,7 @@ export default function AuthStatusCard() {
.catch(() => setMe(null));
}, [token]);
const label = useMemo(() => me?.displayName || [me?.firstName, me?.lastName].filter(Boolean).join(" ") || me?.email, [me]);
const label = useMemo(() => me?.displayName || [me?.firstName, me?.lastName].filter(Boolean).join(" ") || me?.userName || me?.email, [me]);
return (
<Paper sx={{ mt: 2, p: 2 }}>
@@ -27,7 +27,7 @@ import AutoAwesomeIcon from "@mui/icons-material/AutoAwesome";
import MailOutlineIcon from "@mui/icons-material/MailOutline";
import { IconButton } from "@mui/material";
import { api } from "../api";
import { api, getApiErrorMessage } from "../api";
import { useToast } from "../toast";
import { CorrespondenceMessage, GmailMessageSummary, GmailStatus } from "../types";
import { useDialogActions } from "../dialogs";
@@ -126,8 +126,7 @@ export default function Correspondence({ jobId }: { jobId: number }) {
});
setGmailMessages(res.data);
} catch (error: any) {
const message = error?.response?.data && typeof error.response.data === "string" ? error.response.data : "Failed to load Gmail messages.";
toast(message, "error");
toast(getApiErrorMessage(error, "Failed to load Gmail messages."), "error");
} finally {
setGmailMessagesLoading(false);
}
@@ -206,8 +205,8 @@ export default function Correspondence({ jobId }: { jobId: number }) {
await api.post("/correspondence", { jobApplicationId: jobId, from, content: text });
setText("");
await load();
} catch {
toast("Failed to add message.", "error");
} catch (error) {
toast(getApiErrorMessage(error, "Failed to add message."), "error");
}
};
@@ -231,8 +230,8 @@ export default function Correspondence({ jobId }: { jobId: number }) {
setRawEmail("");
await load();
toast("Email logged.", "success");
} catch {
toast("Failed to import email.", "error");
} catch (error) {
toast(getApiErrorMessage(error, "Failed to import email."), "error");
}
};
@@ -241,8 +240,8 @@ export default function Correspondence({ jobId }: { jobId: number }) {
const res = await api.get<{ url: string }>("/gmail/connect-url");
const popup = window.open(res.data.url, "jobtracker-gmail-connect", "width=620,height=760,resizable=yes,scrollbars=yes");
if (!popup) toast("Your browser blocked the Gmail popup.", "error");
} catch {
toast("Failed to start Gmail connection.", "error");
} catch (error) {
toast(getApiErrorMessage(error, "Failed to start Gmail connection."), "error");
}
};
@@ -252,8 +251,8 @@ export default function Correspondence({ jobId }: { jobId: number }) {
setGmailStatus({ connected: false });
setGmailMessages([]);
toast("Gmail disconnected.", "success");
} catch {
toast("Failed to disconnect Gmail.", "error");
} catch (error) {
toast(getApiErrorMessage(error, "Failed to disconnect Gmail."), "error");
}
};
@@ -263,8 +262,8 @@ export default function Correspondence({ jobId }: { jobId: number }) {
await api.delete(`/correspondence/${messageId}`);
await load();
toast("Message removed.", "success");
} catch {
toast("Failed to remove message.", "error");
} catch (error) {
toast(getApiErrorMessage(error, "Failed to remove message."), "error");
}
};
@@ -275,8 +274,7 @@ export default function Correspondence({ jobId }: { jobId: number }) {
await load();
toast("Email imported from Gmail.", "success");
} catch (error: any) {
const message = error?.response?.data && typeof error.response.data === "string" ? error.response.data : "Failed to import Gmail message.";
toast(message, "error");
toast(getApiErrorMessage(error, "Failed to import Gmail message."), "error");
} finally {
setImportingMessageId(null);
}
@@ -289,8 +287,7 @@ export default function Correspondence({ jobId }: { jobId: number }) {
await load();
toast(`Imported ${res.data.imported} messages${res.data.skipped ? `, skipped ${res.data.skipped} duplicates` : ""}.`, "success");
} catch (error: any) {
const message = error?.response?.data && typeof error.response.data === "string" ? error.response.data : "Failed to import Gmail thread.";
toast(message, "error");
toast(getApiErrorMessage(error, "Failed to import Gmail thread."), "error");
} finally {
setImportingThreadId(null);
}
@@ -16,6 +16,7 @@ declare global {
type MeResponse = {
provider?: "local" | "google" | "external";
email?: string;
userName?: string;
displayName?: string;
firstName?: string;
lastName?: string;
@@ -153,7 +154,7 @@ export default function GoogleAuthCard({ onSignedIn }: { onSignedIn?: () => void
};
}, [clientId, me?.provider, me?.googleLink?.linked, onSignedIn, isRawGoogleToken, token, toast, t]);
const signedInName = me?.displayName || [me?.firstName, me?.lastName].filter(Boolean).join(" ") || me?.email || "";
const signedInName = me?.displayName || [me?.firstName, me?.lastName].filter(Boolean).join(" ") || me?.userName || me?.email || "";
return (
<Paper sx={{ mt: 2, p: 2 }}>
@@ -18,7 +18,7 @@ import {
Typography,
} from "@mui/material";
import { api } from "../api";
import { api, getApiErrorMessage } from "../api";
import { ApplicationPackageResponse, CandidateFit, InterviewPrepResponse, JobApplication, ReadinessResponse } from "../types";
import { useToast } from "../toast";
import { useDialogActions } from "../dialogs";
@@ -216,7 +216,7 @@ export default function JobDetailsDialog({ open, jobId, onClose }: Props) {
setJob(res.data);
toast("Summary and skills refreshed.", "success");
} catch (error: any) {
toast(error?.response?.data || "Failed to refresh summary and skills.", "error");
toast(getApiErrorMessage(error, "Failed to refresh summary and skills."), "error");
} finally {
setRefreshingAi(false);
}
@@ -277,7 +277,7 @@ export default function JobDetailsDialog({ open, jobId, onClose }: Props) {
setTailoredCvText(res.data.tailoredCvText ?? "");
toast("Application package generated.", "success");
} catch (error: any) {
toast(error?.response?.data || "Failed to generate application package.", "error");
toast(getApiErrorMessage(error, "Failed to generate application package."), "error");
} finally {
setGeneratingPackage(false);
}
@@ -294,7 +294,7 @@ export default function JobDetailsDialog({ open, jobId, onClose }: Props) {
setInterviewPrep(null);
toast("Tailored CV saved.", "success");
} catch (error: any) {
toast(error?.response?.data || "Failed to save tailored CV.", "error");
toast(getApiErrorMessage(error, "Failed to save tailored CV."), "error");
} finally {
setSavingTailoredCv(false);
}
@@ -317,7 +317,7 @@ export default function JobDetailsDialog({ open, jobId, onClose }: Props) {
setReadiness(null);
toast("Cover letter saved to this job.", "success");
} catch (error: any) {
toast(error?.response?.data || "Failed to save cover letter.", "error");
toast(getApiErrorMessage(error, "Failed to save cover letter."), "error");
} finally {
setSavingApplicationDrafts(false);
}
@@ -330,7 +330,7 @@ export default function JobDetailsDialog({ open, jobId, onClose }: Props) {
setReadiness(null);
toast("Application answer saved to notes.", "success");
} catch (error: any) {
toast(error?.response?.data || "Failed to save application answer.", "error");
toast(getApiErrorMessage(error, "Failed to save application answer."), "error");
} finally {
setSavingApplicationDrafts(false);
}
@@ -343,7 +343,7 @@ export default function JobDetailsDialog({ open, jobId, onClose }: Props) {
setJob((prev) => prev ? { ...prev, recruiterMessageDraft: content } : prev);
toast("Recruiter message saved to this job.", "success");
} catch (error: any) {
toast(error?.response?.data || "Failed to save recruiter message.", "error");
toast(getApiErrorMessage(error, "Failed to save recruiter message."), "error");
} finally {
setSavingApplicationDrafts(false);
}
@@ -374,7 +374,7 @@ export default function JobDetailsDialog({ open, jobId, onClose }: Props) {
setReadiness(null);
toast("Follow-up sent and logged.", "success");
} catch (error: any) {
toast(error?.response?.data || "Failed to send follow-up.", "error");
toast(getApiErrorMessage(error, "Failed to send follow-up."), "error");
} finally {
setSendingDraft(false);
}