mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2025-03-30 01:03:42 -04:00
react-hook-form-mui in ChangePassword
This commit is contained in:
parent
2667dd68cb
commit
dc9c62e8bb
4534
ui/package-lock.json
generated
4534
ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,8 @@
|
|||||||
"gzipper": "^7.0.0",
|
"gzipper": "^7.0.0",
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^17.0.1",
|
||||||
|
"react-hook-form": "^7.41.5",
|
||||||
|
"react-hook-form-mui": "^5.12.3",
|
||||||
"react-router-dom": "^6.2.2",
|
"react-router-dom": "^6.2.2",
|
||||||
"react-scripts": "^5.0.0",
|
"react-scripts": "^5.0.0",
|
||||||
"typescript": "^4.8.4"
|
"typescript": "^4.8.4"
|
||||||
|
@ -2,6 +2,13 @@
|
|||||||
// Copyright (C) 2022 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
|
// Copyright (C) 2022 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
|
||||||
// SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception
|
// SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception
|
||||||
|
|
||||||
|
import { useForm } from "react-hook-form";
|
||||||
|
import {
|
||||||
|
FormContainer,
|
||||||
|
PasswordElement,
|
||||||
|
PasswordRepeatElement,
|
||||||
|
} from "react-hook-form-mui";
|
||||||
|
import Button from "@mui/material/Button";
|
||||||
import LoadingButton from "@mui/lab/LoadingButton";
|
import LoadingButton from "@mui/lab/LoadingButton";
|
||||||
import Dialog from "@mui/material/Dialog";
|
import Dialog from "@mui/material/Dialog";
|
||||||
import DialogActions from "@mui/material/DialogActions";
|
import DialogActions from "@mui/material/DialogActions";
|
||||||
@ -31,6 +38,11 @@ interface Request {
|
|||||||
// the rule can via API request.
|
// the rule can via API request.
|
||||||
const MIN_PASSWORD_LENGTH = 8;
|
const MIN_PASSWORD_LENGTH = 8;
|
||||||
|
|
||||||
|
interface FormData {
|
||||||
|
currentPassword: string;
|
||||||
|
newPassword: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialog for changing password.
|
* Dialog for changing password.
|
||||||
*
|
*
|
||||||
@ -52,13 +64,9 @@ const MIN_PASSWORD_LENGTH = 8;
|
|||||||
*/
|
*/
|
||||||
const ChangePassword = ({ user, open, handleClose }: Props) => {
|
const ChangePassword = ({ user, open, handleClose }: Props) => {
|
||||||
const snackbars = useSnackbars();
|
const snackbars = useSnackbars();
|
||||||
|
const formContext = useForm<FormData>();
|
||||||
|
const setError = formContext.setError;
|
||||||
const [loading, setLoading] = React.useState<Request | null>(null);
|
const [loading, setLoading] = React.useState<Request | null>(null);
|
||||||
const [currentPassword, setCurrentPassword] = React.useState("");
|
|
||||||
const [currentError, setCurrentError] = React.useState(false);
|
|
||||||
const [newPassword, setNewPassword] = React.useState<string>("");
|
|
||||||
const [newError, setNewError] = React.useState(false);
|
|
||||||
const [confirmPassword, setConfirmPassword] = React.useState<string>("");
|
|
||||||
const [confirmError, setConfirmError] = React.useState(false);
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (loading === null) {
|
if (loading === null) {
|
||||||
return;
|
return;
|
||||||
@ -83,9 +91,9 @@ const ChangePassword = ({ user, open, handleClose }: Props) => {
|
|||||||
break;
|
break;
|
||||||
case "error":
|
case "error":
|
||||||
if (response.httpStatus === 412) {
|
if (response.httpStatus === 412) {
|
||||||
if (currentPassword === loading.currentPassword) {
|
setError("currentPassword", {
|
||||||
setCurrentError(true);
|
message: "Incorrect password.",
|
||||||
}
|
});
|
||||||
} else {
|
} else {
|
||||||
snackbars.enqueue({
|
snackbars.enqueue({
|
||||||
message: response.message,
|
message: response.message,
|
||||||
@ -107,146 +115,98 @@ const ChangePassword = ({ user, open, handleClose }: Props) => {
|
|||||||
return () => {
|
return () => {
|
||||||
abort.abort();
|
abort.abort();
|
||||||
};
|
};
|
||||||
}, [loading, handleClose, snackbars, currentPassword]);
|
}, [loading, handleClose, snackbars, setError]);
|
||||||
const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
const onSuccess = (data: FormData) => {
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
if (newPassword.length < MIN_PASSWORD_LENGTH) {
|
|
||||||
setNewError(true);
|
|
||||||
return;
|
|
||||||
} else if (confirmPassword !== newPassword) {
|
|
||||||
setConfirmError(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Suppress concurrent attempts.
|
// Suppress concurrent attempts.
|
||||||
|
console.log("onSuccess", data);
|
||||||
if (loading !== null) {
|
if (loading !== null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setLoading({
|
setLoading({
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
csrf: user.session!.csrf,
|
csrf: user.session!.csrf,
|
||||||
currentPassword: currentPassword,
|
currentPassword: data.currentPassword,
|
||||||
newPassword: newPassword,
|
newPassword: data.newPassword,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onChangeNewPassword = (
|
|
||||||
e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
|
|
||||||
) => {
|
|
||||||
setNewPassword(e.target.value);
|
|
||||||
if (e.target.value.length >= MIN_PASSWORD_LENGTH) {
|
|
||||||
setNewError(false);
|
|
||||||
}
|
|
||||||
if (e.target.value === confirmPassword) {
|
|
||||||
setConfirmError(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const onBlurNewPassword = () => {
|
|
||||||
if (newPassword.length < MIN_PASSWORD_LENGTH) {
|
|
||||||
setNewError(true);
|
|
||||||
}
|
|
||||||
if (newPassword !== confirmPassword && confirmPassword !== "") {
|
|
||||||
setConfirmError(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const onChangeConfirmPassword = (
|
|
||||||
e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
|
|
||||||
) => {
|
|
||||||
setConfirmPassword(e.target.value);
|
|
||||||
if (e.target.value === newPassword) {
|
|
||||||
setConfirmError(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const onBlurConfirmPassword = () => {
|
|
||||||
if (confirmPassword !== newPassword) {
|
|
||||||
setConfirmError(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
onClose={handleClose}
|
|
||||||
aria-labelledby="change-password-title"
|
aria-labelledby="change-password-title"
|
||||||
open={open}
|
open={open}
|
||||||
maxWidth="sm"
|
maxWidth="sm"
|
||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
>
|
>
|
||||||
<DialogTitle id="change-password-title">
|
<DialogTitle id="change-password-title">Change password</DialogTitle>
|
||||||
Change password for {user.name}
|
|
||||||
</DialogTitle>
|
|
||||||
|
|
||||||
<form onSubmit={onSubmit}>
|
<FormContainer formContext={formContext} onSuccess={onSuccess}>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
{/* The username is here in the hopes it will help password managers
|
{/* The username is here in the hopes it will help password managers
|
||||||
* find the correct entry. It's otherwise unused. */}
|
* find the correct entry. It's otherwise unused. */}
|
||||||
<input
|
<TextField
|
||||||
name="username"
|
name="username"
|
||||||
type="hidden"
|
label="Username"
|
||||||
value={user.name}
|
value={user.name}
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
disabled
|
||||||
autoComplete="username"
|
autoComplete="username"
|
||||||
|
variant="filled"
|
||||||
|
fullWidth
|
||||||
|
helperText=" "
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextField
|
<PasswordElement
|
||||||
name="current-password"
|
name="currentPassword"
|
||||||
label="Current password"
|
label="Current password"
|
||||||
variant="filled"
|
variant="filled"
|
||||||
type="password"
|
type="password"
|
||||||
required
|
required
|
||||||
autoComplete="current-password"
|
autoComplete="current-password"
|
||||||
fullWidth
|
fullWidth
|
||||||
error={currentError}
|
helperText=" "
|
||||||
helperText={currentError ? "Current password is incorrect" : " "}
|
|
||||||
value={currentPassword}
|
|
||||||
onChange={(e) => {
|
|
||||||
setCurrentError(false);
|
|
||||||
setCurrentPassword(e.target.value);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<TextField
|
<PasswordElement
|
||||||
name="new-password"
|
name="newPassword"
|
||||||
label="New password"
|
label="New password"
|
||||||
variant="filled"
|
variant="filled"
|
||||||
type="password"
|
|
||||||
required
|
required
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
value={newPassword}
|
validation={{
|
||||||
inputProps={{ minLength: MIN_PASSWORD_LENGTH }}
|
minLength: {
|
||||||
error={newError}
|
value: MIN_PASSWORD_LENGTH,
|
||||||
helperText={`Password must be at least ${MIN_PASSWORD_LENGTH} characters`}
|
message: `Must have at least ${MIN_PASSWORD_LENGTH} characters`,
|
||||||
|
},
|
||||||
|
}}
|
||||||
fullWidth
|
fullWidth
|
||||||
onChange={onChangeNewPassword}
|
helperText=" "
|
||||||
onBlur={onBlurNewPassword}
|
|
||||||
/>
|
/>
|
||||||
<TextField
|
<PasswordRepeatElement
|
||||||
name="confirm-new-password"
|
name="confirmNewPassword"
|
||||||
label="Confirm new password"
|
label="Confirm new password"
|
||||||
variant="filled"
|
variant="filled"
|
||||||
type="password"
|
type="password"
|
||||||
|
passwordFieldName="newPassword"
|
||||||
required
|
required
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
value={confirmPassword}
|
|
||||||
inputProps={{ minLength: MIN_PASSWORD_LENGTH }}
|
|
||||||
fullWidth
|
fullWidth
|
||||||
error={confirmError}
|
helperText=" "
|
||||||
helperText="Passwords must match."
|
|
||||||
onChange={onChangeConfirmPassword}
|
|
||||||
onBlur={onBlurConfirmPassword}
|
|
||||||
/>
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
|
<Button onClick={handleClose} disabled={loading !== null}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
<LoadingButton
|
<LoadingButton
|
||||||
type="submit"
|
type="submit"
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
loading={loading !== null}
|
loading={loading !== null}
|
||||||
disabled={newError || confirmError}
|
|
||||||
>
|
>
|
||||||
Change
|
Change
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</form>
|
</FormContainer>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user