feat: add user completion form
This commit is contained in:
353
src/features/authentication/components/UserCompletionForm.tsx
Normal file
353
src/features/authentication/components/UserCompletionForm.tsx
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
import {
|
||||||
|
TextField,
|
||||||
|
FormControl,
|
||||||
|
InputLabel,
|
||||||
|
MenuItem,
|
||||||
|
Select,
|
||||||
|
Box,
|
||||||
|
type SelectChangeEvent,
|
||||||
|
Switch,
|
||||||
|
FormGroup,
|
||||||
|
Button,
|
||||||
|
Typography,
|
||||||
|
Link,
|
||||||
|
} from '@mui/material';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
export function UserCompletionForm() {
|
||||||
|
const [sex, setSex] = useState('');
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
const [showEmail, setShowEmail] = useState(false);
|
||||||
|
const [password, setPassword] = useState('');
|
||||||
|
const [email, setEmail] = useState('');
|
||||||
|
const [confirmPassword, setConfirmPassword] = useState('');
|
||||||
|
const [codeSent, setCodeSent] = useState(false);
|
||||||
|
const [verificationCode, setVerificationCode] = useState('');
|
||||||
|
const [buttonState, setButtonState] = useState('default'); // default | counting | sent
|
||||||
|
const [countdown, setCountdown] = useState(60);
|
||||||
|
const matchPassword = password === confirmPassword;
|
||||||
|
const hasNumber = /\d/.test(password);
|
||||||
|
const hasMinLength = password.length >= 8;
|
||||||
|
const hasUpperAndLower = /[A-Z]/.test(password) && /[a-z]/.test(password);
|
||||||
|
const hasSpecialChar = /[!@#$%^&*]/.test(password);
|
||||||
|
const correctEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
||||||
|
|
||||||
|
const handleTogglePassword = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setShowPassword(e.target.checked);
|
||||||
|
};
|
||||||
|
const handleToggleEmail = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setShowEmail(e.target.checked);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (e: SelectChangeEvent) => {
|
||||||
|
setSex(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClickCodeSent = () => {
|
||||||
|
setCodeSent(true);
|
||||||
|
setButtonState('sent');
|
||||||
|
setTimeout(() => {
|
||||||
|
setButtonState('counting');
|
||||||
|
setCountdown(60);
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let timer: ReturnType<typeof setInterval>;
|
||||||
|
if (buttonState === 'counting' && countdown > 0) {
|
||||||
|
timer = setInterval(() => {
|
||||||
|
setCountdown((prev) => prev - 1);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
if (countdown === 0) {
|
||||||
|
setButtonState('default');
|
||||||
|
}
|
||||||
|
return () => clearInterval(timer);
|
||||||
|
}, [buttonState, countdown]);
|
||||||
|
|
||||||
|
const toPersianDigits = (str: string) =>
|
||||||
|
str.replace(/\d/g, (d: string) => '۰۱۲۳۴۵۶۷۸۹'[parseInt(d)]);
|
||||||
|
|
||||||
|
const getButtonLabel = () => {
|
||||||
|
if (buttonState === 'sent') return 'ارسال شد!';
|
||||||
|
if (buttonState === 'counting') {
|
||||||
|
const minutes = String(Math.floor(countdown / 60)).padStart(2, '0');
|
||||||
|
const seconds = String(countdown % 60).padStart(2, '0');
|
||||||
|
const time = `${minutes}:${seconds}`;
|
||||||
|
return toPersianDigits(time);
|
||||||
|
}
|
||||||
|
return 'ارسال کد تایید';
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
dir="rtl"
|
||||||
|
style={{
|
||||||
|
backgroundColor: '#F5F5F5',
|
||||||
|
minHeight: '100vh',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: '500px',
|
||||||
|
backgroundColor: 'white',
|
||||||
|
border: '1px solid #ccc',
|
||||||
|
borderRadius: 2,
|
||||||
|
padding: 5,
|
||||||
|
margin: '40px auto',
|
||||||
|
boxShadow: 2,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ flexDirection: 'column', mb: 2 }}>
|
||||||
|
<Typography variant="h5" sx={{ mb: 0.5 }}>
|
||||||
|
تکمیل اطلاعات حساب کاربری
|
||||||
|
</Typography>
|
||||||
|
<Typography sx={{ color: 'gray', fontSize: '14px' }}>
|
||||||
|
اطلاعات کسب و کار خود را وارد کنید
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
gap: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TextField
|
||||||
|
label="نام"
|
||||||
|
placeholder="نام"
|
||||||
|
variant="outlined"
|
||||||
|
sx={{
|
||||||
|
width: '330px',
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
height: 45,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
label="نام خانوادگی"
|
||||||
|
placeholder="نام خانوادگی"
|
||||||
|
variant="outlined"
|
||||||
|
sx={{
|
||||||
|
width: '330px',
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
height: 45,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||||
|
<FormControl sx={{ width: '330px' }}>
|
||||||
|
<InputLabel id="sex-label">جنسیت</InputLabel>
|
||||||
|
<Select
|
||||||
|
labelId="sex-label"
|
||||||
|
id="sex"
|
||||||
|
value={sex}
|
||||||
|
label="جنسیت"
|
||||||
|
onChange={handleChange}
|
||||||
|
sx={{
|
||||||
|
height: '45px',
|
||||||
|
'& .MuiSelect-select': {
|
||||||
|
paddingY: '10px',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MenuItem value="female">زن</MenuItem>
|
||||||
|
<MenuItem value="male">مرد</MenuItem>
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
label="کدملی(اختیاری)"
|
||||||
|
placeholder="کدملی(اختیاری)"
|
||||||
|
variant="outlined"
|
||||||
|
sx={{
|
||||||
|
width: '330px',
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
height: 45,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<FormGroup>
|
||||||
|
<Box sx={{ display: 'flex', gap: 0.5, alignItems: 'center' }}>
|
||||||
|
<Switch
|
||||||
|
checked={showPassword}
|
||||||
|
onChange={handleTogglePassword}
|
||||||
|
sx={{
|
||||||
|
transform: 'scaleX(-1)',
|
||||||
|
'& .MuiSwitch-thumb': {
|
||||||
|
transform: 'scaleX(-1)',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography> تعیین رمز عبور</Typography>
|
||||||
|
</Box>
|
||||||
|
</FormGroup>
|
||||||
|
{showPassword && (
|
||||||
|
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||||
|
<Box
|
||||||
|
sx={{ display: 'flex', flexDirection: 'column', width: '330px' }}
|
||||||
|
>
|
||||||
|
<TextField
|
||||||
|
label="رمز عبور"
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
variant="outlined"
|
||||||
|
sx={{
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
height: 45,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{password && (
|
||||||
|
<Box sx={{ mt: 1 }}>
|
||||||
|
<Typography
|
||||||
|
variant="caption"
|
||||||
|
sx={{ color: hasNumber ? 'green' : 'red' }}
|
||||||
|
>
|
||||||
|
شامل عدد
|
||||||
|
</Typography>
|
||||||
|
<br />
|
||||||
|
<Typography
|
||||||
|
variant="caption"
|
||||||
|
sx={{ color: hasMinLength ? 'green' : 'red' }}
|
||||||
|
>
|
||||||
|
حداقل 8 کاراکتر
|
||||||
|
</Typography>
|
||||||
|
<br />
|
||||||
|
<Typography
|
||||||
|
variant="caption"
|
||||||
|
sx={{ color: hasUpperAndLower ? 'green' : 'red' }}
|
||||||
|
>
|
||||||
|
شامل یک حرف بزرگ و کوچک
|
||||||
|
</Typography>
|
||||||
|
<br />
|
||||||
|
<Typography
|
||||||
|
variant="caption"
|
||||||
|
sx={{ color: hasSpecialChar ? 'green' : 'red' }}
|
||||||
|
>
|
||||||
|
شامل علامت(!@#$%^&*)
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
{showPassword && (
|
||||||
|
<TextField
|
||||||
|
label="تکرار رمز عبور"
|
||||||
|
variant="outlined"
|
||||||
|
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||||
|
error={confirmPassword.length > 0 && !matchPassword}
|
||||||
|
helperText={
|
||||||
|
confirmPassword.length > 0 && !matchPassword
|
||||||
|
? 'مطابقت ندارد'
|
||||||
|
: ' '
|
||||||
|
}
|
||||||
|
sx={{
|
||||||
|
width: '330px',
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
height: 45,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<FormGroup>
|
||||||
|
<Box sx={{ display: 'flex', gap: 0.5, alignItems: 'center' }}>
|
||||||
|
<Switch
|
||||||
|
checked={showEmail}
|
||||||
|
onChange={handleToggleEmail}
|
||||||
|
sx={{
|
||||||
|
transform: 'scaleX(-1)',
|
||||||
|
'& .MuiSwitch-thumb': {
|
||||||
|
transform: 'scaleX(-1)',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography> اتصال ایمیل خود</Typography>
|
||||||
|
</Box>
|
||||||
|
</FormGroup>
|
||||||
|
{showEmail && (
|
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||||||
|
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
|
||||||
|
<TextField
|
||||||
|
label="ایمیل"
|
||||||
|
variant="outlined"
|
||||||
|
value={email}
|
||||||
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
|
sx={{
|
||||||
|
width: '330px',
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
height: 45,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{email && (
|
||||||
|
<Typography sx={{ color: correctEmail ? 'green' : 'red' }}>
|
||||||
|
فرم درست ایمیل وارد کنید
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
<Button
|
||||||
|
variant="text"
|
||||||
|
onClick={onClickCodeSent}
|
||||||
|
sx={{ width: '200px' }}
|
||||||
|
disabled={buttonState === 'sent' || buttonState === 'counting'}
|
||||||
|
>
|
||||||
|
{getButtonLabel()}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
{codeSent && (
|
||||||
|
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||||
|
<TextField
|
||||||
|
label="کد تایید"
|
||||||
|
variant="outlined"
|
||||||
|
value={verificationCode}
|
||||||
|
onChange={(e) => setVerificationCode(e.target.value)}
|
||||||
|
sx={{
|
||||||
|
width: '330px',
|
||||||
|
'& .MuiOutlinedInput-root': {
|
||||||
|
height: 45,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
width: '150px',
|
||||||
|
backgroundColor: 'white',
|
||||||
|
border: 0.5,
|
||||||
|
borderColor: '#1976d2',
|
||||||
|
color: '#1976d2',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
بررسی کد
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||||
|
<Typography variant="body2" sx={{ flex: 1 }}>
|
||||||
|
ادامه فرایند ثبت نام به منزله تایید و قبول{' '}
|
||||||
|
<Link href="" target="_blank" rel="">
|
||||||
|
قوانین و مقررات هارمونی
|
||||||
|
</Link>{' '}
|
||||||
|
می باشد.
|
||||||
|
</Typography>
|
||||||
|
<Button variant="contained" sx={{ width: '250px', height: '40px' }}>
|
||||||
|
تایید و ثبت نام
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user