From e7d58bd33d669d1f277e4922f9d2e8eb0f2feabb Mon Sep 17 00:00:00 2001 From: Aman Chaturvedi Date: Thu, 28 Sep 2023 17:09:47 +0530 Subject: [PATCH 01/30] TP-31899 | Past feedback filters --- src/assets/icons/FilterIcon.tsx | 7 +- src/components/filters/FilterOptions.tsx | 122 ++++++++++ src/components/filters/Filters.tsx | 209 ++++++++++++++++++ src/reducer/feedbackHistorySlice.ts | 13 +- src/screens/allCases/index.tsx | 59 +++++ .../feedback/FeedbackDetailContainer.tsx | 89 +++++++- 6 files changed, 486 insertions(+), 13 deletions(-) create mode 100644 src/components/filters/FilterOptions.tsx create mode 100644 src/components/filters/Filters.tsx diff --git a/src/assets/icons/FilterIcon.tsx b/src/assets/icons/FilterIcon.tsx index 825c24eb..95b472d0 100644 --- a/src/assets/icons/FilterIcon.tsx +++ b/src/assets/icons/FilterIcon.tsx @@ -1,10 +1,13 @@ import * as React from 'react'; import Svg, { Path } from 'react-native-svg'; -const FilterIcon = () => ( +import { IconProps } from '../../../RN-UI-LIB/src/Icons/types'; +import { COLORS } from '../../../RN-UI-LIB/src/styles/colors'; + +const FilterIcon: React.FC = ({ fillColor = COLORS.BACKGROUND.LIGHT }) => ( ); diff --git a/src/components/filters/FilterOptions.tsx b/src/components/filters/FilterOptions.tsx new file mode 100644 index 00000000..1b633400 --- /dev/null +++ b/src/components/filters/FilterOptions.tsx @@ -0,0 +1,122 @@ +import { View } from 'react-native'; +import React from 'react'; +import { IFilters, TFilterOptions } from './Filters'; +import RadioGroup from '../../../RN-UI-LIB/src/components/radio_button/RadioGroup'; +import RNRadioButton from '../../../RN-UI-LIB/src/components/radio_button/RadioButton'; +import { GenericStyles } from '../../../RN-UI-LIB/src/styles'; +import Checkbox from '../../../RN-UI-LIB/src/components/chechbox/Checkbox'; + +interface IFilterOptions { + filters: IFilters; + selectedFilter: string; + selectedFilterOptions: TFilterOptions; + setSelectedFilterOptions: React.Dispatch>; +} + +enum SelectionType { + SINGLE = 'SINGLE', + MULTIPLE = 'MULTIPLE', +} + +const FilterOptions: React.FC = ({ + filters, + selectedFilter, + selectedFilterOptions, + setSelectedFilterOptions, +}) => { + if (!selectedFilter || !filters?.[selectedFilter]) { + return null; + } + + const handleSingleOptionChange = (value: string) => { + if (selectedFilter) { + const selectedOption = !!selectedFilterOptions?.[selectedFilter]?.filters?.[value]; + const currentSelectedFilterCount = + selectedFilterOptions?.[selectedFilter]?.selectedFilterCount || 0; + if (selectedOption && currentSelectedFilterCount === 1) { + // delete the selected filter if we are unchecking the only selected option + setSelectedFilterOptions((prev) => { + const updatedOptions = { ...prev }; + delete updatedOptions[selectedFilter]; + return updatedOptions; + }); + return; + } + setSelectedFilterOptions({ + ...selectedFilterOptions, + [selectedFilter]: { + filters: { + [value]: !selectedOption, + }, + selectedFilterCount: selectedOption ? 0 : 1, + }, + }); + } + }; + + const handleMultiOptionChange = (isChecked: boolean, values: string) => { + if (selectedFilter) { + const currentFilters = selectedFilterOptions?.[selectedFilter]?.filters || {}; + const currentSelectedFilterCount = + selectedFilterOptions?.[selectedFilter]?.selectedFilterCount || 0; + if (!isChecked && currentSelectedFilterCount === 1) { + // delete the selected filter if we are unchecking the only selected option + setSelectedFilterOptions((prev) => { + const updatedOptions = { ...prev }; + delete updatedOptions[selectedFilter]; + return updatedOptions; + }); + return; + } + setSelectedFilterOptions({ + ...selectedFilterOptions, + [selectedFilter]: { + filters: { + ...currentFilters, + [values]: isChecked, + }, + selectedFilterCount: isChecked + ? currentSelectedFilterCount + 1 + : currentSelectedFilterCount - 1, + }, + }); + } + }; + + const filter = filters[selectedFilter]; + const selectionType = filter.selectionType; + const selectedOptions = selectedFilterOptions[selectedFilter]?.filters || {}; + + if (selectionType === SelectionType.SINGLE) { + const selectedOption = Object.keys(selectedOptions)[0]; + return ( + handleSingleOptionChange(value)} + orientation="vertical" + > + {filter.options.map((option) => ( + + ))} + + ); + } else if (selectionType === SelectionType.MULTIPLE) { + return ( + <> + {filter.options.map((option) => ( + + handleMultiOptionChange(value, option.value)} + /> + + ))} + + ); + } + + return null; +}; + +export default FilterOptions; diff --git a/src/components/filters/Filters.tsx b/src/components/filters/Filters.tsx new file mode 100644 index 00000000..37acca82 --- /dev/null +++ b/src/components/filters/Filters.tsx @@ -0,0 +1,209 @@ +import React, { useEffect, useState } from 'react'; +import { View, ScrollView, StyleSheet, PixelRatio } from 'react-native'; +import { GenericStyles } from '../../../RN-UI-LIB/src/styles'; +import Text from '../../../RN-UI-LIB/src/components/Text'; +import Button from '../../../RN-UI-LIB/src/components/Button'; +import { COLORS } from '../../../RN-UI-LIB/src/styles/colors'; +import { _map } from '../../../RN-UI-LIB/src/utlis/common'; +import FilterOptions from './FilterOptions'; +import NavigationHeader from '../../../RN-UI-LIB/src/components/NavigationHeader'; + +interface FilterOption { + value: string; + label: string; +} + +interface FilterData { + operator: string; + filterType: string; + visible: null | string; + selectionType: string; + displayText: string; + options: FilterOption[]; + name: string; +} + +export interface IFilters { + [key: string]: FilterData; +} + +interface IFilterOptions { + filters: Record; + selectedFilterCount: number; +} + +export type TFilterOptions = Record; + +const Filters: React.FC<{ + header: string; + filters: IFilters; + defaultSelectedFilters: TFilterOptions; + closeFilterModal: () => void; + onFilterChange: (selectedFilters: TFilterOptions) => void; +}> = ({ header, filters, defaultSelectedFilters, closeFilterModal, onFilterChange }) => { + // Default select first filter + const [selectedFilter, setSelectedFilter] = useState(Object.keys(filters)[0]); + const [selectedFilterOptions, setSelectedFilterOptions] = + useState(defaultSelectedFilters); + + useEffect(() => { + if (defaultSelectedFilters) { + setSelectedFilterOptions(defaultSelectedFilters); + } + }, [defaultSelectedFilters]); + + const handleFilterChange = (filterName: string) => { + setSelectedFilter(filterName); + + // Initialize selected options for the filter if not already set + if (!selectedFilterOptions[filterName]) { + setSelectedFilterOptions({ + ...selectedFilterOptions, + [filterName]: { + filters: {}, + selectedFilterCount: 0, + }, + }); + } + }; + + const handleSubmit = () => { + onFilterChange(selectedFilterOptions); + closeFilterModal(); + }; + + const handleClearAll = () => { + setSelectedFilterOptions({}); + }; + + return ( + + + + + {/* @ts-expect-error */} + {_map(filters, (filterKey) => { + const filter = filters[filterKey]; + const filterName = filter.name; + + return ( + + handleFilterChange(filterName)} + style={[ + GenericStyles.fill, + { + color: selectedFilter === filterName ? COLORS.TEXT.BLUE : COLORS.TEXT.BLACK, + }, + ]} + > + {filter.displayText} + + {selectedFilterOptions[filterName]?.selectedFilterCount ? ( + + + {selectedFilterOptions[filterName]?.selectedFilterCount} + + + ) : ( + + )} + + ); + })} + + + + + + +