[IMPROVE] Paginated multiselect for EE tags (#22315)

* [IMPROVE] Paginated multiselect for EE tags

* add missing tag interface

* rename ILivechatTag interface

* Add type to endpoint

Co-authored-by: Rafael Ferreira <rafaelblink@gmail.com>
pull/22466/head
Martin Schoeler 4 years ago committed by Martin
parent 68e83b8662
commit 2aa1cfb60a
  1. 9
      client/components/Omnichannel/Tags.js
  2. 2
      client/contexts/ServerContext/endpoints.ts
  3. 13
      client/contexts/ServerContext/endpoints/v1/livechat/tagsList.ts
  4. 2
      client/views/omnichannel/currentChats/FilterByText.js
  5. 7
      definition/ILivechatTag.ts
  6. 10
      definition/ILivechatTagRecord.ts
  7. 58
      ee/client/hooks/useTagsList.ts
  8. 37
      ee/client/omnichannel/tags/CurrentChatTags.js

@ -21,6 +21,7 @@ const Tags = ({ tags = [], handler = () => {}, error = '' }) => {
const dispatchToastMessage = useToastMessageDispatch();
const [tagValue, handleTagValue] = useState('');
const [paginatedTagValue, handlePaginatedTagValue] = useState([]);
const removeTag = (tag) => {
const tagsFiltered = tags.filter((tagArray) => tagArray !== tag);
@ -52,7 +53,13 @@ const Tags = ({ tags = [], handler = () => {}, error = '' }) => {
<Field.Label mb='x4'>{t('Tags')}</Field.Label>
{Tags && tagsList && tagsList.length > 0 ? (
<Field.Row>
<Tags value={tags} handler={handler} />
<Tags
value={paginatedTagValue}
handler={(tags) => {
handler(tags.map((tag) => tag.label));
handlePaginatedTagValue(tags);
}}
/>
</Field.Row>
) : (
<>

@ -15,6 +15,7 @@ import { LivechatDepartment } from './endpoints/v1/livechat/department';
import { LivechatDepartmentsByUnit } from './endpoints/v1/livechat/departmentsByUnit';
import { LivechatMonitorsList } from './endpoints/v1/livechat/monitorsList';
import { LivechatRoomOnHoldEndpoint } from './endpoints/v1/livechat/onHold';
import { LivechatTagsList } from './endpoints/v1/livechat/tagsList';
import { LivechatVisitorInfoEndpoint } from './endpoints/v1/livechat/visitorInfo';
import { AutocompleteAvailableForTeamsEndpoint as RoomsAutocompleteTeamsEndpoint } from './endpoints/v1/rooms/autocompleteAvailableForTeams';
import { AutocompleteChannelAndPrivateEndpoint as RoomsAutocompleteEndpoint } from './endpoints/v1/rooms/autocompleteChannelAndPrivate';
@ -44,6 +45,7 @@ export type ServerEndpoints = {
'livechat/visitors.info': LivechatVisitorInfoEndpoint;
'livechat/room.onHold': LivechatRoomOnHoldEndpoint;
'livechat/monitors.list': LivechatMonitorsList;
'livechat/tags.list': LivechatTagsList;
'livechat/department': LivechatDepartment;
'livechat/departments.by-unit/': LivechatDepartmentsByUnit;
};

@ -0,0 +1,13 @@
import { ILivechatTag } from '../../../../../../definition/ILivechatTag';
import { ObjectFromApi } from '../../../../../../definition/ObjectFromApi';
export type LivechatTagsList = {
GET: (params: {
text: string;
offset: number;
count: number;
}) => {
tags: ObjectFromApi<ILivechatTag>[];
total: number;
};
};

@ -84,7 +84,7 @@ const FilterByText = ({ setFilter, reload, ...props }) => {
...(department?.value && { department: department.value }),
from: from && moment(new Date(from)).utc().format('YYYY-MM-DDTHH:mm:ss'),
to: to && moment(new Date(to)).utc().format('YYYY-MM-DDTHH:mm:ss'),
tags,
tags: tags.map((tag) => tag.label),
customFields: customFields.reduce(reducer, {}),
});
}, [setFilter, guest, servedBy, status, department, from, to, tags, customFields]);

@ -0,0 +1,7 @@
export interface ILivechatTag {
_id: string;
name: string;
description: string;
numDepartments: number;
departments: Array<string>;
}

@ -0,0 +1,10 @@
import { IRocketChatRecord } from './IRocketChatRecord';
export interface ILivechatTagRecord extends IRocketChatRecord {
_id: string;
name: string;
description: string;
numDepartments: number;
departments: Array<string>;
}

@ -0,0 +1,58 @@
import { useCallback, useState } from 'react';
import { useEndpoint } from '../../../client/contexts/ServerContext';
import { useScrollableRecordList } from '../../../client/hooks/lists/useScrollableRecordList';
import { useComponentDidUpdate } from '../../../client/hooks/useComponentDidUpdate';
import { RecordList } from '../../../client/lib/lists/RecordList';
import { ILivechatTagRecord } from '../../../definition/ILivechatTagRecord';
type TagsListOptions = {
filter: string;
};
export const useTagsList = (
options: TagsListOptions,
): {
itemsList: RecordList<ILivechatTagRecord>;
initialItemCount: number;
reload: () => void;
loadMoreItems: (start: number, end: number) => void;
} => {
const [itemsList, setItemsList] = useState(() => new RecordList<ILivechatTagRecord>());
const reload = useCallback(() => setItemsList(new RecordList<ILivechatTagRecord>()), []);
const getTags = useEndpoint('GET', 'livechat/tags.list');
useComponentDidUpdate(() => {
options && reload();
}, [options, reload]);
const fetchData = useCallback(
async (start, end) => {
const { tags, total } = await getTags({
text: options.filter,
offset: start,
count: end + start,
});
return {
items: tags.map((tag: any) => {
tag._updatedAt = new Date(tag._updatedAt);
tag.label = tag.name;
tag.value = { value: tag._id, label: tag.name };
return tag;
}),
itemCount: total,
};
},
[getTags, options.filter],
);
const { loadMoreItems, initialItemCount } = useScrollableRecordList(itemsList, fetchData, 25);
return {
reload,
itemsList,
loadMoreItems,
initialItemCount,
};
};

@ -1,16 +1,35 @@
import { MultiSelect } from '@rocket.chat/fuselage';
import React, { useMemo } from 'react';
import { PaginatedMultiSelectFiltered } from '@rocket.chat/fuselage';
import React, { useMemo, useState } from 'react';
import { useEndpointData } from '../../../../client/hooks/useEndpointData';
import { useRecordList } from '../../../../client/hooks/lists/useRecordList';
import { AsyncStatePhase } from '../../../../client/hooks/useAsyncState';
import { useTagsList } from '../../hooks/useTagsList';
const CurrentChatTags = ({ value, handler, ...props }) => {
const { value: data } = useEndpointData('livechat/tags.list');
const options = useMemo(
() => (data && data.tags ? data.tags.map(({ name }) => [name, name]) : []),
[data],
const CurrentChatTags = ({ value, handler }) => {
const [tagsFilter, setTagsFilter] = useState('');
const { itemsList: tagsList, loadMoreItems: loadMoreTags } = useTagsList(
useMemo(() => ({ filter: tagsFilter }), [tagsFilter]),
);
return <MultiSelect options={options} value={value} onChange={handler} flexGrow={1} {...props} />;
const { phase: tagsPhase, items: tagsItems, itemCount: tagsTotal } = useRecordList(tagsList);
return (
<PaginatedMultiSelectFiltered
maxWidth={'100%'}
flexGrow={1}
filter={tagsFilter}
setFilter={setTagsFilter}
onChange={handler}
options={tagsItems}
value={value}
endReached={
tagsPhase === AsyncStatePhase.LOADING
? () => {}
: (start) => loadMoreTags(start, Math.min(50, tagsTotal))
}
/>
);
};
export default CurrentChatTags;

Loading…
Cancel
Save