Skip to content

Instantly share code, notes, and snippets.

@gcmatheusj
Created March 4, 2020 14:43
Show Gist options
  • Select an option

  • Save gcmatheusj/c46a3e13de6d51db028f3e938fb53ded to your computer and use it in GitHub Desktop.

Select an option

Save gcmatheusj/c46a3e13de6d51db028f3e938fb53ded to your computer and use it in GitHub Desktop.
import * as React from 'react';
import MUIOutlinedInput from '@material-ui/core/OutlinedInput';
import FormControl from '@material-ui/core/FormControl';
import styled, { css } from 'styled-components';
import { connect, FormikContext, getIn } from 'formik';
import FormHelperText from '@material-ui/core/FormHelperText';
import MaskedInput from 'react-text-mask';
import InputAdornment from '@material-ui/core/InputAdornment';
import Visibility from '@material-ui/icons/Visibility';
import VisibilityOff from '@material-ui/icons/VisibilityOff';
import IconButton from '@material-ui/core/IconButton';
import CurrencyInput from 'react-currency-input';
import { isValuesFromFormikEquals } from './utils';
import { getMask, MASK_TYPES } from '../../utils/masks';
import Label from './Label';
import { TextFieldProps } from '@material-ui/core/TextField';
const OutlinedInput = styled(MUIOutlinedInput)`
width: 100%;
${(props) =>
props.prefix !== undefined &&
css`
.MuiOutlinedInput-root fieldset {
margin-left: 10px;
}
.MuiInputBase-input {
margin-left: 0;
}
align-self: flex-end;
width: calc(100% - 30px);
`}
`;
const InputWrapper = styled(FormControl)`
display: flex;
flex-direction: column;
margin: 3px 0 !important;
.MuiOutlinedInput-notchedOutline {
border-radius: 4px;
}
.MuiCard-root {
box-shadow: 0 4px 4px rgba(0, 0, 0, 0.25);
border-radius: 10px;
}
color: #00467e;
font-size: 14px;
p.MuiFormHelperText-root {
margin-top: 3px !important;
}
input {
font-size: 14px;
}
`;
const PrefixContainer = styled.div`
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
`;
interface FormikPartProps {
formik: FormikContext<{}>;
}
interface Props {
label: string;
name: string;
mask?: string;
type?: string;
required?: boolean;
prefix?: string;
min?: number | string;
max?: number | string;
disabled?: boolean;
placeholder?: string;
handleBlur?: () => void;
}
const Mask = ({ inputRef, mask, ...props }) => (
<MaskedInput
{...props}
ref={(ref) => {
inputRef(ref ? ref.inputElement : null);
}}
mask={getMask(mask)}
/>
);
const MemoizedMask = React.memo(Mask);
const CurrencyMask = ({ inputRef, ...props }) => {
const ref = React.useRef(null);
React.useEffect(() => {
inputRef(ref.current.theInput);
}, [inputRef]);
return <CurrencyInput {...props} ref={ref} type="tel" />;
};
const getCustomProps = ({
mask,
type,
name,
setFieldValue,
showPassword,
setShowPassword,
}) => {
if (mask === MASK_TYPES.MONEY) {
return {
onChange: (_, maskedValue) => setFieldValue(name, maskedValue),
inputComponent: CurrencyMask as React.FunctionComponent,
inputProps: {
prefix: 'R$ ',
decimalSeparator: ',',
thousandSeparator: '.',
allowEmpty: true,
},
};
}
if (type === 'password') {
const passwordProps = {
type: showPassword ? 'text' : 'password',
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={() => setShowPassword(!showPassword)}>
{showPassword ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
),
};
if (showPassword) {
return {
...passwordProps,
type: 'text',
};
}
return passwordProps;
}
if (mask) {
return {
inputComponent: MemoizedMask,
};
}
return {};
};
const TextInput: React.FunctionComponent<Props &
FormikPartProps &
TextFieldProps> = ({
label,
name,
type,
mask,
required,
formik,
...props
}) => {
const [showPassword, setShowPassword] = React.useState(false);
const [hasFocused, setHasFocused] = React.useState(false);
const {
values,
errors,
handleChange,
handleBlur,
touched,
setFieldValue,
} = formik;
const value = getIn(values, name);
const error = getIn(errors, name);
const hasTouched = getIn(touched, name) || hasFocused;
const onChange = (e) => {
if (type !== 'number') return handleChange(e);
if (props.min !== undefined) {
if (Number.parseInt(e.target.value) <= props.min) return setFieldValue(name, props.min)
}
return handleChange(e);
};
const onBlur = (e) => {
handleBlur(e);
if (props.handleBlur) props.handleBlur();
};
return (
<InputWrapper disabled={props.disabled}>
<Label htmlFor={name}> {`${label} ${required ? '*' : ''}`} </Label>
<PrefixContainer>
{props.prefix}
<OutlinedInput
id={name}
margin="dense"
name={name}
labelWidth={0}
onChange={onChange}
onBlur={onBlur}
onFocus={() => setHasFocused(true)}
value={value}
error={hasTouched && !!error}
type={type}
prefix={props.prefix}
inputProps={{
mask,
...props,
}}
{...getCustomProps({
mask,
type,
name,
showPassword,
setShowPassword,
...formik,
...props,
})}
/>
</PrefixContainer>
<FormHelperText error={hasTouched && !!error}>
{hasTouched && error}
</FormHelperText>
</InputWrapper>
);
};
export default connect<Props, {}>(
React.memo(TextInput, isValuesFromFormikEquals),
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment