From 2d68e441e47148d8ff38624440f6061b7b0a1ec2 Mon Sep 17 00:00:00 2001 From: Koosha Lahouti Date: Wed, 16 Jul 2025 23:30:12 +0330 Subject: [PATCH] feat: add user completion form --- .../components/UserCompletionForm.tsx | 353 ++++++++++++++++++ .../profile/component/PersonalInformation.tsx | 229 ++++++++++++ .../profile/component/PhoneNumber.tsx | 306 +++++++++++++++ .../profile/component/SocialMedia.tsx | 210 +++++++++++ src/features/profile/component/UserForm.tsx | 13 + 5 files changed, 1111 insertions(+) create mode 100644 src/features/authentication/components/UserCompletionForm.tsx create mode 100644 src/features/profile/component/PersonalInformation.tsx create mode 100644 src/features/profile/component/PhoneNumber.tsx create mode 100644 src/features/profile/component/SocialMedia.tsx create mode 100644 src/features/profile/component/UserForm.tsx diff --git a/src/features/authentication/components/UserCompletionForm.tsx b/src/features/authentication/components/UserCompletionForm.tsx new file mode 100644 index 0000000..7f71c92 --- /dev/null +++ b/src/features/authentication/components/UserCompletionForm.tsx @@ -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) => { + setShowPassword(e.target.checked); + }; + const handleToggleEmail = (e: React.ChangeEvent) => { + 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; + 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 ( +
+ + + + تکمیل اطلاعات حساب کاربری + + + اطلاعات کسب و کار خود را وارد کنید + + + + + + + + + جنسیت + + + + + + + + + تعیین رمز عبور + + + {showPassword && ( + + + setPassword(e.target.value)} + variant="outlined" + sx={{ + '& .MuiOutlinedInput-root': { + height: 45, + }, + }} + /> + {password && ( + + + شامل عدد + +
+ + حداقل 8 کاراکتر + +
+ + شامل یک حرف بزرگ و کوچک + +
+ + شامل علامت(!@#$%^&*) + +
+ )} +
+ {showPassword && ( + setConfirmPassword(e.target.value)} + error={confirmPassword.length > 0 && !matchPassword} + helperText={ + confirmPassword.length > 0 && !matchPassword + ? 'مطابقت ندارد' + : ' ' + } + sx={{ + width: '330px', + '& .MuiOutlinedInput-root': { + height: 45, + }, + }} + /> + )} +
+ )} + + + + + اتصال ایمیل خود + + + {showEmail && ( + + + + setEmail(e.target.value)} + sx={{ + width: '330px', + '& .MuiOutlinedInput-root': { + height: 45, + }, + }} + /> + {email && ( + + فرم درست ایمیل وارد کنید + + )} + + + + {codeSent && ( + + setVerificationCode(e.target.value)} + sx={{ + width: '330px', + '& .MuiOutlinedInput-root': { + height: 45, + }, + }} + /> + + + )} + + )} + + + ادامه فرایند ثبت نام به منزله تایید و قبول{' '} + + قوانین و مقررات هارمونی + {' '} + می باشد. + + + +
+
+ ); +} diff --git a/src/features/profile/component/PersonalInformation.tsx b/src/features/profile/component/PersonalInformation.tsx new file mode 100644 index 0000000..21967f1 --- /dev/null +++ b/src/features/profile/component/PersonalInformation.tsx @@ -0,0 +1,229 @@ +import { + Box, + Typography, + Button, + TextField, + Grid, + FormControl, + Select, + MenuItem, + type SelectChangeEvent, +} from '@mui/material'; +import { useState, type ChangeEvent } from 'react'; + +export function PersonalInformation() { + const [isEditing, setIsEditing] = useState(false); + const [gender, setGender] = useState(''); + const [data, setData] = useState({ + firstName: 'محمد حسین', + lastName: 'برزه‌گر', + gender: 'مرد', + nationalCode: '', + }); + + const handleChange = (e: ChangeEvent) => { + setData((prev) => ({ + ...prev, + [e.target.name]: e.target.value, + })); + }; + + const toggleEdit = () => { + setIsEditing((prev) => !prev); + if (isEditing) { + setData((prev) => ({ + ...prev, + gender: gender === 'male' ? 'مرد' : gender === 'female' ? 'زن' : '', + })); + } else { + setGender( + data.gender === 'مرد' ? 'male' : data.gender === 'زن' ? 'female' : '', + ); + } + }; + + const handleChangeGender = (e: SelectChangeEvent) => { + setGender(e.target.value); + }; + + const displayValue = (value: string | null | undefined) => { + return value && value.trim() !== '' ? value : 'تعیین نشده'; + }; + + return ( +
+ + + + + اطلاعات شخصی من + + + این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی + می‌ماند + + + + + {isEditing && ( + + )} + + + + + + + {isEditing ? ( + + ) : ( + + + نام + + + {displayValue(data.firstName)} + + + )} + + + + {isEditing ? ( + + ) : ( + + + نام خانوادگی + + + {displayValue(data.lastName)} + + + )} + + + + {isEditing ? ( + + + + ) : ( + + + جنسیت + + + {displayValue(data.gender)} + + + )} + + + + {isEditing ? ( + + ) : ( + + + کد ملی + + + {displayValue(data.nationalCode)} + + + )} + + + +
+ ); +} diff --git a/src/features/profile/component/PhoneNumber.tsx b/src/features/profile/component/PhoneNumber.tsx new file mode 100644 index 0000000..ccaff35 --- /dev/null +++ b/src/features/profile/component/PhoneNumber.tsx @@ -0,0 +1,306 @@ +import { + Box, + Typography, + Button, + Dialog, + DialogTitle, + DialogContent, + IconButton, + TextField, +} from '@mui/material'; +import { Edit, CloseSquare } from 'iconsax-react'; +import { useState, useEffect } from 'react'; + +export function PhoneNumber() { + const [open, setOpen] = useState(false); + const [dialogStep, setDialogStep] = useState<'enterPhone' | 'verifyCode'>( + 'enterPhone', + ); + const [buttonState, setButtonState] = useState('default'); // default | counting | sent + const [countdown, setCountdown] = useState(120); + + const handleChangePhoneNumber = () => { + setOpen(true); + }; + const handleClose = () => { + setOpen(false); + setDialogStep('enterPhone'); + }; + const handleSendCode = () => { + setDialogStep('verifyCode'); + setButtonState('sent'); + setTimeout(() => { + setButtonState('counting'); + setCountdown(120); + }, 1000); + }; + const handleResendCode = () => { + setButtonState('sent'); + setTimeout(() => { + setButtonState('counting'); + setCountdown(120); + }, 1000); + }; + + useEffect(() => { + if (buttonState === 'counting' && countdown > 0) { + const timer = setInterval(() => { + setCountdown((prev) => prev - 1); + }, 1000); + return () => clearInterval(timer); + } + if (countdown === 0 && buttonState === 'counting') { + setButtonState('default'); + } + }, [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 'ارسال دوباره کد'; + }; + + const handleEdit = () => { + setDialogStep('enterPhone'); + }; + + return ( +
+ + + + شماره تماس من + + این اطلاعات شما صرفا برای احراز هویت شما است و نزد هارمونی باقی + می‌ماند + + + + + + + + + 09909366045 + + + ۱ ماه پیش + + + + {/* */} + + + + + + ویرایش شماره تماس + + + + + + + {dialogStep === 'enterPhone' ? ( + <> + + شماره تماس جدید + + + شماره تماس جدید جایگزین شماره تماس قبلی شما خواهد شد + + + + + ) : ( + <> + + + + اعتبار سنجی + + + کد تایید 4 رقمی به شماره موبایل شما ارسال شد. لطفا آن را + وارد کنید + + + + + + + + + + + + )} + + + +
+ ); +} diff --git a/src/features/profile/component/SocialMedia.tsx b/src/features/profile/component/SocialMedia.tsx new file mode 100644 index 0000000..8e84bf9 --- /dev/null +++ b/src/features/profile/component/SocialMedia.tsx @@ -0,0 +1,210 @@ +import { Google, Apple, Sms, Trash, CloseSquare } from 'iconsax-react'; +import { + Box, + Button, + Typography, + Dialog, + DialogTitle, + DialogContent, + IconButton, + TextField, +} from '@mui/material'; +import { useState } from 'react'; + +export function SocialMedia() { + const [open, setOpen] = useState(false); + const handleOpen = () => setOpen(true); + const handleClose = () => setOpen(false); + + const emailList = [ + { email: 'emailtemp@email.com', provider: 'email' }, + { email: 'emailtemp@gmail.com', provider: 'google' }, + ]; + + return ( +
+ + + + ایمیل و شبکه‌های اجتماعی من + + این اطلاعات شما صرفاً برای احراز هویت شما است و نزد هارمونی باقی + می‌ماند + + + + + + {emailList.map((item, index) => ( + + + {item.provider === 'google' && ( + + )} + {item.provider === 'apple' && ( + + )} + {item.provider === 'email' && ( + + )} + + + + {item.email} + + ۱ ماه پیش + + + + + + + + ))} + + + + + افزودن ایمیل / سوشال + + + + + + + + + + + + + یا + + + + + + + + + + + +
+ ); +} diff --git a/src/features/profile/component/UserForm.tsx b/src/features/profile/component/UserForm.tsx new file mode 100644 index 0000000..329fc83 --- /dev/null +++ b/src/features/profile/component/UserForm.tsx @@ -0,0 +1,13 @@ +import { PersonalInformation } from './PersonalInformation'; +import { PhoneNumber } from './PhoneNumber'; +import { SocialMedia } from './SocialMedia'; + +export function UserForm() { + return ( + <> + + + + + ); +}