idillon-sfl | 37c18df | 2022-08-26 18:44:27 -0400 | [diff] [blame] | 1 | import { Stack, TextField } from "@mui/material" |
| 2 | import { styled } from "@mui/styles" |
| 3 | import React from "react" |
| 4 | import { InfoButton, ToggleVisibilityButton } from "./buttons" |
idillon | b3788bf | 2022-08-29 15:57:57 -0400 | [diff] [blame] | 5 | import { CheckedIcon, RoundCrossIcon, LockIcon, PenIcon, PersonIcon } from "./svgIcons" |
idillon-sfl | 37c18df | 2022-08-26 18:44:27 -0400 | [diff] [blame] | 6 | |
| 7 | const iconsHeight = "16px" |
| 8 | const StyledCheckedIconSuccess = styled(CheckedIcon)(({theme}) => ({height: iconsHeight, color: theme.palette.success.main})) |
idillon | b3788bf | 2022-08-29 15:57:57 -0400 | [diff] [blame] | 9 | const StyledRoundCrossIconError = styled(RoundCrossIcon)(({theme}) => ({height: iconsHeight, color: theme.palette.error.main})) |
idillon-sfl | 37c18df | 2022-08-26 18:44:27 -0400 | [diff] [blame] | 10 | const StyledPenIconLight = styled(PenIcon)({height: iconsHeight, color: "#03B9E9"}) |
| 11 | const StyledPenIconDark = styled(PenIcon)(({theme}) => ({height: iconsHeight, color: theme.palette.primary.dark})) |
| 12 | const StyledPersonIconLight = styled(PersonIcon)({height: iconsHeight, color: "#03B9E9"}) |
| 13 | const StyledLockIcon = styled(LockIcon)({height: iconsHeight, color: "#03B9E9"}) |
| 14 | |
| 15 | export const UsernameInput = ({infoButtonProps, ...props}) => { |
| 16 | const [isSelected, setIsSelected] = React.useState(false); |
idillon | 24fe8d8 | 2022-08-29 16:55:20 -0400 | [diff] [blame] | 17 | const [input, setInput] = React.useState(props.defaultValue); |
idillon-sfl | 37c18df | 2022-08-26 18:44:27 -0400 | [diff] [blame] | 18 | const [startAdornment, setStartAdornment] = React.useState() |
| 19 | |
| 20 | const onChange = React.useCallback((event) => { |
| 21 | setInput(event.target.value) |
| 22 | props.onChange?.(event) |
| 23 | }, [props.onChange]) |
| 24 | |
| 25 | React.useEffect(() => { |
| 26 | /* Handle startAdornment */ |
| 27 | let Icon = StyledPersonIconLight |
| 28 | let visibility = "visible" |
| 29 | if (props.error) { |
idillon | b3788bf | 2022-08-29 15:57:57 -0400 | [diff] [blame] | 30 | Icon = StyledRoundCrossIconError |
idillon-sfl | 37c18df | 2022-08-26 18:44:27 -0400 | [diff] [blame] | 31 | } |
| 32 | else if (props.success) { |
| 33 | Icon = StyledCheckedIconSuccess |
| 34 | } |
| 35 | else if (!isSelected && !input) { |
| 36 | visibility = "hidden" // keep icon's space so text does not move |
| 37 | } |
| 38 | setStartAdornment(<Icon sx={{visibility}}/>) |
| 39 | }, [props.error, props.success, isSelected, input]) |
| 40 | |
| 41 | return ( |
| 42 | <TextField |
| 43 | {...props} |
| 44 | label="Choose an identifier" |
| 45 | variant="standard" |
| 46 | InputLabelProps={{ shrink: !!(isSelected || input) }} |
| 47 | onChange={onChange} |
| 48 | InputProps={{ |
| 49 | startAdornment, |
| 50 | endAdornment: <InfoButton {...infoButtonProps}/>, |
| 51 | }} |
| 52 | onFocus={() => setIsSelected(true)} |
| 53 | onBlur={() => setIsSelected(false)} |
| 54 | /> |
| 55 | ) |
| 56 | } |
| 57 | |
| 58 | export const PasswordInput = ({infoButtonProps, ...props}) => { |
| 59 | const [showPassword, setShowPassword] = React.useState(false); |
| 60 | const [isSelected, setIsSelected] = React.useState(false); |
idillon | 24fe8d8 | 2022-08-29 16:55:20 -0400 | [diff] [blame] | 61 | const [input, setInput] = React.useState(props.defaultValue); |
idillon-sfl | 37c18df | 2022-08-26 18:44:27 -0400 | [diff] [blame] | 62 | const [startAdornment, setStartAdornment] = React.useState() |
| 63 | |
| 64 | const toggleShowPassword = () => { |
| 65 | setShowPassword((showPassword) => !showPassword); |
| 66 | } |
| 67 | |
| 68 | const onChange = React.useCallback((event) => { |
| 69 | setInput(event.target.value) |
| 70 | props.onChange?.(event) |
| 71 | }, [props.onChange]) |
| 72 | |
| 73 | React.useEffect(() => { |
| 74 | /* Handle startAdornment */ |
| 75 | let Icon = StyledLockIcon |
| 76 | let visibility = "visible" |
| 77 | if (props.error) { |
idillon | b3788bf | 2022-08-29 15:57:57 -0400 | [diff] [blame] | 78 | Icon = StyledRoundCrossIconError |
idillon-sfl | 37c18df | 2022-08-26 18:44:27 -0400 | [diff] [blame] | 79 | } |
| 80 | else if (props.success) { |
| 81 | Icon = StyledCheckedIconSuccess |
| 82 | } |
| 83 | else if (!isSelected && !input) { |
| 84 | visibility = "hidden" // keep icon's space so text does not move |
| 85 | } |
| 86 | setStartAdornment(<Icon sx={{visibility}}/>) |
| 87 | }, [props.error, props.success, isSelected, input]) |
| 88 | |
| 89 | return ( |
| 90 | <TextField |
| 91 | {...props} |
| 92 | label="Password" |
| 93 | type={showPassword ? "text" : "password"} |
| 94 | variant="standard" |
| 95 | autoComplete="current-password" |
| 96 | InputLabelProps={{ shrink: !!(isSelected || input) }} |
| 97 | onChange={onChange} |
| 98 | InputProps={{ |
| 99 | startAdornment, |
| 100 | endAdornment: <Stack direction="row" spacing="14px"> |
| 101 | <InfoButton {...infoButtonProps}/> |
| 102 | <ToggleVisibilityButton |
| 103 | visible={showPassword} |
| 104 | onClick={toggleShowPassword} |
| 105 | /> |
| 106 | </Stack>, |
| 107 | }} |
| 108 | onFocus={() => setIsSelected(true)} |
| 109 | onBlur={() => setIsSelected(false)} |
| 110 | /> |
| 111 | ) |
| 112 | } |
| 113 | |
| 114 | export const NickNameInput = (props) => { |
| 115 | const [isSelected, setIsSelected] = React.useState(false); |
idillon | 24fe8d8 | 2022-08-29 16:55:20 -0400 | [diff] [blame] | 116 | const [input, setInput] = React.useState(props.defaultValue); |
idillon-sfl | 37c18df | 2022-08-26 18:44:27 -0400 | [diff] [blame] | 117 | const [startAdornmentVisibility, setStartAdornmentVisibility] = React.useState() |
| 118 | |
| 119 | const onChange = React.useCallback((event) => { |
| 120 | setInput(event.target.value) |
| 121 | props.onChange?.(event) |
| 122 | }, [props.onChange]) |
| 123 | |
| 124 | React.useEffect(() => { |
| 125 | setStartAdornmentVisibility((isSelected || input) ? "visible" : "hidden") |
| 126 | }, [isSelected, input]) |
| 127 | |
| 128 | return ( |
| 129 | <TextField |
| 130 | {...props} |
| 131 | label="Nickname, surname..." |
| 132 | variant="standard" |
| 133 | InputLabelProps={{ shrink: !!(isSelected || input) }} |
| 134 | onChange={onChange} |
| 135 | InputProps={{ |
| 136 | startAdornment: <StyledPenIconLight sx={{visibility: startAdornmentVisibility}}/>, |
| 137 | }} |
| 138 | onFocus={() => setIsSelected(true)} |
| 139 | onBlur={() => setIsSelected(false)} |
| 140 | /> |
| 141 | ) |
| 142 | } |
| 143 | |
| 144 | export const RegularInput = (props) => { |
| 145 | const [isSelected, setIsSelected] = React.useState(false); |
idillon | 24fe8d8 | 2022-08-29 16:55:20 -0400 | [diff] [blame] | 146 | const [input, setInput] = React.useState(props.defaultValue); |
idillon-sfl | 37c18df | 2022-08-26 18:44:27 -0400 | [diff] [blame] | 147 | const [startAdornmentVisibility, setStartAdornmentVisibility] = React.useState() |
| 148 | const [endAdornmentVisibility, setEndAdornmentVisibility] = React.useState() |
| 149 | |
| 150 | const onChange = React.useCallback((event) => { |
| 151 | setInput(event.target.value) |
| 152 | props.onChange?.(event) |
| 153 | }, [props.onChange]) |
| 154 | |
| 155 | React.useEffect(() => { |
| 156 | setStartAdornmentVisibility((isSelected || input) ? "visible" : "hidden") |
| 157 | setEndAdornmentVisibility((isSelected || input) ? "hidden" : "visible") |
| 158 | }, [isSelected, input]) |
| 159 | |
| 160 | return ( |
| 161 | <TextField |
| 162 | {...props} |
| 163 | variant="standard" |
| 164 | InputLabelProps={{ shrink: !!(isSelected || input) }} |
| 165 | onChange={onChange} |
| 166 | InputProps={{ |
| 167 | startAdornment: <StyledPenIconLight sx={{visibility: startAdornmentVisibility}}/>, |
| 168 | endAdornment: <StyledPenIconDark sx={{visibility: endAdornmentVisibility}}/>, |
| 169 | }} |
| 170 | onFocus={() => setIsSelected(true)} |
| 171 | onBlur={() => setIsSelected(false)} |
| 172 | /> |
| 173 | ) |
| 174 | } |