129 lines
3.5 KiB
TypeScript
129 lines
3.5 KiB
TypeScript
|
import { forwardRef, useState } from 'react'
|
||
|
import Link from 'next/link'
|
||
|
import { ErrorMessage } from '../Authentication/ErrorMessage'
|
||
|
import useTranslation from 'next-translate/useTranslation'
|
||
|
|
||
|
interface InputProps extends React.ComponentPropsWithRef<'input'> {
|
||
|
label: string
|
||
|
errors?: string[]
|
||
|
showForgotPassword?: boolean
|
||
|
}
|
||
|
|
||
|
export const Input = forwardRef<HTMLInputElement, InputProps>((props, ref) => {
|
||
|
const {
|
||
|
label,
|
||
|
name,
|
||
|
type = 'text',
|
||
|
errors = [],
|
||
|
showForgotPassword = false,
|
||
|
...rest
|
||
|
} = props
|
||
|
const { t } = useTranslation()
|
||
|
const [inputType, setInputType] = useState(type)
|
||
|
|
||
|
const handlePassword = (): void => {
|
||
|
const oppositeType = inputType === 'password' ? 'text' : 'password'
|
||
|
setInputType(oppositeType)
|
||
|
}
|
||
|
|
||
|
return (
|
||
|
<>
|
||
|
<div className='container'>
|
||
|
<div className='input-with-label'>
|
||
|
<div className='label-container'>
|
||
|
<label className='label' htmlFor={name}>
|
||
|
{label}
|
||
|
</label>
|
||
|
{type === 'password' && showForgotPassword ? (
|
||
|
<Link href='/authentication/forgot-password'>
|
||
|
<a className='label-forgot-password'>
|
||
|
{t('authentication:forgot-password')}
|
||
|
</a>
|
||
|
</Link>
|
||
|
) : null}
|
||
|
</div>
|
||
|
<div className='input-container'>
|
||
|
<input
|
||
|
data-testid='input'
|
||
|
className='input'
|
||
|
{...rest}
|
||
|
ref={ref}
|
||
|
id={name}
|
||
|
name={name}
|
||
|
type={inputType}
|
||
|
/>
|
||
|
{type === 'password' && (
|
||
|
<div
|
||
|
data-testid='password-eye'
|
||
|
onClick={handlePassword}
|
||
|
className='password-eye'
|
||
|
/>
|
||
|
)}
|
||
|
<ErrorMessage errors={errors} />
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<style jsx>
|
||
|
{`
|
||
|
.container {
|
||
|
margin-bottom: 20px;
|
||
|
}
|
||
|
.input-container {
|
||
|
margin-top: 0;
|
||
|
position: relative;
|
||
|
}
|
||
|
.input-with-label {
|
||
|
display: flex;
|
||
|
flex-direction: column;
|
||
|
}
|
||
|
.label-container {
|
||
|
display: flex;
|
||
|
justify-content: space-between;
|
||
|
margin: 5px 0;
|
||
|
}
|
||
|
.label-forgot-password {
|
||
|
font-size: 12px;
|
||
|
}
|
||
|
.label {
|
||
|
color: var(--color-secondary);
|
||
|
font-size: 16px;
|
||
|
font-family: 'Poppins', 'Arial', 'sans-serif';
|
||
|
padding-left: 3px;
|
||
|
}
|
||
|
.input {
|
||
|
background-color: #f1f1f1;
|
||
|
font-family: 'Roboto', 'Arial', 'sans-serif';
|
||
|
width: 100%;
|
||
|
height: 44px;
|
||
|
line-height: 44px;
|
||
|
padding: 0 20px;
|
||
|
color: #2a2a2a;
|
||
|
border: 0;
|
||
|
box-shadow: ${errors.length >= 1
|
||
|
? '0 0 0 2px var(--color-error)'
|
||
|
: 'none'};
|
||
|
border-radius: 10px;
|
||
|
}
|
||
|
.input:focus {
|
||
|
outline: 0;
|
||
|
border-color: var(--color-primary);
|
||
|
box-shadow: 0 0 0 2px var(--color-primary);
|
||
|
}
|
||
|
.password-eye {
|
||
|
position: absolute;
|
||
|
top: 12px;
|
||
|
right: 16px;
|
||
|
z-index: 1;
|
||
|
width: 20px;
|
||
|
height: 20px;
|
||
|
background-image: url(/images/svg/icons/input/${inputType}.svg);
|
||
|
background-size: cover;
|
||
|
cursor: pointer;
|
||
|
}
|
||
|
`}
|
||
|
</style>
|
||
|
</>
|
||
|
)
|
||
|
})
|