-
Notifications
You must be signed in to change notification settings - Fork 11.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3aca1b0
commit 2cfbafb
Showing
5 changed files
with
293 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
import React, { useEffect, useMemo } from 'react'; | ||
import { TextInput, Box, Icon, MultiSelect, Select, InputBox, Menu } from '@rocket.chat/fuselage'; | ||
import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; | ||
import moment from 'moment'; | ||
|
||
import Page from '../../components/basic/Page'; | ||
import { useTranslation } from '../../contexts/TranslationContext'; | ||
import { useEndpointDataExperimental } from '../../hooks/useEndpointDataExperimental'; | ||
import { usePermission } from '../../contexts/AuthorizationContext'; | ||
import { GenericTable } from '../../components/GenericTable'; | ||
import { useForm } from '../../hooks/useForm'; | ||
import { useMethod } from '../../contexts/ServerContext'; | ||
|
||
|
||
// moment(new Date(from)).utc().format('YYYY-MM-DDTHH:mm:ss') | ||
// guest: '', servedBy: '', status: '', department: '', from: '', to: '' | ||
const Label = (props) => <Box fontScale='p2' color='default' {...props} />; | ||
|
||
const RemoveAllClosed = ({ handleClearFilters, handleRemoveClosed, ...props }) => { | ||
const t = useTranslation(); | ||
const canRemove = usePermission('remove-closed-livechat-rooms'); | ||
|
||
const menuOptions = { | ||
clearFilters: { | ||
label: <Box> | ||
<Icon name='refresh' size='x16' marginInlineEnd='x4' />{t('Clear_filters')} | ||
</Box>, | ||
action: handleClearFilters, | ||
}, | ||
...canRemove && { | ||
removeClosed: { | ||
label: <Box color='danger'> | ||
<Icon name='trash' size='x16' marginInlineEnd='x4' />{t('Remove')} | ||
</Box>, | ||
action: handleRemoveClosed, | ||
}, | ||
}, | ||
}; | ||
return <Menu options={menuOptions} {...props}/>; | ||
}; | ||
|
||
|
||
const FilterByText = ({ setFilter, reload, ...props }) => { | ||
const t = useTranslation(); | ||
|
||
const { data: departments } = useEndpointDataExperimental('livechat/department') || {}; | ||
const { data: agents } = useEndpointDataExperimental('livechat/users/agent'); | ||
|
||
const depOptions = useMemo(() => (departments && departments.departments ? departments.departments.map(({ _id, name }) => [_id, name || _id]) : []), [departments]); | ||
const agentOptions = useMemo(() => (agents && agents.users ? agents.users.map(({ _id, username }) => [_id, username || _id]) : []), [agents]); | ||
const statusOptions = [['all', t('All')], ['closed', t('Closed')], ['opened', t('Open')]]; | ||
|
||
const { values, handlers, reset } = useForm({ guest: '', servedBy: [], status: 'all', department: undefined, from: '', to: '' }); | ||
const { | ||
handleGuest, | ||
handleServedBy, | ||
handleStatus, | ||
handleDepartment, | ||
handleFrom, | ||
handleTo, | ||
} = handlers; | ||
const { | ||
guest, | ||
servedBy, | ||
status, | ||
department, | ||
from, | ||
to, | ||
} = values; | ||
|
||
const onSubmit = useMutableCallback((e) => e.preventDefault()); | ||
|
||
useEffect(() => { | ||
setFilter({ | ||
guest, | ||
servedBy, | ||
status, | ||
department, | ||
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'), | ||
}); | ||
console.log(servedBy); | ||
}, [setFilter, guest, servedBy, status, department, from, to]); | ||
|
||
const handleClearFilters = useMutableCallback(() => { | ||
reset(); | ||
}); | ||
|
||
const removeClosedChats = useMethod('livechat:removeAllClosedRooms'); | ||
|
||
const handleRemoveClosed = useMutableCallback(async () => { | ||
await removeClosedChats(); | ||
console.log(props); | ||
reload(); | ||
}); | ||
|
||
return <Box mb='x16' is='form' onSubmit={onSubmit} display='flex' flexDirection='row' {...props}> | ||
<Box display='flex' mie='x8' flexGrow={1} flexDirection='column'> | ||
<Label mb='x4' >{t('Guest')}:</Label> | ||
<TextInput flexShrink={0} placeholder={t('Guest')} onChange={handleGuest} value={guest} /> | ||
</Box> | ||
<Box display='flex' mie='x8' flexGrow={1} flexDirection='column'> | ||
<Label mb='x4'>{t('Served_By')}:</Label> | ||
<MultiSelect flexShrink={0} options={agentOptions} value={servedBy} onChange={handleServedBy} placeholder={t('Served_By')}/> | ||
</Box> | ||
<Box display='flex' mie='x8' flexGrow={1} flexDirection='column'> | ||
<Label mb='x4'>{t('Department')}:</Label> | ||
<Select flexShrink={0} options={depOptions} value={department} onChange={handleDepartment} placeholder={t('Department')}/> | ||
</Box> | ||
<Box display='flex' mie='x8' flexGrow={1} flexDirection='column'> | ||
<Label mb='x4'>{t('Status')}:</Label> | ||
<Select flexShrink={0} options={statusOptions} value={status} onChange={handleStatus} placeholder={t('Status')}/> | ||
</Box> | ||
<Box display='flex' mie='x8' flexGrow={1} flexDirection='column'> | ||
<Label mb='x4'>{t('From')}:</Label> | ||
<InputBox type='date' flexShrink={0} placeholder={t('From')} onChange={handleFrom} value={from} /> | ||
</Box> | ||
<Box display='flex' mie='x8' flexGrow={1} flexDirection='column'> | ||
<Label mb='x4'>{t('To')}:</Label> | ||
<InputBox type='date' flexShrink={0} placeholder={t('To')} onChange={handleTo} value={to} /> | ||
</Box> | ||
<RemoveAllClosed handleClearFilters={handleClearFilters} handleRemoveClosed={handleRemoveClosed}/> | ||
</Box>; | ||
}; | ||
|
||
|
||
function CurrentChatsPage({ | ||
data, | ||
header, | ||
setParams, | ||
params, | ||
title, | ||
renderRow, | ||
departments, | ||
reload, | ||
children, | ||
}) { | ||
return <Page flexDirection='row'> | ||
<Page> | ||
<Page.Header title={title} /> | ||
<Page.Content> | ||
<GenericTable FilterComponent={FilterByText} header={header} renderRow={renderRow} results={data && data.rooms} departments={departments} total={data && data.total} setParams={setParams} params={params} reload={reload}/> | ||
</Page.Content> | ||
</Page> | ||
{children} | ||
</Page>; | ||
} | ||
|
||
export default CurrentChatsPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
|
||
|
||
import { useDebouncedValue, useMutableCallback } from '@rocket.chat/fuselage-hooks'; | ||
import React, { useMemo, useCallback, useState, useEffect } from 'react'; | ||
import { Table, Icon } from '@rocket.chat/fuselage'; | ||
import moment from 'moment'; | ||
import { FlowRouter } from 'meteor/kadira:flow-router'; | ||
|
||
|
||
import { Th } from '../../components/GenericTable'; | ||
import { useTranslation } from '../../contexts/TranslationContext'; | ||
import { useEndpointDataExperimental } from '../../hooks/useEndpointDataExperimental'; | ||
import { useMethod } from '../../contexts/ServerContext'; | ||
import { usePermission } from '../../contexts/AuthorizationContext'; | ||
import NotAuthorizedPage from '../../components/NotAuthorizedPage'; | ||
import { useRouteParameter, useRoute } from '../../contexts/RouterContext'; | ||
import { useForm } from '../../hooks/useForm'; | ||
import CurrentChatsPage from './CurrentChatsPage'; | ||
|
||
export function RemoveCurrentChatButton({ _id, reload }) { | ||
const removeCurrentChat = useMethod('livechat:removeCurrentChat'); | ||
const currentChatsRoute = useRoute('omnichannel-currentChats'); | ||
|
||
|
||
const handleRemoveClick = useMutableCallback(async (e) => { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
try { | ||
await removeCurrentChat(_id); | ||
} catch (error) { | ||
console.log(error); | ||
} | ||
currentChatsRoute.push({}); | ||
reload(); | ||
}); | ||
|
||
return <Table.Cell fontScale='p1' color='hint' onClick={handleRemoveClick} withTruncatedText><Icon name='trash' size='x20'/></Table.Cell>; | ||
} | ||
|
||
const sortDir = (sortDir) => (sortDir === 'asc' ? 1 : -1); | ||
|
||
const useQuery = ({ guest, servedBy, department, status, from, to, itemsPerPage, current }, [column, direction]) => useMemo(() => { | ||
const query = { | ||
roomName: guest, | ||
sort: JSON.stringify({ [column]: sortDir(direction), usernames: column === 'name' ? sortDir(direction) : undefined }), | ||
...itemsPerPage && { count: itemsPerPage }, | ||
...current && { offset: current }, | ||
}; | ||
|
||
if (from && to) { | ||
query.createdAt = JSON.stringify({ start: from, end: to }); | ||
} | ||
if (status !== 'all') { | ||
query.open = status === 'open'; | ||
} | ||
if (servedBy && servedBy.length > 0) { | ||
query.agents = servedBy; | ||
} | ||
if (department && department.length > 0) { | ||
console.log(department); | ||
query.departmentId = department; | ||
} | ||
|
||
console.log(query); | ||
return query; | ||
}, [guest, servedBy, department, from, to, status, column, direction, itemsPerPage, current]); | ||
|
||
function CurrentChatsRoute() { | ||
const t = useTranslation(); | ||
const canViewCurrentChats = usePermission('view-livechat-current-chats'); | ||
|
||
const [params, setParams] = useState({ fname: '', servedBy: [], status: '', department: '', from: '', to: '', current: 0, itemsPerPage: 25 }); | ||
const [sort, setSort] = useState(['name', 'asc']); | ||
|
||
const debouncedParams = useDebouncedValue(params, 500); | ||
const debouncedSort = useDebouncedValue(sort, 500); | ||
const query = useQuery(debouncedParams, debouncedSort); | ||
// const livechatRoomRoute = useRoute('live/:id'); | ||
|
||
const onHeaderClick = useMutableCallback((id) => { | ||
const [sortBy, sortDirection] = sort; | ||
|
||
if (sortBy === id) { | ||
setSort([id, sortDirection === 'asc' ? 'desc' : 'asc']); | ||
return; | ||
} | ||
setSort([id, 'asc']); | ||
}); | ||
|
||
const onRowClick = useMutableCallback((_id) => { | ||
FlowRouter.go('live', { id: _id }); | ||
// routing this way causes a 404 that only goes away with a refresh, need to fix in review | ||
// livechatRoomRoute.push({ id: _id }); | ||
}); | ||
|
||
const { data, reload } = useEndpointDataExperimental('livechat/rooms', query) || {}; | ||
const { data: departments } = useEndpointDataExperimental('livechat/department', query) || {}; | ||
|
||
console.log(data, departments); | ||
|
||
const header = useMemo(() => [ | ||
<Th key={'name'} direction={sort[1]} active={sort[0] === 'name'} onClick={onHeaderClick} sort='name' w='x120'>{t('Name')}</Th>, | ||
<Th key={'departmentId'} direction={sort[1]} active={sort[0] === 'departmentId'} onClick={onHeaderClick} sort='departmentId' w='x200'>{t('Department')}</Th>, | ||
<Th key={'servedBy'} direction={sort[1]} active={sort[0] === 'servedBy'} onClick={onHeaderClick} sort='servedBy' w='x120'>{t('Served_by')}</Th>, | ||
<Th key={'ts'} direction={sort[1]} active={sort[0] === 'ts'} onClick={onHeaderClick} sort='ts' w='x120'>{t('Started_at')}</Th>, | ||
<Th key={'lm'} direction={sort[1]} active={sort[0] === 'lm'} onClick={onHeaderClick} sort='visibility' w='x120'>{t('Last_message')}</Th>, | ||
<Th key={'status'} direction={sort[1]} active={sort[0] === 'status'} onClick={onHeaderClick} sort='status' w='x120'>{t('Status')}</Th>, | ||
].filter(Boolean), [sort, onHeaderClick, t]); | ||
|
||
const renderRow = useCallback(({ _id, fname, servedBy, ts, lm, department, open }) => <Table.Row key={_id} tabIndex={0} role='link' onClick={() => onRowClick(_id)} action qa-user-id={_id}> | ||
<Table.Cell withTruncatedText>{fname}{_id}</Table.Cell> | ||
<Table.Cell withTruncatedText>{department ? department.name : ''}</Table.Cell> | ||
<Table.Cell withTruncatedText>{servedBy && servedBy.username}</Table.Cell> | ||
<Table.Cell withTruncatedText>{moment(ts).format('L LTS')}</Table.Cell> | ||
<Table.Cell withTruncatedText>{moment(lm).format('L LTS')}</Table.Cell> | ||
<Table.Cell withTruncatedText>{open ? t('Open') : t('Closed')}</Table.Cell> | ||
</Table.Row>, [onRowClick, t]); | ||
|
||
if (!canViewCurrentChats) { | ||
return <NotAuthorizedPage />; | ||
} | ||
|
||
|
||
return <CurrentChatsPage | ||
setParams={setParams} | ||
params={params} | ||
onHeaderClick={onHeaderClick} | ||
data={data} useQuery={useQuery} | ||
reload={reload} | ||
header={header} | ||
renderRow={renderRow} | ||
departments={departments} | ||
title={'Current Chats'}> | ||
</CurrentChatsPage>; | ||
} | ||
|
||
export default CurrentChatsRoute; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters