chore: all review comments
This commit is contained in:
1
.env
Normal file
1
.env
Normal file
@@ -0,0 +1 @@
|
|||||||
|
VITE_GOOGLE_CLIENT_ID=https://272098283932-bft2gvlgjn8edopg0lnqjq1i9ekdmipt.apps.googleusercontent.com/
|
||||||
@@ -34,12 +34,8 @@ export default tseslint.config(
|
|||||||
...tseslint.configs.recommended.rules,
|
...tseslint.configs.recommended.rules,
|
||||||
...reactHooks.configs.recommended.rules,
|
...reactHooks.configs.recommended.rules,
|
||||||
...prettierConfig.rules,
|
...prettierConfig.rules,
|
||||||
'prettier/prettier': [
|
'prettier/prettier': 'error',
|
||||||
'error',
|
'linebreak-style': ['error', 'unix'],
|
||||||
{
|
|
||||||
"endOfLine": "auto"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'react-refresh/only-export-components': 'warn',
|
'react-refresh/only-export-components': 'warn',
|
||||||
'@typescript-eslint/no-explicit-any': 'warn',
|
'@typescript-eslint/no-explicit-any': 'warn',
|
||||||
},
|
},
|
||||||
|
|||||||
39
package-lock.json
generated
39
package-lock.json
generated
@@ -15,14 +15,14 @@
|
|||||||
"i18next": "^25.3.0",
|
"i18next": "^25.3.0",
|
||||||
"i18next-browser-languagedetector": "^8.2.0",
|
"i18next-browser-languagedetector": "^8.2.0",
|
||||||
"i18next-http-backend": "^3.0.2",
|
"i18next-http-backend": "^3.0.2",
|
||||||
"iconsax-reactjs": "^0.0.8",
|
"iconsax-react": "^0.0.8",
|
||||||
"libphonenumber-js": "^1.12.10",
|
"libphonenumber-js": "^1.12.10",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-country-flag": "^3.1.0",
|
"react-country-flag": "^3.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-i18next": "^15.6.0",
|
"react-i18next": "^15.6.0",
|
||||||
"react-router": "^7.8.0",
|
"react-router": "^7.8.0",
|
||||||
"react-virtuoso": "^4.13.0",
|
"react-router-dom": "^7.8.0",
|
||||||
"stylis": "^4.3.6",
|
"stylis": "^4.3.6",
|
||||||
"stylis-plugin-rtl": "^2.1.1"
|
"stylis-plugin-rtl": "^2.1.1"
|
||||||
},
|
},
|
||||||
@@ -3124,11 +3124,14 @@
|
|||||||
"cross-fetch": "4.0.0"
|
"cross-fetch": "4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/iconsax-reactjs": {
|
"node_modules/iconsax-react": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/iconsax-reactjs/-/iconsax-reactjs-0.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/iconsax-react/-/iconsax-react-0.0.8.tgz",
|
||||||
"integrity": "sha512-cb+uTMxbkSFNbu8ZclX7BWQVfOWQt8+m/PsDjnsm/H+mcYrnfTYMjHxiof1FB43k7UAgt1ds+0oFeMVKdqyslw==",
|
"integrity": "sha512-l3dVk4zGtkkJHgvNYqAf0wDKqnKxXykee5/DoESGo2JvSYwaxajJUHSX2YrPRXSov8Hd8ClGFwJxCEaEjrFD1Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"prop-types": "^15.7.2"
|
||||||
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "*"
|
"react": "*"
|
||||||
}
|
}
|
||||||
@@ -3834,6 +3837,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-router-dom": {
|
||||||
|
"version": "7.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.8.0.tgz",
|
||||||
|
"integrity": "sha512-ntInsnDVnVRdtSu6ODmTQ41cbluak/ENeTif7GBce0L6eztFg6/e1hXAysFQI8X25C8ipKmT9cClbJwxx3Kaqw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"react-router": "7.8.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18",
|
||||||
|
"react-dom": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-transition-group": {
|
"node_modules/react-transition-group": {
|
||||||
"version": "4.4.5",
|
"version": "4.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
|
||||||
@@ -3850,16 +3869,6 @@
|
|||||||
"react-dom": ">=16.6.0"
|
"react-dom": ">=16.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-virtuoso": {
|
|
||||||
"version": "4.13.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-virtuoso/-/react-virtuoso-4.13.0.tgz",
|
|
||||||
"integrity": "sha512-XHv2Fglpx80yFPdjZkV9d1baACKghg/ucpDFEXwaix7z0AfVQj+mF6lM+YQR6UC/TwzXG2rJKydRMb3+7iV3PA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": ">=16 || >=17 || >= 18 || >= 19",
|
|
||||||
"react-dom": ">=16 || >=17 || >= 18 || >=19"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/resolve": {
|
"node_modules/resolve": {
|
||||||
"version": "1.22.10",
|
"version": "1.22.10",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
||||||
|
|||||||
@@ -18,14 +18,14 @@
|
|||||||
"i18next": "^25.3.0",
|
"i18next": "^25.3.0",
|
||||||
"i18next-browser-languagedetector": "^8.2.0",
|
"i18next-browser-languagedetector": "^8.2.0",
|
||||||
"i18next-http-backend": "^3.0.2",
|
"i18next-http-backend": "^3.0.2",
|
||||||
"iconsax-reactjs": "^0.0.8",
|
"iconsax-react": "^0.0.8",
|
||||||
"libphonenumber-js": "^1.12.10",
|
"libphonenumber-js": "^1.12.10",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-country-flag": "^3.1.0",
|
"react-country-flag": "^3.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-i18next": "^15.6.0",
|
"react-i18next": "^15.6.0",
|
||||||
"react-router": "^7.8.0",
|
"react-router": "^7.8.0",
|
||||||
"react-virtuoso": "^4.13.0",
|
"react-router-dom": "^7.8.0",
|
||||||
"stylis": "^4.3.6",
|
"stylis": "^4.3.6",
|
||||||
"stylis-plugin-rtl": "^2.1.1"
|
"stylis-plugin-rtl": "^2.1.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,247 +0,0 @@
|
|||||||
{
|
|
||||||
"country.afghanistan": "Afghanistan",
|
|
||||||
"country.aland_islands": "Aland islands",
|
|
||||||
"country.albania": "Albania",
|
|
||||||
"country.algeria": "Algeria",
|
|
||||||
"country.american_samoa": "American samoa",
|
|
||||||
"country.andorra": "Andorra",
|
|
||||||
"country.angola": "Angola",
|
|
||||||
"country.anguilla": "Anguilla",
|
|
||||||
"country.antarctica": "Antarctica",
|
|
||||||
"country.antigua_and_barbuda": "Antigua and barbuda",
|
|
||||||
"country.argentina": "Argentina",
|
|
||||||
"country.armenia": "Armenia",
|
|
||||||
"country.aruba": "Aruba",
|
|
||||||
"country.australia": "Australia",
|
|
||||||
"country.austria": "Austria",
|
|
||||||
"country.azerbaijan": "Azerbaijan",
|
|
||||||
"country.bahamas": "Bahamas",
|
|
||||||
"country.bahrain": "Bahrain",
|
|
||||||
"country.bangladesh": "Bangladesh",
|
|
||||||
"country.barbados": "Barbados",
|
|
||||||
"country.belarus": "Belarus",
|
|
||||||
"country.belgium": "Belgium",
|
|
||||||
"country.belize": "Belize",
|
|
||||||
"country.benin": "Benin",
|
|
||||||
"country.bermuda": "Bermuda",
|
|
||||||
"country.bhutan": "Bhutan",
|
|
||||||
"country.bolivia": "Bolivia",
|
|
||||||
"country.bosnia_and_herzegovina": "Bosnia and herzegovina",
|
|
||||||
"country.botswana": "Botswana",
|
|
||||||
"country.brazil": "Brazil",
|
|
||||||
"country.british_indian_ocean_territory": "British indian ocean territory",
|
|
||||||
"country.british_virgin_islands": "British virgin islands",
|
|
||||||
"country.brunei": "Brunei",
|
|
||||||
"country.bulgaria": "Bulgaria",
|
|
||||||
"country.burkina_faso": "Burkina faso",
|
|
||||||
"country.burundi": "Burundi",
|
|
||||||
"country.cambodia": "Cambodia",
|
|
||||||
"country.cameroon": "Cameroon",
|
|
||||||
"country.canada": "Canada",
|
|
||||||
"country.cape_verde": "Cape verde",
|
|
||||||
"country.cayman_islands": "Cayman islands",
|
|
||||||
"country.central_african_republic": "Central african republic",
|
|
||||||
"country.chad": "Chad",
|
|
||||||
"country.chile": "Chile",
|
|
||||||
"country.china": "China",
|
|
||||||
"country.christmas_island": "Christmas island",
|
|
||||||
"country.cocos_keeling_islands": "Cocos keeling islands",
|
|
||||||
"country.colombia": "Colombia",
|
|
||||||
"country.comoros": "Comoros",
|
|
||||||
"country.congo_brazzaville": "Congo brazzaville",
|
|
||||||
"country.congo_kinshasa": "Congo kinshasa",
|
|
||||||
"country.cook_islands": "Cook islands",
|
|
||||||
"country.costa_rica": "Costa rica",
|
|
||||||
"country.cote_divoire": "Cote divoire",
|
|
||||||
"country.croatia": "Croatia",
|
|
||||||
"country.cuba": "Cuba",
|
|
||||||
"country.curacao": "Curacao",
|
|
||||||
"country.cyprus": "Cyprus",
|
|
||||||
"country.czech_republic": "Czech republic",
|
|
||||||
"country.denmark": "Denmark",
|
|
||||||
"country.djibouti": "Djibouti",
|
|
||||||
"country.dominica": "Dominica",
|
|
||||||
"country.dominican_republic": "Dominican republic",
|
|
||||||
"country.ecuador": "Ecuador",
|
|
||||||
"country.egypt": "Egypt",
|
|
||||||
"country.el_salvador": "El salvador",
|
|
||||||
"country.equatorial_guinea": "Equatorial guinea",
|
|
||||||
"country.eritrea": "Eritrea",
|
|
||||||
"country.estonia": "Estonia",
|
|
||||||
"country.eswatini": "Eswatini",
|
|
||||||
"country.ethiopia": "Ethiopia",
|
|
||||||
"country.falkland_islands": "Falkland islands",
|
|
||||||
"country.faroe_islands": "Faroe islands",
|
|
||||||
"country.fiji": "Fiji",
|
|
||||||
"country.finland": "Finland",
|
|
||||||
"country.france": "France",
|
|
||||||
"country.french_guiana": "French guiana",
|
|
||||||
"country.french_polynesia": "French polynesia",
|
|
||||||
"country.gabon": "Gabon",
|
|
||||||
"country.gambia": "Gambia",
|
|
||||||
"country.georgia": "Georgia",
|
|
||||||
"country.germany": "Germany",
|
|
||||||
"country.ghana": "Ghana",
|
|
||||||
"country.gibraltar": "Gibraltar",
|
|
||||||
"country.greece": "Greece",
|
|
||||||
"country.greenland": "Greenland",
|
|
||||||
"country.grenada": "Grenada",
|
|
||||||
"country.guadeloupe": "Guadeloupe",
|
|
||||||
"country.guam": "Guam",
|
|
||||||
"country.guatemala": "Guatemala",
|
|
||||||
"country.guernsey": "Guernsey",
|
|
||||||
"country.guinea": "Guinea",
|
|
||||||
"country.guinea_bissau": "Guinea bissau",
|
|
||||||
"country.guyana": "Guyana",
|
|
||||||
"country.haiti": "Haiti",
|
|
||||||
"country.honduras": "Honduras",
|
|
||||||
"country.hong_kong": "Hong kong",
|
|
||||||
"country.hungary": "Hungary",
|
|
||||||
"country.iceland": "Iceland",
|
|
||||||
"country.india": "India",
|
|
||||||
"country.indonesia": "Indonesia",
|
|
||||||
"country.iran": "Iran",
|
|
||||||
"country.iraq": "Iraq",
|
|
||||||
"country.ireland": "Ireland",
|
|
||||||
"country.isle_of_man": "Isle of man",
|
|
||||||
"country.israel": "Israel",
|
|
||||||
"country.italy": "Italy",
|
|
||||||
"country.jamaica": "Jamaica",
|
|
||||||
"country.japan": "Japan",
|
|
||||||
"country.jersey": "Jersey",
|
|
||||||
"country.jordan": "Jordan",
|
|
||||||
"country.kazakhstan": "Kazakhstan",
|
|
||||||
"country.kenya": "Kenya",
|
|
||||||
"country.kiribati": "Kiribati",
|
|
||||||
"country.kosovo": "Kosovo",
|
|
||||||
"country.kuwait": "Kuwait",
|
|
||||||
"country.kyrgyzstan": "Kyrgyzstan",
|
|
||||||
"country.laos": "Laos",
|
|
||||||
"country.latvia": "Latvia",
|
|
||||||
"country.lebanon": "Lebanon",
|
|
||||||
"country.lesotho": "Lesotho",
|
|
||||||
"country.liberia": "Liberia",
|
|
||||||
"country.libya": "Libya",
|
|
||||||
"country.liechtenstein": "Liechtenstein",
|
|
||||||
"country.lithuania": "Lithuania",
|
|
||||||
"country.luxembourg": "Luxembourg",
|
|
||||||
"country.macau": "Macau",
|
|
||||||
"country.madagascar": "Madagascar",
|
|
||||||
"country.malawi": "Malawi",
|
|
||||||
"country.malaysia": "Malaysia",
|
|
||||||
"country.maldives": "Maldives",
|
|
||||||
"country.mali": "Mali",
|
|
||||||
"country.malta": "Malta",
|
|
||||||
"country.marshall_islands": "Marshall islands",
|
|
||||||
"country.martinique": "Martinique",
|
|
||||||
"country.mauritania": "Mauritania",
|
|
||||||
"country.mauritius": "Mauritius",
|
|
||||||
"country.mayotte": "Mayotte",
|
|
||||||
"country.mexico": "Mexico",
|
|
||||||
"country.micronesia": "Micronesia",
|
|
||||||
"country.moldova": "Moldova",
|
|
||||||
"country.monaco": "Monaco",
|
|
||||||
"country.mongolia": "Mongolia",
|
|
||||||
"country.montenegro": "Montenegro",
|
|
||||||
"country.montserrat": "Montserrat",
|
|
||||||
"country.morocco": "Morocco",
|
|
||||||
"country.mozambique": "Mozambique",
|
|
||||||
"country.myanmar": "Myanmar",
|
|
||||||
"country.namibia": "Namibia",
|
|
||||||
"country.nauru": "Nauru",
|
|
||||||
"country.nepal": "Nepal",
|
|
||||||
"country.netherlands": "Netherlands",
|
|
||||||
"country.new_caledonia": "New caledonia",
|
|
||||||
"country.new_zealand": "New zealand",
|
|
||||||
"country.nicaragua": "Nicaragua",
|
|
||||||
"country.niger": "Niger",
|
|
||||||
"country.nigeria": "Nigeria",
|
|
||||||
"country.niue": "Niue",
|
|
||||||
"country.norfolk_island": "Norfolk island",
|
|
||||||
"country.north_korea": "North korea",
|
|
||||||
"country.north_macedonia": "North macedonia",
|
|
||||||
"country.northern_mariana_islands": "Northern mariana islands",
|
|
||||||
"country.norway": "Norway",
|
|
||||||
"country.oman": "Oman",
|
|
||||||
"country.pakistan": "Pakistan",
|
|
||||||
"country.palau": "Palau",
|
|
||||||
"country.palestine": "Palestine",
|
|
||||||
"country.panama": "Panama",
|
|
||||||
"country.papua_new_guinea": "Papua new guinea",
|
|
||||||
"country.paraguay": "Paraguay",
|
|
||||||
"country.peru": "Peru",
|
|
||||||
"country.philippines": "Philippines",
|
|
||||||
"country.pitcairn_islands": "Pitcairn islands",
|
|
||||||
"country.poland": "Poland",
|
|
||||||
"country.portugal": "Portugal",
|
|
||||||
"country.puerto_rico": "Puerto rico",
|
|
||||||
"country.qatar": "Qatar",
|
|
||||||
"country.reunion": "Reunion",
|
|
||||||
"country.romania": "Romania",
|
|
||||||
"country.russia": "Russia",
|
|
||||||
"country.rwanda": "Rwanda",
|
|
||||||
"country.saint_barthelemy": "Saint barthelemy",
|
|
||||||
"country.saint_helena": "Saint helena",
|
|
||||||
"country.saint_kitts_and_nevis": "Saint kitts and nevis",
|
|
||||||
"country.saint_lucia": "Saint lucia",
|
|
||||||
"country.saint_martin": "Saint martin",
|
|
||||||
"country.saint_pierre_and_miquelon": "Saint pierre and miquelon",
|
|
||||||
"country.saint_vincent_and_the_grenadines": "Saint vincent and the grenadines",
|
|
||||||
"country.samoa": "Samoa",
|
|
||||||
"country.san_marino": "San marino",
|
|
||||||
"country.sao_tome_and_principe": "Sao tome and principe",
|
|
||||||
"country.saudi_arabia": "Saudi arabia",
|
|
||||||
"country.senegal": "Senegal",
|
|
||||||
"country.serbia": "Serbia",
|
|
||||||
"country.seychelles": "Seychelles",
|
|
||||||
"country.sierra_leone": "Sierra leone",
|
|
||||||
"country.singapore": "Singapore",
|
|
||||||
"country.sint_maarten": "Sint maarten",
|
|
||||||
"country.slovakia": "Slovakia",
|
|
||||||
"country.slovenia": "Slovenia",
|
|
||||||
"country.solomon_islands": "Solomon islands",
|
|
||||||
"country.somalia": "Somalia",
|
|
||||||
"country.south_africa": "South africa",
|
|
||||||
"country.south_georgia_and_south_sandwich_islands": "South georgia and south sandwich islands",
|
|
||||||
"country.south_korea": "South korea",
|
|
||||||
"country.south_sudan": "South sudan",
|
|
||||||
"country.spain": "Spain",
|
|
||||||
"country.sri_lanka": "Sri lanka",
|
|
||||||
"country.sudan": "Sudan",
|
|
||||||
"country.suriname": "Suriname",
|
|
||||||
"country.svalbard_and_jan_mayen": "Svalbard and jan mayen",
|
|
||||||
"country.sweden": "Sweden",
|
|
||||||
"country.switzerland": "Switzerland",
|
|
||||||
"country.syria": "Syria",
|
|
||||||
"country.taiwan": "Taiwan",
|
|
||||||
"country.tajikistan": "Tajikistan",
|
|
||||||
"country.tanzania": "Tanzania",
|
|
||||||
"country.thailand": "Thailand",
|
|
||||||
"country.timor_leste": "Timor leste",
|
|
||||||
"country.togo": "Togo",
|
|
||||||
"country.tokelau": "Tokelau",
|
|
||||||
"country.tonga": "Tonga",
|
|
||||||
"country.trinidad_and_tobago": "Trinidad and tobago",
|
|
||||||
"country.tunisia": "Tunisia",
|
|
||||||
"country.turkey": "Turkey",
|
|
||||||
"country.turkmenistan": "Turkmenistan",
|
|
||||||
"country.turks_and_caicos_islands": "Turks and caicos islands",
|
|
||||||
"country.tuvalu": "Tuvalu",
|
|
||||||
"country.us_virgin_islands": "Us virgin islands",
|
|
||||||
"country.uganda": "Uganda",
|
|
||||||
"country.ukraine": "Ukraine",
|
|
||||||
"country.united_arab_emirates": "United arab emirates",
|
|
||||||
"country.united_kingdom": "United kingdom",
|
|
||||||
"country.united_states": "United states",
|
|
||||||
"country.uruguay": "Uruguay",
|
|
||||||
"country.uzbekistan": "Uzbekistan",
|
|
||||||
"country.vanuatu": "Vanuatu",
|
|
||||||
"country.vatican_city": "Vatican city",
|
|
||||||
"country.venezuela": "Venezuela",
|
|
||||||
"country.vietnam": "Vietnam",
|
|
||||||
"country.wallis_and_futuna": "Wallis and futuna",
|
|
||||||
"country.western_sahara": "Western sahara",
|
|
||||||
"country.yemen": "Yemen",
|
|
||||||
"country.zambia": "Zambia",
|
|
||||||
"country.zimbabwe": "Zimbabwe"
|
|
||||||
}
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
{
|
|
||||||
"country.afghanistan": "افغانستان",
|
|
||||||
"country.aland_islands": "جزایر آلند",
|
|
||||||
"country.albania": "آلبانی",
|
|
||||||
"country.algeria": "الجزایر",
|
|
||||||
"country.american_samoa": "ساموای آمریکایی",
|
|
||||||
"country.andorra": "آندورا",
|
|
||||||
"country.angola": "آنگولا",
|
|
||||||
"country.anguilla": "آنگویلا",
|
|
||||||
"country.antarctica": "جنوبگان",
|
|
||||||
"country.antigua_and_barbuda": "آنتیگوا و باربودا",
|
|
||||||
"country.argentina": "آرژانتین",
|
|
||||||
"country.armenia": "ارمنستان",
|
|
||||||
"country.aruba": "آروبا",
|
|
||||||
"country.australia": "استرالیا",
|
|
||||||
"country.austria": "اتریش",
|
|
||||||
"country.azerbaijan": "آذربایجان",
|
|
||||||
"country.bahamas": "باهاما",
|
|
||||||
"country.bahrain": "بحرین",
|
|
||||||
"country.bangladesh": "بنگلادش",
|
|
||||||
"country.barbados": "باربادوس",
|
|
||||||
"country.belarus": "بلاروس",
|
|
||||||
"country.belgium": "بلژیک",
|
|
||||||
"country.belize": "بلیز",
|
|
||||||
"country.benin": "بنین",
|
|
||||||
"country.bermuda": "برمودا",
|
|
||||||
"country.bhutan": "بوتان",
|
|
||||||
"country.bolivia": "بولیوی",
|
|
||||||
"country.bosnia_and_herzegovina": "بوسنی و هرزگوین",
|
|
||||||
"country.botswana": "بوتسوانا",
|
|
||||||
"country.brazil": "برزیل",
|
|
||||||
"country.british_virgin_islands": "جزایر ویرجین بریتانیا",
|
|
||||||
"country.brunei": "برونئی",
|
|
||||||
"country.bulgaria": "بلغارستان",
|
|
||||||
"country.burkina_faso": "بورکینافاسو",
|
|
||||||
"country.burundi": "بوروندی",
|
|
||||||
"country.cambodia": "کامبوج",
|
|
||||||
"country.cameroon": "کامرون",
|
|
||||||
"country.canada": "کانادا",
|
|
||||||
"country.cape_verde": "کیپ ورد",
|
|
||||||
"country.cayman_islands": "جزایر کیمن",
|
|
||||||
"country.central_african_republic": "جمهوری آفریقای مرکزی",
|
|
||||||
"country.chad": "چاد",
|
|
||||||
"country.chile": "شیلی",
|
|
||||||
"country.china": "چین",
|
|
||||||
"country.colombia": "کلمبیا",
|
|
||||||
"country.comoros": "کومور",
|
|
||||||
"country.costa_rica": "کاستاریکا",
|
|
||||||
"country.cote_divoire": "ساحل عاج",
|
|
||||||
"country.croatia": "کرواسی",
|
|
||||||
"country.cuba": "کوبا",
|
|
||||||
"country.cyprus": "قبرس",
|
|
||||||
"country.czech_republic": "جمهوری چک",
|
|
||||||
"country.denmark": "دانمارک",
|
|
||||||
"country.djibouti": "جیبوتی",
|
|
||||||
"country.dominica": "دومینیکا",
|
|
||||||
"country.dominican_republic": "جمهوری دومینیکن",
|
|
||||||
"country.ecuador": "اکوادور",
|
|
||||||
"country.egypt": "مصر",
|
|
||||||
"country.el_salvador": "السالوادور",
|
|
||||||
"country.equatorial_guinea": "گینه استوایی",
|
|
||||||
"country.eritrea": "اریتره",
|
|
||||||
"country.estonia": "استونی",
|
|
||||||
"country.eswatini": "سوازیلند",
|
|
||||||
"country.ethiopia": "اتیوپی",
|
|
||||||
"country.fiji": "فیجی",
|
|
||||||
"country.finland": "فنلاند",
|
|
||||||
"country.france": "فرانسه",
|
|
||||||
"country.gabon": "گابن",
|
|
||||||
"country.gambia": "گامبیا",
|
|
||||||
"country.georgia": "گرجستان",
|
|
||||||
"country.germany": "آلمان",
|
|
||||||
"country.ghana": "غنا",
|
|
||||||
"country.greece": "یونان",
|
|
||||||
"country.guatemala": "گواتمالا",
|
|
||||||
"country.guinea": "گینه",
|
|
||||||
"country.guinea_bissau": "گینه بیسائو",
|
|
||||||
"country.guyana": "گویان",
|
|
||||||
"country.haiti": "هائیتی",
|
|
||||||
"country.honduras": "هندوراس",
|
|
||||||
"country.hungary": "مجارستان",
|
|
||||||
"country.iceland": "ایسلند",
|
|
||||||
"country.india": "هندوستان",
|
|
||||||
"country.indonesia": "اندونزی",
|
|
||||||
"country.iran": "ایران",
|
|
||||||
"country.iraq": "عراق",
|
|
||||||
"country.ireland": "ایرلند",
|
|
||||||
"country.israel": "اسرائیل",
|
|
||||||
"country.italy": "ایتالیا",
|
|
||||||
"country.jamaica": "جامائیکا",
|
|
||||||
"country.japan": "ژاپن",
|
|
||||||
"country.jordan": "اردن",
|
|
||||||
"country.kazakhstan": "قزاقستان",
|
|
||||||
"country.kenya": "کنیا",
|
|
||||||
"country.kuwait": "کویت",
|
|
||||||
"country.kyrgyzstan": "قرقیزستان",
|
|
||||||
"country.laos": "لائوس",
|
|
||||||
"country.latvia": "لتونی",
|
|
||||||
"country.lebanon": "لبنان",
|
|
||||||
"country.lesotho": "لسوتو",
|
|
||||||
"country.liberia": "لیبریا",
|
|
||||||
"country.libya": "لیبی",
|
|
||||||
"country.luxembourg": "لوکزامبورگ",
|
|
||||||
"country.malaysia": "مالزی",
|
|
||||||
"country.maldives": "مالدیو",
|
|
||||||
"country.mali": "مالی",
|
|
||||||
"country.malta": "مالت",
|
|
||||||
"country.mauritania": "موریتانی",
|
|
||||||
"country.mauritius": "موریس",
|
|
||||||
"country.mexico": "مکزیک",
|
|
||||||
"country.moldova": "مولداوی",
|
|
||||||
"country.monaco": "موناکو",
|
|
||||||
"country.mongolia": "مغولستان",
|
|
||||||
"country.morocco": "مراکش",
|
|
||||||
"country.mozambique": "موزامبیک",
|
|
||||||
"country.myanmar": "میانمار",
|
|
||||||
"country.namibia": "نامیبیا",
|
|
||||||
"country.nepal": "نپال",
|
|
||||||
"country.netherlands": "هلند",
|
|
||||||
"country.new_zealand": "نیوزیلند",
|
|
||||||
"country.nicaragua": "نیکاراگوئه",
|
|
||||||
"country.niger": "نیجر",
|
|
||||||
"country.nigeria": "نیجریه",
|
|
||||||
"country.north_korea": "کره شمالی",
|
|
||||||
"country.north_macedonia": "مقدونیه",
|
|
||||||
"country.norway": "نروژ",
|
|
||||||
"country.oman": "عمان",
|
|
||||||
"country.pakistan": "پاکستان",
|
|
||||||
"country.palau": "پالائو",
|
|
||||||
"country.panama": "پاناما",
|
|
||||||
"country.papua_new_guinea": "پاپوآ گینه نو",
|
|
||||||
"country.paraguay": "پاراگوئه",
|
|
||||||
"country.peru": "پرو",
|
|
||||||
"country.philippines": "فیلیپین",
|
|
||||||
"country.poland": "لهستان",
|
|
||||||
"country.portugal": "پرتغال",
|
|
||||||
"country.qatar": "قطر",
|
|
||||||
"country.romania": "رومانی",
|
|
||||||
"country.russia": "روسیه",
|
|
||||||
"country.rwanda": "رواندا",
|
|
||||||
"country.saudi_arabia": "عربستان سعودی",
|
|
||||||
"country.senegal": "سنگال",
|
|
||||||
"country.serbia": "صربستان",
|
|
||||||
"country.seychelles": "سیشل",
|
|
||||||
"country.sierra_leone": "سیرالئون",
|
|
||||||
"country.singapore": "سنگاپور",
|
|
||||||
"country.south_africa": "آفریقای جنوبی",
|
|
||||||
"country.south_korea": "کره جنوبی",
|
|
||||||
"country.south_sudan": "سودان جنوبی",
|
|
||||||
"country.spain": "اسپانیا",
|
|
||||||
"country.sri_lanka": "سریلانکا",
|
|
||||||
"country.sudan": "سودان",
|
|
||||||
"country.suriname": "سورینام",
|
|
||||||
"country.sweden": "سوئد",
|
|
||||||
"country.switzerland": "سوئیس",
|
|
||||||
"country.syria": "سوریه",
|
|
||||||
"country.taiwan": "تایوان",
|
|
||||||
"country.tajikistan": "تاجیکستان",
|
|
||||||
"country.tanzania": "تانزانیا",
|
|
||||||
"country.thailand": "تایلند",
|
|
||||||
"country.timor_leste": "تیمور شرقی",
|
|
||||||
"country.togo": "توگو",
|
|
||||||
"country.tonga": "تونگا",
|
|
||||||
"country.trinidad_and_tobago": "ترینیداد و توباگو",
|
|
||||||
"country.tunisia": "تونس",
|
|
||||||
"country.turkey": "ترکیه",
|
|
||||||
"country.turkmenistan": "ترکمنستان",
|
|
||||||
"country.tuvalu": "تووالو",
|
|
||||||
"country.uganda": "اوگاندا",
|
|
||||||
"country.ukraine": "اوکراین",
|
|
||||||
"country.united_arab_emirates": "امارات متحده عربی",
|
|
||||||
"country.united_kingdom": "انگلستان",
|
|
||||||
"country.united_states": "ایالات متحده آمریکا",
|
|
||||||
"country.uruguay": "اروگوئه",
|
|
||||||
"country.uzbekistan": "ازبکستان",
|
|
||||||
"country.vanuatu": "وانواتو",
|
|
||||||
"country.venezuela": "ونزوئلا",
|
|
||||||
"country.vietnam": "ویتنام",
|
|
||||||
"country.yemen": "یمن",
|
|
||||||
"country.zambia": "زامبیا",
|
|
||||||
"country.zimbabwe": "زیمبابوه"
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,7 @@ import { CssBaseline } from '@mui/material';
|
|||||||
import './App.css';
|
import './App.css';
|
||||||
import { LanguageManager } from './components/LanguageManager';
|
import { LanguageManager } from './components/LanguageManager';
|
||||||
import { AuthenticationPage } from './features/authorization/routes/AuthenticationPage';
|
import { AuthenticationPage } from './features/authorization/routes/AuthenticationPage';
|
||||||
import { BrowserRouter, Navigate, Route, Routes } from 'react-router';
|
import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
|
||||||
import { ForgetPasswordPage } from './features/authorization/routes/ForgetPasswordPage';
|
import { ForgetPasswordPage } from './features/authorization/routes/ForgetPasswordPage';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { TextField, Stack } from '@mui/material';
|
|||||||
interface DigitInputProps {
|
interface DigitInputProps {
|
||||||
error: boolean;
|
error: boolean;
|
||||||
success: boolean;
|
success: boolean;
|
||||||
onChange: Dispatch<SetStateAction<string[]>>;
|
onChange: Dispatch<SetStateAction<string>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DigitInput: React.FC<DigitInputProps> = ({
|
const DigitInput: React.FC<DigitInputProps> = ({
|
||||||
@@ -26,13 +26,18 @@ const DigitInput: React.FC<DigitInputProps> = ({
|
|||||||
inputRefs.current[0]?.focus();
|
inputRefs.current[0]?.focus();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleDigitInputValueChange = (value: string[]) => {
|
||||||
|
const formatted = value.filter((char) => char !== '').join('');
|
||||||
|
onChange(formatted);
|
||||||
|
};
|
||||||
|
|
||||||
const handleChange = (value: string, index: number) => {
|
const handleChange = (value: string, index: number) => {
|
||||||
if (!/^\d$/.test(value) && value !== '') return;
|
if (!/^\d$/.test(value) && value !== '') return;
|
||||||
|
|
||||||
const newCode = [...code];
|
const newCode = [...code];
|
||||||
newCode[index] = value;
|
newCode[index] = value;
|
||||||
setCode(newCode);
|
setCode(newCode);
|
||||||
onChange(newCode);
|
handleDigitInputValueChange(newCode);
|
||||||
|
|
||||||
if (value && index < 4 - 1) {
|
if (value && index < 4 - 1) {
|
||||||
inputRefs.current[index + 1]?.focus();
|
inputRefs.current[index + 1]?.focus();
|
||||||
@@ -62,7 +67,7 @@ const DigitInput: React.FC<DigitInputProps> = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
setCode(newCode);
|
setCode(newCode);
|
||||||
onChange(newCode);
|
handleDigitInputValueChange(newCode);
|
||||||
|
|
||||||
// Focus the next empty input after the last pasted character
|
// Focus the next empty input after the last pasted character
|
||||||
const lastIndex = Math.min(pastedData.length, code.length) - 1;
|
const lastIndex = Math.min(pastedData.length, code.length) - 1;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState, type JSX } from 'react';
|
import { useState, type JSX } from 'react';
|
||||||
import { LoginRegisterForm } from './LoginRegiserForm';
|
import { LoginRegisterForm } from './LoginRegiserForm';
|
||||||
import type { AuthMode, AuthType } from '../../types/authTypes';
|
import type { AuthMode, AuthStep, AuthType } from '../../types/authTypes';
|
||||||
import { OtpVerifyForm } from './OtpVerifyForm';
|
import { OtpVerifyForm } from './OtpVerifyForm';
|
||||||
import { isNumeric } from '@/utils/regexes/isNumeric';
|
import { isNumeric } from '@/utils/regexes/isNumeric';
|
||||||
import { CompleteSignUp } from './CompleteSignUp';
|
import { CompleteSignUp } from './CompleteSignUp';
|
||||||
@@ -8,22 +8,17 @@ import { EnterPasswordForm } from './EnterPasswordForm';
|
|||||||
import { UserStatus } from '../../types/userTypes';
|
import { UserStatus } from '../../types/userTypes';
|
||||||
import type { CountryCode, GUID } from '@/types/commonTypes';
|
import type { CountryCode, GUID } from '@/types/commonTypes';
|
||||||
import { VerifyPhoneNumber } from './VerifyPhoneNumber';
|
import { VerifyPhoneNumber } from './VerifyPhoneNumber';
|
||||||
import { useSearchParams } from 'react-router';
|
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
export const AuthenticationSteps = (): JSX.Element => {
|
export const AuthenticationSteps = (): JSX.Element => {
|
||||||
const DEFAULT_RETURN_URL = 'https://account.business-harmony.com/';
|
const navigate = useNavigate();
|
||||||
|
const DEFAULT_RETURN_URL = '/profile';
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const authReturnUrl: string =
|
const authReturnUrl: string =
|
||||||
searchParams.get('returnUrl') ?? DEFAULT_RETURN_URL;
|
searchParams.get('returnUrl') ?? DEFAULT_RETURN_URL;
|
||||||
const [authMode, setAuthMode] = useState<AuthMode>('register');
|
const [authMode, setAuthMode] = useState<AuthMode>('register');
|
||||||
const [authType, setAuthType] = useState<AuthType>('phone');
|
const [authType, setAuthType] = useState<AuthType>('phone');
|
||||||
const [currentStep, setCurrentStep] = useState<
|
const [currentStep, setCurrentStep] = useState<AuthStep>('emailOrPhone');
|
||||||
| 'emailOrPhone'
|
|
||||||
| 'verify'
|
|
||||||
| 'enterPassword'
|
|
||||||
| 'addPhoneNumber'
|
|
||||||
| 'addedPhoneNumberVerify'
|
|
||||||
>('emailOrPhone');
|
|
||||||
const [loginRegisterValue, setLoginRegisterValue] = useState<string>('');
|
const [loginRegisterValue, setLoginRegisterValue] = useState<string>('');
|
||||||
const [countryCode, setCountryCode] = useState<CountryCode>('+98');
|
const [countryCode, setCountryCode] = useState<CountryCode>('+98');
|
||||||
const [addPhoneCountryCode, setAddPhoneCountryCode] =
|
const [addPhoneCountryCode, setAddPhoneCountryCode] =
|
||||||
@@ -54,24 +49,28 @@ export const AuthenticationSteps = (): JSX.Element => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOTPVerfied = (userId: GUID) => {
|
|
||||||
handleUserLoggedIn(userId);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUserLoggedIn = (userId: GUID) => {
|
const handleUserLoggedIn = (userId: GUID) => {
|
||||||
localStorage.setItem('userID', userId);
|
localStorage.setItem('userID', userId);
|
||||||
|
|
||||||
location.href = authReturnUrl;
|
redirectToReturnUrl();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleConfrimPhoneNumber = (userId: GUID) => {
|
const handleConfrimPhoneNumber = (userId: GUID) => {
|
||||||
handleUserLoggedIn(userId);
|
localStorage.setItem('userID', userId);
|
||||||
|
|
||||||
setCurrentStep('addPhoneNumber');
|
setCurrentStep('addPhoneNumber');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePhoneNumberVerified = () => {
|
const handlePhoneNumberVerified = () => {
|
||||||
location.href = authReturnUrl;
|
redirectToReturnUrl();
|
||||||
|
};
|
||||||
|
|
||||||
|
const redirectToReturnUrl = () => {
|
||||||
|
if (authReturnUrl === DEFAULT_RETURN_URL) {
|
||||||
|
navigate(DEFAULT_RETURN_URL);
|
||||||
|
} else {
|
||||||
|
location.href = authReturnUrl;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -95,7 +94,7 @@ export const AuthenticationSteps = (): JSX.Element => {
|
|||||||
onVerifyPhoneNumber={handleConfrimPhoneNumber}
|
onVerifyPhoneNumber={handleConfrimPhoneNumber}
|
||||||
authReturnUrl={authReturnUrl}
|
authReturnUrl={authReturnUrl}
|
||||||
countryCode={countryCode}
|
countryCode={countryCode}
|
||||||
onOTPVerified={handleOTPVerfied}
|
onOTPVerified={handleUserLoggedIn}
|
||||||
onEditValue={() => setCurrentStep('emailOrPhone')}
|
onEditValue={() => setCurrentStep('emailOrPhone')}
|
||||||
authMode={authMode}
|
authMode={authMode}
|
||||||
authType={authType}
|
authType={authType}
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ export const CompleteSignUp = ({
|
|||||||
const handleBlur = () => {
|
const handleBlur = () => {
|
||||||
setTouched(true);
|
setTouched(true);
|
||||||
|
|
||||||
|
handleValueError();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleValueError = () => {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
setError(t('loginForm.thisFieldIsRequired'));
|
setError(t('loginForm.thisFieldIsRequired'));
|
||||||
}
|
}
|
||||||
@@ -52,15 +56,11 @@ export const CompleteSignUp = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleCompleteSignUp = async () => {
|
const handleCompleteSignUp = async () => {
|
||||||
if (!value) {
|
handleValueError();
|
||||||
setError(t('loginForm.thisFieldIsRequired'));
|
|
||||||
inputRef.current?.focus();
|
if (!value || !isPhoneValid(countryCode, value)) {
|
||||||
}
|
|
||||||
if (!isPhoneValid(countryCode, value)) {
|
|
||||||
setError(t('loginForm.phoneNumberIsInvalid'));
|
|
||||||
inputRef.current?.focus();
|
inputRef.current?.focus();
|
||||||
} else {
|
} else {
|
||||||
setError(undefined);
|
|
||||||
setSendOtpLoading(true);
|
setSendOtpLoading(true);
|
||||||
|
|
||||||
await sendSmsOtp({ phoneNumber: countryCode + value });
|
await sendSmsOtp({ phoneNumber: countryCode + value });
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
import { AuthenticationCard } from '../AuthenticationCard';
|
import { AuthenticationCard } from '../AuthenticationCard';
|
||||||
import { ArrowLeft, Edit2, Eye, EyeSlash } from 'iconsax-reactjs';
|
import { ArrowLeft, Edit2, Eye, EyeSlash } from 'iconsax-react';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Toast } from '@/components/Toast';
|
import { Toast } from '@/components/Toast';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router-dom';
|
||||||
import type { AuthType } from '../../types/authTypes';
|
import type { AuthType } from '../../types/authTypes';
|
||||||
import type { CountryCode, GUID } from '@/types/commonTypes';
|
import type { CountryCode, GUID } from '@/types/commonTypes';
|
||||||
import {
|
import {
|
||||||
@@ -48,7 +48,7 @@ export const EnterPasswordForm = ({
|
|||||||
const [showPassword, setShowPassword] = useState<boolean>(false);
|
const [showPassword, setShowPassword] = useState<boolean>(false);
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
const [loginLoading, setLoginLoading] = useState<boolean>(false);
|
const [loginLoading, setLoginLoading] = useState<boolean>(false);
|
||||||
const [loginStatus, setLoginStatus] = useState<'success' | 'failed'>();
|
const [isLoginStatusSuccess, setIsLoginStatusSuccess] = useState<boolean>();
|
||||||
const [loginAlertOpen, setLoginAlertOpen] = useState<boolean>(false);
|
const [loginAlertOpen, setLoginAlertOpen] = useState<boolean>(false);
|
||||||
const [loginFailedMessage, setLoginFailedMessage] = useState<string>('');
|
const [loginFailedMessage, setLoginFailedMessage] = useState<string>('');
|
||||||
const [sendOtpLoading, setSendOtpLoading] = useState<boolean>(false);
|
const [sendOtpLoading, setSendOtpLoading] = useState<boolean>(false);
|
||||||
@@ -74,10 +74,10 @@ export const EnterPasswordForm = ({
|
|||||||
const jsonRes = await result.json();
|
const jsonRes = await result.json();
|
||||||
|
|
||||||
if (jsonRes.success) {
|
if (jsonRes.success) {
|
||||||
setLoginStatus('success');
|
setIsLoginStatusSuccess(true);
|
||||||
onLoggedIn(jsonRes.userId);
|
onLoggedIn(jsonRes.userId);
|
||||||
} else {
|
} else {
|
||||||
setLoginStatus('failed');
|
setIsLoginStatusSuccess(false);
|
||||||
setLoginFailedMessage(jsonRes.message);
|
setLoginFailedMessage(jsonRes.message);
|
||||||
}
|
}
|
||||||
setLoginAlertOpen(true);
|
setLoginAlertOpen(true);
|
||||||
@@ -103,9 +103,9 @@ export const EnterPasswordForm = ({
|
|||||||
<Toast
|
<Toast
|
||||||
open={loginAlertOpen}
|
open={loginAlertOpen}
|
||||||
onClose={() => setLoginAlertOpen(false)}
|
onClose={() => setLoginAlertOpen(false)}
|
||||||
color={loginStatus === 'failed' ? 'error' : 'success'}
|
color={!isLoginStatusSuccess ? 'error' : 'success'}
|
||||||
>
|
>
|
||||||
{loginStatus === 'failed'
|
{!isLoginStatusSuccess
|
||||||
? loginFailedMessage
|
? loginFailedMessage
|
||||||
: t('verify.youHaveSuccessfullyLoggedIn')}
|
: t('verify.youHaveSuccessfullyLoggedIn')}
|
||||||
</Toast>
|
</Toast>
|
||||||
@@ -127,7 +127,7 @@ export const EnterPasswordForm = ({
|
|||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
size="large"
|
size="large"
|
||||||
sx={{ textTransform: 'lowercase', width: 'auto' }}
|
sx={{ width: 'auto' }}
|
||||||
endIcon={<Edit2 />}
|
endIcon={<Edit2 />}
|
||||||
onClick={onEditValue}
|
onClick={onEditValue}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Button } from '@mui/material';
|
import { Button } from '@mui/material';
|
||||||
import { Google } from 'iconsax-reactjs';
|
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import type { GoogleCodeClientResponse } from '../../types/userTypes';
|
import type { GoogleCodeClientResponse } from '../../types/userTypes';
|
||||||
import { loginOrSignUpWithGoogle } from '../../api/authorizationAPI';
|
import { loginOrSignUpWithGoogle } from '../../api/authorizationAPI';
|
||||||
import type { GUID } from '@/types/commonTypes';
|
import type { GUID } from '@/types/commonTypes';
|
||||||
|
import { Google } from 'iconsax-react';
|
||||||
|
|
||||||
export interface GoogleAuthenticationProps {
|
export interface GoogleAuthenticationProps {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
@@ -32,7 +32,7 @@ export const GoogleAuthentication = ({
|
|||||||
|
|
||||||
script.onload = () => {
|
script.onload = () => {
|
||||||
clientRef.current = google.accounts.oauth2.initCodeClient({
|
clientRef.current = google.accounts.oauth2.initCodeClient({
|
||||||
client_id: 'CLIEND_ID',
|
client_id: import.meta.env.VITE_GOOGLE_CLIENT_ID,
|
||||||
scope: 'openid email profile',
|
scope: 'openid email profile',
|
||||||
ux_mode: 'popup',
|
ux_mode: 'popup',
|
||||||
response_type: 'id_token',
|
response_type: 'id_token',
|
||||||
@@ -48,13 +48,17 @@ export const GoogleAuthentication = ({
|
|||||||
if (jsonRes.success) {
|
if (jsonRes.success) {
|
||||||
onGoogleAuthenticated(jsonRes.userId);
|
onGoogleAuthenticated(jsonRes.userId);
|
||||||
} else {
|
} else {
|
||||||
handleGoogleLogin();
|
// Todo: Add useToast to handle error
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoginWithGoogleLoading(false);
|
setLoginWithGoogleLoading(false);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.body.removeChild(script);
|
||||||
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleGoogleLogin = () => {
|
const handleGoogleLogin = () => {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { isNumeric } from '@/utils/regexes/isNumeric';
|
import { isNumeric } from '@/utils/regexes/isNumeric';
|
||||||
import type { AuthType } from '../../types/authTypes';
|
import type { AuthType } from '../../types/authTypes';
|
||||||
import { isEmail } from '@/utils/regexes/isEmail';
|
import { isEmail } from '@/utils/regexes/isEmail';
|
||||||
import parsePhoneNumberFromString from 'libphonenumber-js';
|
|
||||||
import { AuthenticationCard } from '../AuthenticationCard';
|
import { AuthenticationCard } from '../AuthenticationCard';
|
||||||
import { CountryCodeSelector } from '../CountryCodeSelector';
|
import { CountryCodeSelector } from '../CountryCodeSelector';
|
||||||
import type { UserStatus } from '../../types/userTypes';
|
import type { UserStatus } from '../../types/userTypes';
|
||||||
@@ -12,6 +11,7 @@ import { getUserStatusByPhoneNumberOrEmail } from '../../api/authorizationAPI';
|
|||||||
import { Toast } from '@/components/Toast';
|
import { Toast } from '@/components/Toast';
|
||||||
import type { CountryCode, GUID } from '@/types/commonTypes';
|
import type { CountryCode, GUID } from '@/types/commonTypes';
|
||||||
import { GoogleAuthentication } from './GoogleAuthentication';
|
import { GoogleAuthentication } from './GoogleAuthentication';
|
||||||
|
import { isPhoneNumber } from '@/utils/regexes/isValidPhoneNumber';
|
||||||
|
|
||||||
export interface LoginRegisterFormProps {
|
export interface LoginRegisterFormProps {
|
||||||
loginRegisterValue: string;
|
loginRegisterValue: string;
|
||||||
@@ -62,42 +62,32 @@ export function LoginRegisterForm({
|
|||||||
validateInput(loginRegisterValue, authType);
|
validateInput(loginRegisterValue, authType);
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateInput = (value: string, authType: AuthType) => {
|
const validateInput = (
|
||||||
if (!value) {
|
value: string,
|
||||||
setError(t('loginForm.thisFieldIsRequired'));
|
authType: AuthType,
|
||||||
} else if (authType === 'email' && !isEmail(value)) {
|
setErrors: boolean = true,
|
||||||
setError(t('loginForm.emailIsInvalid'));
|
): boolean => {
|
||||||
} else if (authType === 'phone' && !isPhoneValid(countryCode, value)) {
|
|
||||||
setError(t('loginForm.phoneNumberIsInvalid'));
|
|
||||||
} else {
|
|
||||||
setError(undefined);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const isPhoneValid = (code: string, phone: string) => {
|
|
||||||
const phoneNumber = parsePhoneNumberFromString(code + phone);
|
|
||||||
|
|
||||||
return phoneNumber && phoneNumber.isValid();
|
|
||||||
};
|
|
||||||
|
|
||||||
const isInputValid = (value: string, authType: AuthType): boolean => {
|
|
||||||
if (!value) {
|
if (!value) {
|
||||||
|
if (setErrors) setError(t('loginForm.thisFieldIsRequired'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authType === 'email' && !isEmail(value)) {
|
if (authType === 'email' && !isEmail(value)) {
|
||||||
|
if (setErrors) setError(t('loginForm.emailIsInvalid'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authType === 'phone' && !isPhoneValid(countryCode, value)) {
|
if (authType === 'phone' && !isPhoneNumber(countryCode, value)) {
|
||||||
|
if (setErrors) setError(t('loginForm.phoneNumberIsInvalid'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (setErrors) setError(undefined);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
if (isInputValid(loginRegisterValue, authType)) {
|
if (validateInput(loginRegisterValue, authType, false)) {
|
||||||
setCheckStatusLoading(true);
|
setCheckStatusLoading(true);
|
||||||
const result = await getUserStatusByPhoneNumberOrEmail({
|
const result = await getUserStatusByPhoneNumberOrEmail({
|
||||||
phoneNumber:
|
phoneNumber:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Box, Button, Stack, Typography } from '@mui/material';
|
import { Box, Button, Stack, Typography } from '@mui/material';
|
||||||
import { Edit2 } from 'iconsax-reactjs';
|
import { Edit2 } from 'iconsax-react';
|
||||||
import DigitInput from '@/components/components/DigitsInput';
|
import DigitInput from '@/components/components/DigitsInput';
|
||||||
import type { AuthMode, AuthType } from '../../types/authTypes';
|
import type { AuthMode, AuthType } from '../../types/authTypes';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
@@ -80,12 +80,6 @@ export function OtpVerifyForm({
|
|||||||
return `${min}:${sec.toString().padStart(2, '0')}`;
|
return `${min}:${sec.toString().padStart(2, '0')}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDigitInputChange = (value: string[]) => {
|
|
||||||
const formattedValue = value.filter((char) => char !== '').join('');
|
|
||||||
|
|
||||||
setOtpCode(formattedValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleVerifyOTP = () => {
|
const handleVerifyOTP = () => {
|
||||||
if (!otpCode || otpCode.length < 4) {
|
if (!otpCode || otpCode.length < 4) {
|
||||||
setOtpDigitInvalid(true);
|
setOtpDigitInvalid(true);
|
||||||
@@ -146,17 +140,14 @@ export function OtpVerifyForm({
|
|||||||
return '';
|
return '';
|
||||||
};
|
};
|
||||||
|
|
||||||
const verifyAlertMessage = (): string => {
|
const toastMessage =
|
||||||
if (verifyStatus === 'failed') {
|
verifyStatus === 'failed'
|
||||||
return errorMessage ?? t('verify.theVerificationCodeIsIncorrect');
|
? (errorMessage ?? t('verify.theVerificationCodeIsIncorrect'))
|
||||||
} else if (verifyStatus === 'success' && authMode === 'register') {
|
: verifyStatus === 'success' && authMode === 'register'
|
||||||
return t('verify.youHaveSuccessfullySignedIn');
|
? t('verify.youHaveSuccessfullySignedIn')
|
||||||
} else if (verifyStatus === 'success' && authMode === 'login') {
|
: verifyStatus === 'success' && authMode === 'login'
|
||||||
return t('verify.youHaveSuccessfullyLoggedIn');
|
? t('verify.youHaveSuccessfullyLoggedIn')
|
||||||
}
|
: '';
|
||||||
|
|
||||||
return '';
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack alignItems="center">
|
<Stack alignItems="center">
|
||||||
@@ -166,7 +157,7 @@ export function OtpVerifyForm({
|
|||||||
onClose={() => setVerifyAlertOpen(false)}
|
onClose={() => setVerifyAlertOpen(false)}
|
||||||
color={verifyStatus === 'failed' ? 'error' : 'success'}
|
color={verifyStatus === 'failed' ? 'error' : 'success'}
|
||||||
>
|
>
|
||||||
{verifyAlertMessage()}
|
{toastMessage}
|
||||||
</Toast>
|
</Toast>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
@@ -199,7 +190,7 @@ export function OtpVerifyForm({
|
|||||||
<DigitInput
|
<DigitInput
|
||||||
error={otpDigitInvalid || verifyStatus === 'failed'}
|
error={otpDigitInvalid || verifyStatus === 'failed'}
|
||||||
success={verifyStatus === 'success'}
|
success={verifyStatus === 'success'}
|
||||||
onChange={(value) => handleDigitInputChange(value as string[])}
|
onChange={(value) => setOtpCode(value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button onClick={handleVerifyOTP} loading={verifyStatusLoading}>
|
<Button onClick={handleVerifyOTP} loading={verifyStatusLoading}>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Box, Button, Stack, Typography } from '@mui/material';
|
import { Box, Button, Stack, Typography } from '@mui/material';
|
||||||
import { Edit2 } from 'iconsax-reactjs';
|
import { Edit2 } from 'iconsax-react';
|
||||||
import DigitInput from '@/components/components/DigitsInput';
|
import DigitInput from '@/components/components/DigitsInput';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Toast } from '@/components/Toast';
|
import { Toast } from '@/components/Toast';
|
||||||
@@ -63,12 +63,6 @@ export function VerifyPhoneNumber({
|
|||||||
return `${min}:${sec.toString().padStart(2, '0')}`;
|
return `${min}:${sec.toString().padStart(2, '0')}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDigitInputChange = (value: string[]) => {
|
|
||||||
const formattedValue = value.filter((char) => char !== '').join('');
|
|
||||||
|
|
||||||
setOtpCode(formattedValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleVerifyOTP = async () => {
|
const handleVerifyOTP = async () => {
|
||||||
if (!otpCode || otpCode.length < 4) {
|
if (!otpCode || otpCode.length < 4) {
|
||||||
setOtpDigitInvalid(true);
|
setOtpDigitInvalid(true);
|
||||||
@@ -147,7 +141,7 @@ export function VerifyPhoneNumber({
|
|||||||
<DigitInput
|
<DigitInput
|
||||||
error={otpDigitInvalid || verifyStatus === 'failed'}
|
error={otpDigitInvalid || verifyStatus === 'failed'}
|
||||||
success={verifyStatus === 'success'}
|
success={verifyStatus === 'success'}
|
||||||
onChange={(value) => handleDigitInputChange(value as string[])}
|
onChange={(value) => setOtpCode(value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button onClick={handleVerifyOTP} loading={verifyStatusLoading}>
|
<Button onClick={handleVerifyOTP} loading={verifyStatusLoading}>
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { useMemo, useRef, useState, type RefObject } from 'react';
|
import { useMemo, useRef, useState, type RefObject } from 'react';
|
||||||
import { ArrowDown2 } from 'iconsax-reactjs';
|
import { ArrowDown2 } from 'iconsax-react';
|
||||||
import ReactCountryFlag from 'react-country-flag';
|
import ReactCountryFlag from 'react-country-flag';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { countries, type Country } from '../data/countries';
|
import { countries, type Country } from '../../../countries';
|
||||||
import type { CountryCode } from '@/types/commonTypes';
|
import type { CountryCode } from '@/types/commonTypes';
|
||||||
interface CountryCodeSelectorProps {
|
interface CountryCodeSelectorProps {
|
||||||
show: boolean;
|
show: boolean;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
import { AuthenticationCard } from '../AuthenticationCard';
|
import { AuthenticationCard } from '../AuthenticationCard';
|
||||||
import { Edit2, Eye, EyeSlash, TickCircle } from 'iconsax-reactjs';
|
import { Edit2, Eye, EyeSlash, TickCircle } from 'iconsax-react';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Box, Button, Stack, Typography } from '@mui/material';
|
import { Box, Button, Stack, Typography } from '@mui/material';
|
||||||
import { Edit2 } from 'iconsax-reactjs';
|
import { Edit2 } from 'iconsax-react';
|
||||||
import DigitInput from '@/components/components/DigitsInput';
|
import DigitInput from '@/components/components/DigitsInput';
|
||||||
import type { AuthType } from '../../types/authTypes';
|
import type { AuthType } from '../../types/authTypes';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
@@ -69,12 +69,6 @@ export function ForgetPasswordOtp({
|
|||||||
return `${min}:${sec.toString().padStart(2, '0')}`;
|
return `${min}:${sec.toString().padStart(2, '0')}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDigitInputChange = (value: string[]) => {
|
|
||||||
const formattedValue = value.filter((char) => char !== '').join('');
|
|
||||||
|
|
||||||
setOtpCode(formattedValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleVerifyOTP = async () => {
|
const handleVerifyOTP = async () => {
|
||||||
if (!otpCode || otpCode.length < 4) {
|
if (!otpCode || otpCode.length < 4) {
|
||||||
setOtpDigitInvalid(true);
|
setOtpDigitInvalid(true);
|
||||||
@@ -158,7 +152,7 @@ export function ForgetPasswordOtp({
|
|||||||
<DigitInput
|
<DigitInput
|
||||||
error={otpDigitInvalid || verifyStatus === 'failed'}
|
error={otpDigitInvalid || verifyStatus === 'failed'}
|
||||||
success={verifyStatus === 'success'}
|
success={verifyStatus === 'success'}
|
||||||
onChange={(value) => handleDigitInputChange(value as string[])}
|
onChange={(value) => setOtpCode(value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button onClick={handleVerifyOTP} loading={verifyStatusLoading}>
|
<Button onClick={handleVerifyOTP} loading={verifyStatusLoading}>
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { isNumeric } from '@/utils/regexes/isNumeric';
|
import { isNumeric } from '@/utils/regexes/isNumeric';
|
||||||
import type { AuthType } from '../../types/authTypes';
|
import type { AuthType } from '../../types/authTypes';
|
||||||
import { isEmail } from '@/utils/regexes/isEmail';
|
import { isEmail } from '@/utils/regexes/isEmail';
|
||||||
import parsePhoneNumberFromString from 'libphonenumber-js';
|
|
||||||
import { AuthenticationCard } from '../AuthenticationCard';
|
import { AuthenticationCard } from '../AuthenticationCard';
|
||||||
import { CountryCodeSelector } from '../CountryCodeSelector';
|
import { CountryCodeSelector } from '../CountryCodeSelector';
|
||||||
import type { CountryCode } from '@/types/commonTypes';
|
import type { CountryCode } from '@/types/commonTypes';
|
||||||
import { sendForgetPassCode } from '../../api/authorizationAPI';
|
import { sendForgetPassCode } from '../../api/authorizationAPI';
|
||||||
import type { SendForgetPassCodeRequest } from '../../types/userTypes';
|
import type { SendForgetPassCodeRequest } from '../../types/userTypes';
|
||||||
import { Toast } from '@/components/Toast';
|
import { Toast } from '@/components/Toast';
|
||||||
|
import { isPhoneNumber } from '@/utils/regexes/isValidPhoneNumber';
|
||||||
|
|
||||||
export interface ForgettedPasswordInfoProps {
|
export interface ForgettedPasswordInfoProps {
|
||||||
forgettedPasswordInfo: string;
|
forgettedPasswordInfo: string;
|
||||||
@@ -57,42 +57,28 @@ export function ForgettedPasswordInfo({
|
|||||||
validateInput(forgettedPasswordInfo, infoType);
|
validateInput(forgettedPasswordInfo, infoType);
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateInput = (value: string, authType: AuthType) => {
|
const validateInput = (
|
||||||
|
value: string,
|
||||||
|
authType: AuthType,
|
||||||
|
setErrors: boolean = true,
|
||||||
|
) => {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
setError(t('loginForm.thisFieldIsRequired'));
|
if (setErrors) setError(t('loginForm.thisFieldIsRequired'));
|
||||||
|
return false;
|
||||||
} else if (authType === 'email' && !isEmail(value)) {
|
} else if (authType === 'email' && !isEmail(value)) {
|
||||||
setError(t('loginForm.emailIsInvalid'));
|
if (setErrors) setError(t('loginForm.emailIsInvalid'));
|
||||||
} else if (authType === 'phone' && !isPhoneValid(countryCode, value)) {
|
return false;
|
||||||
setError(t('loginForm.phoneNumberIsInvalid'));
|
} else if (authType === 'phone' && !isPhoneNumber(countryCode, value)) {
|
||||||
|
if (setErrors) setError(t('loginForm.phoneNumberIsInvalid'));
|
||||||
|
return false;
|
||||||
} else {
|
} else {
|
||||||
setError(undefined);
|
if (setErrors) setError(undefined);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const isPhoneValid = (code: string, phone: string) => {
|
|
||||||
const phoneNumber = parsePhoneNumberFromString(code + phone);
|
|
||||||
|
|
||||||
return phoneNumber && phoneNumber.isValid();
|
|
||||||
};
|
|
||||||
|
|
||||||
const isInputValid = (value: string, infoType: AuthType): boolean => {
|
|
||||||
if (!value) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (infoType === 'email' && !isEmail(value)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (infoType === 'phone' && !isPhoneValid(countryCode, value)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
if (isInputValid(forgettedPasswordInfo, infoType)) {
|
if (validateInput(forgettedPasswordInfo, infoType, false)) {
|
||||||
setSendCodeLoading(true);
|
setSendCodeLoading(true);
|
||||||
|
|
||||||
const sendCodeRequest: SendForgetPassCodeRequest = {
|
const sendCodeRequest: SendForgetPassCodeRequest = {
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
export type AuthType = 'email' | 'phone';
|
export type AuthType = 'email' | 'phone';
|
||||||
|
|
||||||
export type AuthMode = 'register' | 'login';
|
export type AuthMode = 'register' | 'login';
|
||||||
|
|
||||||
|
export type AuthStep =
|
||||||
|
| 'emailOrPhone'
|
||||||
|
| 'verify'
|
||||||
|
| 'enterPassword'
|
||||||
|
| 'addPhoneNumber'
|
||||||
|
| 'addedPhoneNumberVerify';
|
||||||
|
|||||||
7
src/utils/regexes/isValidPhoneNumber.tsx
Normal file
7
src/utils/regexes/isValidPhoneNumber.tsx
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import parsePhoneNumberFromString from 'libphonenumber-js';
|
||||||
|
|
||||||
|
export const isPhoneNumber = (code: string, phone: string) => {
|
||||||
|
const phoneNumber = parsePhoneNumberFromString(code + phone);
|
||||||
|
|
||||||
|
return phoneNumber && phoneNumber.isValid();
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user