diff --git a/src/screens/searchResult/screen/searchResultScreen.tsx b/src/screens/searchResult/screen/searchResultScreen.tsx
index f284454908..c53711e31c 100644
--- a/src/screens/searchResult/screen/searchResultScreen.tsx
+++ b/src/screens/searchResult/screen/searchResultScreen.tsx
@@ -1,11 +1,11 @@
-import React, { useState } from 'react';
+import React, { memo, useState } from 'react';
import { View } from 'react-native';
import ScrollableTabView from 'react-native-scrollable-tab-view';
import { useIntl } from 'react-intl';
-import { debounce } from 'lodash';
+import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
+import useDebounce from '../../../utils/useDebounceHook';
// Components
-import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
import { SearchInput, TabBar } from '../../../components';
import Communities from './tabs/communities/view/communitiesResults';
import PostsResults from './tabs/best/view/postsResults';
@@ -17,13 +17,52 @@ import styles from './searchResultStyles';
import globalStyles from '../../../globalStyles';
const SearchResultScreen = ({ navigation }) => {
- const [searchValue, setSearchValue] = useState('');
const intl = useIntl();
+ const { debounce } = useDebounce();
+
+ const [searchInputValue, setSearchInputValue] = useState('');
+ const [searchValue, setSearchValue] = useState('');
+
+ const _handleChangeText = (value) => {
+ setSearchInputValue(value);
+ };
+
+ const _handleSearchValue = (value) => {
+ setSearchValue(value);
+ };
+
+ // custom debounce to debounce search value but updates search input value instantly
+ // fixes character missing bug due to lodash debounce
+ const debouncedSearch = debounce(_handleSearchValue, _handleChangeText, 1000);
const _navigationGoBack = () => {
navigation.goBack();
};
+ return (
+
+
+
+
+ );
+};
+
+const SearchResultsTabView = memo(({ searchValue }: { searchValue: string }) => {
+ const intl = useIntl();
+
+ const clippedSearchValue =
+ searchValue.startsWith('#') || searchValue.startsWith('@')
+ ? searchValue.substring(1)
+ : searchValue;
+ const isUsername = !!(searchValue.startsWith('#') || searchValue.startsWith('@'));
+
const _renderTabbar = () => (
{
/>
);
- const _handleChangeText = debounce((value) => {
- setSearchValue(value);
- }, 1000);
-
- const clippedSearchValue =
- searchValue.startsWith('#') || searchValue.startsWith('@')
- ? searchValue.substring(1)
- : searchValue;
-
return (
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
);
-};
+});
export default gestureHandlerRootHOC(SearchResultScreen);
diff --git a/src/screens/searchResult/screen/tabs/people/container/peopleResultsContainer.js b/src/screens/searchResult/screen/tabs/people/container/peopleResultsContainer.js
index 02b476b87c..334e450010 100644
--- a/src/screens/searchResult/screen/tabs/people/container/peopleResultsContainer.js
+++ b/src/screens/searchResult/screen/tabs/people/container/peopleResultsContainer.js
@@ -5,16 +5,24 @@ import { useNavigation } from '@react-navigation/native';
import ROUTES from '../../../../../../constants/routeNames';
import { searchAccount } from '../../../../../../providers/ecency/ecency';
+import { lookupAccounts } from '../../../../../../providers/hive/dhive';
-const PeopleResultsContainer = ({ children, searchValue, username }) => {
+const PeopleResultsContainer = ({ children, searchValue, username, isUsername }) => {
const navigation = useNavigation();
const [users, setUsers] = useState([]);
+ const [userNames, setUsernames] = useState([]);
const [noResult, setNoResult] = useState(false);
useEffect(() => {
setNoResult(false);
setUsers([]);
+ if (!searchValue) {
+ setUsernames([]);
+ }
+ if (searchValue && isUsername) {
+ _fetchUsernames(searchValue);
+ }
searchAccount(searchValue, 20, searchValue ? 0 : 1)
.then((res) => {
@@ -29,6 +37,11 @@ const PeopleResultsContainer = ({ children, searchValue, username }) => {
});
}, [searchValue]);
+ const _fetchUsernames = async (username) => {
+ const users = await lookupAccounts(username);
+ setUsernames(users);
+ };
+
// Component Functions
const _handleOnPress = (item) => {
@@ -45,6 +58,7 @@ const PeopleResultsContainer = ({ children, searchValue, username }) => {
children &&
children({
users,
+ userNames,
handleOnPress: _handleOnPress,
noResult,
})
diff --git a/src/screens/searchResult/screen/tabs/people/view/peopleResults.js b/src/screens/searchResult/screen/tabs/people/view/peopleResults.js
index 5d142b0d07..8f53e977e1 100644
--- a/src/screens/searchResult/screen/tabs/people/view/peopleResults.js
+++ b/src/screens/searchResult/screen/tabs/people/view/peopleResults.js
@@ -11,7 +11,7 @@ import PeopleResultsContainer from '../container/peopleResultsContainer';
import styles from './peopleResultsStyles';
-const PeopleResults = ({ searchValue }) => {
+const PeopleResults = ({ searchValue, isUsername }) => {
const _renderEmptyContent = () => {
return (
<>
@@ -20,11 +20,38 @@ const PeopleResults = ({ searchValue }) => {
);
};
+ const _renderUsernames = (userNames, handleOnPress) => {
+ return searchValue && isUsername && userNames && userNames.length ? (
+ index.toString()}
+ renderItem={({ item, index }) => (
+
+ handleOnPress({
+ name: item,
+ text: item,
+ })
+ }
+ index={index}
+ username={item}
+ text={`@${item}`}
+ isHasRightItem
+ isLoggedIn
+ searchValue={searchValue}
+ isLoadingRightAction={false}
+ />
+ )}
+ ListEmptyComponent={_renderEmptyContent}
+ />
+ ) : null;
+ };
+
return (
-
- {({ users, handleOnPress, noResult }) => (
+
+ {({ users, userNames, handleOnPress, noResult }) => (
- {noResult ? (
+ {noResult && !userNames.length ? (
) : (
{
/>
)}
ListEmptyComponent={_renderEmptyContent}
+ ListHeaderComponent={_renderUsernames(userNames, handleOnPress)}
/>
)}
diff --git a/src/utils/useDebounceHook.ts b/src/utils/useDebounceHook.ts
new file mode 100644
index 0000000000..c956648116
--- /dev/null
+++ b/src/utils/useDebounceHook.ts
@@ -0,0 +1,36 @@
+import { useEffect, useRef } from 'react';
+
+/**
+ * custom debounce hook returns a method which debounces first method and always call the second method
+ */
+export const useDebounce = () => {
+ const timeoutToClear = useRef(null);
+
+ useEffect(() => {
+ return () => {
+ clearTimeout(timeoutToClear?.current as any);
+ };
+ }, []);
+
+ /**
+ * custom debounce method which debounces first method and always call the second method
+ * @param {function which needs to be debounced} callback
+ * @param {this function would be called always} alwaysCall
+ * @param {debounce delay in ms} ms
+ */
+ const debounce = (callback, alwaysCall, ms) => {
+ return (...args) => {
+ alwaysCall(...args);
+ clearTimeout(timeoutToClear?.current as any);
+ timeoutToClear.current = setTimeout(() => {
+ callback(...args);
+ }, ms);
+ };
+ };
+
+ return {
+ debounce,
+ };
+};
+
+export default useDebounce;