react-native-country-select 0.2.6 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -23
- package/lib/assets/images/preview.png +0 -0
- package/lib/components/AlphabeticFilter/index.tsx +180 -0
- package/lib/components/BottomSheetModal/index.tsx +223 -0
- package/lib/components/CloseButton/index.tsx +38 -0
- package/lib/components/CountryItem/index.tsx +27 -19
- package/lib/components/CountrySelect/index.tsx +297 -498
- package/lib/components/FullscreenModal/index.tsx +85 -0
- package/lib/components/PopupModal/index.tsx +77 -0
- package/lib/components/SearchInput/index.tsx +47 -0
- package/lib/components/index.ts +0 -1
- package/lib/components/styles.js +41 -1
- package/lib/interface/alfabeticFilterProps.ts +18 -0
- package/lib/interface/closeButtonProps.ts +12 -0
- package/lib/interface/countryItemProps.ts +4 -3
- package/lib/interface/countrySelectProps.ts +25 -5
- package/lib/interface/countrySelectStyles.ts +7 -0
- package/lib/interface/index.ts +3 -0
- package/lib/interface/searchInputProps.ts +16 -0
- package/lib/interface/theme.ts +3 -0
- package/lib/utils/createAlphabet.ts +3 -0
- package/lib/utils/getCountriesList.ts +100 -0
- package/lib/utils/getCountryNameInLanguage.ts +8 -0
- package/lib/utils/getTranslation.ts +145 -1
- package/lib/utils/normalizeCountryName.ts +3 -0
- package/lib/utils/sortCountriesAlphabetically.ts +17 -0
- package/package.json +18 -12
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/* eslint-disable react-native/no-inline-styles */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import {
|
|
4
|
+
Modal,
|
|
5
|
+
ModalProps,
|
|
6
|
+
NativeSyntheticEvent,
|
|
7
|
+
Pressable,
|
|
8
|
+
View,
|
|
9
|
+
} from 'react-native';
|
|
10
|
+
|
|
11
|
+
import {ICountrySelectStyle} from '../../interface';
|
|
12
|
+
|
|
13
|
+
interface FullscreenModalProps extends ModalProps {
|
|
14
|
+
visible: boolean;
|
|
15
|
+
onRequestClose: (event: NativeSyntheticEvent<any>) => void;
|
|
16
|
+
statusBarTranslucent?: boolean;
|
|
17
|
+
removedBackdrop?: boolean;
|
|
18
|
+
disabledBackdropPress?: boolean;
|
|
19
|
+
onBackdropPress?: () => void;
|
|
20
|
+
accessibilityLabelBackdrop?: string;
|
|
21
|
+
accessibilityHintBackdrop?: string;
|
|
22
|
+
styles: ICountrySelectStyle;
|
|
23
|
+
countrySelectStyle?: ICountrySelectStyle;
|
|
24
|
+
header?: React.ReactNode;
|
|
25
|
+
children: React.ReactNode;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const FullscreenModal: React.FC<FullscreenModalProps> = ({
|
|
29
|
+
visible,
|
|
30
|
+
onRequestClose,
|
|
31
|
+
statusBarTranslucent,
|
|
32
|
+
removedBackdrop,
|
|
33
|
+
disabledBackdropPress,
|
|
34
|
+
onBackdropPress,
|
|
35
|
+
accessibilityLabelBackdrop,
|
|
36
|
+
accessibilityHintBackdrop,
|
|
37
|
+
styles,
|
|
38
|
+
countrySelectStyle,
|
|
39
|
+
header,
|
|
40
|
+
children,
|
|
41
|
+
...props
|
|
42
|
+
}) => {
|
|
43
|
+
return (
|
|
44
|
+
<Modal
|
|
45
|
+
visible={visible}
|
|
46
|
+
transparent
|
|
47
|
+
animationType="fade"
|
|
48
|
+
onRequestClose={onRequestClose}
|
|
49
|
+
statusBarTranslucent={statusBarTranslucent}
|
|
50
|
+
{...props}>
|
|
51
|
+
<View
|
|
52
|
+
testID="countrySelectContainer"
|
|
53
|
+
style={[
|
|
54
|
+
styles.container,
|
|
55
|
+
countrySelectStyle?.container,
|
|
56
|
+
{flex: 1, width: '100%', height: '100%'},
|
|
57
|
+
]}>
|
|
58
|
+
<Pressable
|
|
59
|
+
testID="countrySelectBackdrop"
|
|
60
|
+
accessibilityRole="button"
|
|
61
|
+
accessibilityLabel={accessibilityLabelBackdrop}
|
|
62
|
+
accessibilityHint={accessibilityHintBackdrop}
|
|
63
|
+
disabled={disabledBackdropPress || removedBackdrop}
|
|
64
|
+
style={[
|
|
65
|
+
styles.backdrop,
|
|
66
|
+
{alignItems: 'center', justifyContent: 'center'},
|
|
67
|
+
countrySelectStyle?.backdrop,
|
|
68
|
+
removedBackdrop && {backgroundColor: 'transparent'},
|
|
69
|
+
]}
|
|
70
|
+
onPress={onBackdropPress || onRequestClose}
|
|
71
|
+
/>
|
|
72
|
+
<View
|
|
73
|
+
testID="countrySelectContent"
|
|
74
|
+
style={[
|
|
75
|
+
styles.content,
|
|
76
|
+
countrySelectStyle?.content,
|
|
77
|
+
{borderRadius: 0, width: '100%', height: '100%'},
|
|
78
|
+
]}>
|
|
79
|
+
{header}
|
|
80
|
+
<View style={{flex: 1, flexDirection: 'row'}}>{children}</View>
|
|
81
|
+
</View>
|
|
82
|
+
</View>
|
|
83
|
+
</Modal>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/* eslint-disable react-native/no-inline-styles */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import {
|
|
4
|
+
Modal,
|
|
5
|
+
ModalProps,
|
|
6
|
+
NativeSyntheticEvent,
|
|
7
|
+
Pressable,
|
|
8
|
+
View,
|
|
9
|
+
} from 'react-native';
|
|
10
|
+
|
|
11
|
+
import {ICountrySelectStyle} from '../../interface';
|
|
12
|
+
|
|
13
|
+
interface PopupModalProps extends ModalProps {
|
|
14
|
+
visible: boolean;
|
|
15
|
+
onRequestClose: (event: NativeSyntheticEvent<any>) => void;
|
|
16
|
+
statusBarTranslucent?: boolean;
|
|
17
|
+
removedBackdrop?: boolean;
|
|
18
|
+
disabledBackdropPress?: boolean;
|
|
19
|
+
onBackdropPress?: () => void;
|
|
20
|
+
accessibilityLabelBackdrop?: string;
|
|
21
|
+
accessibilityHintBackdrop?: string;
|
|
22
|
+
styles: ICountrySelectStyle;
|
|
23
|
+
countrySelectStyle?: ICountrySelectStyle;
|
|
24
|
+
header?: React.ReactNode;
|
|
25
|
+
children: React.ReactNode;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const PopupModal: React.FC<PopupModalProps> = ({
|
|
29
|
+
visible,
|
|
30
|
+
onRequestClose,
|
|
31
|
+
statusBarTranslucent,
|
|
32
|
+
removedBackdrop,
|
|
33
|
+
disabledBackdropPress,
|
|
34
|
+
onBackdropPress,
|
|
35
|
+
accessibilityLabelBackdrop,
|
|
36
|
+
accessibilityHintBackdrop,
|
|
37
|
+
styles,
|
|
38
|
+
countrySelectStyle,
|
|
39
|
+
header,
|
|
40
|
+
children,
|
|
41
|
+
...props
|
|
42
|
+
}) => {
|
|
43
|
+
return (
|
|
44
|
+
<Modal
|
|
45
|
+
visible={visible}
|
|
46
|
+
transparent
|
|
47
|
+
animationType="fade"
|
|
48
|
+
onRequestClose={onRequestClose}
|
|
49
|
+
statusBarTranslucent={statusBarTranslucent}
|
|
50
|
+
{...props}>
|
|
51
|
+
<View
|
|
52
|
+
testID="countrySelectContainer"
|
|
53
|
+
style={[styles.container, countrySelectStyle?.container]}>
|
|
54
|
+
<Pressable
|
|
55
|
+
testID="countrySelectBackdrop"
|
|
56
|
+
accessibilityRole="button"
|
|
57
|
+
accessibilityLabel={accessibilityLabelBackdrop}
|
|
58
|
+
accessibilityHint={accessibilityHintBackdrop}
|
|
59
|
+
disabled={disabledBackdropPress || removedBackdrop}
|
|
60
|
+
style={[
|
|
61
|
+
styles.backdrop,
|
|
62
|
+
{alignItems: 'center', justifyContent: 'center'},
|
|
63
|
+
countrySelectStyle?.backdrop,
|
|
64
|
+
removedBackdrop && {backgroundColor: 'transparent'},
|
|
65
|
+
]}
|
|
66
|
+
onPress={onBackdropPress || onRequestClose}
|
|
67
|
+
/>
|
|
68
|
+
<View
|
|
69
|
+
testID="countrySelectContent"
|
|
70
|
+
style={[styles.content, countrySelectStyle?.content]}>
|
|
71
|
+
{header}
|
|
72
|
+
<View style={{flex: 1, flexDirection: 'row'}}>{children}</View>
|
|
73
|
+
</View>
|
|
74
|
+
</View>
|
|
75
|
+
</Modal>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {TextInput} from 'react-native';
|
|
3
|
+
|
|
4
|
+
import {createStyles} from '../styles';
|
|
5
|
+
import {translations} from '../../utils/getTranslation';
|
|
6
|
+
import {ISearchInputProps, ICountrySelectLanguages} from '../../interface';
|
|
7
|
+
|
|
8
|
+
export const SearchInput: React.FC<ISearchInputProps> = ({
|
|
9
|
+
theme,
|
|
10
|
+
language,
|
|
11
|
+
value,
|
|
12
|
+
onChangeText,
|
|
13
|
+
countrySelectStyle,
|
|
14
|
+
searchPlaceholder,
|
|
15
|
+
searchPlaceholderTextColor,
|
|
16
|
+
searchSelectionColor,
|
|
17
|
+
accessibilityLabelSearchInput,
|
|
18
|
+
accessibilityHintSearchInput,
|
|
19
|
+
}) => {
|
|
20
|
+
const styles = createStyles(theme);
|
|
21
|
+
return (
|
|
22
|
+
<TextInput
|
|
23
|
+
testID="countrySelectSearchInput"
|
|
24
|
+
accessibilityRole="text"
|
|
25
|
+
accessibilityLabel={
|
|
26
|
+
accessibilityLabelSearchInput ||
|
|
27
|
+
translations.accessibilityLabelSearchInput[language]
|
|
28
|
+
}
|
|
29
|
+
accessibilityHint={
|
|
30
|
+
accessibilityHintSearchInput ||
|
|
31
|
+
translations.accessibilityHintSearchInput[language]
|
|
32
|
+
}
|
|
33
|
+
style={[styles.searchInput, countrySelectStyle?.searchInput]}
|
|
34
|
+
placeholder={
|
|
35
|
+
searchPlaceholder ||
|
|
36
|
+
translations.searchPlaceholder[language as ICountrySelectLanguages]
|
|
37
|
+
}
|
|
38
|
+
placeholderTextColor={
|
|
39
|
+
searchPlaceholderTextColor ||
|
|
40
|
+
(theme === 'dark' ? '#FFFFFF80' : '#00000080')
|
|
41
|
+
}
|
|
42
|
+
selectionColor={searchSelectionColor}
|
|
43
|
+
value={value}
|
|
44
|
+
onChangeText={onChangeText}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
};
|
package/lib/components/index.ts
CHANGED
package/lib/components/styles.js
CHANGED
|
@@ -34,7 +34,8 @@ export const createStyles = (theme, modalType, isFullScreen) =>
|
|
|
34
34
|
: {
|
|
35
35
|
marginTop: StatusBar.currentHeight,
|
|
36
36
|
width: '100%',
|
|
37
|
-
|
|
37
|
+
borderTopLeftRadius: 20,
|
|
38
|
+
borderTopRightRadius: 20,
|
|
38
39
|
backgroundColor: theme === 'dark' ? '#202020' : '#FFFFFF',
|
|
39
40
|
},
|
|
40
41
|
dragHandleContainer: {
|
|
@@ -82,6 +83,10 @@ export const createStyles = (theme, modalType, isFullScreen) =>
|
|
|
82
83
|
borderWidth: 1,
|
|
83
84
|
borderRadius: 8,
|
|
84
85
|
},
|
|
86
|
+
countryItemSelected: {
|
|
87
|
+
backgroundColor: 'rgba(33, 150, 243, 0.15)',
|
|
88
|
+
borderColor: '#2196F3',
|
|
89
|
+
},
|
|
85
90
|
flag: {
|
|
86
91
|
flex: 0.1,
|
|
87
92
|
marginRight: 10,
|
|
@@ -106,12 +111,18 @@ export const createStyles = (theme, modalType, isFullScreen) =>
|
|
|
106
111
|
fontSize: 14,
|
|
107
112
|
color: theme === 'dark' ? '#FFFFFF80' : '#00000080',
|
|
108
113
|
},
|
|
114
|
+
callingCodeSelected: {
|
|
115
|
+
color: '#1976D2',
|
|
116
|
+
},
|
|
109
117
|
countryName: {
|
|
110
118
|
flex: 0.8,
|
|
111
119
|
fontSize: 16,
|
|
112
120
|
fontWeight: '500',
|
|
113
121
|
color: theme === 'dark' ? '#FFFFFF' : '#000000',
|
|
114
122
|
},
|
|
123
|
+
countryNameSelected: {
|
|
124
|
+
color: '#1976D2',
|
|
125
|
+
},
|
|
115
126
|
sectionTitle: {
|
|
116
127
|
fontSize: 16,
|
|
117
128
|
fontWeight: '600',
|
|
@@ -142,4 +153,33 @@ export const createStyles = (theme, modalType, isFullScreen) =>
|
|
|
142
153
|
fontSize: 16,
|
|
143
154
|
color: theme === 'dark' ? '#FFFFFF' : '#000000',
|
|
144
155
|
},
|
|
156
|
+
alphabetContainer: {
|
|
157
|
+
marginRight: 16,
|
|
158
|
+
},
|
|
159
|
+
alphabetLetter: {
|
|
160
|
+
width: 24,
|
|
161
|
+
height: 24,
|
|
162
|
+
borderRadius: 12,
|
|
163
|
+
marginVertical: 2,
|
|
164
|
+
alignItems: 'center',
|
|
165
|
+
justifyContent: 'center',
|
|
166
|
+
backgroundColor: 'transparent',
|
|
167
|
+
},
|
|
168
|
+
alphabetLetterActive: {
|
|
169
|
+
backgroundColor: theme === 'dark' ? '#FFFFFF30' : '#00000020',
|
|
170
|
+
},
|
|
171
|
+
alphabetLetterDisabled: {
|
|
172
|
+
opacity: 0.4,
|
|
173
|
+
},
|
|
174
|
+
alphabetLetterText: {
|
|
175
|
+
fontSize: 12,
|
|
176
|
+
color: theme === 'dark' ? '#FFFFFFB3' : '#000000B3',
|
|
177
|
+
fontWeight: '600',
|
|
178
|
+
},
|
|
179
|
+
alphabetLetterTextActive: {
|
|
180
|
+
color: theme === 'dark' ? '#FFFFFF' : '#000000',
|
|
181
|
+
},
|
|
182
|
+
alphabetLetterTextDisabled: {
|
|
183
|
+
color: theme === 'dark' ? '#FFFFFF80' : '#00000080',
|
|
184
|
+
},
|
|
145
185
|
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {IThemeProps} from './theme';
|
|
2
|
+
import {ICountrySelectStyle} from './countrySelectStyles';
|
|
3
|
+
import {ICountrySelectLanguages} from './countrySelectLanguages';
|
|
4
|
+
import {IListItem} from './itemList';
|
|
5
|
+
|
|
6
|
+
export interface AlphabeticFilterProps {
|
|
7
|
+
theme?: IThemeProps;
|
|
8
|
+
activeLetter: string | null;
|
|
9
|
+
onPressLetter: (index: number) => void;
|
|
10
|
+
language: ICountrySelectLanguages;
|
|
11
|
+
countries: IListItem[];
|
|
12
|
+
allCountriesStartIndex: number;
|
|
13
|
+
countrySelectStyle?: ICountrySelectStyle;
|
|
14
|
+
accessibilityLabelAlphabetFilter?: string;
|
|
15
|
+
accessibilityHintAlphabetFilter?: string;
|
|
16
|
+
accessibilityLabelAlphabetLetter?: string;
|
|
17
|
+
accessibilityHintAlphabetLetter?: string;
|
|
18
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {ICountrySelectLanguages} from './countrySelectLanguages';
|
|
2
|
+
import {ICountrySelectStyle} from './countrySelectStyles';
|
|
3
|
+
import {IThemeProps} from './theme';
|
|
4
|
+
|
|
5
|
+
export interface ICloseButtonProps {
|
|
6
|
+
theme?: IThemeProps;
|
|
7
|
+
language: ICountrySelectLanguages;
|
|
8
|
+
onClose: () => void;
|
|
9
|
+
countrySelectStyle?: ICountrySelectStyle;
|
|
10
|
+
accessibilityLabelCloseButton?: string;
|
|
11
|
+
accessibilityHintCloseButton?: string;
|
|
12
|
+
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import {ICountry} from './country';
|
|
2
|
+
import {IThemeProps} from './theme';
|
|
2
3
|
import {ICountrySelectStyle} from './countrySelectStyles';
|
|
3
4
|
import {ICountrySelectLanguages} from './countrySelectLanguages';
|
|
4
5
|
|
|
5
6
|
export interface ICountryItemProps {
|
|
6
|
-
|
|
7
|
+
country: ICountry;
|
|
8
|
+
theme?: IThemeProps;
|
|
9
|
+
isSelected?: boolean;
|
|
7
10
|
onSelect: (country: ICountry) => void;
|
|
8
|
-
onClose: () => void;
|
|
9
11
|
language: ICountrySelectLanguages;
|
|
10
|
-
theme?: 'light' | 'dark';
|
|
11
12
|
countrySelectStyle?: ICountrySelectStyle;
|
|
12
13
|
accessibilityLabel?: string;
|
|
13
14
|
accessibilityHint?: string;
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import {ModalProps} from 'react-native';
|
|
3
|
+
|
|
3
4
|
import {ICountry} from './country';
|
|
5
|
+
import {IThemeProps} from './theme';
|
|
4
6
|
import {ICountryCca2} from './countryCca2';
|
|
5
|
-
import {ICountrySelectLanguages} from './countrySelectLanguages';
|
|
6
|
-
import {ICountrySelectStyle} from './countrySelectStyles';
|
|
7
7
|
import {ISectionTitle} from './sectionTitle';
|
|
8
|
+
import {ICountrySelectStyle} from './countrySelectStyles';
|
|
9
|
+
import {ICountrySelectLanguages} from './countrySelectLanguages';
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
interface ICountrySelectBaseProps extends ModalProps, IThemeProps {
|
|
10
12
|
visible: boolean;
|
|
11
13
|
onClose: () => void;
|
|
12
|
-
onSelect: (country: ICountry) => void;
|
|
13
14
|
modalType?: 'bottomSheet' | 'popup';
|
|
14
15
|
countrySelectStyle?: ICountrySelectStyle;
|
|
15
|
-
theme?: 'light' | 'dark';
|
|
16
16
|
isFullScreen?: boolean;
|
|
17
17
|
popularCountries?: string[];
|
|
18
18
|
visibleCountries?: ICountryCca2[];
|
|
19
19
|
hiddenCountries?: ICountryCca2[];
|
|
20
20
|
language?: ICountrySelectLanguages;
|
|
21
21
|
showSearchInput?: boolean;
|
|
22
|
+
showAlphabetFilter?: boolean;
|
|
22
23
|
searchPlaceholder?: string;
|
|
23
24
|
searchPlaceholderTextColor?: string;
|
|
24
25
|
searchSelectionColor?: string;
|
|
@@ -47,4 +48,23 @@ export interface ICountrySelectProps extends ModalProps {
|
|
|
47
48
|
accessibilityHintCountriesList?: string;
|
|
48
49
|
accessibilityLabelCountryItem?: string;
|
|
49
50
|
accessibilityHintCountryItem?: string;
|
|
51
|
+
accessibilityLabelAlphabetFilter?: string;
|
|
52
|
+
accessibilityHintAlphabetFilter?: string;
|
|
53
|
+
accessibilityLabelAlphabetLetter?: string;
|
|
54
|
+
accessibilityHintAlphabetLetter?: string;
|
|
50
55
|
}
|
|
56
|
+
|
|
57
|
+
interface ICountrySelectSingleProps extends ICountrySelectBaseProps {
|
|
58
|
+
isMultiSelect?: false;
|
|
59
|
+
onSelect: (country: ICountry) => void;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface ICountrySelectMultiProps extends ICountrySelectBaseProps {
|
|
63
|
+
isMultiSelect: true;
|
|
64
|
+
selectedCountries: ICountry[];
|
|
65
|
+
onSelect: (country: ICountry[]) => void;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type ICountrySelectProps =
|
|
69
|
+
| ICountrySelectSingleProps
|
|
70
|
+
| ICountrySelectMultiProps;
|
|
@@ -19,4 +19,11 @@ export interface ICountrySelectStyle {
|
|
|
19
19
|
countryName?: StyleProp<TextStyle>;
|
|
20
20
|
countryNotFoundContainer?: StyleProp<ViewStyle>;
|
|
21
21
|
countryNotFoundMessage?: StyleProp<TextStyle>;
|
|
22
|
+
alphabetContainer?: StyleProp<ViewStyle>;
|
|
23
|
+
alphabetLetter?: StyleProp<ViewStyle>;
|
|
24
|
+
alphabetLetterText?: StyleProp<TextStyle>;
|
|
25
|
+
alphabetLetterActive?: StyleProp<ViewStyle>;
|
|
26
|
+
alphabetLetterDisabled?: StyleProp<ViewStyle>;
|
|
27
|
+
alphabetLetterTextActive?: StyleProp<TextStyle>;
|
|
28
|
+
alphabetLetterTextDisabled?: StyleProp<TextStyle>;
|
|
22
29
|
}
|
package/lib/interface/index.ts
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {ICountrySelectLanguages} from './countrySelectLanguages';
|
|
2
|
+
import {ICountrySelectStyle} from './countrySelectStyles';
|
|
3
|
+
import {IThemeProps} from './theme';
|
|
4
|
+
|
|
5
|
+
export interface ISearchInputProps {
|
|
6
|
+
theme?: IThemeProps;
|
|
7
|
+
language: ICountrySelectLanguages;
|
|
8
|
+
value: string;
|
|
9
|
+
onChangeText: (text: string) => void;
|
|
10
|
+
countrySelectStyle?: ICountrySelectStyle;
|
|
11
|
+
searchPlaceholder?: string;
|
|
12
|
+
searchPlaceholderTextColor?: string;
|
|
13
|
+
searchSelectionColor?: string;
|
|
14
|
+
accessibilityLabelSearchInput?: string;
|
|
15
|
+
accessibilityHintSearchInput?: string;
|
|
16
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {translations} from './getTranslation';
|
|
2
|
+
import countries from '../constants/countries.json';
|
|
3
|
+
import {normalizeCountryName} from './normalizeCountryName';
|
|
4
|
+
import {ICountry, ICountrySelectLanguages, IListItem} from '../interface';
|
|
5
|
+
import {sortCountriesAlphabetically} from './sortCountriesAlphabetically';
|
|
6
|
+
|
|
7
|
+
type Params = {
|
|
8
|
+
searchQuery: string;
|
|
9
|
+
popularCountries: string[];
|
|
10
|
+
language: ICountrySelectLanguages;
|
|
11
|
+
visibleCountries: string[];
|
|
12
|
+
hiddenCountries: string[];
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function getCountriesList({
|
|
16
|
+
searchQuery,
|
|
17
|
+
popularCountries,
|
|
18
|
+
language,
|
|
19
|
+
visibleCountries,
|
|
20
|
+
hiddenCountries,
|
|
21
|
+
}: Params): IListItem[] {
|
|
22
|
+
const query = searchQuery.toLowerCase().trim();
|
|
23
|
+
|
|
24
|
+
let countriesData = countries as unknown as ICountry[];
|
|
25
|
+
|
|
26
|
+
if (visibleCountries.length > 0 && hiddenCountries.length > 0) {
|
|
27
|
+
countriesData = (countries as unknown as ICountry[]).filter(country => {
|
|
28
|
+
return (
|
|
29
|
+
visibleCountries.includes(country.cca2) &&
|
|
30
|
+
!hiddenCountries.includes(country.cca2)
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (visibleCountries.length > 0 && hiddenCountries.length === 0) {
|
|
36
|
+
countriesData = (countries as unknown as ICountry[]).filter(country =>
|
|
37
|
+
visibleCountries.includes(country.cca2),
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (hiddenCountries.length > 0 && visibleCountries.length === 0) {
|
|
42
|
+
countriesData = (countries as unknown as ICountry[]).filter(
|
|
43
|
+
country => !hiddenCountries.includes(country.cca2),
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (query.length > 0) {
|
|
48
|
+
const filteredCountries = countriesData.filter(country => {
|
|
49
|
+
const countryName =
|
|
50
|
+
country.translations[language]?.common || country.name.common || '';
|
|
51
|
+
const normalizedCountryName = normalizeCountryName(
|
|
52
|
+
countryName.toLowerCase(),
|
|
53
|
+
);
|
|
54
|
+
const normalizedQuery = normalizeCountryName(query);
|
|
55
|
+
const callingCode = country.idd.root.toLowerCase();
|
|
56
|
+
const flag = country.flag.toLowerCase();
|
|
57
|
+
const countryCode = country.cca2.toLowerCase();
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
normalizedCountryName.includes(normalizedQuery) ||
|
|
61
|
+
countryName.toLowerCase().includes(query) ||
|
|
62
|
+
callingCode.includes(query) ||
|
|
63
|
+
flag.includes(query) ||
|
|
64
|
+
countryCode.includes(query)
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
return sortCountriesAlphabetically(filteredCountries, language);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const popularCountriesData = sortCountriesAlphabetically(
|
|
72
|
+
countriesData.filter(country => popularCountries.includes(country.cca2)),
|
|
73
|
+
language,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const otherCountriesData = sortCountriesAlphabetically(
|
|
77
|
+
countriesData.filter(country => !popularCountries.includes(country.cca2)),
|
|
78
|
+
language,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const result: IListItem[] = [];
|
|
82
|
+
|
|
83
|
+
if (popularCountriesData.length > 0) {
|
|
84
|
+
result.push({
|
|
85
|
+
isSection: true as const,
|
|
86
|
+
title:
|
|
87
|
+
translations.popularCountriesTitle[language as ICountrySelectLanguages],
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
result.push(...popularCountriesData);
|
|
91
|
+
result.push({
|
|
92
|
+
isSection: true as const,
|
|
93
|
+
title:
|
|
94
|
+
translations.allCountriesTitle[language as ICountrySelectLanguages],
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
result.push(...otherCountriesData);
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import {ICountrySelectLanguages, ICountry} from '../interface';
|
|
2
|
+
|
|
3
|
+
export const getCountryNameInLanguage = (
|
|
4
|
+
country: ICountry,
|
|
5
|
+
language: ICountrySelectLanguages = 'eng',
|
|
6
|
+
): string => {
|
|
7
|
+
return country.translations[language]?.common || country.name.common || '';
|
|
8
|
+
};
|