From 20435545ef1972fc44a459aad92aa6a2ac801996 Mon Sep 17 00:00:00 2001 From: kunalsharma Date: Thu, 22 Dec 2022 05:15:54 +0530 Subject: [PATCH] filters --- .../allCasesFilters/FiltersContainer.tsx | 225 ++++++++++++------ src/components/utlis/parsers.ts | 9 +- src/reducer/allCasesSlice.ts | 102 +++++++- src/screens/allCases/CaseItem.tsx | 43 +++- src/screens/allCases/interface.ts | 10 + src/store/store.ts | 6 +- 6 files changed, 301 insertions(+), 94 deletions(-) diff --git a/src/components/screens/allCases/allCasesFilters/FiltersContainer.tsx b/src/components/screens/allCases/allCasesFilters/FiltersContainer.tsx index ca41417c..cc45e283 100644 --- a/src/components/screens/allCases/allCasesFilters/FiltersContainer.tsx +++ b/src/components/screens/allCases/allCasesFilters/FiltersContainer.tsx @@ -1,5 +1,5 @@ import React, {useEffect, useMemo} from 'react'; -import {StyleSheet, TouchableOpacity, View} from 'react-native'; +import {PixelRatio, StyleSheet, TouchableOpacity, View} from 'react-native'; import {GenericStyles} from '../../../../../RN-UI-LIB/src/styles'; import Heading from '../../../../../RN-UI-LIB/src/components/Heading'; import Text from '../../../../../RN-UI-LIB/src/components/Text'; @@ -9,62 +9,59 @@ import {RootState} from '../../../../store/store'; import TextInput from '../../../../../RN-UI-LIB/src/components/TextInput'; import CheckboxGroup from '../../../../../RN-UI-LIB/src/components/chechbox/CheckboxGroup'; import {useAppDispatch} from '../../../../hooks'; -import {setFilterList, setSelectedFilters} from '../allCasesSlice'; -import {Data, IFilter} from '../interface'; import { CONDITIONAL_OPERATORS, FILTER_TYPES, - Option, + Option, SELECTION_TYPES, } from '../../../../common/Constants'; -import {objectParser} from '../../../utlis/parsers'; +import {getObjectValueFromKeys} from '../../../utlis/parsers'; +import {IFilter} from "../../../../screens/allCases/interface"; +import {clearSelectedFilters, setFilterList, setSelectedFilters} from "../../../../reducer/allCasesSlice"; +import RadioGroup from "../../../../../RN-UI-LIB/src/components/radio_button/RadioGroup"; +import RadioButton from "../../../../../RN-UI-LIB/src/components/radio_button/RadioButton"; interface FilterContainerProps { closeFilterModal: () => void; } +class Data { +} + const evaluateFilterForCases = ( caseRecord: Data, selectedFilterKeys: string[], filters: Record, - selectedFilters: Record, + selectedFilters: Record, ) => { let evaluatedResult = true; selectedFilterKeys.forEach(key => { switch (filters[key].filterType) { case FILTER_TYPES.DATE: - // objectParser(caseRecord , filters[key].fieldToCompare.split('.')) - // evaluatedResult = evaluatedResult && selectedFilters[key].some(filter => filter.value ) switch (filters[key].operator) { case CONDITIONAL_OPERATORS.EQUALS: if (selectedFilters[key]) { evaluatedResult = - evaluatedResult && - selectedFilters[key].some( - filter => - new Date().getTime() - filter.value === - objectParser( + evaluatedResult && selectedFilters[key][ + new Date().getTime() - getObjectValueFromKeys( caseRecord, filters[key].fieldToCompare.split( '.', ), - ), - ); + ) + ] } break; case CONDITIONAL_OPERATORS.LESS_THAN_EQUAL_TO: if (selectedFilters[key]) { evaluatedResult = evaluatedResult && - selectedFilters[key].some( - filter => - new Date().getTime() - filter.value <= - objectParser( - caseRecord, - filters[key].fieldToCompare.split( - '.', - ), - ), - ); + new Date().getTime() - (selectedFilters[key].value * 1000) <= + getObjectValueFromKeys( + caseRecord, + filters[key].fieldToCompare.split( + '.', + ), + ) } break; default: @@ -76,30 +73,51 @@ const evaluateFilterForCases = ( if (selectedFilters[key]) { evaluatedResult = evaluatedResult && - selectedFilters[key].some( - filter => - filter.value === - objectParser( - caseRecord, - filters[key].fieldToCompare.split( - '.', - ), - ), - ); + selectedFilters[key][ + new Date().getTime() - getObjectValueFromKeys( + caseRecord, + filters[key].fieldToCompare.split( + '.', + ), + )] + // selectedFilters[key].some( + // filter => { + // console.log('filter.value .....' , filter.value); + // console.log('field value' , getObjectValueFromKeys( + // caseRecord, + // filters[key].fieldToCompare.split( + // '.', + // ))); + // return filter.value === + // getObjectValueFromKeys( + // caseRecord, + // filters[key].fieldToCompare.split( + // '.', + // ), + // ) + // }, + // ); } break; case CONDITIONAL_OPERATORS.LESS_THAN_EQUAL_TO: if (selectedFilters[key]){ evaluatedResult = evaluatedResult && - selectedFilters[key].some( - filter => - filter.value <= - objectParser( - caseRecord, - filters[key].fieldToCompare.split('.'), - ), - ); + new Date().getTime() - (selectedFilters[key].value * 1000) <= + getObjectValueFromKeys( + caseRecord, + filters[key].fieldToCompare.split( + '.', + ), + ) + // selectedFilters[key].some( + // filter => + // filter.value <= + // getObjectValueFromKeys( + // caseRecord, + // filters[key].fieldToCompare.split('.'), + // ), + // ); } break; default: @@ -115,11 +133,12 @@ const evaluateFilterForCases = ( const FiltersContainer: React.FC = props => { const {closeFilterModal} = props; - const {filters, selectedFilters, compiledList} = useSelector( + const {filters, selectedFilters, casesList , filterList} = useSelector( (state: RootState) => ({ filters: state.allCases.filters, selectedFilters: state.allCases.selectedFilters, - compiledList: state.allCases.compiledList, + casesList: state.allCases.casesList, + filterList: state.allCases.filterList, }), ); const [selectedFilterKey, setSelectedFilterKey] = React.useState(); @@ -130,7 +149,8 @@ const FiltersContainer: React.FC = props => { // Record // >({}); const dispatch = useAppDispatch(); - const handleFilterSelection = (filterValues: Option[]) => { + const handleFilterSelection = (filterValues: any) => { + console.log(filterValues); selectedFilterKey && dispatch(setSelectedFilters({[selectedFilterKey]: filterValues})); }; @@ -142,7 +162,7 @@ const FiltersContainer: React.FC = props => { const applyFilter = () => { dispatch( setFilterList( - compiledList.filter(record => + casesList.filter(record => evaluateFilterForCases( record, Object.keys(selectedFilters), @@ -154,36 +174,68 @@ const FiltersContainer: React.FC = props => { ); }; + const onClearAll = () => { + dispatch(clearSelectedFilters()); + } + + useEffect(() => { + console.log('filterList.......', JSON.stringify(filterList)); + },[filterList]); + + useEffect(() => { + console.log('casesList.......', JSON.stringify(casesList)); + },[casesList]); + useEffect(() => { console.log('selectedFilters.......', selectedFilters); }, [selectedFilters]); const Options = React.useMemo(() => { if (selectedFilterKey) { - const options = filters[selectedFilterKey].options.filter( - option => - option.label.toLowerCase().indexOf(filterSearchString) > -1, - ); - // console.log('options..........', options); - const selectedFilterValues = selectedFilters[ - selectedFilterKey - ]?.map((x: any) => x.value); - // console.log("selectedFilters", selectedFilterValues) - return ( - - {/* @ts-ignore */} - - - ); + switch (filters[selectedFilterKey].selectionType) { + case SELECTION_TYPES.MULTIPLE : + const options = filters[selectedFilterKey].options.filter( + option => + option.label.toLowerCase().indexOf(filterSearchString) > -1, + ); + // console.log('options..........', options); + // const selectedFilterValues = selectedFilters[ + // selectedFilterKey + // ]?.map((x: any) => x.value); + // console.log("selectedFilters", selectedFilterValues) + return ( + + {/*@ts-ignore */} + + + ); + case SELECTION_TYPES.SINGLE : + return ( + + {/*@ts-ignore */} + + { + filters[selectedFilterKey].options.map(option =>( + + )) + } + + + ) + } } return <>; }, [selectedFilterKey, selectedFilters, filterSearchString]); @@ -221,8 +273,8 @@ const FiltersContainer: React.FC = props => { styles.filterSelector, GenericStyles.row, GenericStyles.alignCenter, + GenericStyles.spaceBetween, styles.mv8, - // GenericStyles.fill, key === selectedFilterKey && styles.selectedFilterKey, ]} @@ -239,6 +291,17 @@ const FiltersContainer: React.FC = props => { dark> {filters[key].displayText} + { + selectedFilters[key] && ( + + + { + typeof selectedFilters[key] === 'object' ? Object.keys(selectedFilters[key]).length : 1 + } + + + ) + } ))} @@ -262,7 +325,7 @@ const FiltersContainer: React.FC = props => { , keysArray: Array) => any = (obj , keysArray) => { +export const getObjectValueFromKeys: (obj: Record , keysArray: Array) => any = (obj , keysArray) => { - if (keysArray.length){ - return obj[keysArray[0]] && objectParser(obj[keysArray[0]], keysArray.slice(1)); + if (keysArray.length && obj[keysArray[0]]){ + return getObjectValueFromKeys(obj[keysArray[0]], keysArray.slice(1)); + }else if (obj){ + console.log(obj); + return obj } return null; diff --git a/src/reducer/allCasesSlice.ts b/src/reducer/allCasesSlice.ts index f0982a42..444de79b 100644 --- a/src/reducer/allCasesSlice.ts +++ b/src/reducer/allCasesSlice.ts @@ -3,8 +3,9 @@ import {Search} from '../../RN-UI-LIB/src/utlis/search'; import {createSlice} from '@reduxjs/toolkit'; import {navigateToScreen} from '../components/utlis/navigationUtlis'; import { - ICaseItem, + ICaseItem, IFilter, } from '../screens/allCases/interface'; +import {CONDITIONAL_OPERATORS, FILTER_TYPES, SELECTION_TYPES} from "../common/Constants"; export type ICasesMap = {[key: string]: ICaseItem}; @@ -21,6 +22,8 @@ interface IAllCasesSlice { newlyPinnedCases: number; completedCases: number; caseDetails: any; + filters: Record; + selectedFilters: Record } const initialState: IAllCasesSlice = { @@ -36,6 +39,88 @@ const initialState: IAllCasesSlice = { newlyPinnedCases: 0, completedCases: 0, caseDetails: {}, + filters: { + pincodes: { + filterType: FILTER_TYPES.STRING, + selectionType: SELECTION_TYPES.MULTIPLE, + displayText: 'Pincode', + fieldToCompare: 'currentTask.metadata.address.pinCode', + operator: CONDITIONAL_OPERATORS.EQUALS, + options: [ + { + label: "500000", + value: "500000" + }, + { + label: "560036", + value: "560036" + }, + { + label: "560037", + value: "560037" + } + ] + }, + caseStatus: { + filterType: FILTER_TYPES.STRING, + selectionType: SELECTION_TYPES.MULTIPLE, + displayText: 'Feedback', + fieldToCompare: 'caseStatus', + operator: CONDITIONAL_OPERATORS.EQUALS, + options: [ + { + label: "NEW", + value: "New" + }, + { + label: "UNASSIGNED", + value: "UNASSIGNED" + }, + { + label: "ASSIGNED", + value: "ASSIGNED" + }, + { + label: "IN_PROGRESS", + value: "IN_PROGRESS" + }, + { + label: "CLOSED", + value: "CLOSED" + }, + { + label: "FORCE_CLOSED", + value: "FORCE_CLOSED" + }, + { + label: "EXPIRED", + value: "EXPIRED" + } + ] + }, + allocatedAt: { + filterType: FILTER_TYPES.DATE, + selectionType: SELECTION_TYPES.SINGLE, + displayText: 'Allocation Date', + fieldToCompare: 'allocatedAt', + operator: CONDITIONAL_OPERATORS.LESS_THAN_EQUAL_TO, + options: [ + { + label: "Last 2 days", + value: 172800 + }, + { + label: "Last 5 days", + value: 432000 + }, + { + label: "Last 10 days", + value: 864000 + } + ] + } + }, + selectedFilters: {} }; const getPinnedListDetails = (casesList: ICaseItem[]) => { @@ -133,6 +218,16 @@ const allCasesSlice = createSlice({ state.newlyPinnedCases = 0; navigateToScreen('Home'); }, + setSelectedFilters: (state , action) => { + state.selectedFilters = {...state.selectedFilters , ...action.payload} + }, + clearSelectedFilters: (state) => { + state.selectedFilters = {}; + }, + setFilterList: (state, action) => { + console.log('filterList.....', action.payload); + state.filterList = action.payload; + } }, }); @@ -143,7 +238,10 @@ export const { resetTodoList, filterData, proceedToTodoList, - deleteIntermediateTodoListItem + deleteIntermediateTodoListItem, + setSelectedFilters, + setFilterList, + clearSelectedFilters } = allCasesSlice.actions; export default allCasesSlice.reducer; diff --git a/src/screens/allCases/CaseItem.tsx b/src/screens/allCases/CaseItem.tsx index 99c0dd1a..3e1c29a4 100644 --- a/src/screens/allCases/CaseItem.tsx +++ b/src/screens/allCases/CaseItem.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import {ListRenderItemInfo, StyleSheet, View} from 'react-native'; +import {ListRenderItemInfo, Modal, StyleSheet, TouchableOpacity, View} from 'react-native'; import SearchIcon from '../../../RN-UI-LIB/src/Icons/SearchIcon'; import {GenericStyles} from '../../../RN-UI-LIB/src/styles'; import TextInput from '../../../RN-UI-LIB/src/components/TextInput'; @@ -8,6 +8,8 @@ import Heading from '../../../RN-UI-LIB/src/components/Heading'; import Text from '../../../RN-UI-LIB/src/components/Text'; import ListItem from './ListItem'; import {COLORS} from '../../../RN-UI-LIB/src/styles/colors'; +import FilterIcon from "../../assets/icons/FilterIcon"; +import FiltersContainer from "../../components/screens/allCases/allCasesFilters/FiltersContainer"; interface ICaseItemProps { data: ListRenderItemInfo; @@ -23,22 +25,37 @@ const CaseItem: React.FC = ({ handleSearchChange, }) => { const {FILTER, CASES_HEADER, TODO_HEADER} = CaseTypes; + const [showFilterModal, setShowFilterModal] = + React.useState(false); switch (caseData.type) { case FILTER: return ( - - } - onChangeText={handleSearchChange} - placeholder="Search by name, address" - /> - + <> + + } + onChangeText={handleSearchChange} + placeholder="Search by name, address" + /> + setShowFilterModal(prev => !prev)}> + + + + setShowFilterModal((prev => !prev))} visible={showFilterModal} > + setShowFilterModal((prev => !prev))} /> + + ); case CASES_HEADER: return ( diff --git a/src/screens/allCases/interface.ts b/src/screens/allCases/interface.ts index 7d9e1fb7..0b1b19ae 100644 --- a/src/screens/allCases/interface.ts +++ b/src/screens/allCases/interface.ts @@ -1,4 +1,5 @@ import {COLORS} from '../../../RN-UI-LIB/src/styles/colors'; +import {CONDITIONAL_OPERATORS, FILTER_TYPES, Option, SELECTION_TYPES} from "../../common/Constants"; export enum CaseTypes { TODO_HEADER, @@ -147,3 +148,12 @@ export enum ClassType { '.GeoLocationEntityMetadata', '.CallingEntityMetadata' } + +export interface IFilter { + filterType: FILTER_TYPES, + displayText: string, + selectionType: SELECTION_TYPES, + fieldToCompare: string, + operator: CONDITIONAL_OPERATORS, + options: Option[], +} diff --git a/src/store/store.ts b/src/store/store.ts index 4591ad39..b24d6fdf 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -28,8 +28,8 @@ const persistConfig = { key: 'root', version: 1, storage: AsyncStorage, - whitelist: ['case', 'common', 'allCases', 'user'], - blackList:['case'], + whitelist: ['case', 'common', 'user'], + blackList:['case' , 'allCases'], }; const persistedReducer = persistReducer(persistConfig, rootReducer); @@ -47,4 +47,4 @@ export const persistor = persistStore(store); export default store; export type RootState = ReturnType; -export type AppDispatch = typeof store.dispatch; \ No newline at end of file +export type AppDispatch = typeof store.dispatch;