1
- import React , { ChangeEvent , FormEvent , ReactElement , useCallback , useEffect , useState } from "react" ;
2
- import { Container , Row , Col , Form , FormGroup , Button , Alert } from "react-bootstrap" ;
3
- import { deleteSpaces } from "../../../background/methods/strings" ;
4
- import { biggerMaxStrLength , notMinStrLength } from "../../../background/methods/checkInput" ;
5
- import info_svg from "../../../assets/images/icons/material.io/info-24px.svg" ;
6
- import check_svg from "../../../assets/images/icons/material.io/check_circle-24px.svg" ;
7
- import error_svg from "../../../assets/images/icons/material.io/error-24px.svg" ;
1
+ import React , { ReactElement , useEffect , useState } from "react" ;
2
+ import { Alert , Col , Container , Row } from "react-bootstrap" ;
3
+ import { notMinStrLength } from "../../../background/methods/checkInput" ;
8
4
import fileFighter from "../../../assets/images/logos/adventurer-run.gif" ;
9
5
import { registerNewUser } from "../../../background/api/registration" ;
10
6
import { getWindowSize , getWindowSize_Interface } from "../../../background/methods/windowSize" ;
11
7
import { getStyleValue } from "../../../background/methods/style" ;
12
- import { DEFAULT_ALERT_DURATION , MAX_PASSWORD_LENGTH , MIN_PASSWORD_LENGTH } from "../../../background/constants" ;
8
+ import { DEFAULT_ALERT_DURATION , MIN_PASSWORD_LENGTH } from "../../../background/constants" ;
9
+ import UserInformationInput , { UserInformationInterface } from "./UserInformationInput" ;
13
10
14
11
export default function Registration ( ) : ReactElement {
15
-
16
- const [ username , setUsername ] = useState < string > ( "" ) ;
17
- const [ password , setPassword ] = useState < string > ( "" ) ;
18
- const [ passwordConfirmation , setPasswordConfirmation ] = useState < string > ( "" ) ;
19
- const [ passwordInformationLength , setPasswordInformationLength ] = useState < boolean > ( false ) ;
20
- const [ passwordInformationLowercase , setPasswordInformationLowercase ] = useState < boolean > ( false ) ;
21
- const [ passwordInformationUppercase , setPasswordInformationUppercase ] = useState < boolean > ( false ) ;
22
- const [ passwordInformationNumber , setPasswordInformationNumber ] = useState < boolean > ( false ) ;
23
- const [ passwordsMatch , setPasswordsMatch ] = useState < boolean > ( true ) ;
24
12
const [ alertMessage , setAlertMessage ] = useState < string > ( "Error 404: No Message found." ) ;
25
13
const [ alertVariant , setAlertColor ] = useState < "primary" | "secondary" | "success" | "danger" | "warning" | "info" | "light" | "dark" > ( "success" ) ;
26
14
const [ alertVisibility , setAlertVisibility ] = useState < boolean > ( false ) ;
27
15
16
+ const [ newUser , setNewUser ] = useState < UserInformationInterface > ( {
17
+ username : "" ,
18
+ password : "" ,
19
+ passwordConfirmation : ""
20
+ } )
21
+
28
22
const registrationContainer = document . getElementById ( "registrationContainer" )
29
23
const logoSubmit = document . getElementById ( "logoSubmit" )
30
24
31
25
useEffect ( ( ) => {
32
26
function repositionSubmitLogo ( ) {
33
27
const logo = document . getElementById ( "logoSubmit" )
34
- if ( logo ) {
28
+ if ( logo ) {
35
29
const container : HTMLElement | null = document . getElementById ( "registrationContainer" ) ;
36
30
const leftContainerOffset : number = container ?. getBoundingClientRect ( ) . left ?? 0 ;
37
31
38
- let containerPadding :string | number | null = getStyleValue ( container , "padding-left" ) ;
32
+ let containerPadding : string | number | null = getStyleValue ( container , "padding-left" ) ;
39
33
const pxPosition = containerPadding . indexOf ( "px" ) ;
40
34
containerPadding = pxPosition === - 1 ? null : Number ( containerPadding . substr ( 0 , pxPosition ) )
41
35
42
- logo . style . left = - ( leftContainerOffset + logo . offsetWidth * 2 + ( containerPadding ?? 20 ) ) + "px" ;
36
+ logo . style . left = - ( leftContainerOffset + logo . offsetWidth * 2 + ( containerPadding ?? 20 ) ) + "px" ;
43
37
}
44
38
}
45
- repositionSubmitLogo ( )
46
- } , [ registrationContainer , logoSubmit ] )
47
39
48
- const reviewPasswordMatch = useCallback ( ( ) :void => {
49
- setPasswordsMatch ( password === passwordConfirmation ) ;
50
- } , [ password , passwordConfirmation ] ) ;
51
-
52
- useEffect ( ( ) => {
53
- reviewPasswordMatch ( )
54
- } , [ reviewPasswordMatch ] )
40
+ repositionSubmitLogo ( )
41
+ } , [ registrationContainer , logoSubmit ] )
55
42
56
- const handleSubmit = async ( event : FormEvent ) => {
43
+ const handleSubmit = async ( ) => {
57
44
console . log ( "[REGISTRATION] handleSubmit" )
58
- event . preventDefault ( ) ;
59
- reviewPasswordMatch ( ) ;
60
- if ( ! username ) {
45
+ if ( ! newUser . username ) {
61
46
handleAlertVisibility ( DEFAULT_ALERT_DURATION , "danger" , "Error: Please choose an username." )
62
- } else if ( ! passwordsMatch ) {
47
+ } else if ( newUser . password !== newUser . passwordConfirmation ) {
63
48
handleAlertVisibility ( DEFAULT_ALERT_DURATION , "danger" , "Error: Password and password confirmation must match." )
64
- } else if ( ! passwordInformationNumber || ! passwordInformationLowercase || ! passwordInformationUppercase || ! passwordInformationLength ) {
49
+ } else if ( newUser . password . match ( / \d / ) == null || newUser . password . match ( / [ a - z ] / ) == null || newUser . password . match ( / [ A - Z ] / ) == null || notMinStrLength ( newUser . password , MIN_PASSWORD_LENGTH ) ) {
65
50
handleAlertVisibility ( DEFAULT_ALERT_DURATION , "danger" , "Error: Please pay attention to the notes below the input fields." )
66
51
} else {
67
- await registerNewUser ( username , password , passwordConfirmation )
52
+ await registerNewUser ( newUser . username , newUser . password , newUser . passwordConfirmation )
68
53
. then ( res => {
69
54
handleAlertVisibility ( DEFAULT_ALERT_DURATION , "success" , "Worked: " + ( res . outputMessage ? res . outputMessage : ( res . httpStatus + " " + res . httpMessage ) ) ) ;
70
55
toggleSubmitLogo ( ) ;
@@ -86,106 +71,17 @@ export default function Registration(): ReactElement {
86
71
}
87
72
}
88
73
89
- const makePasswordInputFitRules = ( input : string ) : [ string , boolean ] => {
90
- input = deleteSpaces ( input ) ;
91
- if ( biggerMaxStrLength ( input , MAX_PASSWORD_LENGTH ) ) {
92
- handleAlertVisibility ( DEFAULT_ALERT_DURATION , "warning" , "Maximum password length exceeded. Input was undone." ) ;
93
- return [ input , false ] ;
94
- }
95
- return [ input , true ] ;
96
- }
97
-
98
- const handlePasswordChange = ( event : ChangeEvent < HTMLInputElement > ) => {
99
- event . preventDefault ( ) ;
100
- let value : [ string , boolean ] | string = makePasswordInputFitRules ( event . target . value ) ;
101
- if ( ! value [ 1 ] ) {
102
- value = password ;
103
- } else {
104
- value = value [ 0 ]
105
- }
106
- setPasswordInformationLength ( ! notMinStrLength ( value , MIN_PASSWORD_LENGTH ) ) ;
107
- setPasswordInformationLowercase ( value . match ( / [ a - z ] / ) !== null ) ;
108
- setPasswordInformationUppercase ( value . match ( / [ A - Z ] / ) !== null ) ;
109
- setPasswordInformationNumber ( value . match ( / \d / ) !== null ) ;
110
- setPassword ( value )
111
- }
112
-
113
- const handlePasswordConfirmationChange = async ( event : ChangeEvent < HTMLInputElement > ) => {
114
- event . preventDefault ( ) ;
115
- let value : [ string , boolean ] | string = makePasswordInputFitRules ( event . target . value ) ;
116
- if ( ! value [ 1 ] ) {
117
- value = passwordConfirmation ;
118
- } else {
119
- value = value [ 0 ]
120
- }
121
- setPasswordConfirmation ( value ) ;
122
- }
123
-
124
74
return (
125
75
< Container className = "h-100" style = { { position : "relative" } } id = "registrationContainer" >
126
76
< Row >
127
77
< Col md = { { span : 6 , offset : 3 } } >
128
78
< h1 > Create new account</ h1 >
129
- < Form onSubmit = { handleSubmit } >
130
- < FormGroup controlId = "formBasicUsername" >
131
- < Form . Label > Username</ Form . Label >
132
- < Form . Control type = { "name" } value = { username }
133
- onChange = { event => setUsername ( event . target . value ) } />
134
- </ FormGroup >
135
- < Form . Group controlId = "formBasicPassword" >
136
- < Form . Label > Password</ Form . Label >
137
- < Form . Control type = "password"
138
- placeholder = "Must contain one number, uppercase & lowercase letter each"
139
- value = { password }
140
- onChange = { ( event : ChangeEvent < HTMLInputElement > ) => handlePasswordChange ( event ) } />
141
- < div >
142
- < img alt = { "status icon password length" }
143
- src = { passwordInformationLength ? check_svg : info_svg } />
144
- < span className = { "sr-only" } > { passwordInformationLength ? "Done: " : "Missing: " } </ span >
145
- < span className = { passwordInformationLength ? "text-success" : "text-muted" } > Passwords must be between 8 and 20 characters.</ span >
146
- </ div >
147
- < div >
148
- < img alt = { "status icon password contains uppercase character" }
149
- src = { passwordInformationUppercase ? check_svg : info_svg } />
150
- < span
151
- className = { "sr-only" } > { passwordInformationUppercase ? "Done: " : "Missing: " } </ span >
152
- < span className = { passwordInformationUppercase ? "text-success" : "text-muted" } > Passwords must be at least contain 1 uppercase character.</ span >
153
- </ div >
154
- < div >
155
- < img alt = { "status icon password contains lowercase character" }
156
- src = { passwordInformationLowercase ? check_svg : info_svg } />
157
- < span
158
- className = { "sr-only" } > { passwordInformationLowercase ? "Done: " : "Missing: " } </ span >
159
- < span className = { passwordInformationLowercase ? "text-success" : "text-muted" } > Passwords must be at least contain 1 lowercase character.</ span >
160
- </ div >
161
- < div >
162
- < img alt = { "status icon password contains number" }
163
- src = { passwordInformationNumber ? check_svg : info_svg } />
164
- < span className = { "sr-only" } > { passwordInformationNumber ? "Done: " : "Missing: " } </ span >
165
- < span className = { passwordInformationNumber ? "text-success" : "text-muted" } > Passwords must be at least contain 1 number.</ span >
166
- </ div >
167
- </ Form . Group >
168
- < Form . Group controlId = "formConfirmPassword" >
169
- < Form . Label > Re-enter password</ Form . Label >
170
- < Form . Control type = "password"
171
- value = { passwordConfirmation }
172
- onChange = { ( event : ChangeEvent < HTMLInputElement > ) => handlePasswordConfirmationChange ( event ) } />
173
- < div >
174
- < img alt = { "status icon passwords match" }
175
- src = { ! passwordConfirmation ? info_svg : passwordsMatch ? check_svg : error_svg } />
176
- < span className = { "sr-only" } > { passwordsMatch ? "Done: " : "Missing: " } </ span >
177
- < span
178
- className = { ! passwordConfirmation ? "text-muted" : passwordsMatch ? "text-success" : "text-danger" } > Passwords must match.</ span >
179
- </ div >
180
- </ Form . Group >
181
- < Button variant = "primary" type = "submit" >
182
- Submit
183
- </ Button >
184
- < Alert variant = { alertVariant } onClose = { ( ) => setAlertVisibility ( false ) } show = { alertVisibility }
185
- dismissible >
186
- < p > { alertMessage } </ p >
187
- </ Alert >
188
- </ Form >
79
+ < UserInformationInput triggerAlert = { handleAlertVisibility } submitFunction = { handleSubmit }
80
+ newUser = { newUser } setNewUser = { setNewUser } />
81
+ < Alert variant = { alertVariant } onClose = { ( ) => setAlertVisibility ( false ) } show = { alertVisibility }
82
+ dismissible >
83
+ < p > { alertMessage } </ p >
84
+ </ Alert >
189
85
</ Col >
190
86
</ Row >
191
87
< img className = { "invisible m0 position-relative" } src = { fileFighter } alt = "logo"
@@ -196,7 +92,7 @@ export default function Registration(): ReactElement {
196
92
function toggleSubmitLogo ( ) {
197
93
const logo = document . getElementById ( "logoSubmit" )
198
94
if ( logo ) {
199
- const size :getWindowSize_Interface = getWindowSize ( ) ;
95
+ const size : getWindowSize_Interface = getWindowSize ( ) ;
200
96
201
97
setTimeout ( ( ) => { //run right
202
98
logo . style . transition = "4s" ;
0 commit comments