fix(auth): bind mailbox callbacks to pending popup

This commit is contained in:
cesnimda
2026-10-17 10:27:45 +02:00
parent c5176e3251
commit dac29278db
19 changed files with 1403 additions and 38 deletions
@@ -44,6 +44,7 @@ import {
import { useDialogActions } from "../dialogs";
import { useI18n } from "../i18n/I18nProvider";
import ViewStateNotice from "./ViewStateNotice";
import { emailOAuthCallbackOrigin, emailOAuthMessage, type EmailOAuthAttempt } from "../emailOAuth";
function parseRawEmail(raw: string): { subject?: string; date?: string; from?: string; to?: string; body: string } {
const lines = raw.replace(/\r\n/g, "\n").split("\n");
@@ -155,6 +156,16 @@ export default function Correspondence({ jobId, jobContext }: { jobId: number; j
const [manageNote, setManageNote] = useState("");
const [manageSaving, setManageSaving] = useState(false);
const autoRefreshKeyRef = useRef<string | null>(null);
const gmailOAuth = useRef<{ active: boolean; generation: number; starting: boolean; attempt: EmailOAuthAttempt | null }>({ active: true, generation: 0, starting: false, attempt: null });
const startupTranslation = useRef(t);
useEffect(() => { startupTranslation.current = t; }, [t]);
useEffect(() => {
const session = gmailOAuth.current;
session.active = true;
return () => { session.active = false; session.generation += 1; session.starting = false; session.attempt = null; };
}, [jobId]);
const load = useCallback(async () => {
setMessagesLoading(true);
@@ -292,8 +303,11 @@ export default function Correspondence({ jobId, jobContext }: { jobId: number; j
useEffect(() => {
const onMessage = (event: MessageEvent) => {
const data = event.data as { source?: string; status?: string; message?: string };
if (data?.source !== "jobtracker-gmail-oauth") return;
const session = gmailOAuth.current;
if (!session.active || !session.attempt) return;
const data = emailOAuthMessage(event, session.attempt);
if (!data) return;
session.attempt = null;
if (data.status === "connected") {
toast(data.message || t("googleLinkedSuccess"), "success");
void loadGmailStatus();
@@ -356,12 +370,24 @@ export default function Correspondence({ jobId, jobContext }: { jobId: number; j
};
const connectGmail = async () => {
const session = gmailOAuth.current;
if (!session.active || session.starting) return;
if (session.attempt && !session.attempt.popup.closed) { session.attempt.popup.focus(); return; }
session.attempt = null;
session.starting = true;
const generation = session.generation;
try {
const res = await api.get<{ url: string }>("/gmail/connect-url");
if (!session.active || generation !== session.generation) return;
const origin = emailOAuthCallbackOrigin(res.data.url, "gmail");
if (!origin) { toast(startupTranslation.current("correspondenceStartGmailFailed"), "error"); return; }
const popup = window.open(res.data.url, "jobtracker-gmail-connect", "width=620,height=760,resizable=yes,scrollbars=yes");
if (!popup) toast(t("correspondenceBlockedPopup"), "error");
if (!popup) toast(startupTranslation.current("correspondenceBlockedPopup"), "error");
else session.attempt = { provider: "gmail", origin, popup };
} catch (error) {
toast(getApiErrorMessage(error, t("correspondenceStartGmailFailed")), "error");
if (session.active && generation === session.generation) toast(getApiErrorMessage(error, startupTranslation.current("correspondenceStartGmailFailed")), "error");
} finally {
if (generation === session.generation) session.starting = false;
}
};