forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {Fragment, useMemo} from 'react'
2import {Image} from 'expo-image'
3import {msg} from '@lingui/macro'
4import {useLingui} from '@lingui/react'
5
6import {
7 type CountryCode,
8 getDefaultCountry,
9 INTERNATIONAL_TELEPHONE_CODES,
10} from '#/lib/international-telephone-codes'
11import {regionName} from '#/locale/helpers'
12import {isWeb} from '#/platform/detection'
13import {atoms as a, web} from '#/alf'
14import * as Select from '#/components/Select'
15import {useGeolocation} from '#/geolocation'
16
17/**
18 * Country picker for a phone number input
19 *
20 * Pro tip: you can use `location?.countryCode` from `useGeolocationStatus()`
21 * to set a default value.
22 */
23export function InternationalPhoneCodeSelect({
24 value,
25 onChange,
26}: {
27 value?: CountryCode
28 onChange: (value: CountryCode) => void
29}) {
30 const {_, i18n} = useLingui()
31 const location = useGeolocation()
32
33 const defaultCountry = useMemo(() => {
34 return getDefaultCountry(location)
35 }, [location])
36
37 const items = useMemo(() => {
38 return (
39 Object.entries(INTERNATIONAL_TELEPHONE_CODES)
40 .map(([value, {code, unicodeFlag, svgFlag}]) => {
41 const name = regionName(value, i18n.locale)
42
43 return {
44 value,
45 name,
46 code,
47 label: `${name} ${code}`,
48 unicodeFlag,
49 svgFlag,
50 }
51 })
52 // boost the default value to the top, then sort by name
53 .sort((a, b) => {
54 if (a.value === defaultCountry) return -1
55 if (b.value === defaultCountry) return 1
56 return a.name.localeCompare(b.name)
57 })
58 )
59 }, [i18n.locale, defaultCountry])
60
61 const selected = useMemo(() => {
62 return items.find(item => item.value === value)
63 }, [value, items])
64
65 return (
66 <Select.Root value={value} onValueChange={onChange as (v: string) => void}>
67 <Select.Trigger label={_(msg`Select telephone code`)}>
68 <Select.ValueText placeholder="+..." webOverrideValue={selected}>
69 {selected => (
70 <>
71 <Flag {...selected} />
72 {selected.code}
73 </>
74 )}
75 </Select.ValueText>
76 <Select.Icon />
77 </Select.Trigger>
78 <Select.Content
79 label={_(msg`Country code`)}
80 items={items}
81 renderItem={item => (
82 <Fragment key={item.value}>
83 <Select.Item value={item.value} label={item.label}>
84 <Select.ItemIndicator />
85 <Select.ItemText style={[a.flex_1]} emoji>
86 {isWeb ? <Flag {...item} /> : item.unicodeFlag + ' '}
87 {item.name}
88 </Select.ItemText>
89 <Select.ItemText style={[a.text_right]}>
90 {' '}
91 {item.code}
92 </Select.ItemText>
93 </Select.Item>
94 {item.value === defaultCountry && <Select.Separator />}
95 </Fragment>
96 )}
97 />
98 </Select.Root>
99 )
100}
101
102function Flag({unicodeFlag, svgFlag}: {unicodeFlag: string; svgFlag: any}) {
103 if (isWeb) {
104 return (
105 <Image
106 source={svgFlag}
107 style={[
108 a.rounded_2xs,
109 {height: 13, aspectRatio: 4 / 3, marginRight: 6},
110 web({verticalAlign: 'bottom'}),
111 ]}
112 accessibilityIgnoresInvertColors
113 />
114 )
115 }
116 return unicodeFlag + ' '
117}