Skip to content

Commit

Permalink
[MOB-79] Categories search redirect (#2443)
Browse files Browse the repository at this point in the history
Support clicking on categories to redirect to search
  • Loading branch information
ameer2468 authored May 2, 2024
1 parent 8fd0085 commit da9fb95
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 52 deletions.
17 changes: 14 additions & 3 deletions apps/mobile/src/components/overview/CategoryItem.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { formatNumber } from '@sd/client';
import { Pressable, Text, View } from 'react-native';
import { ClassInput } from 'twrnc';
import { formatNumber } from '@sd/client';
import { tw, twStyle } from '~/lib/tailwind';

import { useNavigation } from '@react-navigation/native';
import { useSearchStore } from '~/stores/searchStore';
import { Icon, IconName } from '../icons/Icon';

interface CategoryItemProps {
Expand All @@ -16,7 +18,9 @@ interface CategoryItemProps {
style?: ClassInput;
}

const CategoryItem = ({ name, icon, items, style }: CategoryItemProps) => {
const CategoryItem = ({ name, icon, items, style, kind }: CategoryItemProps) => {
const navigation = useNavigation();
const searchStore = useSearchStore();
return (
<Pressable
style={twStyle(
Expand All @@ -25,7 +29,14 @@ const CategoryItem = ({ name, icon, items, style }: CategoryItemProps) => {
style
)}
onPress={() => {
//TODO: implement
searchStore.updateFilters('kind', {
name,
icon: icon + '20' as IconName,
id: kind
}, true);
navigation.navigate('SearchStack', {
screen: 'Search',
})
}}
>
<Icon name={icon} size={56} />
Expand Down
31 changes: 25 additions & 6 deletions apps/mobile/src/hooks/useFiltersSearch.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import { SearchFilterArgs } from '@sd/client';
import { SearchFilterArgs, useLibraryQuery } from '@sd/client';
import { useEffect, useMemo } from 'react';
import { Filters, SearchFilters, getSearchStore, useSearchStore } from '~/stores/searchStore';

/**
* This hook merges the selected filters from Filters page in order
* to make query calls for saved searches and setups filters for the search
* the data structure has been designed to match the desktop app
* @param search - search input string value
*/

export function useFiltersSearch() {
const searchStore = useSearchStore();;

export function useFiltersSearch(search: string) {

const [name, ext] = useMemo(() => search.split('.'), [search]);
const searchStore = useSearchStore();

const locations = useLibraryQuery(['locations.list'], {
keepPreviousData: true,
enabled: (name || ext) ? true : false,
});

const filterFactory = (key: SearchFilters, value: Filters[keyof Filters]) => {

Expand Down Expand Up @@ -49,8 +57,19 @@ export function useFiltersSearch() {

const mergedFilters = useMemo(() => {

const filters = [] as SearchFilterArgs[];
const filters = [] as SearchFilterArgs[];

//It's a global search if no locations have been selected
if (searchStore.filters.locations.length === 0 || !name || !ext) {
const locationIds = locations.data?.map((l) => l.id);
if (locationIds) filters.push({ filePath: { locations: { in: locationIds } } });
}

//handle search input
if (name) filters.push({ filePath: { name: { contains: name } } });
if (ext) filters.push({ filePath: { extension: { in: [ext] } } });

// handle selected filters
for (const key in searchStore.filters) {

const filterKey = key as SearchFilters;
Expand All @@ -77,10 +96,10 @@ export function useFiltersSearch() {
// makes sure the array is not 2D
return filters.flat();

}, [searchStore.filters]);
}, [searchStore.filters, search]);


useEffect(() => {
getSearchStore().mergedFilters = mergedFilters;
}, [searchStore.filters]);
}, [searchStore.filters, search]);
};
2 changes: 1 addition & 1 deletion apps/mobile/src/screens/overview/Categories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useLibraryQuery } from '@sd/client';
import { useMemo } from 'react';
import { FlatList, View } from 'react-native';
import { useDebounce } from 'use-debounce';
import { useLibraryQuery } from '@sd/client';
import { IconName } from '~/components/icons/Icon';
import ScreenContainer from '~/components/layout/ScreenContainer';
import CategoryItem from '~/components/overview/CategoryItem';
Expand Down
48 changes: 8 additions & 40 deletions apps/mobile/src/screens/search/Search.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useIsFocused } from '@react-navigation/native';
import { SearchFilterArgs, useLibraryQuery, usePathsExplorerQuery } from '@sd/client';
import { ArrowLeft, DotsThreeOutline, FunnelSimple, MagnifyingGlass } from 'phosphor-react-native';
import { Suspense, useDeferredValue, useMemo, useState } from 'react';
import { usePathsExplorerQuery } from '@sd/client';
import { ArrowLeft, DotsThreeOutline, FunnelSimple } from 'phosphor-react-native';
import { Suspense, useDeferredValue, useState } from 'react';
import { ActivityIndicator, Platform, Pressable, TextInput, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import Explorer from '~/components/explorer/Explorer';
Expand All @@ -15,42 +15,21 @@ import { useSearchStore } from '~/stores/searchStore';

const SearchScreen = ({ navigation }: SearchStackScreenProps<'Search'>) => {
const headerHeight = useSafeAreaInsets().top;
const [loading, setLoading] = useState(false);
const searchStore = useSearchStore();
const explorerStore = useExplorerStore();
const isFocused = useIsFocused();
const appliedFiltersLength = Object.keys(searchStore.appliedFilters).length;
const isAndroid = Platform.OS === 'android';
const locations = useLibraryQuery(['locations.list'], {
keepPreviousData: true,
});

const [search, setSearch] = useState('');
const deferredSearch = useDeferredValue(search);

const filters = useMemo(() => {
const [name, ext] = deferredSearch.split('.');

const filters: SearchFilterArgs[] = [];

if (name) filters.push({ filePath: { name: { contains: name } } });
if (ext) filters.push({ filePath: { extension: { in: [ext] } } });

if (name || ext) {
// Add locations filter to search all locations
if (locations.data && locations.data.length > 0) filters.push({ filePath: { locations: { in:
locations.data?.map((location) => location.id) } } });
}

return searchStore.mergedFilters.concat(filters);
}, [deferredSearch, searchStore.mergedFilters, locations.data]);
const appliedFiltersLength = Object.keys(searchStore.appliedFilters).length;
const isAndroid = Platform.OS === 'android';

const objects = usePathsExplorerQuery({
arg: {
take: 30,
filters
filters: searchStore.mergedFilters,
},
enabled: isFocused && filters.length > 1, // only fetch when screen is focused & filters are applied
enabled: isFocused && searchStore.mergedFilters.length > 1, // only fetch when screen is focused & filters are applied
suspense: true,
order: null,
onSuccess: () => getExplorerStore().resetNewThumbnails()
Expand All @@ -60,7 +39,7 @@ const SearchScreen = ({ navigation }: SearchStackScreenProps<'Search'>) => {
const noObjects = objects.items?.length === 0 || !objects.items;
const noSearch = deferredSearch.length === 0 && appliedFiltersLength === 0;

useFiltersSearch();
useFiltersSearch(deferredSearch);

return (
<View
Expand All @@ -87,17 +66,6 @@ const SearchScreen = ({ navigation }: SearchStackScreenProps<'Search'>) => {
style={tw`h-10 w-4/5 flex-wrap rounded-md border border-app-inputborder bg-app-input`}
>
<View style={tw`flex h-full flex-row items-center px-3`}>
<View style={tw`mr-3`}>
{loading ? (
<ActivityIndicator size={'small'} color={'white'} />
) : (
<MagnifyingGlass
size={20}
weight="bold"
color={tw.color('ink-dull')}
/>
)}
</View>
<TextInput
value={search}
onChangeText={(t) => setSearch(t)}
Expand Down
8 changes: 6 additions & 2 deletions apps/mobile/src/stores/searchStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ const searchStore = proxy<
State & {
updateFilters: <K extends keyof State['filters']>(
filter: K,
value: State['filters'][K] extends Array<infer U> ? U : State['filters'][K]
value: State['filters'][K] extends Array<infer U> ? U : State['filters'][K],
apply?: boolean
) => void;
applyFilters: () => void;
setSearch: (search: string) => void;
Expand All @@ -89,7 +90,7 @@ const searchStore = proxy<
>({
...initialState,
//for updating the filters upon value selection
updateFilters: (filter, value) => {
updateFilters: (filter, value, apply = false) => {
if (filter === 'hidden') {
// Directly assign boolean values without an array operation
searchStore.filters['hidden'] = value as boolean;
Expand All @@ -107,6 +108,9 @@ const searchStore = proxy<
searchStore.filters[filter] = updatedFilter;
}
}
//instead of a useEffect or subscription - we can call applyFilters directly
// useful when you want to apply the filters from another screen
if (apply) searchStore.applyFilters();
},
//for clicking add filters and applying the selection
applyFilters: () => {
Expand Down

0 comments on commit da9fb95

Please sign in to comment.