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
-
2src/app/api/remote-logs/route.ts
-
29src/app/api/remote-network/route.ts
-
6src/app/finding-match/page.tsx
-
21src/app/globals.css
-
19src/app/intro/page.tsx
-
5src/app/layout.tsx
-
45src/app/new-match/page.tsx
-
10src/app/new-match/profile/page.tsx
-
12src/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
-
53src/app/request-accepted/page.tsx
-
21src/app/request-sent/page.tsx
-
159src/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
-
29src/components/questions/question-number.tsx
-
350src/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
-
37src/components/questions/question-snap-list.tsx
-
11src/components/questions/question-text.tsx
-
11src/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
-
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
-
2src/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
-
658src/data/questions/en.json
-
658src/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
-
104src/hooks/useFlutterBridge.ts
-
11src/lib/auth-bridge.ts
-
6src/lib/http.ts
-
18src/lib/performance.ts
-
18src/lib/view-paddings.ts
-
4src/plugins/jsx-locator-loader.cjs
-
5src/translations/dictionaries.ts
-
2src/translations/locales/ar.json
-
2src/translations/locales/az.json
-
2src/translations/locales/bn.json
-
2src/translations/locales/da.json
-
2src/translations/locales/de.json
-
2src/translations/locales/en.json
-
2src/translations/locales/es.json
-
2src/translations/locales/fa.json
-
2src/translations/locales/fr.json
-
2src/translations/locales/gu.json
-
2src/translations/locales/ha.json
-
2src/translations/locales/he.json
-
2src/translations/locales/hi.json
-
2src/translations/locales/id.json
-
2src/translations/locales/ks.json
-
2src/translations/locales/pt.json
-
2src/translations/locales/ru.json
-
2src/translations/locales/sw.json
-
2src/translations/locales/tg.json
-
2src/translations/locales/tr.json
-
2src/translations/locales/ul.json
-
2src/translations/locales/ur.json
-
2src/translations/locales/uz.json
-
2src/translations/locales/zh.json
-
6src/translations/provider.tsx
-
2src/view-paddings.ts
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; |
|||
} |
|||
658
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
658
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
@ -1,7 +1,7 @@ |
|||
export { FixedBottom } from "./components/utils/fixed-bottom"; |
|||
export { useFlutterConfig, useViewPaddings } from "./hooks/use-view-paddings"; |
|||
export { |
|||
type InitialConfig, |
|||
type ViewPaddings, |
|||
viewPaddingsBridge, |
|||
} from "./lib/view-paddings"; |
|||
export { FixedBottom } from "./components/utils/fixed-bottom"; |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue