fix: api call and change the props of components
This commit is contained in:
23
src/App.tsx
23
src/App.tsx
@@ -21,29 +21,6 @@ function App() {
|
|||||||
<LanguageManager />
|
<LanguageManager />
|
||||||
<UserCompletionForm />
|
<UserCompletionForm />
|
||||||
<ThemeToggleButton />
|
<ThemeToggleButton />
|
||||||
{/* <div style={{ padding: '16px' }}>
|
|
||||||
<Typography variant="h3">{t('helloWorld')}</Typography>
|
|
||||||
<Box
|
|
||||||
sx={{ display: 'flex', flexDirection: 'column', gap: '10px', mt: 5 }}
|
|
||||||
>
|
|
||||||
<Button color="secondary" variant="contained">
|
|
||||||
secondary button
|
|
||||||
</Button>
|
|
||||||
<TextField label={t('helloWorld')} />
|
|
||||||
<Alert severity="success" variant="filled">
|
|
||||||
success
|
|
||||||
</Alert>
|
|
||||||
<Alert severity="warning" variant="filled">
|
|
||||||
warning
|
|
||||||
</Alert>
|
|
||||||
<Alert severity="info" variant="filled">
|
|
||||||
info
|
|
||||||
</Alert>
|
|
||||||
<Alert severity="error" variant="filled">
|
|
||||||
error
|
|
||||||
</Alert>
|
|
||||||
</Box>
|
|
||||||
</div> */}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,14 @@ import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
|||||||
import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalali';
|
import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalali';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
export function DateOfBirth() {
|
interface DateOfBirthProps {
|
||||||
|
value: Date | null;
|
||||||
|
onChange: (date: Date | null) => void;
|
||||||
|
}
|
||||||
|
export function DateOfBirth({ value, onChange }: DateOfBirthProps) {
|
||||||
const { t, i18n } = useTranslation('completionForm');
|
const { t, i18n } = useTranslation('completionForm');
|
||||||
const isFarsi = i18n.language === 'fa' || i18n.language === 'fa-IR';
|
const isFarsi = i18n.language === 'fa' || i18n.language === 'fa-IR';
|
||||||
const [birthDate, setBirthDate] = useState<Date | null>(null);
|
// const [birthDate, setBirthDate] = useState<Date | null>(null);
|
||||||
|
|
||||||
const Adapter = useMemo(() => {
|
const Adapter = useMemo(() => {
|
||||||
return isFarsi ? AdapterDateFnsJalali : AdapterDateFns;
|
return isFarsi ? AdapterDateFnsJalali : AdapterDateFns;
|
||||||
@@ -18,8 +22,8 @@ export function DateOfBirth() {
|
|||||||
<LocalizationProvider dateAdapter={Adapter}>
|
<LocalizationProvider dateAdapter={Adapter}>
|
||||||
<DatePicker
|
<DatePicker
|
||||||
label={t('completion.dateOfBirth')}
|
label={t('completion.dateOfBirth')}
|
||||||
value={birthDate}
|
value={value}
|
||||||
onChange={(newValue) => setBirthDate(newValue)}
|
onChange={onChange}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
textField: {
|
textField: {
|
||||||
fullWidth: true,
|
fullWidth: true,
|
||||||
|
|||||||
@@ -9,18 +9,34 @@ import {
|
|||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Woman, Man } from 'iconsax-react';
|
import { Woman, Man } from 'iconsax-react';
|
||||||
import { useState } from 'react';
|
import { useState, type Dispatch, type SetStateAction } from 'react';
|
||||||
import { DateOfBirth } from './DateOfBirth';
|
import { DateOfBirth } from './DateOfBirth';
|
||||||
import { countries } from '../data/Countries';
|
import { countries } from '../data/Countries';
|
||||||
|
|
||||||
interface PersonalInfoFieldsProps {
|
interface PersonalInfoFieldsProps {
|
||||||
sex: string;
|
firstName: string;
|
||||||
setSex: (sex: string) => void;
|
setFirstName: (v: string) => void;
|
||||||
|
lastName: string;
|
||||||
|
setLastName: (v: string) => void;
|
||||||
|
sex: 'male' | 'female';
|
||||||
|
setSex: Dispatch<SetStateAction<'female' | 'male'>>;
|
||||||
country: string;
|
country: string;
|
||||||
setCountry: (country: string) => void;
|
setCountry: (country: string) => void;
|
||||||
|
nationalId: string;
|
||||||
|
setNationalId: (v: string) => void;
|
||||||
|
birthDate: Date | null;
|
||||||
|
setBirthDate: (d: Date | null) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PersonalInfoFields({
|
export function PersonalInfoFields({
|
||||||
|
firstName,
|
||||||
|
setFirstName,
|
||||||
|
lastName,
|
||||||
|
setLastName,
|
||||||
|
nationalId,
|
||||||
|
setNationalId,
|
||||||
|
birthDate,
|
||||||
|
setBirthDate,
|
||||||
sex,
|
sex,
|
||||||
setSex,
|
setSex,
|
||||||
country,
|
country,
|
||||||
@@ -30,7 +46,7 @@ export function PersonalInfoFields({
|
|||||||
const [countryError, setCountryError] = useState(false);
|
const [countryError, setCountryError] = useState(false);
|
||||||
|
|
||||||
const handleChangeSex = (e: any) => {
|
const handleChangeSex = (e: any) => {
|
||||||
setSex(e.target.value);
|
setSex(e.target.value as 'female' | 'male');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChangeCountry = (_: any, newValue: any) => {
|
const handleChangeCountry = (_: any, newValue: any) => {
|
||||||
@@ -81,12 +97,16 @@ export function PersonalInfoFields({
|
|||||||
label={t('completion.name')}
|
label={t('completion.name')}
|
||||||
placeholder={t('completion.name')}
|
placeholder={t('completion.name')}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
value={firstName}
|
||||||
|
onChange={(e) => setFirstName(e.target.value)}
|
||||||
sx={fieldSx}
|
sx={fieldSx}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label={t('completion.familyName')}
|
label={t('completion.familyName')}
|
||||||
placeholder={t('completion.familyName')}
|
placeholder={t('completion.familyName')}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
value={lastName}
|
||||||
|
onChange={(e) => setLastName(e.target.value)}
|
||||||
sx={fieldSx}
|
sx={fieldSx}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -127,6 +147,8 @@ export function PersonalInfoFields({
|
|||||||
<TextField
|
<TextField
|
||||||
label={t('completion.optionalNationalCode')}
|
label={t('completion.optionalNationalCode')}
|
||||||
placeholder={t('completion.optionalNationalCode')}
|
placeholder={t('completion.optionalNationalCode')}
|
||||||
|
value={nationalId}
|
||||||
|
onChange={(e) => setNationalId(e.target.value)}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
sx={fieldSx}
|
sx={fieldSx}
|
||||||
/>
|
/>
|
||||||
@@ -181,7 +203,7 @@ export function PersonalInfoFields({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Box sx={fieldSx}>
|
<Box sx={fieldSx}>
|
||||||
<DateOfBirth />
|
<DateOfBirth value={birthDate} onChange={setBirthDate} />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -7,11 +7,15 @@ import {
|
|||||||
Dialog,
|
Dialog,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogActions,
|
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
interface Props {
|
||||||
export function SubmitSection() {
|
onSubmit: () => void;
|
||||||
|
loading: boolean;
|
||||||
|
error: string | null;
|
||||||
|
success: boolean;
|
||||||
|
}
|
||||||
|
export function SubmitSection({ onSubmit, loading, error, success }: Props) {
|
||||||
const { t, i18n } = useTranslation('completionForm');
|
const { t, i18n } = useTranslation('completionForm');
|
||||||
const [openDialog, setOpenDialog] = useState(false);
|
const [openDialog, setOpenDialog] = useState(false);
|
||||||
|
|
||||||
@@ -20,8 +24,6 @@ export function SubmitSection() {
|
|||||||
setOpenDialog(true);
|
setOpenDialog(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCloseDialog = () => setOpenDialog(false);
|
|
||||||
|
|
||||||
const agreementText = `۱. محرمانگی اطلاعات
هارمونی متعهد میشود تحت هیچ شرایطی اطلاعات هویتی کاربران نظیر شماره تلفن، ایمیل، رمز عبور، شناسه کاربری و هرگونه داده مرتبط را در اختیار اشخاص ثالث قرار ندهد. اطلاعات کاربران صرفاً در چارچوب ارائه خدمات احراز هویت مورد استفاده قرار گرفته و حتی پس از غیرفعالسازی حساب یا قطع همکاری، این اطلاعات محرمانه باقی خواهد ماند. هارمونی موظف به پیادهسازی تدابیر امنیتی لازم برای جلوگیری از هرگونه دسترسی غیرمجاز میباشد.
|
const agreementText = `۱. محرمانگی اطلاعات
هارمونی متعهد میشود تحت هیچ شرایطی اطلاعات هویتی کاربران نظیر شماره تلفن، ایمیل، رمز عبور، شناسه کاربری و هرگونه داده مرتبط را در اختیار اشخاص ثالث قرار ندهد. اطلاعات کاربران صرفاً در چارچوب ارائه خدمات احراز هویت مورد استفاده قرار گرفته و حتی پس از غیرفعالسازی حساب یا قطع همکاری، این اطلاعات محرمانه باقی خواهد ماند. هارمونی موظف به پیادهسازی تدابیر امنیتی لازم برای جلوگیری از هرگونه دسترسی غیرمجاز میباشد.
|
||||||
۲. مسئولیت حفظ اطلاعات ورود
کاربر موظف است از حساب کاربری خود محافظت کند و رمز عبوری ایمن و غیرقابل حدس انتخاب نماید. تغییر دورهای رمز عبور و اقدام فوری در صورت احساس خطر دسترسی غیرمجاز الزامی است. مسئولیت هرگونه سوءاستفاده از حساب کاربری به دلیل بیاحتیاطی کاربر، بر عهده خود وی خواهد بود.
|
۲. مسئولیت حفظ اطلاعات ورود
کاربر موظف است از حساب کاربری خود محافظت کند و رمز عبوری ایمن و غیرقابل حدس انتخاب نماید. تغییر دورهای رمز عبور و اقدام فوری در صورت احساس خطر دسترسی غیرمجاز الزامی است. مسئولیت هرگونه سوءاستفاده از حساب کاربری به دلیل بیاحتیاطی کاربر، بر عهده خود وی خواهد بود.
|
||||||
۳. رخنههای امنیتی و حملات سایبری
هارمونی در برابر رخنههای امنیتی ناشی از حملات سایبری که خارج از کنترل سیستم است، مسئولیتی ندارد. با این حال، هارمونی از بهروزترین استانداردهای امنیتی و رمزنگاری برای جلوگیری از چنین حوادثی بهره میبرد.
|
۳. رخنههای امنیتی و حملات سایبری
هارمونی در برابر رخنههای امنیتی ناشی از حملات سایبری که خارج از کنترل سیستم است، مسئولیتی ندارد. با این حال، هارمونی از بهروزترین استانداردهای امنیتی و رمزنگاری برای جلوگیری از چنین حوادثی بهره میبرد.
|
||||||
@@ -72,7 +74,7 @@ export function SubmitSection() {
|
|||||||
{t('completion.agreementPart2')}
|
{t('completion.agreementPart2')}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Button
|
{/* <Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
sx={{
|
sx={{
|
||||||
width: { xs: '100%', sm: '247px' },
|
width: { xs: '100%', sm: '247px' },
|
||||||
@@ -80,12 +82,20 @@ export function SubmitSection() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('completion.registerButton')}
|
{t('completion.registerButton')}
|
||||||
|
</Button> */}
|
||||||
|
<Button variant="contained" onClick={onSubmit} disabled={loading}>
|
||||||
|
{loading
|
||||||
|
? t('completion.submitting')
|
||||||
|
: success
|
||||||
|
? t('completion.success')
|
||||||
|
: t('completion.registerButton')}
|
||||||
</Button>
|
</Button>
|
||||||
|
{error && <Typography color="error">{error}</Typography>}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
open={openDialog}
|
open={openDialog}
|
||||||
onClose={handleCloseDialog}
|
onClose={() => setOpenDialog(false)}
|
||||||
fullWidth
|
fullWidth
|
||||||
maxWidth="md"
|
maxWidth="md"
|
||||||
dir={i18n.language.startsWith('fa') ? 'rtl' : 'ltr'}
|
dir={i18n.language.startsWith('fa') ? 'rtl' : 'ltr'}
|
||||||
|
|||||||
@@ -6,14 +6,22 @@ import { PasswordSection } from './PasswordSection';
|
|||||||
import { EmailSection } from './EmailSection';
|
import { EmailSection } from './EmailSection';
|
||||||
import { SubmitSection } from './SubmitSection';
|
import { SubmitSection } from './SubmitSection';
|
||||||
import Logo from '@/components/Logo';
|
import Logo from '@/components/Logo';
|
||||||
|
import apiClient from '@/lib/apiClient';
|
||||||
|
|
||||||
export function UserCompletionForm() {
|
export function UserCompletionForm() {
|
||||||
const { t } = useTranslation('completionForm');
|
const { t } = useTranslation('completionForm');
|
||||||
const [sex, setSex] = useState('');
|
|
||||||
|
const [firstName, setFirstName] = useState('');
|
||||||
|
const [lastName, setLastName] = useState('');
|
||||||
|
const [nationalId, setNationalId] = useState('');
|
||||||
|
const [birthDate, setBirthDate] = useState<Date | null>(null);
|
||||||
|
const [sex, setSex] = useState<'female' | 'male'>('female');
|
||||||
const [country, setCountry] = useState('');
|
const [country, setCountry] = useState('');
|
||||||
|
|
||||||
const [showPasswordSection, setShowPasswordSection] = useState(false);
|
const [showPasswordSection, setShowPasswordSection] = useState(false);
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
const [confirmPassword, setConfirmPassword] = useState('');
|
const [confirmPassword, setConfirmPassword] = useState('');
|
||||||
|
|
||||||
const [showEmail, setShowEmail] = useState(false);
|
const [showEmail, setShowEmail] = useState(false);
|
||||||
const [email, setEmail] = useState('');
|
const [email, setEmail] = useState('');
|
||||||
const [codeSent, setCodeSent] = useState(false);
|
const [codeSent, setCodeSent] = useState(false);
|
||||||
@@ -24,6 +32,7 @@ export function UserCompletionForm() {
|
|||||||
const [countdown, setCountdown] = useState(60);
|
const [countdown, setCountdown] = useState(60);
|
||||||
const [emailVerified, setEmailVerified] = useState(false);
|
const [emailVerified, setEmailVerified] = useState(false);
|
||||||
const [isVerifyingCode, setIsVerifyingCode] = useState(false);
|
const [isVerifyingCode, setIsVerifyingCode] = useState(false);
|
||||||
|
const correctEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
||||||
|
|
||||||
const matchPassword = password === confirmPassword;
|
const matchPassword = password === confirmPassword;
|
||||||
const hasNumber = /\d/.test(password);
|
const hasNumber = /\d/.test(password);
|
||||||
@@ -33,7 +42,10 @@ export function UserCompletionForm() {
|
|||||||
const validPassword =
|
const validPassword =
|
||||||
hasNumber && hasMinLength && hasUpperAndLower && hasSpecialChar;
|
hasNumber && hasMinLength && hasUpperAndLower && hasSpecialChar;
|
||||||
const [showPasswordValidations, setShowPasswordValidations] = useState(false);
|
const [showPasswordValidations, setShowPasswordValidations] = useState(false);
|
||||||
const correctEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [success, setSuccess] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (password) {
|
if (password) {
|
||||||
@@ -96,6 +108,44 @@ export function UserCompletionForm() {
|
|||||||
setCodeSent(false);
|
setCodeSent(false);
|
||||||
setEmailVerified(false);
|
setEmailVerified(false);
|
||||||
};
|
};
|
||||||
|
const STATICTOKEN = 'Bearer abcdef1234567890';
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
setSuccess(false);
|
||||||
|
try {
|
||||||
|
const { data } = await apiClient.post<{
|
||||||
|
success: boolean;
|
||||||
|
errorCode: number;
|
||||||
|
message: string;
|
||||||
|
validations: { property: string; message: string }[];
|
||||||
|
}>(
|
||||||
|
'/User/CompleteUserInformation',
|
||||||
|
{
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
|
gender: sex === 'female' ? 2 : 1,
|
||||||
|
nationalId,
|
||||||
|
savePassword: showPasswordSection,
|
||||||
|
password: showPasswordSection ? password : undefined,
|
||||||
|
saveEmail: showEmail,
|
||||||
|
email: showEmail ? email : undefined,
|
||||||
|
birthDate,
|
||||||
|
},
|
||||||
|
{ headers: { Authorization: STATICTOKEN } },
|
||||||
|
);
|
||||||
|
if (data.success) {
|
||||||
|
setSuccess(true);
|
||||||
|
} else {
|
||||||
|
setError(data.message || 'Validation error');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setError((err as Error).message || 'An error occurred');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@@ -140,14 +190,20 @@ export function UserCompletionForm() {
|
|||||||
{t('completion.description')}
|
{t('completion.description')}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<PersonalInfoFields
|
<PersonalInfoFields
|
||||||
|
firstName={firstName}
|
||||||
|
setFirstName={setFirstName}
|
||||||
|
lastName={lastName}
|
||||||
|
setLastName={setLastName}
|
||||||
|
nationalId={nationalId}
|
||||||
|
setNationalId={setNationalId}
|
||||||
|
birthDate={birthDate}
|
||||||
|
setBirthDate={setBirthDate}
|
||||||
sex={sex}
|
sex={sex}
|
||||||
setSex={setSex}
|
setSex={setSex}
|
||||||
country={country}
|
country={country}
|
||||||
setCountry={setCountry}
|
setCountry={setCountry}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<PasswordSection
|
<PasswordSection
|
||||||
showPasswordSection={showPasswordSection}
|
showPasswordSection={showPasswordSection}
|
||||||
setShowPasswordSection={setShowPasswordSection}
|
setShowPasswordSection={setShowPasswordSection}
|
||||||
@@ -163,7 +219,6 @@ export function UserCompletionForm() {
|
|||||||
validPassword={validPassword}
|
validPassword={validPassword}
|
||||||
showValidations={showPasswordValidations}
|
showValidations={showPasswordValidations}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<EmailSection
|
<EmailSection
|
||||||
showEmail={showEmail}
|
showEmail={showEmail}
|
||||||
setShowEmail={setShowEmail}
|
setShowEmail={setShowEmail}
|
||||||
@@ -181,8 +236,12 @@ export function UserCompletionForm() {
|
|||||||
isVerifyingCode={isVerifyingCode}
|
isVerifyingCode={isVerifyingCode}
|
||||||
handleEditEmail={handleEditEmail}
|
handleEditEmail={handleEditEmail}
|
||||||
/>
|
/>
|
||||||
|
<SubmitSection
|
||||||
<SubmitSection />
|
onSubmit={handleSubmit}
|
||||||
|
loading={loading}
|
||||||
|
error={error}
|
||||||
|
success={success}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const getToken = () => localStorage.getItem('authToken');
|
|||||||
|
|
||||||
const apiClient = axios.create({
|
const apiClient = axios.create({
|
||||||
// Define the base URL for all API requests
|
// Define the base URL for all API requests
|
||||||
baseURL: 'https://api.yourapp.com/v1',
|
baseURL: 'https://account.business-harmony.com/api/',
|
||||||
|
|
||||||
// Set a timeout for requests (e.g., 10 seconds)
|
// Set a timeout for requests (e.g., 10 seconds)
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
|
|||||||
Reference in New Issue
Block a user