diff --git a/package.json b/package.json index 00bb49e..2da81e0 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "dependencies": { "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", + "@mui/icons-material": "^5.11.16", "@mui/material": "^5.11.16", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", diff --git a/src/api/index.js b/src/api/index.js index 1abbc2d..afe7b2c 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -1,38 +1,35 @@ -const signInUser = async (email, password) => { - try { - const response = await fetch('https://lmel2.wiremockapi.cloud/json/1', { - method: 'POST', - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ email, password }) - }); - const responseJson = await response.json() - return responseJson - } catch(e) { - console.log('error occurred', e) - return false - } -} +const createUserAccount = async ({ email, password }) => { + try { + const response = await fetch("https://lmel2.wiremockapi.cloud/json/1", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ email, password }), + }); + const responseJson = await response.json(); + return responseJson; + } catch (e) { + console.log("error occurred", e); + return false; + } +}; const signUpUser = async ({ email, password }) => { - try { - const response = await fetch('https://lmel2.wiremockapi.cloud/json/1', { - method: 'POST', - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ email, password }) - }); - const responseJson = await response.json() - return responseJson - } catch(e) { - console.log('error occurred', e) - return false - } -} + try { + const response = await fetch("https://lmel2.wiremockapi.cloud/json/1", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ email, password }), + }); + const responseJson = await response.json(); + return responseJson; + } catch (e) { + console.log("error occurred", e); + return false; + } +}; -export { - signInUser, - signUpUser -} \ No newline at end of file +export { createUserAccount, signUpUser }; diff --git a/src/components/CustomCheckbox.js b/src/components/CustomCheckbox.js new file mode 100644 index 0000000..7ef7e7b --- /dev/null +++ b/src/components/CustomCheckbox.js @@ -0,0 +1,22 @@ +import React from 'react'; +import Checkbox from '@mui/material/Checkbox'; + +const label = { inputProps: { 'aria-label': 'Checkbox label' } }; + +export default function CustomCheckbox(props) { + const onChange = (e) => { + props.onChange(props.name, e.target.checked) + } + + return ( +
+ + {props.text} +
+ ) +} \ No newline at end of file diff --git a/src/components/CustomSelect.js b/src/components/CustomSelect.js new file mode 100644 index 0000000..972cf4f --- /dev/null +++ b/src/components/CustomSelect.js @@ -0,0 +1,31 @@ +import React from 'react' +import MenuItem from '@mui/material/MenuItem'; +import Select from '@mui/material/Select'; +import h from '../helper/index' +import { InputLabel } from '@mui/material'; + +export default function CustomSelect(props) { + const onChange = (e) => { + props.onChange(props.name, e.target.value) + } + + return <> + {h.capitalizeFirst(props.name)} + + +} \ No newline at end of file diff --git a/src/components/CustomTextField.js b/src/components/CustomTextField.js index 244ea69..1b41b46 100644 --- a/src/components/CustomTextField.js +++ b/src/components/CustomTextField.js @@ -15,12 +15,13 @@ export default function CustomTextField(props) { id={props.name} name={props.name} onChange={onChange} - defaultValue={props.defaultValue || ''} value={props.value} label={h.capitalizeFirst(props.name)} variant="outlined" error={props.error} helperText={props.helperText} + type={props.type} + InputProps={props.inputProps} /> ); } \ No newline at end of file diff --git a/src/components/Signup.css b/src/components/Signup.css index c006280..16234fc 100644 --- a/src/components/Signup.css +++ b/src/components/Signup.css @@ -1,22 +1,26 @@ .signup-input { - margin: 10px 0px !important; + margin: 10px 0px !important; } .dialog { - display: flex; - flex-direction: column; - background-color: white; - padding: 20px 35px; - border-radius: 10px; - width: 240px; - height: fit-content; - box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); + display: flex; + flex-direction: column; + background-color: white; + padding: 20px 35px; + border-radius: 10px; + width: 240px; + height: fit-content; + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); } .dialog-header { - color: #2d842d; - font-size: 20px; - font-weight: bold; - margin-bottom: 15px; - text-align: center; -} \ No newline at end of file + color: #2d842d; + font-size: 20px; + font-weight: bold; + margin-bottom: 15px; + text-align: center; +} + +.anonymous-input { + margin-left: -10px !important; +} diff --git a/src/components/Signup.js b/src/components/Signup.js index 6a577d9..82ce706 100644 --- a/src/components/Signup.js +++ b/src/components/Signup.js @@ -1,8 +1,17 @@ import * as React from "react"; -import { signUpUser } from "../api/index"; +import { createUserAccount } from "../api/index"; import "./Signup.css"; import CustomTextField from "./CustomTextField"; -import h from '../helper/index'; +import h from "../helper/index"; + +import IconButton from "@mui/material/IconButton"; +import InputAdornment from "@mui/material/InputAdornment"; +import Visibility from "@mui/icons-material/Visibility"; +import VisibilityOff from "@mui/icons-material/VisibilityOff"; +import CustomSelect from "./CustomSelect"; +import CustomCheckbox from "./CustomCheckbox"; +import Button from "@mui/material/Button"; +import CircularProgress from "@mui/material/CircularProgress"; const defaultUser = { username: "", @@ -20,20 +29,27 @@ const defaultUser = { const SignUp = (props) => { const [user, setUser] = React.useState(defaultUser); const [errors, setErrors] = React.useState(defaultUser); + const [showPassword, setShowPassword] = React.useState(false); + const [saving, setSaving] = React.useState(null); + + const handleClickShowPassword = () => setShowPassword((show) => !show); + + const handleMouseDownPassword = (e) => e.preventDefault(); - const onChangeOfValue = (key, value) => { - setUser({ ...user, [key]: value }); + const onChangeOfValue = (key, value) => setUser({ ...user, [key]: value }); + + const createUser = async () => { + setSaving(true); + const response = await createUserAccount(user); + console.log("----", response); + setSaving(false); }; - const onBlur = () => { - setErrors(h.validator(user)) - } + const onBlur = () => setErrors(h.validator(user)); return (
-
- Sign up here! -
+
Sign up here!
{ error={errors.password.helperText} helperText={errors.password.helperText} name="password" + type={showPassword ? "text" : "password"} value={user.password} onChange={onChangeOfValue} + inputProps={{ + endAdornment: ( + + + {showPassword ? : } + + + ), + }} /> - - - + { value={user.state} onChange={onChangeOfValue} /> + +
); }; diff --git a/src/helper/index.js b/src/helper/index.js index 7765194..c4db9b1 100644 --- a/src/helper/index.js +++ b/src/helper/index.js @@ -2,34 +2,114 @@ const validUsername = (username) => { return /^(?=.{6,15}$)(?![_.])(?!.*[_.]{2})[a-zA-Z0-9._]+(? { + return /^[a-zA-Z ]+$/.test(firstname) +} + +const validLastname = (lastname) => { + return validFirstname(lastname) +} + +const validEmail = (email) => { + return /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(email) +} + +const validPassword = (password) => { + return /^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{6,16}$/.test(password) +} + +const validAge = (age) => { + const n = Number(age) + if(Number.isNaN(n)) { + return false + } else if(n <=0 || n > 120) { + return false + } + return true; +} + +const validCity = (city) => { + return /^[a-zA-Z ]+$/.test(city) +} + const isUsernameValid = (username) => { if(!username) return true; return validUsername(username) } +const isFirstnameValid = (firstname) => { + if(!firstname) return true; + return validFirstname(firstname) +} + +const isLastnameValid = (lastname) => { + if(!lastname) return true; + return validLastname(lastname) +} + +const isValidEmail = (email) => { + if(!email) return true; + return validEmail(email) +} + +const isValidPassword = (password) => { + if(!password) return true; + return validPassword(password) +} + +const isValidAge = (age) => { + if(!age) return true; + return validAge(age) +} + +const isValidCity = (city) => { + if(!city) return true; + if(city.length > 50) return false; + return validCity(city) +} + const capitalizeFirst = (str) => { if(!str) return ''; return str[0].toUpperCase() + str.slice(1, str.length) } const validator = (user) => { - const errorObj = { - username: { - helperText: undefined - } - } + const errorObj = {} Object.keys(user).forEach((key) => { errorObj[key] = {} errorObj[key].helperText = undefined }) - if (!isUsernameValid(user.username)) { - errorObj.username.helperText = `username is invalid` + errorObj.username.helperText = `Username is invalid` + } + + if (!isFirstnameValid(user.firstname)) { + errorObj.firstname.helperText = `Firstname is invalid` + } + + if (!isLastnameValid(user.lastname)) { + errorObj.lastname.helperText = `Lastname is invalid` + } + + if (!isValidEmail(user.email)) { + errorObj.email.helperText = `Email is invalid` + } + + if (!isValidPassword(user.password)) { + errorObj.password.helperText = 'Password is invalid' + } + + if(!isValidAge(user.age)) { + errorObj.age.helperText = 'Age is invalid' + } + + if(!isValidCity(user.city)) { + errorObj.city.helperText = 'City is invalid' } - if (!isUsernameValid(user.firstname)) { - errorObj.firstname.helperText = `firstname is invalid` + if(!isValidCity(user.state)) { + errorObj.state.helperText = 'State is invalid' } return errorObj