From 870e6f4497f9b62e52b89eca709e71e96112a554 Mon Sep 17 00:00:00 2001 From: Shri Prakash Bajpai Date: Tue, 23 Apr 2024 18:50:02 +0530 Subject: [PATCH] TP-55185 Revamp UI for CSA (#943) * TP-55185 Revamp CSA changes done * TP-55185 Revamp CSA type fixes done * TP-55185 fixes done * TP-55185 PR fixes * TP-55185 fixes * TP-55185 CSA changes * TP-55185 Fixes done --- __mocks__/auth/user.json | 1 + .../FilterDrawer/FilterRenderingEngine.tsx | 30 +++++ src/components/FilterDrawer/LeftPanel.tsx | 2 + src/components/FilterDrawer/RightPanel.tsx | 43 ++++--- .../FilterDrawer/SectionedOptions.tsx | 61 ++++++++++ .../FilterDrawer/SelectedFilters.tsx | 16 ++- .../components/DateTimePickerFilter.tsx | 41 +++++++ src/components/FilterDrawer/constants.ts | 42 +++++++ src/components/FilterDrawer/index.module.scss | 12 ++ src/components/FilterDrawer/index.tsx | 42 ++++++- src/components/FilterDrawer/types.ts | 27 +++++ src/components/FilterDrawer/utils.ts | 48 +++++++- src/components/TableFilters/TableFilters.tsx | 10 +- src/pages/Cases/CasesActions.tsx | 3 +- .../Cases/components/CaseTableColumnCSA.tsx | 109 ++++++++++++++++++ src/pages/Cases/components/Cases.module.scss | 24 ++++ src/pages/Cases/components/Cases.tsx | 53 +++++++-- .../Cases/components/CustomTagWithTime.tsx | 21 ++++ src/pages/Cases/constants/CasesConstants.ts | 11 +- src/pages/Cases/constants/CasesInterfaces.tsx | 10 +- src/pages/Cases/reducers/CasesSlice.ts | 45 +++++++- 21 files changed, 608 insertions(+), 43 deletions(-) create mode 100644 src/components/FilterDrawer/FilterRenderingEngine.tsx create mode 100644 src/components/FilterDrawer/SectionedOptions.tsx create mode 100644 src/components/FilterDrawer/components/DateTimePickerFilter.tsx create mode 100644 src/components/FilterDrawer/constants.ts create mode 100644 src/pages/Cases/components/CaseTableColumnCSA.tsx create mode 100644 src/pages/Cases/components/CustomTagWithTime.tsx diff --git a/__mocks__/auth/user.json b/__mocks__/auth/user.json index bd29aac1..951a0465 100644 --- a/__mocks__/auth/user.json +++ b/__mocks__/auth/user.json @@ -28,6 +28,7 @@ "overallPerformanceAgencyManagerPerformanceTable": true, "overallPerformanceAgencyPerformanceTable": true, "fcmDashboard": true, + "csaUiRevampEnabled": true "teleGovernancePerformanceDashboard": true, "teleGovernanceAgencyPerformanceTable": true, "teleGovernanceAgentPerformanceTable": true, diff --git a/src/components/FilterDrawer/FilterRenderingEngine.tsx b/src/components/FilterDrawer/FilterRenderingEngine.tsx new file mode 100644 index 00000000..0ea65837 --- /dev/null +++ b/src/components/FilterDrawer/FilterRenderingEngine.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import DateTimePickerFilter from './components/DateTimePickerFilter'; +import { IFilterDrawerSchema, ISelectedOptions } from './types'; +import { FilterType } from './constants'; + +const ComponentMap = { + [FilterType.DATE_TIME_PICKER]: DateTimePickerFilter +}; + +interface IQuestionRenderingEngine { + filterType: string; + filterKey: string; + filterSchema: Record; + selectedOptions: ISelectedOptions; + setSelectedOptions: (selectedOptions: ISelectedOptions) => void; +} + +const FilterRenderingEngine: React.FC = props => { + const Comp = ComponentMap[props.filterType as FilterType]; + if (!Comp) { + return null; + } + return ( +
+ +
+ ); +}; + +export default FilterRenderingEngine; diff --git a/src/components/FilterDrawer/LeftPanel.tsx b/src/components/FilterDrawer/LeftPanel.tsx index c6dbeecc..61d89a33 100644 --- a/src/components/FilterDrawer/LeftPanel.tsx +++ b/src/components/FilterDrawer/LeftPanel.tsx @@ -2,6 +2,7 @@ import styles from './index.module.scss'; import cx from 'classnames'; import { Typography } from '@navi/web-ui/lib/primitives'; import { ILeftPanel } from './types'; +import { DATE_QUERY_PARAMS, FilterKeys } from './constants'; const LeftPanel = (props: ILeftPanel) => { const { filterSchemaMap, filterSchema, selectedFilter, selectedOptions, handleFilterChange } = @@ -10,6 +11,7 @@ const LeftPanel = (props: ILeftPanel) => { return (
{filterSchemaMap?.map(filterKey => { + if (DATE_QUERY_PARAMS.includes(filterKey as FilterKeys)) return null; const { label } = filterSchema?.[filterKey] || {}; return (
{ const { filterSchema, selectedFilter, selectedOptions, setSelectedOptions, tableName } = props; @@ -75,21 +76,33 @@ const RightPanel = (props: IRightPanel) => { />
)} -
- {filteredOptionsData?.map(option => ( -
- handleCheckboxChange(e, option)} - title={option.label as string} - defaultChecked={isOptionChecked( - option?.value as string, - selectedOptions, - selectedFilter - )} - /> -
- ))} -
+ {filteredOptionsData?.length && filteredOptionsData[0]?.filterSectionLabel ? ( + + ) : ( +
+ {filteredOptionsData?.map(option => ( +
+ handleCheckboxChange(e, option)} + title={option.label as string} + defaultChecked={isOptionChecked( + option?.value as string, + selectedOptions, + selectedFilter + )} + /> +
+ ))} +
+ )}
); }; diff --git a/src/components/FilterDrawer/SectionedOptions.tsx b/src/components/FilterDrawer/SectionedOptions.tsx new file mode 100644 index 00000000..8ff1315d --- /dev/null +++ b/src/components/FilterDrawer/SectionedOptions.tsx @@ -0,0 +1,61 @@ +import { getFilterKey, isOptionChecked } from './utils'; +import { Checkbox, Typography } from '@navi/web-ui/lib/primitives'; +import styles from './index.module.scss'; +import cx from 'classnames'; +import { ISectionedOptionValues } from './types'; +import FilterRenderingEngine from './FilterRenderingEngine'; +import { FILTERS_WITH_SUBFILTERS, subFilterMapping } from './constants'; + +const SectionedOptions = (props: ISectionedOptionValues) => { + const { + filteredOptionsData, + filterSchema, + selectedOptions, + selectedFilter, + handleCheckboxChange, + setSelectedOptions, + isSearchEnabled + } = props; + + return ( +
+ {filteredOptionsData.map(option => { + const { filterSectionLabel, filterSectionValue } = option; + return ( +
+ + {filterSectionLabel} + + {filterSectionValue.map(option => { + const isChecked = isOptionChecked( + option?.value as string, + selectedOptions, + selectedFilter + ); + return ( +
+ handleCheckboxChange(e, option)} + title={option.label as string} + defaultChecked={isChecked} + /> + {isChecked && FILTERS_WITH_SUBFILTERS.includes(option?.value) ? ( + + ) : null} +
+ ); + })} +
+ ); + })} +
+ ); +}; + +export default SectionedOptions; diff --git a/src/components/FilterDrawer/SelectedFilters.tsx b/src/components/FilterDrawer/SelectedFilters.tsx index e28a15ca..0976b530 100644 --- a/src/components/FilterDrawer/SelectedFilters.tsx +++ b/src/components/FilterDrawer/SelectedFilters.tsx @@ -10,11 +10,19 @@ import { import { getTableQueryParams } from '@cp/src/utils/QueryParamsHelper'; import { Button, Typography } from '@navi/web-ui/lib/primitives'; import { ISelectedFilters } from './types'; +import { DATE_QUERY_PARAMS, DEFAULT_QUERY_PARAM_TABLE_IDENTIFIER, FilterKeys } from './constants'; +import { getOptionsAndLabels } from './utils'; const SelectedFilters = (props: ISelectedFilters) => { - const { filterSchemaMap, filterSchema, handleFilterChange, clearAllFilters } = props; + const { + filterSchemaMap, + filterSchema, + handleFilterChange, + clearAllFilters, + queryParamTableIdentifier = DEFAULT_QUERY_PARAM_TABLE_IDENTIFIER + } = props; const CLEAR_ALL_FILTERS_COUNT = 1; - const queryParams = getTableQueryParams(filterSchema, 'filters'); + const queryParams = getTableQueryParams(filterSchema, queryParamTableIdentifier); const handleCancelIconClick = (filterKey: string) => { handleFilterChange(filterKey); @@ -23,7 +31,9 @@ const SelectedFilters = (props: ISelectedFilters) => { const renderSelectedFilters = useMemo(() => { let activeFiltersCount = 0; const selectedFilters = filterSchemaMap.map((filterKey: string) => { - const { options, label } = filterSchema[filterKey] || {}; + if (DATE_QUERY_PARAMS.includes(filterKey as FilterKeys)) return null; + //Checking if the option is of type sectioned filter option + const { options, label } = getOptionsAndLabels(filterSchema, filterKey); const activeFilters = queryParams?.[filterKey]; const isActiveFilterArray = Array.isArray(activeFilters); const selectedOptions = isActiveFilterArray diff --git a/src/components/FilterDrawer/components/DateTimePickerFilter.tsx b/src/components/FilterDrawer/components/DateTimePickerFilter.tsx new file mode 100644 index 00000000..dfaba3d8 --- /dev/null +++ b/src/components/FilterDrawer/components/DateTimePickerFilter.tsx @@ -0,0 +1,41 @@ +import { useCallback } from 'react'; +import DateTimePickerComponent from '../../DateTimePicker/DateTimePickerComponent'; +import { DATE_TIME_TYPE } from '../../DateTimePicker/constants'; +import { getCurrentDate, handleOptionChange } from '../utils'; +import { getTodayDate } from '@cp/src/pages/CaseDetails/constants/communicationHistory.constant'; +import { IDateTimePickerFilterProps } from '../types'; +import styles from '../index.module.scss'; +import { FiltersWithSubfiltersMapping } from '../constants'; + +const DateTimePickerFilter = (props: IDateTimePickerFilterProps) => { + const { filterKey, filterSchema, selectedOptions, setSelectedOptions } = props; + + const defaultDate = getCurrentDate(); + let date: string[] = selectedOptions?.[filterKey]; + if (!date.length) date = defaultDate; + + const handleDateChange = useCallback( + (e: React.ChangeEvent) => { + handleOptionChange( + e, + { label: FiltersWithSubfiltersMapping.PROMISE_TO_PAY, value: e.target.value }, + filterKey, + selectedOptions, + filterSchema, + setSelectedOptions + ); + }, + [filterKey, filterSchema, selectedOptions, setSelectedOptions] + ); + + return ( + + ); +}; + +export default DateTimePickerFilter; diff --git a/src/components/FilterDrawer/constants.ts b/src/components/FilterDrawer/constants.ts new file mode 100644 index 00000000..72f55020 --- /dev/null +++ b/src/components/FilterDrawer/constants.ts @@ -0,0 +1,42 @@ +export const DEFAULT_QUERY_PARAM_TABLE_IDENTIFIER = 'filters'; + +export enum FiltersWithSubfiltersMapping { + PROMISE_TO_PAY = 'PROMISE_TO_PAY', + REQUESTED_CALLBACK = 'REQUESTED_CALLBACK' +} + +export enum FilterKeys { + PROMISE_TO_PAY_TELE_CSA = 'promiseToPayDateTeleCsa', + REQUESTED_CALLBACK_TELE_CSA = 'requestedCallbackDateTeleCsa', + PROMISE_TO_PAY_FIELD_AGENT = 'promiseToPayDateFieldAgent', + TELE_INTERACTION_STATUSES = 'teleInteractionStatuses' +} + +export enum FilterType { + DATE_TIME_PICKER = 'DateTimePickerFilter' +} + +export const FILTERS_WITH_SUBFILTERS = [ + FiltersWithSubfiltersMapping.PROMISE_TO_PAY, + FiltersWithSubfiltersMapping.REQUESTED_CALLBACK +]; + +export const subFilterMapping = new Map([ + [FiltersWithSubfiltersMapping.PROMISE_TO_PAY, FilterType.DATE_TIME_PICKER], + [FiltersWithSubfiltersMapping.REQUESTED_CALLBACK, FilterType.DATE_TIME_PICKER] +]); + +export const TeleInteractionStatusesFilterKey = new Map([ + [FiltersWithSubfiltersMapping.PROMISE_TO_PAY, FilterKeys.PROMISE_TO_PAY_TELE_CSA], + [FiltersWithSubfiltersMapping.REQUESTED_CALLBACK, FilterKeys.REQUESTED_CALLBACK_TELE_CSA] +]); + +export const FieldInteractionStatusesFilterKey = new Map([ + [FiltersWithSubfiltersMapping.PROMISE_TO_PAY, FilterKeys.PROMISE_TO_PAY_FIELD_AGENT] +]); + +export const DATE_QUERY_PARAMS = [ + FilterKeys.PROMISE_TO_PAY_TELE_CSA, + FilterKeys.REQUESTED_CALLBACK_TELE_CSA, + FilterKeys.PROMISE_TO_PAY_FIELD_AGENT +]; diff --git a/src/components/FilterDrawer/index.module.scss b/src/components/FilterDrawer/index.module.scss index 7892e108..35fb02b4 100644 --- a/src/components/FilterDrawer/index.module.scss +++ b/src/components/FilterDrawer/index.module.scss @@ -131,3 +131,15 @@ } } } + +.filterSectionLabel { + font-weight: 500; + color: var(--blue-cyan); + background-color: var(--bg-secondary); + padding: 12px 16px; + margin-bottom: 16; +} + +.datePicker { + margin-top: 12px; +} diff --git a/src/components/FilterDrawer/index.tsx b/src/components/FilterDrawer/index.tsx index ff2554d4..96c69e85 100644 --- a/src/components/FilterDrawer/index.tsx +++ b/src/components/FilterDrawer/index.tsx @@ -21,6 +21,8 @@ import LeftPanel from './LeftPanel'; import RightPanel from './RightPanel'; import SelectedFilters from './SelectedFilters'; import { IFilterDrawer } from './types'; +import { FilterKeys, FiltersWithSubfiltersMapping } from './constants'; +import { DEFAULT_QUERY_PARAM_TABLE_IDENTIFIER } from './constants'; const FilterDrawer = (props: IFilterDrawer) => { const { @@ -31,14 +33,20 @@ const FilterDrawer = (props: IFilterDrawer) => { rightContainerClass, selectedFiltersClass, onApply, - tableName + tableName, + queryParamTableIdentifier = DEFAULT_QUERY_PARAM_TABLE_IDENTIFIER, + filterKeys } = props; const mainParams = readQueryParams(); - const queryParams = getTableQueryParams(filterSchema, 'filters'); + const queryParams = getTableQueryParams(filterSchema, queryParamTableIdentifier); const navigate = useNavigate(); - const filterSchemaMap = useMemo(() => Object.keys(filterSchema), [filterSchema]); + const filterSchemaMap = useMemo(() => { + const keys = Object.keys(filterSchema); + filterKeys && keys.push(...filterKeys); //Adding keys for subfilters + return keys; + }, [filterSchema, filterKeys]); const [showFilterDrawer, setShowFilterDrawer] = useState(false); const [selectedFilter, setSelectedFilter] = useState(''); @@ -68,10 +76,35 @@ const FilterDrawer = (props: IFilterDrawer) => { setSelectedFilter(filterKey); }; + const handleDateChangesInParams = (selectedFilters: Record) => { + if ( + !selectedFilters?.teleInteractionStatuses?.includes( + FiltersWithSubfiltersMapping.PROMISE_TO_PAY + ) + ) { + selectedFilters.promiseToPayDateTeleCsa = []; + } + if ( + !selectedFilters?.teleInteractionStatuses?.includes( + FiltersWithSubfiltersMapping.REQUESTED_CALLBACK + ) + ) { + selectedFilters.requestedCallbackDateTeleCsa = []; + } + if ( + !selectedFilters?.fieldInteractionStatuses?.includes( + FiltersWithSubfiltersMapping.PROMISE_TO_PAY + ) + ) { + selectedFilters.promiseToPayDateFieldAgent = []; + } + }; + const applyFilterChangeHandler = (selectedFilters: Record) => { + handleDateChangesInParams(selectedFilters); const url = createQueryParams({ ...mainParams, - filters: { + [queryParamTableIdentifier]: { ...selectedFilters } }); @@ -145,6 +178,7 @@ const FilterDrawer = (props: IFilterDrawer) => { filterSchema={filterSchema} handleFilterChange={clearFilterWithFilterKey} clearAllFilters={filterCtaHandler} + queryParamTableIdentifier={queryParamTableIdentifier} />