mirror of
https://github.com/openziti/zrok.git
synced 2025-03-13 15:08:21 +01:00
cracked the approach for live form editing; password change (#822)
This commit is contained in:
parent
e3cd4f9254
commit
f962a7d253
49
ui100/package-lock.json
generated
49
ui100/package-lock.json
generated
@ -20,6 +20,7 @@
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-router": "^7.0.1",
|
||||
"yup": "^1.6.1",
|
||||
"zustand": "^5.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -4118,6 +4119,12 @@
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/property-expr": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
|
||||
"integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
@ -4464,6 +4471,12 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/tiny-case": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
|
||||
"integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tiny-warning": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
||||
@ -4483,6 +4496,12 @@
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/toposort": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
|
||||
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ts-api-utils": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz",
|
||||
@ -4521,6 +4540,18 @@
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
|
||||
"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
|
||||
"license": "(MIT OR CC0-1.0)",
|
||||
"engines": {
|
||||
"node": ">=12.20"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.6.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
|
||||
@ -4605,9 +4636,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.4.11",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz",
|
||||
"integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==",
|
||||
"version": "5.4.14",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz",
|
||||
"integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -4719,6 +4750,18 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/yup": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/yup/-/yup-1.6.1.tgz",
|
||||
"integrity": "sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"property-expr": "^2.0.5",
|
||||
"tiny-case": "^1.0.3",
|
||||
"toposort": "^2.0.2",
|
||||
"type-fest": "^2.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/zustand": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.2.tgz",
|
||||
|
@ -22,6 +22,7 @@
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-router": "^7.0.1",
|
||||
"yup": "^1.6.1",
|
||||
"zustand": "^5.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1,8 +1,10 @@
|
||||
import {User} from "./model/user.ts";
|
||||
import {useState} from "react";
|
||||
import {useEffect, useState} from "react";
|
||||
import {modalStyle} from "./styling/theme.ts";
|
||||
import {Box, Button, Grid2, Modal, TextField, Typography} from "@mui/material";
|
||||
import {useFormik} from "formik";
|
||||
import * as Yup from 'yup';
|
||||
import {getAccountApi} from "./model/api.ts";
|
||||
|
||||
interface AccountPasswordChangeModalProps {
|
||||
close: () => void;
|
||||
@ -12,6 +14,8 @@ interface AccountPasswordChangeModalProps {
|
||||
|
||||
const AccountPasswordChangeModal =({ close, isOpen, user }: AccountPasswordChangeModalProps) => {
|
||||
const [errorMessage, setErrorMessage] = useState<React.JSX.Element>(null);
|
||||
const submitButton = <Button color="primary" variant="contained" type="submit" sx={{ mt: 2 }}>Change Password</Button>;
|
||||
const [bottomControl, setBottomControl] = useState<React.JSX.Element>(submitButton);
|
||||
|
||||
const passwordChangeForm = useFormik({
|
||||
initialValues: {
|
||||
@ -20,11 +24,54 @@ const AccountPasswordChangeModal =({ close, isOpen, user }: AccountPasswordChang
|
||||
duplicateNewPassword: "",
|
||||
},
|
||||
onSubmit: v => {
|
||||
setErrorMessage(null as React.JSX.Element);
|
||||
// api
|
||||
}
|
||||
setErrorMessage(null);
|
||||
getAccountApi(user).changePassword({
|
||||
body: {
|
||||
email: user.email,
|
||||
oldPassword: v.currentPassword,
|
||||
newPassword: v.newPassword,
|
||||
}
|
||||
})
|
||||
.then(d => {
|
||||
setBottomControl(<Typography>Your password has been changed!</Typography>);
|
||||
})
|
||||
.catch(e => {
|
||||
setErrorMessage(<Typography color="red">Password change failed! Check your current password!</Typography>);
|
||||
})
|
||||
},
|
||||
validationSchema: Yup.object({
|
||||
currentPassword: Yup.string()
|
||||
.required("Current password is required"),
|
||||
newPassword: Yup.string()
|
||||
.min(8, "Password must be at least 8 characters")
|
||||
.max(64, "Password must be less than 64 characters")
|
||||
.matches(
|
||||
/^.*[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?].*$/,
|
||||
"Password requires at least one special character"
|
||||
)
|
||||
.matches(
|
||||
/^.*[a-z].*$/,
|
||||
"Password requires at least one lowercase letter"
|
||||
)
|
||||
.matches(
|
||||
/^.*[A-Z].*$/,
|
||||
"Password requires at least one uppercase letter"
|
||||
)
|
||||
.required("Password is required"),
|
||||
duplicateNewPassword: Yup.string()
|
||||
.required("Please confirm your new password")
|
||||
.test("password-matches", "Password confirmation does not match", v => v === passwordChangeForm.values.newPassword)
|
||||
}),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
passwordChangeForm.values.currentPassword = "";
|
||||
passwordChangeForm.values.newPassword = "";
|
||||
passwordChangeForm.values.duplicateNewPassword = "";
|
||||
setErrorMessage(null);
|
||||
setBottomControl(submitButton);
|
||||
}, [isOpen]);
|
||||
|
||||
return (
|
||||
<Modal open={isOpen} onClose={close}>
|
||||
<Box sx={{ ...modalStyle }}>
|
||||
@ -42,6 +89,8 @@ const AccountPasswordChangeModal =({ close, isOpen, user }: AccountPasswordChang
|
||||
value={passwordChangeForm.values.currentPassword}
|
||||
onChange={passwordChangeForm.handleChange}
|
||||
onBlur={passwordChangeForm.handleBlur}
|
||||
error={passwordChangeForm.errors.currentPassword !== undefined}
|
||||
helperText={passwordChangeForm.errors.currentPassword}
|
||||
sx={{ mt: 2 }}
|
||||
/>
|
||||
<TextField
|
||||
@ -53,6 +102,8 @@ const AccountPasswordChangeModal =({ close, isOpen, user }: AccountPasswordChang
|
||||
value={passwordChangeForm.values.newPassword}
|
||||
onChange={passwordChangeForm.handleChange}
|
||||
onBlur={passwordChangeForm.handleBlur}
|
||||
error={passwordChangeForm.errors.newPassword !== undefined}
|
||||
helperText={passwordChangeForm.errors.newPassword}
|
||||
sx={{ mt: 2 }}
|
||||
/>
|
||||
<TextField
|
||||
@ -60,15 +111,18 @@ const AccountPasswordChangeModal =({ close, isOpen, user }: AccountPasswordChang
|
||||
type="password"
|
||||
id="duplicateNewPassword"
|
||||
name="duplicateNewPassword"
|
||||
label="Re-enter New Password"
|
||||
label="Confirm New Password"
|
||||
value={passwordChangeForm.values.duplicateNewPassword}
|
||||
onChange={passwordChangeForm.handleChange}
|
||||
onBlur={passwordChangeForm.handleBlur}
|
||||
error={passwordChangeForm.errors.duplicateNewPassword !== undefined}
|
||||
helperText={passwordChangeForm.errors.duplicateNewPassword}
|
||||
sx={{ mt: 2 }}
|
||||
/>
|
||||
</Grid2>
|
||||
{ errorMessage ? <Grid2 container sx={{ mt: 2, p: 1}}><Typography>{errorMessage}</Typography></Grid2> : null}
|
||||
<Grid2 container sx={{ flexGrow: 1, p: 1 }} alignItems="center">
|
||||
<Button color="primary" variant="contained" type="submit" sx={{ mt: 2 }}>Change Password</Button>
|
||||
{bottomControl}
|
||||
</Grid2>
|
||||
</form>
|
||||
</Box>
|
||||
|
Loading…
Reference in New Issue
Block a user