87 lines
4.1 KiB
JavaScript
87 lines
4.1 KiB
JavaScript
import Alert from "@mui/material/Alert";
|
|
import Box from "@mui/material/Box";
|
|
import Button from "@mui/material/Button";
|
|
import Card from "@mui/material/Card";
|
|
import CardContent from "@mui/material/CardContent";
|
|
import Stack from "@mui/material/Stack";
|
|
import TextField from "@mui/material/TextField";
|
|
import Typography from "@mui/material/Typography";
|
|
import { useState } from "react";
|
|
import { useNavigate } from "react-router-dom";
|
|
import { AppIdentity } from "@/shared/ui/AppIdentity.jsx";
|
|
import { useExternalAuth } from "../auth/ExternalAuthProvider.jsx";
|
|
import { useExternalI18n } from "../i18n/ExternalI18nProvider.jsx";
|
|
import { LanguageSwitcher } from "../i18n/LanguageSwitcher.jsx";
|
|
import { translateExternalError } from "../i18n/errors.js";
|
|
import { useExternalSessionBrand } from "../shared/useExternalSessionBrand.js";
|
|
|
|
export default function ChangePasswordPage() {
|
|
const { changePassword, logout, session } = useExternalAuth();
|
|
const { t } = useExternalI18n();
|
|
const [form, setForm] = useState({ confirmPassword: "", newPassword: "", oldPassword: "" });
|
|
const [error, setError] = useState("");
|
|
const [submitting, setSubmitting] = useState(false);
|
|
const navigate = useNavigate();
|
|
useExternalSessionBrand(session, t("app.title"));
|
|
|
|
const submit = async (event) => {
|
|
event.preventDefault();
|
|
if (!form.newPassword.trim()) {
|
|
setError(t("auth.passwordWhitespace"));
|
|
return;
|
|
}
|
|
if (form.newPassword.length < 8) {
|
|
setError(t("auth.passwordMinError"));
|
|
return;
|
|
}
|
|
if (form.newPassword !== form.confirmPassword) {
|
|
setError(t("auth.passwordMismatch"));
|
|
return;
|
|
}
|
|
setSubmitting(true);
|
|
setError("");
|
|
try {
|
|
await changePassword({ newPassword: form.newPassword, oldPassword: form.oldPassword });
|
|
navigate("/overview", { replace: true });
|
|
} catch (requestError) {
|
|
setError(translateExternalError(requestError, t, "auth.passwordChangedFailed"));
|
|
} finally {
|
|
setSubmitting(false);
|
|
}
|
|
};
|
|
|
|
const cancel = async () => {
|
|
await logout();
|
|
navigate("/login", { replace: true });
|
|
};
|
|
|
|
return (
|
|
<Box className="external-login-page">
|
|
<Card className="external-login-card" elevation={0}>
|
|
<CardContent>
|
|
<Stack sx={{ alignItems: "flex-end" }}><LanguageSwitcher /></Stack>
|
|
<Stack spacing={1.5} sx={{ alignItems: "center" }}>
|
|
<AppIdentity
|
|
appCode={session?.appCode}
|
|
appName={session?.appName || session?.appCode}
|
|
className="external-change-password-brand"
|
|
logoUrl={session?.logoUrl}
|
|
showLogoFallback={false}
|
|
size="large"
|
|
/>
|
|
<Typography component="h1" variant="h5">{t("auth.changePassword")}</Typography>
|
|
<Typography color="text.secondary">{session?.passwordChangeRequired ? t("auth.firstLoginChange") : session?.account}</Typography>
|
|
</Stack>
|
|
<Stack component="form" spacing={2} onSubmit={submit}>
|
|
{error ? <Alert severity="error">{error}</Alert> : null}
|
|
<TextField autoComplete="current-password" disabled={submitting} label={t("auth.currentPassword")} required type="password" value={form.oldPassword} onChange={(event) => setForm({ ...form, oldPassword: event.target.value })} />
|
|
<TextField autoComplete="new-password" disabled={submitting} helperText={t("auth.passwordMin")} label={t("auth.newPassword")} required type="password" value={form.newPassword} onChange={(event) => setForm({ ...form, newPassword: event.target.value })} />
|
|
<TextField autoComplete="new-password" disabled={submitting} label={t("auth.confirmNewPassword")} required type="password" value={form.confirmPassword} onChange={(event) => setForm({ ...form, confirmPassword: event.target.value })} />
|
|
<Stack direction="row" spacing={1}><Button disabled={submitting} fullWidth onClick={cancel} variant="outlined">{t("auth.logout")}</Button><Button disabled={submitting} fullWidth type="submit" variant="contained">{t("auth.savePassword")}</Button></Stack>
|
|
</Stack>
|
|
</CardContent>
|
|
</Card>
|
|
</Box>
|
|
);
|
|
}
|