loginForm.tsx

  1import { Button, ButtonGroup, createStyles, makeStyles, TextField, Theme } from '@material-ui/core';
  2import * as React from 'react';
  3import { Controller, useForm } from 'react-hook-form';
  4
  5import { nameofFactory, noComplete } from '../common';
  6
  7export interface LoginFormData {
  8    nickname: string;
  9    roomName: string;
 10    roomPass: string;
 11    create: boolean;
 12}
 13
 14const formName = nameofFactory<LoginFormData>();
 15
 16const useStyles = makeStyles((theme: Theme) =>
 17    createStyles({
 18        padBottom: {
 19            marginBottom: theme.spacing(2),
 20        },
 21        label: {
 22            color: theme.palette.text.secondary + ' !important',
 23        },
 24    })
 25);
 26
 27export interface LoginFormProps {
 28    existingRoom: boolean;
 29    onSubmit: (data: LoginFormData) => Promise<void>;
 30    errorMessage?: string;
 31}
 32
 33// Sync rules with protocol.go.
 34export function LoginForm(props: LoginFormProps) {
 35    const classes = useStyles();
 36    const { control, handleSubmit, errors, setValue, register } = useForm<LoginFormData>({});
 37    React.useEffect(() => register({ name: formName('create') }), [register]);
 38    const doSubmit = handleSubmit(props.onSubmit);
 39
 40    return (
 41        <form onSubmit={(e) => e.preventDefault()}>
 42            {props.existingRoom ? (
 43                <div>
 44                    <em>Joining existing game; please choose a nickname.</em>
 45                </div>
 46            ) : null}
 47
 48            <div className={props.existingRoom ? classes.padBottom : undefined}>
 49                <Controller
 50                    control={control}
 51                    as={TextField}
 52                    name={formName('nickname')}
 53                    label="Nickname"
 54                    defaultValue=""
 55                    error={!!errors.nickname}
 56                    rules={{ required: true, minLength: 1, maxLength: 16 }}
 57                    fullWidth={true}
 58                    inputProps={noComplete}
 59                    autoFocus
 60                    InputLabelProps={{ classes: { focused: classes.label } }}
 61                />
 62            </div>
 63
 64            {props.existingRoom ? null : (
 65                <>
 66                    <div>
 67                        <Controller
 68                            control={control}
 69                            as={TextField}
 70                            name={formName('roomName')}
 71                            label="Room name"
 72                            defaultValue=""
 73                            error={!!errors.roomName}
 74                            rules={{ required: true, minLength: 1, maxLength: 20 }}
 75                            fullWidth={true}
 76                            inputProps={noComplete}
 77                            InputLabelProps={{ classes: { focused: classes.label } }}
 78                        />
 79                    </div>
 80
 81                    <div className={classes.padBottom}>
 82                        <Controller
 83                            control={control}
 84                            as={TextField}
 85                            name={formName('roomPass')}
 86                            label="Password"
 87                            defaultValue=""
 88                            type="password"
 89                            error={!!errors.roomPass}
 90                            rules={{ required: true, minLength: 1 }}
 91                            fullWidth={true}
 92                            inputProps={noComplete}
 93                            InputLabelProps={{ classes: { focused: classes.label } }}
 94                        />
 95                    </div>
 96                </>
 97            )}
 98
 99            {props.errorMessage && (
100                <div className={classes.padBottom}>
101                    <em>{props.errorMessage}</em>
102                </div>
103            )}
104
105            <div>
106                <ButtonGroup variant="contained">
107                    <Button
108                        type="submit"
109                        onClick={() => {
110                            setValue(formName('create'), false);
111                            doSubmit();
112                        }}
113                    >
114                        Join game
115                    </Button>
116
117                    {props.existingRoom ? null : (
118                        <Button
119                            type="button"
120                            onClick={() => {
121                                setValue(formName('create'), true);
122                                doSubmit();
123                            }}
124                        >
125                            Create new game
126                        </Button>
127                    )}
128                </ButtonGroup>
129            </div>
130        </form>
131    );
132}