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 } 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 noComplete = {
17 autoComplete: 'off',
18 'data-lpignore': 'true',
19};
20
21const useStyles = makeStyles((theme: Theme) =>
22 createStyles({
23 padBottom: {
24 marginBottom: theme.spacing(2),
25 },
26 })
27);
28
29export interface LoginFormProps {
30 existingRoom: boolean;
31 onSubmit: (data: LoginFormData) => Promise<void>;
32 errorMessage?: string;
33}
34
35// Sync rules with protocol.go.
36export function LoginForm(props: LoginFormProps) {
37 const classes = useStyles();
38 const { control, handleSubmit, errors, setValue, register } = useForm<LoginFormData>({});
39 React.useEffect(() => register({ name: formName('create') }), [register]);
40 const doSubmit = handleSubmit(props.onSubmit);
41
42 return (
43 <form onSubmit={(e) => e.preventDefault()}>
44 {props.existingRoom ? (
45 <div>
46 <em>Joining existing game; please choose a nickname.</em>
47 </div>
48 ) : null}
49
50 <div className={props.existingRoom ? classes.padBottom : undefined}>
51 <Controller
52 control={control}
53 as={TextField}
54 name={formName('nickname')}
55 label="Nickname"
56 defaultValue=""
57 error={!!errors.nickname}
58 rules={{ required: true, minLength: 1, maxLength: 16 }}
59 fullWidth={true}
60 inputProps={noComplete}
61 autoFocus
62 />
63 </div>
64
65 {props.existingRoom ? null : (
66 <>
67 <div>
68 <Controller
69 control={control}
70 as={TextField}
71 name={formName('roomName')}
72 label="Room name"
73 defaultValue=""
74 error={!!errors.roomName}
75 rules={{ required: true, minLength: 1, maxLength: 20 }}
76 fullWidth={true}
77 inputProps={noComplete}
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 />
94 </div>
95 </>
96 )}
97
98 {props.errorMessage && (
99 <div className={classes.padBottom}>
100 <em>{props.errorMessage}</em>
101 </div>
102 )}
103
104 <div>
105 <ButtonGroup variant="contained">
106 <Button
107 type="submit"
108 onClick={() => {
109 setValue(formName('create'), false);
110 doSubmit();
111 }}
112 >
113 Join game
114 </Button>
115
116 {props.existingRoom ? null : (
117 <Button
118 type="button"
119 onClick={() => {
120 setValue(formName('create'), true);
121 doSubmit();
122 }}
123 >
124 Create new game
125 </Button>
126 )}
127 </ButtonGroup>
128 </div>
129 </form>
130 );
131}