somewhat set text fields theme

Change-Id: I624d78fdb8c7c96d19713a72bf691c910b353e5e
diff --git a/client/src/components/buttons.js b/client/src/components/buttons.js
index 1233369..0919c69 100644
--- a/client/src/components/buttons.js
+++ b/client/src/components/buttons.js
@@ -1,8 +1,9 @@
+import { QuestionMark } from "@mui/icons-material";
 import { IconButton } from "@mui/material";
 import { styled } from "@mui/styles";
-import { CameraIcon, CancelIcon, FolderIcon, PenIcon } from "./svgIcons";
+import { CameraIcon, CancelIcon, CrossedEyeIcon, EyeIcon, FolderIcon, InfoIcon, PenIcon } from "./svgIcons";
 
-const CustomisePictureButton = styled(
+const RoundButton = styled(
     ({Icon, ...props}) => (
         <IconButton {...props} disableRipple={true}>
             <Icon fontSize="inherit"/>
@@ -11,8 +12,6 @@
 )(({theme}) => ({
     border: `1px solid ${theme.palette.primary.dark}`,
     color: theme.palette.primary.dark,
-    height: "53px",
-    width: "53px",
     fontSize: "15px",
     "&:hover": {
         background: theme.palette.primary.light,
@@ -21,40 +20,95 @@
         color: "#FFF",
         background: theme.palette.primary.dark,
     },
+    "&.MuiIconButton-sizeSmall": {
+        height: "15px",
+        width: "15px",
+    },
+    "&.MuiIconButton-sizeMedium": {
+        height: "30px",
+        width: "30px",
+    },
+    "&.MuiIconButton-sizeLarge": {
+        height: "53px",
+        width: "53px",
+    }
 }));
 
-export const RemovePictureButton = (props) => {
+export const CancelButton = (props) => {
     return (
-        <CustomisePictureButton {...props}
+        <RoundButton {...props}
             aria-label="remove picture"
             Icon={CancelIcon}
+            size="large"
         />
     )
 }
 
-export const EditPictureButton = (props) => {
+export const EditButton = (props) => {
     return (
-        <CustomisePictureButton {...props}
+        <RoundButton {...props}
             aria-label="edit picture"
             Icon={PenIcon}
+            size="large"
         />
     )
 }
 
-export const UploadPictureButton = (props) => {
+export const UploadButton = (props) => {
     return (
-        <CustomisePictureButton {...props}
+        <RoundButton {...props}
             aria-label="upload picture"
             Icon={FolderIcon}
+            size="large"
         />
     )
 }
 
 export const TakePictureButton = (props) => {
     return (
-        <CustomisePictureButton {...props}
+        <RoundButton {...props}
             aria-label="take picture"
             Icon={CameraIcon}
+            size="large"
         />
     )
 }
+
+export const InfoButton = (props) => {
+    return (
+        <RoundButton {...props}
+            aria-label="informations"
+            Icon={InfoIcon}
+            size="small"
+        />
+    )
+}
+
+export const TipButton = (props) => {
+    return (
+        <RoundButton {...props}
+            aria-label="informations"
+            Icon={QuestionMark}
+            size="medium"
+        />
+    )
+}
+
+export const ToggleVisibilityButton = styled(
+    ({visible, ...props}) => {
+        const Icon = visible ? CrossedEyeIcon : EyeIcon
+        return (
+            <IconButton {...props} disableRipple={true}>
+                <Icon fontSize="inherit"/>
+            </IconButton>
+        )
+    }
+)(({theme}) => ({
+    color: theme.palette.primary.dark,
+    fontSize: "15px",
+    height: "15px",
+    width: "15px",
+    "&:hover": {
+        background: theme.palette.primary.light,
+    },
+}));
\ No newline at end of file
diff --git a/client/src/components/inputs.js b/client/src/components/inputs.js
new file mode 100644
index 0000000..f7e5824
--- /dev/null
+++ b/client/src/components/inputs.js
@@ -0,0 +1,174 @@
+import { Stack, TextField } from "@mui/material"
+import { styled } from "@mui/styles"
+import React from "react"
+import { InfoButton, ToggleVisibilityButton } from "./buttons"
+import { CheckedIcon, CrossIcon, LockIcon, PenIcon, PersonIcon } from "./svgIcons"
+
+const iconsHeight = "16px"
+const StyledCheckedIconSuccess = styled(CheckedIcon)(({theme}) => ({height: iconsHeight, color: theme.palette.success.main}))
+const StyledCrossIconError = styled(CrossIcon)(({theme}) => ({height: iconsHeight, color: theme.palette.error.main}))
+const StyledPenIconLight = styled(PenIcon)({height: iconsHeight, color: "#03B9E9"})
+const StyledPenIconDark  = styled(PenIcon)(({theme}) => ({height: iconsHeight, color: theme.palette.primary.dark}))
+const StyledPersonIconLight = styled(PersonIcon)({height: iconsHeight, color: "#03B9E9"})
+const StyledLockIcon = styled(LockIcon)({height: iconsHeight, color: "#03B9E9"})
+
+export const UsernameInput = ({infoButtonProps, ...props}) => {
+    const [isSelected, setIsSelected] = React.useState(false);
+    const [input, setInput] = React.useState();
+    const [startAdornment, setStartAdornment] = React.useState()
+
+    const onChange = React.useCallback((event) => {
+        setInput(event.target.value)
+        props.onChange?.(event)
+    }, [props.onChange])
+
+    React.useEffect(() => {
+        /* Handle startAdornment */
+        let Icon = StyledPersonIconLight
+        let visibility = "visible"
+        if (props.error) {
+            Icon = StyledCrossIconError
+        }
+        else if (props.success) {
+            Icon = StyledCheckedIconSuccess
+        }
+        else if (!isSelected && !input) {
+            visibility = "hidden" // keep icon's space so text does not move
+        }
+        setStartAdornment(<Icon sx={{visibility}}/>)
+    }, [props.error, props.success, isSelected, input])
+
+    return (
+        <TextField
+            {...props}
+            label="Choose an identifier"
+            variant="standard"
+            InputLabelProps={{ shrink: !!(isSelected || input) }}
+            onChange={onChange}
+            InputProps={{
+                startAdornment,
+                endAdornment: <InfoButton {...infoButtonProps}/>,
+            }}
+            onFocus={() => setIsSelected(true)}
+            onBlur={() => setIsSelected(false)}
+        />
+    )
+}
+
+export const PasswordInput = ({infoButtonProps, ...props}) => {
+    const [showPassword, setShowPassword] = React.useState(false);
+    const [isSelected, setIsSelected] = React.useState(false);
+    const [input, setInput] = React.useState();
+    const [startAdornment, setStartAdornment] = React.useState()
+
+    const toggleShowPassword = () => {
+        setShowPassword((showPassword) => !showPassword);
+    }
+
+    const onChange = React.useCallback((event) => {
+        setInput(event.target.value)
+        props.onChange?.(event)
+    }, [props.onChange])
+
+    React.useEffect(() => {
+        /* Handle startAdornment */
+        let Icon = StyledLockIcon
+        let visibility = "visible"
+        if (props.error) {
+            Icon = StyledCrossIconError
+        }
+        else if (props.success) {
+            Icon = StyledCheckedIconSuccess
+        }
+        else if (!isSelected && !input) {
+            visibility = "hidden" // keep icon's space so text does not move
+        }
+        setStartAdornment(<Icon sx={{visibility}}/>)
+    }, [props.error, props.success, isSelected, input])
+
+    return (
+        <TextField
+            {...props}
+            label="Password"
+            type={showPassword ? "text" : "password"}
+            variant="standard"
+            autoComplete="current-password"
+            InputLabelProps={{ shrink: !!(isSelected || input) }}
+            onChange={onChange}
+            InputProps={{
+                startAdornment,
+                endAdornment: <Stack direction="row" spacing="14px">
+                    <InfoButton {...infoButtonProps}/>
+                    <ToggleVisibilityButton
+                        visible={showPassword}
+                        onClick={toggleShowPassword}
+                    />
+                </Stack>,
+            }}
+            onFocus={() => setIsSelected(true)}
+            onBlur={() => setIsSelected(false)}
+        />
+    )
+}
+
+export const NickNameInput = (props) => {
+    const [isSelected, setIsSelected] = React.useState(false);
+    const [input, setInput] = React.useState();
+    const [startAdornmentVisibility, setStartAdornmentVisibility] = React.useState()
+
+    const onChange = React.useCallback((event) => {
+        setInput(event.target.value)
+        props.onChange?.(event)
+    }, [props.onChange])
+
+    React.useEffect(() => {
+        setStartAdornmentVisibility((isSelected || input) ? "visible" : "hidden")
+    }, [isSelected, input])
+
+    return (
+        <TextField
+            {...props}
+            label="Nickname, surname..."
+            variant="standard"
+            InputLabelProps={{ shrink: !!(isSelected || input) }}
+            onChange={onChange}
+            InputProps={{
+                startAdornment: <StyledPenIconLight sx={{visibility: startAdornmentVisibility}}/>,
+            }}
+            onFocus={() => setIsSelected(true)}
+            onBlur={() => setIsSelected(false)}
+        />
+    )
+}
+
+export const RegularInput = (props) => {
+    const [isSelected, setIsSelected] = React.useState(false);
+    const [input, setInput] = React.useState();
+    const [startAdornmentVisibility, setStartAdornmentVisibility] = React.useState()
+    const [endAdornmentVisibility, setEndAdornmentVisibility] = React.useState()
+
+    const onChange = React.useCallback((event) => {
+        setInput(event.target.value)
+        props.onChange?.(event)
+    }, [props.onChange])
+
+    React.useEffect(() => {
+        setStartAdornmentVisibility((isSelected || input) ? "visible" : "hidden")
+        setEndAdornmentVisibility((isSelected || input) ? "hidden" : "visible")
+    }, [isSelected, input])
+
+    return (
+        <TextField
+            {...props}
+            variant="standard"
+            InputLabelProps={{ shrink: !!(isSelected || input) }}
+            onChange={onChange}
+            InputProps={{
+                startAdornment: <StyledPenIconLight sx={{visibility: startAdornmentVisibility}}/>,
+                endAdornment: <StyledPenIconDark sx={{visibility: endAdornmentVisibility}}/>,
+            }}
+            onFocus={() => setIsSelected(true)}
+            onBlur={() => setIsSelected(false)}
+        />
+    )
+}
diff --git a/client/src/components/svgIcons.js b/client/src/components/svgIcons.js
index f7350b6..0fe7d85 100644
--- a/client/src/components/svgIcons.js
+++ b/client/src/components/svgIcons.js
@@ -1,9 +1,19 @@
 import { SvgIcon } from "@mui/material"
 
+/*
+    We use SvgIcon so the icons can be handled more easily by Material ui components.
+    Here some tips to add an SvgIcon in case you too struggle to find informations online:
+    - Open the svg with https://jakearchibald.github.io/svgomg/ in order to clean it from useless information.
+    - Replace the <svg> tag for <SvgIcon>.
+    - Try removing "style" attributes. They are often uncessary and cause errors.
+    - If some "style" attributes are necessary, convert them to the React inline style syntax (https://reactjs.org/docs/dom-elements.html#style).
+    - Play with the viewBox attribute in order to center the icon and make it uses all available space. Adding a temporary border with inline style might help.
+*/
+
 export const CameraIcon = (props) => {
     return (
         <SvgIcon {...props} viewBox="2 3 20 19">
-              <path d="M3.6 20.3c-.4 0-.8-.2-1.1-.5-.2-.2-.4-.6-.4-.9V7.7c-.1-.3.1-.7.4-1 .2-.3.5-.4.8-.5H7.9l1.2-2.5h5.7L16 6.2h4.3c.4 0 .8.2 1.1.5.2.2.4.6.4.9v11.2c0 .4-.2.8-.5 1.1-.2.2-.6.4-.9.4H3.6zm0-12.6-.1 11v.1h17.1V7.7h-5.3L14 5.2h-4L8.8 7.7H3.6zm8.4 9.7c-1.2 0-2.3-.5-3.2-1.3-.8-.8-1.3-2-1.3-3.2 0-1.2.5-2.3 1.3-3.2.8-.8 2-1.3 3.2-1.3 1.2 0 2.3.5 3.2 1.3.8.8 1.3 2 1.3 3.2s-.5 2.3-1.3 3.2c-.9.8-2 1.3-3.2 1.3zm0-7.5c-.8 0-1.6.3-2.1.9S9 12.1 9 12.9s.3 1.6.9 2.1c1.1 1.1 3.1 1.1 4.3 0 .6-.6.9-1.3.9-2.1s-.3-1.6-.9-2.1c-.6-.6-1.4-.9-2.2-.9z"/>
+            <path d="M3.6 20.3c-.4 0-.8-.2-1.1-.5-.2-.2-.4-.6-.4-.9V7.7c-.1-.3.1-.7.4-1 .2-.3.5-.4.8-.5H7.9l1.2-2.5h5.7L16 6.2h4.3c.4 0 .8.2 1.1.5.2.2.4.6.4.9v11.2c0 .4-.2.8-.5 1.1-.2.2-.6.4-.9.4H3.6zm0-12.6-.1 11v.1h17.1V7.7h-5.3L14 5.2h-4L8.8 7.7H3.6zm8.4 9.7c-1.2 0-2.3-.5-3.2-1.3-.8-.8-1.3-2-1.3-3.2 0-1.2.5-2.3 1.3-3.2.8-.8 2-1.3 3.2-1.3 1.2 0 2.3.5 3.2 1.3.8.8 1.3 2 1.3 3.2s-.5 2.3-1.3 3.2c-.9.8-2 1.3-3.2 1.3zm0-7.5c-.8 0-1.6.3-2.1.9S9 12.1 9 12.9s.3 1.6.9 2.1c1.1 1.1 3.1 1.1 4.3 0 .6-.6.9-1.3.9-2.1s-.3-1.6-.9-2.1c-.6-.6-1.4-.9-2.2-.9z"/>
         </SvgIcon>
     )
 }
@@ -16,6 +26,46 @@
     )
 }
 
+export const CheckedIcon = (props) => {
+    return (
+        <SvgIcon {...props} viewBox="0 0 16 16">
+            <path d="M11.138 5.152 6.802 9.486l-1.936-1.94a.64205296.64205296 0 0 0-.908.908l2.39 2.394a.642.642 0 0 0 .908 0l4.79-4.785a.6431145.6431145 0 0 0-.908-.911Z"/>
+            <path d="M8 16a8 8 0 1 1 8-8 8.009 8.009 0 0 1-8 8ZM8 1.284A6.716 6.716 0 1 0 14.716 8 6.723 6.723 0 0 0 8 1.284Z"/>
+        </SvgIcon>
+    )
+}
+
+export const CrossedEyeIcon = (props) => {
+    return (
+        <SvgIcon {...props} viewBox="0 0 15.931 12.145">
+            <path d="M7.933 10.41a7.081 7.081 0 0 1-3.7-1.292 12.409 12.409 0 0 1-2.874-2.717.237.237 0 0 1 0-.366 14.122 14.122 0 0 1 2.429-2.372L3 2.873a14.6 14.6 0 0 0-2.836 2.93.629.629 0 0 0 .019.87 13.62 13.62 0 0 0 4.222 3.834 7.4 7.4 0 0 0 3.547 1 7.067 7.067 0 0 0 2.948-.711l-.848-.848a5.577 5.577 0 0 1-2.119.462ZM15.74 5.784a13.154 13.154 0 0 0-4.26-3.856A7.284 7.284 0 0 0 8.145.941a6.436 6.436 0 0 0-2.892.6l.848.848a5.691 5.691 0 0 1 1.793-.348 5.788 5.788 0 0 1 2.583.617 11.437 11.437 0 0 1 3.586 2.783c.193.212.347.424.54.636a.209.209 0 0 1 .019.289 13.993 13.993 0 0 1-2.256 2.275l.79.79a14.6 14.6 0 0 0 2.6-2.737.658.658 0 0 0-.016-.91Z"/>
+            <path d="m9.687 5.974 1 1a3.349 3.349 0 0 0 .1-.752 2.867 2.867 0 0 0-2.835-2.848 2.576 2.576 0 0 0-.771.116l1.022 1.021a1.738 1.738 0 0 1 1.484 1.463ZM5.311 5.205a2.6 2.6 0 0 0-.193 1.022A2.867 2.867 0 0 0 7.971 9.06a3.005 3.005 0 0 0 1.022-.193l-.906-.906h-.135a1.749 1.749 0 0 1-1.734-1.773v-.077ZM2.882.173A.514.514 0 0 0 2.493 0a.659.659 0 0 0-.556.386.49.49 0 0 0 .135.578l11.007 11.007a.514.514 0 0 0 .386.173.659.659 0 0 0 .559-.386.49.49 0 0 0-.131-.577Z"/>
+        </SvgIcon>
+    )
+}
+
+export const CrossIcon = (props) => {
+    return (
+        <SvgIcon {...props} viewBox="0 0 16 16">
+            <path d="M8 16a8 8 0 1 1 8-8 8.009 8.009 0 0 1-8 8ZM8 .888A7.112 7.112 0 1 0 15.112 8 7.12 7.12 0 0 0 8 .888Z"/>
+            <path d="M10.837 5.167a.444.444 0 0 0-.628 0l-2.2 2.2-2.214-2.2a.44406306.44406306 0 0 0-.628.628l2.2 2.2-2.2 2.2a.44904009.44904009 0 0 0 .628.642l2.2-2.2 2.2 2.2a.4507918.4507918 0 1 0 .642-.633l-2.2-2.2 2.2-2.209a.445.445 0 0 0 0-.628Z"/>
+        </SvgIcon>
+    )
+}
+
+export const EyeIcon = (props) => {
+    return (
+        <SvgIcon {...props} viewBox="0 0 15.931 10.568">
+            <path d="M7.933 9.469a7.081 7.081 0 0 1-3.7-1.292A12.409 12.409 0 0 1 1.359 5.46a.237.237 0 0 1 0-.366c.733-.892 3.322-3.276 4.685-3.702l-.791-.79a18.682 18.682 0 0 0-5.089 4.26.629.629 0 0 0 .019.867 13.62 13.62 0 0 0 4.222 3.837 7.4 7.4 0 0 0 3.547 1 7.067 7.067 0 0 0 2.948-.711l-.847-.853a5.577 5.577 0 0 1-2.12.467Z"/>
+            <path d="M15.74 4.843A13.154 13.154 0 0 0 11.48.987 7.284 7.284 0 0 0 8.145 0a6.436 6.436 0 0 0-2.892.6l.848.848A5.691 5.691 0 0 1 7.894 1.1a5.788 5.788 0 0 1 2.583.617A11.437 11.437 0 0 1 14.063 4.5c.193.212.347.424.54.636a.209.209 0 0 1 .019.289 17.151 17.151 0 0 1-4.627 3.6l.79.79a21.4 21.4 0 0 0 4.973-4.067.658.658 0 0 0-.018-.905Z"/>
+            <g transform="translate(4.952 1.963)" style={{"stroke": "#005699", "fill": "none"}}>
+                <circle cx="3" cy="3" r="3" style={{"stroke": "none"}}/>
+                <circle cx="3" cy="3" r="2.5"/>
+            </g>
+        </SvgIcon>
+    )
+}
+
 export const FolderIcon = (props) => {
     return (
         <SvgIcon {...props} viewBox="0 0 17.504 14.812">
@@ -24,6 +74,24 @@
     )
 }
 
+export const InfoIcon = (props) => {
+    return (
+        <SvgIcon {...props} viewBox="2 2 20 20">
+            <path d="M11 7h2v2h-2zm0 4h2v6h-2zm1-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>
+        </SvgIcon>
+    )
+}
+
+export const LockIcon = (props) => {
+    return (
+        <SvgIcon {...props} viewBox="0 0 12.727 15.636">
+            <path d="M10.727 15.636H2a2 2 0 0 1-2-2V7.454a2 2 0 0 1 2-2h8.727a2 2 0 0 1 2 2v6.182a2 2 0 0 1-2 2ZM2 6.545a.91.91 0 0 0-.909.909v6.182a.91.91 0 0 0 .909.909h8.727a.908.908 0 0 0 .909-.909V7.454a.908.908 0 0 0-.909-.909Z"/>
+            <path d="M10.363 6.546h-8A.546.546 0 0 1 1.818 6V4.181a4.048 4.048 0 0 1 1.35-2.974A4.73 4.73 0 0 1 6.364 0a4.729 4.729 0 0 1 3.195 1.207 4.048 4.048 0 0 1 1.35 2.974V6a.546.546 0 0 1-.546.546Zm-4-5.455a3.645 3.645 0 0 0-2.462.923 2.918 2.918 0 0 0-.993 2.167v1.274h6.91V4.181a2.918 2.918 0 0 0-.993-2.167 3.644 3.644 0 0 0-2.461-.923ZM6.363 11.272a1.636 1.636 0 1 1 1.636-1.636 1.638 1.638 0 0 1-1.636 1.636Zm0-2.182a.545.545 0 1 0 .545.545.546.546 0 0 0-.545-.544Z"/>
+            <path d="M5.818 10.727v1.819a.5455.5455 0 1 0 1.091 0v-1.819a.5455.5455 0 0 0-1.091 0Z"/>
+        </SvgIcon>
+    )
+}
+
 export const PenIcon = (props) => {
     return (
         <SvgIcon {...props} viewBox="0 0 14.863 14.863">
@@ -31,3 +99,13 @@
         </SvgIcon>
     )
 }
+
+export const PersonIcon = (props) => {
+    return (
+    <SvgIcon {...props} viewBox="0 0 24 24">
+        <g stroke="#03B9E9" strokeWidth="1.75" fill="none" fillRule="evenodd" strokeLinejoin="round">
+            <path d="M17 6.5c0 2.48522308-2.0147769 4.5-4.5 4.5C10.01477692 11 8 8.98522308 8 6.5 8 4.0147769 10.01477692 2 12.5 2 14.9852231 2 17 4.0147769 17 6.5ZM3 22c0-5.5228267 4.02947764-10 9.00005436-10C16.9705224 12 21 16.4771733 21 22"/>
+        </g>
+    </SvgIcon>
+    )
+}
diff --git a/client/src/themes/default.js b/client/src/themes/default.js
index 4de4f94..1e4f0ac 100644
--- a/client/src/themes/default.js
+++ b/client/src/themes/default.js
@@ -69,6 +69,7 @@
           fontSize: "15px",
           lineHeight: "17px",
           textTransform: "none",
+          borderRadius: "5px",
         },
         sizeSmall: {
           height: "36px",
@@ -140,6 +141,70 @@
         },
       },
     },
+    MuiInput: {
+      styleOverrides: {
+        root: {
+          color: theme.palette.primary.dark,
+          "&.Mui-error": {
+            color: theme.palette.error.main,
+          },
+        },
+        underline: {
+          /*
+            Material UI uses "before" for the regular underline.
+            There is a second underline called "after" placed over "before"
+          */
+          "&:before": {
+            borderBottom: `2px solid ${theme.palette.primary.dark}`,
+          },
+          "&:hover:not(.Mui-disabled, .Mui-error):before": {
+            borderBottom: "2px solid #03B9E9",
+          },
+          "&:after": {
+            borderBottom: "2px solid #03B9E9",
+          },
+          "&:hover:not(.Mui-error):after": {
+            borderBottom: "2px solid #03B9E9",
+          },
+        },
+      }
+    },
+    MuiFormControl: {
+      styleOverrides: {
+        root: {
+          height: "90px",
+        },
+      },
+    },
+    MuiFormHelperText: {
+      styleOverrides: {
+        root: {
+          position: "absolute",
+          bottom: "0px",
+          fontSize: "15px",
+        },
+      },
+    },
+    MuiInputLabel: {
+      styleOverrides: {
+        root: {
+          color: "black",
+          fontSize: "15px",
+          left: "50%",
+          transform: "translate(-50%, 20px)",
+          transition: "left .2s, transform .2s",
+        },
+        shrink: {
+          color: "black",
+          left: 0,
+          transform: "translate(0, 50px) scale(0.75)",
+          transition: "left .2s, transform .2s",
+          "&.Mui-focused, &.Mui-error": {
+            color: "black",
+          },
+        },
+      },
+    },
     MuiCssBaseline: {
       styleOverrides: `
         @font-face {