import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Group, Select, Text, type ComboboxItem, type SelectProps } from '@mantine/core';
import { registerLocale, getNames, getName } from 'i18n-iso-countries';
import * as Flags from 'country-flag-icons/react/3x2';
import en from 'i18n-iso-countries/langs/en.json';
import am from 'i18n-iso-countries/langs/am.json';
// Registered once at module load — locale data is static.
registerLocale(en);
registerLocale(am);
type CountryLang = 'en' | 'am';
function resolveLang(lng: string): CountryLang {
return lng === 'am' ? 'am' : 'en';
}
/** Localized country name for an alpha-2 code; '' when unset/unknown. */
export function getCountryName(code: string | null | undefined, lang: CountryLang = 'en'): string {
return code ? (getName(code, lang) ?? '') : '';
}
function CountryFlag({ code }: { code: string }) {
const Flag = Flags[code as keyof typeof Flags];
return Flag ? : null;
}
// Case-insensitive substring on name, plus ISO code prefix ("et" → Ethiopia).
const filterCountries: SelectProps['filter'] = ({ options, search }) => {
const q = search.trim().toLowerCase();
if (!q) return options;
return (options as ComboboxItem[]).filter(
(o) => o.label.toLowerCase().includes(q) || o.value.toLowerCase().startsWith(q),
);
};
// Module scope → stable reference, no re-render churn.
const renderCountryOption: SelectProps['renderOption'] = ({ option }) => (
{option.label}
);
export interface CountrySelectProps {
value: string | null;
onChange: (value: string | null) => void;
label?: string;
placeholder?: string;
description?: React.ReactNode;
error?: React.ReactNode;
required?: boolean;
disabled?: boolean;
}
export function CountrySelect({
value,
onChange,
placeholder,
...rest
}: CountrySelectProps) {
const { t, i18n } = useTranslation();
const lang = resolveLang(i18n.language);
const countries = useMemo(
() =>
Object.entries(getNames(lang))
.map(([code, label]) => ({ value: code, label }))
.sort((a, b) => a.label.localeCompare(b.label, lang)),
[lang],
);
return (
: undefined}
renderOption={renderCountryOption}
filter={filterCountries}
nothingFoundMessage={t('country.notFound')}
searchable
clearable
maxDropdownHeight={320}
{...rest}
/>
);
}