Files
jobtrackingapp/job-tracker-ui/src/views/MicrosoftLegacyRelinkPage.tsx
T

65 lines
2.9 KiB
TypeScript

import React, { useState } from "react";
import { Alert, Box, Button, CircularProgress, Typography } from "@mui/material";
import { useNavigate } from "react-router-dom";
import { api, getApiErrorMessage } from "../api";
import { getMicrosoftMsalInstance } from "../components/MicrosoftAuthCard";
import { useI18n } from "../i18n/I18nProvider";
import AuthPageFrame from "../layout/AuthPageFrame";
export default function MicrosoftLegacyRelinkPage() {
const { t } = useI18n();
const navigate = useNavigate();
const [working, setWorking] = useState(false);
const [success, setSuccess] = useState(false);
const [error, setError] = useState<string | null>(null);
const params = new URLSearchParams(window.location.search);
const userId = params.get("userId") || "";
const tenantId = params.get("tenantId") || "";
const objectId = params.get("objectId") || "";
const recoveryToken = params.get("token") || "";
const clientId = (process.env.NEXT_PUBLIC_MICROSOFT_CLIENT_ID || "").trim();
const missing = !userId || !tenantId || !objectId || !recoveryToken || !clientId;
async function confirm() {
setWorking(true);
setError(null);
try {
const msal = getMicrosoftMsalInstance(clientId);
await msal.initialize();
const result = await msal.loginPopup({ scopes: ["openid", "profile", "email"] });
if (!result.idToken) throw new Error(t("microsoftAuthFailed"));
await api.post("/auth/microsoft/legacy-relink/confirm", {
userId,
tenantId,
objectId,
recoveryToken,
microsoftToken: result.idToken,
});
setSuccess(true);
} catch (e: any) {
setError(getApiErrorMessage(e, t("microsoftLegacyRelinkFailed")));
} finally {
setWorking(false);
}
}
return (
<AuthPageFrame title={t("microsoftLegacyRelinkTitle")} description={t("microsoftLegacyRelinkBody")}>
{missing ? <Alert severity="error" sx={{ mt: 2 }}>{t("microsoftLegacyRelinkMissing")}</Alert> : null}
{error ? <Alert severity="error" sx={{ mt: 2 }}>{error}</Alert> : null}
{success ? <Alert severity="success" role="status" sx={{ mt: 2 }}>{t("microsoftLegacyRelinkSuccess")}</Alert> : null}
<Box sx={{ display: "flex", flexWrap: "wrap", justifyContent: "flex-end", gap: 1, mt: 3, "& > button": { maxWidth: "100%", whiteSpace: "normal", overflowWrap: "anywhere" } }}>
<Button onClick={() => navigate("/login")}>{t("backToLogin")}</Button>
{!success ? (
<Button variant="contained" disabled={missing || working} aria-busy={working} startIcon={working ? <CircularProgress size={20} aria-hidden="true" /> : undefined} onClick={() => void confirm()}>
{t("continueWithMicrosoft")}
</Button>
) : null}
</Box>
{working ? <Typography role="status" aria-live="polite" variant="body2" color="text.secondary" sx={{ mt: 1.5 }}>{t("loading")}</Typography> : null}
</AuthPageFrame>
);
}