fix: api call and change the props of components

This commit is contained in:
Koosha Lahouti
2025-08-05 14:03:09 -07:00
parent 6cb742ff39
commit 0f9ef06742
6 changed files with 119 additions and 47 deletions

View File

@@ -21,29 +21,6 @@ function App() {
<LanguageManager />
<UserCompletionForm />
<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> */}
</>
);
}

View File

@@ -5,10 +5,14 @@ import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { AdapterDateFnsJalali } from '@mui/x-date-pickers/AdapterDateFnsJalali';
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 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(() => {
return isFarsi ? AdapterDateFnsJalali : AdapterDateFns;
@@ -18,8 +22,8 @@ export function DateOfBirth() {
<LocalizationProvider dateAdapter={Adapter}>
<DatePicker
label={t('completion.dateOfBirth')}
value={birthDate}
onChange={(newValue) => setBirthDate(newValue)}
value={value}
onChange={onChange}
slotProps={{
textField: {
fullWidth: true,

View File

@@ -9,18 +9,34 @@ import {
} from '@mui/material';
import { useTranslation } from 'react-i18next';
import { Woman, Man } from 'iconsax-react';
import { useState } from 'react';
import { useState, type Dispatch, type SetStateAction } from 'react';
import { DateOfBirth } from './DateOfBirth';
import { countries } from '../data/Countries';
interface PersonalInfoFieldsProps {
sex: string;
setSex: (sex: string) => void;
firstName: string;
setFirstName: (v: string) => void;
lastName: string;
setLastName: (v: string) => void;
sex: 'male' | 'female';
setSex: Dispatch<SetStateAction<'female' | 'male'>>;
country: string;
setCountry: (country: string) => void;
nationalId: string;
setNationalId: (v: string) => void;
birthDate: Date | null;
setBirthDate: (d: Date | null) => void;
}
export function PersonalInfoFields({
firstName,
setFirstName,
lastName,
setLastName,
nationalId,
setNationalId,
birthDate,
setBirthDate,
sex,
setSex,
country,
@@ -30,7 +46,7 @@ export function PersonalInfoFields({
const [countryError, setCountryError] = useState(false);
const handleChangeSex = (e: any) => {
setSex(e.target.value);
setSex(e.target.value as 'female' | 'male');
};
const handleChangeCountry = (_: any, newValue: any) => {
@@ -81,12 +97,16 @@ export function PersonalInfoFields({
label={t('completion.name')}
placeholder={t('completion.name')}
variant="outlined"
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
sx={fieldSx}
/>
<TextField
label={t('completion.familyName')}
placeholder={t('completion.familyName')}
variant="outlined"
value={lastName}
onChange={(e) => setLastName(e.target.value)}
sx={fieldSx}
/>
</Box>
@@ -127,6 +147,8 @@ export function PersonalInfoFields({
<TextField
label={t('completion.optionalNationalCode')}
placeholder={t('completion.optionalNationalCode')}
value={nationalId}
onChange={(e) => setNationalId(e.target.value)}
variant="outlined"
sx={fieldSx}
/>
@@ -181,7 +203,7 @@ export function PersonalInfoFields({
/>
<Box sx={fieldSx}>
<DateOfBirth />
<DateOfBirth value={birthDate} onChange={setBirthDate} />
</Box>
</Box>
</Box>

View File

@@ -7,11 +7,15 @@ import {
Dialog,
DialogTitle,
DialogContent,
DialogActions,
} from '@mui/material';
import { useTranslation } from 'react-i18next';
export function SubmitSection() {
interface Props {
onSubmit: () => void;
loading: boolean;
error: string | null;
success: boolean;
}
export function SubmitSection({ onSubmit, loading, error, success }: Props) {
const { t, i18n } = useTranslation('completionForm');
const [openDialog, setOpenDialog] = useState(false);
@@ -20,8 +24,6 @@ export function SubmitSection() {
setOpenDialog(true);
};
const handleCloseDialog = () => setOpenDialog(false);
const agreementText = `۱. محرمانگی اطلاعات
 هارمونی متعهد می‌شود تحت هیچ شرایطی اطلاعات هویتی کاربران نظیر شماره تلفن، ایمیل، رمز عبور، شناسه کاربری و هرگونه داده مرتبط را در اختیار اشخاص ثالث قرار ندهد. اطلاعات کاربران صرفاً در چارچوب ارائه خدمات احراز هویت مورد استفاده قرار گرفته و حتی پس از غیرفعال‌سازی حساب یا قطع همکاری، این اطلاعات محرمانه باقی خواهد ماند. هارمونی موظف به پیاده‌سازی تدابیر امنیتی لازم برای جلوگیری از هرگونه دسترسی غیرمجاز می‌باشد.
۲. مسئولیت حفظ اطلاعات ورود
 کاربر موظف است از حساب کاربری خود محافظت کند و رمز عبوری ایمن و غیرقابل حدس انتخاب نماید. تغییر دوره‌ای رمز عبور و اقدام فوری در صورت احساس خطر دسترسی غیرمجاز الزامی است. مسئولیت هرگونه سوءاستفاده از حساب کاربری به دلیل بی‌احتیاطی کاربر، بر عهده خود وی خواهد بود.
۳. رخنه‌های امنیتی و حملات سایبری
 هارمونی در برابر رخنه‌های امنیتی ناشی از حملات سایبری که خارج از کنترل سیستم است، مسئولیتی ندارد. با این حال، هارمونی از به‌روزترین استانداردهای امنیتی و رمزنگاری برای جلوگیری از چنین حوادثی بهره می‌برد.
@@ -72,7 +74,7 @@ export function SubmitSection() {
{t('completion.agreementPart2')}
</Typography>
<Button
{/* <Button
variant="contained"
sx={{
width: { xs: '100%', sm: '247px' },
@@ -80,12 +82,20 @@ export function SubmitSection() {
}}
>
{t('completion.registerButton')}
</Button> */}
<Button variant="contained" onClick={onSubmit} disabled={loading}>
{loading
? t('completion.submitting')
: success
? t('completion.success')
: t('completion.registerButton')}
</Button>
{error && <Typography color="error">{error}</Typography>}
</Box>
<Dialog
open={openDialog}
onClose={handleCloseDialog}
onClose={() => setOpenDialog(false)}
fullWidth
maxWidth="md"
dir={i18n.language.startsWith('fa') ? 'rtl' : 'ltr'}

View File

@@ -6,14 +6,22 @@ import { PasswordSection } from './PasswordSection';
import { EmailSection } from './EmailSection';
import { SubmitSection } from './SubmitSection';
import Logo from '@/components/Logo';
import apiClient from '@/lib/apiClient';
export function UserCompletionForm() {
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 [showPasswordSection, setShowPasswordSection] = useState(false);
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [showEmail, setShowEmail] = useState(false);
const [email, setEmail] = useState('');
const [codeSent, setCodeSent] = useState(false);
@@ -24,6 +32,7 @@ export function UserCompletionForm() {
const [countdown, setCountdown] = useState(60);
const [emailVerified, setEmailVerified] = useState(false);
const [isVerifyingCode, setIsVerifyingCode] = useState(false);
const correctEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
const matchPassword = password === confirmPassword;
const hasNumber = /\d/.test(password);
@@ -33,7 +42,10 @@ export function UserCompletionForm() {
const validPassword =
hasNumber && hasMinLength && hasUpperAndLower && hasSpecialChar;
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(() => {
if (password) {
@@ -96,6 +108,44 @@ export function UserCompletionForm() {
setCodeSent(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 (
<Box
@@ -140,14 +190,20 @@ export function UserCompletionForm() {
{t('completion.description')}
</Typography>
</Box>
<PersonalInfoFields
firstName={firstName}
setFirstName={setFirstName}
lastName={lastName}
setLastName={setLastName}
nationalId={nationalId}
setNationalId={setNationalId}
birthDate={birthDate}
setBirthDate={setBirthDate}
sex={sex}
setSex={setSex}
country={country}
setCountry={setCountry}
/>
<PasswordSection
showPasswordSection={showPasswordSection}
setShowPasswordSection={setShowPasswordSection}
@@ -163,7 +219,6 @@ export function UserCompletionForm() {
validPassword={validPassword}
showValidations={showPasswordValidations}
/>
<EmailSection
showEmail={showEmail}
setShowEmail={setShowEmail}
@@ -181,8 +236,12 @@ export function UserCompletionForm() {
isVerifyingCode={isVerifyingCode}
handleEditEmail={handleEditEmail}
/>
<SubmitSection />
<SubmitSection
onSubmit={handleSubmit}
loading={loading}
error={error}
success={success}
/>
</Box>
</Box>
);

View File

@@ -5,7 +5,7 @@ const getToken = () => localStorage.getItem('authToken');
const apiClient = axios.create({
// 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)
timeout: 10000,