From 8358841ff7ef18aea987face66895c592f8201e6 Mon Sep 17 00:00:00 2001 From: mirkiy Date: Wed, 21 Aug 2024 19:03:17 +0100 Subject: [PATCH 01/16] search bar and heading in progress --- src/Containers/.StartupContainer.tsx.swp | Bin 0 -> 12288 bytes src/NativeBase/Components/FreeSearchBar.tsx | 30 +++- .../Components/SearchIconHighlighted.tsx | 3 +- src/NativeBase/Containers/ListContainer.tsx | 132 ++++++++++-------- src/Navigators/Main.tsx | 3 +- 5 files changed, 103 insertions(+), 65 deletions(-) create mode 100644 src/Containers/.StartupContainer.tsx.swp diff --git a/src/Containers/.StartupContainer.tsx.swp b/src/Containers/.StartupContainer.tsx.swp new file mode 100644 index 0000000000000000000000000000000000000000..186bc6893e9d8a01a312395073fea1223e41a300 GIT binary patch literal 12288 zcmeI2O>Y}T7{@2&t)+yQq9Sp72uOA!$Lj&>yetVIzJ0JiT!E4|=_+y%}-@$!w4}1-FK>&8ZW$+d_3;uk8 zu_N#+xC1^0AA!^0ud|H(2)+SdfxF;K@Hw~zhCqT9;DMv(8T%Q02kwF|Ko4w#El>il zgK2OEJO`cy&w!`FQ{WVs0=W)PU>;q_P64NYQ@|Dm8^X^0Qde z@uQVisUahp1w_kUTkyk6`LlUz@tz*N5q-epAnkC{Dd{~<%^=lUs6A@&V2>KI)2Bwa zYkePhY4p*E#cooc2{=xD${A}y)b+zqB)j#Q3lG{NoCIx(PkDW2VWKt3Iy+q6h&FIW zRMiIyCgkGs!%s4$)fMa3O0NiQKQ5c_N6(Ewivywi*OO2LzD^}6Gs>V8`*N3;hNN^q z#`}j?GmRisHE(Zk;;TruhvbcBw7e$$Bpkgj8^OlD8-72{bTtxjTp{}sr15$_@9m-K zLUNtSgvt!h!$NhD2wgUhnc|nDhzGh{o~8OF8stWH21}Iq2V&RPype=W(dowgCRbdS zOPe@3TPnIDS~=0orq5ccz4Xww_q;dFEk;{cZ(XdLzV|*`(L7xEzeRVAAE_l%=k!~g20_63|5cioVNABXdhMF>fmc7Ns`RH3`p+ zs#ck*Nrj2G=zk(%7zUa*d5ls?WtpvwjRv;rDrC!;hJ|sV+bn*M<-s1`31Bo18Kq@5 zjRDqmPs2aLoT-%fSU-Gz$5*_>#wHVCj4dVi13fQ!nDr(sA6>j-r&aI0qPkNY0nfCE z)r9XuYC*+=$}3o$Wl;gPqF?TZy&%-aNJX1<1rbsRQ5uKFJESx*6=qJ?SD80A$Nm8Td_fKX literal 0 HcmV?d00001 diff --git a/src/NativeBase/Components/FreeSearchBar.tsx b/src/NativeBase/Components/FreeSearchBar.tsx index cc8fcef9..7b64bcc0 100644 --- a/src/NativeBase/Components/FreeSearchBar.tsx +++ b/src/NativeBase/Components/FreeSearchBar.tsx @@ -2,8 +2,9 @@ * @file Text input for searching. */ -import { Box, Input } from 'native-base' +import { Box, Icon, IconButton, Input } from 'native-base' import React, { FC, useState } from 'react' +import MaterialIcons from 'react-native-vector-icons/MaterialIcons' import SearchIconHighlighted from './SearchIconHighlighted' export interface FreeSearchBarProps { @@ -39,12 +40,31 @@ const FreeSearchBar: FC = ({ const onSubmitEditing = () => handleSubmit(text) + const clearText = () => setText('') + return ( } + InputRightElement={ + text ? ( + + } + onPress={clearText} + variant="link" + _pressed={{ bg: 'gray.200' }} + /> + ) : undefined + } lineHeight="md" marginBottom={marginBottom ?? '4'} marginTop={marginTop ?? '0'} @@ -56,6 +76,14 @@ const FreeSearchBar: FC = ({ placeholder="Search..." textAlignVertical="center" value={text} + borderWidth={0} + backgroundColor={text ? 'gray.200' : 'gray.100'} + borderRadius={15} + placeholderTextColor="gray.400" + color="gray.800" + _focus={{ + borderColor: 'transparent', // Ensure no border color on focus + }} /> ) diff --git a/src/NativeBase/Components/SearchIconHighlighted.tsx b/src/NativeBase/Components/SearchIconHighlighted.tsx index 964794d6..5421a650 100644 --- a/src/NativeBase/Components/SearchIconHighlighted.tsx +++ b/src/NativeBase/Components/SearchIconHighlighted.tsx @@ -14,7 +14,8 @@ import MaterialIcons from 'react-native-vector-icons/MaterialIcons' const SearchIconHighlighted = () => ( text + return ( <> - navigate(screens.search[params.type], '')} - /> - - Projects List + /> */} + + Roles {/* TODO: reinstate when functionality is ready */} {/* */} - {params?.type && listItemsToShow ? ( - <> - {/* Past / Upcoming / My Events choice */} - {params.type === ListType.Events && ( - - )} - - {/* Quick search for upcoming events (Today / This week / This month) */} - {params.type === ListType.Events && - eventsShowUpcomingQuickSearch && - eventsQuickSearchUpcomingChoice && ( + + + + + {params?.type && listItemsToShow ? ( + <> + {/* Past / Upcoming / My Events choice */} + {params.type === ListType.Events && ( + + )} + + {/* Quick search for upcoming events (Today / This week / This month) */} + {params.type === ListType.Events && + eventsShowUpcomingQuickSearch && + eventsQuickSearchUpcomingChoice && ( + + + + )} + + {/* If the user has searched, show some text indicating what they searched for + and give them the option to clear the search */} + {params?.search && ( - + {params?.search?.description && ( + + Results for {params.search.description} + + )} + + Clear search + )} - {/* If the user has searched, show some text indicating what they searched for - and give them the option to clear the search */} - {params?.search && ( - - {params?.search?.description && ( - - Results for {params.search.description} - - )} - - Clear search - - - )} - - {/* Projects filter & sort options */} - {params.type === ListType.Projects && - Boolean(params?.search) && - Boolean(listItemsToShow.length) && } - - - - ) : ( - <> - - - - - )} - + {/* Projects filter & sort options */} + {params.type === ListType.Projects && + Boolean(params?.search) && + Boolean(listItemsToShow.length) && } + + + + ) : ( + <> + + + + + )} + + ) } diff --git a/src/Navigators/Main.tsx b/src/Navigators/Main.tsx index 60e42b8c..391a44a7 100644 --- a/src/Navigators/Main.tsx +++ b/src/Navigators/Main.tsx @@ -7,7 +7,7 @@ import { BottomTabNavigationOptions, } from '@react-navigation/bottom-tabs' import { useRoute } from '@react-navigation/native' -import { ListContainer } from '@/NativeBase/Containers' +import { ListContainer, ProjectSearchContainer } from '@/NativeBase/Containers' import { ListType } from '@/NativeBase/Containers/ListContainer' import { SettingsContainer } from '@/NativeBase/Containers' import SelectionIcons from '@/NativeBase/Assets/Icons/Icomoon/SelectionIcons' @@ -17,6 +17,7 @@ import { Platform } from 'react-native' import MaterialIcons from 'react-native-vector-icons/MaterialIcons' import MyProfile from '@/NativeBase/Containers/ProfileContainer' import { useFeatureFlags } from '@/Services/featureFlags' +import MyExperienceContainer from '@/NativeBase/Containers/MyExperienceContainer' const Tab = createBottomTabNavigator() From d02ea0421d1ee72bb3cf975716a1daa98ccbc0ac Mon Sep 17 00:00:00 2001 From: mirkiy Date: Thu, 5 Sep 2024 17:50:53 +0100 Subject: [PATCH 02/16] tag style buttons in progress --- src/NativeBase/Containers/ListContainer.tsx | 102 +++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/src/NativeBase/Containers/ListContainer.tsx b/src/NativeBase/Containers/ListContainer.tsx index c9b12597..f15302d9 100644 --- a/src/NativeBase/Containers/ListContainer.tsx +++ b/src/NativeBase/Containers/ListContainer.tsx @@ -7,7 +7,17 @@ /* eslint-disable @typescript-eslint/no-shadow */ -import { Heading, ScrollView, VStack } from 'native-base' +import { + Heading, + HStack, + Icon, + IconButton, + ScrollView, + Tag, + VStack, + Text, + Pressable, +} from 'native-base' import React, { useEffect, useState } from 'react' import { Dimensions } from 'react-native' import { useDispatch, useSelector } from 'react-redux' @@ -45,6 +55,7 @@ import { ProjectsState, setProjects } from '@/Store/Projects' import underDevelopmentAlert from '@/Utils/UnderDevelopmentAlert' import SkeletonLoading from '../Components/SkeletonLoading' import FreeSearchBar from '../Components/FreeSearchBar' +import MaterialIcons from 'react-native-vector-icons/MaterialIcons' const ClearSearchLabel = styled.Text` @@ -272,6 +283,10 @@ const ListContainer = (props: { const onSubmitEditing = (text: string) => text + const handleTagPress = (tag: string) => { + console.log(`${tag} tag clicked`) + } + return ( <> {/* + + + handleTagPress('Roles')} + borderRadius={40} + p={2} + display="flex" + flexDirection="row" + alignItems="center" + justifyContent="center" + backgroundColor="#F6E2EE" + borderColor="#D1338A" + borderWidth={1} + > + Roles + + } + variant="outline" + _icon={{ color: 'gray.500' }} + onPress={() => handleTagPress('Roles')} // Optional: Handle icon click separately if needed + /> + + handleTagPress('Tech')} + borderRadius={40} + p={2} + display="flex" + flexDirection="row" + alignItems="center" + justifyContent="center" + backgroundColor="#F6E2EE" + borderColor="#D1338A" + borderWidth={1} + > + Tech + + } + variant="outline" + _icon={{ color: 'gray.500' }} + onPress={() => handleTagPress('Tech')} // Optional: Handle icon click separately if needed + /> + + handleTagPress('Causes')} + borderRadius={40} + p={2} + display="flex" + flexDirection="row" + alignItems="center" + justifyContent="center" + backgroundColor="#F6E2EE" + borderColor="#D1338A" + borderWidth={1} + > + Causes + + } + variant="outline" + _icon={{ color: 'gray.500' }} + onPress={() => handleTagPress('Causes')} // Optional: Handle icon click separately if needed + /> + + + Date: Thu, 5 Sep 2024 18:20:00 +0100 Subject: [PATCH 03/16] toggling icons within tags --- src/NativeBase/Containers/ListContainer.tsx | 40 +++++++++++++++------ 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/NativeBase/Containers/ListContainer.tsx b/src/NativeBase/Containers/ListContainer.tsx index f15302d9..a2da64e2 100644 --- a/src/NativeBase/Containers/ListContainer.tsx +++ b/src/NativeBase/Containers/ListContainer.tsx @@ -160,6 +160,20 @@ const ListContainer = (props: { (state: { projects: ProjectsState }) => state.projects?.projects, ) + // State for toggling icons + const [iconState, setIconState] = useState>({ + Roles: false, + Tech: false, + Causes: false, + }) + + const handleTagPress = (tag: string) => { + setIconState(prevState => ({ + ...prevState, + [tag]: !prevState[tag], // Toggle the state + })) + } + /* * * Shared logic @@ -283,10 +297,6 @@ const ListContainer = (props: { const onSubmitEditing = (text: string) => text - const handleTagPress = (tag: string) => { - console.log(`${tag} tag clicked`) - } - return ( <> {/* } variant="outline" _icon={{ color: 'gray.500' }} - onPress={() => handleTagPress('Roles')} // Optional: Handle icon click separately if needed + onPress={() => handleTagPress('Roles')} /> } variant="outline" _icon={{ color: 'gray.500' }} - onPress={() => handleTagPress('Tech')} // Optional: Handle icon click separately if needed + onPress={() => handleTagPress('Tech')} /> } variant="outline" _icon={{ color: 'gray.500' }} - onPress={() => handleTagPress('Causes')} // Optional: Handle icon click separately if needed + onPress={() => handleTagPress('Causes')} /> From de3f8f6881bbdca4619fd36ac5e1cc38c9934097 Mon Sep 17 00:00:00 2001 From: mirkiy Date: Wed, 11 Sep 2024 18:55:12 +0100 Subject: [PATCH 04/16] new filter button and horizontal scrollview added --- src/NativeBase/Containers/ListContainer.tsx | 235 ++++++++++++-------- 1 file changed, 138 insertions(+), 97 deletions(-) diff --git a/src/NativeBase/Containers/ListContainer.tsx b/src/NativeBase/Containers/ListContainer.tsx index a2da64e2..1751fddd 100644 --- a/src/NativeBase/Containers/ListContainer.tsx +++ b/src/NativeBase/Containers/ListContainer.tsx @@ -17,6 +17,7 @@ import { VStack, Text, Pressable, + View, } from 'native-base' import React, { useEffect, useState } from 'react' import { Dimensions } from 'react-native' @@ -303,107 +304,147 @@ const ListContainer = (props: { showSearchButton onSearchButtonPress={() => navigate(screens.search[params.type], '')} /> */} - - Roles - {/* TODO: reinstate when functionality is ready */} - {/* */} - - - - - handleTagPress('Roles')} - borderRadius={40} - p={2} - display="flex" - flexDirection="row" - alignItems="center" - justifyContent="center" - backgroundColor="#F6E2EE" - borderColor="#D1338A" - borderWidth={1} - > - Roles - - } - variant="outline" - _icon={{ color: 'gray.500' }} + + Roles + + {/* TODO: reinstate when functionality is ready */} + {/* */} + + + + + + } + /> + + + + + + + handleTagPress('Roles')} - /> - - handleTagPress('Tech')} - borderRadius={40} - p={2} - display="flex" - flexDirection="row" - alignItems="center" - justifyContent="center" - backgroundColor="#F6E2EE" - borderColor="#D1338A" - borderWidth={1} - > - Tech - - } - variant="outline" - _icon={{ color: 'gray.500' }} + borderRadius={40} + pl={4} + pr={2} + py={2} + display="flex" + flexDirection="row" + alignItems="center" + justifyContent="center" + backgroundColor="#F6E2EE" + borderColor="#D1338A" + borderWidth={1} + > + Roles + + } + variant="outline" + _icon={{ color: 'gray.500' }} + onPress={() => handleTagPress('Roles')} + /> + + handleTagPress('Tech')} - /> - - handleTagPress('Causes')} - borderRadius={40} - p={2} - display="flex" - flexDirection="row" - alignItems="center" - justifyContent="center" - backgroundColor="#F6E2EE" - borderColor="#D1338A" - borderWidth={1} - > - Causes - - } - variant="outline" - _icon={{ color: 'gray.500' }} + borderRadius={40} + pl={4} + pr={2} + py={2} + display="flex" + flexDirection="row" + alignItems="center" + justifyContent="center" + backgroundColor="#F6E2EE" + borderColor="#D1338A" + borderWidth={1} + > + Tech + + } + variant="outline" + _icon={{ color: 'gray.500' }} + onPress={() => handleTagPress('Tech')} + /> + + handleTagPress('Causes')} - /> - - + borderRadius={40} + pl={4} + pr={2} + py={2} + display="flex" + flexDirection="row" + alignItems="center" + justifyContent="center" + backgroundColor="#F6E2EE" + borderColor="#D1338A" + borderWidth={1} + > + Causes + + } + variant="outline" + _icon={{ color: 'gray.500' }} + onPress={() => handleTagPress('Causes')} + /> + + + Date: Thu, 12 Sep 2024 12:58:20 +0100 Subject: [PATCH 05/16] TagButtons component --- src/NativeBase/Components/TagButtons.tsx | 113 ++++++++++ src/NativeBase/Containers/ListContainer.tsx | 228 ++++++-------------- 2 files changed, 179 insertions(+), 162 deletions(-) create mode 100644 src/NativeBase/Components/TagButtons.tsx diff --git a/src/NativeBase/Components/TagButtons.tsx b/src/NativeBase/Components/TagButtons.tsx new file mode 100644 index 00000000..c30637df --- /dev/null +++ b/src/NativeBase/Components/TagButtons.tsx @@ -0,0 +1,113 @@ +import React from 'react' +import { HStack, Icon, IconButton, Pressable, Text } from 'native-base' +import MaterialIcons from 'react-native-vector-icons/MaterialIcons' + +interface TagButtonsProps { + iconState: Record + handleTagPress: (tag: string) => void +} + +const TagButtons: React.FC = ({ + iconState, + handleTagPress, +}) => { + return ( + + handleTagPress('Roles')} + borderRadius={40} + pl={4} + pr={2} + py={2} + display="flex" + flexDirection="row" + alignItems="center" + justifyContent="center" + backgroundColor="#F6E2EE" + borderColor="#D1338A" + borderWidth={1} + > + Roles + + } + variant="outline" + _icon={{ color: 'gray.500' }} + onPress={() => handleTagPress('Roles')} + /> + + handleTagPress('Tech')} + borderRadius={40} + pl={4} + pr={2} + py={2} + display="flex" + flexDirection="row" + alignItems="center" + justifyContent="center" + backgroundColor="#F6E2EE" + borderColor="#D1338A" + borderWidth={1} + > + Tech + + } + variant="outline" + _icon={{ color: 'gray.500' }} + onPress={() => handleTagPress('Tech')} + /> + + handleTagPress('Causes')} + borderRadius={40} + pl={4} + pr={2} + py={2} + display="flex" + flexDirection="row" + alignItems="center" + justifyContent="center" + backgroundColor="#F6E2EE" + borderColor="#D1338A" + borderWidth={1} + > + Causes + + } + variant="outline" + _icon={{ color: 'gray.500' }} + onPress={() => handleTagPress('Causes')} + /> + + + ) +} + +export default TagButtons diff --git a/src/NativeBase/Containers/ListContainer.tsx b/src/NativeBase/Containers/ListContainer.tsx index 1751fddd..8ad63058 100644 --- a/src/NativeBase/Containers/ListContainer.tsx +++ b/src/NativeBase/Containers/ListContainer.tsx @@ -57,6 +57,7 @@ import underDevelopmentAlert from '@/Utils/UnderDevelopmentAlert' import SkeletonLoading from '../Components/SkeletonLoading' import FreeSearchBar from '../Components/FreeSearchBar' import MaterialIcons from 'react-native-vector-icons/MaterialIcons' +import TagButtons from '../Components/TagButtons' const ClearSearchLabel = styled.Text` @@ -343,173 +344,76 @@ const ListContainer = (props: { showsHorizontalScrollIndicator={false} paddingTop="0px" > - - handleTagPress('Roles')} - borderRadius={40} - pl={4} - pr={2} - py={2} - display="flex" - flexDirection="row" - alignItems="center" - justifyContent="center" - backgroundColor="#F6E2EE" - borderColor="#D1338A" - borderWidth={1} - > - Roles - - } - variant="outline" - _icon={{ color: 'gray.500' }} - onPress={() => handleTagPress('Roles')} - /> - - handleTagPress('Tech')} - borderRadius={40} - pl={4} - pr={2} - py={2} - display="flex" - flexDirection="row" - alignItems="center" - justifyContent="center" - backgroundColor="#F6E2EE" - borderColor="#D1338A" - borderWidth={1} - > - Tech - - } - variant="outline" - _icon={{ color: 'gray.500' }} - onPress={() => handleTagPress('Tech')} - /> - - handleTagPress('Causes')} - borderRadius={40} - pl={4} - pr={2} - py={2} - display="flex" - flexDirection="row" - alignItems="center" - justifyContent="center" - backgroundColor="#F6E2EE" - borderColor="#D1338A" - borderWidth={1} - > - Causes - - } - variant="outline" - _icon={{ color: 'gray.500' }} - onPress={() => handleTagPress('Causes')} - /> - - + - - - - {params?.type && listItemsToShow ? ( - <> - {/* Past / Upcoming / My Events choice */} - {params.type === ListType.Events && ( - - )} - - {/* Quick search for upcoming events (Today / This week / This month) */} - {params.type === ListType.Events && - eventsShowUpcomingQuickSearch && - eventsQuickSearchUpcomingChoice && ( + + + + {params?.type && listItemsToShow ? ( + <> + {/* Past / Upcoming / My Events choice */} + {params.type === ListType.Events && ( + + )} + + {/* Quick search for upcoming events (Today / This week / This month) */} + {params.type === ListType.Events && + eventsShowUpcomingQuickSearch && + eventsQuickSearchUpcomingChoice && ( + + + + )} + + {/* If the user has searched, show some text indicating what they searched for + and give them the option to clear the search */} + {params?.search && ( - + {params?.search?.description && ( + + Results for {params.search.description} + + )} + + Clear search + )} - {/* If the user has searched, show some text indicating what they searched for - and give them the option to clear the search */} - {params?.search && ( - - {params?.search?.description && ( - - Results for {params.search.description} - - )} - - Clear search - - - )} - - {/* Projects filter & sort options */} - {params.type === ListType.Projects && - Boolean(params?.search) && - Boolean(listItemsToShow.length) && } - - - - ) : ( - <> - - - - - )} - - + {/* Projects filter & sort options */} + {params.type === ListType.Projects && + Boolean(params?.search) && + Boolean(listItemsToShow.length) && } + + + + ) : ( + <> + + + + + )} + + + ) } From 5e8eb3c1c52d6eb01ed9a305217693c56c6c57d6 Mon Sep 17 00:00:00 2001 From: mirkiy Date: Thu, 12 Sep 2024 15:44:29 +0100 Subject: [PATCH 06/16] scrolling fixed --- src/NativeBase/Containers/ListContainer.tsx | 22 +++++++-------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/NativeBase/Containers/ListContainer.tsx b/src/NativeBase/Containers/ListContainer.tsx index 8ad63058..1159d4b2 100644 --- a/src/NativeBase/Containers/ListContainer.tsx +++ b/src/NativeBase/Containers/ListContainer.tsx @@ -305,7 +305,7 @@ const ListContainer = (props: { showSearchButton onSearchButtonPress={() => navigate(screens.search[params.type], '')} /> */} - + Roles @@ -339,21 +339,13 @@ const ListContainer = (props: { - - - - + + + + + - + {params?.type && listItemsToShow ? ( <> {/* Past / Upcoming / My Events choice */} From 974c6032ac5898fdb054782a836e521e57dd6505 Mon Sep 17 00:00:00 2001 From: mirkiy Date: Wed, 18 Sep 2024 18:41:19 +0100 Subject: [PATCH 07/16] search bar, filters, tagbuttons in progress --- src/NativeBase/Components/TagButtons.tsx | 28 ++--- src/NativeBase/Containers/ListContainer.tsx | 29 +++-- .../Containers/MyExperienceContainer.tsx | 57 +++++++-- .../Containers/ProjectSearchContainer.tsx | 108 ++++++++++-------- 4 files changed, 140 insertions(+), 82 deletions(-) diff --git a/src/NativeBase/Components/TagButtons.tsx b/src/NativeBase/Components/TagButtons.tsx index c30637df..c07b16ae 100644 --- a/src/NativeBase/Components/TagButtons.tsx +++ b/src/NativeBase/Components/TagButtons.tsx @@ -3,8 +3,8 @@ import { HStack, Icon, IconButton, Pressable, Text } from 'native-base' import MaterialIcons from 'react-native-vector-icons/MaterialIcons' interface TagButtonsProps { - iconState: Record - handleTagPress: (tag: string) => void + iconState: Record<'Roles' | 'Tech' | 'Causes', boolean> // Updated to specific keys + handleTagPress: (tag: 'Roles' | 'Tech' | 'Causes') => void // Updated to specific union type } const TagButtons: React.FC = ({ @@ -23,11 +23,11 @@ const TagButtons: React.FC = ({ flexDirection="row" alignItems="center" justifyContent="center" - backgroundColor="#F6E2EE" - borderColor="#D1338A" + backgroundColor={iconState.Roles ? '#F6E2EE' : 'gray.100'} + borderColor={iconState.Roles ? '#D1338A' : 'transparent'} borderWidth={1} > - Roles + Roles = ({ iconState.Roles ? 'keyboard-arrow-up' : 'keyboard-arrow-down' } size={5} - color="#D1338A" + color={iconState.Roles ? '#D1338A' : 'gray.500'} /> } variant="outline" @@ -54,11 +54,11 @@ const TagButtons: React.FC = ({ flexDirection="row" alignItems="center" justifyContent="center" - backgroundColor="#F6E2EE" - borderColor="#D1338A" + backgroundColor={iconState.Tech ? '#F6E2EE' : 'gray.100'} + borderColor={iconState.Tech ? '#D1338A' : 'transparent'} borderWidth={1} > - Tech + Tech = ({ iconState.Tech ? 'keyboard-arrow-up' : 'keyboard-arrow-down' } size={5} - color="#D1338A" + color={iconState.Tech ? '#D1338A' : 'gray.500'} /> } variant="outline" @@ -85,11 +85,11 @@ const TagButtons: React.FC = ({ flexDirection="row" alignItems="center" justifyContent="center" - backgroundColor="#F6E2EE" - borderColor="#D1338A" + backgroundColor={iconState.Causes ? '#F6E2EE' : 'gray.100'} + borderColor={iconState.Causes ? '#D1338A' : 'transparent'} borderWidth={1} > - Causes + Causes = ({ iconState.Causes ? 'keyboard-arrow-up' : 'keyboard-arrow-down' } size={5} - color="#D1338A" + color={iconState.Causes ? '#D1338A' : 'gray.500'} /> } variant="outline" diff --git a/src/NativeBase/Containers/ListContainer.tsx b/src/NativeBase/Containers/ListContainer.tsx index 1159d4b2..194471b8 100644 --- a/src/NativeBase/Containers/ListContainer.tsx +++ b/src/NativeBase/Containers/ListContainer.tsx @@ -58,6 +58,8 @@ import SkeletonLoading from '../Components/SkeletonLoading' import FreeSearchBar from '../Components/FreeSearchBar' import MaterialIcons from 'react-native-vector-icons/MaterialIcons' import TagButtons from '../Components/TagButtons' +import ProjectSearchContainer from './ProjectSearchContainer' +import MyExperienceContainer from './MyExperienceContainer' const ClearSearchLabel = styled.Text` @@ -161,6 +163,7 @@ const ListContainer = (props: { const allProjects = useSelector( (state: { projects: ProjectsState }) => state.projects?.projects, ) + const [searchText, setSearchText] = useState('') // State for toggling icons const [iconState, setIconState] = useState>({ @@ -262,7 +265,9 @@ const ListContainer = (props: { } as ListRouteParams) } } - + const handleSearchSubmit = (text: string) => { + setSearchText(text) + } /* * * Events-specific logic @@ -305,14 +310,20 @@ const ListContainer = (props: { showSearchButton onSearchButtonPress={() => navigate(screens.search[params.type], '')} /> */} + {/* TODO: reinstate when functionality is ready */} + {/* */} + Roles - - {/* TODO: reinstate when functionality is ready */} - {/* */} + + + {/* - + - + */} - + {/* */} + + + + diff --git a/src/NativeBase/Containers/MyExperienceContainer.tsx b/src/NativeBase/Containers/MyExperienceContainer.tsx index c9632774..2b751605 100644 --- a/src/NativeBase/Containers/MyExperienceContainer.tsx +++ b/src/NativeBase/Containers/MyExperienceContainer.tsx @@ -10,6 +10,8 @@ import { View, Text, Button, + IconButton, + Icon, } from 'native-base' import ProfileButtons from '../Components/ProfileButtons' import ProgressBar from '../Components/ProgressBar' @@ -22,6 +24,7 @@ import { getProgressBarColors, nextScreen, } from '../../Utils/ProgressBarColours' +import MaterialIcons from 'react-native-vector-icons/MaterialIcons' const MyExperienceContainer = () => { const [skillsValue, setSkillsValue] = React.useState([]) // skills selected by the user @@ -47,23 +50,53 @@ const MyExperienceContainer = () => { return ( <> - + {/* My Experience - + */} {/* */} - - null} - handleChangeText={(text: string) => setSearchTxt(text)} - /> - + {/* */} + + + + null} + handleChangeText={(text: string) => setSearchTxt(text)} + /> + + + + + } + /> + + + + {/* */} {filteredSkills.map((roleGroup: RoleGroup, index: number) => ( @@ -108,7 +141,7 @@ const MyExperienceContainer = () => { ))} - + {/* { Skip )} - + */} ) diff --git a/src/NativeBase/Containers/ProjectSearchContainer.tsx b/src/NativeBase/Containers/ProjectSearchContainer.tsx index 6bc1b6fa..8ed20e2f 100644 --- a/src/NativeBase/Containers/ProjectSearchContainer.tsx +++ b/src/NativeBase/Containers/ProjectSearchContainer.tsx @@ -1,66 +1,46 @@ -/** - * @file Projects search screen container. - */ - import React, { useState } from 'react' -import Fuse from 'fuse.js' // fuzzy text search - see docs at https://fusejs.io import { ScrollView, VStack } from 'native-base' import { useSelector } from 'react-redux' -import { ListRouteParams, ListSearch, ListType } from './ListContainer' import ChoicesList, { ChoicesListChoice, ChoicesListColour, ChoicesListFontStyle, } from '../Components/ChoicesList' import FreeSearchBar from '../Components/FreeSearchBar' -import SegmentedPicker, { - SegmentedPickerOption, -} from '../Components/SegmentedPicker' +import TagButtons from '../Components/TagButtons' // Import your TagButtons component import { navigate, RootStackParamList } from '@/Navigators/utils' import { - Projects, ProjectsSearchField, ProjectSector, ProjectTechnology, + Projects, } from '@/Services/modules/projects' +import { ProjectsState } from '@/Store/Projects' +import { searchByArray, fuzzySearchByArray } from '@/Utils/Search' import { - roleGroups, RoleGroupName, + roleGroups, } from '@/Services/modules/projects/roleGroups' -import { ProjectsState } from '@/Store/Projects' -import { searchByArray, fuzzySearchByArray } from '@/Utils/Search' +import Fuse from 'fuse.js' +import { ListSearch, ListType, ListRouteParams } from './ListContainer' -enum Tab { - Roles = 'Roles', - Tech = 'Tech', - Causes = 'Causes', -} +// Use string literals instead of enum for Tab +type Tab = 'Roles' | 'Tech' | 'Causes' export interface ProjectSearch extends ListSearch { results: Projects // the projects results for this search } -/** - * Container for the user to search projects e.g. by free text, category, skills - * - * @returns {React.ReactElement} Component - */ const ProjectSearchContainer = () => { + // Fetch all projects from the store const allProjects = useSelector( (state: { projects: ProjectsState }) => state.projects.projects, ) - const [selectedTab, setSelectedTab] = useState(Tab.Roles) - const tabs = Object.values(Tab).map( - tab => - ({ - text: tab, - onPress: () => setSelectedTab(tab), - isSelected: tab === selectedTab, - } as SegmentedPickerOption), - ) - // Define which quick search options to use + // State to track the currently active tag + const [activeTag, setActiveTag] = useState(null) + // Define which quick search options to use const quickSearchRoleGroupNames: RoleGroupName[] = [ RoleGroupName.WebDeveloper, RoleGroupName.TechSupport, @@ -69,16 +49,19 @@ const ProjectSearchContainer = () => { RoleGroupName.BAPM, RoleGroupName.ScrumMaster, ] - const quickSearchRoleChoices = quickSearchRoleGroupNames.map( - roleGroupName => - ({ - text: roleGroupName, - onPress: () => - handleQuickSearchSubmit(ProjectsSearchField.Role, roleGroupName), - } as ChoicesListChoice), - ) + const quickSearchRoleChoices: ChoicesListChoice[] = + quickSearchRoleGroupNames.map( + roleGroupName => + ({ + text: roleGroupName, + onPress: () => + handleQuickSearchSubmit(ProjectsSearchField.Role, roleGroupName), + } as ChoicesListChoice), + ) - const quickSearchTechnologies = Object.values(ProjectTechnology).map( + const quickSearchTechnologies: ChoicesListChoice[] = Object.values( + ProjectTechnology, + ).map( technology => ({ text: technology, @@ -87,7 +70,9 @@ const ProjectSearchContainer = () => { } as ChoicesListChoice), ) - const quickSearchCauses = Object.values(ProjectSector).map( + const quickSearchCauses: ChoicesListChoice[] = Object.values( + ProjectSector, + ).map( cause => ({ text: cause, @@ -210,14 +195,37 @@ const ProjectSearchContainer = () => { ) } + /** + * Handle tag press logic + * If the tag is already open, close it by setting activeTag to null. + * If a different tag is clicked, close the previous one and open the new one. + */ + const handleTagPress = (tag: Tab) => { + if (activeTag === tag) { + setActiveTag(null) // Close the currently active tag + } else { + setActiveTag(tag) // Open the selected tag and close others + } + } + return ( - - - + {/* Free Search Bar for entering free text queries */} + {/* */} + + {/* Tag Buttons for Roles, Tech, and Causes */} + - {selectedTab === Tab.Roles && ( + {/* Show the list of role choices if Roles tab is active */} + {activeTag === 'Roles' && ( { /> )} - {selectedTab === Tab.Tech && ( + {/* Show the list of technology choices if Tech tab is active */} + {activeTag === 'Tech' && ( { /> )} - {selectedTab === Tab.Causes && ( + {/* Show the list of causes if Causes tab is active */} + {activeTag === 'Causes' && ( Date: Wed, 23 Oct 2024 13:49:41 +0100 Subject: [PATCH 08/16] TagButtons and colours updated --- src/NativeBase/Components/TagButtons.tsx | 133 +++++------------- src/NativeBase/Containers/ListContainer.tsx | 6 +- .../Containers/ProjectSearchContainer.tsx | 25 ++-- 3 files changed, 49 insertions(+), 115 deletions(-) diff --git a/src/NativeBase/Components/TagButtons.tsx b/src/NativeBase/Components/TagButtons.tsx index c07b16ae..6f130795 100644 --- a/src/NativeBase/Components/TagButtons.tsx +++ b/src/NativeBase/Components/TagButtons.tsx @@ -3,109 +3,52 @@ import { HStack, Icon, IconButton, Pressable, Text } from 'native-base' import MaterialIcons from 'react-native-vector-icons/MaterialIcons' interface TagButtonsProps { - iconState: Record<'Roles' | 'Tech' | 'Causes', boolean> // Updated to specific keys - handleTagPress: (tag: 'Roles' | 'Tech' | 'Causes') => void // Updated to specific union type + tags: string[] // An array of tag names, e.g., ['Roles', 'Tech', 'Causes'] + iconState: Record // A dynamic record that maps tags to boolean states + handleTagPress: (tag: string) => void // A function that takes any tag } const TagButtons: React.FC = ({ + tags, iconState, handleTagPress, }) => { return ( - handleTagPress('Roles')} - borderRadius={40} - pl={4} - pr={2} - py={2} - display="flex" - flexDirection="row" - alignItems="center" - justifyContent="center" - backgroundColor={iconState.Roles ? '#F6E2EE' : 'gray.100'} - borderColor={iconState.Roles ? '#D1338A' : 'transparent'} - borderWidth={1} - > - Roles - - } - variant="outline" - _icon={{ color: 'gray.500' }} - onPress={() => handleTagPress('Roles')} - /> - - handleTagPress('Tech')} - borderRadius={40} - pl={4} - pr={2} - py={2} - display="flex" - flexDirection="row" - alignItems="center" - justifyContent="center" - backgroundColor={iconState.Tech ? '#F6E2EE' : 'gray.100'} - borderColor={iconState.Tech ? '#D1338A' : 'transparent'} - borderWidth={1} - > - Tech - - } - variant="outline" - _icon={{ color: 'gray.500' }} - onPress={() => handleTagPress('Tech')} - /> - - handleTagPress('Causes')} - borderRadius={40} - pl={4} - pr={2} - py={2} - display="flex" - flexDirection="row" - alignItems="center" - justifyContent="center" - backgroundColor={iconState.Causes ? '#F6E2EE' : 'gray.100'} - borderColor={iconState.Causes ? '#D1338A' : 'transparent'} - borderWidth={1} - > - Causes - - } - variant="outline" - _icon={{ color: 'gray.500' }} - onPress={() => handleTagPress('Causes')} - /> - + {tags.map(tag => ( + handleTagPress(tag)} + borderRadius={40} + pl={4} + pr={2} + py={2} + display="flex" + flexDirection="row" + alignItems="center" + justifyContent="center" + backgroundColor={iconState[tag] ? 'primary.20' : 'gray.100'} + borderColor={iconState[tag] ? 'primary.100' : 'transparent'} + borderWidth={1} + > + {tag} + + } + variant="outline" + _icon={{ color: 'gray.500' }} + onPress={() => handleTagPress(tag)} + /> + + ))} ) } diff --git a/src/NativeBase/Containers/ListContainer.tsx b/src/NativeBase/Containers/ListContainer.tsx index 194471b8..b50536b8 100644 --- a/src/NativeBase/Containers/ListContainer.tsx +++ b/src/NativeBase/Containers/ListContainer.tsx @@ -316,9 +316,9 @@ const ListContainer = (props: { Roles - + {/* */} - {/* + - */} + diff --git a/src/NativeBase/Containers/ProjectSearchContainer.tsx b/src/NativeBase/Containers/ProjectSearchContainer.tsx index 8ed20e2f..f8d29611 100644 --- a/src/NativeBase/Containers/ProjectSearchContainer.tsx +++ b/src/NativeBase/Containers/ProjectSearchContainer.tsx @@ -7,7 +7,7 @@ import ChoicesList, { ChoicesListFontStyle, } from '../Components/ChoicesList' import FreeSearchBar from '../Components/FreeSearchBar' -import TagButtons from '../Components/TagButtons' // Import your TagButtons component +import TagButtons from '../Components/TagButtons' import { navigate, RootStackParamList } from '@/Navigators/utils' import { ProjectsSearchField, @@ -24,9 +24,6 @@ import { import Fuse from 'fuse.js' import { ListSearch, ListType, ListRouteParams } from './ListContainer' -// Use string literals instead of enum for Tab -type Tab = 'Roles' | 'Tech' | 'Causes' - export interface ProjectSearch extends ListSearch { results: Projects // the projects results for this search } @@ -37,8 +34,8 @@ const ProjectSearchContainer = () => { (state: { projects: ProjectsState }) => state.projects.projects, ) - // State to track the currently active tag - const [activeTag, setActiveTag] = useState(null) + // State to track the currently active tag (using simple strings) + const [activeTag, setActiveTag] = useState(null) // Define which quick search options to use const quickSearchRoleGroupNames: RoleGroupName[] = [ @@ -170,8 +167,6 @@ const ProjectSearchContainer = () => { allProjects, [ { name: 'client', weight: 1 }, - // We reduce the 'weight' (aka importance) put on the description field as it's more likely to return - // false positive matches because there's lots of general text in that field { name: 'description', weight: 0.5 }, { name: 'name', weight: 1 }, { name: 'role', weight: 1 }, @@ -200,12 +195,8 @@ const ProjectSearchContainer = () => { * If the tag is already open, close it by setting activeTag to null. * If a different tag is clicked, close the previous one and open the new one. */ - const handleTagPress = (tag: Tab) => { - if (activeTag === tag) { - setActiveTag(null) // Close the currently active tag - } else { - setActiveTag(tag) // Open the selected tag and close others - } + const handleTagPress = (tag: string) => { + setActiveTag(activeTag === tag ? null : tag) } return ( @@ -215,14 +206,14 @@ const ProjectSearchContainer = () => { {/* Tag Buttons for Roles, Tech, and Causes */} - {/* Show the list of role choices if Roles tab is active */} {activeTag === 'Roles' && ( @@ -242,7 +233,7 @@ const ProjectSearchContainer = () => { /> )} - {/* Show the list of causes if Causes tab is active */} + {/* Show the list of causes if Causes tag is active */} {activeTag === 'Causes' && ( Date: Thu, 21 Nov 2024 18:12:58 +0000 Subject: [PATCH 09/16] roles filter in list container in progress --- src/NativeBase/Containers/ListContainer.tsx | 50 ++++++++++++++----- .../Containers/ProjectSearchContainer.tsx | 4 +- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/NativeBase/Containers/ListContainer.tsx b/src/NativeBase/Containers/ListContainer.tsx index b50536b8..0b99f790 100644 --- a/src/NativeBase/Containers/ListContainer.tsx +++ b/src/NativeBase/Containers/ListContainer.tsx @@ -60,6 +60,7 @@ import MaterialIcons from 'react-native-vector-icons/MaterialIcons' import TagButtons from '../Components/TagButtons' import ProjectSearchContainer from './ProjectSearchContainer' import MyExperienceContainer from './MyExperienceContainer' +import { RoleGroup, roleGroups } from '@/Services/modules/projects/roleGroups' const ClearSearchLabel = styled.Text` @@ -120,6 +121,7 @@ const ListContainer = (props: { // Shared const dispatch = useDispatch() const [listItemsToShow, setListItemsToShow] = useState() + const [roleSearchText, setRoleSearchText] = useState('') const params = props.route.params const screens = { list: { @@ -137,6 +139,15 @@ const ListContainer = (props: { onPress: option === 'all' ? () => undefined : underDevelopmentAlert, } as SegmentedPickerOption), ) + // Filter roles based on the search text + const filteredRoles = roleGroups.filter((roleGroup: RoleGroup) => + roleGroup.groupName.toLowerCase().includes(roleSearchText.toLowerCase()), + ) + + // Handle role search submit + const handleRoleSearchChange = (text: string) => { + setRoleSearchText(text) + } // Events-specific const [fetchAllUpcomingEvents, { data: allUpcomingEventsResult }] = @@ -265,9 +276,7 @@ const ListContainer = (props: { } as ListRouteParams) } } - const handleSearchSubmit = (text: string) => { - setSearchText(text) - } + /* * * Events-specific logic @@ -302,7 +311,7 @@ const ListContainer = (props: { } }, [params?.options?.events, params?.search, params?.type]) - const onSubmitEditing = (text: string) => text + // const onSubmitEditing = (text: string) => text return ( <> @@ -315,13 +324,14 @@ const ListContainer = (props: { - Roles - {/* */} - + + Roles + @@ -348,17 +358,31 @@ const ListContainer = (props: { /> + + {/* Display filtered roles based on the search */} + + {roleSearchText && filteredRoles.length > 0 && ( + <> + + Roles matching "{roleSearchText}" + + {filteredRoles.map((roleGroup, index) => ( + + {roleGroup.groupName} + + ))} + + )} + - + - {/* */} - - + {params?.type && listItemsToShow ? ( @@ -416,6 +440,8 @@ const ListContainer = (props: { + + )} diff --git a/src/NativeBase/Containers/ProjectSearchContainer.tsx b/src/NativeBase/Containers/ProjectSearchContainer.tsx index f8d29611..94fe8656 100644 --- a/src/NativeBase/Containers/ProjectSearchContainer.tsx +++ b/src/NativeBase/Containers/ProjectSearchContainer.tsx @@ -200,7 +200,7 @@ const ProjectSearchContainer = () => { } return ( - + {/* Free Search Bar for entering free text queries */} {/* */} @@ -242,7 +242,7 @@ const ProjectSearchContainer = () => { /> )} - + ) } From 73d8b22db1aec92310f26650b3bc6fdd59c484f6 Mon Sep 17 00:00:00 2001 From: mirkiy Date: Thu, 21 Nov 2024 18:51:41 +0000 Subject: [PATCH 10/16] clear of the search results --- src/NativeBase/Components/FreeSearchBar.tsx | 7 +++++- src/NativeBase/Containers/ListContainer.tsx | 25 +++++++++++++++------ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/NativeBase/Components/FreeSearchBar.tsx b/src/NativeBase/Components/FreeSearchBar.tsx index 7b64bcc0..f9fad335 100644 --- a/src/NativeBase/Components/FreeSearchBar.tsx +++ b/src/NativeBase/Components/FreeSearchBar.tsx @@ -10,6 +10,7 @@ import SearchIconHighlighted from './SearchIconHighlighted' export interface FreeSearchBarProps { handleChangeText?: (updatedText: string) => void handleSubmit: (submitText: string) => void + handleClearSearch?: () => void marginBottom?: string marginTop?: string } @@ -27,6 +28,7 @@ export interface FreeSearchBarProps { const FreeSearchBar: FC = ({ handleChangeText, handleSubmit, + handleClearSearch, marginBottom, marginTop, }) => { @@ -40,7 +42,10 @@ const FreeSearchBar: FC = ({ const onSubmitEditing = () => handleSubmit(text) - const clearText = () => setText('') + const clearText = () => { + setText('') + if (handleClearSearch) handleClearSearch() // Call the clear function passed as prop + } return ( diff --git a/src/NativeBase/Containers/ListContainer.tsx b/src/NativeBase/Containers/ListContainer.tsx index 0b99f790..31c43d4e 100644 --- a/src/NativeBase/Containers/ListContainer.tsx +++ b/src/NativeBase/Containers/ListContainer.tsx @@ -122,6 +122,7 @@ const ListContainer = (props: { const dispatch = useDispatch() const [listItemsToShow, setListItemsToShow] = useState() const [roleSearchText, setRoleSearchText] = useState('') + const [filteredRoles, setFilteredRoles] = useState(roleGroups) const params = props.route.params const screens = { list: { @@ -139,14 +140,20 @@ const ListContainer = (props: { onPress: option === 'all' ? () => undefined : underDevelopmentAlert, } as SegmentedPickerOption), ) - // Filter roles based on the search text - const filteredRoles = roleGroups.filter((roleGroup: RoleGroup) => - roleGroup.groupName.toLowerCase().includes(roleSearchText.toLowerCase()), - ) - - // Handle role search submit + // Handle role search text change const handleRoleSearchChange = (text: string) => { setRoleSearchText(text) + // Filter roles based on search text + const filtered = roleGroups.filter(roleGroup => + roleGroup.groupName.toLowerCase().includes(text.toLowerCase()), + ) + setFilteredRoles(filtered) + } + + // Clear role search text and reset filtered roles + const handleClearSearch = () => { + setRoleSearchText('') // Clear search text + setFilteredRoles(roleGroups) // Reset the filtered roles to the full list } // Events-specific @@ -174,7 +181,7 @@ const ListContainer = (props: { const allProjects = useSelector( (state: { projects: ProjectsState }) => state.projects?.projects, ) - const [searchText, setSearchText] = useState('') + // const [searchText, setSearchText] = useState('') // State for toggling icons const [iconState, setIconState] = useState>({ @@ -332,6 +339,7 @@ const ListContainer = (props: { @@ -373,6 +381,9 @@ const ListContainer = (props: { ))} )} + {roleSearchText && filteredRoles.length === 0 && ( + No roles found + )} From 9555d896f5c73770de4afd3ddec4cfbabaa25e82 Mon Sep 17 00:00:00 2001 From: mirkiy Date: Thu, 21 Nov 2024 18:54:04 +0000 Subject: [PATCH 11/16] styling changes --- src/NativeBase/Containers/ListContainer.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/NativeBase/Containers/ListContainer.tsx b/src/NativeBase/Containers/ListContainer.tsx index 31c43d4e..fd99fd62 100644 --- a/src/NativeBase/Containers/ListContainer.tsx +++ b/src/NativeBase/Containers/ListContainer.tsx @@ -390,8 +390,6 @@ const ListContainer = (props: { - - From 23e74066d907d67735cf381ba7bcc44f87991417 Mon Sep 17 00:00:00 2001 From: mirkiy Date: Tue, 3 Dec 2024 18:54:25 +0000 Subject: [PATCH 12/16] unused imports deleted --- src/NativeBase/Components/SearchIconHighlighted.tsx | 9 +-------- src/NativeBase/Containers/ListContainer.tsx | 8 -------- src/Navigators/Main.tsx | 3 +-- 3 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/NativeBase/Components/SearchIconHighlighted.tsx b/src/NativeBase/Components/SearchIconHighlighted.tsx index 5421a650..4b32116f 100644 --- a/src/NativeBase/Components/SearchIconHighlighted.tsx +++ b/src/NativeBase/Components/SearchIconHighlighted.tsx @@ -12,14 +12,7 @@ import MaterialIcons from 'react-native-vector-icons/MaterialIcons' * @returns {React.ReactElement} Component */ const SearchIconHighlighted = () => ( - + ) export default SearchIconHighlighted diff --git a/src/NativeBase/Containers/ListContainer.tsx b/src/NativeBase/Containers/ListContainer.tsx index fd99fd62..f09df0ec 100644 --- a/src/NativeBase/Containers/ListContainer.tsx +++ b/src/NativeBase/Containers/ListContainer.tsx @@ -13,10 +13,8 @@ import { Icon, IconButton, ScrollView, - Tag, VStack, Text, - Pressable, View, } from 'native-base' import React, { useEffect, useState } from 'react' @@ -34,13 +32,9 @@ import List, { ListOptions, } from '@/NativeBase/Components/List' import ProjectFilterSort from '@/Components/Project/ProjectFilterSort' -import TopOfApp from '@/NativeBase/Components/TopOfApp' import { navigate, RootStackParamList } from '@/Navigators/utils' -import { heightOfTopOfAppPlusBottomNav } from '@/Utils/Layout' import { capitaliseFirstLetter } from '@/Utils/Text' - import { SegmentedPickerOption } from '../Components/SegmentedPicker' - import { Events, EventsRange, @@ -57,9 +51,7 @@ import underDevelopmentAlert from '@/Utils/UnderDevelopmentAlert' import SkeletonLoading from '../Components/SkeletonLoading' import FreeSearchBar from '../Components/FreeSearchBar' import MaterialIcons from 'react-native-vector-icons/MaterialIcons' -import TagButtons from '../Components/TagButtons' import ProjectSearchContainer from './ProjectSearchContainer' -import MyExperienceContainer from './MyExperienceContainer' import { RoleGroup, roleGroups } from '@/Services/modules/projects/roleGroups' const ClearSearchLabel = styled.Text` diff --git a/src/Navigators/Main.tsx b/src/Navigators/Main.tsx index 391a44a7..60e42b8c 100644 --- a/src/Navigators/Main.tsx +++ b/src/Navigators/Main.tsx @@ -7,7 +7,7 @@ import { BottomTabNavigationOptions, } from '@react-navigation/bottom-tabs' import { useRoute } from '@react-navigation/native' -import { ListContainer, ProjectSearchContainer } from '@/NativeBase/Containers' +import { ListContainer } from '@/NativeBase/Containers' import { ListType } from '@/NativeBase/Containers/ListContainer' import { SettingsContainer } from '@/NativeBase/Containers' import SelectionIcons from '@/NativeBase/Assets/Icons/Icomoon/SelectionIcons' @@ -17,7 +17,6 @@ import { Platform } from 'react-native' import MaterialIcons from 'react-native-vector-icons/MaterialIcons' import MyProfile from '@/NativeBase/Containers/ProfileContainer' import { useFeatureFlags } from '@/Services/featureFlags' -import MyExperienceContainer from '@/NativeBase/Containers/MyExperienceContainer' const Tab = createBottomTabNavigator() From 31cac5a0ad79a0388c3a0ddb1d2b07b305ccfb31 Mon Sep 17 00:00:00 2001 From: Daniel Kaschl <25082557+dkaschl@users.noreply.github.com> Date: Tue, 3 Dec 2024 21:36:34 +0000 Subject: [PATCH 13/16] WIP next steps --- src/NativeBase/Containers/ListContainer.tsx | 67 ++++++++++++++------- 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/src/NativeBase/Containers/ListContainer.tsx b/src/NativeBase/Containers/ListContainer.tsx index f09df0ec..ad8879c4 100644 --- a/src/NativeBase/Containers/ListContainer.tsx +++ b/src/NativeBase/Containers/ListContainer.tsx @@ -7,34 +7,19 @@ /* eslint-disable @typescript-eslint/no-shadow */ -import { - Heading, - HStack, - Icon, - IconButton, - ScrollView, - VStack, - Text, - View, -} from 'native-base' -import React, { useEffect, useState } from 'react' -import { Dimensions } from 'react-native' -import { useDispatch, useSelector } from 'react-redux' -import styled from 'styled-components/native' -import { EventSearch } from '@/Containers/EventSearchContainer' -import { ProjectSearch } from './ProjectSearchContainer' import EventOptions from '@/Components/Event/EventOptions' import EventSearchUpcomingQuickSearch, { EventQuickSearchUpcomingChoice, } from '@/Components/Event/EventSearchQuickSearchUpcoming' +import ProjectFilterSort from '@/Components/Project/ProjectFilterSort' +import { EventSearch } from '@/Containers/EventSearchContainer' +import FreeSearchBar from '@/NativeBase/Components/FreeSearchBar' import List, { ListDisplayMode, ListOptions, } from '@/NativeBase/Components/List' -import ProjectFilterSort from '@/Components/Project/ProjectFilterSort' +import SkeletonLoading from '@/NativeBase/Components/SkeletonLoading' import { navigate, RootStackParamList } from '@/Navigators/utils' -import { capitaliseFirstLetter } from '@/Utils/Text' -import { SegmentedPickerOption } from '../Components/SegmentedPicker' import { Events, EventsRange, @@ -45,14 +30,28 @@ import { Projects, useLazyFetchAllProjectsQuery, } from '@/Services/modules/projects' +import { RoleGroup, roleGroups } from '@/Services/modules/projects/roleGroups' import { EventsState, setEvents } from '@/Store/Events' import { ProjectsState, setProjects } from '@/Store/Projects' +import { capitaliseFirstLetter } from '@/Utils/Text' import underDevelopmentAlert from '@/Utils/UnderDevelopmentAlert' -import SkeletonLoading from '../Components/SkeletonLoading' -import FreeSearchBar from '../Components/FreeSearchBar' +import { + Heading, + HStack, + Icon, + IconButton, + ScrollView, + Text, + View, + VStack, +} from 'native-base' +import React, { useEffect, useState } from 'react' +import { Dimensions } from 'react-native' import MaterialIcons from 'react-native-vector-icons/MaterialIcons' -import ProjectSearchContainer from './ProjectSearchContainer' -import { RoleGroup, roleGroups } from '@/Services/modules/projects/roleGroups' +import { useDispatch, useSelector } from 'react-redux' +import styled from 'styled-components/native' +import { SegmentedPickerOption } from '../Components/SegmentedPicker' +import ProjectSearchContainer, { ProjectSearch } from './ProjectSearchContainer' const ClearSearchLabel = styled.Text` @@ -310,6 +309,27 @@ const ListContainer = (props: { } }, [params?.options?.events, params?.search, params?.type]) + function updateListForTestWithRoleWebDeveloper(): void { + //TODO + // 1. when we click on the button, we want the list of projects to be filtered for roles category web-developer and displayed on the same screen. + + // 2. we want to use existing filtering logic to manipulate the list of projects and show it in the list + + // 3. we are really cool and start using maybe redux selectors to apply the filtering (maybe?) + + // 4. step 3 is OPTIONAL. once we have managed to get to step 2, we will now focus on doing roles filtering using our tagbuttons. + + // 5. we will extend this logic also to the tech and fields area + + // 6. we will now focus on the fullsearch bar - maybe break down in additional sub tasks to make progress easier... + + // 7. we clean up unused components + + // 8. we start refactoring and making the code/architecture more clean + + throw new Error('Function not implemented.') + } + // const onSubmitEditing = (text: string) => text return ( @@ -347,6 +367,7 @@ const ListContainer = (props: { alignItems="center" > Date: Wed, 4 Dec 2024 19:58:58 +0000 Subject: [PATCH 14/16] starting to work on little incrementations --- src/NativeBase/Containers/ListContainer.tsx | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/NativeBase/Containers/ListContainer.tsx b/src/NativeBase/Containers/ListContainer.tsx index ad8879c4..6633c824 100644 --- a/src/NativeBase/Containers/ListContainer.tsx +++ b/src/NativeBase/Containers/ListContainer.tsx @@ -233,6 +233,7 @@ const ListContainer = (props: { // What to do when the user navigates to this container // e.g. set which data to show -- either search results or everything useEffect(() => { + console.log('params search:', params.search) if (params?.search) { setListItemsToShow(params.search.results) } @@ -312,22 +313,22 @@ const ListContainer = (props: { function updateListForTestWithRoleWebDeveloper(): void { //TODO // 1. when we click on the button, we want the list of projects to be filtered for roles category web-developer and displayed on the same screen. - + /* + console.log(listItemsToShow!.map((item: Project) => item.role).join(', ')) + const filteredList: Project[] = listItemsToShow!.filter((item: Project) => item.role === 'User Researcher') + setListItemsToShow(filteredList) + */ + /* THIS DOES NOT WORK +const filteredList: Project[] = listItemsToShow!.filter((item: Project) => item.role === 'User Researcher') +params.search = { results: filteredList, description: 'fake filtering' } as ProjectSearch +*/ // 2. we want to use existing filtering logic to manipulate the list of projects and show it in the list - // 3. we are really cool and start using maybe redux selectors to apply the filtering (maybe?) - // 4. step 3 is OPTIONAL. once we have managed to get to step 2, we will now focus on doing roles filtering using our tagbuttons. - // 5. we will extend this logic also to the tech and fields area - // 6. we will now focus on the fullsearch bar - maybe break down in additional sub tasks to make progress easier... - // 7. we clean up unused components - // 8. we start refactoring and making the code/architecture more clean - - throw new Error('Function not implemented.') } // const onSubmitEditing = (text: string) => text From 3a55cb3a8907045f897a3ed5a0790be51ea0bc50 Mon Sep 17 00:00:00 2001 From: Daniel Kaschl <25082557+dkaschl@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:17:32 +0000 Subject: [PATCH 15/16] removing old pages, moving logic into listcontainer --- APP_DEVELOPMENT.md | 22 +- src/Components/Project/ProjectFilterSort.tsx | 34 --- .../ProjectTagButtonsFilter.tsx} | 79 ++---- src/NativeBase/Components/TopOfApp.tsx | 20 +- src/NativeBase/Containers/ListContainer.tsx | 249 +++++++++--------- .../Containers/SearchResultsContainer.tsx | 22 +- .../Containers/VerticalStackContainer.tsx | 107 -------- src/NativeBase/Containers/index.ts | 6 +- src/Navigators/Application.tsx | 47 ++-- src/Navigators/Main.tsx | 26 +- 10 files changed, 213 insertions(+), 399 deletions(-) delete mode 100644 src/Components/Project/ProjectFilterSort.tsx rename src/NativeBase/{Containers/ProjectSearchContainer.tsx => Components/ProjectTagButtonsFilter.tsx} (77%) delete mode 100644 src/NativeBase/Containers/VerticalStackContainer.tsx diff --git a/APP_DEVELOPMENT.md b/APP_DEVELOPMENT.md index f1abbd25..6e9b6023 100644 --- a/APP_DEVELOPMENT.md +++ b/APP_DEVELOPMENT.md @@ -66,11 +66,11 @@ The app designs are produced in Figma. You can inspect different elements within Our app is built using React Native working with the [Expo CLI (command-line tool).](https://docs.expo.dev/more/expo-cli/) and [Expo Go.](https://expo.dev/client) -It's easy to be confused about React Native and Expo, partly because they have changed over time as has the relationship between them (it's easy to find articles which are out of date) and because there are different ways to use them. [This article](https://retool.com/blog/expo-cli-vs-react-native-cli/) has quite a good background. +It's easy to be confused about React Native and Expo, partly because they have changed over time as has the relationship between them (it's easy to find articles which are out of date) and because there are different ways to use them. [This article](https://retool.com/blog/expo-cli-vs-react-native-cli/) has quite a good background. ### Expo trade-offs -We are using the Expo CLI and Expo Go because they make development and deployment of the app a lot easier. The main trade-off is that we cannot use every npm package that works with React Native. +We are using the Expo CLI and Expo Go because they make development and deployment of the app a lot easier. The main trade-off is that we cannot use every npm package that works with React Native. There are many React Native packages we can use, but when it involves interacting with the device hardware (e.g. camera, GPS, etc) or the OS (e.g. the clipboard, file storage or sharing) or occasionally other areas (e.g. SVGs) then we are usually limited to packages that are supported as part of the Expo SDK library (but for the kind of app we're building, this should be ok). @@ -145,7 +145,7 @@ When you're building (or changing) a component or container, or changing a theme NativeBase does some handling of dark mode straight out of the box, so you may not need to change anything. -**If you're switching a container to use NativeBase** check out `SettingsContainer` and `VerticalStackContainer` examples as they're already working reasonably well with dark mode. One of the things you'll need to do in your container is switch from using the old theme and switch from using any `styled` components/views. +**If you're switching a container to use NativeBase** check out `SettingsContainer` example as they're already working reasonably well with dark mode. One of the things you'll need to do in your container is switch from using the old theme and switch from using any `styled` components/views. **If you need to set colours based on dark/light mode** [see the docs here](https://docs.nativebase.io/dark-mode) and wherever possible set `_light` and `_dark` properties in the `StaTheme` file (approach 1. in the docs) rather than setting them on your individual component -- i.e. try to make settings as universal and as easily reusable as possible. @@ -279,27 +279,27 @@ There are broadly two kinds of things that can go wrong on the front-end app: Ordinarily, when you are developing using Expo Go, you should **not** have `BUGSNAG_API_KEY` set to the real API key value, otherwise it will send crash logs to Bugsnag which we usually don't want (ordinarily we only want to use Bugsnag to track errors and crashes on real devices). - > You do need to set a value otherwise the app will not run, so you can use e.g. `BUGSNAG_API_KEY="no_api_key"` +> You do need to set a value otherwise the app will not run, so you can use e.g. `BUGSNAG_API_KEY="no_api_key"` - > During development, in the terminal window where you are running Expo you may see the message `[bugsnag] Bugsnag.start() was called more than once. Ignoring.` You don't need to worry about this, it's just the app reloading and trying to start Bugsnag again. +> During development, in the terminal window where you are running Expo you may see the message `[bugsnag] Bugsnag.start() was called more than once. Ignoring.` You don't need to worry about this, it's just the app reloading and trying to start Bugsnag again. ### Seeing Bugsnag reports Ask one of the team to add you to the **it470-volunteer-app-errors** Slack channel where you can see the latest bugs coming in from the app on real devices, and the API production server. -If you know a bug has been fixed or can safely be ignored, please click the 'Mark as fixed' or 'Ignore' button on the error in the Slack message. +If you know a bug has been fixed or can safely be ignored, please click the 'Mark as fixed' or 'Ignore' button on the error in the Slack message. -To get more details on a bug you'll need to go to [our Bugsnag inbox here](https://app.bugsnag.com/scottish-tech-army/volunteer-app/errors) -- you'll need the Bugsnag login details from another team member. +To get more details on a bug you'll need to go to [our Bugsnag inbox here](https://app.bugsnag.com/scottish-tech-army/volunteer-app/errors) -- you'll need the Bugsnag login details from another team member. - > Note: there are two Projects in Bugsnag -- one for the front-end app ('Volunteer app'), another for the API ('Volunteer app API'). Make sure you're looking at the right one. You can also filter by development/production. +> Note: there are two Projects in Bugsnag -- one for the front-end app ('Volunteer app'), another for the API ('Volunteer app API'). Make sure you're looking at the right one. You can also filter by development/production. - > When you look into an error, click on it in the Inbox in Bugsnag, then on the 'Stacktrace' tab you'll need to find where the error originated. The first entry in the stacktrace is just the `logging` module, you need to find what's below that and click to expand it to see where in the code the error actually occurred. +> When you look into an error, click on it in the Inbox in Bugsnag, then on the 'Stacktrace' tab you'll need to find where the error originated. The first entry in the stacktrace is just the `logging` module, you need to find what's below that and click to expand it to see where in the code the error actually occurred. ### Logging errors to Bugsnag during development -You can log errors to Bugsnag when developing in Expo Go if you really need to. **You shouldn't normally need to do this -- Bugsnag error logging is usually to monitor crashes and errors in the production app. You should only use this in development when normal error detection is insufficient** e.g. because you want to figure out why the app is crashing due to a lack of memory. **Don't** use this in place of normal code tools like `console.error` and `console.log` and other normal testing approaches. +You can log errors to Bugsnag when developing in Expo Go if you really need to. **You shouldn't normally need to do this -- Bugsnag error logging is usually to monitor crashes and errors in the production app. You should only use this in development when normal error detection is insufficient** e.g. because you want to figure out why the app is crashing due to a lack of memory. **Don't** use this in place of normal code tools like `console.error` and `console.log` and other normal testing approaches. -You can force the app to report errors to Bugsnag during development using Expo Go (this also overrides the user permissions setting which normally determines whether or not send error reports). To do this: +You can force the app to report errors to Bugsnag during development using Expo Go (this also overrides the user permissions setting which normally determines whether or not send error reports). To do this: - Create a `.env` file if you don't have one already, and add `BUGSNAG_API_KEY="xxxxxxxxxxxxxxxx"` repacing `xxxxxxxxxxxxxxxx` with the value of our actual Bugsnag API key for the app (ask on the team Slack channel and someone can give you this -- note: the front-end app and the API use different Bugsnag API keys) - In your `.env` file include the line `BUGSNAG_ALWAYS_SEND_BUGS="true"` (this forces the API to send errors to Bugsnag, even though you're in a development environment) diff --git a/src/Components/Project/ProjectFilterSort.tsx b/src/Components/Project/ProjectFilterSort.tsx deleted file mode 100644 index b906a812..00000000 --- a/src/Components/Project/ProjectFilterSort.tsx +++ /dev/null @@ -1,34 +0,0 @@ -/** - * @file Project Filter Sort - */ - -import React from 'react' -import styled from 'styled-components/native' -import underDevelopmentAlert from '../../Utils/UnderDevelopmentAlert' - -const FilterSortView = styled.View` - display: flex; - flex-direction: row; - justify-content: space-around; - margin: 23px 10px; -` -const FilterSortText = styled.Text` - font-size: 18px; - text-decoration: underline; -` -const FilterSortTouch = styled.TouchableOpacity`` - -const ProjectFilterSort = () => { - return ( - - - Filter - - - Sort - - - ) -} - -export default ProjectFilterSort diff --git a/src/NativeBase/Containers/ProjectSearchContainer.tsx b/src/NativeBase/Components/ProjectTagButtonsFilter.tsx similarity index 77% rename from src/NativeBase/Containers/ProjectSearchContainer.tsx rename to src/NativeBase/Components/ProjectTagButtonsFilter.tsx index 94fe8656..337f5fd3 100644 --- a/src/NativeBase/Containers/ProjectSearchContainer.tsx +++ b/src/NativeBase/Components/ProjectTagButtonsFilter.tsx @@ -1,34 +1,37 @@ -import React, { useState } from 'react' -import { ScrollView, VStack } from 'native-base' -import { useSelector } from 'react-redux' -import ChoicesList, { - ChoicesListChoice, - ChoicesListColour, - ChoicesListFontStyle, -} from '../Components/ChoicesList' -import FreeSearchBar from '../Components/FreeSearchBar' -import TagButtons from '../Components/TagButtons' import { navigate, RootStackParamList } from '@/Navigators/utils' import { - ProjectsSearchField, + Projects, ProjectSector, + ProjectsSearchField, ProjectTechnology, - Projects, } from '@/Services/modules/projects' -import { ProjectsState } from '@/Store/Projects' -import { searchByArray, fuzzySearchByArray } from '@/Utils/Search' import { RoleGroupName, roleGroups, } from '@/Services/modules/projects/roleGroups' +import { ProjectsState } from '@/Store/Projects' +import { fuzzySearchByArray, searchByArray } from '@/Utils/Search' import Fuse from 'fuse.js' -import { ListSearch, ListType, ListRouteParams } from './ListContainer' +import { VStack } from 'native-base' +import React, { useState } from 'react' +import { useSelector } from 'react-redux' +import { + ListRouteParams, + ListSearch, + ListType, +} from '../Containers/ListContainer' +import ChoicesList, { + ChoicesListChoice, + ChoicesListColour, + ChoicesListFontStyle, +} from './ChoicesList' +import TagButtons from './TagButtons' export interface ProjectSearch extends ListSearch { results: Projects // the projects results for this search } -const ProjectSearchContainer = () => { +const ProjectsTagButtonsFilter = () => { // Fetch all projects from the store const allProjects = useSelector( (state: { projects: ProjectsState }) => state.projects.projects, @@ -142,44 +145,7 @@ const ProjectSearchContainer = () => { } "${searchQueryChoice}"` navigate( - 'SearchResults' as keyof RootStackParamList, - { - type: ListType.Projects, - search: { - results, - description, - } as ProjectSearch, - } as ListRouteParams, - ) - } - - const handleFreeTextSubmit = (freeTextSearchQuery: string) => { - // Add free text to list of search queries - const searchQueries = [freeTextSearchQuery] - - // If the free text query matches a group of job roles, add these to the list of search queries too - const relatedRoles = getRelatedRoles(freeTextSearchQuery) - if (relatedRoles?.length) { - searchQueries.push(...relatedRoles) - } - - const results = fuzzySearchByArray( - allProjects, - [ - { name: 'client', weight: 1 }, - { name: 'description', weight: 0.5 }, - { name: 'name', weight: 1 }, - { name: 'role', weight: 1 }, - { name: 'skills', weight: 1 }, - { name: 'sector', weight: 1 }, - ], - searchQueries, - ) - - const description = `"${freeTextSearchQuery}"` - - navigate( - 'SearchResults' as keyof RootStackParamList, + 'Projects' as keyof RootStackParamList, { type: ListType.Projects, search: { @@ -201,9 +167,6 @@ const ProjectSearchContainer = () => { return ( - {/* Free Search Bar for entering free text queries */} - {/* */} - {/* Tag Buttons for Roles, Tech, and Causes */} { ) } -export default ProjectSearchContainer +export default ProjectsTagButtonsFilter diff --git a/src/NativeBase/Components/TopOfApp.tsx b/src/NativeBase/Components/TopOfApp.tsx index afd256f4..a540fb56 100644 --- a/src/NativeBase/Components/TopOfApp.tsx +++ b/src/NativeBase/Components/TopOfApp.tsx @@ -4,19 +4,17 @@ * Follows example here https://docs.nativebase.io/building-app-bar */ +import StaLogoWideDarkMode from '@/NativeBase/Assets/Images/Logos/sta-logo-wide-dark-mode.svg' +import StaLogoWide from '@/NativeBase/Assets/Images/Logos/sta-logo-wide.svg' import { Box, - HStack, - Icon, - IconButton, + Heading, StatusBar, useColorMode, useColorModeValue, + VStack, } from 'native-base' import React, { FC } from 'react' -import MaterialIcons from 'react-native-vector-icons/MaterialIcons' -import StaLogoWide from '@/NativeBase/Assets/Images/Logos/sta-logo-wide.svg' -import StaLogoWideDarkMode from '@/NativeBase/Assets/Images/Logos/sta-logo-wide-dark-mode.svg' import StaTheme from '../Theme/StaTheme' interface TopOfAppProps { @@ -63,7 +61,13 @@ const TopOfApp: FC = ({ _light={{ backgroundColor: StaTheme.colors.bg['100'] }} safeAreaTop > - + + Roles + + + + {/* = ({ /> )} - + */} ) diff --git a/src/NativeBase/Containers/ListContainer.tsx b/src/NativeBase/Containers/ListContainer.tsx index 6633c824..09e4c701 100644 --- a/src/NativeBase/Containers/ListContainer.tsx +++ b/src/NativeBase/Containers/ListContainer.tsx @@ -11,7 +11,6 @@ import EventOptions from '@/Components/Event/EventOptions' import EventSearchUpcomingQuickSearch, { EventQuickSearchUpcomingChoice, } from '@/Components/Event/EventSearchQuickSearchUpcoming' -import ProjectFilterSort from '@/Components/Project/ProjectFilterSort' import { EventSearch } from '@/Containers/EventSearchContainer' import FreeSearchBar from '@/NativeBase/Components/FreeSearchBar' import List, { @@ -19,6 +18,7 @@ import List, { ListOptions, } from '@/NativeBase/Components/List' import SkeletonLoading from '@/NativeBase/Components/SkeletonLoading' +import TopOfApp from '@/NativeBase/Components/TopOfApp' import { navigate, RootStackParamList } from '@/Navigators/utils' import { Events, @@ -27,31 +27,27 @@ import { useLazyFetchAllUpcomingEventsQuery, } from '@/Services/modules/events' import { + Project, Projects, useLazyFetchAllProjectsQuery, } from '@/Services/modules/projects' -import { RoleGroup, roleGroups } from '@/Services/modules/projects/roleGroups' +import { roleGroups } from '@/Services/modules/projects/roleGroups' import { EventsState, setEvents } from '@/Store/Events' import { ProjectsState, setProjects } from '@/Store/Projects' +import { fuzzySearchByArray } from '@/Utils/Search' import { capitaliseFirstLetter } from '@/Utils/Text' import underDevelopmentAlert from '@/Utils/UnderDevelopmentAlert' -import { - Heading, - HStack, - Icon, - IconButton, - ScrollView, - Text, - View, - VStack, -} from 'native-base' +import Fuse from 'fuse.js' +import { HStack, Icon, IconButton, ScrollView, View, VStack } from 'native-base' import React, { useEffect, useState } from 'react' import { Dimensions } from 'react-native' import MaterialIcons from 'react-native-vector-icons/MaterialIcons' import { useDispatch, useSelector } from 'react-redux' import styled from 'styled-components/native' +import ProjectsTagButtonsFilter, { + ProjectSearch, +} from '../Components/ProjectTagButtonsFilter' import { SegmentedPickerOption } from '../Components/SegmentedPicker' -import ProjectSearchContainer, { ProjectSearch } from './ProjectSearchContainer' const ClearSearchLabel = styled.Text` @@ -112,9 +108,9 @@ const ListContainer = (props: { // Shared const dispatch = useDispatch() const [listItemsToShow, setListItemsToShow] = useState() - const [roleSearchText, setRoleSearchText] = useState('') - const [filteredRoles, setFilteredRoles] = useState(roleGroups) + const params = props.route.params + const screens = { list: { [ListType.Events]: 'Events' as keyof RootStackParamList, @@ -131,21 +127,6 @@ const ListContainer = (props: { onPress: option === 'all' ? () => undefined : underDevelopmentAlert, } as SegmentedPickerOption), ) - // Handle role search text change - const handleRoleSearchChange = (text: string) => { - setRoleSearchText(text) - // Filter roles based on search text - const filtered = roleGroups.filter(roleGroup => - roleGroup.groupName.toLowerCase().includes(text.toLowerCase()), - ) - setFilteredRoles(filtered) - } - - // Clear role search text and reset filtered roles - const handleClearSearch = () => { - setRoleSearchText('') // Clear search text - setFilteredRoles(roleGroups) // Reset the filtered roles to the full list - } // Events-specific const [fetchAllUpcomingEvents, { data: allUpcomingEventsResult }] = @@ -233,7 +214,6 @@ const ListContainer = (props: { // What to do when the user navigates to this container // e.g. set which data to show -- either search results or everything useEffect(() => { - console.log('params search:', params.search) if (params?.search) { setListItemsToShow(params.search.results) } @@ -266,6 +246,70 @@ const ListContainer = (props: { allProjects, ]) + // Ensure job title searches find related roles + const getRelatedRoles = ( + possibleRoleSearchQuery: string, + ): string[] | undefined => { + const fuse = new Fuse(roleGroups, { + keys: ['roleNames'], + minMatchCharLength: 2, + threshold: 0.1, + }) + + const fuseResults = fuse.search(possibleRoleSearchQuery) + + if (fuseResults.length) { + const roles = [] + + for (const fuseResult of fuseResults) { + for (const role of fuseResult.item.roleNames) { + roles.push(role) + } + } + + return roles + } + + return undefined + } + + const handleFreeTextSubmit = (freeTextSearchQuery: string) => { + // Add free text to list of search queries + const searchQueries = [freeTextSearchQuery] + + // If the free text query matches a group of job roles, add these to the list of search queries too + const relatedRoles = getRelatedRoles(freeTextSearchQuery) + if (relatedRoles?.length) { + searchQueries.push(...relatedRoles) + } + + const results = fuzzySearchByArray( + allProjects, + [ + { name: 'client', weight: 1 }, + { name: 'description', weight: 0.5 }, + { name: 'name', weight: 1 }, + { name: 'role', weight: 1 }, + { name: 'skills', weight: 1 }, + { name: 'sector', weight: 1 }, + ], + searchQueries, + ) + + const description = `"${freeTextSearchQuery}"` + + navigate( + 'Projects' as keyof RootStackParamList, + { + type: ListType.Projects, + search: { + results, + description, + } as ProjectSearch, + } as ListRouteParams, + ) + } + // Clear the search so the user's seeing all data instead const clearSearch = () => { if (params?.type) { @@ -322,6 +366,20 @@ const ListContainer = (props: { const filteredList: Project[] = listItemsToShow!.filter((item: Project) => item.role === 'User Researcher') params.search = { results: filteredList, description: 'fake filtering' } as ProjectSearch */ + + /* THIS WORKS TOO: calling directly the already partly implemented search functionality of the ListContainer component + */ + const searchResults: ProjectSearch = { + description: 'test description', + results: (listItemsToShow as Projects).filter( + (item: Project) => item.role === 'User Researcher', + ), + } + navigate(screens.list[params.type], { + type: params.type, + search: searchResults, + } as ListRouteParams) + // 2. we want to use existing filtering logic to manipulate the list of projects and show it in the list // 3. we are really cool and start using maybe redux selectors to apply the filtering (maybe?) // 4. step 3 is OPTIONAL. once we have managed to get to step 2, we will now focus on doing roles filtering using our tagbuttons. @@ -335,24 +393,17 @@ params.search = { results: filteredList, description: 'fake filtering' } as Proj return ( <> - {/* navigate(screens.search[params.type], '')} - /> */} + {/* TODO: reinstate when functionality is ready */} {/* */} - - Roles - @@ -367,6 +418,7 @@ params.search = { results: filteredList, description: 'fake filtering' } as Proj justifyContent="center" alignItems="center" > + {/* TODO remove button once not needed anymore for testing SVA-444 */} - - {/* Display filtered roles based on the search */} - - {roleSearchText && filteredRoles.length > 0 && ( - <> - - Roles matching "{roleSearchText}" - - {filteredRoles.map((roleGroup, index) => ( - - {roleGroup.groupName} - - ))} - - )} - {roleSearchText && filteredRoles.length === 0 && ( - No roles found - )} - - + - - - {params?.type && listItemsToShow ? ( - <> - {/* Past / Upcoming / My Events choice */} - {params.type === ListType.Events && ( - - )} - - {/* Quick search for upcoming events (Today / This week / This month) */} - {params.type === ListType.Events && - eventsShowUpcomingQuickSearch && - eventsQuickSearchUpcomingChoice && ( - - - - )} - - {/* If the user has searched, show some text indicating what they searched for - and give them the option to clear the search */} - {params?.search && ( + + {params?.type && listItemsToShow ? ( + <> + {/* Past / Upcoming / My Events choice */} + {params.type === ListType.Events && ( + + )} + + {/* Quick search for upcoming events (Today / This week / This month) */} + {params.type === ListType.Events && + eventsShowUpcomingQuickSearch && + eventsQuickSearchUpcomingChoice && ( - {params?.search?.description && ( - - Results for {params.search.description} - - )} - - Clear search - + )} - {/* Projects filter & sort options */} - {params.type === ListType.Projects && - Boolean(params?.search) && - Boolean(listItemsToShow.length) && } - - - - ) : ( - <> - - - - - - - )} - - + + + ) : ( + <> + + + + + + + )} + ) diff --git a/src/NativeBase/Containers/SearchResultsContainer.tsx b/src/NativeBase/Containers/SearchResultsContainer.tsx index c0cd090e..f97b9770 100644 --- a/src/NativeBase/Containers/SearchResultsContainer.tsx +++ b/src/NativeBase/Containers/SearchResultsContainer.tsx @@ -2,7 +2,15 @@ * @file Search results screen container. */ -import React, { useState } from 'react' +import { EventSearch } from '@/Containers/EventSearchContainer' +import List, { + ListDisplayMode, + ListOptions, +} from '@/NativeBase/Components/List' +import SearchIconHighlighted from '@/NativeBase/Components/SearchIconHighlighted' +import { goBack, navigate, RootStackParamList } from '@/Navigators/utils' +import { Events } from '@/Services/modules/events' +import { Projects } from '@/Services/modules/projects' import { Box, HStack, @@ -12,17 +20,10 @@ import { Text, View, } from 'native-base' +import React, { useState } from 'react' import { Dimensions } from 'react-native' import MaterialIcons from 'react-native-vector-icons/MaterialIcons' -import { EventSearch } from '@/Containers/EventSearchContainer' -import List, { - ListDisplayMode, - ListOptions, -} from '@/NativeBase/Components/List' -import SearchIconHighlighted from '@/NativeBase/Components/SearchIconHighlighted' -import { goBack, navigate, RootStackParamList } from '@/Navigators/utils' -import { Events } from '@/Services/modules/events' -import { Projects } from '@/Services/modules/projects' +import { ProjectSearch } from '../Components/ProjectTagButtonsFilter' import { ListRouteParams, ListScreens, @@ -30,7 +31,6 @@ import { ListType, searchScreens, } from './ListContainer' -import { ProjectSearch } from './ProjectSearchContainer' export interface SearchResults extends ListSearch { results: Events | Projects diff --git a/src/NativeBase/Containers/VerticalStackContainer.tsx b/src/NativeBase/Containers/VerticalStackContainer.tsx deleted file mode 100644 index bda67477..00000000 --- a/src/NativeBase/Containers/VerticalStackContainer.tsx +++ /dev/null @@ -1,107 +0,0 @@ -/** - * @file A generalised stacked container used for events or projects. - */ -import React from 'react' -import { - Box, - FlatList, - Text, - Heading, - Button, - HStack, - FavouriteIcon, - VStack, -} from 'native-base' -import TechBadge from '../Components/TechBadge' -import TopOfApp from '../Components/TopOfApp' -import { ColorType } from 'native-base/lib/typescript/components/types' - -type TechBadge = { - caption: string - color: ColorType -} - -const data = [ - { - id: '1', - title: 'Fyne Futures Charity Inventory Integration', - charity: 'Fyne Futures Ltd', - role: 'Business analyst', - description: - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', - badge: [ - { caption: 'Analysis', color: 'primary' }, - { caption: 'Data', color: 'secondary' }, - ], - hours: '1-4 hours per week', - buddying: true, - }, - { - id: '2', - title: 'Fyne Futures Charity Inventory Integration', - charity: 'Fyne Futures Ltd', - role: 'Frontend Developer', - description: - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', - badge: [{ caption: 'Frontend', color: 'primary' }], - hours: '1-4 hours per week', - buddying: true, - }, - { - id: '3', - title: 'Fyne Futures Charity Inventory Integration', - charity: 'Fyne Futures Ltd', - role: 'Backend Developer', - description: - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', - badge: [{ caption: 'Backend', color: 'primary' }], - hours: '1-4 hours per week', - buddying: true, - }, -] - -const VerticalStackContainer = () => { - return ( - <> - - - ( - - - {item.title} - {item.charity} - {item.role} - {item.description} - - {item.hours} - - {item.buddying - ? 'Suitable for buddying' - : 'Not suitable for buddiing'} - - - - - - - - )} - keyExtractor={item => item.id} - /> - - ) -} - -export default VerticalStackContainer diff --git a/src/NativeBase/Containers/index.ts b/src/NativeBase/Containers/index.ts index 8cac1f00..548d60f0 100644 --- a/src/NativeBase/Containers/index.ts +++ b/src/NativeBase/Containers/index.ts @@ -2,12 +2,10 @@ * @file Exports the containers for easy access elsewhere. */ +export { default as ProjectsTagButtonsFilter } from '../Components/ProjectTagButtonsFilter' export { default as ListContainer } from './ListContainer' +export { default as LoginContainer } from './LoginContainer' export { default as ProfileContainer } from './ProfileContainer' export { default as ProjectDetailContainer } from './ProjectDetailContainer' -export { default as ProjectSearchContainer } from './ProjectSearchContainer' -export { default as SearchResultsContainer } from './SearchResultsContainer' export { default as SettingsContainer } from './SettingsContainer' -export { default as VerticalStackContainer } from './VerticalStackContainer' export { default as WebViewContainer } from './WebViewContainer' -export { default as LoginContainer } from './LoginContainer' diff --git a/src/Navigators/Application.tsx b/src/Navigators/Application.tsx index f9a3e0f7..df7fbbfd 100644 --- a/src/Navigators/Application.tsx +++ b/src/Navigators/Application.tsx @@ -2,37 +2,35 @@ * @file Defines the list of screens (apart from the main screens that have tabs at the bottom of the app e.g. Projects -- these are defined in Main.tsx). */ -import { useColorMode, View } from 'native-base' -import React, { useEffect, useRef, useState } from 'react' -import { AppState, StatusBar, useColorScheme } from 'react-native' -import { useSafeAreaInsets } from 'react-native-safe-area-context' -import { NavigationContainer } from '@react-navigation/native' -import { - createStackNavigator, - StackHeaderProps, - StackNavigationOptions, -} from '@react-navigation/stack' -import { useSelector } from 'react-redux' import { EventDetailContainer, - StartupContainer, EventSearchContainer, + StartupContainer, WelcomeContainer, } from '@/Containers' -import MyExperienceContainer from '@/NativeBase/Containers/MyExperienceContainer' -import ProjectRegisterInterestContainer from '@/NativeBase/Containers/ProjectRegisterInterestContainer' -import MainNavigator from './Main' -import { navigationRef } from './utils' import NavigationHeader from '@/NativeBase/Components/NavigationHeader' import { LoginContainer, ProjectDetailContainer, - ProjectSearchContainer, - SearchResultsContainer, WebViewContainer, } from '@/NativeBase/Containers' +import MyExperienceContainer from '@/NativeBase/Containers/MyExperienceContainer' +import ProjectRegisterInterestContainer from '@/NativeBase/Containers/ProjectRegisterInterestContainer' import StaTheme from '@/NativeBase/Theme/StaTheme' import { ThemeState } from '@/Store/Theme' +import { NavigationContainer } from '@react-navigation/native' +import { + createStackNavigator, + StackHeaderProps, + StackNavigationOptions, +} from '@react-navigation/stack' +import { useColorMode, View } from 'native-base' +import React, { useEffect, useRef, useState } from 'react' +import { AppState, StatusBar, useColorScheme } from 'react-native' +import { useSafeAreaInsets } from 'react-native-safe-area-context' +import { useSelector } from 'react-redux' +import MainNavigator from './Main' +import { navigationRef } from './utils' const Stack = createStackNavigator() @@ -166,23 +164,14 @@ const ApplicationNavigator = () => { }} /> - - - + /> */} { return ( - {/* */} Date: Sat, 14 Dec 2024 18:42:02 +0000 Subject: [PATCH 16/16] handleQuickSearch passed as a prop, logic moved to ListContainer --- src/Containers/.StartupContainer.tsx.swp | Bin 12288 -> 0 bytes .../Components/ProjectTagButtonsFilter.tsx | 97 +++--------------- src/NativeBase/Containers/ListContainer.tsx | 40 +++++++- 3 files changed, 51 insertions(+), 86 deletions(-) delete mode 100644 src/Containers/.StartupContainer.tsx.swp diff --git a/src/Containers/.StartupContainer.tsx.swp b/src/Containers/.StartupContainer.tsx.swp deleted file mode 100644 index 186bc6893e9d8a01a312395073fea1223e41a300..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2O>Y}T7{@2&t)+yQq9Sp72uOA!$Lj&>yetVIzJ0JiT!E4|=_+y%}-@$!w4}1-FK>&8ZW$+d_3;uk8 zu_N#+xC1^0AA!^0ud|H(2)+SdfxF;K@Hw~zhCqT9;DMv(8T%Q02kwF|Ko4w#El>il zgK2OEJO`cy&w!`FQ{WVs0=W)PU>;q_P64NYQ@|Dm8^X^0Qde z@uQVisUahp1w_kUTkyk6`LlUz@tz*N5q-epAnkC{Dd{~<%^=lUs6A@&V2>KI)2Bwa zYkePhY4p*E#cooc2{=xD${A}y)b+zqB)j#Q3lG{NoCIx(PkDW2VWKt3Iy+q6h&FIW zRMiIyCgkGs!%s4$)fMa3O0NiQKQ5c_N6(Ewivywi*OO2LzD^}6Gs>V8`*N3;hNN^q z#`}j?GmRisHE(Zk;;TruhvbcBw7e$$Bpkgj8^OlD8-72{bTtxjTp{}sr15$_@9m-K zLUNtSgvt!h!$NhD2wgUhnc|nDhzGh{o~8OF8stWH21}Iq2V&RPype=W(dowgCRbdS zOPe@3TPnIDS~=0orq5ccz4Xww_q;dFEk;{cZ(XdLzV|*`(L7xEzeRVAAE_l%=k!~g20_63|5cioVNABXdhMF>fmc7Ns`RH3`p+ zs#ck*Nrj2G=zk(%7zUa*d5ls?WtpvwjRv;rDrC!;hJ|sV+bn*M<-s1`31Bo18Kq@5 zjRDqmPs2aLoT-%fSU-Gz$5*_>#wHVCj4dVi13fQ!nDr(sA6>j-r&aI0qPkNY0nfCE z)r9XuYC*+=$}3o$Wl;gPqF?TZy&%-aNJX1<1rbsRQ5uKFJESx*6=qJ?SD80A$Nm8Td_fKX diff --git a/src/NativeBase/Components/ProjectTagButtonsFilter.tsx b/src/NativeBase/Components/ProjectTagButtonsFilter.tsx index 337f5fd3..c589dc09 100644 --- a/src/NativeBase/Components/ProjectTagButtonsFilter.tsx +++ b/src/NativeBase/Components/ProjectTagButtonsFilter.tsx @@ -1,25 +1,15 @@ -import { navigate, RootStackParamList } from '@/Navigators/utils' import { Projects, ProjectSector, ProjectsSearchField, ProjectTechnology, } from '@/Services/modules/projects' -import { - RoleGroupName, - roleGroups, -} from '@/Services/modules/projects/roleGroups' +import { RoleGroupName } from '@/Services/modules/projects/roleGroups' import { ProjectsState } from '@/Store/Projects' -import { fuzzySearchByArray, searchByArray } from '@/Utils/Search' -import Fuse from 'fuse.js' import { VStack } from 'native-base' -import React, { useState } from 'react' +import React, { FC, useState } from 'react' import { useSelector } from 'react-redux' -import { - ListRouteParams, - ListSearch, - ListType, -} from '../Containers/ListContainer' +import { ListSearch } from '../Containers/ListContainer' import ChoicesList, { ChoicesListChoice, ChoicesListColour, @@ -30,8 +20,16 @@ import TagButtons from './TagButtons' export interface ProjectSearch extends ListSearch { results: Projects // the projects results for this search } +export interface ProjectsTagButtonsFilterProps { + handleQuickSearchSubmit: ( + searchField: ProjectsSearchField, + searchQueryChoice: string, + ) => void +} -const ProjectsTagButtonsFilter = () => { +const ProjectsTagButtonsFilter: FC = ({ + handleQuickSearchSubmit, +}) => { // Fetch all projects from the store const allProjects = useSelector( (state: { projects: ProjectsState }) => state.projects.projects, @@ -85,77 +83,6 @@ const ProjectsTagButtonsFilter = () => { const quickSearchListColour = ChoicesListColour.primary const quickSearchListStyle = ChoicesListFontStyle.mediumLight - // Ensure job title searches find related roles - const getRelatedRoles = ( - possibleRoleSearchQuery: string, - ): string[] | undefined => { - const fuse = new Fuse(roleGroups, { - keys: ['roleNames'], - minMatchCharLength: 2, - threshold: 0.1, - }) - - const fuseResults = fuse.search(possibleRoleSearchQuery) - - if (fuseResults.length) { - const roles = [] - - for (const fuseResult of fuseResults) { - for (const role of fuseResult.item.roleNames) { - roles.push(role) - } - } - - return roles - } - - return undefined - } - - const handleQuickSearchSubmit = ( - searchField: ProjectsSearchField, - searchQueryChoice: string, - ) => { - let searchQueries = [] as string[] - let results = [] as Projects - - searchQueries.push(searchQueryChoice) - - if (searchField === 'role') { - const relatedRoles = getRelatedRoles(searchQueryChoice) - - if (relatedRoles?.length) { - searchQueries = searchQueries.concat(relatedRoles) - } - results = fuzzySearchByArray( - allProjects, - [searchField], - searchQueries, - ) as Projects // we need to use fuzzy search as the roles names are not exact (charities use different ways of naming roles) - } else { - results = searchByArray( - allProjects, - searchField, - searchQueries, - ) as Projects // here we do not want to use fuzzy search as it would include unwanted results - } - - const description = `${ - searchField === 'sector' ? 'cause' : searchField - } "${searchQueryChoice}"` - - navigate( - 'Projects' as keyof RootStackParamList, - { - type: ListType.Projects, - search: { - results, - description, - } as ProjectSearch, - } as ListRouteParams, - ) - } - /** * Handle tag press logic * If the tag is already open, close it by setting activeTag to null. diff --git a/src/NativeBase/Containers/ListContainer.tsx b/src/NativeBase/Containers/ListContainer.tsx index 09e4c701..db78e647 100644 --- a/src/NativeBase/Containers/ListContainer.tsx +++ b/src/NativeBase/Containers/ListContainer.tsx @@ -29,6 +29,7 @@ import { import { Project, Projects, + ProjectsSearchField, useLazyFetchAllProjectsQuery, } from '@/Services/modules/projects' import { roleGroups } from '@/Services/modules/projects/roleGroups' @@ -391,6 +392,41 @@ params.search = { results: filteredList, description: 'fake filtering' } as Proj // const onSubmitEditing = (text: string) => text + const handleQuickSearchSubmit = ( + searchField: ProjectsSearchField, + searchQueryChoice: string, + ) => { + let searchQueries = [searchQueryChoice] + let results: Projects = [] + + // Add related roles if the search is by role + if (searchField === ProjectsSearchField.Role) { + const relatedRoles = getRelatedRoles(searchQueryChoice) + if (relatedRoles?.length) { + searchQueries = searchQueries.concat(relatedRoles) + } + } + + // Perform the search + results = fuzzySearchByArray( + allProjects, + [{ name: searchField, weight: 1 }], + searchQueries, + ) as Projects + + // Create a description for the search + const description = `${searchField}: "${searchQueryChoice}"` + + // Navigate to the updated list with the search results + navigate(screens.list[params.type], { + type: ListType.Projects, + search: { + results, + description, + } as ProjectSearch, + } as ListRouteParams) + } + return ( <> @@ -436,7 +472,9 @@ params.search = { results: filteredList, description: 'fake filtering' } as Proj - +