[MOB-79] Categories search redirect (#2443)

Support clicking on categories to redirect to search
This commit is contained in:
ameer2468 2024-05-02 17:05:24 +03:00 committed by GitHub
parent 8fd00851ea
commit da9fb959e8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 54 additions and 52 deletions

View file

@ -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 {
@ -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(
@ -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} />

View file

@ -1,4 +1,4 @@
import { SearchFilterArgs } from '@sd/client';
import { SearchFilterArgs, useLibraryQuery } from '@sd/client';
import { useEffect, useMemo } from 'react';
import { Filters, SearchFilters, getSearchStore, useSearchStore } from '~/stores/searchStore';
@ -6,11 +6,19 @@ import { Filters, SearchFilters, getSearchStore, useSearchStore } from '~/stores
* 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]) => {
@ -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;
@ -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]);
};

View file

@ -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';

View file

@ -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';
@ -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()
@ -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
@ -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)}

View file

@ -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;
@ -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;
@ -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: () => {