chore: add icons and toast

This commit is contained in:
Koosha Lahouti
2025-08-12 04:23:08 +03:30
parent 91f61614c5
commit 508b7af39f
14 changed files with 1250 additions and 584 deletions

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect } from 'react';
import {
TextField,
Box,
@@ -12,7 +12,7 @@ import {
} from '@mui/material';
import { useTranslation } from 'react-i18next';
import { TickCircle, Edit } from 'iconsax-react';
import { Toast } from '@/components/Toast';
import { Icon } from '@rkheftan/harmony-ui';
interface EmailSectionProps {
showEmail: boolean;
@@ -50,15 +50,11 @@ export function EmailSection({
handleEditEmail,
}: EmailSectionProps) {
const { t } = useTranslation('completionForm');
const [showSuccessToast, setShowSuccessToast] = useState(false);
const [showErrorToast, setShowErrorToast] = useState(false);
const onSendCodeClick = () => {
if (!correctEmail) {
setShowErrorToast(true);
return;
}
setShowErrorToast(false);
handleSendCode();
};
@@ -68,14 +64,11 @@ export function EmailSection({
useEffect(() => {
if (emailVerified) {
setShowSuccessToast(true);
}
}, [emailVerified]);
const fieldSx = {
flex: '1 1 260px',
// maxWidth: emailVerified ? '634px' : '462px',
// width: '100%',
};
return (
@@ -130,15 +123,11 @@ export function EmailSection({
startAdornment:
!isVerifyingCode && emailVerified ? (
<InputAdornment position="end">
<TickCircle
size="24"
color="#2e7d32"
<Icon
Component={TickCircle}
size="medium"
variant="Bold"
style={{
position: 'absolute',
right: 0,
marginRight: '4px',
}}
color="success.main"
/>
</InputAdornment>
) : null,
@@ -146,10 +135,10 @@ export function EmailSection({
buttonState === 'counting' ? (
<InputAdornment position="start">
<IconButton onClick={handleEditEmail}>
<Edit
size="20"
color="#2979FF"
style={{ position: 'absolute', left: 0 }}
<Icon
Component={Edit}
color="primary.main"
size="medium"
/>
</IconButton>
</InputAdornment>
@@ -226,22 +215,6 @@ export function EmailSection({
)}
</Box>
)}
<Toast
color="success"
open={showSuccessToast}
onClose={() => setShowSuccessToast(false)}
>
{t('completion.alertSuccess')}
</Toast>
<Toast
color="error"
open={showErrorToast}
onClose={() => setShowErrorToast(false)}
>
{t('completion.emailCorrectForm')}
</Toast>
</>
);
}

View File

@@ -9,8 +9,9 @@ import {
InputAdornment,
} from '@mui/material';
import { useTranslation } from 'react-i18next';
import { TickCircle, Eye, EyeSlash, CloseCircle } from 'iconsax-react';
import { TickCircle, Eye, EyeSlash, CloseCircle, Size } from 'iconsax-react';
import { PasswordValidationItem } from './PasswordValidation';
import { Icon } from '@rkheftan/harmony-ui';
interface PasswordSectionProps {
showPasswordSection: boolean;
@@ -60,8 +61,6 @@ export function PasswordSection({
const fieldSx = {
flex: '1 1 260px',
maxWidth: '309px',
width: '100%',
};
return (
@@ -127,25 +126,31 @@ export function PasswordSection({
}}
>
{validPassword && (
<TickCircle
size="24"
color="#14AE5C"
variant="Bold"
style={{
position: 'absolute',
right: 0,
marginRight: '16px',
}}
/>
<Box sx={{ position: 'absolute', left: 0, px: 2 }}>
<Icon
Component={TickCircle}
size="medium"
color="success.main"
variant="Bold"
/>
</Box>
)}
<IconButton
onClick={handleTogglePasswordEye}
sx={{ ml: validPassword ? 0.5 : 'auto' }}
>
{showPasswordText ? (
<Eye size="24" color="#2979FF" />
<Icon
Component={Eye}
color="primary.main"
size="medium"
/>
) : (
<EyeSlash size="24" color="#2979FF" />
<Icon
Component={EyeSlash}
size="medium"
color="primary.main"
/>
)}
</IconButton>
</Box>
@@ -184,27 +189,30 @@ export function PasswordSection({
>
{confirmPassword.length > 0 &&
(matchPassword ? (
<TickCircle
size="24"
color="#14AE5C"
variant="Bold"
style={{
position: 'absolute',
right: 0,
marginRight: '16px',
}}
/>
<Box sx={{ position: 'absolute', left: 0, px: 2 }}>
<Icon
Component={TickCircle}
size="medium"
color="success.main"
variant="Bold"
/>
</Box>
) : (
<CloseCircle
size="24"
color="red"
variant="Bold"
style={{
<Box
sx={{
position: 'absolute',
right: 0,
marginRight: '16px',
left: 0,
alignItems: 'center',
px: 2,
}}
/>
>
<Icon
Component={CloseCircle}
size="medium"
color="error.main"
variant="Bold"
/>
</Box>
))}
<IconButton
@@ -217,9 +225,17 @@ export function PasswordSection({
}}
>
{showPasswordRepititonText ? (
<Eye size="24" color="#2979FF" />
<Icon
Component={Eye}
color="primary.main"
size="medium"
/>
) : (
<EyeSlash size="24" color="#2979FF" />
<Icon
Component={EyeSlash}
size="medium"
color="primary.main"
/>
)}
</IconButton>
</Box>
@@ -252,7 +268,6 @@ export function PasswordSection({
<Box
sx={{
flex: '1 1 260px',
maxWidth: '317px',
display: 'flex',
flexDirection: 'column',
}}
@@ -269,7 +284,6 @@ export function PasswordSection({
<Box
sx={{
flex: '1 1 260px',
maxWidth: '317px',
display: 'flex',
flexDirection: 'column',
}}

View File

@@ -1,5 +1,6 @@
import { Box, Typography } from '@mui/material';
import { TickCircle } from 'iconsax-react';
import { Icon } from '@rkheftan/harmony-ui';
interface ValidationItemProps {
isValid: boolean;
@@ -20,11 +21,13 @@ export function PasswordValidationItem({
flexWrap: 'wrap',
}}
>
<TickCircle
size="16"
color={isValid ? '#14AE5C' : '#2979FF'}
<Icon
Component={TickCircle}
size="small"
color={isValid ? 'success.main' : 'primary.main'}
variant={isValid ? 'Bold' : 'Outline'}
/>
<Typography
variant="body2"
color="text.primary"

View File

@@ -10,15 +10,11 @@ import {
} from '@mui/material';
import { useTranslation } from 'react-i18next';
import { Woman, Man } from 'iconsax-react';
import { useState, type Dispatch, type SetStateAction } from 'react';
import { countries } from '../data/Countries';
import { type Dispatch, type SetStateAction } from 'react';
import DateOfBirth from './DateOfBirth';
interface CountryType {
name: string;
fa: string;
flag: string;
}
import { countries } from '../data/Countries';
import { CountryFlag } from '@/components/CountryFlag';
import { Icon } from '@rkheftan/harmony-ui';
interface PersonalInfoFieldsProps {
firstName: string;
@@ -50,47 +46,18 @@ export function PersonalInfoFields({
setCountry,
}: PersonalInfoFieldsProps) {
const { t } = useTranslation('completionForm');
const [countryError, setCountryError] = useState(false);
// Language check to pass down for date picker
// const isFarsi = i18n.language === 'fa' || i18n.language === 'fa-IR';
const countryOptions = countries.map((c) => ({
code: c.code,
label: t(c.label, { ns: 'countries' }),
}));
const currentCountry = countryOptions.find((c) => c.code === country) || null;
const handleChangeSex = (e: SelectChangeEvent<'male' | 'female'>) => {
setSex(e.target.value as 'female' | 'male');
};
const handleChangeCountry = (
_: React.SyntheticEvent,
newValue: string | CountryType | null,
) => {
if (typeof newValue === 'string') {
setCountry(newValue);
setCountryError(false);
} else if (newValue === null) {
setCountry('');
setCountryError(false);
} else {
setCountry(newValue.name);
setCountryError(false);
}
};
const handleCountryBlur = (e: React.FocusEvent<HTMLInputElement>) => {
const inputValue = e.target.value.trim();
// Check if input matches any country's fa name
const exists = countries.some((c) => c.fa === inputValue);
setCountryError(Boolean(inputValue && !exists));
};
const handleInputChange = (_: React.SyntheticEvent, value: string) => {
const exists = countries.some((c) => c.fa === value.trim());
setCountryError(Boolean(value.trim() && !exists));
};
const fieldSx = {
flex: '1 1 260px',
maxWidth: '309px',
width: '100%',
};
return (
@@ -153,13 +120,13 @@ export function PersonalInfoFields({
>
<MenuItem value="female">
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<Woman size={20} color="#F50057" />
<Icon Component={Woman} color="#F50057" size="small" />
{t('completion.woman')}
</Box>
</MenuItem>
<MenuItem value="male">
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<Man size={20} color="#0091EA" />
<Icon Component={Man} size="small" color="#0091EA" />
{t('completion.man')}
</Box>
</MenuItem>
@@ -188,40 +155,23 @@ export function PersonalInfoFields({
}}
>
<Autocomplete
options={countries}
getOptionLabel={(c) => (typeof c === 'string' ? c : c.fa)}
value={countries.find((c) => c.name === country) || null}
onChange={handleChangeCountry}
onInputChange={handleInputChange}
freeSolo
noOptionsText=""
renderOption={(props, c) => (
<Box
component="li"
{...props}
sx={{ display: 'flex', alignItems: 'center', gap: 1 }}
>
<img
src={`https://flagcdn.com/w40/${c.flag}.png`}
width="24"
height="24"
style={{ borderRadius: '2px', border: '1px solid #ccc' }}
alt={c.name}
/>
{c.fa}
sx={fieldSx}
options={countryOptions}
getOptionLabel={(option) => option.label}
value={currentCountry}
onChange={(_, newValue) => {
setCountry(newValue?.code || '');
}}
renderOption={(props, option) => (
<Box component="li" {...props} key={option.code}>
<CountryFlag code={option.code} />
{option.label}
</Box>
)}
renderInput={(params) => (
<TextField
{...params}
label={t('completion.country')}
variant="outlined"
error={countryError}
helperText={countryError ? t('completion.invalidCountry') : ''}
onBlur={handleCountryBlur}
/>
<TextField {...params} label={t('completion.country')} />
)}
sx={fieldSx}
clearOnEscape
/>
<Box sx={fieldSx}>

View File

@@ -7,7 +7,8 @@ import { PasswordSection } from './PasswordSection';
import { EmailSection } from './EmailSection';
import { SubmitSection } from './SubmitSection';
import apiClient from '@/lib/apiClient';
import { Toast } from '@/components/Toast';
import { useToast } from '@rkheftan/harmony-ui';
import { AxiosError } from 'axios';
export function UserCompletionForm() {
const { t } = useTranslation('completionForm');
@@ -48,19 +49,8 @@ export function UserCompletionForm() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [success, setSuccess] = useState(false);
const [showSuccessToast, setShowSuccessToast] = useState(false);
const [showErrorToast, setShowErrorToast] = useState(false);
const [toastMessage, setToastMessage] = useState('');
const [showVerifyCodeSectionSuccess, setShowVerifyCodeSectionSuccess] =
useState(false);
const [showVerifyCodeSectionError, setShowVerifyCodeSectionError] =
useState(false);
const [sentVerificationCode, setSentVerificationCode] = useState('');
const [showVerifiedSuccess, setShowVerifiedSuccess] = useState(false);
const [showVerifiedError, setShowVerifiedError] = useState(false);
const [emailVerifiedMessage, setEmailVerifiedMessage] = useState('');
const showToast = useToast();
useEffect(() => {
if (password) {
@@ -111,28 +101,34 @@ export function UserCompletionForm() {
try {
const response = await apiClient.post('/User/SendEmailOtp', { email });
if (response.data?.success) {
setShowVerifyCodeSectionSuccess(true);
setSentVerificationCode(
response.data.message || 'کد با موفقیت ارسال شد',
);
showToast({
message: response.data.message || t('completion.successfullCodeSent'),
severity: 'success',
});
setCodeSent(true);
setButtonState('counting');
setCountdown(120);
} else if (response.data?.codeSentAnyway) {
setShowVerifyCodeSectionSuccess(true);
setSentVerificationCode(
'کد ارسال شد، اما: ' + (response.data.message || ''),
);
showToast({
message: t('completion.codeSentBut') + (response.data.message || ''),
severity: 'warning',
});
setCodeSent(true);
setButtonState('counting');
setCountdown(120);
} else {
setShowVerifyCodeSectionError(true);
setSentVerificationCode(response.data.message || 'مشکلی پیش آمده');
showToast({
message: response.data.message || t('completion.problem'),
severity: 'error',
});
}
} catch (err: any) {
setShowVerifyCodeSectionError(true);
setSentVerificationCode(err.response?.data?.message || 'مشکلی پیش آمده');
} catch (error: unknown) {
const err = error as AxiosError<{ message?: string }>;
showToast({
message: err.response?.data?.message || t('completion.problem'),
severity: 'error',
});
} finally {
setLoading(false);
}
@@ -141,6 +137,7 @@ export function UserCompletionForm() {
const handleVerifyCode = async () => {
if (!verificationCode.trim()) {
setError('Please enter the verification code');
return;
}
@@ -156,18 +153,23 @@ export function UserCompletionForm() {
if (res.data?.success) {
setEmailVerified(true);
setSuccess(true);
setShowVerifiedSuccess(true);
setEmailVerifiedMessage(res.data.message || 'کد با موفقیت تایید شد');
showToast({
message: res.data.message || t('completion.codeVerified'),
severity: 'success',
});
} else {
// setError(res.data?.message || 'Invalid verification code');
setShowVerifiedError(true);
setEmailVerifiedMessage(res.data?.message || 'کد تایید نامعتبر است');
showToast({
message: res.data?.message || t('completion.invalidCode'),
severity: 'error',
});
setEmailVerified(false);
}
} catch (err: any) {
setError(err.response?.data?.message || 'خطای ناشناخته');
setShowVerifiedError(true);
setEmailVerifiedMessage(err.response?.data?.message || 'خطای ناشناخته');
} catch (error: unknown) {
const err = error as AxiosError<{ message?: string }>;
showToast({
message: err.response?.data?.message || '',
severity: 'error',
});
setEmailVerified(false);
} finally {
setIsVerifyingCode(false);
@@ -205,17 +207,23 @@ export function UserCompletionForm() {
country,
});
if (data.success) {
setToastMessage(data.message || t('completion.submitSuccess'));
setShowSuccessToast(true);
showToast({
message: data.message || t('completion.submitSuccess'),
severity: 'success',
});
} else {
setToastMessage(data.message || t('completion.submitError'));
setShowErrorToast(true);
showToast({
message: data.message || t('completion.submitError'),
severity: 'success',
});
}
} catch (err: any) {
setToastMessage(
err.response?.data?.message || err.message || 'خطای ناشناخته',
);
setShowErrorToast(true);
} catch (error: unknown) {
const err = error as AxiosError<{ message?: string }>;
showToast({
message:
err.response?.data?.message || err.message || t('completion.problem'),
severity: 'error',
});
} finally {
setLoading(false);
}
@@ -289,37 +297,6 @@ export function UserCompletionForm() {
showValidations={showPasswordValidations}
/>
<Toast
color="success"
open={showVerifyCodeSectionSuccess}
onClose={() => setShowVerifyCodeSectionSuccess(false)}
>
{sentVerificationCode}
</Toast>
<Toast
color="error"
open={showVerifyCodeSectionError}
onClose={() => setShowVerifyCodeSectionError(false)}
>
{sentVerificationCode}
</Toast>
<Toast
color="success"
open={showVerifiedSuccess}
onClose={() => setShowVerifiedSuccess(false)}
>
{emailVerifiedMessage}
</Toast>
<Toast
color="error"
open={showVerifiedError}
onClose={() => setShowVerifiedError(false)}
>
{emailVerifiedMessage}
</Toast>
<EmailSection
showEmail={showEmail}
setShowEmail={setShowEmail}
@@ -337,21 +314,6 @@ export function UserCompletionForm() {
isVerifyingCode={isVerifyingCode}
handleEditEmail={handleEditEmail}
/>
<Toast
color="success"
open={showSuccessToast}
onClose={() => setShowSuccessToast(false)}
>
{toastMessage}
</Toast>
<Toast
color="error"
open={showErrorToast}
onClose={() => setShowErrorToast(false)}
>
{toastMessage}
</Toast>
<SubmitSection
onSubmit={handleSubmit}
loading={loading}

View File

@@ -0,0 +1,271 @@
export interface Country {
code: string;
label: string;
phone: string;
}
export interface Country {
code: string;
label: string;
phone: string;
}
export const countries: readonly Country[] = [
{ code: 'AF', label: 'country.afghanistan', phone: '+93' },
{ code: 'AX', label: 'country.aland_islands', phone: '+358' },
{ code: 'AL', label: 'country.albania', phone: '+355' },
{ code: 'DZ', label: 'country.algeria', phone: '+213' },
{ code: 'AS', label: 'country.american_samoa', phone: '+1684' },
{ code: 'AD', label: 'country.andorra', phone: '+376' },
{ code: 'AO', label: 'country.angola', phone: '+244' },
{ code: 'AI', label: 'country.anguilla', phone: '+1264' },
{ code: 'AQ', label: 'country.antarctica', phone: '+672' },
{ code: 'AG', label: 'country.antigua_and_barbuda', phone: '+1268' },
{ code: 'AR', label: 'country.argentina', phone: '+54' },
{ code: 'AM', label: 'country.armenia', phone: '+374' },
{ code: 'AW', label: 'country.aruba', phone: '+297' },
{ code: 'AU', label: 'country.australia', phone: '+61' },
{ code: 'AT', label: 'country.austria', phone: '+43' },
{ code: 'AZ', label: 'country.azerbaijan', phone: '+994' },
{ code: 'BS', label: 'country.bahamas', phone: '+1242' },
{ code: 'BH', label: 'country.bahrain', phone: '+973' },
{ code: 'BD', label: 'country.bangladesh', phone: '+880' },
{ code: 'BB', label: 'country.barbados', phone: '+1246' },
{ code: 'BY', label: 'country.belarus', phone: '+375' },
{ code: 'BE', label: 'country.belgium', phone: '+32' },
{ code: 'BZ', label: 'country.belize', phone: '+501' },
{ code: 'BJ', label: 'country.benin', phone: '+229' },
{ code: 'BM', label: 'country.bermuda', phone: '+1441' },
{ code: 'BT', label: 'country.bhutan', phone: '+975' },
{ code: 'BO', label: 'country.bolivia', phone: '+591' },
{ code: 'BA', label: 'country.bosnia_and_herzegovina', phone: '+387' },
{ code: 'BW', label: 'country.botswana', phone: '+267' },
{ code: 'BR', label: 'country.brazil', phone: '+55' },
{
code: 'IO',
label: 'country.british_indian_ocean_territory',
phone: '+246',
},
{ code: 'VG', label: 'country.british_virgin_islands', phone: '+1284' },
{ code: 'BN', label: 'country.brunei', phone: '+673' },
{ code: 'BG', label: 'country.bulgaria', phone: '+359' },
{ code: 'BF', label: 'country.burkina_faso', phone: '+226' },
{ code: 'BI', label: 'country.burundi', phone: '+257' },
{ code: 'KH', label: 'country.cambodia', phone: '+855' },
{ code: 'CM', label: 'country.cameroon', phone: '+237' },
{ code: 'CA', label: 'country.canada', phone: '+1' },
{ code: 'CV', label: 'country.cape_verde', phone: '+238' },
{ code: 'KY', label: 'country.cayman_islands', phone: '+1345' },
{ code: 'CF', label: 'country.central_african_republic', phone: '+236' },
{ code: 'TD', label: 'country.chad', phone: '+235' },
{ code: 'CL', label: 'country.chile', phone: '+56' },
{ code: 'CN', label: 'country.china', phone: '+86' },
{ code: 'CX', label: 'country.christmas_island', phone: '+61' },
{ code: 'CC', label: 'country.cocos_keeling_islands', phone: '+61' },
{ code: 'CO', label: 'country.colombia', phone: '+57' },
{ code: 'KM', label: 'country.comoros', phone: '+269' },
{ code: 'CG', label: 'country.congo_brazzaville', phone: '+242' },
{ code: 'CD', label: 'country.congo_kinshasa', phone: '+243' },
{ code: 'CK', label: 'country.cook_islands', phone: '+682' },
{ code: 'CR', label: 'country.costa_rica', phone: '+506' },
{ code: 'CI', label: 'country.cote_divoire', phone: '+225' },
{ code: 'HR', label: 'country.croatia', phone: '+385' },
{ code: 'CU', label: 'country.cuba', phone: '+53' },
{ code: 'CW', label: 'country.curacao', phone: '+599' },
{ code: 'CY', label: 'country.cyprus', phone: '+357' },
{ code: 'CZ', label: 'country.czech_republic', phone: '+420' },
{ code: 'DK', label: 'country.denmark', phone: '+45' },
{ code: 'DJ', label: 'country.djibouti', phone: '+253' },
{ code: 'DM', label: 'country.dominica', phone: '+1767' },
{ code: 'DO', label: 'country.dominican_republic', phone: '+1' },
{ code: 'EC', label: 'country.ecuador', phone: '+593' },
{ code: 'EG', label: 'country.egypt', phone: '+20' },
{ code: 'SV', label: 'country.el_salvador', phone: '+503' },
{ code: 'GQ', label: 'country.equatorial_guinea', phone: '+240' },
{ code: 'ER', label: 'country.eritrea', phone: '+291' },
{ code: 'EE', label: 'country.estonia', phone: '+372' },
{ code: 'SZ', label: 'country.eswatini', phone: '+268' },
{ code: 'ET', label: 'country.ethiopia', phone: '+251' },
{ code: 'FK', label: 'country.falkland_islands', phone: '+500' },
{ code: 'FO', label: 'country.faroe_islands', phone: '+298' },
{ code: 'FJ', label: 'country.fiji', phone: '+679' },
{ code: 'FI', label: 'country.finland', phone: '+358' },
{ code: 'FR', label: 'country.france', phone: '+33' },
{ code: 'GF', label: 'country.french_guiana', phone: '+594' },
{ code: 'PF', label: 'country.french_polynesia', phone: '+689' },
{ code: 'GA', label: 'country.gabon', phone: '+241' },
{ code: 'GM', label: 'country.gambia', phone: '+220' },
{ code: 'GE', label: 'country.georgia', phone: '+995' },
{ code: 'DE', label: 'country.germany', phone: '+49' },
{ code: 'GH', label: 'country.ghana', phone: '+233' },
{ code: 'GI', label: 'country.gibraltar', phone: '+350' },
{ code: 'GR', label: 'country.greece', phone: '+30' },
{ code: 'GL', label: 'country.greenland', phone: '+299' },
{ code: 'GD', label: 'country.grenada', phone: '+1473' },
{ code: 'GP', label: 'country.guadeloupe', phone: '+590' },
{ code: 'GU', label: 'country.guam', phone: '+1671' },
{ code: 'GT', label: 'country.guatemala', phone: '+502' },
{ code: 'GG', label: 'country.guernsey', phone: '+44' },
{ code: 'GN', label: 'country.guinea', phone: '+224' },
{ code: 'GW', label: 'country.guinea_bissau', phone: '+245' },
{ code: 'GY', label: 'country.guyana', phone: '+592' },
{ code: 'HT', label: 'country.haiti', phone: '+509' },
{ code: 'HN', label: 'country.honduras', phone: '+504' },
{ code: 'HK', label: 'country.hong_kong', phone: '+852' },
{ code: 'HU', label: 'country.hungary', phone: '+36' },
{ code: 'IS', label: 'country.iceland', phone: '+354' },
{ code: 'IN', label: 'country.india', phone: '+91' },
{ code: 'ID', label: 'country.indonesia', phone: '+62' },
{ code: 'IR', label: 'country.iran', phone: '+98' },
{ code: 'IQ', label: 'country.iraq', phone: '+964' },
{ code: 'IE', label: 'country.ireland', phone: '+353' },
{ code: 'IM', label: 'country.isle_of_man', phone: '+44' },
{ code: 'IL', label: 'country.israel', phone: '+972' },
{ code: 'IT', label: 'country.italy', phone: '+39' },
{ code: 'JM', label: 'country.jamaica', phone: '+1876' },
{ code: 'JP', label: 'country.japan', phone: '+81' },
{ code: 'JE', label: 'country.jersey', phone: '+44' },
{ code: 'JO', label: 'country.jordan', phone: '+962' },
{ code: 'KZ', label: 'country.kazakhstan', phone: '+7' },
{ code: 'KE', label: 'country.kenya', phone: '+254' },
{ code: 'KI', label: 'country.kiribati', phone: '+686' },
{ code: 'XK', label: 'country.kosovo', phone: '+383' },
{ code: 'KW', label: 'country.kuwait', phone: '+965' },
{ code: 'KG', label: 'country.kyrgyzstan', phone: '+996' },
{ code: 'LA', label: 'country.laos', phone: '+856' },
{ code: 'LV', label: 'country.latvia', phone: '+371' },
{ code: 'LB', label: 'country.lebanon', phone: '+961' },
{ code: 'LS', label: 'country.lesotho', phone: '+266' },
{ code: 'LR', label: 'country.liberia', phone: '+231' },
{ code: 'LY', label: 'country.libya', phone: '+218' },
{ code: 'LI', label: 'country.liechtenstein', phone: '+423' },
{ code: 'LT', label: 'country.lithuania', phone: '+370' },
{ code: 'LU', label: 'country.luxembourg', phone: '+352' },
{ code: 'MO', label: 'country.macau', phone: '+853' },
{ code: 'MG', label: 'country.madagascar', phone: '+261' },
{ code: 'MW', label: 'country.malawi', phone: '+265' },
{ code: 'MY', label: 'country.malaysia', phone: '+60' },
{ code: 'MV', label: 'country.maldives', phone: '+960' },
{ code: 'ML', label: 'country.mali', phone: '+223' },
{ code: 'MT', label: 'country.malta', phone: '+356' },
{ code: 'MH', label: 'country.marshall_islands', phone: '+692' },
{ code: 'MQ', label: 'country.martinique', phone: '+596' },
{ code: 'MR', label: 'country.mauritania', phone: '+222' },
{ code: 'MU', label: 'country.mauritius', phone: '+230' },
{ code: 'YT', label: 'country.mayotte', phone: '+262' },
{ code: 'MX', label: 'country.mexico', phone: '+52' },
{ code: 'FM', label: 'country.micronesia', phone: '+691' },
{ code: 'MD', label: 'country.moldova', phone: '+373' },
{ code: 'MC', label: 'country.monaco', phone: '+377' },
{ code: 'MN', label: 'country.mongolia', phone: '+976' },
{ code: 'ME', label: 'country.montenegro', phone: '+382' },
{ code: 'MS', label: 'country.montserrat', phone: '+1664' },
{ code: 'MA', label: 'country.morocco', phone: '+212' },
{ code: 'MZ', label: 'country.mozambique', phone: '+258' },
{ code: 'MM', label: 'country.myanmar', phone: '+95' },
{ code: 'NA', label: 'country.namibia', phone: '+264' },
{ code: 'NR', label: 'country.nauru', phone: '+674' },
{ code: 'NP', label: 'country.nepal', phone: '+977' },
{ code: 'NL', label: 'country.netherlands', phone: '+31' },
{ code: 'NC', label: 'country.new_caledonia', phone: '+687' },
{ code: 'NZ', label: 'country.new_zealand', phone: '+64' },
{ code: 'NI', label: 'country.nicaragua', phone: '+505' },
{ code: 'NE', label: 'country.niger', phone: '+227' },
{ code: 'NG', label: 'country.nigeria', phone: '+234' },
{ code: 'NU', label: 'country.niue', phone: '+683' },
{ code: 'NF', label: 'country.norfolk_island', phone: '+672' },
{ code: 'KP', label: 'country.north_korea', phone: '+850' },
{ code: 'MK', label: 'country.north_macedonia', phone: '+389' },
{ code: 'MP', label: 'country.northern_mariana_islands', phone: '+1670' },
{ code: 'NO', label: 'country.norway', phone: '+47' },
{ code: 'OM', label: 'country.oman', phone: '+968' },
{ code: 'PK', label: 'country.pakistan', phone: '+92' },
{ code: 'PW', label: 'country.palau', phone: '+680' },
{ code: 'PS', label: 'country.palestine', phone: '+970' },
{ code: 'PA', label: 'country.panama', phone: '+507' },
{ code: 'PG', label: 'country.papua_new_guinea', phone: '+675' },
{ code: 'PY', label: 'country.paraguay', phone: '+595' },
{ code: 'PE', label: 'country.peru', phone: '+51' },
{ code: 'PH', label: 'country.philippines', phone: '+63' },
{ code: 'PN', label: 'country.pitcairn_islands', phone: '+64' },
{ code: 'PL', label: 'country.poland', phone: '+48' },
{ code: 'PT', label: 'country.portugal', phone: '+351' },
{ code: 'PR', label: 'country.puerto_rico', phone: '+1' },
{ code: 'QA', label: 'country.qatar', phone: '+974' },
{ code: 'RE', label: 'country.reunion', phone: '+262' },
{ code: 'RO', label: 'country.romania', phone: '+40' },
{ code: 'RU', label: 'country.russia', phone: '+7' },
{ code: 'RW', label: 'country.rwanda', phone: '+250' },
{ code: 'BL', label: 'country.saint_barthelemy', phone: '+590' },
{ code: 'SH', label: 'country.saint_helena', phone: '+290' },
{ code: 'KN', label: 'country.saint_kitts_and_nevis', phone: '+1869' },
{ code: 'LC', label: 'country.saint_lucia', phone: '+1758' },
{ code: 'MF', label: 'country.saint_martin', phone: '+590' },
{ code: 'PM', label: 'country.saint_pierre_and_miquelon', phone: '+508' },
{
code: 'VC',
label: 'country.saint_vincent_and_the_grenadines',
phone: '+1784',
},
{ code: 'WS', label: 'country.samoa', phone: '+685' },
{ code: 'SM', label: 'country.san_marino', phone: '+378' },
{ code: 'ST', label: 'country.sao_tome_and_principe', phone: '+239' },
{ code: 'SA', label: 'country.saudi_arabia', phone: '+966' },
{ code: 'SN', label: 'country.senegal', phone: '+221' },
{ code: 'RS', label: 'country.serbia', phone: '+381' },
{ code: 'SC', label: 'country.seychelles', phone: '+248' },
{ code: 'SL', label: 'country.sierra_leone', phone: '+232' },
{ code: 'SG', label: 'country.singapore', phone: '+65' },
{ code: 'SX', label: 'country.sint_maarten', phone: '+1721' },
{ code: 'SK', label: 'country.slovakia', phone: '+421' },
{ code: 'SI', label: 'country.slovenia', phone: '+386' },
{ code: 'SB', label: 'country.solomon_islands', phone: '+677' },
{ code: 'SO', label: 'country.somalia', phone: '+252' },
{ code: 'ZA', label: 'country.south_africa', phone: '+27' },
{
code: 'GS',
label: 'country.south_georgia_and_south_sandwich_islands',
phone: '+500',
},
{ code: 'KR', label: 'country.south_korea', phone: '+82' },
{ code: 'SS', label: 'country.south_sudan', phone: '+211' },
{ code: 'ES', label: 'country.spain', phone: '+34' },
{ code: 'LK', label: 'country.sri_lanka', phone: '+94' },
{ code: 'SD', label: 'country.sudan', phone: '+249' },
{ code: 'SR', label: 'country.suriname', phone: '+597' },
{ code: 'SJ', label: 'country.svalbard_and_jan_mayen', phone: '+47' },
{ code: 'SE', label: 'country.sweden', phone: '+46' },
{ code: 'CH', label: 'country.switzerland', phone: '+41' },
{ code: 'SY', label: 'country.syria', phone: '+963' },
{ code: 'TW', label: 'country.taiwan', phone: '+886' },
{ code: 'TJ', label: 'country.tajikistan', phone: '+992' },
{ code: 'TZ', label: 'country.tanzania', phone: '+255' },
{ code: 'TH', label: 'country.thailand', phone: '+66' },
{ code: 'TL', label: 'country.timor_leste', phone: '+670' },
{ code: 'TG', label: 'country.togo', phone: '+228' },
{ code: 'TK', label: 'country.tokelau', phone: '+690' },
{ code: 'TO', label: 'country.tonga', phone: '+676' },
{ code: 'TT', label: 'country.trinidad_and_tobago', phone: '+1868' },
{ code: 'TN', label: 'country.tunisia', phone: '+216' },
{ code: 'TR', label: 'country.turkey', phone: '+90' },
{ code: 'TM', label: 'country.turkmenistan', phone: '+993' },
{ code: 'TC', label: 'country.turks_and_caicos_islands', phone: '+1649' },
{ code: 'TV', label: 'country.tuvalu', phone: '+688' },
{ code: 'VI', label: 'country.us_virgin_islands', phone: '+1340' },
{ code: 'UG', label: 'country.uganda', phone: '+256' },
{ code: 'UA', label: 'country.ukraine', phone: '+380' },
{ code: 'AE', label: 'country.united_arab_emirates', phone: '+971' },
{ code: 'GB', label: 'country.united_kingdom', phone: '+44' },
{ code: 'US', label: 'country.united_states', phone: '+1' },
{ code: 'UY', label: 'country.uruguay', phone: '+598' },
{ code: 'UZ', label: 'country.uzbekistan', phone: '+998' },
{ code: 'VU', label: 'country.vanuatu', phone: '+678' },
{ code: 'VA', label: 'country.vatican_city', phone: '+39' },
{ code: 'VE', label: 'country.venezuela', phone: '+58' },
{ code: 'VN', label: 'country.vietnam', phone: '+84' },
{ code: 'WF', label: 'country.wallis_and_futuna', phone: '+681' },
{ code: 'EH', label: 'country.western_sahara', phone: '+212' },
{ code: 'YE', label: 'country.yemen', phone: '+967' },
{ code: 'ZM', label: 'country.zambia', phone: '+260' },
{ code: 'ZW', label: 'country.zimbabwe', phone: '+263' },
];

View File

@@ -1,33 +0,0 @@
// components/CountryList.ts
export const countries = [
{ name: 'Afghanistan', fa: 'افغانستان', flag: 'af' },
{ name: 'Albania', fa: 'آلبانی', flag: 'al' },
{ name: 'Algeria', fa: 'الجزایر', flag: 'dz' },
{ name: 'Argentina', fa: 'آرژانتین', flag: 'ar' },
{ name: 'Armenia', fa: 'ارمنستان', flag: 'am' },
{ name: 'Australia', fa: 'استرالیا', flag: 'au' },
{ name: 'Austria', fa: 'اتریش', flag: 'at' },
{ name: 'Bahrain', fa: 'بحرین', flag: 'bh' },
{ name: 'Canada', fa: 'کانادا', flag: 'ca' },
{ name: 'China', fa: 'چین', flag: 'cn' },
{ name: 'France', fa: 'فرانسه', flag: 'fr' },
{ name: 'Germany', fa: 'آلمان', flag: 'de' },
{ name: 'India', fa: 'هند', flag: 'in' },
{ name: 'Iran', fa: 'ایران', flag: 'ir' },
{ name: 'Iraq', fa: 'عراق', flag: 'iq' },
{ name: 'Italy', fa: 'ایتالیا', flag: 'it' },
{ name: 'Japan', fa: 'ژاپن', flag: 'jp' },
{ name: 'Netherlands', fa: 'هلند', flag: 'nl' },
{ name: 'Pakistan', fa: 'پاکستان', flag: 'pk' },
{ name: 'Qatar', fa: 'قطر', flag: 'qa' },
{ name: 'Russia', fa: 'روسیه', flag: 'ru' },
{ name: 'Saudi Arabia', fa: 'عربستان سعودی', flag: 'sa' },
{ name: 'Spain', fa: 'اسپانیا', flag: 'es' },
{ name: 'Sweden', fa: 'سوئد', flag: 'se' },
{ name: 'Switzerland', fa: 'سوئیس', flag: 'ch' },
{ name: 'Turkey', fa: 'ترکیه', flag: 'tr' },
{ name: 'United Arab Emirates', fa: 'امارات متحده عربی', flag: 'ae' },
{ name: 'United Kingdom', fa: 'بریتانیا', flag: 'gb' },
{ name: 'United States', fa: 'ایالات متحده آمریکا', flag: 'us' },
{ name: 'Yemen', fa: 'یمن', flag: 'ye' },
];