Merge pull request #331 from bluewave-labs/feat/textfield-refactor

Refactored textfield components into one
This commit is contained in:
Alexander Holliday authored and GitHub committed 2024-07-13 15:03:45 -07:00
commit df7655310e
34 files changed
+502 -1175

No files matched your search

@@ -0,0 +1,89 @@
.field {
min-width: 250px;
}
.field h3.MuiTypography-root,
.field h5.MuiTypography-root,
.field input,
.field textarea,
.field .input-error {
font-size: var(--env-var-font-size-medium);
}
.field h3.MuiTypography-root,
.field h5.MuiTypography-root,
.field input,
.field textarea {
color: var(--env-var-color-5);
}
.field h3.MuiTypography-root {
font-weight: 500;
}
.field h3.MuiTypography-root span.field-required {
color: var(--env-var-color-19);
margin-left: 2px;
}
.field h3.MuiTypography-root span.field-optional {
opacity: 0.6;
margin-left: 4px;
}
.field h5.MuiTypography-root {
position: relative;
opacity: 0.8;
padding-right: var(--env-var-spacing-1-minus);
}
.field .MuiInputBase-root:has(input) {
height: 34px;
}
.field .MuiInputBase-root:has(.MuiInputAdornment-root) {
padding-right: var(--env-var-spacing-1-minus);
}
.field .MuiInputBase-root:has(.copy.MuiInputAdornment-root > .MuiButtonBase-root) {
padding-right: 0;
}
.field .MuiInputBase-root .copy.MuiInputAdornment-root .MuiButtonBase-root {
padding: 0 var(--env-var-spacing-1-minus);
font-size: var(--env-var-font-size-medium);
border-radius: 0;
height: 34px;
}
.field .MuiInputBase-root .copy.MuiInputAdornment-root .MuiButtonBase-root svg {
width: 20px;
height: 20px;
margin-right: 5px;
}
.field .MuiInputBase-root .MuiInputAdornment-root .MuiButtonBase-root:hover {
border-color: var(--env-var-color-29);
}
.field input {
height: 100%;
padding: 0 var(--env-var-spacing-1-minus);
}
.field .MuiInputBase-root:has(textarea) {
padding: var(--env-var-spacing-1-minus);
}
.field .MuiOutlinedInput-root fieldset {
border-color: var(--env-var-color-29);
border-radius: var(--env-var-radius-1);
}
.field:not(:has(.input-error))
.MuiOutlinedInput-root:hover:not(:has(input:focus)):not(:has(textarea:focus))
fieldset {
border-color: var(--env-var-color-29);
}
.field .input-error {
color: var(--env-var-color-24);
opacity: 0.8;
}
.field:has(.input-error) .MuiOutlinedInput-root fieldset {
border-color: var(--env-var-color-19);
}
.register-page .field .MuiOutlinedInput-root fieldset,
.register-page .field input,
.login-page .field .MuiOutlinedInput-root fieldset,
.login-page .field input,
.forgot-password-page .field .MuiOutlinedInput-root fieldset,
.forgot-password-page .field input,
.set-new-password-page .field .MuiOutlinedInput-root fieldset,
.set-new-password-page .field input {
border-radius: var(--env-var-radius-2);
}
@@ -0,0 +1,158 @@
import PropTypes from "prop-types";
import { useTheme } from "@emotion/react";
import {
IconButton,
InputAdornment,
Stack,
TextField,
Typography,
} from "@mui/material";
import VisibilityOff from "@mui/icons-material/VisibilityOff";
import Visibility from "@mui/icons-material/Visibility";
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
import Button from "../../Button";
import "./index.css";
import { useState } from "react";
/**
* @param {Object} props
* @param {string} [props.type] - Type of input field (e.g., 'text', 'password').
* @param {string} props.id - ID of the input field.
* @param {string} [props.label] - Label for the input field.
* @param {boolean} [props.isRequired] - Indicates if the field is required, will display a red asterisk.
* @param {boolean} [props.isOptional] - Indicates if the field is optional, will display optional text.
* @param {boolean} [props.hasCopy] - Indicates if the field supports copying.
* @param {string} [props.autoComplete] - Autocomplete value for the input field.
* @param {string} [props.placeholder] - Placeholder text for the input field.
* @param {string} props.value - Value of the input field.
* @param {function} props.onChange - Function called on input change.
* @param {string} [props.error] - Error message to display for the input field.
* @param {boolean} [props.disabled] - Indicates if the input field is disabled.
*/
const Field = ({
type = "text",
id,
label,
isRequired,
isOptional,
hasCopy,
autoComplete,
placeholder,
value,
onChange,
error,
disabled,
}) => {
const theme = useTheme();
// TODO - are we using this feature anywhere ?
const [copy, setCopy] = useState(false);
const handleCopy = () => {
setCopy(true);
setTimeout(() => setCopy(false), 1000);
};
const [isVisible, setVisible] = useState(false);
return (
<Stack gap={theme.gap.xs} className={`field field-${type}`}>
{label && (
<Typography component="h3">
{label}
{isRequired ? <span className="field-required">*</span> : ""}
{isOptional ? <span className="field-optional">(optional)</span> : ""}
</Typography>
)}
<TextField
type={type === "password" ? (isVisible ? "text" : type) : type}
id={id}
autoComplete={autoComplete}
placeholder={placeholder}
multiline={type === "description"}
rows={type === "description" ? 4 : 1}
value={value}
onChange={onChange}
disabled={disabled}
InputProps={{
startAdornment: type === "url" && (
<Stack
direction="row"
alignItems="center"
height="100%"
sx={{
borderRight: `solid 1px ${theme.palette.section.borderColor}`,
}}
>
<Typography component="h5">https://</Typography>
</Stack>
),
endAdornment:
type === "password" ? (
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={() => setVisible((show) => !show)}
tabIndex={-1}
sx={{
color: theme.palette.section.borderColor,
padding: `calc(${theme.gap.xs} / 2)`,
"&:focus": {
outline: "none",
},
"& .MuiTouchRipple-root": {
pointerEvents: "none",
display: "none",
},
}}
>
{!isVisible ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
) : (
hasCopy && (
<InputAdornment className="copy" position="end">
<Button
level="tertiary"
label={copy ? "Copied" : "Copy"}
img={<ContentCopyIcon />}
onClick={handleCopy}
sx={{
borderLeft: `solid 1px ${theme.palette.section.borderColor}`,
lineHeight: 0,
"& .MuiTouchRipple-root": {
pointerEvents: "none",
display: "none",
},
}}
/>
</InputAdornment>
)
),
}}
/>
{error && (
<Typography component="span" className="input-error" mt={theme.gap.xs}>
{error}
</Typography>
)}
</Stack>
);
};
Field.propTypes = {
type: PropTypes.oneOf(["text", "password", "url", "email", "description"]),
id: PropTypes.string.isRequired,
label: PropTypes.string,
isRequired: PropTypes.bool,
isOptional: PropTypes.bool,
hasCopy: PropTypes.bool,
autoComplete: PropTypes.string,
placeholder: PropTypes.string,
value: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
error: PropTypes.string,
disabled: PropTypes.bool,
};
export default Field;
@@ -3,7 +3,7 @@ import React, { useState } from "react";
import { useTheme } from "@emotion/react";
import { Box, Divider, Stack, Typography } from "@mui/material";
import ButtonSpinner from "../../ButtonSpinner";
import PasswordTextField from "../../TextFields/Password/PasswordTextField";
import Field from "../../Inputs/Field";
import { editPasswordValidation } from "../../../Validation/validation";
import Alert from "../../Alert";
import { update } from "../../../Features/Auth/authSlice";
@@ -35,7 +35,6 @@ const PasswordPanel = () => {
confirm: "",
});
const [errors, setErrors] = useState({});
const [showPassword, setShowPassword] = useState(false); // password visibility
const handleChange = (event) => {
const { value, id } = event.target;
@@ -120,76 +119,43 @@ const PasswordPanel = () => {
<Stack>
<Typography component="h1">Current password</Typography>
</Stack>
<Stack>
<PasswordTextField
id="edit-current-password"
label={null}
placeholder="Enter your current password"
autoComplete="current-password"
visibility={showPassword}
setVisibility={setShowPassword}
value={localData.password}
onChange={handleChange}
error={errors[idToName["edit-current-password"]] ? true : false}
/>
{errors[idToName["edit-current-password"]] ? (
<Typography component="p" className="input-error">
{errors[idToName["edit-current-password"]]}
</Typography>
) : (
""
)}
</Stack>
<Field
type="password"
id="edit-current-password"
placeholder="Enter your current password"
autoComplete="current-password"
value={localData.password}
onChange={handleChange}
error={errors[idToName["edit-current-password"]]}
/>
</div>
<div className="edit-password-form__wrapper">
<Stack>
<Typography component="h1">New password</Typography>
</Stack>
<Stack>
<PasswordTextField
id="edit-new-password"
label={null}
placeholder="Enter your new password"
autoComplete="new-password"
visibility={showPassword}
setVisibility={setShowPassword}
value={localData.newPassword}
onChange={handleChange}
error={errors[idToName["edit-new-password"]] ? true : false}
/>
{errors[idToName["edit-new-password"]] ? (
<Typography component="p" className="input-error">
{errors[idToName["edit-new-password"]]}
</Typography>
) : (
""
)}
</Stack>
<Field
type="password"
id="edit-new-password"
placeholder="Enter your new password"
autoComplete="new-password"
value={localData.newPassword}
onChange={handleChange}
error={errors[idToName["edit-new-password"]]}
/>
</div>
<div className="edit-password-form__wrapper">
<Stack>
<Typography component="h1">Confirm new password</Typography>
</Stack>
<Stack>
<PasswordTextField
id="edit-confirm-password"
label={null}
placeholder="Reenter your new password"
autoComplete="new-password"
visibility={showPassword}
setVisibility={setShowPassword}
value={localData.confirm}
onChange={handleChange}
error={errors[idToName["edit-confirm-password"]] ? true : false}
/>
{errors[idToName["edit-confirm-password"]] ? (
<Typography component="p" className="input-error">
{errors[idToName["edit-confirm-password"]]}
</Typography>
) : (
""
)}
</Stack>
<Field
type="password"
id="edit-confirm-password"
placeholder="Reenter your new password"
autoComplete="new-password"
value={localData.confirm}
onChange={handleChange}
error={errors[idToName["edit-confirm-password"]]}
/>
</div>
<div className="edit-password-form__wrapper">
<Stack></Stack>
@@ -4,9 +4,9 @@ import TabPanel from "@mui/lab/TabPanel";
import { Box, Divider, Modal, Stack, Typography } from "@mui/material";
import ButtonSpinner from "../../ButtonSpinner";
import Button from "../../Button";
import EmailTextField from "../../TextFields/Email/EmailTextField";
import StringTextField from "../../TextFields/Text/TextField";
import Avatar from "../../Avatar";
import Field from "../../Inputs/Field";
import ImageField from "../../Inputs/Image";
import {
editProfileValidation,
imageValidation,
@@ -17,7 +17,6 @@ import {
deleteUser,
update,
} from "../../../Features/Auth/authSlice";
import ImageField from "../../TextFields/Image";
import ImageIcon from "@mui/icons-material/Image";
import ProgressUpload from "../../ProgressBars";
import { formatBytes } from "../../../Utils/fileUtils";
@@ -219,47 +218,27 @@ const ProfilePanel = () => {
<Stack>
<Typography component="h1">First name</Typography>
</Stack>
<Stack>
<StringTextField
id="edit-first-name"
label={null}
value={localData.firstname}
placeholder="Enter your first name"
autoComplete="given-name"
onChange={handleChange}
error={errors[idToName["edit-first-name"]] ? true : false}
/>
{errors[idToName["edit-first-name"]] ? (
<Typography component="p" className="input-error">
{errors[idToName["edit-first-name"]]}
</Typography>
) : (
""
)}
</Stack>
<Field
id="edit-first-name"
value={localData.firstname}
placeholder="Enter your first name"
autoComplete="given-name"
onChange={handleChange}
error={errors[idToName["edit-first-name"]]}
/>
</div>
<div className="edit-profile-form__wrapper">
<Stack>
<Typography component="h1">Last name</Typography>
</Stack>
<Stack>
<StringTextField
id="edit-last-name"
label={null}
value={localData.lastname}
placeholder="Enter your last name"
autoComplete="family-name"
onChange={handleChange}
error={errors[idToName["edit-last-name"]] ? true : false}
/>
{errors[idToName["edit-last-name"]] ? (
<Typography component="p" className="input-error">
{errors[idToName["edit-last-name"]]}
</Typography>
) : (
""
)}
</Stack>
<Field
id="edit-last-name"
placeholder="Enter your last name"
autoComplete="family-name"
value={localData.lastname}
onChange={handleChange}
error={errors[idToName["edit-last-name"]]}
/>
</div>
<div className="edit-profile-form__wrapper">
<Stack>
@@ -268,25 +247,15 @@ const ProfilePanel = () => {
This is your current email address — it cannot be changed.
</Typography>
</Stack>
<Stack>
<EmailTextField
id="edit-email"
label={null}
value={user.email}
placeholder="Enter your email"
autoComplete="email"
// onChange={handleChange}
// error={errors[idToName["edit-email"]] ? true : false}
disabled={true}
/>
{errors[idToName["edit-email"]] ? (
<Typography component="p" className="input-error">
{errors[idToName["edit-email"]]}
</Typography>
) : (
""
)}
</Stack>
<Field
id="edit-email"
value={user.email}
placeholder="Enter your email"
autoComplete="email"
// onChange={handleChange}
// error={errors[idToName["edit-email"]]}
disabled={true}
/>
</div>
<div className="edit-profile-form__wrapper">
<Stack>
@@ -1,49 +0,0 @@
import React from "react";
import "./descriptionTextField.css";
import { TextField } from "@mui/material";
import PropTypes from "prop-types";
import { useTheme } from "@mui/material";
/**
* @component
* @param {Object} props
* @param {function} props.onChange - The function to call when the text field changes (optional)
* @param {string} props.hintText - The hint text displayed within the text field (required)
* @param {boolean} props.hasError - A flag indicating if the text field has an error (required)
* @returns {JSX.Element} - Renders the description text field component
*/
const DescriptionTextField = ({ onChange, hintText, hasError }) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
return (
<div
className="description-field-holder"
style={{ fontFamily: fontFamily }}
>
<div className="text-field-title">Description</div>
<TextField
onChange={onChange}
id="description-field-area"
error={hasError}
className="description-field-area"
multiline
rows={4}
placeholder="Enter a description..."
helperText={hintText}
/>
</div>
);
};
DescriptionTextField.propTypes = {
hintText: PropTypes.string.isRequired,
hasError: PropTypes.bool.isRequired,
};
export default DescriptionTextField;
@@ -1,77 +0,0 @@
:root {
--env-var-color-1: #101828;
--env-var-color-2: #475467;
--env-var-color-3: #1570ef;
--env-var-color-4: #d0d5dd;
--env-var-color-5: #344054;
--env-var-color-6: #eaecf0;
--env-var-color-7: #7f56d9;
--env-var-color-8: #fff;
--env-var-color-9: #f2f2f2;
--env-var-color-10: #175cd3;
--env-var-radius-1: 4px;
--env-var-radius-2: 8px;
--env-var-width-1: 100vw;
--env-var-width-2: 360px;
--env-var-height-1: 100vh;
--env-var-spacing-1: 12px;
--env-var-spacing-2: 24px;
--env-var-spacing-3: 32px;
--env-var-spacing-4: 40px;
--env-var-font-size-small: 11px;
--env-var-font-size-medium: 13px;
--env-var-font-size-medium-plus: 14px;
--env-var-font-size-large: 16px;
--env-var-font-size-xlarge: 30px;
--env-var-img-width-1: 20px;
--env-var-default-1: 24px;
--env-var-default-2: 40px;
}
.description-field-holder {
margin: 10px 20px;
margin-top: 20px;
}
.text-field-title {
color: var(--env-var-color-5);
font-weight: bold;
margin-bottom: 10px;
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
font-weight: bold;
}
.description-field-area {
min-width: 320px;
font-size: var(--env-var-font-size-medium);
border-radius: 8px;
}
.description-field-label {
margin-top: 10px;
font-size: var(--env-var-font-size-small);
}
.with-error {
color: red;
}
#description-field-area-helper-text {
margin-left: 0;
margin-top: 10px;
font-size: var(--env-var-font-size-small);
}
#description-field-area {
min-width: 320px;
font-size: var(--env-var-font-size-medium);
}
@@ -1,106 +0,0 @@
import React, { useState } from "react";
import "./emailTextField.css";
import { InputAdornment, TextField } from "@mui/material";
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
import { useTheme } from "@mui/material";
/**
* `EmailTextField` is a functional React component that renders a text field for email input.
*
* @component
* @param {Object} props - The properties that define the `EmailTextField` component.
* @param {function} props.onChange - The function to call when the text field changes.
* @param {string} props.id - The id of the text field.
* @param {string} [props.label="Email"] - The label of the text field.
* @param {string} props.value - The value of the text field.
* @param {string} props.variant - The variant of the text field.
* @param {string} props.placeholder - The placeholder of the text field.
* @param {React.Element} props.icon - The icon to be displayed in the text field.
* @param {string} props.helperText - The helper text to be displayed below the text field.
* @param {boolean} props.error - If true, the text field will indicate an error state.
* @param {boolean} props.disabled - If true, the text field will be disabled and cannot be interacted with.
*
* @example
* // To use this component, import it and use it in your JSX like this:
* <EmailTextField id="email" variant="outlined" placeholder="Enter your email" />
*
* @returns {React.Element} The `EmailTextField` component with a text field for email input.
*/
const EmailTextField = ({
onChange,
id,
label = "Email",
value = undefined,
variant,
placeholder,
autoComplete,
icon,
helperText,
error,
disabled
}) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
const [showIcon, setShowIcon] = useState(false);
const handleMouseEnter = () => setShowIcon(true);
const handleMouseLeave = () => setShowIcon(false);
return (
<div style={{ fontFamily: fontFamily }}>
<div className="email-text-field-title">{label}</div>
<div className="email-text-field">
<TextField
onChange={onChange}
error={error}
className="email-text-field-input"
id={id}
value={value}
variant={variant}
placeholder={placeholder}
autoComplete={autoComplete}
disabled={disabled}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<div className="icon-holder">
{error && showIcon && (
<ErrorOutlineIcon
className="text-field-icon"
style={{ fill: "red", width: "16px", height: "16px" }}
/>
)}
{error && !showIcon && (
<ErrorOutlineIcon
className="text-field-icon"
style={{ fill: "red", width: "16px", height: "16px" }}
/>
)}
{!error && showIcon && !disabled && (
<HelpOutlineIcon
className="text-field-icon"
style={{ width: "16px", height: "16px" }}
/>
)}
</div>
</InputAdornment>
),
}}
helperText={helperText}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
/>
</div>
</div>
);
};
export default EmailTextField;
@@ -1,77 +0,0 @@
:root {
--env-var-color-1: #101828;
--env-var-color-2: #475467;
--env-var-color-3: #1570ef;
--env-var-color-4: #d0d5dd;
--env-var-color-5: #344054;
--env-var-color-6: #eaecf0;
--env-var-color-7: #7f56d9;
--env-var-color-8: #fff;
--env-var-color-9: #f2f2f2;
--env-var-color-10: #175cd3;
--env-var-radius-1: 4px;
--env-var-radius-2: 8px;
--env-var-width-1: 100vw;
--env-var-width-2: 360px;
--env-var-height-1: 100vh;
--env-var-spacing-1: 12px;
--env-var-spacing-2: 24px;
--env-var-spacing-3: 32px;
--env-var-spacing-4: 40px;
--env-var-font-size-small: 11px;
--env-var-font-size-medium: 13px;
--env-var-font-size-medium-plus: 14px;
--env-var-font-size-large: 16px;
--env-var-font-size-xlarge: 30px;
--env-var-img-width-1: 20px;
--env-var-default-1: 24px;
--env-var-default-2: 40px;
}
.email-text-field {
position: relative;
margin-top: 10px;
}
#outlined-basic {
width: 320px;
height: 14px;
font-size: var(--env-var-font-size-medium);
padding: 8px 12px;
}
.email-text-field-title {
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
font-weight: bold;
}
.email-text-field-input {
font-size: var(--env-var-font-size-medium);
}
#outlined-basic-helper-text {
margin-left: 0;
margin-top: 10px;
font-size: var(--env-var-font-size-small);
}
.text-field-icon {
width: 16px;
height: 16px;
}
.icon-holder {
width: 16px;
height: 16px;
padding: 0;
margin: 0;
}
@@ -1,59 +0,0 @@
import PropTypes from "prop-types";
import { Stack, Typography } from "@mui/material";
import "./flexibileTextField.css";
import { useTheme } from "@emotion/react";
/**
* @param {Object} props - The component props.
* @param {string} props.id - The ID of the input field.
* @param {string} props.title - The title or label for the input field.
* @param {string} props.type - The type of the input field (e.g., 'text', 'password').
* @param {string} props.placeholder - The placeholder text for the input field.
* @param {string} props.value - The current value of the input field.
* @param {function} props.onChange - The function to call when the input field value changes.
* @param {string} [props.error] - Optional. Error message to display if there's an error with the input.
* @returns {JSX.Element} JSX Element representing the flexible text input field.
*/
const FlexibileTextField = ({
id,
title,
type,
placeholder,
value,
onChange,
error,
}) => {
const theme = useTheme();
return (
<Stack className="flexible-textfield" gap={theme.gap.small}>
<Typography component="h2">{title}</Typography>
<input
id={id}
type={type}
placeholder={placeholder}
value={value}
onChange={onChange}
/>
{error ? (
<Typography component="p" className="input-error">
{error}
</Typography>
) : (
""
)}
</Stack>
);
};
FlexibileTextField.propTypes = {
id: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
placeholder: PropTypes.string,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
onChange: PropTypes.func.isRequired,
error: PropTypes.string,
};
export default FlexibileTextField;
@@ -1,30 +0,0 @@
.flexible-textfield{
position: relative;
}
.flexible-textfield h2.MuiTypography-root{
color: var(--env-var-color-5);
font-size: var(--env-var-font-size-medium);
font-weight: 400;
}
.flexible-textfield h2.MuiTypography-root span{
opacity: 0.6;
}
.flexible-textfield input {
min-width: 300px;
height: 34px;
padding: 0 var(--env-var-spacing-1);
border: 1px solid var(--env-var-color-4);
border-radius: var(--env-var-radius-1);
}
.flexible-textfield p.MuiTypography-root.input-error {
color: var(--env-var-color-24);
opacity: 0.8;
position: absolute;
top: calc(100% + 5px);
}
.flexible-textfield:has(p.MuiTypography-root.input-error) input{
border-color: var(--env-var-color-24);
}
.flexible-textfield input:focus {
outline: none;
}
@@ -1,119 +0,0 @@
import "./passwordTextField.css";
import React, { useState } from "react";
import { IconButton, InputAdornment, TextField } from "@mui/material";
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
import { useTheme } from "@mui/material";
import VisibilityOff from "@mui/icons-material/VisibilityOff";
import Visibility from "@mui/icons-material/Visibility";
/**
* @component
* @param {Object} props
* @param {string} props.value - The current value of the text field
* @param {function} props.onChange - The function to call when the text field changes (optional)
* @param {string} props.id - Unique ID for the text field (optional)
* @param {string} props.label - The label text displayed above the text field (optional)
* @param {"standard" | "outlined" | "filled"} props.variant - The variant of the text field (e.g., "outlined") (optional)
* @param {string} props.placeholder - The placeholder text displayed within the text field (optional)
* @param {"error" | "help"} [props.icon] - The type of icon to display (error or help) (optional)
* @param {string} props.helperText - The helper text displayed below the text field (optional)
* @param {boolean} props.error - A flag indicating if the text field has an error (required)
* @param {boolean} props.visibility - A flag indicating if the password visibility is toggled (optional)
* @param {function} props.setVisibility - Function to toggle password visibility (optional)
* @returns {JSX.Element} - Renders the password text field component with dynamic icon display
*/
const PasswordTextField = ({
value,
onChange,
id,
label = "Password",
autoComplete,
variant,
placeholder,
icon,
helperText,
error,
visibility,
setVisibility,
}) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
const [showIcon, setShowIcon] = useState(false);
const handleMouseEnter = () => setShowIcon(true);
const handleMouseLeave = () => setShowIcon(false);
return (
<div style={{ fontFamily: fontFamily }}>
<div className="password-text-field-title">{label}</div>
<div className="password-text-field">
<TextField
value={value}
onChange={onChange}
type={visibility ? "text" : "password"}
autoComplete={autoComplete}
error={error}
className="password-text-field-input"
id={id}
variant={variant}
placeholder={placeholder}
InputProps={{
endAdornment: (
<InputAdornment position="end">
{visibility !== undefined ? (
<IconButton
aria-label="toggle password visibility"
onClick={() => setVisibility((show) => !show)}
tabIndex={-1}
sx={{
width: "30px",
height: "30px",
"&:focus": {
outline: "none",
},
}}
>
{!visibility ? <VisibilityOff /> : <Visibility />}
</IconButton>
) : (
<div className="icon-holder">
{error && showIcon && (
<ErrorOutlineIcon
className="text-field-icon"
style={{ fill: "red", width: "16px", height: "16px" }}
/>
)}
{error && !showIcon && (
<ErrorOutlineIcon
className="text-field-icon"
style={{ fill: "red", width: "16px", height: "16px" }}
/>
)}
{!error && showIcon && (
<HelpOutlineIcon
className="text-field-icon"
style={{ width: "16px", height: "16px" }}
/>
)}
</div>
)}
</InputAdornment>
),
}}
helperText={helperText}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
/>
</div>
</div>
);
};
export default PasswordTextField;
@@ -1,73 +0,0 @@
:root {
--env-var-color-1: #101828;
--env-var-color-2: #475467;
--env-var-color-3: #1570ef;
--env-var-color-4: #d0d5dd;
--env-var-color-5: #344054;
--env-var-color-6: #eaecf0;
--env-var-color-7: #7f56d9;
--env-var-color-8: #fff;
--env-var-color-9: #f2f2f2;
--env-var-color-10: #175cd3;
--env-var-radius-1: 4px;
--env-var-radius-2: 8px;
--env-var-width-1: 100vw;
--env-var-width-2: 360px;
--env-var-height-1: 100vh;
--env-var-spacing-1: 12px;
--env-var-spacing-2: 24px;
--env-var-spacing-3: 32px;
--env-var-spacing-4: 40px;
--env-var-font-size-small: 11px;
--env-var-font-size-medium: 13px;
--env-var-font-size-medium-plus: 14px;
--env-var-font-size-large: 16px;
--env-var-font-size-xlarge: 30px;
--env-var-img-width-1: 20px;
--env-var-default-1: 24px;
--env-var-default-2: 40px;
}
.password-text-field {
position: relative;
margin-top: 10px;
}
#outlined-basic {
width: 320px;
height: 14px;
font-size: var(--env-var-font-size-medium);
padding: 8px 12px;
}
.password-text-field-title {
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
font-weight: bold;
}
#outlined-basic-helper-text {
margin-left: 0;
margin-top: 10px;
font-size: var(--env-var-font-size-small);
}
.text-field-icon {
width: 16px;
height: 16px;
}
.icon-holder {
width: 16px;
height: 16px;
padding: 0;
margin: 0;
}
@@ -1,94 +0,0 @@
import "./textField.css";
import React, { useState } from "react";
import { InputAdornment, TextField } from "@mui/material";
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
import { useTheme } from "@mui/material";
/**
* @param {Object} props - The component props.
* @param {function} props.onChange - The function to call when the text field changes.
* @param {string} props.id - The ID of the text field.
* @param {string} props.label - The label text for the text field.
* @param {string} props.value - The value of the text field.
* @param {string} props.variant - The variant of the text field.
* @param {string} props.placeholder - The placeholder text for the text field.
* @param {ReactNode} props.icon - The icon to display in the text field.
* @param {string} props.helperText - The helper text for the text field.
* @param {boolean} props.error - Whether the text field has an error.
* @returns {JSX.Element} The rendered component.
*/
const StringTextField = ({
onChange,
autoComplete,
id,
label,
value = undefined,
variant,
placeholder,
icon,
helperText,
error,
}) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
const [showIcon, setShowIcon] = useState(false);
const handleMouseEnter = () => setShowIcon(true);
const handleMouseLeave = () => setShowIcon(false);
return (
<div style={{ fontFamily: fontFamily }}>
<div className="email-text-field-title">{label}</div>
<div className="email-text-field">
<TextField
onChange={onChange}
error={error}
className="email-text-field-input"
id={id}
variant={variant}
value={value}
placeholder={placeholder}
autoComplete={autoComplete}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<div className="icon-holder">
{error && showIcon && (
<ErrorOutlineIcon
className="text-field-icon"
style={{ fill: "red", width: "16px", height: "16px" }}
/>
)}
{error && !showIcon && (
<ErrorOutlineIcon
className="text-field-icon"
style={{ fill: "red", width: "16px", height: "16px" }}
/>
)}
{!error && showIcon && (
<HelpOutlineIcon
className="text-field-icon"
style={{ width: "16px", height: "16px" }}
/>
)}
</div>
</InputAdornment>
),
}}
helperText={helperText}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
/>
</div>
</div>
);
};
export default StringTextField;
@@ -1,37 +0,0 @@
:root {
--env-var-color-1: #101828;
--env-var-color-2: #475467;
--env-var-color-3: #1570ef;
--env-var-color-4: #d0d5dd;
--env-var-color-5: #344054;
--env-var-color-6: #eaecf0;
--env-var-color-7: #7f56d9;
--env-var-color-8: #fff;
--env-var-color-9: #f2f2f2;
--env-var-color-10: #175cd3;
--env-var-radius-1: 4px;
--env-var-radius-2: 8px;
--env-var-width-1: 100vw;
--env-var-width-2: 360px;
--env-var-height-1: 100vh;
--env-var-spacing-1: 12px;
--env-var-spacing-2: 24px;
--env-var-spacing-3: 32px;
--env-var-spacing-4: 40px;
--env-var-font-size-small: 11px;
--env-var-font-size-medium: 13px;
--env-var-font-size-medium-plus: 14px;
--env-var-font-size-large: 16px;
--env-var-font-size-xlarge: 30px;
--env-var-img-width-1: 20px;
--env-var-default-1: 24px;
--env-var-default-2: 40px;
}
@@ -1,72 +0,0 @@
import React, { useState } from "react";
import "./websiteTextField.css";
import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
import { useTheme } from "@mui/material";
/**
* @component
* @param {Object} props
* @param {boolean} [props.showHelp=true] - Controls the visibility of the help icon (defaults to true)
* @param {boolean} [props.hasCopyButton=false] - Controls the visibility of the copy button (defaults to false)
* @param {string} props.hintText - The hint text displayed below the text field (required)
* @returns {JSX.Element} - Renders the website text field component with optional help and copy features
*/
const WebsiteTextField = ({
showHelp = true,
hasCopyButton = false,
hintText,
}) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
const [copied, setCopied] = useState(false);
const handleCopy = () => {
setCopied(true);
setTimeout(() => setCopied(false), 1000);
};
return (
<div style={{ fontFamily: fontFamily }}>
<div className="website-textfield-title">Website</div>
<div className="website-textfield">
<label className="website-label">http://</label>
<input
type="url"
name="website-url"
id="website-url"
className="website-url"
/>
{showHelp && (
<div
className={
`website-icon-holder ` + !hasCopyButton
? "with-no-copy-button"
: ""
}
>
<HelpOutlineIcon style={{ fill: "var(--icon-color)" }} />
</div>
)}
{hasCopyButton && (
<div className="copy-to-clipboard-button" onClick={handleCopy}>
<ContentCopyIcon
className="copy-icon"
style={{ width: "20px", height: "20px" }}
/>
<span className="">{copied ? " Copied " : " Copy "}</span>
</div>
)}
</div>
<label className="website-textfield-hint">{hintText}</label>
</div>
);
};
export default WebsiteTextField;
@@ -1,111 +0,0 @@
:root {
--env-var-color-1: #101828;
--env-var-color-2: #475467;
--env-var-color-3: #1570ef;
--env-var-color-4: #d0d5dd;
--env-var-color-5: #344054;
--env-var-color-6: #eaecf0;
--env-var-color-7: #7f56d9;
--env-var-color-8: #fff;
--env-var-color-9: #f2f2f2;
--env-var-color-10: #175cd3;
--env-var-radius-1: 4px;
--env-var-radius-2: 8px;
--env-var-width-1: 100vw;
--env-var-width-2: 360px;
--env-var-height-1: 100vh;
--env-var-spacing-1: 12px;
--env-var-spacing-2: 24px;
--env-var-spacing-3: 32px;
--env-var-spacing-4: 40px;
--env-var-font-size-small: 11px;
--env-var-font-size-medium: 13px;
--env-var-font-size-medium-plus: 14px;
--env-var-font-size-large: 16px;
--env-var-font-size-xlarge: 30px;
--env-var-img-width-1: 20px;
--env-var-default-1: 24px;
--env-var-default-2: 40px;
}
.website-textfield-title {
margin: 0 20px;
margin-top: 30px;
font-size: 13px;
color: var(--env-var-color-5);
font-weight: bold;
}
.website-textfield {
display: flex;
align-items: center;
position: relative;
margin: 10px 20px 5px;
}
.website-textfield-hint {
margin: 10px 20px;
font-size: 11px;
}
.website-label {
padding: 6px 20px 6px 10px;
border: solid 1px var(--env-var-color-4);
border-right: none;
border-radius: 4px 0 0 4px;
font-size: 13px;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
color: var(--env-var-color-2);
}
.website-url {
width: 248px;
height: 31.5px;
padding: 0px 15px;
border: solid 1px var(--env-var-color-4);
}
.website-icon-holder {
width: 40px;
height: 33px;
padding: 5px;
border: solid 1px var(--env-var-color-4);
border-left: none;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
}
.copy-to-clipboard-button {
padding: 5.5px 20px 6px 10px;
border: solid 1px var(--env-var-color-4);
border-left: none;
border-radius: 0 8px 8px 0;
font-size: 13px;
text-align: center;
display: flex;
justify-content: space-evenly;
align-items: center;
color: var(--env-var-color-2);
cursor: pointer;
}
.copy-icon {
margin-right: 5px;
}
.with-no-copy-button {
display: none;
}
+3 -5
View File
@@ -139,7 +139,7 @@
}
}
.account .MuiStack-root:has(p.MuiTypography-root.input-error) {
.account .MuiStack-root:has(span.MuiTypography-root.input-error) {
position: relative;
}
.account .text-field-icon {
@@ -150,11 +150,9 @@
height: 18px !important;
opacity: 0.8;
}
.account p.MuiTypography-root.input-error {
color: var(--env-var-color-24);
opacity: 0.8;
.account span.MuiTypography-root.input-error {
position: absolute;
top: calc(100% + 5px);
top: 100%;
}
.account .email-text-field,
.account .password-text-field {
@@ -55,6 +55,13 @@
outline: none;
border: none;
}
.create-monitor-form .MuiStack-root:has(span.MuiTypography-root.input-error) {
position: relative;
}
.create-monitor-form span.MuiTypography-root.input-error {
position: absolute;
top: 100%;
}
.monitors-gaps-medium {
height: var(--env-var-spacing-2);
+10 -12
View File
@@ -1,6 +1,5 @@
import "./index.css";
import ConfigBox from "../../Components/ConfigBox";
import FlexibileTextField from "../../Components/TextFields/Flexibile/FlexibileTextField";
import React, { useState } from "react";
import RadioButton from "../../Components/RadioButton";
import CustomizableCheckBox from "../../Components/Checkbox/CustomizableCheckbox";
@@ -12,6 +11,7 @@ import { createMonitor } from "../../Features/Monitors/monitorsSlice";
import { useNavigate } from "react-router-dom";
import { useTheme } from "@emotion/react";
import WestRoundedIcon from "@mui/icons-material/WestRounded";
import Field from "../../Components/Inputs/Field";
const CreateNewMonitor = () => {
const MS_PER_MINUTE = 60000;
@@ -86,6 +86,7 @@ const CreateNewMonitor = () => {
//obj to submit
let monitor = {
...generalSettings,
url: "https://" + generalSettings.url,
...checks,
};
@@ -162,25 +163,22 @@ const CreateNewMonitor = () => {
}
rightLayout={
<Stack gap={theme.gap.xl}>
<FlexibileTextField
id="monitor-url"
title="URL to monitor"
<Field
type="url"
placeholder="https://google.com"
id="monitor-url"
label="URL to monitor"
placeholder="google.com"
value={generalSettings.url}
onChange={(event) =>
handleChange(event, "url", setGeneralSettings)
}
error={errors["url"]}
/>
<FlexibileTextField
id="monitor-name"
title={
<>
Friendly name <span>(optional)</span>
</>
}
<Field
type="text"
id="monitor-name"
label="Friendly name"
isOptional={true}
placeholder="Google"
value={generalSettings.name}
onChange={(event) =>
+32 -8
View File
@@ -37,11 +37,11 @@ import { useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { getMonitors } from "../../Features/Monitors/monitorsSlice";
import { getMonitorsByUserId } from "../../Features/Monitors/monitorsSlice";
import ImageField from "../../Components/TextFields/Image";
import ImageField from "../../Components/Inputs/Image";
import ProgressUpload from "../../Components/ProgressBars";
import Alert from "../../Components/Alert";
import { createToast } from "../../Utils/toastUtils";
import { ToastContainer } from "react-toastify";
import Field from "../../Components/Inputs/Field";
const cols = [
{
@@ -203,6 +203,9 @@ const Demo = () => {
setIsLoading(false);
}, 4000);
};
//fields
const [visibility, setVisibility] = useState(false);
return (
<div>
<div style={{ padding: "4rem", border: "1px solid black" }}>
@@ -439,7 +442,7 @@ const Demo = () => {
/>
</Stack>
<Divider sx={{ margin: `${theme.spacing(2)}` }} />
<Stack justifyContent="center" alignItems="center">
<Stack direction="row" gap="10px" flexWrap="wrap">
<Box width="500px">
<Alert
variant="info"
@@ -447,20 +450,20 @@ const Demo = () => {
body="Since you logged in via SSO, you cannot reset or modify your password."
/>
</Box>
<Box width="500px" mt="5px">
<Box width="500px">
<Alert
variant="warning"
body="New password must contain at least 8 characters and must have at least one uppercase letter, one number and one symbol."
/>
</Box>
<Box width="500px" mt="5px">
<Box width="500px">
<Alert
variant="error"
title="Error"
body="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
/>
</Box>
<Box width="500px" mt="5px">
<Box width="500px">
<Alert
variant="info"
title="We've just released a new feature"
@@ -468,7 +471,7 @@ const Demo = () => {
isToast={true}
/>
</Box>
<Box width="500px" mt="5px">
<Box width="500px">
<Alert
variant="info"
body="Your password is incorrect."
@@ -491,7 +494,28 @@ const Demo = () => {
</Box>
</Stack>
<Divider sx={{ margin: `${theme.spacing(2)}` }} />
<ToastContainer />
<Stack direction="row" justifyContent="center" gap="20px">
<Field type="text" label="Name" placeholder="Enter a name" />
<Field
type="email"
label="Email"
isRequired={true}
placeholder="name.surname@companyname.com"
error="This is an error message."
/>
<Field
type="password"
label="Password"
isRequired={true}
placeholder="Create a password"
/>
<Field
type="url"
label="Website"
placeholder="google.com"
/>
</Stack>
<Divider sx={{ margin: `${theme.spacing(2)}` }} />
</div>
);
};
+8 -6
View File
@@ -2,13 +2,13 @@ import BackgroundPattern from "../../Components/BackgroundPattern/BackgroundPatt
import "./index.css";
import React from "react";
import Logomark from "../../assets/Images/key-password.png";
import EmailTextField from "../../Components/TextFields/Email/EmailTextField";
import Button from "../../Components/Button";
import LeftArrow from "../../assets/Images/arrow-left.png";
import { useState, useEffect } from "react";
import { recoveryValidation } from "../../Validation/validation";
import axiosInstance from "../../Utils/axiosConfig";
import { useNavigate } from "react-router-dom";
import Field from "../../Components/Inputs/Field";
const ForgotPassword = () => {
const navigate = useNavigate();
@@ -76,12 +76,14 @@ const ForgotPassword = () => {
</div>
<div className="forgot-password-v-gap-large"></div>
<div className="forgot-password-body">
<EmailTextField
onChange={handleInput}
error={errors.email !== undefined ? true : false}
helperText={errors.email !== undefined ? errors.email : ""}
placeholder="Enter your email"
<Field
type="email"
id="forgot-password-email-input"
label="Email"
isRequired={true}
placeholder="Enter your email"
onChange={handleInput}
error={errors.email}
/>
<div className="forgot-password-v-gap-medium"></div>
<Button
+3 -11
View File
@@ -39,17 +39,9 @@
color: var(--env-var-color-1);
}
#login-email-input {
width: 308px;
height: 1px;
font-size: var(--env-var-font-size-medium);
}
#login-password-input {
width: 308px;
height: 1px;
font-size: var(--env-var-font-size-medium);
}
/* .login-form-inputs .field h3.MuiTypography-root{
font-weight: 600;
} */
.login-form-password-options {
display: flex;
+15 -13
View File
@@ -4,16 +4,15 @@ import { useNavigate } from "react-router-dom";
import "./index.css";
import BackgroundPattern from "../../Components/BackgroundPattern/BackgroundPattern";
import Logomark from "../../assets/Images/Logomark.png";
import EmailTextField from "../../Components/TextFields/Email/EmailTextField";
import CheckBox from "../../Components/Checkbox/Checkbox";
import Button from "../../Components/Button";
import Google from "../../assets/Images/Google.png";
import PasswordTextField from "../../Components/TextFields/Password/PasswordTextField";
import axiosInstance from "../../Utils/axiosConfig";
import { loginValidation } from "../../Validation/validation";
import { login } from "../../Features/Auth/authSlice";
import { useDispatch } from "react-redux";
import { createToast } from "../../Utils/toastUtils";
import Field from "../../Components/Inputs/Field";
const Login = () => {
const dispatch = useDispatch();
@@ -125,23 +124,26 @@ const Login = () => {
<div className="login-form-heading">Log in to your account</div>
</div>
<div className="login-form-v3-spacing" />
<div className="login-form-inputs">
<EmailTextField
onChange={handleInput}
error={errors.email ? true : false}
helperText={errors.email ? errors.email : ""}
<Field
type="email"
id="login-email-input"
label="Email"
placeholder="Enter your email"
autoComplete="email"
id="login-email-input"
onChange={handleInput}
error={errors.email}
/>
<div className="login-form-v2-spacing" />
<PasswordTextField
onChange={handleInput}
error={errors.password ? true : false}
helperText={errors.password ? errors.password : ""}
placeholder="Password"
autoComplete="current-password"
<Field
type="password"
id="login-password-input"
label="Password"
placeholder="Enter your password"
autoComplete="current-password"
onChange={handleInput}
error={errors.password}
/>
</div>
<div className="login-form-v3-spacing" />
+1 -1
View File
@@ -6,7 +6,7 @@ import { getMonitorsByUserId } from "../../Features/Monitors/monitorsSlice";
import { useNavigate } from "react-router-dom";
import Button from "../../Components/Button";
import ServerStatus from "../../Components/Charts/Servers/ServerStatus";
import SearchTextField from "../../Components/TextFields/Search/SearchTextField";
import SearchTextField from "../../Components/Inputs/Search/SearchTextField";
import MonitorTable from "../../Components/MonitorTable";
import { useTheme } from "@emotion/react";
+59 -41
View File
@@ -1,12 +1,8 @@
import React from "react";
import EmailTextField from "../../Components/TextFields/Email/EmailTextField";
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
import WebsiteTextField from "../../Components/TextFields/Website/WebsiteTextField";
import DescriptionTextField from "../../Components/TextFields/Description/DescriptionTextField";
import PlayGroundCharts from "./PlayGround-Charts";
import PlayGroundPopupModals from "./PlayGround-Popup-Modals";
import PlayGroundTooltips from "./PlayGround-Tooltips";
import Field from "../../Components/Inputs/Field";
// This Component is just for the development and test
// purposes and just to see what my components look like while development
@@ -15,49 +11,71 @@ function PlayGround() {
return (
<div>
{/* Default state of Email Text Fields */}
<EmailTextField
error={false}
placeholder="olivia@untitledui.com"
id="outlined-basic"
helperText="This is a hint text to help user."
/>
{/* Email Text Field when validation error occures */}
<EmailTextField
error={true}
placeholder="olivia@untitledui.com"
id="outlined-basic"
icon={<ErrorOutlineIcon style={{ fill: "red" }} />}
helperText="This is an error message"
/>
{/* Email Text Field while mouse hover */}
<EmailTextField
error={false}
placeholder="olivia@untitledui.com"
id="outlined-basic"
icon={<HelpOutlineIcon />}
helperText="This is a hint text to help user."
/>
<div
style={{
display: "flex",
flexDirection: "column",
gap: "10px",
maxWidth: "400px",
padding: "10px",
}}
>
<Field
type="email"
id="outlined-basic"
label="Email"
placeholder="olivia@untitledui.com"
/>
{/* Email Text Field when validation error occures */}
<Field
type="email"
id="outlined-basic"
label="Email"
placeholder="olivia@untitledui.com"
error="This is an error message"
/>
</div>
<hr />
{/* Now, illustration of the Website text fields */}
<WebsiteTextField hintText="This is a hint text to help user." />
<WebsiteTextField
hasCopyButton={true}
hintText="This is a hint text to help user."
/>
{/* Now, illustration of the Website text fields */}
<div
style={{
display: "flex",
flexDirection: "column",
gap: "10px",
maxWidth: "400px",
padding: "10px",
}}
>
<Field type="url" label="Website" />
<Field type="url" label="Website" hasCopy={true} />
</div>
<hr />
{/* Now, illustration of the Description text fields */}
<DescriptionTextField
hasError={false}
hintText="This is a hint text to help user."
/>
<DescriptionTextField
hasError={true}
hintText="This is a hint text to help user."
/>
<div
style={{
display: "flex",
flexDirection: "column",
gap: "10px",
maxWidth: "400px",
padding: "10px",
}}
>
<Field
type="description"
label="Description"
placeholder="Enter a description... "
/>
<Field
type="description"
label="Description"
placeholder="Enter a description... "
error="This is an error message"
/>
</div>
<hr />
<PlayGroundCharts />
<hr />
-11
View File
@@ -1,5 +1,4 @@
.register-page {
width: var(--env-var-width-1);
display: flex;
justify-content: center;
min-height: var(--env-var-height-1);
@@ -40,16 +39,6 @@
font-weight: 600;
}
#register-firstname-input,
#register-lastname-input,
#register-email-input,
#register-password-input {
font-size: var(--env-var-font-size-medium);
width: 294px;
height: 11px;
padding: 12px 14px;
}
.register-bottom-spacing {
height: 50px;
}
+43 -28
View File
@@ -4,9 +4,6 @@ import { useNavigate } from "react-router-dom";
import "./index.css";
import BackgroundPattern from "../../Components/BackgroundPattern/BackgroundPattern";
import Logomark from "../../assets/Images/Logomark.png";
import EmailTextField from "../../Components/TextFields/Email/EmailTextField";
import PasswordTextField from "../../Components/TextFields/Password/PasswordTextField";
import StringTextField from "../../Components/TextFields/Text/TextField";
import Check from "../../Components/Check/Check";
import Button from "../../Components/Button";
import Google from "../../assets/Images/Google.png";
@@ -15,6 +12,7 @@ import axiosInstance from "../../Utils/axiosConfig";
import { useDispatch } from "react-redux";
import { register } from "../../Features/Auth/authSlice";
import { createToast } from "../../Utils/toastUtils";
import Field from "../../Components/Inputs/Field";
const Register = () => {
const dispatch = useDispatch();
@@ -119,6 +117,7 @@ const Register = () => {
}
};
return (
<div className="register-page">
<BackgroundPattern></BackgroundPattern>
@@ -137,42 +136,58 @@ const Register = () => {
</div>
<div className="register-form-v-spacing-40px" />
<div className="register-form-inputs">
<StringTextField
onChange={handleInput}
error={errors.firstname ? true : false}
helperText={errors.firstname ? errors.firstname : ""}
label="First name*"
placeholder="Enter your first name"
<Field
id="register-firstname-input"
label="Name"
isRequired={true}
placeholder="Talha"
autoComplete="given-name"
onChange={handleInput}
error={errors.firstname}
/>
<div className="login-form-v2-spacing" />
<StringTextField
onChange={handleInput}
error={errors.lastname ? true : false}
helperText={errors.lastname ? errors.lastname : ""}
label="Last name*"
placeholder="Enter your last name"
<Field
id="register-lastname-input"
label="Surname"
isRequired={true}
placeholder="Bolat"
autoComplete="family-name"
onChange={handleInput}
error={errors.lastname}
/>
<div className="login-form-v2-spacing" />
<EmailTextField
onChange={handleInput}
label="Email*"
error={errors.email ? true : false}
helperText={errors.email ? errors.email : ""}
placeholder="Enter your email"
autoComplete="email"
<Field
type="email"
id="register-email-input"
label="Email"
isRequired={true}
placeholder="name.surname@companyname.com"
autoComplete="email"
onChange={handleInput}
error={errors.email}
/>
<div className="login-form-v2-spacing" />
<PasswordTextField
onChange={handleInput}
label="Password*"
error={errors.password ? true : false}
helperText={errors.password ? errors.password : ""}
<Field
type="password"
id="register-password-input"
label="Password"
isRequired={true}
placeholder="Create a password"
autoComplete="current-password"
id="register-password-input"
error={errors.password}
onChange={handleInput}
/>
<div className="login-form-v2-spacing" />
{/* TODO - hook up to form state and run checks */}
<Field
type="password"
id="register-confirm-input"
label="Confirm password"
isRequired={true}
placeholder="Confirm your password"
autoComplete="current-password"
error={errors.confirm}
onChange={handleInput}
/>
</div>
<div className="login-form-v2-spacing" />
+15 -13
View File
@@ -1,7 +1,6 @@
import BackgroundPattern from "../../Components/BackgroundPattern/BackgroundPattern";
import "./index.css";
import LockIcon from "../../assets/Images/lock-icon.png";
import PasswordTextField from "../../Components/TextFields/Password/PasswordTextField";
import Check from "../../Components/Check/Check";
import Button from "../../Components/Button";
import LeftArrow from "../../assets/Images/arrow-left.png";
@@ -10,6 +9,7 @@ import { useState, useEffect } from "react";
import { newPasswordValidation } from "../../Validation/validation";
import axiosInstance from "../../Utils/axiosConfig";
import { useNavigate } from "react-router-dom";
import Field from "../../Components/Inputs/Field";
const SetNewPassword = () => {
const navigate = useNavigate();
@@ -83,22 +83,24 @@ const SetNewPassword = () => {
</div>
<div className="set-new-password-form-gap-large"></div>
<div className="set-new-password-form-content">
<PasswordTextField
label="Password"
onChange={handleInput}
error={errors.password !== undefined ? true : false}
helperText={errors.password !== undefined ? errors.password : ""}
placeholder="••••••••"
<Field
type="password"
id="register-password-input"
label="Password"
isRequired={true}
placeholder="••••••••"
onChange={handleInput}
error={errors.password}
/>
<div className="set-new-password-form-gap-medium"></div>
<PasswordTextField
label="Confirm password"
onChange={handleInput}
error={errors.confirm !== undefined ? true : false}
helperText={errors.confirm !== undefined ? errors.confirm : ""}
placeholder="••••••••"
<Field
type="password"
id="confirm-password-input"
label="Confirm password"
isRequired={true}
placeholder="••••••••"
onChange={handleInput}
error={errors.confirm}
/>
<div className="set-new-password-form-gap-medium"></div>
<div className="set-new-password-form-checks">
+3 -2
View File
@@ -91,6 +91,7 @@ const theme = createTheme({
pY: "40px",
},
gap: {
xs: "4px",
small: "8px",
medium: "12px",
ml: "16px",
@@ -101,7 +102,7 @@ const theme = createTheme({
info: {
color: secondaryMain,
bg: otherColorsWhite,
border: "#d0d5dd",
border: sectionBorder,
},
error: {
color: "#d92d20",
@@ -111,7 +112,7 @@ const theme = createTheme({
warning: {
color: "#DC6803",
bg: "#fffcf5",
border: "#fec84b"
border: "#fec84b",
},
},
});
+1
View File
@@ -59,6 +59,7 @@
--env-var-spacing-1: 12px;
--env-var-spacing-1-plus: 16px;
--env-var-spacing-1-minus: 10px;
--env-var-spacing-2: 24px;
--env-var-spacing-3: 32px;
--env-var-spacing-4: 40px;