This commit is contained in:
kunalsharma
2022-12-22 05:15:54 +05:30
parent 69e95501c5
commit 20435545ef
6 changed files with 301 additions and 94 deletions

View File

@@ -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<string, IFilter>,
selectedFilters: Record<string, Option[]>,
selectedFilters: Record<string, any>,
) => {
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<FilterContainerProps> = 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<string>();
@@ -130,7 +149,8 @@ const FiltersContainer: React.FC<FilterContainerProps> = props => {
// Record<string, any>
// >({});
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<FilterContainerProps> = props => {
const applyFilter = () => {
dispatch(
setFilterList(
compiledList.filter(record =>
casesList.filter(record =>
evaluateFilterForCases(
record,
Object.keys(selectedFilters),
@@ -154,36 +174,68 @@ const FiltersContainer: React.FC<FilterContainerProps> = 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 (
<View
style={[
styles.filterSelector,
GenericStyles.row,
GenericStyles.alignCenter,
]}>
{/* @ts-ignore */}
<CheckboxGroup
onSelectionChange={handleFilterSelection}
options={options}
defaultValue={selectedFilterValues}
/>
</View>
);
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 (
<View
style={[
styles.filterSelector,
GenericStyles.row,
GenericStyles.alignCenter,
]}>
{/*@ts-ignore */}
<CheckboxGroup onSelectionChange={handleFilterSelection}
options={options}
defaultValue={selectedFilters[selectedFilterKey]}
/>
</View>
);
case SELECTION_TYPES.SINGLE :
return (
<View
style={[
styles.filterSelector,
GenericStyles.row,
GenericStyles.alignCenter,
]}>
{/*@ts-ignore */}
<RadioGroup value={selectedFilters[selectedFilterKey]} onSelectionChange={handleFilterSelection} >
{
filters[selectedFilterKey].options.map(option =>(
<RadioButton value={option.label} id={option.value} />
))
}
</RadioGroup>
</View>
)
}
}
return <></>;
}, [selectedFilterKey, selectedFilters, filterSearchString]);
@@ -221,8 +273,8 @@ const FiltersContainer: React.FC<FilterContainerProps> = 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<FilterContainerProps> = props => {
dark>
{filters[key].displayText}
</Text>
{
selectedFilters[key] && (
<View style={[key === selectedFilterKey ? styles.filterCountSelected : styles.filterCount]} >
<Text style={[ key === selectedFilterKey && GenericStyles.whiteText ]} bold dark small >
{
typeof selectedFilters[key] === 'object' ? Object.keys(selectedFilters[key]).length : 1
}
</Text>
</View>
)
}
</TouchableOpacity>
))}
</View>
@@ -262,7 +325,7 @@ const FiltersContainer: React.FC<FilterContainerProps> = props => {
<View style={[GenericStyles.row]}>
<TouchableOpacity
activeOpacity={0.7}
onPress={closeFilterModal}
onPress={onClearAll}
style={[
styles.bottomCTA,
{flex: 1, alignItems: 'center'},
@@ -335,6 +398,22 @@ const styles = StyleSheet.create({
ph7: {
paddingHorizontal: 7,
},
filterCount: {
backgroundColor: COLORS.BACKGROUND.SILVER,
borderColor: COLORS.BORDER.PRIMARY,
borderWidth: 1,
height: PixelRatio.roundToNearestPixel(25),
width: PixelRatio.roundToNearestPixel(25),
borderRadius: 20,
alignItems: 'center',
},
filterCountSelected: {
backgroundColor: COLORS.TEXT.BLUE,
height: PixelRatio.roundToNearestPixel(25),
width: PixelRatio.roundToNearestPixel(25),
borderRadius: 20,
alignItems: 'center',
}
});
export default FiltersContainer;

View File

@@ -1,7 +1,10 @@
export const objectParser: (obj: Record<string, any> , keysArray: Array<string>) => any = (obj , keysArray) => {
export const getObjectValueFromKeys: (obj: Record<string, any> , keysArray: Array<string>) => 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;

View File

@@ -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<string, IFilter>;
selectedFilters: Record<string, any>
}
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;

View File

@@ -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<ICaseItem>;
@@ -23,22 +25,37 @@ const CaseItem: React.FC<ICaseItemProps> = ({
handleSearchChange,
}) => {
const {FILTER, CASES_HEADER, TODO_HEADER} = CaseTypes;
const [showFilterModal, setShowFilterModal] =
React.useState<boolean>(false);
switch (caseData.type) {
case FILTER:
return (
<View
style={[
GenericStyles.ph16,
styles.pv12,
GenericStyles.whiteBackground,
]}>
<TextInput
LeftComponent={<SearchIcon />}
onChangeText={handleSearchChange}
placeholder="Search by name, address"
/>
</View>
<>
<View
style={[
GenericStyles.ph16,
styles.pv12,
GenericStyles.whiteBackground,
GenericStyles.centerAlignedRow,
]}>
<TextInput
style={[{flexBasis: '75%'}]}
LeftComponent={<SearchIcon />}
onChangeText={handleSearchChange}
placeholder="Search by name, address"
/>
<TouchableOpacity
style={[{flexBasis: '20%', alignItems: 'center'}]}
activeOpacity={0.7}
onPress={() => setShowFilterModal(prev => !prev)}>
<FilterIcon />
</TouchableOpacity>
</View>
<Modal animationType="slide" animated onRequestClose={()=>setShowFilterModal((prev => !prev))} visible={showFilterModal} >
<FiltersContainer closeFilterModal={()=>setShowFilterModal((prev => !prev))} />
</Modal>
</>
);
case CASES_HEADER:
return (

View File

@@ -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[],
}

View File

@@ -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<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
export type AppDispatch = typeof store.dispatch;