228 lines
7.1 KiB
TypeScript
228 lines
7.1 KiB
TypeScript
import React, { useState } from 'react';
|
|
import {
|
|
TextField,
|
|
Box,
|
|
IconButton,
|
|
Switch,
|
|
FormGroup,
|
|
Typography,
|
|
InputAdornment,
|
|
Grid,
|
|
} from '@mui/material';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { TickCircle, Eye, EyeSlash, CloseCircle } from 'iconsax-react';
|
|
import { PasswordValidationItem } from './PasswordValidation';
|
|
import { Icon } from '@harmony/kit';
|
|
import { type PasswordSectionProps } from '../../types/settingForm';
|
|
|
|
export function PasswordSection({
|
|
showPasswordSection,
|
|
setShowPasswordSection,
|
|
password,
|
|
setPassword,
|
|
confirmPassword,
|
|
setConfirmPassword,
|
|
matchPassword,
|
|
hasNumber,
|
|
hasMinLength,
|
|
hasUpperAndLower,
|
|
hasSpecialChar,
|
|
validPassword,
|
|
errors,
|
|
touched,
|
|
handleBlur,
|
|
}: PasswordSectionProps) {
|
|
const { t } = useTranslation('completionForm');
|
|
const [showPasswordText, setShowPasswordText] = useState(false);
|
|
const [showPasswordRepetitionText, setShowPasswordRepetitionText] =
|
|
useState(false);
|
|
const [showValidations, setShowValidation] = useState(false);
|
|
|
|
const handleTogglePasswordSection = (
|
|
e: React.ChangeEvent<HTMLInputElement>,
|
|
) => {
|
|
setShowPasswordSection(e.target.checked);
|
|
};
|
|
|
|
const handleTogglePasswordEye = () => setShowPasswordText((prev) => !prev);
|
|
const handleTogglePasswordRepetitionEye = () =>
|
|
setShowPasswordRepetitionText((prev) => !prev);
|
|
|
|
const handleBlurPassword = () => {
|
|
handleBlur('password');
|
|
setShowValidation(false);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<FormGroup>
|
|
<Box
|
|
sx={{
|
|
display: 'flex',
|
|
gap: 0.5,
|
|
alignItems: 'center',
|
|
}}
|
|
>
|
|
<Switch
|
|
checked={showPasswordSection}
|
|
onChange={handleTogglePasswordSection}
|
|
/>
|
|
<Typography
|
|
sx={{
|
|
color: showPasswordSection ? 'primary.main' : 'text.primary',
|
|
}}
|
|
>
|
|
{t('completion.determinePassword')}
|
|
</Typography>
|
|
</Box>
|
|
</FormGroup>
|
|
|
|
{showPasswordSection && (
|
|
<Grid container spacing={2}>
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<TextField
|
|
fullWidth
|
|
label={t('completion.password')}
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
variant="outlined"
|
|
type={showPasswordText ? 'text' : 'password'}
|
|
autoFocus
|
|
onBlur={handleBlurPassword}
|
|
onFocus={() => setShowValidation(true)}
|
|
error={touched.password && !!errors.password}
|
|
helperText={touched.password && errors.password}
|
|
sx={{
|
|
flex: '1 1 260px',
|
|
'& .MuiInputBase-input': {
|
|
pr: 8, // Increased padding to accommodate both icons
|
|
},
|
|
}}
|
|
slotProps={{
|
|
input: {
|
|
endAdornment: (
|
|
<InputAdornment position="end">
|
|
<IconButton
|
|
onClick={handleTogglePasswordEye}
|
|
sx={{ p: 0.5 }}
|
|
>
|
|
{showPasswordText ? (
|
|
<Icon
|
|
Component={Eye}
|
|
color="primary.main"
|
|
size="medium"
|
|
/>
|
|
) : (
|
|
<Icon
|
|
Component={EyeSlash}
|
|
size="medium"
|
|
color="primary.main"
|
|
/>
|
|
)}
|
|
</IconButton>
|
|
</InputAdornment>
|
|
),
|
|
startAdornment: validPassword && (
|
|
<InputAdornment position="start">
|
|
<Icon
|
|
Component={TickCircle}
|
|
size="medium"
|
|
color="success.main"
|
|
variant="Bold"
|
|
/>
|
|
</InputAdornment>
|
|
),
|
|
},
|
|
}}
|
|
/>
|
|
</Grid>
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<TextField
|
|
fullWidth
|
|
label={t('completion.passwordRepetition')}
|
|
variant="outlined"
|
|
value={confirmPassword}
|
|
onChange={(e) => setConfirmPassword(e.target.value)}
|
|
onBlur={() => handleBlur('confirmPassword')}
|
|
error={touched.confirmPassword && !!errors.confirmPassword}
|
|
helperText={touched.confirmPassword && errors.confirmPassword}
|
|
type={showPasswordRepetitionText ? 'text' : 'password'}
|
|
sx={{
|
|
flex: '1 1',
|
|
}}
|
|
slotProps={{
|
|
input: {
|
|
endAdornment: (
|
|
<InputAdornment position="end">
|
|
<IconButton
|
|
onClick={handleTogglePasswordRepetitionEye}
|
|
sx={{ p: 0.5 }}
|
|
>
|
|
{showPasswordRepetitionText ? (
|
|
<Icon
|
|
Component={Eye}
|
|
color="primary.main"
|
|
size="medium"
|
|
/>
|
|
) : (
|
|
<Icon
|
|
Component={EyeSlash}
|
|
size="medium"
|
|
color="primary.main"
|
|
/>
|
|
)}
|
|
</IconButton>
|
|
</InputAdornment>
|
|
),
|
|
startAdornment: confirmPassword.length > 0 && (
|
|
<InputAdornment position="start">
|
|
<Icon
|
|
Component={matchPassword ? TickCircle : CloseCircle}
|
|
size="medium"
|
|
color={matchPassword ? 'success.main' : 'error.main'}
|
|
variant="Bold"
|
|
/>
|
|
</InputAdornment>
|
|
),
|
|
},
|
|
}}
|
|
/>
|
|
</Grid>
|
|
|
|
{showValidations && (
|
|
<>
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<PasswordValidationItem
|
|
isValid={hasNumber}
|
|
label={t('completion.hasNumber')}
|
|
/>
|
|
</Grid>
|
|
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<PasswordValidationItem
|
|
isValid={hasMinLength}
|
|
label={t('completion.hasMinLength')}
|
|
/>
|
|
</Grid>
|
|
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<PasswordValidationItem
|
|
isValid={hasUpperAndLower}
|
|
label={t('completion.hasUpperAndLower')}
|
|
/>
|
|
</Grid>
|
|
|
|
<Grid size={{ xs: 12, md: 6 }}>
|
|
<PasswordValidationItem
|
|
isValid={hasSpecialChar}
|
|
label={t('completion.hasSpecialChar')}
|
|
/>
|
|
</Grid>
|
|
</>
|
|
)}
|
|
</Grid>
|
|
)}
|
|
</>
|
|
);
|
|
}
|