+}
+
+export const Dropdown = memo((props: DropdownProps) => {
+ const {
+ dataSet,
+ suggestionsListMaxHeight,
+ renderItem,
+ ListEmptyComponent,
+ ItemSeparatorComponent,
+ direction,
+ ...rest
+ } = props
+ const themeName = useColorScheme()
+ const styles = useMemo(() => getStyles(themeName || 'light'), [themeName])
+
+ const defaultItemSeparator = useMemo(() => function () {
+ return
+ }, [styles.itemSeparator])
+
+ return (
+
+ item.id}
+ ListEmptyComponent={ListEmptyComponent}
+ ItemSeparatorComponent={ItemSeparatorComponent ?? defaultItemSeparator}
+ {...rest.flatListProps}
+ />
+
+ )
+})
+
+const getStyles = (themeName: 'light' | 'dark' = 'light') =>
+ StyleSheet.create({
+ container: {},
+ listContainer: {
+ backgroundColor: theme[themeName].suggestionsListBackgroundColor,
+ width: '100%',
+ zIndex: 9,
+ borderRadius: 5,
+ shadowColor: theme[themeName || 'light'].shadowColor,
+ shadowOffset: {
+ width: 0,
+ height: 12,
+ },
+ shadowOpacity: 0.3,
+ shadowRadius: 15.46,
+
+ elevation: 20,
+ },
+ itemSeparator: {
+ height: 1,
+ width: '100%',
+ backgroundColor: theme[themeName || 'light'].itemSeparatorColor,
+ },
+ })
diff --git a/mobile/components/AutocompleteDropdown-v4.3.1/HOC/withFadeAnimation.tsx b/mobile/components/AutocompleteDropdown-v4.3.1/HOC/withFadeAnimation.tsx
new file mode 100644
index 000000000..4897ec237
--- /dev/null
+++ b/mobile/components/AutocompleteDropdown-v4.3.1/HOC/withFadeAnimation.tsx
@@ -0,0 +1,32 @@
+import type { FC, ComponentType } from 'react'
+import React, { useEffect, useRef } from 'react'
+import type { ViewProps } from 'react-native'
+import { Animated, Easing } from 'react-native'
+
+interface WithFadeAnimationProps {
+ containerStyle?: ViewProps['style']
+}
+
+export const withFadeAnimation = (
+ WrappedComponent: ComponentType
,
+ { containerStyle }: WithFadeAnimationProps = {},
+): FC
=> {
+ return (props: P) => {
+ const opacityAnimationValue = useRef(new Animated.Value(0)).current
+
+ useEffect(() => {
+ Animated.timing(opacityAnimationValue, {
+ duration: 800,
+ toValue: 1,
+ useNativeDriver: true,
+ easing: Easing.bezier(0.3, 0.58, 0.25, 0.99),
+ }).start()
+ }, [opacityAnimationValue])
+
+ return (
+
+
+
+ )
+ }
+}
diff --git a/mobile/components/AutocompleteDropdown-v4.3.1/NothingFound.tsx b/mobile/components/AutocompleteDropdown-v4.3.1/NothingFound.tsx
new file mode 100644
index 000000000..c128f15ee
--- /dev/null
+++ b/mobile/components/AutocompleteDropdown-v4.3.1/NothingFound.tsx
@@ -0,0 +1,27 @@
+import type { FC } from 'react'
+import React, { memo } from 'react'
+import { StyleSheet, Text, View } from 'react-native'
+import { withFadeAnimation } from './HOC/withFadeAnimation'
+
+interface NothingFoundProps {
+ emptyResultText?: string
+}
+
+export const NothingFound: FC = memo(({ ...props }) => {
+ const EL = withFadeAnimation(
+ () => (
+
+ {props.emptyResultText || 'Nothing found'}
+
+ ),
+ {},
+ )
+ return
+})
+
+const styles = StyleSheet.create({
+ container: {
+ padding: 10,
+ },
+ text: { textAlign: 'center' },
+})
diff --git a/mobile/components/AutocompleteDropdown-v4.3.1/RightButton.tsx b/mobile/components/AutocompleteDropdown-v4.3.1/RightButton.tsx
new file mode 100644
index 000000000..9cb3e62f9
--- /dev/null
+++ b/mobile/components/AutocompleteDropdown-v4.3.1/RightButton.tsx
@@ -0,0 +1,107 @@
+/* eslint-disable react/display-name */
+import React, { memo, useEffect, useRef } from 'react'
+import type { StyleProp, ViewStyle } from 'react-native'
+import { ActivityIndicator, Animated, Easing, StyleSheet, TouchableOpacity, View } from 'react-native'
+// import { ChevronDown, XCircle } from 'react-native-feather'
+import { ChevronDown } from 'react-native-feather'
+import { MaterialIcons } from '@expo/vector-icons'
+
+interface RightButtonProps {
+ inputHeight?: number
+ onClearPress?: () => void
+ onChevronPress?: () => void
+ isOpened?: boolean
+ showChevron?: boolean
+ showClear?: boolean
+ loading?: boolean
+ buttonsContainerStyle?: StyleProp
+ ChevronIconComponent?: React.ReactNode
+ ClearIconComponent?: React.ReactNode
+ RightIconComponent?: React.ReactNode
+ onRightIconComponentPress?: () => void
+}
+
+export const RightButton: React.FC = memo(
+ ({
+ inputHeight,
+ onClearPress,
+ onChevronPress,
+ isOpened,
+ showChevron,
+ showClear,
+ loading,
+ buttonsContainerStyle,
+ ChevronIconComponent,
+ ClearIconComponent,
+ RightIconComponent,
+ onRightIconComponentPress,
+ }) => {
+ const isOpenedAnimationValue = useRef(new Animated.Value(0)).current
+
+ useEffect(() => {
+ Animated.timing(isOpenedAnimationValue, {
+ duration: 350,
+ toValue: isOpened ? 1 : 0,
+ useNativeDriver: true,
+ easing: Easing.bezier(0.3, 0.58, 0.25, 0.99),
+ }).start()
+ }, [isOpened, isOpenedAnimationValue])
+
+ const chevronSpin = isOpenedAnimationValue.interpolate({
+ inputRange: [0, 1],
+ outputRange: ['0deg', '180deg'],
+ })
+
+ return (
+
+ {!loading && showClear && (
+
+ {/* {ClearIconComponent ?? } */}
+ {ClearIconComponent ?? }
+
+ )}
+ {loading && }
+ {RightIconComponent && (
+
+ {RightIconComponent}
+
+ )}
+ {showChevron && (
+
+
+ {ChevronIconComponent ?? }
+
+
+ )}
+
+ )
+ },
+)
+
+const styles = StyleSheet.create({
+ container: {
+ position: 'relative',
+ flex: 0,
+ flexDirection: 'row',
+ right: 8,
+ zIndex: 10,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: 'transparent',
+ },
+ clearButton: {
+ width: 26,
+ alignItems: 'center',
+ },
+ chevronButton: {
+ width: 26,
+ alignItems: 'center',
+ height: '100%',
+ justifyContent: 'center',
+ },
+})
diff --git a/mobile/components/AutocompleteDropdown-v4.3.1/ScrollViewListItem.tsx b/mobile/components/AutocompleteDropdown-v4.3.1/ScrollViewListItem.tsx
new file mode 100644
index 000000000..fc4d93c28
--- /dev/null
+++ b/mobile/components/AutocompleteDropdown-v4.3.1/ScrollViewListItem.tsx
@@ -0,0 +1,83 @@
+import type { FC } from 'react'
+import React, { memo, useMemo } from 'react'
+import type { ViewProps } from 'react-native'
+import { StyleSheet, Text, TouchableOpacity, View, useColorScheme } from 'react-native'
+import diacriticless from './diacriticless'
+import { theme } from './theme'
+
+interface ScrollViewListItemProps {
+ highlight: string
+ title: string
+ style?: ViewProps['style']
+ onPress?: () => void
+ ignoreAccents?: boolean
+ numberOfLines?: number
+}
+
+export const ScrollViewListItem: FC = memo(
+ ({ highlight, title, style, onPress, ignoreAccents, numberOfLines = 2 }) => {
+ const themeName = useColorScheme()
+ const styles = useMemo(() => getStyles(themeName || 'light'), [themeName])
+
+ const titleParts = useMemo(() => {
+ let titleHighlighted = ''
+ let titleStart = title
+ let titleEnd = ''
+
+ if (typeof title === 'string' && title?.length > 0 && highlight?.length > 0) {
+ const highlightIn = ignoreAccents ? diacriticless(title?.toLowerCase()) : title?.toLowerCase()
+ const highlightWhat = ignoreAccents ? diacriticless(highlight?.toLowerCase()) : highlight?.toLowerCase()
+
+ const substrIndex = highlightIn?.indexOf(highlightWhat)
+ if (substrIndex !== -1) {
+ titleStart = title?.slice(0, substrIndex)
+ titleHighlighted = title?.slice(substrIndex, substrIndex + highlight?.length)
+ titleEnd = title?.slice(substrIndex + highlight?.length)
+ }
+ }
+
+ return { titleHighlighted, titleStart, titleEnd }
+ }, [highlight, ignoreAccents, title])
+
+ return (
+
+
+
+
+ {titleParts.titleStart}
+
+
+ {titleParts.titleHighlighted}
+
+
+ {titleParts.titleEnd}
+
+
+
+
+ )
+ },
+)
+
+const getStyles = (themeName: 'light' | 'dark' = 'light') =>
+ StyleSheet.create({
+ container: {
+ padding: 15,
+ flex: 1,
+ flexDirection: 'row',
+ alignItems: 'flex-start',
+ justifyContent: 'flex-start',
+ flexWrap: 'nowrap',
+
+ width: '100%',
+ },
+ text: {
+ color: theme[themeName].listItemTextColor,
+ fontSize: 16,
+ flexGrow: 1,
+ flexShrink: 0,
+ },
+ textBold: {
+ fontWeight: 'bold',
+ },
+ })
diff --git a/mobile/components/AutocompleteDropdown-v4.3.1/diacriticless.ts b/mobile/components/AutocompleteDropdown-v4.3.1/diacriticless.ts
new file mode 100644
index 000000000..3f8448a7a
--- /dev/null
+++ b/mobile/components/AutocompleteDropdown-v4.3.1/diacriticless.ts
@@ -0,0 +1,527 @@
+interface DiacriticsMap {
+ [key: string]: string[]
+}
+
+// all diacritics
+const diacritics: DiacriticsMap = {
+ a: [
+ 'a',
+ 'à',
+ 'á',
+ 'â',
+ 'ã',
+ 'ä',
+ 'å',
+ 'æ',
+ 'ā',
+ 'ă',
+ 'ą',
+ 'ǎ',
+ 'ǟ',
+ 'ǡ',
+ 'ǻ',
+ 'ȁ',
+ 'ȃ',
+ 'ȧ',
+ 'ɐ',
+ 'ɑ',
+ 'ɒ',
+ 'ͣ',
+ 'а',
+ 'ӑ',
+ 'ӓ',
+ 'ᵃ',
+ 'ᵄ',
+ 'ᶏ',
+ 'ḁ',
+ 'ẚ',
+ 'ạ',
+ 'ả',
+ 'ấ',
+ 'ầ',
+ 'ẩ',
+ 'ẫ',
+ 'ậ',
+ 'ắ',
+ 'ằ',
+ 'ẳ',
+ 'ẵ',
+ 'ặ',
+ 'ₐ',
+ 'ⱥ',
+ 'a',
+ ],
+ A: [
+ 'A',
+ 'À',
+ 'Á',
+ 'Â',
+ 'Ã',
+ 'Ä',
+ 'Å',
+ 'Ā',
+ 'Ă',
+ 'Ą',
+ 'Ǎ',
+ 'Ǟ',
+ 'Ǡ',
+ 'Ǻ',
+ 'Ȁ',
+ 'Ȃ',
+ 'Ȧ',
+ 'Ⱥ',
+ 'А',
+ 'Ӑ',
+ 'Ӓ',
+ 'ᴀ',
+ 'ᴬ',
+ 'Ḁ',
+ 'Ạ',
+ 'Ả',
+ 'Ấ',
+ 'Ầ',
+ 'Ẩ',
+ 'Ẫ',
+ 'Ậ',
+ 'Ắ',
+ 'Ằ',
+ 'Ẳ',
+ 'Ẵ',
+ 'Ặ',
+ 'A',
+ ],
+
+ b: ['b', 'ƀ', 'ƃ', 'ɓ', 'ᖯ', 'ᵇ', 'ᵬ', 'ᶀ', 'ḃ', 'ḅ', 'ḇ', 'b'],
+ B: ['B', 'Ɓ', 'Ƃ', 'Ƀ', 'ʙ', 'ᛒ', 'ᴃ', 'ᴮ', 'ᴯ', 'Ḃ', 'Ḅ', 'Ḇ', 'B'],
+
+ c: ['c', 'ç', 'ć', 'ĉ', 'ċ', 'č', 'ƈ', 'ȼ', 'ɕ', 'ͨ', 'ᴄ', 'ᶜ', 'ḉ', 'ↄ', 'c'],
+ C: ['C', 'Ç', 'Ć', 'Ĉ', 'Ċ', 'Č', 'Ƈ', 'Ȼ', 'ʗ', 'Ḉ', 'C'],
+
+ d: ['d', 'ď', 'đ', 'Ƌ', 'ƌ', 'ȡ', 'ɖ', 'ɗ', 'ͩ', 'ᵈ', 'ᵭ', 'ᶁ', 'ᶑ', 'ḋ', 'ḍ', 'ḏ', 'ḑ', 'ḓ', 'd'],
+ D: ['D', 'Ď', 'Đ', 'Ɖ', 'Ɗ', 'ᴰ', 'Ḋ', 'Ḍ', 'Ḏ', 'Ḑ', 'Ḓ', 'D'],
+
+ e: [
+ 'e',
+ 'è',
+ 'é',
+ 'ê',
+ 'ë',
+ 'ē',
+ 'ĕ',
+ 'ė',
+ 'ę',
+ 'ě',
+ 'ǝ',
+ 'ȅ',
+ 'ȇ',
+ 'ȩ',
+ 'ɇ',
+ 'ɘ',
+ 'ͤ',
+ 'ᵉ',
+ 'ᶒ',
+ 'ḕ',
+ 'ḗ',
+ 'ḙ',
+ 'ḛ',
+ 'ḝ',
+ 'ẹ',
+ 'ẻ',
+ 'ẽ',
+ 'ế',
+ 'ề',
+ 'ể',
+ 'ễ',
+ 'ệ',
+ 'ₑ',
+ 'e',
+ ],
+ E: [
+ 'E',
+ 'È',
+ 'É',
+ 'Ê',
+ 'Ë',
+ 'Ē',
+ 'Ĕ',
+ 'Ė',
+ 'Ę',
+ 'Ě',
+ 'Œ',
+ 'Ǝ',
+ 'Ɛ',
+ 'Ȅ',
+ 'Ȇ',
+ 'Ȩ',
+ 'Ɇ',
+ 'ɛ',
+ 'ɜ',
+ 'ɶ',
+ 'Є',
+ 'Э',
+ 'э',
+ 'є',
+ 'Ӭ',
+ 'ӭ',
+ 'ᴇ',
+ 'ᴈ',
+ 'ᴱ',
+ 'ᴲ',
+ 'ᵋ',
+ 'ᵌ',
+ 'ᶓ',
+ 'ᶔ',
+ 'ᶟ',
+ 'Ḕ',
+ 'Ḗ',
+ 'Ḙ',
+ 'Ḛ',
+ 'Ḝ',
+ 'Ẹ',
+ 'Ẻ',
+ 'Ẽ',
+ 'Ế',
+ 'Ề',
+ 'Ể',
+ 'Ễ',
+ 'Ệ',
+ 'E',
+ '𐐁',
+ '𐐩',
+ ],
+
+ f: ['f', 'ƒ', 'ᵮ', 'ᶂ', 'ᶠ', 'ḟ', 'f'],
+ F: ['F', 'Ƒ', 'Ḟ', 'ⅎ', 'F'],
+
+ g: ['g', 'ĝ', 'ğ', 'ġ', 'ģ', 'ǥ', 'ǧ', 'ǵ', 'ɠ', 'ɡ', 'ᵍ', 'ᵷ', 'ᵹ', 'ᶃ', 'ᶢ', 'ḡ', 'g'],
+ G: ['G', 'Ĝ', 'Ğ', 'Ġ', 'Ģ', 'Ɠ', 'Ǥ', 'Ǧ', 'Ǵ', 'ɢ', 'ʛ', 'ᴳ', 'Ḡ', 'G'],
+
+ h: [
+ 'h',
+ 'ĥ',
+ 'ħ',
+ 'ƕ',
+ 'ȟ',
+ 'ɥ',
+ 'ɦ',
+ 'ʮ',
+ 'ʯ',
+ 'ʰ',
+ 'ʱ',
+ 'ͪ',
+ 'Һ',
+ 'һ',
+ 'ᑋ',
+ 'ᶣ',
+ 'ḣ',
+ 'ḥ',
+ 'ḧ',
+ 'ḩ',
+ 'ḫ',
+ 'ⱨ',
+ 'h',
+ ],
+ H: ['H', 'Ĥ', 'Ħ', 'Ȟ', 'ʜ', 'ᕼ', 'ᚺ', 'ᚻ', 'ᴴ', 'Ḣ', 'Ḥ', 'Ḧ', 'Ḩ', 'Ḫ', 'Ⱨ', 'H'],
+
+ i: [
+ 'i',
+ 'ì',
+ 'í',
+ 'î',
+ 'ï',
+ 'ĩ',
+ 'ī',
+ 'ĭ',
+ 'į',
+ 'ǐ',
+ 'ȉ',
+ 'ȋ',
+ 'ɨ',
+ 'ͥ',
+ 'ᴉ',
+ 'ᵎ',
+ 'ᵢ',
+ 'ᶖ',
+ 'ᶤ',
+ 'ḭ',
+ 'ḯ',
+ 'ỉ',
+ 'ị',
+ 'i',
+ ],
+ I: [
+ 'I',
+ 'Ì',
+ 'Í',
+ 'Î',
+ 'Ï',
+ 'Ĩ',
+ 'Ī',
+ 'Ĭ',
+ 'Į',
+ 'İ',
+ 'Ǐ',
+ 'Ȉ',
+ 'Ȋ',
+ 'ɪ',
+ 'І',
+ 'ᴵ',
+ 'ᵻ',
+ 'ᶦ',
+ 'ᶧ',
+ 'Ḭ',
+ 'Ḯ',
+ 'Ỉ',
+ 'Ị',
+ 'I',
+ ],
+
+ j: ['j', 'ĵ', 'ǰ', 'ɉ', 'ʝ', 'ʲ', 'ᶡ', 'ᶨ', 'j'],
+ J: ['J', 'Ĵ', 'ᴊ', 'ᴶ', 'J'],
+
+ k: ['k', 'ķ', 'ƙ', 'ǩ', 'ʞ', 'ᵏ', 'ᶄ', 'ḱ', 'ḳ', 'ḵ', 'ⱪ', 'k'],
+ K: ['K', 'Ķ', 'Ƙ', 'Ǩ', 'ᴷ', 'Ḱ', 'Ḳ', 'Ḵ', 'Ⱪ', 'K'],
+
+ l: ['l', 'ĺ', 'ļ', 'ľ', 'ŀ', 'ł', 'ƚ', 'ȴ', 'ɫ', 'ɬ', 'ɭ', 'ˡ', 'ᶅ', 'ᶩ', 'ᶪ', 'ḷ', 'ḹ', 'ḻ', 'ḽ', 'ℓ', 'ⱡ'],
+ L: ['L', 'Ĺ', 'Ļ', 'Ľ', 'Ŀ', 'Ł', 'Ƚ', 'ʟ', 'ᴌ', 'ᴸ', 'ᶫ', 'Ḷ', 'Ḹ', 'Ḻ', 'Ḽ', 'Ⱡ', 'Ɫ'],
+
+ m: ['m', 'ɯ', 'ɰ', 'ɱ', 'ͫ', 'ᴟ', 'ᵐ', 'ᵚ', 'ᵯ', 'ᶆ', 'ᶬ', 'ᶭ', 'ḿ', 'ṁ', 'ṃ', '㎡', '㎥', 'm'],
+ M: ['M', 'Ɯ', 'ᴍ', 'ᴹ', 'Ḿ', 'Ṁ', 'Ṃ', 'M'],
+
+ n: ['n', 'ñ', 'ń', 'ņ', 'ň', 'ʼn', 'ƞ', 'ǹ', 'ȵ', 'ɲ', 'ɳ', 'ᵰ', 'ᶇ', 'ᶮ', 'ᶯ', 'ṅ', 'ṇ', 'ṉ', 'ṋ', 'ⁿ', 'n'],
+ N: ['N', 'Ñ', 'Ń', 'Ņ', 'Ň', 'Ɲ', 'Ǹ', 'Ƞ', 'ɴ', 'ᴎ', 'ᴺ', 'ᴻ', 'ᶰ', 'Ṅ', 'Ṇ', 'Ṉ', 'Ṋ', 'N'],
+
+ o: [
+ 'o',
+ 'ò',
+ 'ó',
+ 'ô',
+ 'õ',
+ 'ö',
+ 'ø',
+ 'ō',
+ 'ŏ',
+ 'ő',
+ 'ơ',
+ 'ǒ',
+ 'ǫ',
+ 'ǭ',
+ 'ǿ',
+ 'ȍ',
+ 'ȏ',
+ 'ȫ',
+ 'ȭ',
+ 'ȯ',
+ 'ȱ',
+ 'ɵ',
+ 'ͦ',
+ 'о',
+ 'ӧ',
+ 'ө',
+ 'ᴏ',
+ 'ᴑ',
+ 'ᴓ',
+ 'ᴼ',
+ 'ᵒ',
+ 'ᶱ',
+ 'ṍ',
+ 'ṏ',
+ 'ṑ',
+ 'ṓ',
+ 'ọ',
+ 'ỏ',
+ 'ố',
+ 'ồ',
+ 'ổ',
+ 'ỗ',
+ 'ộ',
+ 'ớ',
+ 'ờ',
+ 'ở',
+ 'ỡ',
+ 'ợ',
+ 'ₒ',
+ 'o',
+ '𐐬',
+ ],
+ O: [
+ 'O',
+ 'Ò',
+ 'Ó',
+ 'Ô',
+ 'Õ',
+ 'Ö',
+ 'Ø',
+ 'Ō',
+ 'Ŏ',
+ 'Ő',
+ 'Ɵ',
+ 'Ơ',
+ 'Ǒ',
+ 'Ǫ',
+ 'Ǭ',
+ 'Ǿ',
+ 'Ȍ',
+ 'Ȏ',
+ 'Ȫ',
+ 'Ȭ',
+ 'Ȯ',
+ 'Ȱ',
+ 'О',
+ 'Ӧ',
+ 'Ө',
+ 'Ṍ',
+ 'Ṏ',
+ 'Ṑ',
+ 'Ṓ',
+ 'Ọ',
+ 'Ỏ',
+ 'Ố',
+ 'Ồ',
+ 'Ổ',
+ 'Ỗ',
+ 'Ộ',
+ 'Ớ',
+ 'Ờ',
+ 'Ở',
+ 'Ỡ',
+ 'Ợ',
+ 'O',
+ '𐐄',
+ ],
+
+ p: ['p', 'ᵖ', 'ᵱ', 'ᵽ', 'ᶈ', 'ṕ', 'ṗ', 'p'],
+ P: ['P', 'Ƥ', 'ᴘ', 'ᴾ', 'Ṕ', 'Ṗ', 'Ᵽ', 'P'],
+
+ q: ['q', 'ɋ', 'ʠ', 'ᛩ', 'q'],
+ Q: ['Q', 'Ɋ', 'Q'],
+
+ r: ['r', 'ŕ', 'ŗ', 'ř', 'ȑ', 'ȓ', 'ɍ', 'ɹ', 'ɻ', 'ʳ', 'ʴ', 'ʵ', 'ͬ', 'ᵣ', 'ᵲ', 'ᶉ', 'ṙ', 'ṛ', 'ṝ', 'ṟ'],
+ R: ['R', 'Ŕ', 'Ŗ', 'Ř', 'Ʀ', 'Ȑ', 'Ȓ', 'Ɍ', 'ʀ', 'ʁ', 'ʶ', 'ᚱ', 'ᴙ', 'ᴚ', 'ᴿ', 'Ṙ', 'Ṛ', 'Ṝ', 'Ṟ', 'Ɽ'],
+
+ s: ['s', 'ś', 'ŝ', 'ş', 'š', 'ș', 'ʂ', 'ᔆ', 'ᶊ', 'ṡ', 'ṣ', 'ṥ', 'ṧ', 'ṩ', 's'],
+ S: ['S', 'Ś', 'Ŝ', 'Ş', 'Š', 'Ș', 'ȿ', 'ˢ', 'ᵴ', 'Ṡ', 'Ṣ', 'Ṥ', 'Ṧ', 'Ṩ', 'S'],
+
+ t: ['t', 'ţ', 'ť', 'ŧ', 'ƫ', 'ƭ', 'ț', 'ʇ', 'ͭ', 'ᵀ', 'ᵗ', 'ᵵ', 'ᶵ', 'ṫ', 'ṭ', 'ṯ', 'ṱ', 'ẗ', 't'],
+ T: ['T', 'Ţ', 'Ť', 'Ƭ', 'Ʈ', 'Ț', 'Ⱦ', 'ᴛ', 'ᵀ', 'Ṫ', 'Ṭ', 'Ṯ', 'Ṱ', 'T'],
+
+ u: [
+ 'u',
+ 'ù',
+ 'ú',
+ 'û',
+ 'ü',
+ 'ũ',
+ 'ū',
+ 'ŭ',
+ 'ů',
+ 'ű',
+ 'ų',
+ 'ư',
+ 'ǔ',
+ 'ǖ',
+ 'ǘ',
+ 'ǚ',
+ 'ǜ',
+ 'ȕ',
+ 'ȗ',
+ 'ͧ',
+ 'ߎ',
+ 'ᵘ',
+ 'ᵤ',
+ 'ṳ',
+ 'ṵ',
+ 'ṷ',
+ 'ṹ',
+ 'ṻ',
+ 'ụ',
+ 'ủ',
+ 'ứ',
+ 'ừ',
+ 'ử',
+ 'ữ',
+ 'ự',
+ 'u',
+ ],
+ U: [
+ 'U',
+ 'Ù',
+ 'Ú',
+ 'Û',
+ 'Ü',
+ 'Ũ',
+ 'Ū',
+ 'Ŭ',
+ 'Ů',
+ 'Ű',
+ 'Ų',
+ 'Ư',
+ 'Ǔ',
+ 'Ǖ',
+ 'Ǘ',
+ 'Ǚ',
+ 'Ǜ',
+ 'Ȕ',
+ 'Ȗ',
+ 'Ʉ',
+ 'ᴜ',
+ 'ᵁ',
+ 'ᵾ',
+ 'Ṳ',
+ 'Ṵ',
+ 'Ṷ',
+ 'Ṹ',
+ 'Ṻ',
+ 'Ụ',
+ 'Ủ',
+ 'Ứ',
+ 'Ừ',
+ 'Ử',
+ 'Ữ',
+ 'Ự',
+ 'U',
+ ],
+
+ v: ['v', 'ʋ', 'ͮ', 'ᵛ', 'ᵥ', 'ᶹ', 'ṽ', 'ṿ', 'ⱱ', 'v', 'ⱴ'],
+ V: ['V', 'Ʋ', 'Ʌ', 'ʌ', 'ᴠ', 'ᶌ', 'Ṽ', 'Ṿ', 'V'],
+
+ w: ['w', 'ŵ', 'ʷ', 'ᵂ', 'ẁ', 'ẃ', 'ẅ', 'ẇ', 'ẉ', 'ẘ', 'ⱳ', 'w'],
+ W: ['W', 'Ŵ', 'ʍ', 'ᴡ', 'Ẁ', 'Ẃ', 'Ẅ', 'Ẇ', 'Ẉ', 'Ⱳ', 'W'],
+
+ x: ['x', '̽', '͓', 'ᶍ', 'ͯ', 'ẋ', 'ẍ', 'ₓ', 'x'],
+ X: ['X', 'ˣ', 'ͯ', 'Ẋ', 'Ẍ', '☒', '✕', '✖', '✗', '✘', 'X'],
+
+ y: ['y', 'ý', 'ÿ', 'ŷ', 'ȳ', 'ɏ', 'ʸ', 'ẏ', 'ỳ', 'ỵ', 'ỷ', 'ỹ', 'y'],
+ Y: ['Y', 'Ý', 'Ŷ', 'Ÿ', 'Ƴ', 'ƴ', 'Ȳ', 'Ɏ', 'ʎ', 'ʏ', 'Ẏ', 'Ỳ', 'Ỵ', 'Ỷ', 'Ỹ', 'Y'],
+
+ z: ['z', 'ź', 'ż', 'ž', 'ƶ', 'ȥ', 'ɀ', 'ʐ', 'ʑ', 'ᙆ', 'ᙇ', 'ᶻ', 'ᶼ', 'ᶽ', 'ẑ', 'ẓ', 'ẕ', 'ⱬ', 'z'],
+ Z: ['Z', 'Ź', 'Ż', 'Ž', 'Ƶ', 'Ȥ', 'ᴢ', 'ᵶ', 'Ẑ', 'Ẓ', 'Ẕ', 'Ⱬ', 'Z'],
+}
+
+/*
+ * Main function of the module which removes all diacritics from the received text
+ */
+
+export default function removeDiacritics(text: string): string {
+ const result: string[] = []
+
+ for (let i = 0; i < text.length; i++) {
+ const searchChar = text.charAt(i)
+ let foundChar = false
+
+ for (const key in diacritics) {
+ const index = diacritics[key]?.indexOf(searchChar)
+ if (index !== -1) {
+ result.push(key)
+ foundChar = true
+ break
+ }
+ }
+
+ if (!foundChar) {
+ result.push(searchChar)
+ }
+ }
+
+ return result.join('')
+}
diff --git a/mobile/components/AutocompleteDropdown-v4.3.1/helpers.ts b/mobile/components/AutocompleteDropdown-v4.3.1/helpers.ts
new file mode 100644
index 000000000..b655af3f2
--- /dev/null
+++ b/mobile/components/AutocompleteDropdown-v4.3.1/helpers.ts
@@ -0,0 +1,21 @@
+export const fadeInDownShort = {
+ 0: {
+ opacity: 0,
+ transform: [{ translateY: -20 }],
+ },
+ 1: {
+ opacity: 1,
+ transform: [{ translateY: 0 }],
+ },
+}
+
+export const fadeInUpShort = {
+ 0: {
+ opacity: 0,
+ transform: [{ translateY: 20 }],
+ },
+ 1: {
+ opacity: 1,
+ transform: [{ translateY: 0 }],
+ },
+}
diff --git a/mobile/components/AutocompleteDropdown-v4.3.1/index.tsx b/mobile/components/AutocompleteDropdown-v4.3.1/index.tsx
new file mode 100644
index 000000000..8a7ddb9bb
--- /dev/null
+++ b/mobile/components/AutocompleteDropdown-v4.3.1/index.tsx
@@ -0,0 +1,587 @@
+/* eslint-disable @typescript-eslint/no-unused-expressions */
+import React, {
+ forwardRef,
+ memo,
+ useCallback,
+ useEffect,
+ useLayoutEffect,
+ useMemo,
+ useRef,
+ useState,
+ useContext,
+} from 'react'
+import debounce from 'lodash.debounce'
+import type {
+ GestureResponderEvent,
+ ListRenderItem,
+ NativeSyntheticEvent,
+ TextInputFocusEventData,
+ TextInputSubmitEditingEventData,
+} from 'react-native'
+import {
+ Dimensions,
+ Keyboard,
+ Platform,
+ Pressable,
+ TextInput,
+ TouchableOpacity,
+ View,
+ useColorScheme,
+} from 'react-native'
+import { moderateScale, ScaledSheet } from 'react-native-size-matters'
+import { Dropdown } from './Dropdown'
+import { NothingFound } from './NothingFound'
+import { RightButton } from './RightButton'
+import { ScrollViewListItem } from './ScrollViewListItem'
+import { AutocompleteDropdownContext, AutocompleteDropdownContextProvider } from './AutocompleteDropdownContext'
+import diacriticless from './diacriticless'
+import { theme } from './theme'
+import type { IAutocompleteDropdownProps, AutocompleteDropdownItem } from './types'
+
+export * from './types'
+export { AutocompleteDropdownContextProvider }
+
+export const AutocompleteDropdown = memo<
+ React.ForwardRefExoticComponent & React.RefAttributes>
+>(
+ forwardRef((props: IAutocompleteDropdownProps, ref) => {
+ const {
+ dataSet: dataSetProp,
+ initialValue: initialValueProp,
+ clearOnFocus = true,
+ caseSensitive = false,
+ ignoreAccents = true,
+ trimSearchText = true,
+ editable = true,
+ matchFrom,
+ inputHeight = moderateScale(40, 0.2),
+ suggestionsListMaxHeight = moderateScale(200, 0.2),
+ // bottomOffset = 0,
+ direction: directionProp,
+ controller,
+ onSelectItem: onSelectItemProp,
+ onOpenSuggestionsList: onOpenSuggestionsListProp,
+ useFilter,
+ renderItem: customRenderItem,
+ EmptyResultComponent,
+ emptyResultText,
+ onClear,
+ onChangeText: onTextChange,
+ debounce: debounceDelay = 0,
+ onChevronPress: onChevronPressProp,
+ onFocus: onFocusProp,
+ onBlur: onBlurProp,
+ onSubmit: onSubmitProp,
+ closeOnSubmit,
+ loading: loadingProp,
+ LeftComponent,
+ textInputProps,
+ showChevron,
+ showClear,
+ rightButtonsContainerStyle,
+ ChevronIconComponent,
+ ClearIconComponent,
+ RightIconComponent,
+ onRightIconComponentPress,
+ containerStyle,
+ inputContainerStyle,
+ suggestionsListTextStyle,
+ } = props
+ const InputComponent = (props.InputComponent as typeof TextInput) || TextInput
+ const inputRef = useRef(null)
+ const containerRef = useRef(null)
+ const [searchText, setSearchText] = useState('')
+ const [inputValue, setInputValue] = useState('')
+ const [loading, setLoading] = useState(loadingProp)
+ const [selectedItem, setSelectedItem] = useState(null)
+ const [isOpened, setIsOpened] = useState(false)
+ const initialDataSetRef = useRef(dataSetProp)
+ // const initialValueRef = useRef(initialValueProp)
+ const [dataSet, setDataSet] = useState(dataSetProp)
+ const matchFromStart = matchFrom === 'start'
+ const {
+ content,
+ setContent,
+ activeInputContainerRef,
+ activeControllerRef,
+ direction = directionProp,
+ setDirection,
+ controllerRefs,
+ } = useContext(AutocompleteDropdownContext)
+ const themeName = useColorScheme() || 'light'
+ const styles = useMemo(() => getStyles(themeName), [themeName])
+
+ useEffect(() => {
+ setLoading(loadingProp)
+ }, [loadingProp])
+
+ const calculateDirection = useCallback(
+ async ({ waitForKeyboard }: { waitForKeyboard: boolean }) => {
+ const [, positionY] = await new Promise<[x: number, y: number, width: number, height: number]>((resolve) => {
+ containerRef.current?.measureInWindow((...rect) => resolve(rect))
+ },)
+
+ return new Promise((resolve) => {
+ setTimeout(
+ () => {
+ const kbHeight = Keyboard.metrics?.()?.height || 0
+ const screenHeight = Dimensions.get('window').height
+ setDirection((screenHeight - kbHeight) / 2 > positionY ? 'down' : 'up')
+ resolve()
+ },
+ waitForKeyboard ? Platform.select({ ios: 600, android: 250, default: 1 }) : 1, // wait for keyboard to show
+ )
+ })
+ },
+ [setDirection],
+ )
+
+ const onClearPress = useCallback(() => {
+ setSearchText('')
+ setInputValue('')
+ setSelectedItem(null)
+ setIsOpened(false)
+ inputRef.current?.blur()
+ if (typeof onClear === 'function') {
+ onClear()
+ }
+ }, [onClear])
+
+ /** methods */
+ const close = useCallback(() => {
+ setIsOpened(false)
+ setContent(undefined)
+ }, [setContent])
+
+ const blur = useCallback(() => {
+ inputRef.current?.blur()
+ }, [])
+
+ const open = useCallback(async () => {
+ if (directionProp) {
+ setDirection(directionProp)
+ } else {
+ await calculateDirection({ waitForKeyboard: !!inputRef.current?.isFocused() })
+ }
+
+ setTimeout(() => {
+ setIsOpened(true)
+ }, 0)
+ }, [calculateDirection, directionProp, setDirection])
+
+ const toggle = useCallback(() => {
+ isOpened ? close() : open()
+ }, [close, isOpened, open])
+
+ const clear = useCallback(() => {
+ onClearPress()
+ }, [onClearPress])
+
+ useLayoutEffect(() => {
+ if (ref) {
+ if (typeof ref === 'function') {
+ ref(inputRef.current)
+ } else {
+ ref.current = inputRef.current
+ }
+ }
+ }, [ref])
+
+ /** Set initial value */
+ // useEffect(() => {
+ // const initialDataSet = initialDataSetRef.current
+ // const initialValue = initialValueRef.current
+
+ // let initialValueItem: AutocompleteDropdownItem | undefined
+ // if (typeof initialValue === 'string') {
+ // initialValueItem = initialDataSet?.find((el) => el.id === initialValue)
+ // } else if (typeof initialValue === 'object' && initialValue.id) {
+ // initialValueItem = initialDataSet?.find((el) => el.id === initialValue?.id)
+ // if (!initialValueItem) {
+ // // set the item as it is if it's not in the list
+ // initialValueItem = initialValue
+ // }
+ // }
+
+ // if (initialValueItem) {
+ // setSelectedItem(initialValueItem)
+ // }
+ // }, [])
+
+ // useEffect(() => () => {
+ // setContent(undefined)
+ // setIsOpened(false)
+ // }, [setContent])
+
+ /** Set initial value */
+ useEffect(() => {
+ if (!Array.isArray(dataSet) || selectedItem) {
+ // nothing to set or already setted
+ return
+ }
+
+ let dataSetItem
+ if (typeof initialValueProp === 'string') {
+ dataSetItem = dataSet.find((el) => el.id === initialValueProp)
+ } else if (typeof initialValueProp === 'object' && initialValueProp.id) {
+ dataSetItem = dataSet.find((el) => el.id === initialValueProp.id)
+ }
+
+ if (dataSetItem) {
+ setSelectedItem(dataSetItem)
+ }
+ }, [initialValueProp, dataSet]) // eslint-disable-line react-hooks/exhaustive-deps
+
+ useEffect(() => () => {
+ setContent(undefined)
+ setIsOpened(false)
+ }, [setContent])
+
+ const setInputText = useCallback((text: string) => {
+ setSearchText(text)
+ }, [])
+
+ const setItem = useCallback((item: AutocompleteDropdownItem | null) => {
+ setSelectedItem(item)
+ }, [])
+
+ useEffect(() => {
+ if (activeControllerRef?.current) {
+ controllerRefs?.current.push(activeControllerRef?.current)
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [])
+
+ const closeAll = useCallback(() => {
+ controllerRefs?.current.forEach((c) => {
+ c?.blur?.()
+ c?.close?.()
+ })
+ }, [controllerRefs])
+
+ /** expose controller methods */
+ useEffect(() => {
+ const methods = activeControllerRef ? { close, blur, open, toggle, clear, setInputText, setItem } : null
+ if (activeControllerRef) {
+ activeControllerRef.current = methods
+ }
+ if (typeof controller === 'function') {
+ controller(methods)
+ } else if (controller) {
+ controller.current = methods
+ }
+ }, [blur, clear, close, controller, activeControllerRef, open, setInputText, setItem, toggle])
+
+ useEffect(() => {
+ if (selectedItem) {
+ setInputValue(selectedItem.title ?? '')
+ } else {
+ setInputValue('')
+ }
+ }, [selectedItem])
+
+ useEffect(() => {
+ setInputValue(searchText)
+ }, [searchText])
+
+ useEffect(() => {
+ if (typeof onSelectItemProp === 'function') {
+ onSelectItemProp(selectedItem)
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [selectedItem])
+
+ useEffect(() => {
+ if (typeof onOpenSuggestionsListProp === 'function') {
+ onOpenSuggestionsListProp(isOpened)
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [isOpened])
+
+ useEffect(() => {
+ // renew state on close
+ if (!isOpened && selectedItem && !loading && !inputRef.current?.isFocused()) {
+ setInputValue(selectedItem.title || '')
+ }
+ }, [isOpened, loading, searchText, selectedItem])
+
+ const _onSelectItem = useCallback((item: AutocompleteDropdownItem) => {
+ setSelectedItem(item)
+ inputRef.current?.blur()
+ setIsOpened(false)
+ }, [])
+
+ useEffect(() => {
+ initialDataSetRef.current = dataSetProp
+ setDataSet(dataSetProp)
+ }, [dataSetProp])
+
+ useEffect(() => {
+ const initialDataSet = initialDataSetRef.current
+ if (!searchText?.length) {
+ setDataSet(initialDataSet)
+ return
+ }
+
+ if (!Array.isArray(initialDataSet) || useFilter === false) {
+ return
+ }
+
+ let findWhat = caseSensitive ? searchText : searchText.toLowerCase()
+
+ if (ignoreAccents) {
+ findWhat = diacriticless(findWhat)
+ }
+
+ if (trimSearchText) {
+ findWhat = findWhat.trim()
+ }
+
+ const newSet = initialDataSet.filter((item: AutocompleteDropdownItem) => {
+ const titleStr = item.title || ''
+ const title = caseSensitive ? titleStr : titleStr.toLowerCase()
+ const findWhere = ignoreAccents ? diacriticless(title) : title
+
+ if (matchFromStart) {
+ return typeof item.title === 'string' && findWhere.startsWith(findWhat)
+ }
+ return typeof item.title === 'string' && findWhere.indexOf(findWhat) !== -1
+ })
+
+ setDataSet(newSet)
+ }, [ignoreAccents, matchFromStart, caseSensitive, searchText, trimSearchText, useFilter])
+
+ const renderItem: ListRenderItem = useCallback(
+ ({ item }) => {
+ if (typeof customRenderItem === 'function') {
+ const EL = customRenderItem(item, searchText)
+ return _onSelectItem(item)}>{EL}
+ }
+
+ return (
+ _onSelectItem(item)}
+ ignoreAccents={ignoreAccents}
+ />
+ )
+ },
+ [_onSelectItem, customRenderItem, ignoreAccents, searchText, suggestionsListTextStyle],
+ )
+
+ const ListEmptyComponent = useMemo(() => EmptyResultComponent ?? , [EmptyResultComponent, emptyResultText])
+
+ const debouncedEvent = useMemo(
+ () =>
+ debounce((text: string) => {
+ if (typeof onTextChange === 'function') {
+ onTextChange(text)
+ }
+ setLoading(false)
+ }, debounceDelay),
+ [debounceDelay, onTextChange],
+ )
+
+ const onChangeText = useCallback(
+ (text: string) => {
+ setSearchText(text)
+ setInputValue(text)
+ setLoading(true)
+ debouncedEvent(text)
+ },
+ [debouncedEvent],
+ )
+
+ const onChevronPress = useCallback(() => {
+ toggle()
+ Keyboard.dismiss()
+
+ if (typeof onChevronPressProp === 'function') {
+ onChevronPressProp()
+ }
+ }, [onChevronPressProp, toggle])
+
+ const onFocus = useCallback(
+ (e: NativeSyntheticEvent) => {
+ if (clearOnFocus) {
+ setSearchText('')
+ setInputValue('')
+ }
+ if (typeof onFocusProp === 'function') {
+ onFocusProp(e)
+ }
+ open()
+ },
+ [clearOnFocus, onFocusProp, open],
+ )
+
+ const onBlur = useCallback(
+ (e: NativeSyntheticEvent) => {
+ if (typeof onBlurProp === 'function') {
+ onBlurProp(e)
+ }
+ },
+ [onBlurProp],
+ )
+
+ const onSubmit = useCallback(
+ (e: NativeSyntheticEvent) => {
+ inputRef.current?.blur()
+ if (closeOnSubmit) {
+ close()
+ }
+
+ if (typeof onSubmitProp === 'function') {
+ onSubmitProp(e)
+ }
+ },
+ [close, closeOnSubmit, onSubmitProp],
+ )
+
+ const onPressOut = useCallback(
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ (e: GestureResponderEvent) => {
+ closeAll()
+ if (editable) {
+ inputRef?.current?.focus()
+ } else {
+ toggle()
+ }
+ },
+ [closeAll, editable, toggle],
+ )
+
+ // eslint-disable-next-line consistent-return
+ useEffect(() => {
+ if ((!content && !inputRef.current?.isFocused()) || loading) {
+ const db = debounce(() => {
+ setIsOpened(false)
+ }, 100)
+ db()
+ return () => {
+ db.cancel()
+ }
+ }
+ }, [content, loading])
+
+ useEffect(() => {
+ // searchTextRef
+ if (searchText && inputRef.current?.isFocused() && !loading) {
+ setIsOpened(true)
+ }
+ }, [loading, searchText])
+
+ useEffect(() => {
+ if (isOpened && Array.isArray(dataSet)) {
+ if (activeInputContainerRef) {
+ activeInputContainerRef.current = containerRef.current
+ }
+
+ setContent(
+ ,
+ )
+ } else {
+ setContent(undefined)
+ }
+ }, [
+ ListEmptyComponent,
+ activeInputContainerRef,
+ dataSet,
+ direction,
+ inputHeight,
+ isOpened,
+ props,
+ renderItem,
+ setContent,
+ suggestionsListMaxHeight,
+ ])
+
+ return (
+ true}
+ onTouchEnd={(e) => {
+ e.stopPropagation()
+ }}
+ style={[styles.container, containerStyle]}>
+ { }} // it's necessary use onLayout here for Androd (bug?)
+ style={[styles.inputContainerStyle, inputContainerStyle]}>
+ {LeftComponent}
+
+
+
+
+
+
+ )
+ }),
+)
+
+const getStyles = (themeName: 'light' | 'dark' = 'light') =>
+ ScaledSheet.create({
+ container: {
+ marginVertical: 2,
+ },
+ inputContainerStyle: {
+ display: 'flex',
+ flexDirection: 'row',
+ backgroundColor: theme[themeName].inputBackgroundColor,
+ borderRadius: 5,
+ overflow: 'hidden',
+ },
+ input: {
+ flexGrow: 1,
+ flexShrink: 1,
+ overflow: 'hidden',
+ paddingHorizontal: 13,
+ fontSize: 16,
+ color: theme[themeName].inputTextColor,
+ },
+ pressable: {
+ flexGrow: 1,
+ flexShrink: 1,
+ },
+ })
diff --git a/mobile/components/AutocompleteDropdown-v4.3.1/theme.tsx b/mobile/components/AutocompleteDropdown-v4.3.1/theme.tsx
new file mode 100644
index 000000000..3adfa76fd
--- /dev/null
+++ b/mobile/components/AutocompleteDropdown-v4.3.1/theme.tsx
@@ -0,0 +1,23 @@
+export const light = {
+ inputBackgroundColor: '#e5ecf2',
+ inputPlaceholderColor: '#00000066',
+ inputTextColor: '#333',
+ suggestionsListBackgroundColor: '#fff',
+ itemSeparatorColor: '#ddd',
+ shadowColor: '#00000099',
+ listItemTextColor: '#333',
+}
+
+type Theme = typeof light
+
+export const dark: Theme = {
+ inputBackgroundColor: '#1c1c1e',
+ inputPlaceholderColor: '#767680',
+ inputTextColor: '#fff',
+ suggestionsListBackgroundColor: '#151516',
+ itemSeparatorColor: '#3e3e41',
+ shadowColor: '#919aaa5d',
+ listItemTextColor: '#dbdddf',
+}
+
+export const theme = { light, dark }
diff --git a/mobile/components/AutocompleteDropdown-v4.3.1/types/global.d.ts b/mobile/components/AutocompleteDropdown-v4.3.1/types/global.d.ts
new file mode 100644
index 000000000..4f6322192
--- /dev/null
+++ b/mobile/components/AutocompleteDropdown-v4.3.1/types/global.d.ts
@@ -0,0 +1,8 @@
+declare global {
+ namespace setInterval {
+ function setInterval(callback: () => void, ms?: number | undefined): NodeJS.Timeout
+ }
+ namespace setTimeout {
+ function setTimeout(callback: () => void, ms?: number | undefined): NodeJS.Timeout
+ }
+}
diff --git a/mobile/components/AutocompleteDropdown-v4.3.1/types/index.ts b/mobile/components/AutocompleteDropdown-v4.3.1/types/index.ts
new file mode 100644
index 000000000..da696beef
--- /dev/null
+++ b/mobile/components/AutocompleteDropdown-v4.3.1/types/index.ts
@@ -0,0 +1,77 @@
+import type { MutableRefObject } from 'react'
+import type React from 'react'
+import type { StyleProp, TextInputProps, TextStyle, ViewStyle, FlatListProps, TextInput } from 'react-native'
+
+export type AutocompleteDropdownItem = {
+ id: string
+ title?: string | null
+}
+
+export interface IAutocompleteDropdownRef {
+ clear: () => void
+ close: () => void
+ blur: () => void
+ open: () => Promise
+ setInputText: (text: string) => void
+ toggle: () => void
+ setItem: (item: AutocompleteDropdownItem) => void
+}
+
+export interface IAutocompleteDropdownProps {
+ /**
+ * @example [
+ * { id: "1", title: "Alpha" },
+ * { id: "2", title: "Beta" },
+ * { id: "3", title: "Gamma" }
+ * ]
+ */
+ dataSet: AutocompleteDropdownItem[] | null
+ inputHeight?: number
+ suggestionsListMaxHeight?: number
+ initialValue?: string | { id: string } | AutocompleteDropdownItem
+ loading?: boolean
+ useFilter?: boolean
+ showClear?: boolean
+ showChevron?: boolean
+ closeOnBlur?: boolean
+ closeOnSubmit?: boolean
+ clearOnFocus?: boolean
+ caseSensitive?: boolean
+ ignoreAccents?: boolean
+ trimSearchText?: boolean
+ editable?: boolean
+ matchFrom?: 'any' | 'start'
+ debounce?: number
+ direction?: 'down' | 'up'
+ position?: 'absolute' | 'relative'
+ bottomOffset?: number
+ textInputProps?: TextInputProps
+ onChangeText?: (text: string) => void
+ onSelectItem?: (item: AutocompleteDropdownItem | null) => void
+ renderItem?: (item: AutocompleteDropdownItem, searchText: string) => React.ReactElement | null
+ onOpenSuggestionsList?: (isOpened: boolean) => void
+ onClear?: () => void
+ onChevronPress?: () => void
+ onRightIconComponentPress?: () => void
+ onSubmit?: TextInputProps['onSubmitEditing']
+ onBlur?: TextInputProps['onBlur']
+ onFocus?: TextInputProps['onFocus']
+ controller?:
+ | MutableRefObject
+ | ((controller: IAutocompleteDropdownRef | null) => void)
+ containerStyle?: StyleProp
+ inputContainerStyle?: StyleProp
+ rightButtonsContainerStyle?: StyleProp
+ suggestionsListContainerStyle?: StyleProp
+ suggestionsListTextStyle?: StyleProp
+ ChevronIconComponent?: React.ReactElement
+ RightIconComponent?: React.ReactElement
+ LeftComponent?: React.ReactElement
+ ClearIconComponent?: React.ReactElement
+ InputComponent?: React.ComponentType
+ ItemSeparatorComponent?: React.ComponentType | null
+ EmptyResultComponent?: React.ReactElement
+ emptyResultText?: string
+ flatListProps?: Partial>
+ ref?: React.LegacyRef | undefined
+}
diff --git a/mobile/components/AutocompleteDropdown-v4.3.1/useKeyboardHeight.ts b/mobile/components/AutocompleteDropdown-v4.3.1/useKeyboardHeight.ts
new file mode 100644
index 000000000..0f5b3ab72
--- /dev/null
+++ b/mobile/components/AutocompleteDropdown-v4.3.1/useKeyboardHeight.ts
@@ -0,0 +1,17 @@
+import { useEffect, useState } from 'react'
+import { Keyboard } from 'react-native'
+
+export function useKeyboardHeight() {
+ const [keyboardHeight, setKeyboardHeight] = useState(0)
+
+ useEffect(() => {
+ const showSubscription = Keyboard.addListener('keyboardDidShow', e => setKeyboardHeight(e.endCoordinates.height))
+ const hideSubscription = Keyboard.addListener('keyboardDidHide', () => setKeyboardHeight(0))
+ return () => {
+ showSubscription.remove()
+ hideSubscription.remove()
+ }
+ }, [])
+
+ return keyboardHeight
+}
diff --git a/mobile/components/Layout.tsx b/mobile/components/Layout.tsx
index 984fb2a9f..53e6d263a 100644
--- a/mobile/components/Layout.tsx
+++ b/mobile/components/Layout.tsx
@@ -9,7 +9,7 @@ import Button from './Button'
import i18n from '@/lang/i18n'
import * as helper from '@/common/helper'
import Header from './Header'
-import { AutocompleteDropdownContextProvider } from './AutocompleteDropdown-v4'
+// import { AutocompleteDropdownContextProvider } from './AutocompleteDropdown-v4.3.1'
interface LayoutProps {
navigation: NativeStackNavigationProp
@@ -136,7 +136,7 @@ const Layout = ({
{(!loading
&& ((!user && !strict) || (user && user.verified) ? (
- {children}
+ children
) : (
{i18n.t('VALIDATE_EMAIL')}
diff --git a/mobile/components/LocationSelectList.tsx b/mobile/components/LocationSelectList.tsx
index 351f0f4d9..620760f34 100644
--- a/mobile/components/LocationSelectList.tsx
+++ b/mobile/components/LocationSelectList.tsx
@@ -4,7 +4,7 @@ import { MaterialIcons } from '@expo/vector-icons'
import * as env from '@/config/env.config'
import * as LocationService from '@/services/LocationService'
import * as helper from '@/common/helper'
-import { AutocompleteDropdown, AutocompleteDropdownItem } from './AutocompleteDropdown-v4'
+import { AutocompleteDropdown, AutocompleteDropdownItem } from './AutocompleteDropdown-v4.3.1'
interface LocationSelectListProps {
selectedItem?: string