change(ui) - search live vs recorded

This commit is contained in:
Shekar Siri 2023-03-31 14:36:44 +02:00
parent c38dd87f3f
commit 70c63f7b07
3 changed files with 129 additions and 95 deletions

View file

@ -18,7 +18,7 @@ function AssistSearchField(props: Props) {
return (
<div className="flex items-center w-full">
<div style={{ width: '60%', marginRight: '10px' }}>
<SessionSearchField fetchFilterSearch={props.fetchFilterSearch} addFilterByKeyAndValue={props.addFilterByKeyAndValue} />
<SessionSearchField />
</div>
<Button
variant="text-primary"

View file

@ -6,10 +6,7 @@ import stl from './FilterModal.module.css';
import { filtersMap } from 'Types/filter/newFilter';
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
function filterJson(
jsonObj: Record<string, any>,
excludeKeys: string[] = []
): Record<string, any> {
function filterJson(jsonObj: Record<string, any>, excludeKeys: string[] = []): Record<string, any> {
let filtered: Record<string, any> = {};
for (const key in jsonObj) {
@ -26,37 +23,39 @@ export const getMatchingEntries = (searchQuery: string, filters: Record<string,
const matchingCategories: string[] = [];
const matchingFilters: Record<string, any> = {};
const lowerCaseQuery = searchQuery.toLowerCase();
if (lowerCaseQuery.length === 0) return {
matchingCategories: Object.keys(filters),
matchingFilters: filters,
};
Object.keys(filters).forEach(name => {
if (lowerCaseQuery.length === 0)
return {
matchingCategories: Object.keys(filters),
matchingFilters: filters,
};
Object.keys(filters).forEach((name) => {
if (name.toLocaleLowerCase().includes(lowerCaseQuery)) {
matchingCategories.push(name);
matchingFilters[name] = filters[name];
} else {
const filtersQuery = filters[name]
.filter((filterOption: any) => filterOption.label.toLocaleLowerCase().includes(lowerCaseQuery))
const filtersQuery = filters[name].filter((filterOption: any) =>
filterOption.label.toLocaleLowerCase().includes(lowerCaseQuery)
);
if (filtersQuery.length > 0) matchingFilters[name] = filtersQuery
filtersQuery.length > 0 && matchingCategories.push(name);
}
})
if (filtersQuery.length > 0) matchingFilters[name] = filtersQuery;
filtersQuery.length > 0 && matchingCategories.push(name);
}
});
return { matchingCategories, matchingFilters };
}
};
interface Props {
filters: any,
onFilterClick?: (filter: any) => void,
filterSearchList: any,
filters: any;
onFilterClick?: (filter: any) => void;
filterSearchList: any;
// metaOptions: any,
isMainSearch?: boolean,
fetchingFilterSearchList: boolean,
searchQuery?: string,
excludeFilterKeys?: Array<string>
isMainSearch?: boolean;
fetchingFilterSearchList: boolean;
searchQuery?: string;
excludeFilterKeys?: Array<string>;
}
function FilterModal(props: Props) {
const {
@ -66,7 +65,7 @@ function FilterModal(props: Props) {
isMainSearch = false,
fetchingFilterSearchList,
searchQuery = '',
excludeFilterKeys = []
excludeFilterKeys = [],
} = props;
const showSearchList = isMainSearch && searchQuery.length > 0;
@ -74,34 +73,51 @@ function FilterModal(props: Props) {
const _filter = filtersMap[filter.type];
_filter.value = [filter.value];
onFilterClick(_filter);
}
};
const { matchingCategories, matchingFilters } = getMatchingEntries(searchQuery, filterJson(filters, excludeFilterKeys));
const { matchingCategories, matchingFilters } = getMatchingEntries(
searchQuery,
filterJson(filters, excludeFilterKeys)
);
const isResultEmpty = (!filterSearchList || Object.keys(filterSearchList).length === 0)
&& matchingCategories.length === 0 && Object.keys(matchingFilters).length === 0
const isResultEmpty =
(!filterSearchList || Object.keys(filterSearchList).length === 0) &&
matchingCategories.length === 0 &&
Object.keys(matchingFilters).length === 0;
return (
<div className={stl.wrapper} style={{ width: '480px', maxHeight: '380px', overflowY: 'auto'}}>
<div className={searchQuery && !isResultEmpty ? 'mb-6' : ''} style={{ columns: matchingCategories.length > 1 ? 'auto 200px' : 1 }}>
{matchingCategories.map((key) => {
return (
<div className="mb-6 flex flex-col gap-2" key={key}>
<div className="uppercase font-medium mb-1 color-gray-medium tracking-widest text-sm">{key}</div>
<div>
{matchingFilters[key] && matchingFilters[key].map((filter: any) => (
<div key={filter.label} className={cn(stl.optionItem, "flex items-center py-2 cursor-pointer -mx-2 px-2")} onClick={() => onFilterClick({ ...filter, value: [''] })}>
<Icon name={filter.icon} size="16"/>
<span className="ml-2">{filter.label}</span>
</div>
)
)}
</div>
<div className={stl.wrapper} style={{ width: '480px', maxHeight: '380px', overflowY: 'auto' }}>
<div
className={searchQuery && !isResultEmpty ? 'mb-6' : ''}
style={{ columns: matchingCategories.length > 1 ? 'auto 200px' : 1 }}
>
{matchingCategories.map((key) => {
return (
<div className="mb-6 flex flex-col gap-2" key={key}>
<div className="uppercase font-medium mb-1 color-gray-medium tracking-widest text-sm">
{key}
</div>
)}
)}
</div>
{ showSearchList && (
<div>
{matchingFilters[key] &&
matchingFilters[key].map((filter: any) => (
<div
key={filter.label}
className={cn(
stl.optionItem,
'flex items-center py-2 cursor-pointer -mx-2 px-2'
)}
onClick={() => onFilterClick({ ...filter, value: [''] })}
>
<Icon name={filter.icon} size="16" />
<span className="ml-2">{filter.label}</span>
</div>
))}
</div>
</div>
);
})}
</div>
{showSearchList && (
<Loader size="small" loading={fetchingFilterSearchList}>
<div className="-mx-6 px-6">
{isResultEmpty && !fetchingFilterSearchList ? (
@ -109,30 +125,38 @@ function FilterModal(props: Props) {
<AnimatedSVG name={ICONS.NO_SEARCH_RESULTS} size={180} />
<div className="color-gray-medium font-medium px-3"> No Suggestions Found </div>
</div>
) : Object.keys(filterSearchList).map((key, index) => {
const filter = filterSearchList[key];
const option = filtersMap[key];
return option ? (
<div
key={index}
className={cn('mb-3')}
>
<div className="font-medium uppercase color-gray-medium text-sm mb-2">{option.label}</div>
<div>
{filter.map((f, i) => (
<div
key={i}
className={cn(stl.filterSearchItem, "cursor-pointer px-3 py-1 text-sm flex items-center")}
onClick={() => onFilterSearchClick({ type: key, value: f.value })}
>
<Icon className="mr-2" name={option.icon} size="16" />
<div className="whitespace-nowrap text-ellipsis overflow-hidden">{f.value}</div>
</div>
))}
) : (
Object.keys(filterSearchList).map((key, index) => {
const filter = filterSearchList[key];
const option = filtersMap[key];
return option ? (
<div key={index} className={cn('mb-3')}>
<div className="font-medium uppercase color-gray-medium mb-2">
{option.label}
</div>
<div>
{filter.map((f, i) => (
<div
key={i}
className={cn(
stl.filterSearchItem,
'cursor-pointer px-3 py-1 flex items-center'
)}
onClick={() => onFilterSearchClick({ type: key, value: f.value })}
>
<Icon className="mr-2" name={option.icon} size="16" />
<div className="whitespace-nowrap text-ellipsis overflow-hidden">
{f.value}
</div>
</div>
))}
</div>
</div>
</div>
) : <></>;
})}
) : (
<></>
);
})
)}
</div>
</Loader>
)}
@ -141,14 +165,15 @@ function FilterModal(props: Props) {
}
export default connect((state: any, props: any) => {
return ({
filters: props.isLive ? state.getIn([ 'search', 'filterListLive' ]) : state.getIn([ 'search', 'filterList' ]),
filterSearchList: props.isLive ? state.getIn([ 'liveSearch', 'filterSearchList' ]) : state.getIn([ 'search', 'filterSearchList' ]),
// filterSearchList: state.getIn([ 'search', 'filterSearchList' ]),
// liveFilterSearchList: state.getIn([ 'liveSearch', 'filterSearchList' ]),
// metaOptions: state.getIn([ 'customFields', 'list' ]),
return {
filters: props.isLive
? state.getIn(['search', 'filterListLive'])
: state.getIn(['search', 'filterList']),
filterSearchList: props.isLive
? state.getIn(['liveSearch', 'filterSearchList'])
: state.getIn(['search', 'filterSearchList']),
fetchingFilterSearchList: props.isLive
? state.getIn(['liveSearch', 'fetchFilterSearch', 'loading'])
: state.getIn(['search', 'fetchFilterSearch', 'loading']),
})
? state.getIn(['liveSearch', 'fetchFilterSearch', 'loading'])
: state.getIn(['search', 'fetchFilterSearch', 'loading']),
};
})(FilterModal);

View file

@ -5,16 +5,27 @@ import FilterModal from 'Shared/Filters/FilterModal';
import { debounce } from 'App/utils';
import { assist as assistRoute, isRoute } from 'App/routes';
import { addFilterByKeyAndValue, fetchFilterSearch } from 'Duck/search';
import {
addFilterByKeyAndValue as liveAddFilterByKeyAndValue,
fetchFilterSearch as liveFetchFilterSearch,
} from 'Duck/liveSearch';
const ASSIST_ROUTE = assistRoute();
interface Props {
fetchFilterSearch: (query: any) => void;
addFilterByKeyAndValue: (key: string, value: string) => void;
filterSearchListLive: any;
liveAddFilterByKeyAndValue: (key: string, value: string) => void;
filterSearchList: any;
liveFetchFilterSearch: any;
}
function SessionSearchField(props: Props) {
const debounceFetchFilterSearch = React.useCallback(debounce(props.fetchFilterSearch, 1000), []);
const isLive =
isRoute(ASSIST_ROUTE, window.location.pathname) ||
window.location.pathname.includes('multiview');
const debounceFetchFilterSearch = React.useCallback(
debounce(isLive ? props.liveFetchFilterSearch : props.fetchFilterSearch, 1000),
[]
);
const [showModal, setShowModal] = useState(false);
const [searchQuery, setSearchQuery] = useState('');
@ -24,7 +35,9 @@ function SessionSearchField(props: Props) {
};
const onAddFilter = (filter: any) => {
props.addFilterByKeyAndValue(filter.key, filter.value);
isLive
? props.liveAddFilterByKeyAndValue(filter.key, filter.value)
: props.addFilterByKeyAndValue(filter.key, filter.value);
};
return (
@ -47,10 +60,7 @@ function SessionSearchField(props: Props) {
searchQuery={searchQuery}
isMainSearch={true}
onFilterClick={onAddFilter}
isLive={
isRoute(ASSIST_ROUTE, window.location.pathname) ||
window.location.pathname.includes('multiview')
}
isLive={isLive}
/>
</div>
)}
@ -58,10 +68,9 @@ function SessionSearchField(props: Props) {
);
}
export default connect(
(state: any) => ({
filterSearchList: state.getIn(['search', 'filterSearchList']),
filterSearchListLive: state.getIn(['liveSearch', 'filterSearchList']),
}),
{ addFilterByKeyAndValue, fetchFilterSearch }
)(SessionSearchField);
export default connect(null, {
addFilterByKeyAndValue,
fetchFilterSearch,
liveFetchFilterSearch,
liveAddFilterByKeyAndValue,
})(SessionSearchField);