Track cleanup progress and polish profile/system flows
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user