From 594de4668248bac9b744e6882329183c95ac339c Mon Sep 17 00:00:00 2001 From: Leon Jiang <35908040+leonyjiang@users.noreply.github.com> Date: Wed, 10 Mar 2021 18:15:26 -0500 Subject: Add utils, fix ordering of recent searches --- src/screens/search/SearchScreen.tsx | 52 ++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 29 deletions(-) (limited to 'src/screens') diff --git a/src/screens/search/SearchScreen.tsx b/src/screens/search/SearchScreen.tsx index 728510c5..089e0d27 100644 --- a/src/screens/search/SearchScreen.tsx +++ b/src/screens/search/SearchScreen.tsx @@ -18,7 +18,13 @@ import {loadSearchResults} from '../../services'; import {resetScreenType} from '../../store/actions'; import {RootState} from '../../store/rootReducer'; import {ProfilePreviewType, ScreenType, CategoryPreviewType} from '../../types'; -import {normalize, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils'; +import { + normalize, + SCREEN_HEIGHT, + SCREEN_WIDTH, + getRecentlySearchedCategories, + getRecentlySearchedUsers, +} from '../../utils'; /** * Search Screen for user recommendations and a search @@ -58,9 +64,8 @@ const SearchScreen: React.FC = () => { */ useEffect(() => { if (!searching) return; - if (!query.length) loadRecentSearches(); if (query.length < 3) { - setResults(undefined); + loadRecentlySearched().then(() => setResults(undefined)); return; } (async () => { @@ -101,7 +106,9 @@ const SearchScreen: React.FC = () => { // when searching state changes, run animation and reset query accordingly useEffect(() => { if (searching) { - timing(top, topInConfig).start(); + loadRecentlySearched().then(() => { + timing(top, topInConfig).start(); + }); } else { setQuery(''); handleBlur(); @@ -109,36 +116,23 @@ const SearchScreen: React.FC = () => { } }, [searching]); - const loadRecentlySearchedUsers = async () => { - try { - const asyncCache = await AsyncStorage.getItem('@recently_searched_users'); - asyncCache != null ? setRecents(JSON.parse(asyncCache)) : setRecents([]); - } catch (e) { - console.log(e); - } - }; - const loadRecentlySearchedCategories = async () => { - try { - const recentCategoriesJSON = await AsyncStorage.getItem( - '@recently_searched_categories', - ); - setRecentCategories( - recentCategoriesJSON ? JSON.parse(recentCategoriesJSON) : [], - ); - } catch (e) { - console.log(e); - } - }; - const loadRecentSearches = () => { - loadRecentlySearchedUsers(); - loadRecentlySearchedCategories(); + // loads recent searches (users & categories) from AsyncStorage + const loadRecentlySearched = async () => { + return Promise.all([ + getRecentlySearchedUsers(), + getRecentlySearchedCategories(), + ]).then( + ([users, categories]: [ProfilePreviewType[], CategoryPreviewType[]]) => { + setRecents(users); + setRecentCategories(categories); + }, + ); }; const clearRecentlySearched = async () => { try { AsyncStorage.removeItem('@recently_searched_users'); AsyncStorage.removeItem('@recently_searched_categories'); - loadRecentlySearchedUsers(); - loadRecentlySearchedCategories(); + loadRecentlySearched(); } catch (e) { console.log(e); } -- cgit v1.2.3-70-g09d2 From f7557073cc3a5a70b8514c7cb041952d54aa31a1 Mon Sep 17 00:00:00 2001 From: Leon Jiang <35908040+leonyjiang@users.noreply.github.com> Date: Wed, 10 Mar 2021 19:02:29 -0500 Subject: Add simple, non-animated dynamic placeholder --- src/components/search/SearchBar.tsx | 83 +++++++++++++++++++++++++++++++++++-- src/screens/search/SearchScreen.tsx | 2 +- 2 files changed, 80 insertions(+), 5 deletions(-) (limited to 'src/screens') diff --git a/src/components/search/SearchBar.tsx b/src/components/search/SearchBar.tsx index 5e3a1e64..61d7582f 100644 --- a/src/components/search/SearchBar.tsx +++ b/src/components/search/SearchBar.tsx @@ -1,4 +1,4 @@ -import React, {useState} from 'react'; +import React, {useState, useEffect} from 'react'; import { StyleSheet, TextInput, @@ -20,6 +20,7 @@ const AnimatedIcon = Animated.createAnimatedComponent(Icon); interface SearchBarProps extends TextInputProps { onCancel: () => void; top: Animated.Value; + searching: boolean; } const SearchBar: React.FC = ({ onFocus, @@ -27,6 +28,7 @@ const SearchBar: React.FC = ({ onChangeText, value, onCancel, + searching, top, }) => { const handleSubmit = ( @@ -35,9 +37,83 @@ const SearchBar: React.FC = ({ e.preventDefault(); Keyboard.dismiss(); }; + const DEFAULT_PLACEHOLDER: string = 'Search'; + // the list of suggestions to cycle through. TODO: get this from the backend + const SEARCH_SUGGESTIONS: string[] = [ + "Brown '21", + "Brown '22", + "Brown '23", + "Brown '24", + 'Trending on Tagg', + 'New to Tagg', + ]; + /* + * index & id of current placeholder, used in selecting next placeholder. -1 + * indicates DEFAULT_PLACEHOLDER. TODO: make it appear more random by tracking + * last 3-5 ids & use longer list of placeholders + */ + const [placeholderId, setPlaceholderId] = useState(-1); + // the current placeholder + const [placeholder, setPlaceholder] = useState(DEFAULT_PLACEHOLDER); + + /* + * Utility function that generates a random integer in [0, xCeil). + * + * @param xCeil - the exclusive ceiling (getRandomInt(2) => 0 or 1, not 2) + * @returns a random integer in the range [0, xCeil) + */ + const getRandomInt = (xCeil: number): number => { + return Math.floor(Math.random() * Math.floor(xCeil)); + }; + + /* + * Handler for `placeholderChangeInterval` that sets the next placeholderId. + */ + const updatePlaceholder = () => { + let nextId: number = getRandomInt(SEARCH_SUGGESTIONS.length); + while (nextId === placeholderId) { + nextId = getRandomInt(SEARCH_SUGGESTIONS.length); + } + // TODO: FIGURE OUT WHY CHANGES IN placeholderId ARE NOT REFLECTED HERE + // my thought: the value is set when the function is defined, so it keeps + // its inital value of -1 forever. + console.log(`Previous ID: ${placeholderId}`); + console.log(`Next ID: ${nextId}`); + setPlaceholderId(nextId); + }; + + /* + * Update `placeholder` when `placeholderId` is updated by the interval handler. + */ + useEffect(() => { + if (placeholderId === -1) { + setPlaceholder(DEFAULT_PLACEHOLDER); + return; + } + setPlaceholder( + DEFAULT_PLACEHOLDER.concat(` '${SEARCH_SUGGESTIONS[placeholderId]}'`), + ); + }, [placeholderId]); + + /* + * Sets the interval when the user begins searching and clears it when the user is done. + */ + useEffect(() => { + if (!searching) { + return; + } + updatePlaceholder(); + const updateInterval = setInterval(() => { + updatePlaceholder(); + }, 4000); + return () => { + clearInterval(updateInterval); + setPlaceholderId(-1); + }; + }, [searching]); /* - * CSS properties for width change animation. + * Animated nodes used in search bar activation animation. */ const marginRight: Animated.Node = interpolate(top, { inputRange: [-SCREEN_HEIGHT, 0], @@ -59,13 +135,12 @@ const SearchBar: React.FC = ({ /> diff --git a/src/screens/search/SearchScreen.tsx b/src/screens/search/SearchScreen.tsx index 089e0d27..59b17f57 100644 --- a/src/screens/search/SearchScreen.tsx +++ b/src/screens/search/SearchScreen.tsx @@ -167,7 +167,7 @@ const SearchScreen: React.FC = () => { onBlur={handleBlur} onFocus={handleFocus} value={query} - {...{top}} + {...{top, searching}} />