Browse Source
feat: implement core marriage matching application architecture including UI components, question workflows, and multi-language support.
front-test-2
feat: implement core marriage matching application architecture including UI components, question workflows, and multi-language support.
front-test-2
102 changed files with 26606 additions and 2882 deletions
-
8next.config.ts
-
22668public/openapi.json
-
4src/app/[lang]/layout.tsx
-
2src/app/[lang]/questions-list/[slug]/page.tsx
-
14src/app/[lang]/test-webview/page.tsx
-
7src/app/api/dev-storage/route.ts
-
10src/app/api/open-in-ide/route.ts
-
2src/app/api/proxy/route.ts
-
6src/app/api/remote-logs/route.ts
-
29src/app/api/remote-network/route.ts
-
2src/app/candidate-contact/page.tsx
-
8src/app/finding-match/page.tsx
-
21src/app/globals.css
-
21src/app/intro/page.tsx
-
5src/app/layout.tsx
-
57src/app/new-match/page.tsx
-
10src/app/new-match/profile/page.tsx
-
16src/app/providers.tsx
-
5src/app/questions-list/[slug]/answer-pace-sheet.tsx
-
54src/app/questions-list/[slug]/question-detail-client.tsx
-
2src/app/questions-list/[slug]/test-intro-client.tsx
-
29src/app/questions-list/page.tsx
-
59src/app/request-accepted/page.tsx
-
23src/app/request-sent/page.tsx
-
199src/components/dev/dev-click-to-component.tsx
-
74src/components/questions/progress-helper.ts
-
24src/components/questions/question-answer-storage.tsx
-
716src/components/questions/question-birthplace.tsx
-
2src/components/questions/question-card.tsx
-
25src/components/questions/question-date.tsx
-
69src/components/questions/question-dropdown.tsx
-
2src/components/questions/question-exit-navigation-button.tsx
-
18src/components/questions/question-file.tsx
-
33src/components/questions/question-number.tsx
-
352src/components/questions/question-phone.tsx
-
22src/components/questions/question-photo.tsx
-
2src/components/questions/question-progress-tracker.tsx
-
11src/components/questions/question-section-flow.tsx
-
8src/components/questions/question-slider.tsx
-
39src/components/questions/question-snap-list.tsx
-
11src/components/questions/question-text.tsx
-
15src/components/questions/question-title.tsx
-
19src/components/questions/required-steps-card.tsx
-
36src/components/questions/test-loading-screen.tsx
-
16src/components/questions/test-questions-flow.tsx
-
2src/components/sliders/slider-page.tsx
-
8src/components/sliders/slider-slide-four.tsx
-
24src/components/sliders/slider-slide-one.tsx
-
4src/components/sliders/slider-slide-two.tsx
-
4src/components/ui/button.tsx
-
9src/components/ui/female-consent-sheet.tsx
-
15src/components/ui/help-modal.tsx
-
8src/components/ui/navigation-button.tsx
-
45src/components/ui/report-actions-sheet.tsx
-
4src/components/ui/token-switcher.tsx
-
5src/components/utils/dev-click-to-component.tsx
-
5src/components/utils/fixed-bottom.tsx
-
2024src/data/cattell-fallback.ts
-
401src/data/countries.ts
-
72src/data/glasser-fallback.ts
-
157src/data/languages.ts
-
283src/data/nationalities.ts
-
10src/data/question-data.ts
-
660src/data/questions/en.json
-
660src/data/questions/fa.json
-
14src/hooks/marriage/query-keys.ts
-
10src/hooks/marriage/types.ts
-
3src/hooks/marriage/use-section-data.ts
-
6src/hooks/use-close-service-on-back.ts
-
114src/hooks/useFlutterBridge.ts
-
17src/lib/auth-bridge.ts
-
6src/lib/http.ts
-
24src/lib/performance.ts
-
26src/lib/view-paddings.ts
-
4src/plugins/jsx-locator-loader.cjs
-
5src/translations/dictionaries.ts
-
4src/translations/locales/ar.json
-
4src/translations/locales/az.json
-
4src/translations/locales/bn.json
-
4src/translations/locales/da.json
-
4src/translations/locales/de.json
-
4src/translations/locales/en.json
-
4src/translations/locales/es.json
-
4src/translations/locales/fa.json
-
4src/translations/locales/fr.json
-
4src/translations/locales/gu.json
-
4src/translations/locales/ha.json
-
4src/translations/locales/he.json
-
4src/translations/locales/hi.json
-
4src/translations/locales/id.json
-
4src/translations/locales/ks.json
-
4src/translations/locales/pt.json
-
4src/translations/locales/ru.json
-
4src/translations/locales/sw.json
-
4src/translations/locales/tg.json
-
4src/translations/locales/tr.json
-
4src/translations/locales/ul.json
-
4src/translations/locales/ur.json
-
4src/translations/locales/uz.json
-
4src/translations/locales/zh.json
22668
public/openapi.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,716 @@ |
|||
"use client"; |
|||
|
|||
import { useCallback, useEffect, useRef, useState } from "react"; |
|||
import { getCountryList, COUNTRIES_EN, COUNTRIES_FA } from "@/data/countries"; |
|||
import type { QuestionField } from "@/data/question-data"; |
|||
import { useI18n } from "@/translations/provider"; |
|||
import { useQuestionAnswers } from "./question-answer-storage"; |
|||
import QuestionTitle from "./question-title"; |
|||
|
|||
type QuestionBirthplaceProps = { |
|||
question: QuestionField; |
|||
questionIndex: number; |
|||
disabled?: boolean; |
|||
}; |
|||
|
|||
type BirthplaceValue = { |
|||
country?: string; |
|||
city?: string; |
|||
}; |
|||
|
|||
function parseValue(rawValue: unknown): { country: string; city: string } { |
|||
if (!rawValue) return { country: "", city: "" }; |
|||
|
|||
if (typeof rawValue === "object" && rawValue !== null) { |
|||
const obj = rawValue as BirthplaceValue; |
|||
return { |
|||
country: typeof obj.country === "string" ? obj.country : "", |
|||
city: typeof obj.city === "string" ? obj.city : "", |
|||
}; |
|||
} |
|||
|
|||
if (typeof rawValue === "string") { |
|||
let str = rawValue.trim(); |
|||
// Clean legacy country names with parentheses containing commas
|
|||
str = str.replace( |
|||
"United Kingdom (UK, England, Wales, Scotland, Northern Ireland)", |
|||
"United Kingdom (UK)", |
|||
); |
|||
str = str.replace("United States (US, USA, America)", "United States (US)"); |
|||
str = str.replace( |
|||
"United Arab Emirates (UAE, Dubai, Abu Dhabi)", |
|||
"United Arab Emirates (UAE)", |
|||
); |
|||
str = str.replace("Congo (Congo-Brazzaville)", "Congo"); |
|||
str = str.replace("Czechia (Czech Republic)", "Czechia"); |
|||
str = str.replace("Myanmar (formerly Burma)", "Myanmar"); |
|||
str = str.replace( |
|||
"امارات متحده عربی (دبی، ابوظبی، UAE)", |
|||
"امارات متحده عربی (UAE)", |
|||
); |
|||
str = str.replace( |
|||
"بریتانیا (انگلستان، اسکاتلند، ولز، ایرلند شمالی، UK)", |
|||
"بریتانیا (UK)", |
|||
); |
|||
str = str.replace( |
|||
"ایالات متحده آمریکا (آمریکا، US، USA)", |
|||
"ایالات متحده آمریکا (US)", |
|||
); |
|||
|
|||
if (str.includes(",")) { |
|||
const parts = str.split(",").map((s) => s.trim()); |
|||
return { city: parts[0] || "", country: parts[1] || "" }; |
|||
} |
|||
if (str.includes(" - ")) { |
|||
const parts = str.split(" - ").map((s) => s.trim()); |
|||
return { country: parts[0] || "", city: parts[1] || "" }; |
|||
} |
|||
const isCountry = COUNTRIES_EN.includes(str) || COUNTRIES_FA.includes(str); |
|||
if (isCountry) { |
|||
return { country: str, city: "" }; |
|||
} |
|||
return { country: "", city: str }; |
|||
} |
|||
|
|||
return { country: "", city: "" }; |
|||
} |
|||
|
|||
export function QuestionBirthplace({ |
|||
question, |
|||
questionIndex, |
|||
disabled, |
|||
}: QuestionBirthplaceProps) { |
|||
const { dictionary: t, locale } = useI18n(); |
|||
const { getAnswerValue, setAnswerValue } = useQuestionAnswers(); |
|||
const rawValue = getAnswerValue(question, questionIndex); |
|||
|
|||
const initial = parseValue(rawValue); |
|||
const [selectedCountry, setSelectedCountry] = useState(initial.country); |
|||
const [cityInput, setCityInput] = useState(initial.city); |
|||
|
|||
const [isOpen, setIsOpen] = useState(false); |
|||
const [searchQuery, setSearchQuery] = useState(""); |
|||
const containerRef = useRef<HTMLDivElement>(null); |
|||
const listRef = useRef<HTMLDivElement>(null); |
|||
const searchInputRef = useRef<HTMLInputElement>(null); |
|||
|
|||
const isResidence = |
|||
question.title.toLowerCase().includes("residence") || |
|||
question.title.includes("سکونت"); |
|||
|
|||
const [mode, setMode] = useState<"auto" | "manual">("auto"); |
|||
const [isDetecting, setIsDetecting] = useState(false); |
|||
const [detectedLocation, setDetectedLocation] = useState(""); |
|||
|
|||
const updateAnswers = (country: string, city: string) => { |
|||
const formatted = |
|||
city && country ? `${city}, ${country}` : city || country || null; |
|||
setAnswerValue(question, questionIndex, formatted); |
|||
}; |
|||
|
|||
// GeoIP detection logic
|
|||
const detectLocation = (force = false) => { |
|||
const alreadyChecked = |
|||
typeof window !== "undefined" |
|||
? localStorage.getItem("hasCheckedGeoIPResidence") |
|||
: "true"; |
|||
if (alreadyChecked && !force) { |
|||
if (rawValue) { |
|||
const parsed = parseValue(rawValue); |
|||
if (parsed.country && parsed.city) { |
|||
setDetectedLocation(`${parsed.city}, ${parsed.country}`); |
|||
setMode("auto"); |
|||
} else { |
|||
setMode("manual"); |
|||
} |
|||
} else { |
|||
setMode("auto"); |
|||
} |
|||
return; |
|||
} |
|||
|
|||
// If there is already a saved value and we are not forcing, do not fetch again
|
|||
if (rawValue && !force) { |
|||
const parsed = parseValue(rawValue); |
|||
if (parsed.country && parsed.city) { |
|||
setDetectedLocation(`${parsed.city}, ${parsed.country}`); |
|||
setMode("auto"); |
|||
} else { |
|||
setMode("manual"); |
|||
} |
|||
return; |
|||
} |
|||
|
|||
setIsDetecting(true); |
|||
if (typeof window !== "undefined") { |
|||
localStorage.setItem("hasCheckedGeoIPResidence", "true"); |
|||
} |
|||
fetch("https://ipapi.co/json/") |
|||
.then((res) => res.json()) |
|||
.then((data) => { |
|||
if (data && data.city && data.country_name) { |
|||
const city = data.city; |
|||
const country = data.country_name; |
|||
setSelectedCountry(country); |
|||
setCityInput(city); |
|||
setDetectedLocation(`${city}, ${country}`); |
|||
updateAnswers(country, city); |
|||
setMode("auto"); |
|||
} else { |
|||
throw new Error("Missing data"); |
|||
} |
|||
}) |
|||
.catch(() => { |
|||
fetch("https://ipwho.is/") |
|||
.then((res) => res.json()) |
|||
.then((data) => { |
|||
if (data && data.city && data.country) { |
|||
const city = data.city; |
|||
const country = data.country; |
|||
setSelectedCountry(country); |
|||
setCityInput(city); |
|||
setDetectedLocation(`${city}, ${country}`); |
|||
updateAnswers(country, city); |
|||
setMode("auto"); |
|||
} else { |
|||
setMode("manual"); |
|||
} |
|||
}) |
|||
.catch(() => { |
|||
setMode("manual"); |
|||
}); |
|||
}) |
|||
.finally(() => { |
|||
setIsDetecting(false); |
|||
}); |
|||
}; |
|||
|
|||
useEffect(() => { |
|||
if (isResidence) { |
|||
detectLocation(); |
|||
} |
|||
}, [isResidence]); |
|||
|
|||
const handleAutoClick = () => { |
|||
setMode("auto"); |
|||
detectLocation(true); |
|||
}; |
|||
|
|||
const handleManualClick = () => { |
|||
if (typeof window !== "undefined") { |
|||
localStorage.setItem("hasCheckedGeoIPResidence", "true"); |
|||
} |
|||
setMode("manual"); |
|||
setSelectedCountry(""); |
|||
setCityInput(""); |
|||
updateAnswers("", ""); |
|||
}; |
|||
|
|||
// Synchronize state if rawValue changes externally
|
|||
useEffect(() => { |
|||
const updated = parseValue(rawValue); |
|||
if (updated.country !== selectedCountry) { |
|||
setSelectedCountry(updated.country); |
|||
} |
|||
if (updated.city.trim() !== cityInput.trim()) { |
|||
setCityInput(updated.city); |
|||
} |
|||
if (updated.country && updated.city) { |
|||
setDetectedLocation(`${updated.city}, ${updated.country}`); |
|||
} |
|||
}, [rawValue]); |
|||
|
|||
// Lock page scroll when dropdown is open
|
|||
useEffect(() => { |
|||
if (isOpen) { |
|||
document.body.classList.add("dropdown-open"); |
|||
document.body.style.overflow = "hidden"; |
|||
document.documentElement.style.overflow = "hidden"; |
|||
} else { |
|||
document.body.classList.remove("dropdown-open"); |
|||
document.body.style.overflow = ""; |
|||
document.documentElement.style.overflow = ""; |
|||
} |
|||
return () => { |
|||
document.body.classList.remove("dropdown-open"); |
|||
document.body.style.overflow = ""; |
|||
document.documentElement.style.overflow = ""; |
|||
}; |
|||
}, [isOpen]); |
|||
|
|||
useEffect(() => { |
|||
if (isOpen) { |
|||
const timer = setTimeout(() => { |
|||
searchInputRef.current?.focus(); |
|||
}, 50); |
|||
return () => clearTimeout(timer); |
|||
} |
|||
}, [isOpen]); |
|||
|
|||
const handleListWheel = useCallback((e: React.WheelEvent<HTMLDivElement>) => { |
|||
e.stopPropagation(); |
|||
const el = listRef.current; |
|||
if (!el) return; |
|||
|
|||
const atTop = el.scrollTop <= 0 && e.deltaY < 0; |
|||
const atBottom = |
|||
el.scrollTop + el.clientHeight >= el.scrollHeight && e.deltaY > 0; |
|||
|
|||
if (atTop || atBottom) { |
|||
e.preventDefault(); |
|||
} |
|||
}, []); |
|||
|
|||
useEffect(() => { |
|||
function handleClickOutside(event: MouseEvent) { |
|||
if ( |
|||
containerRef.current && |
|||
!containerRef.current.contains(event.target as Node) |
|||
) { |
|||
setIsOpen(false); |
|||
} |
|||
} |
|||
document.addEventListener("mousedown", handleClickOutside); |
|||
return () => { |
|||
document.removeEventListener("mousedown", handleClickOutside); |
|||
}; |
|||
}, []); |
|||
|
|||
const options = getCountryList(locale); |
|||
const filteredOptions = options.filter((option) => |
|||
option.toLowerCase().includes(searchQuery.toLowerCase()), |
|||
); |
|||
|
|||
const handleSelectCountry = (country: string) => { |
|||
if (typeof window !== "undefined") { |
|||
localStorage.setItem("hasCheckedGeoIPResidence", "true"); |
|||
} |
|||
setSelectedCountry(country); |
|||
setCityInput(""); |
|||
setIsOpen(false); |
|||
updateAnswers(country, ""); |
|||
}; |
|||
|
|||
const handleCityChange = (e: React.ChangeEvent<HTMLInputElement>) => { |
|||
if (typeof window !== "undefined") { |
|||
localStorage.setItem("hasCheckedGeoIPResidence", "true"); |
|||
} |
|||
const newCity = e.target.value; |
|||
setCityInput(newCity); |
|||
updateAnswers(selectedCountry, newCity); |
|||
}; |
|||
|
|||
const isRtl = locale === "fa" || locale === "ar" || locale === "ur"; |
|||
const selectCountryPlaceholder = isRtl ? "انتخاب کشور" : "Select country"; |
|||
const cityPlaceholder = |
|||
question.extras?.placeHolder || |
|||
(isRtl ? "شهر، منطقه یا محله" : "City, region, or neighborhood"); |
|||
|
|||
return ( |
|||
<div |
|||
ref={containerRef} |
|||
className={[ |
|||
"relative flex w-full flex-col gap-3 transition-opacity duration-200", |
|||
disabled ? "pointer-events-none opacity-30" : "", |
|||
].join(" ")} |
|||
> |
|||
<QuestionTitle question={question} /> |
|||
|
|||
{isResidence ? ( |
|||
<> |
|||
{/* GeoIP Auto/Manual selector UI */} |
|||
<div className="flex flex-col gap-3.5 w-full py-1"> |
|||
{/* Left Side: Location Info */} |
|||
<div className="flex items-center gap-2.5 min-w-0"> |
|||
<svg |
|||
width="16" |
|||
height="20" |
|||
viewBox="0 0 16 20" |
|||
fill="none" |
|||
className="shrink-0 text-[#181818]" |
|||
> |
|||
<path |
|||
d="M8 0C3.58 0 0 3.58 0 8C0 13.54 8 20 8 20C8 20 16 13.54 16 8C16 3.58 12.42 0 8 0ZM8 11C6.34 11 5 9.66 5 8C5 6.34 6.34 5 8 5C9.66 5 11 6.34 11 8C11 9.66 9.66 11 8 11Z" |
|||
fill="currentColor" |
|||
/> |
|||
</svg> |
|||
<span className="text-[16px] font-bold text-[#181818]"> |
|||
{isDetecting |
|||
? locale === "fa" |
|||
? "در حال شناسایی..." |
|||
: "Detecting..." |
|||
: detectedLocation || |
|||
(locale === "fa" ? "نامشخص" : "Unknown")} |
|||
</span> |
|||
</div> |
|||
|
|||
{/* Right Side: Toggle Buttons */} |
|||
<div className="flex items-center gap-2 w-full"> |
|||
{/* Auto Button */} |
|||
<button |
|||
type="button" |
|||
onClick={handleAutoClick} |
|||
className={[ |
|||
"flex flex-1 items-center justify-center gap-1.5 h-[46px] rounded-xl text-[14px] font-bold cursor-pointer transition-all shadow-sm", |
|||
mode === "auto" |
|||
? "bg-[#F2465F] text-white" |
|||
: "bg-white border border-[#D0D5DD] text-[#344054] hover:bg-gray-50", |
|||
].join(" ")} |
|||
> |
|||
<svg |
|||
width="16" |
|||
height="16" |
|||
viewBox="0 0 16 16" |
|||
fill="none" |
|||
className="shrink-0" |
|||
> |
|||
<circle |
|||
cx="8" |
|||
cy="8" |
|||
r="6" |
|||
stroke="currentColor" |
|||
strokeWidth="2" |
|||
/> |
|||
<circle cx="8" cy="8" r="2" fill="currentColor" /> |
|||
<path |
|||
d="M8 0V3M8 13V16M0 8H3M13 8H16" |
|||
stroke="currentColor" |
|||
strokeWidth="2" |
|||
strokeLinecap="round" |
|||
/> |
|||
</svg> |
|||
<span>{locale === "fa" ? "خودکار" : "Auto"}</span> |
|||
</button> |
|||
|
|||
{/* Manual Button */} |
|||
<button |
|||
type="button" |
|||
onClick={handleManualClick} |
|||
className={[ |
|||
"flex flex-1 items-center justify-center gap-1.5 h-[46px] rounded-xl text-[14px] font-bold cursor-pointer transition-all shadow-sm", |
|||
mode === "manual" |
|||
? "bg-[#F2465F] text-white" |
|||
: "bg-white border border-[#D0D5DD] text-[#344054] hover:bg-gray-50", |
|||
].join(" ")} |
|||
> |
|||
<svg |
|||
width="16" |
|||
height="16" |
|||
viewBox="0 0 16 16" |
|||
fill="none" |
|||
className="shrink-0" |
|||
> |
|||
<path |
|||
d="M1 3.5L5 1.5L11 4.5L15 2.5V12.5L11 14.5L5 11.5L1 13.5V3.5Z" |
|||
stroke="currentColor" |
|||
strokeWidth="2" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
/> |
|||
<path |
|||
d="M5 1.5V11.5M11 4.5V14.5" |
|||
stroke="currentColor" |
|||
strokeWidth="2" |
|||
/> |
|||
</svg> |
|||
<span>{locale === "fa" ? "دستی" : "Manual"}</span> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
|
|||
{mode === "manual" && ( |
|||
<div className="flex flex-col gap-3 w-full animate-in fade-in slide-in-from-top-2 duration-200"> |
|||
{/* Country Selection Dropdown */} |
|||
<div className="relative w-full"> |
|||
<button |
|||
type="button" |
|||
disabled={disabled} |
|||
onClick={() => setIsOpen(!isOpen)} |
|||
className={[ |
|||
"flex h-[54px] w-full items-center justify-between rounded-[16px] border bg-white px-4.5 text-start transition-all cursor-pointer outline-none", |
|||
isOpen |
|||
? "border-[#6F6F6F] ring-1 ring-[#6F6F6F]" |
|||
: "border-[#D0D5DD] hover:border-[#98A2B3]", |
|||
].join(" ")} |
|||
> |
|||
<span |
|||
className={[ |
|||
"text-[15px] font-medium truncate", |
|||
selectedCountry ? "text-[#181818]" : "text-[#667085]", |
|||
].join(" ")} |
|||
> |
|||
{selectedCountry || selectCountryPlaceholder} |
|||
</span> |
|||
<svg |
|||
width="16" |
|||
height="10" |
|||
viewBox="0 0 16 10" |
|||
fill="none" |
|||
className={[ |
|||
"shrink-0 transition-transform duration-200", |
|||
isOpen ? "rotate-180" : "", |
|||
].join(" ")} |
|||
> |
|||
<path |
|||
d="M14.75 1.25L7.75 8.25L0.75 1.25" |
|||
stroke="#344054" |
|||
strokeWidth="1.75" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
/> |
|||
</svg> |
|||
</button> |
|||
|
|||
{isOpen && ( |
|||
<div className="absolute top-[calc(100%+8px)] left-0 z-50 flex w-full flex-col gap-3.5 rounded-[20px] bg-white p-4.5 shadow-[0_12px_36px_rgba(0,0,0,0.09)] border border-[#EAECF0] animate-in fade-in zoom-in-95 duration-150"> |
|||
{options.length > 3 || searchQuery ? ( |
|||
<div className="flex h-[46px] w-full items-center gap-2.5 rounded-[12px] bg-[#EFEFEF] px-3.5 transition-colors focus-within:bg-[#E8E8E8]"> |
|||
<svg |
|||
width="18" |
|||
height="18" |
|||
viewBox="0 0 18 18" |
|||
fill="none" |
|||
className="shrink-0 text-[#667085]" |
|||
> |
|||
<path |
|||
d="M8.25 14.25C11.5637 14.25 14.25 11.5637 14.25 8.25C14.25 4.93629 11.5637 2.25 8.25 2.25C4.93629 2.25 2.25 4.93629 2.25 8.25C2.25 11.5637 4.93629 14.25 8.25 14.25Z" |
|||
stroke="#667085" |
|||
strokeWidth="1.75" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
/> |
|||
<path |
|||
d="M15.75 15.75L12.5 12.5" |
|||
stroke="#667085" |
|||
strokeWidth="1.75" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
/> |
|||
</svg> |
|||
<input |
|||
ref={searchInputRef} |
|||
type="text" |
|||
value={searchQuery} |
|||
onChange={(e) => setSearchQuery(e.target.value)} |
|||
placeholder="Search..." |
|||
className="flex-1 bg-transparent text-[14px] font-medium text-[#181818] outline-none placeholder:text-[#98A2B3]" |
|||
/> |
|||
{searchQuery ? ( |
|||
<button |
|||
type="button" |
|||
onClick={() => setSearchQuery("")} |
|||
className="text-[#667085] hover:text-[#181818] text-xs font-semibold" |
|||
> |
|||
✕ |
|||
</button> |
|||
) : null} |
|||
</div> |
|||
) : null} |
|||
|
|||
<div |
|||
ref={listRef} |
|||
onWheel={handleListWheel} |
|||
onTouchStart={(e) => e.stopPropagation()} |
|||
onTouchMove={(e) => e.stopPropagation()} |
|||
onTouchEnd={(e) => e.stopPropagation()} |
|||
className="flex max-h-[220px] flex-col gap-3.5 overflow-y-auto overscroll-contain pr-1" |
|||
> |
|||
{filteredOptions.length > 0 ? ( |
|||
filteredOptions.map((option) => { |
|||
const isSelected = selectedCountry === option; |
|||
|
|||
return ( |
|||
<button |
|||
key={option} |
|||
type="button" |
|||
onClick={() => handleSelectCountry(option)} |
|||
className="flex w-full items-center gap-3 text-start cursor-pointer group/opt py-0.5" |
|||
> |
|||
<div |
|||
className={[ |
|||
"size-[20px] shrink-0 rounded-full transition-all duration-150", |
|||
isSelected |
|||
? "bg-[#F2465F] shadow-xs" |
|||
: "border-[2px] border-[#344054] bg-transparent group-hover/opt:border-[#181818]", |
|||
].join(" ")} |
|||
/> |
|||
<span className="text-[15px] font-bold text-[#181818]"> |
|||
{option} |
|||
</span> |
|||
</button> |
|||
); |
|||
}) |
|||
) : ( |
|||
<span className="py-2 text-[13px] text-[#667085]"> |
|||
No options found |
|||
</span> |
|||
)} |
|||
</div> |
|||
</div> |
|||
)} |
|||
</div> |
|||
|
|||
{/* City Text Input */} |
|||
<div className="w-full"> |
|||
<input |
|||
type="text" |
|||
disabled={disabled} |
|||
value={cityInput} |
|||
onChange={handleCityChange} |
|||
placeholder={cityPlaceholder} |
|||
className="h-[54px] w-full rounded-[16px] border border-[#D0D5DD] bg-white px-4.5 text-[15px] font-medium text-[#181818] placeholder:text-[#98A2B3] hover:border-[#98A2B3] focus:border-[#6F6F6F] focus:ring-1 focus:ring-[#6F6F6F] outline-none transition-all" |
|||
/> |
|||
</div> |
|||
</div> |
|||
)} |
|||
</> |
|||
) : ( |
|||
<> |
|||
{/* 1. Country Selection Dropdown */} |
|||
<div className="relative w-full"> |
|||
<button |
|||
type="button" |
|||
disabled={disabled} |
|||
onClick={() => setIsOpen(!isOpen)} |
|||
className={[ |
|||
"flex h-[54px] w-full items-center justify-between rounded-[16px] border bg-white px-4.5 text-start transition-all cursor-pointer outline-none", |
|||
isOpen |
|||
? "border-[#6F6F6F] ring-1 ring-[#6F6F6F]" |
|||
: "border-[#D0D5DD] hover:border-[#98A2B3]", |
|||
].join(" ")} |
|||
> |
|||
<span |
|||
className={[ |
|||
"text-[15px] font-medium truncate", |
|||
selectedCountry ? "text-[#181818]" : "text-[#667085]", |
|||
].join(" ")} |
|||
> |
|||
{selectedCountry || selectCountryPlaceholder} |
|||
</span> |
|||
<svg |
|||
width="16" |
|||
height="10" |
|||
viewBox="0 0 16 10" |
|||
fill="none" |
|||
className={[ |
|||
"shrink-0 transition-transform duration-200", |
|||
isOpen ? "rotate-180" : "", |
|||
].join(" ")} |
|||
> |
|||
<path |
|||
d="M14.75 1.25L7.75 8.25L0.75 1.25" |
|||
stroke="#344054" |
|||
strokeWidth="1.75" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
/> |
|||
</svg> |
|||
</button> |
|||
|
|||
{isOpen && ( |
|||
<div className="absolute top-[calc(100%+8px)] left-0 z-50 flex w-full flex-col gap-3.5 rounded-[20px] bg-white p-4.5 shadow-[0_12px_36px_rgba(0,0,0,0.09)] border border-[#EAECF0] animate-in fade-in zoom-in-95 duration-150"> |
|||
{options.length > 3 || searchQuery ? ( |
|||
<div className="flex h-[46px] w-full items-center gap-2.5 rounded-[12px] bg-[#EFEFEF] px-3.5 transition-colors focus-within:bg-[#E8E8E8]"> |
|||
<svg |
|||
width="18" |
|||
height="18" |
|||
viewBox="0 0 18 18" |
|||
fill="none" |
|||
className="shrink-0 text-[#667085]" |
|||
> |
|||
<path |
|||
d="M8.25 14.25C11.5637 14.25 14.25 11.5637 14.25 8.25C14.25 4.93629 11.5637 2.25 8.25 2.25C4.93629 2.25 2.25 4.93629 2.25 8.25C2.25 11.5637 4.93629 14.25 8.25 14.25Z" |
|||
stroke="#667085" |
|||
strokeWidth="1.75" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
/> |
|||
<path |
|||
d="M15.75 15.75L12.5 12.5" |
|||
stroke="#667085" |
|||
strokeWidth="1.75" |
|||
strokeLinecap="round" |
|||
strokeLinejoin="round" |
|||
/> |
|||
</svg> |
|||
<input |
|||
ref={searchInputRef} |
|||
type="text" |
|||
value={searchQuery} |
|||
onChange={(e) => setSearchQuery(e.target.value)} |
|||
placeholder="Search..." |
|||
className="flex-1 bg-transparent text-[14px] font-medium text-[#181818] outline-none placeholder:text-[#98A2B3]" |
|||
/> |
|||
{searchQuery ? ( |
|||
<button |
|||
type="button" |
|||
onClick={() => setSearchQuery("")} |
|||
className="text-[#667085] hover:text-[#181818] text-xs font-semibold" |
|||
> |
|||
✕ |
|||
</button> |
|||
) : null} |
|||
</div> |
|||
) : null} |
|||
|
|||
<div |
|||
ref={listRef} |
|||
onWheel={handleListWheel} |
|||
onTouchStart={(e) => e.stopPropagation()} |
|||
onTouchMove={(e) => e.stopPropagation()} |
|||
onTouchEnd={(e) => e.stopPropagation()} |
|||
className="flex max-h-[220px] flex-col gap-3.5 overflow-y-auto overscroll-contain pr-1" |
|||
> |
|||
{filteredOptions.length > 0 ? ( |
|||
filteredOptions.map((option) => { |
|||
const isSelected = selectedCountry === option; |
|||
|
|||
return ( |
|||
<button |
|||
key={option} |
|||
type="button" |
|||
onClick={() => handleSelectCountry(option)} |
|||
className="flex w-full items-center gap-3 text-start cursor-pointer group/opt py-0.5" |
|||
> |
|||
<div |
|||
className={[ |
|||
"size-[20px] shrink-0 rounded-full transition-all duration-150", |
|||
isSelected |
|||
? "bg-[#F2465F] shadow-xs" |
|||
: "border-[2px] border-[#344054] bg-transparent group-hover/opt:border-[#181818]", |
|||
].join(" ")} |
|||
/> |
|||
<span className="text-[15px] font-bold text-[#181818]"> |
|||
{option} |
|||
</span> |
|||
</button> |
|||
); |
|||
}) |
|||
) : ( |
|||
<span className="py-2 text-[13px] text-[#667085]"> |
|||
No options found |
|||
</span> |
|||
)} |
|||
</div> |
|||
</div> |
|||
)} |
|||
</div> |
|||
|
|||
{/* 2. City Text Input */} |
|||
<div className="w-full"> |
|||
<input |
|||
type="text" |
|||
disabled={disabled} |
|||
value={cityInput} |
|||
onChange={handleCityChange} |
|||
placeholder={cityPlaceholder} |
|||
className="h-[54px] w-full rounded-[16px] border border-[#D0D5DD] bg-white px-4.5 text-[15px] font-medium text-[#181818] placeholder:text-[#98A2B3] hover:border-[#98A2B3] focus:border-[#6F6F6F] focus:ring-1 focus:ring-[#6F6F6F] outline-none transition-all" |
|||
/> |
|||
</div> |
|||
</> |
|||
)} |
|||
</div> |
|||
); |
|||
} |
|||
|
|||
export default QuestionBirthplace; |
|||
@ -1 +1,4 @@ |
|||
export { DevClickToComponent, default } from "@/components/dev/dev-click-to-component"; |
|||
export { |
|||
DevClickToComponent, |
|||
default, |
|||
} from "@/components/dev/dev-click-to-component"; |
|||
2024
src/data/cattell-fallback.ts
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,401 @@ |
|||
export const COUNTRIES_EN = [ |
|||
"Afghanistan", |
|||
"Albania", |
|||
"Algeria", |
|||
"Andorra", |
|||
"Angola", |
|||
"Antigua and Barbuda", |
|||
"Argentina", |
|||
"Armenia", |
|||
"Australia", |
|||
"Austria", |
|||
"Azerbaijan", |
|||
"Bahamas", |
|||
"Bahrain", |
|||
"Bangladesh", |
|||
"Barbados", |
|||
"Belarus", |
|||
"Belgium", |
|||
"Belize", |
|||
"Benin", |
|||
"Bhutan", |
|||
"Bolivia", |
|||
"Bosnia and Herzegovina", |
|||
"Botswana", |
|||
"Brazil", |
|||
"Brunei", |
|||
"Bulgaria", |
|||
"Burkina Faso", |
|||
"Burundi", |
|||
"Cabo Verde", |
|||
"Cambodia", |
|||
"Cameroon", |
|||
"Canada", |
|||
"Central African Republic", |
|||
"Chad", |
|||
"Chile", |
|||
"China", |
|||
"Colombia", |
|||
"Comoros", |
|||
"Congo", |
|||
"Costa Rica", |
|||
"Croatia", |
|||
"Cuba", |
|||
"Cyprus", |
|||
"Czechia", |
|||
"Democratic Republic of the Congo", |
|||
"Denmark", |
|||
"Djibouti", |
|||
"Dominica", |
|||
"Dominican Republic", |
|||
"Ecuador", |
|||
"Egypt", |
|||
"El Salvador", |
|||
"Equatorial Guinea", |
|||
"Eritrea", |
|||
"Estonia", |
|||
"Eswatini", |
|||
"Ethiopia", |
|||
"Fiji", |
|||
"Finland", |
|||
"France", |
|||
"Gabon", |
|||
"Gambia", |
|||
"Georgia", |
|||
"Germany", |
|||
"Ghana", |
|||
"Greece", |
|||
"Grenada", |
|||
"Guatemala", |
|||
"Guinea", |
|||
"Guinea-Bissau", |
|||
"Guyana", |
|||
"Haiti", |
|||
"Holy See", |
|||
"Honduras", |
|||
"Hungary", |
|||
"Iceland", |
|||
"India", |
|||
"Indonesia", |
|||
"Iran", |
|||
"Iraq", |
|||
"Ireland", |
|||
"Italy", |
|||
"Ivory Coast", |
|||
"Jamaica", |
|||
"Japan", |
|||
"Jordan", |
|||
"Kazakhstan", |
|||
"Kenya", |
|||
"Kiribati", |
|||
"Kuwait", |
|||
"Kyrgyzstan", |
|||
"Laos", |
|||
"Latvia", |
|||
"Lebanon", |
|||
"Lesotho", |
|||
"Liberia", |
|||
"Libya", |
|||
"Liechtenstein", |
|||
"Lithuania", |
|||
"Luxembourg", |
|||
"Madagascar", |
|||
"Malawi", |
|||
"Malaysia", |
|||
"Maldives", |
|||
"Mali", |
|||
"Malta", |
|||
"Marshall Islands", |
|||
"Mauritania", |
|||
"Mauritius", |
|||
"Mexico", |
|||
"Micronesia", |
|||
"Moldova", |
|||
"Monaco", |
|||
"Mongolia", |
|||
"Montenegro", |
|||
"Morocco", |
|||
"Mozambique", |
|||
"Myanmar", |
|||
"Namibia", |
|||
"Nauru", |
|||
"Nepal", |
|||
"Netherlands", |
|||
"New Zealand", |
|||
"Nicaragua", |
|||
"Niger", |
|||
"Nigeria", |
|||
"North Korea", |
|||
"North Macedonia", |
|||
"Norway", |
|||
"Oman", |
|||
"Pakistan", |
|||
"Palau", |
|||
"Palestine State", |
|||
"Panama", |
|||
"Papua New Guinea", |
|||
"Paraguay", |
|||
"Peru", |
|||
"Philippines", |
|||
"Poland", |
|||
"Portugal", |
|||
"Qatar", |
|||
"Romania", |
|||
"Russia", |
|||
"Rwanda", |
|||
"Saint Kitts and Nevis", |
|||
"Saint Lucia", |
|||
"Saint Vincent and the Grenadines", |
|||
"Samoa", |
|||
"San Marino", |
|||
"Sao Tome and Principe", |
|||
"Saudi Arabia", |
|||
"Senegal", |
|||
"Serbia", |
|||
"Seychelles", |
|||
"Sierra Leone", |
|||
"Singapore", |
|||
"Slovakia", |
|||
"Slovenia", |
|||
"Solomon Islands", |
|||
"Somalia", |
|||
"South Africa", |
|||
"South Korea", |
|||
"South Sudan", |
|||
"Spain", |
|||
"Sri Lanka", |
|||
"Sudan", |
|||
"Suriname", |
|||
"Sweden", |
|||
"Switzerland", |
|||
"Syria", |
|||
"Tajikistan", |
|||
"Tanzania", |
|||
"Thailand", |
|||
"Timor-Leste", |
|||
"Togo", |
|||
"Tonga", |
|||
"Trinidad and Tobago", |
|||
"Tunisia", |
|||
"Turkey", |
|||
"Turkmenistan", |
|||
"Tuvalu", |
|||
"Uganda", |
|||
"Ukraine", |
|||
"United Arab Emirates (UAE)", |
|||
"United Kingdom (UK)", |
|||
"United States (US)", |
|||
"Uruguay", |
|||
"Uzbekistan", |
|||
"Vanuatu", |
|||
"Venezuela", |
|||
"Vietnam", |
|||
"Yemen", |
|||
"Zambia", |
|||
"Zimbabwe", |
|||
]; |
|||
|
|||
export const COUNTRIES_FA = [ |
|||
"افغانستان", |
|||
"آلبانی", |
|||
"الجزایر", |
|||
"آندورا", |
|||
"آنگولا", |
|||
"آنتیگوا و باربودا", |
|||
"آرژانتین", |
|||
"ارمنستان", |
|||
"استرالیا", |
|||
"اتریش", |
|||
"آذربایجان", |
|||
"باهاما", |
|||
"بحرین", |
|||
"بنگلادش", |
|||
"باربادوس", |
|||
"بلاروس", |
|||
"بلژیک", |
|||
"بلیز", |
|||
"بنین", |
|||
"بوتان", |
|||
"بولیوی", |
|||
"بوسنی و هرزگوین", |
|||
"بوتسوانا", |
|||
"برزیل", |
|||
"برونئی", |
|||
"بلغارستان", |
|||
"بورکینافاسو", |
|||
"بوروندی", |
|||
"کیپ ورد", |
|||
"کامبوج", |
|||
"کامرون", |
|||
"کانادا", |
|||
"جمهوری آفریقای مرکزی", |
|||
"چاد", |
|||
"شیلی", |
|||
"چین", |
|||
"کلمبیا", |
|||
"کومور", |
|||
"کنگو", |
|||
"کاستاریکا", |
|||
"کرواسی", |
|||
"کوبا", |
|||
"قبرس", |
|||
"جمهوری چک", |
|||
"جمهوری دموکراتیک کنگو", |
|||
"دانمارک", |
|||
"جیبوتی", |
|||
"دومینیکا", |
|||
"جمهوری دومینیکن", |
|||
"اکوادور", |
|||
"مصر", |
|||
"السالوادور", |
|||
"گینه استوایی", |
|||
"اریتره", |
|||
"استونی", |
|||
"اسواتینی", |
|||
"اتیوپی", |
|||
"فیجی", |
|||
"فنلاند", |
|||
"فرانسه", |
|||
"گابن", |
|||
"Gambia", |
|||
"گرجستان", |
|||
"آلمان", |
|||
"غنا", |
|||
"یونان", |
|||
"گرنادا", |
|||
"گواتمالا", |
|||
"گینه", |
|||
"گینه بیسائو", |
|||
"گویان", |
|||
"هایتی", |
|||
"واتیکان", |
|||
"هندوراس", |
|||
"مجارستان", |
|||
"ایسلند", |
|||
"هند", |
|||
"اندونزی", |
|||
"ایران", |
|||
"عراق", |
|||
"ایرلند", |
|||
"ایتالیا", |
|||
"ساحل عاج", |
|||
"جامائیکا", |
|||
"ژاپن", |
|||
"اردن", |
|||
"قزاقستان", |
|||
"کنیا", |
|||
"کیریباتی", |
|||
"کویت", |
|||
"قرقیزستان", |
|||
"لائوس", |
|||
"لتونی", |
|||
"لبنان", |
|||
"لسوتو", |
|||
"لیبریا", |
|||
"لیبی", |
|||
"لیختناشتاین", |
|||
"لیتوانی", |
|||
"لوکزامبورگ", |
|||
"ماداگاسکار", |
|||
"مالاوی", |
|||
"مالزی", |
|||
"مالدیو", |
|||
"مالی", |
|||
"مالت", |
|||
"جزایر مارشال", |
|||
"موریتانی", |
|||
"موریس", |
|||
"مکزیک", |
|||
"میکرونزی", |
|||
"مولداوی", |
|||
"موناکو", |
|||
"مغولستان", |
|||
"مونتهنگرو", |
|||
"مراکش", |
|||
"موزامبیک", |
|||
"میانمار", |
|||
"نامیبیا", |
|||
"نائورو", |
|||
"نپال", |
|||
"هلند", |
|||
"نیوزیلند", |
|||
"نیکاراگوئه", |
|||
"نیجر", |
|||
"نیجریه", |
|||
"کره شمالی", |
|||
"مقدونیه شمالی", |
|||
"نروژ", |
|||
"عمان", |
|||
"پاکستان", |
|||
"پالائو", |
|||
"فلسطین", |
|||
"پاناما", |
|||
"پاپوآ گینه نو", |
|||
"پاراگوئه", |
|||
"پرو", |
|||
"فیلیپین", |
|||
"لهستان", |
|||
"پرتغال", |
|||
"قطر", |
|||
"رومانی", |
|||
"روسیه", |
|||
"رواندا", |
|||
"سنت کیتس و نویس", |
|||
"سنت لوسیا", |
|||
"سنت وینسنت و گرنادینها", |
|||
"ساموآ", |
|||
"سان مارینو", |
|||
"سائوتومه و پرنسیپ", |
|||
"عربستان سعودی", |
|||
"سنگال", |
|||
"صربستان", |
|||
"سیشل", |
|||
"سیرالئون", |
|||
"سنگاپور", |
|||
"اسلواکی", |
|||
"اسلوونی", |
|||
"جزایر سلیمان", |
|||
"سومالی", |
|||
"آفریقای جنوبی", |
|||
"کره جنوبی", |
|||
"سودان جنوبی", |
|||
"اسپانیا", |
|||
"سریلانکا", |
|||
"سودان", |
|||
"سورینام", |
|||
"سوئد", |
|||
"سوئیس", |
|||
"سوریه", |
|||
"تاجیکستان", |
|||
"تانزانیا", |
|||
"تایلند", |
|||
"تیمور شرقی", |
|||
"توگو", |
|||
"تونگا", |
|||
"ترینیداد و توباگو", |
|||
"تونس", |
|||
"ترکیه", |
|||
"ترکمنستان", |
|||
"تووالو", |
|||
"اوگاندا", |
|||
"اوکراین", |
|||
"امارات متحده عربی (UAE)", |
|||
"بریتانیا (UK)", |
|||
"ایالات متحده آمریکا (US)", |
|||
"اروگوئه", |
|||
"ازبکستان", |
|||
"وانواتو", |
|||
"ونزوئلا", |
|||
"ویتنام", |
|||
"یمن", |
|||
"زامبیا", |
|||
"زیمبابوه", |
|||
]; |
|||
|
|||
export function getCountryList(locale: string): string[] { |
|||
const normalized = String(locale || "en").toLowerCase(); |
|||
if (normalized === "fa" || normalized === "fa-ir") { |
|||
return COUNTRIES_FA; |
|||
} |
|||
return COUNTRIES_EN; |
|||
} |
|||
@ -0,0 +1,157 @@ |
|||
export const LANGUAGES_EN = [ |
|||
"Afrikaans", |
|||
"Albanian", |
|||
"Amharic", |
|||
"Arabic", |
|||
"Armenian", |
|||
"Azerbaijani", |
|||
"Bengali", |
|||
"Bosnian", |
|||
"Bulgarian", |
|||
"Burmese", |
|||
"Catalan", |
|||
"Chinese", |
|||
"Croatian", |
|||
"Czech", |
|||
"Danish", |
|||
"Dutch", |
|||
"English", |
|||
"Estonian", |
|||
"Finnish", |
|||
"French", |
|||
"Georgian", |
|||
"German", |
|||
"Greek", |
|||
"Gujarati", |
|||
"Hausa", |
|||
"Hebrew", |
|||
"Hindi", |
|||
"Hungarian", |
|||
"Icelandic", |
|||
"Indonesian", |
|||
"Irish", |
|||
"Italian", |
|||
"Japanese", |
|||
"Kashmiri", |
|||
"Kazakh", |
|||
"Khmer", |
|||
"Korean", |
|||
"Kyrgyz", |
|||
"Latvian", |
|||
"Lithuanian", |
|||
"Macedonian", |
|||
"Malay", |
|||
"Maltese", |
|||
"Mongolian", |
|||
"Nepali", |
|||
"Norwegian", |
|||
"Pashto", |
|||
"Persian (Farsi)", |
|||
"Polish", |
|||
"Portuguese", |
|||
"Punjabi", |
|||
"Romanian", |
|||
"Russian", |
|||
"Serbian", |
|||
"Sinhala", |
|||
"Slovak", |
|||
"Slovenian", |
|||
"Somali", |
|||
"Spanish", |
|||
"Swahili", |
|||
"Swedish", |
|||
"Tajik", |
|||
"Tamil", |
|||
"Telugu", |
|||
"Thai", |
|||
"Turkish", |
|||
"Turkmen", |
|||
"Ukrainian", |
|||
"Urdu", |
|||
"Urdu Roman (Latin)", |
|||
"Uzbek", |
|||
"Vietnamese", |
|||
"Other", |
|||
]; |
|||
|
|||
export const LANGUAGES_FA = [ |
|||
"آذربایجانی", |
|||
"آفریکانس", |
|||
"آلمانی", |
|||
"آلبانیایی", |
|||
"امهری", |
|||
"اردو", |
|||
"اردو (لاتین)", |
|||
"ارمنی", |
|||
"ازبکی", |
|||
"اسپانیایی", |
|||
"استونیایی", |
|||
"اسلواکی", |
|||
"اسلوونیایی", |
|||
"انگلیسی", |
|||
"اندونزیایی", |
|||
"اوکراینی", |
|||
"ایتالیایی", |
|||
"ایرلندی", |
|||
"ایسلندی", |
|||
"بنگالی", |
|||
"بوسنیایی", |
|||
"بلغاری", |
|||
"پشتو", |
|||
"پنجابی", |
|||
"پرتغالی", |
|||
"تاجیکی", |
|||
"تامیلی", |
|||
"تایلندی", |
|||
"تلوگو", |
|||
"ترکی", |
|||
"ترکمنی", |
|||
"چکی", |
|||
"چینی", |
|||
"دانمارکی", |
|||
"روسی", |
|||
"رومانیایی", |
|||
"ژاپنی", |
|||
"سواحیلی", |
|||
"سوئدی", |
|||
"سینهالی", |
|||
"صربی", |
|||
"سومالیایی", |
|||
"عربی", |
|||
"عبری", |
|||
"فارسی", |
|||
"فرانسوی", |
|||
"فنلاندی", |
|||
"قزاقی", |
|||
"قرقیزی", |
|||
"کاتالان", |
|||
"کرهای", |
|||
"کرواتی", |
|||
"کشمیری", |
|||
"گجراتی", |
|||
"گرجی", |
|||
"لتونیایی", |
|||
"لیتوانیایی", |
|||
"لهستانی", |
|||
"مالایی", |
|||
"مالتی", |
|||
"مجاری", |
|||
"مقدونیهای", |
|||
"مغولی", |
|||
"میانماری (برمهای)", |
|||
"نپالی", |
|||
"نروژی", |
|||
"هلندی", |
|||
"ویتنامی", |
|||
"هندی", |
|||
"هوسا", |
|||
"سایر", |
|||
]; |
|||
|
|||
export function getLanguageList(locale: string): string[] { |
|||
const normalized = String(locale || "en").toLowerCase(); |
|||
if (normalized === "fa" || normalized === "fa-ir") { |
|||
return LANGUAGES_FA; |
|||
} |
|||
return LANGUAGES_EN; |
|||
} |
|||
@ -0,0 +1,283 @@ |
|||
export const NATIONALITIES_EN = [ |
|||
"Afghan", |
|||
"Albanian", |
|||
"Algerian", |
|||
"American (US)", |
|||
"Andorran", |
|||
"Angolan", |
|||
"Antiguan", |
|||
"Argentinian", |
|||
"Armenian", |
|||
"Australian", |
|||
"Austrian", |
|||
"Azerbaijani", |
|||
"Bahamian", |
|||
"Bahraini", |
|||
"Bangladeshi", |
|||
"Barbadian", |
|||
"Belarusian", |
|||
"Belgian", |
|||
"Belizean", |
|||
"Beninese", |
|||
"Bhutanese", |
|||
"Bolivian", |
|||
"Bosnian", |
|||
"Botswanan", |
|||
"Brazilian", |
|||
"British (UK)", |
|||
"Bruneian", |
|||
"Bulgarian", |
|||
"Burkinabè", |
|||
"Burmese", |
|||
"Burundian", |
|||
"Cabo Verdean", |
|||
"Cambodian", |
|||
"Cameroonian", |
|||
"Canadian", |
|||
"Central African", |
|||
"Chadian", |
|||
"Chilean", |
|||
"Chinese", |
|||
"Colombian", |
|||
"Comorian", |
|||
"Congolese", |
|||
"Costa Rican", |
|||
"Croatian", |
|||
"Cuban", |
|||
"Cypriot", |
|||
"Czech", |
|||
"Danish", |
|||
"Djiboutian", |
|||
"Dominican", |
|||
"Dutch", |
|||
"Ecuadorian", |
|||
"Egyptian", |
|||
"Emirati (UAE)", |
|||
"Equatorial Guinean", |
|||
"Eritrean", |
|||
"Estonian", |
|||
"Ethiopian", |
|||
"Fijian", |
|||
"Filipino", |
|||
"Finnish", |
|||
"French", |
|||
"Gabonese", |
|||
"Gambian", |
|||
"Georgian", |
|||
"German", |
|||
"Ghanaian", |
|||
"Greek", |
|||
"Grenadian", |
|||
"Guatemalan", |
|||
"Guinean", |
|||
"Guyanese", |
|||
"Haitian", |
|||
"Honduran", |
|||
"Hungarian", |
|||
"Icelandic", |
|||
"Indian", |
|||
"Indonesian", |
|||
"Iranian", |
|||
"Iraqi", |
|||
"Irish", |
|||
"Italian", |
|||
"Ivorian", |
|||
"Jamaican", |
|||
"Japanese", |
|||
"Jordanian", |
|||
"Kazakhstani", |
|||
"Kenyan", |
|||
"Kuwaiti", |
|||
"Kyrgyzstani", |
|||
"Laotian", |
|||
"Latvian", |
|||
"Lebanese", |
|||
"Liberian", |
|||
"Libyan", |
|||
"Liechtensteiner", |
|||
"Lithuanian", |
|||
"Luxembourger", |
|||
"Macedonian", |
|||
"Malagasy", |
|||
"Malawian", |
|||
"Malaysian", |
|||
"Maldivian", |
|||
"Malian", |
|||
"Maltese", |
|||
"Mauritanian", |
|||
"Mauritian", |
|||
"Mexican", |
|||
"Micronesian", |
|||
"Moldovan", |
|||
"Monégasque", |
|||
"Mongolian", |
|||
"Montenegrin", |
|||
"Moroccan", |
|||
"Mozambican", |
|||
"Namibian", |
|||
"Nauruan", |
|||
"Nepalese", |
|||
"New Zealander", |
|||
"Nicaraguan", |
|||
"Nigerien", |
|||
"Nigerian", |
|||
"North Korean", |
|||
"Norwegian", |
|||
"Omani", |
|||
"Pakistani", |
|||
"Palestinian", |
|||
"Panamanian", |
|||
"Papua New Guinean", |
|||
"Paraguayan", |
|||
"Peruvian", |
|||
"Polish", |
|||
"Portuguese", |
|||
"Qatari", |
|||
"Romanian", |
|||
"Russian", |
|||
"Rwandan", |
|||
"Saudi", |
|||
"Senegalese", |
|||
"Serbian", |
|||
"Seychellois", |
|||
"Sierra Leonean", |
|||
"Singaporean", |
|||
"Slovak", |
|||
"Slovenian", |
|||
"Somali", |
|||
"South African", |
|||
"South Korean", |
|||
"Spanish", |
|||
"Sri Lankan", |
|||
"Sudanese", |
|||
"Surinamese", |
|||
"Swazi", |
|||
"Swedish", |
|||
"Swiss", |
|||
"Syrian", |
|||
"Tajikistani", |
|||
"Tanzanian", |
|||
"Thai", |
|||
"Togolese", |
|||
"Tongan", |
|||
"Tunisian", |
|||
"Turkish", |
|||
"Turkmen", |
|||
"Ugandan", |
|||
"Ukrainian", |
|||
"Uruguayan", |
|||
"Uzbekistani", |
|||
"Venezuelan", |
|||
"Vietnamese", |
|||
"Yemeni", |
|||
"Zambian", |
|||
"Zimbabwean", |
|||
"Other", |
|||
]; |
|||
|
|||
export const NATIONALITIES_FA = [ |
|||
"آذربایجانی", |
|||
"آرژانتینی", |
|||
"آلمانی", |
|||
"آلبانیایی", |
|||
"آمریکایی (US)", |
|||
"آندورایی", |
|||
"آنگولایی", |
|||
"اتریشی", |
|||
"اتیوپیایی", |
|||
"ارمنی", |
|||
"اردنی", |
|||
"اروگوئهای", |
|||
"ازبکستانی", |
|||
"اسپانیایی", |
|||
"استرالیایی", |
|||
"استونیایی", |
|||
"اسلواکی", |
|||
"اسلوونیایی", |
|||
"افغانستانی", |
|||
"الجزایری", |
|||
"اماراتی (UAE)", |
|||
"اندونزیایی", |
|||
"انگلیسی", |
|||
"ایتالیایی", |
|||
"ایرانی", |
|||
"ایرلندی", |
|||
"بحرینی", |
|||
"برزیلی", |
|||
"بریتانیایی (UK)", |
|||
"بلغارستانی", |
|||
"بنگلادشی", |
|||
"بلژیکی", |
|||
"بلاروسی", |
|||
"بوسنیایی", |
|||
"پاکستانی", |
|||
"پرتغالی", |
|||
"پروایی", |
|||
"تاجیکستانی", |
|||
"تایلندی", |
|||
"ترکیهای", |
|||
"تونسی", |
|||
"چکی", |
|||
"چینی", |
|||
"دانمارکی", |
|||
"روسی", |
|||
"رومانیایی", |
|||
"ژاپنی", |
|||
"سریلانکایی", |
|||
"سعودی", |
|||
"سنگاپوری", |
|||
"سوری", |
|||
"سومالیایی", |
|||
"سوئدی", |
|||
"سوئیسی", |
|||
"شیلیایی", |
|||
"عراقی", |
|||
"عربستانی", |
|||
"عمانی", |
|||
"فرانسوی", |
|||
"فلسطینی", |
|||
"فیلیپینی", |
|||
"فنلاندی", |
|||
"قزاقستانی", |
|||
"قطری", |
|||
"قرقیزستانی", |
|||
"کره جنوبی", |
|||
"کره شمالی", |
|||
"کلمبیایی", |
|||
"کامرونی", |
|||
"کانادایی", |
|||
"کنگویی", |
|||
"کوبایی", |
|||
"کویتی", |
|||
"کنیایی", |
|||
"گرجستانی", |
|||
"لبنانی", |
|||
"لهستانی", |
|||
"لیبیایی", |
|||
"لیتوانیایی", |
|||
"مالزیایی", |
|||
"مالدیوی", |
|||
"مراکشی", |
|||
"مصر", |
|||
"مکزیکی", |
|||
"مولداویایی", |
|||
"مغولی", |
|||
"نامیبیاایی", |
|||
"نپالی", |
|||
"نروژی", |
|||
"نیوزیلندی", |
|||
"نیجریهای", |
|||
"هلندی", |
|||
"ونزوئلایی", |
|||
"ویتنامی", |
|||
"یمنی", |
|||
"سایر", |
|||
]; |
|||
|
|||
export function getNationalityList(locale: string): string[] { |
|||
const normalized = String(locale || "en").toLowerCase(); |
|||
if (normalized === "fa" || normalized === "fa-ir") { |
|||
return NATIONALITIES_FA; |
|||
} |
|||
return NATIONALITIES_EN; |
|||
} |
|||
660
src/data/questions/en.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
660
src/data/questions/fa.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue