diff options
author | zirops <zirops@gmail.com> | 2021-01-26 10:57:25 +0100 |
---|---|---|
committer | zirops <zirops@gmail.com> | 2021-01-26 10:57:25 +0100 |
commit | 12184a5ef570593ab492c1499f2d7a23e3be2569 (patch) | |
tree | bc2f7ed0d098bbaef247d0e5ab7f5a57f08ab3be /modern | |
parent | 2201f5417f41204453e3cd53da003296925282aa (diff) | |
download | trackermap-web-12184a5ef570593ab492c1499f2d7a23e3be2569.tar.gz trackermap-web-12184a5ef570593ab492c1499f2d7a23e3be2569.tar.bz2 trackermap-web-12184a5ef570593ab492c1499f2d7a23e3be2569.zip |
user self registration
Diffstat (limited to 'modern')
-rw-r--r-- | modern/src/LoginPage.js | 29 | ||||
-rw-r--r-- | modern/src/RegisterDialog.js | 109 |
2 files changed, 136 insertions, 2 deletions
diff --git a/modern/src/LoginPage.js b/modern/src/LoginPage.js index 2636c807..cbe50fe4 100644 --- a/modern/src/LoginPage.js +++ b/modern/src/LoginPage.js @@ -7,6 +7,9 @@ import FormControl from '@material-ui/core/FormControl'; import Paper from '@material-ui/core/Paper'; import { makeStyles } from '@material-ui/core'; import TextField from '@material-ui/core/TextField'; +import RegisterDialog from './RegisterDialog'; +import Snackbar from '@material-ui/core/Snackbar'; +import { useSelector } from 'react-redux'; import t from './common/localization'; @@ -47,10 +50,19 @@ const LoginPage = () => { const [failed, setFailed] = useState(false); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); + const [registerDialogShown, setRegisterDialogShown] = useState(false); + const [snackbarOpen, setSnackbarOpen] = useState(false); const classes = useStyles(); const history = useHistory(); + const server = useSelector(state => state.session.server); + + let registrationPref = false; + if (server) { + registrationPref = server['registration'] + } + const handleEmailChange = (event) => { setEmail(event.target.value); } @@ -60,7 +72,14 @@ const LoginPage = () => { } const handleRegister = () => { - // TODO: Implement registration + setRegisterDialogShown(true); + } + + const handleRegisterResult = (resultOk) => { + setRegisterDialogShown(false); + if (resultOk) { + setSnackbarOpen(true); + } } const handleLogin = async (event) => { @@ -109,7 +128,7 @@ const LoginPage = () => { <FormControl fullWidth margin='normal'> <div className={classes.buttons}> - <Button type='button' variant='contained' disabled onClick={handleRegister}> + <Button type='button' variant='contained' onClick={handleRegister} disabled={!registrationPref}> {t('loginRegister')} </Button> <Button type='submit' variant='contained' color='primary' disabled={!email || !password}> @@ -118,6 +137,12 @@ const LoginPage = () => { </div> </FormControl> </form> + {registerDialogShown && <RegisterDialog open={registerDialogShown} onResult={handleRegisterResult} />} + <Snackbar + anchorOrigin={{ vertical: 'bottom', horizontal: 'center', }} + open={snackbarOpen} autoHideDuration={6000} + onClose={()=>{setSnackbarOpen(false);}} message={t('loginCreated')} + /> </Paper> </main> ); diff --git a/modern/src/RegisterDialog.js b/modern/src/RegisterDialog.js new file mode 100644 index 00000000..ecd07ac2 --- /dev/null +++ b/modern/src/RegisterDialog.js @@ -0,0 +1,109 @@ +import t from './common/localization' +import React, { useState } from 'react'; +import Button from '@material-ui/core/Button'; +import Dialog from '@material-ui/core/Dialog'; +import DialogActions from '@material-ui/core/DialogActions'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import TextField from '@material-ui/core/TextField'; +import Alert from '@material-ui/lab/Alert'; + +const RegisterDialog = ({ open, onResult }) => { + const [formFields, setFormFields] = useState({}); + const [validationErrors, setValidationErrors] = useState({}); + const [errorResponse, setErrorResponse] = useState(null); + + const handleChange = (event) => { + setFormFields({ ...formFields, [event.target.name]: event.target.value }); + setValidationErrors({ ...validationErrors, [event.target.name]: false }); + } + + const handleRegister = async (event) => { + event.preventDefault(); + setErrorResponse(null); + let objErrors = {}; + if (formFields.name.trim() === '') { + objErrors.name = true; + } + if (! + /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(formFields.email)) { + objErrors.email = true; + } + if (formFields.password.trim() === '') { + objErrors.password = true; + } + if (Object.keys(objErrors).length !== 0) { + setValidationErrors(objErrors); + return; + } + + const response = await fetch('/api/users', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(formFields) + }); + + if (response.ok) { + onResult(true) + } else { + setErrorResponse(t('errorGeneral')); + } + } + + return ( + <Dialog + open={open} + onClose={() => { onResult(false) }}> + <DialogContent> + <DialogContentText>{t('loginRegister')}</DialogContentText> + + {errorResponse && <Alert severity="error">{errorResponse}</Alert>} + + <TextField + margin='normal' + required + fullWidth + error={validationErrors.name} + label={t('sharedName')} + name='name' + value={formFields.name || ''} + autoComplete='name' + autoFocus + onChange={handleChange} + helperText={validationErrors.name && 'Name is required'} /> + + <TextField + margin='normal' + required + fullWidth + error={validationErrors.email} + label={t('userEmail')} + name='email' + value={formFields.email || ''} + autoComplete='email' + onChange={handleChange} + helperText={validationErrors.email && 'Invalid e-mail'} /> + + <TextField + margin='normal' + required + fullWidth + error={validationErrors.password} + label={t('userPassword')} + name='password' + value={formFields.password || ''} + type='password' + autoComplete='current-password' + onChange={handleChange} + helperText={validationErrors.password && 'Password is required'} /> + + </DialogContent> + <DialogActions> + <Button color="primary" onClick={handleRegister} disabled={!formFields.name || !formFields.email || !formFields.password}>{t('loginRegister')}</Button> + <Button autoFocus onClick={() => onResult(false)}>{t('sharedCancel')}</Button> + </DialogActions> + </Dialog> + ); +}; + +export default RegisterDialog; |