From 1e3d4070bd6465ec96ac8dcd56664e71923c6ade Mon Sep 17 00:00:00 2001 From: Cosimo Negri Date: Tue, 19 Sep 2023 23:31:07 +0200 Subject: [PATCH 1/9] [search] Add SVG assets --- assets/search/materials.svg | 3 +++ assets/search/news.svg | 3 +++ assets/search/notifications.svg | 3 +++ assets/search/sections.svg | 3 +++ 4 files changed, 12 insertions(+) create mode 100644 assets/search/materials.svg create mode 100644 assets/search/news.svg create mode 100644 assets/search/notifications.svg create mode 100644 assets/search/sections.svg diff --git a/assets/search/materials.svg b/assets/search/materials.svg new file mode 100644 index 00000000..d6771cf4 --- /dev/null +++ b/assets/search/materials.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/search/news.svg b/assets/search/news.svg new file mode 100644 index 00000000..5bf27248 --- /dev/null +++ b/assets/search/news.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/search/notifications.svg b/assets/search/notifications.svg new file mode 100644 index 00000000..556aae6a --- /dev/null +++ b/assets/search/notifications.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/search/sections.svg b/assets/search/sections.svg new file mode 100644 index 00000000..f4b42e33 --- /dev/null +++ b/assets/search/sections.svg @@ -0,0 +1,3 @@ + + + From 68ebc0f23b2bc8715dd3840cbf10aa613b8e2b7e Mon Sep 17 00:00:00 2001 From: Cosimo Negri Date: Thu, 21 Sep 2023 13:41:42 +0200 Subject: [PATCH 2/9] add global search page --- src/components/Search/SearchTagFilter.tsx | 59 +++++++++ src/components/Search/SearchTile.tsx | 81 ++++++++++++ src/navigation/NavigationTypes.ts | 1 + src/pages/GlobalSearch.tsx | 154 ++++++++++++++++++++++ src/utils/search.ts | 33 +++++ 5 files changed, 328 insertions(+) create mode 100644 src/components/Search/SearchTagFilter.tsx create mode 100644 src/components/Search/SearchTile.tsx create mode 100644 src/pages/GlobalSearch.tsx create mode 100644 src/utils/search.ts diff --git a/src/components/Search/SearchTagFilter.tsx b/src/components/Search/SearchTagFilter.tsx new file mode 100644 index 00000000..01d6c42a --- /dev/null +++ b/src/components/Search/SearchTagFilter.tsx @@ -0,0 +1,59 @@ +import { Pressable } from "react-native" +import { SearchTag, getSearchTagIcon } from "utils/search" + +import { BodyText } from "components/Text" +import { Icon } from "components/Icon" +import { usePalette } from "utils/colors" + +interface SearchTagFilterProps { + tag: SearchTag + title: string + onClick: () => void + isSelected: boolean +} + +export const SearchTagFilter = ({ + tag, + title, + onClick, + isSelected, +}: SearchTagFilterProps) => { + const { isLight, buttonFill } = usePalette() + const icon = getSearchTagIcon(tag) + + return ( + + + + {title} + + + ) +} diff --git a/src/components/Search/SearchTile.tsx b/src/components/Search/SearchTile.tsx new file mode 100644 index 00000000..807645b8 --- /dev/null +++ b/src/components/Search/SearchTile.tsx @@ -0,0 +1,81 @@ +import { Pressable, View } from "react-native" +import { SearchTag, getSearchTagIcon } from "utils/search" + +import { BodyText } from "components/Text" +import { Icon } from "components/Icon" +import { usePalette } from "utils/colors" +import { Divider } from "components/Divider" + +interface SearchTileProps { + tag: SearchTag + title: string + subtitle?: string + onClick?: () => void +} + +export const SearchTile = ({ + tag, + title, + subtitle, + onClick, +}: SearchTileProps) => { + const { isLight, buttonFill } = usePalette() + const icon = getSearchTagIcon(tag) + + return ( + + + + + + + + + {title} + + + {subtitle && ( + + {subtitle} + + )} + + + + + + ) +} diff --git a/src/navigation/NavigationTypes.ts b/src/navigation/NavigationTypes.ts index 5844b434..d2081c84 100644 --- a/src/navigation/NavigationTypes.ts +++ b/src/navigation/NavigationTypes.ts @@ -54,6 +54,7 @@ export type RootStackNavigatorParams = { export type MainStackNavigatorParams = { Home: undefined + GlobalSearch: undefined Article: { article: Article } ArticlesList: { tagName: string } OtherCategories: { tags: TagWithData[] } diff --git a/src/pages/GlobalSearch.tsx b/src/pages/GlobalSearch.tsx new file mode 100644 index 00000000..8e7dd3c8 --- /dev/null +++ b/src/pages/GlobalSearch.tsx @@ -0,0 +1,154 @@ +import React from "react" +import { View, StyleSheet } from "react-native" + +import { MainStackScreen } from "navigation/NavigationTypes" +import { ListPage } from "components/PageLayout" +import { PoliSearchBar } from "components/Home" +import { SearchTagFilter } from "components/Search/SearchTagFilter" +import { SearchTile } from "components/Search/SearchTile" +import { SearchTag, SEARCH_TAGS, SEARCH_TAG_TO_LABEL } from "utils/search" + +export const GlobalSearch: MainStackScreen<"GlobalSearch"> = () => { + const [selectedTag, setSelectedTag] = React.useState(null) + const [input, setInput] = React.useState("") + + // temporary result + const resultData = [ + { + tag: "news" as const, + title: "Titolo News", + subtitle: "Questo e un risultato di ricerca", + key: 0, + }, + { + tag: "sections" as const, + title: "Titolo sezione", + subtitle: "Questo e un risultato di ricerca", + key: 1, + }, + { + tag: "notifications" as const, + title: "Titolo notifica", + subtitle: "Questo e un risultato di ricerca", + key: 2, + }, + { + tag: "materials" as const, + title: "Titolo materiali", + subtitle: "Questo e un risultato di ricerca", + key: 3, + }, + { + tag: "news" as const, + title: "Titolo News", + subtitle: "Questo e un risultato di ricerca", + key: 4, + }, + { + tag: "sections" as const, + title: "Titolo sezione", + subtitle: "Questo e un risultato di ricerca", + key: 5, + }, + { + tag: "notifications" as const, + title: "Titolo notifica", + subtitle: "Questo e un risultato di ricerca", + key: 6, + }, + { + tag: "materials" as const, + title: "Titolo materiali", + subtitle: "Questo e un risultato di ricerca", + key: 7, + }, + { + tag: "news" as const, + title: "Titolo News", + subtitle: "Questo e un risultato di ricerca", + key: 8, + }, + { + tag: "sections" as const, + title: "Titolo sezione", + subtitle: "Questo e un risultato di ricerca", + key: 9, + }, + { + tag: "notifications" as const, + title: "Titolo notifica", + subtitle: "Questo e un risultato di ricerca", + key: 10, + }, + { + tag: "materials" as const, + title: "Titolo materiali", + subtitle: "Questo e un risultato di ricerca", + key: 11, + }, + ] + + return ( + + setInput(input)} + /> + + {SEARCH_TAGS.map(tag => ( + + + tag === selectedTag + ? setSelectedTag(null) + : setSelectedTag(tag) + } + isSelected={tag === selectedTag} + /> + + ))} + + + } + data={ + input + ? resultData.filter( + result => !selectedTag || result.tag === selectedTag + ) + : [] + } + renderItem={({ item }) => ( + + )} + /> + ) +} + +const styles = StyleSheet.create({ + searchBar: { + marginBottom: 0, + }, + tagsContainer: { + flexDirection: "row", + flexWrap: "wrap", + marginTop: 16, + marginBottom: 10, + alignSelf: "center", + justifyContent: "center", + }, + tag: { + width: "50%", + minWidth: 130, + paddingHorizontal: 4, + paddingVertical: 6, + }, +}) diff --git a/src/utils/search.ts b/src/utils/search.ts new file mode 100644 index 00000000..c1eb7da5 --- /dev/null +++ b/src/utils/search.ts @@ -0,0 +1,33 @@ +import news from "assets/search/news.svg" +import notifications from "assets/search/notifications.svg" +import sections from "assets/search/sections.svg" +import materials from "assets/search/materials.svg" + +export const SEARCH_TAGS = [ + "sections", + "news", + "notifications", + "materials", +] as const + +export type SearchTag = (typeof SEARCH_TAGS)[number] + +export const SEARCH_TAG_TO_LABEL: Record = { + sections: "Sezioni dell'app", + news: "News & Avvisi", + notifications: "Notifiche", + materials: "Materiali", +} + +export const getSearchTagIcon = (type: SearchTag) => { + switch (type) { + case "news": + return news + case "notifications": + return notifications + case "sections": + return sections + case "materials": + return materials + } +} From db07eeb6f6195064605376e6e9e4c33ebf0cf16d Mon Sep 17 00:00:00 2001 From: Cosimo Negri Date: Thu, 21 Sep 2023 13:42:52 +0200 Subject: [PATCH 3/9] add navigation from `Home` to `GlobalSearch` --- src/components/Home/SearchButton.tsx | 39 +++++++++++++++++++++++++++ src/components/Home/index.tsx | 1 + src/navigation/MainStackNavigator.tsx | 2 ++ src/pages/Home.tsx | 4 +-- 4 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/components/Home/SearchButton.tsx diff --git a/src/components/Home/SearchButton.tsx b/src/components/Home/SearchButton.tsx new file mode 100644 index 00000000..9dc68645 --- /dev/null +++ b/src/components/Home/SearchButton.tsx @@ -0,0 +1,39 @@ +import { Pressable } from "react-native" +import { useTranslation } from "react-i18next" +import { useNavigation } from "navigation/NavigationTypes" + +import searchDark from "assets/menu/searchDark.svg" +import { Icon } from "components/Icon" +import { BodyText } from "components/Text" +import { usePalette } from "utils/colors" + +export const SearchButton = () => { + const navigation = useNavigation() + const { fieldBackground, buttonFill } = usePalette() + + const { t } = useTranslation() //i18n hook + + return ( + navigation.navigate("GlobalSearch")} + > + + + {"" + t("search")} + + + ) +} diff --git a/src/components/Home/index.tsx b/src/components/Home/index.tsx index d8f369f8..8138fa89 100644 --- a/src/components/Home/index.tsx +++ b/src/components/Home/index.tsx @@ -3,3 +3,4 @@ export * from "./MainTitle" export * from "./MenuButton" export * from "./StickyHeader" export * from "./PoliSearchBar" +export * from "./SearchButton" diff --git a/src/navigation/MainStackNavigator.tsx b/src/navigation/MainStackNavigator.tsx index a1638937..96bb665d 100644 --- a/src/navigation/MainStackNavigator.tsx +++ b/src/navigation/MainStackNavigator.tsx @@ -6,6 +6,7 @@ import { FC } from "react" import { MainStackNavigatorParams } from "navigation/NavigationTypes" import { Home } from "pages/Home" +import { GlobalSearch } from "pages/GlobalSearch" import { Article } from "pages/news/ArticleDetails" import { ArticlesList } from "pages/news/ArticlesList" import { Error404 } from "pages/Error404" @@ -38,6 +39,7 @@ export const MainStack: FC = () => { initialRouteName="Home" > + = () => { borderTopRightRadius: 30, }} > - setSearch(searchKey)} /> + From 1e92bd5aeba387f3d0bf0135275d45639e29c198 Mon Sep 17 00:00:00 2001 From: Cosimo Negri Date: Thu, 21 Sep 2023 13:46:30 +0200 Subject: [PATCH 4/9] =?UTF-8?q?=E2=9C=8F=EF=B8=8Frename=20`Search`=20folde?= =?UTF-8?q?r=20to=20`GlobalSearch`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/{Search => GlobalSearch}/SearchTagFilter.tsx | 0 src/components/{Search => GlobalSearch}/SearchTile.tsx | 0 src/pages/GlobalSearch.tsx | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/components/{Search => GlobalSearch}/SearchTagFilter.tsx (100%) rename src/components/{Search => GlobalSearch}/SearchTile.tsx (100%) diff --git a/src/components/Search/SearchTagFilter.tsx b/src/components/GlobalSearch/SearchTagFilter.tsx similarity index 100% rename from src/components/Search/SearchTagFilter.tsx rename to src/components/GlobalSearch/SearchTagFilter.tsx diff --git a/src/components/Search/SearchTile.tsx b/src/components/GlobalSearch/SearchTile.tsx similarity index 100% rename from src/components/Search/SearchTile.tsx rename to src/components/GlobalSearch/SearchTile.tsx diff --git a/src/pages/GlobalSearch.tsx b/src/pages/GlobalSearch.tsx index 8e7dd3c8..2c3ac408 100644 --- a/src/pages/GlobalSearch.tsx +++ b/src/pages/GlobalSearch.tsx @@ -4,8 +4,8 @@ import { View, StyleSheet } from "react-native" import { MainStackScreen } from "navigation/NavigationTypes" import { ListPage } from "components/PageLayout" import { PoliSearchBar } from "components/Home" -import { SearchTagFilter } from "components/Search/SearchTagFilter" -import { SearchTile } from "components/Search/SearchTile" +import { SearchTagFilter } from "components/GlobalSearch/SearchTagFilter" +import { SearchTile } from "components/GlobalSearch/SearchTile" import { SearchTag, SEARCH_TAGS, SEARCH_TAG_TO_LABEL } from "utils/search" export const GlobalSearch: MainStackScreen<"GlobalSearch"> = () => { From 65f33b30c148132ecade8e966cbcbb2f801d80ad Mon Sep 17 00:00:00 2001 From: Cosimo Negri Date: Thu, 21 Sep 2023 13:49:13 +0200 Subject: [PATCH 5/9] [fix linter] add key prop to elements in iterator --- src/pages/GlobalSearch.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/GlobalSearch.tsx b/src/pages/GlobalSearch.tsx index 2c3ac408..e0faf0b7 100644 --- a/src/pages/GlobalSearch.tsx +++ b/src/pages/GlobalSearch.tsx @@ -100,6 +100,7 @@ export const GlobalSearch: MainStackScreen<"GlobalSearch"> = () => { {SEARCH_TAGS.map(tag => ( From 0fb3a5b80305b83c3acdb094d4aa912883d13281 Mon Sep 17 00:00:00 2001 From: Cosimo Negri Date: Thu, 21 Sep 2023 13:53:22 +0200 Subject: [PATCH 6/9] [fix linter] really fix the issue with the key prop --- src/pages/GlobalSearch.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/GlobalSearch.tsx b/src/pages/GlobalSearch.tsx index e0faf0b7..d4f54f50 100644 --- a/src/pages/GlobalSearch.tsx +++ b/src/pages/GlobalSearch.tsx @@ -98,9 +98,8 @@ export const GlobalSearch: MainStackScreen<"GlobalSearch"> = () => { /> {SEARCH_TAGS.map(tag => ( - + From 4d819d6e6743d470c836f74d2435fb7e4639c86e Mon Sep 17 00:00:00 2001 From: Cosimo Negri Date: Thu, 21 Sep 2023 13:59:45 +0200 Subject: [PATCH 7/9] [fix linter] remove unused filter from the `MainMenu` --- src/components/Home/MainMenu.tsx | 13 +++---------- src/pages/Home.tsx | 5 +---- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/components/Home/MainMenu.tsx b/src/components/Home/MainMenu.tsx index 8a35c008..82d6ba96 100644 --- a/src/components/Home/MainMenu.tsx +++ b/src/components/Home/MainMenu.tsx @@ -1,4 +1,4 @@ -import { FC, useEffect, useState } from "react" +import { useEffect, useState } from "react" import { ScrollView, View } from "react-native" import { useNavigation } from "navigation/NavigationTypes" @@ -25,7 +25,7 @@ type ButtonState = ButtonInterface & { shown: boolean } /** * the main menu of the app, an horizontal scroll view with the buttons to navigate to the different pages */ -export const MainMenu: FC<{ filter?: string }> = ({ filter }) => { +export const MainMenu = () => { const { navigate } = useNavigation() const defaultIcons: ButtonInterface[] = [ @@ -110,7 +110,7 @@ export const MainMenu: FC<{ filter?: string }> = ({ filter }) => { useEffect(() => { scrollView.current?.scrollTo({ x: 0, y: 0, animated: true }) - }, [filter, scrollView]) + }, [scrollView]) useEffect(() => { AsyncStorage.getItem("menu:icons") @@ -206,13 +206,6 @@ export const MainMenu: FC<{ filter?: string }> = ({ filter }) => { {icons .filter(i => i.shown) - .filter( - i => - i.type === ButtonType.ADD || - (filter - ? i.title.toLowerCase().includes(filter.toLowerCase()) - : true) - ) .map(buttonIcon => ( { diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index 8c725d8d..f8cdaa81 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -1,4 +1,3 @@ -import { useState } from "react" import { View } from "react-native" import { NewsManager } from "components/Home/News" @@ -15,8 +14,6 @@ import { BoxShadowView } from "components/BoxShadow" export const Home: MainStackScreen<"Home"> = () => { const { homeBackground, background } = usePalette() - const [search, setSearch] = useState("") - return ( = () => { }} > - + From 25325f65376edbf9ffda6571f32a0adef9a7e99c Mon Sep 17 00:00:00 2001 From: Cosimo Negri Date: Thu, 21 Sep 2023 14:05:12 +0200 Subject: [PATCH 8/9] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20move=20`PoliSearchBar`?= =?UTF-8?q?=20out=20of=20the=20`Home`=20folder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Home/index.tsx | 1 - src/components/{Home => }/PoliSearchBar.tsx | 0 src/pages/FreeClass/FreeClassrooms.tsx | 2 +- src/pages/GlobalSearch.tsx | 2 +- src/pages/Groups.tsx | 2 +- 5 files changed, 3 insertions(+), 4 deletions(-) rename src/components/{Home => }/PoliSearchBar.tsx (100%) diff --git a/src/components/Home/index.tsx b/src/components/Home/index.tsx index 8138fa89..64fc4c4d 100644 --- a/src/components/Home/index.tsx +++ b/src/components/Home/index.tsx @@ -2,5 +2,4 @@ export * from "./MainMenu" export * from "./MainTitle" export * from "./MenuButton" export * from "./StickyHeader" -export * from "./PoliSearchBar" export * from "./SearchButton" diff --git a/src/components/Home/PoliSearchBar.tsx b/src/components/PoliSearchBar.tsx similarity index 100% rename from src/components/Home/PoliSearchBar.tsx rename to src/components/PoliSearchBar.tsx diff --git a/src/pages/FreeClass/FreeClassrooms.tsx b/src/pages/FreeClass/FreeClassrooms.tsx index 65432b65..5bb4e4a7 100644 --- a/src/pages/FreeClass/FreeClassrooms.tsx +++ b/src/pages/FreeClass/FreeClassrooms.tsx @@ -1,7 +1,7 @@ import { useContext, useEffect, useState } from "react" import { MainStackScreen, useNavigation } from "navigation/NavigationTypes" import { View, Alert, ActivityIndicator, StyleSheet } from "react-native" -import { PoliSearchBar } from "components/Home" +import { PoliSearchBar } from "components/PoliSearchBar" import { usePalette } from "utils/colors" import { BodyText } from "components/Text" import campusIcon from "assets/freeClassrooms/campus.svg" diff --git a/src/pages/GlobalSearch.tsx b/src/pages/GlobalSearch.tsx index d4f54f50..58f5c5cf 100644 --- a/src/pages/GlobalSearch.tsx +++ b/src/pages/GlobalSearch.tsx @@ -3,7 +3,7 @@ import { View, StyleSheet } from "react-native" import { MainStackScreen } from "navigation/NavigationTypes" import { ListPage } from "components/PageLayout" -import { PoliSearchBar } from "components/Home" +import { PoliSearchBar } from "components/PoliSearchBar" import { SearchTagFilter } from "components/GlobalSearch/SearchTagFilter" import { SearchTile } from "components/GlobalSearch/SearchTile" import { SearchTag, SEARCH_TAGS, SEARCH_TAG_TO_LABEL } from "utils/search" diff --git a/src/pages/Groups.tsx b/src/pages/Groups.tsx index 22eddb40..2748d023 100644 --- a/src/pages/Groups.tsx +++ b/src/pages/Groups.tsx @@ -15,7 +15,7 @@ import { import { GroupTile } from "components/Groups/GroupTile" import { ModalGroup } from "components/Groups/ModalGroup" -import { PoliSearchBar } from "components/Home/PoliSearchBar" +import { PoliSearchBar } from "components/PoliSearchBar" import { useTranslation } from "react-i18next" import { useApiCall } from "api/useApiCall" import { ListPage } from "components/PageLayout" From c9e63870aaf0296076fad878dc7190b5d59d0991 Mon Sep 17 00:00:00 2001 From: Cosimo Negri Date: Thu, 21 Sep 2023 15:31:11 +0200 Subject: [PATCH 9/9] navigate to `GlobalSearch` in writing mode --- src/components/PoliSearchBar.tsx | 20 ++++++++++++++------ src/pages/GlobalSearch.tsx | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/components/PoliSearchBar.tsx b/src/components/PoliSearchBar.tsx index 4372586e..86759c6e 100644 --- a/src/components/PoliSearchBar.tsx +++ b/src/components/PoliSearchBar.tsx @@ -1,6 +1,7 @@ -import { FC, useEffect, useState, useRef } from "react" +import { useEffect, useState, useRef } from "react" import { TextInput, + TextInputProps, Animated, Pressable, StyleProp, @@ -12,17 +13,23 @@ import searchDark from "assets/menu/searchDark.svg" import { Icon } from "components/Icon" import { useTranslation } from "react-i18next" +interface PoliSearchBarProps extends Pick { + onChange: (searchKey: string) => void + style?: StyleProp +} + /** * the search bar, which requests a search everytime the input text changes */ -export const PoliSearchBar: FC<{ - onChange: (searchKey: string) => void - style?: StyleProp -}> = ({ onChange, style }) => { +export const PoliSearchBar = ({ + autoFocus = false, + onChange, + style, +}: PoliSearchBarProps) => { const { fieldBackground, fieldText, bodyText, isLight, palette } = usePalette() - const [isFocused, setIsFocused] = useState(false) + const [isFocused, setIsFocused] = useState(autoFocus) const shadowAnim = useRef(new Animated.Value(0)).current const inputText = useRef(null) @@ -98,6 +105,7 @@ export const PoliSearchBar: FC<{ onChangeText={onChange} onFocus={() => setIsFocused(true)} onBlur={() => setIsFocused(false)} + autoFocus={autoFocus} /> = () => { setInput(input)} + autoFocus /> {SEARCH_TAGS.map(tag => (