From decefab53cd27536d3373460d03e2ceaf9e7f2bb Mon Sep 17 00:00:00 2001 From: Douglas Fabris Date: Thu, 26 Jan 2023 21:50:18 -0300 Subject: [PATCH] Chore: Refactor Directory Tables (#27646) --- .../client/components/RoomIcon/RoomIcon.tsx | 5 +- .../client/views/directory/ChannelsTable.js | 170 ------------------ .../client/views/directory/DirectoryPage.tsx | 6 +- .../client/views/directory/RoomTags.tsx | 7 +- .../client/views/directory/TeamsTable.js | 136 -------------- .../{ => tabs/channels}/ChannelsTab.tsx | 6 +- .../channels/ChannelsTable/ChannelsTable.tsx | 147 +++++++++++++++ .../ChannelsTable/ChannelsTableRow.tsx | 61 +++++++ .../tabs/channels/ChannelsTable/index.ts | 1 + .../directory/{ => tabs/teams}/TeamsTab.tsx | 8 +- .../tabs/teams/TeamsTable/TeamsTable.tsx | 129 +++++++++++++ .../tabs/teams/TeamsTable/TeamsTableRow.tsx | 51 ++++++ .../directory/tabs/teams/TeamsTable/index.ts | 1 + .../directory/{ => tabs/users}/UsersTab.tsx | 2 +- .../users}/UsersTable/UsersTable.tsx | 23 ++- .../users}/UsersTable/UsersTableRow.tsx | 6 +- .../{ => tabs/users}/UsersTable/index.ts | 0 17 files changed, 427 insertions(+), 332 deletions(-) delete mode 100644 apps/meteor/client/views/directory/ChannelsTable.js delete mode 100644 apps/meteor/client/views/directory/TeamsTable.js rename apps/meteor/client/views/directory/{ => tabs/channels}/ChannelsTab.tsx (74%) create mode 100644 apps/meteor/client/views/directory/tabs/channels/ChannelsTable/ChannelsTable.tsx create mode 100644 apps/meteor/client/views/directory/tabs/channels/ChannelsTable/ChannelsTableRow.tsx create mode 100644 apps/meteor/client/views/directory/tabs/channels/ChannelsTable/index.ts rename apps/meteor/client/views/directory/{ => tabs/teams}/TeamsTab.tsx (64%) create mode 100644 apps/meteor/client/views/directory/tabs/teams/TeamsTable/TeamsTable.tsx create mode 100644 apps/meteor/client/views/directory/tabs/teams/TeamsTable/TeamsTableRow.tsx create mode 100644 apps/meteor/client/views/directory/tabs/teams/TeamsTable/index.ts rename apps/meteor/client/views/directory/{ => tabs/users}/UsersTab.tsx (87%) rename apps/meteor/client/views/directory/{ => tabs/users}/UsersTable/UsersTable.tsx (82%) rename apps/meteor/client/views/directory/{ => tabs/users}/UsersTable/UsersTableRow.tsx (89%) rename apps/meteor/client/views/directory/{ => tabs/users}/UsersTable/index.ts (100%) diff --git a/apps/meteor/client/components/RoomIcon/RoomIcon.tsx b/apps/meteor/client/components/RoomIcon/RoomIcon.tsx index 3410fedc06c..754826bed4c 100644 --- a/apps/meteor/client/components/RoomIcon/RoomIcon.tsx +++ b/apps/meteor/client/components/RoomIcon/RoomIcon.tsx @@ -11,14 +11,15 @@ export const RoomIcon = ({ room, size = 'x16', isIncomingCall, - placement, + placement = 'default', }: { room: IRoom; size?: ComponentProps['size']; isIncomingCall?: boolean; - placement: 'sidebar' | 'default'; + placement?: 'sidebar' | 'default'; }): ReactElement | null => { const iconPropsOrReactNode = useRoomIcon(room); + if (isIncomingCall) { return ; } diff --git a/apps/meteor/client/views/directory/ChannelsTable.js b/apps/meteor/client/views/directory/ChannelsTable.js deleted file mode 100644 index 02990624605..00000000000 --- a/apps/meteor/client/views/directory/ChannelsTable.js +++ /dev/null @@ -1,170 +0,0 @@ -import { Box, Table, Avatar, Icon } from '@rocket.chat/fuselage'; -import { useMediaQuery, useAutoFocus } from '@rocket.chat/fuselage-hooks'; -import { useRoute, useTranslation } from '@rocket.chat/ui-contexts'; -import React, { useMemo, useState, useCallback } from 'react'; - -import FilterByText from '../../components/FilterByText'; -import GenericTable from '../../components/GenericTable'; -import MarkdownText from '../../components/MarkdownText'; -import { useEndpointData } from '../../hooks/useEndpointData'; -import { useFormatDate } from '../../hooks/useFormatDate'; -import { roomCoordinator } from '../../lib/rooms/roomCoordinator'; -import RoomTags from './RoomTags'; -import { useDirectoryQuery } from './hooks/useDirectoryQuery'; - -const style = { - whiteSpace: 'nowrap', - textOverflow: 'ellipsis', - overflow: 'hidden', -}; - -function ChannelsTable() { - const t = useTranslation(); - const refAutoFocus = useAutoFocus(true); - const [sort, setSort] = useState(['name', 'asc']); - const [params, setParams] = useState({ current: 0, itemsPerPage: 25 }); - - const mediaQuery = useMediaQuery('(min-width: 768px)'); - - const query = useDirectoryQuery(params, sort, 'channels'); - - const onHeaderClick = useCallback( - (id) => { - const [sortBy, sortDirection] = sort; - - if (sortBy === id) { - setSort([id, sortDirection === 'asc' ? 'desc' : 'asc']); - return; - } - setSort([id, 'asc']); - }, - [sort], - ); - - const header = useMemo( - () => - [ - - {t('Name')} - , - - {t('Users')} - , - mediaQuery && ( - - {t('Created_at')} - - ), - mediaQuery && ( - - {t('Last_Message')} - - ), - mediaQuery && ( - - {t('Belongs_To')} - - ), - ].filter(Boolean), - [sort, onHeaderClick, t, mediaQuery], - ); - - const channelRoute = useRoute('channel'); - const groupsRoute = useRoute('group'); - - const { value: data = {} } = useEndpointData('/v1/directory', { params: query }); - - const onClick = useMemo( - () => (name, type) => (e) => { - if (e.type === 'click' || e.key === 'Enter') { - type === 'c' ? channelRoute.push({ name }) : groupsRoute.push({ name }); - } - }, - [channelRoute, groupsRoute], - ); - - const formatDate = useFormatDate(); - const renderRow = useCallback( - (room) => { - const { _id, ts, t, name, fname, usersCount, lastMessage, topic, belongsTo } = room; - const avatarUrl = roomCoordinator.getRoomDirectives(t)?.getAvatarPath(room); - - return ( - - - - - - - - - {' '} - - {fname || name} - - - - {topic && } - - - - - {usersCount} - - {mediaQuery && ( - - {formatDate(ts)} - - )} - {mediaQuery && ( - - {lastMessage && formatDate(lastMessage.ts)} - - )} - {mediaQuery && ( - - {belongsTo} - - )} - - ); - }, - [formatDate, mediaQuery, onClick], - ); - - return ( - ( - - )} - renderRow={renderRow} - results={data.result} - setParams={setParams} - total={data.total} - /> - ); -} - -export default ChannelsTable; diff --git a/apps/meteor/client/views/directory/DirectoryPage.tsx b/apps/meteor/client/views/directory/DirectoryPage.tsx index 6e06c446fe5..8024d2ae66d 100644 --- a/apps/meteor/client/views/directory/DirectoryPage.tsx +++ b/apps/meteor/client/views/directory/DirectoryPage.tsx @@ -4,9 +4,9 @@ import type { ReactElement } from 'react'; import React, { useEffect, useCallback } from 'react'; import Page from '../../components/Page'; -import ChannelsTab from './ChannelsTab'; -import TeamsTab from './TeamsTab'; -import UsersTab from './UsersTab'; +import ChannelsTab from './tabs/channels/ChannelsTab'; +import TeamsTab from './tabs/teams/TeamsTab'; +import UsersTab from './tabs/users/UsersTab'; const DirectoryPage = (): ReactElement => { const t = useTranslation(); diff --git a/apps/meteor/client/views/directory/RoomTags.tsx b/apps/meteor/client/views/directory/RoomTags.tsx index 58a410faf7d..20a36cf7c5c 100644 --- a/apps/meteor/client/views/directory/RoomTags.tsx +++ b/apps/meteor/client/views/directory/RoomTags.tsx @@ -4,16 +4,17 @@ import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; -function RoomTags({ room }: { room: IRoom }): ReactElement { +const RoomTags = ({ room }: { room: IRoom }): ReactElement => { const t = useTranslation(); + return ( - + {room.default && {t('default')}} {room.featured && {t('featured')}} ); -} +}; export default RoomTags; diff --git a/apps/meteor/client/views/directory/TeamsTable.js b/apps/meteor/client/views/directory/TeamsTable.js deleted file mode 100644 index 90e5a6b246d..00000000000 --- a/apps/meteor/client/views/directory/TeamsTable.js +++ /dev/null @@ -1,136 +0,0 @@ -import { Box, Table, Avatar, Icon } from '@rocket.chat/fuselage'; -import { useAutoFocus, useMediaQuery } from '@rocket.chat/fuselage-hooks'; -import { useRoute, useTranslation } from '@rocket.chat/ui-contexts'; -import React, { useMemo, useState, useCallback } from 'react'; - -import FilterByText from '../../components/FilterByText'; -import GenericTable from '../../components/GenericTable'; -import MarkdownText from '../../components/MarkdownText'; -import { useEndpointData } from '../../hooks/useEndpointData'; -import { useFormatDate } from '../../hooks/useFormatDate'; -import { roomCoordinator } from '../../lib/rooms/roomCoordinator'; -import RoomTags from './RoomTags'; -import { useDirectoryQuery } from './hooks/useDirectoryQuery'; - -const style = { - whiteSpace: 'nowrap', - textOverflow: 'ellipsis', - overflow: 'hidden', -}; - -function TeamsTable() { - const t = useTranslation(); - const [sort, setSort] = useState(['name', 'asc']); - const [params, setParams] = useState({ current: 0, itemsPerPage: 25 }); - - const refAutoFocus = useAutoFocus(true); - const mediaQuery = useMediaQuery('(min-width: 768px)'); - - const onHeaderClick = useCallback( - (id) => { - const [sortBy, sortDirection] = sort; - - if (sortBy === id) { - setSort([id, sortDirection === 'asc' ? 'desc' : 'asc']); - return; - } - setSort([id, 'asc']); - }, - [sort], - ); - - const header = useMemo( - () => - [ - - {t('Name')} - , - - {t('Channels')} - , - mediaQuery && ( - - {t('Created_at')} - - ), - ].filter(Boolean), - [sort, onHeaderClick, t, mediaQuery], - ); - - const channelsRoute = useRoute('channel'); - const groupsRoute = useRoute('group'); - - const query = useDirectoryQuery(params, sort, 'teams'); - - const { value: data = {} } = useEndpointData('/v1/directory', { params: query }); - - const onClick = useMemo( - () => (name, type) => (e) => { - if (e.type === 'click' || e.key === 'Enter') { - type === 'c' ? channelsRoute.push({ name }) : groupsRoute.push({ name }); - } - }, - [channelsRoute, groupsRoute], - ); - - const formatDate = useFormatDate(); - const renderRow = useCallback( - (team) => { - const { _id, ts, t, name, fname, topic, roomsCount } = team; - const avatarUrl = roomCoordinator.getRoomDirectives(t)?.getAvatarPath(team); - - return ( - - - - - - - - - {' '} - - {fname || name} - - - - {topic && } - - - - - {roomsCount} - - {mediaQuery && ( - - {formatDate(ts)} - - )} - - ); - }, - [formatDate, mediaQuery, onClick], - ); - - return ( - ( - - )} - renderRow={renderRow} - results={data.result} - setParams={setParams} - total={data.total} - /> - ); -} - -export default TeamsTable; diff --git a/apps/meteor/client/views/directory/ChannelsTab.tsx b/apps/meteor/client/views/directory/tabs/channels/ChannelsTab.tsx similarity index 74% rename from apps/meteor/client/views/directory/ChannelsTab.tsx rename to apps/meteor/client/views/directory/tabs/channels/ChannelsTab.tsx index 3ba0a23f8b1..e1627e63e06 100644 --- a/apps/meteor/client/views/directory/ChannelsTab.tsx +++ b/apps/meteor/client/views/directory/tabs/channels/ChannelsTab.tsx @@ -2,10 +2,10 @@ import { usePermission } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; -import NotAuthorizedPage from '../notAuthorized/NotAuthorizedPage'; +import NotAuthorizedPage from '../../../notAuthorized/NotAuthorizedPage'; import ChannelsTable from './ChannelsTable'; -function ChannelsTab(): ReactElement { +const ChannelsTab = (): ReactElement => { const canViewPublicRooms = usePermission('view-c-room'); if (canViewPublicRooms) { @@ -13,6 +13,6 @@ function ChannelsTab(): ReactElement { } return ; -} +}; export default ChannelsTab; diff --git a/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/ChannelsTable.tsx b/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/ChannelsTable.tsx new file mode 100644 index 00000000000..5769bbb12bf --- /dev/null +++ b/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/ChannelsTable.tsx @@ -0,0 +1,147 @@ +import type { IRoom } from '@rocket.chat/core-typings'; +import { Pagination, States, StatesIcon, StatesTitle, StatesActions, StatesAction } from '@rocket.chat/fuselage'; +import { useDebouncedValue, useMediaQuery } from '@rocket.chat/fuselage-hooks'; +import { useRoute, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts'; +import { useQuery } from '@tanstack/react-query'; +import React, { useMemo, useState } from 'react'; + +import FilterByText from '../../../../../components/FilterByText'; +import { + GenericTable, + GenericTableHeader, + GenericTableHeaderCell, + GenericTableBody, + GenericTableLoadingTable, +} from '../../../../../components/GenericTable'; +import { usePagination } from '../../../../../components/GenericTable/hooks/usePagination'; +import { useSort } from '../../../../../components/GenericTable/hooks/useSort'; +import { useDirectoryQuery } from '../../../hooks/useDirectoryQuery'; +import ChannelsTableRow from './ChannelsTableRow'; + +const ChannelsTable = () => { + const t = useTranslation(); + const mediaQuery = useMediaQuery('(min-width: 768px)'); + + const [text, setText] = useState(''); + const debouncedText = useDebouncedValue(text, 500); + + const channelRoute = useRoute('channel'); + const groupsRoute = useRoute('group'); + + const { current, itemsPerPage, setItemsPerPage: onSetItemsPerPage, setCurrent: onSetCurrent, ...paginationProps } = usePagination(); + const { sortBy, sortDirection, setSort } = useSort<'name' | 'usersCount' | 'lastMessage' | 'createdAt'>('name'); + + const headers = useMemo( + () => + [ + + {t('Name')} + , + + {t('Users')} + , + mediaQuery && ( + + {t('Created_at')} + + ), + mediaQuery && ( + + {t('Last_Message')} + + ), + mediaQuery && ( + + {t('Belongs_To')} + + ), + ].filter(Boolean), + [setSort, sortBy, t, sortDirection, mediaQuery], + ); + + const getDirectoryData = useEndpoint('GET', '/v1/directory'); + const query = useDirectoryQuery({ text: debouncedText, current, itemsPerPage }, [sortBy, sortDirection], 'channels'); + const { data, isFetched, isLoading, isError, refetch } = useQuery(['getDirectoryData', query], () => getDirectoryData(query)); + + const onClick = useMemo( + () => (name: IRoom['name'], type: IRoom['t']) => (e: React.KeyboardEvent | React.MouseEvent) => { + if (name && (e.type === 'click' || (e as React.KeyboardEvent).key === 'Enter')) { + type === 'c' ? channelRoute.push({ name }) : groupsRoute.push({ name }); + } + }, + [channelRoute, groupsRoute], + ); + + return ( + <> + setText(text)} /> + {isLoading && ( + + {headers} + + + + + )} + {data?.result && data.result.length > 0 && isFetched && ( + <> + + {headers} + + {data.result.map((room) => ( + + ))} + + + + + )} + {isFetched && data?.result.length === 0 && ( + + + {t('No_results_found')} + + )} + {isError && ( + + + {t('Something_went_wrong')} + + refetch()}>{t('Reload_page')} + + + )} + + ); +}; + +export default ChannelsTable; diff --git a/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/ChannelsTableRow.tsx b/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/ChannelsTableRow.tsx new file mode 100644 index 00000000000..f5000e3d842 --- /dev/null +++ b/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/ChannelsTableRow.tsx @@ -0,0 +1,61 @@ +import type { IRoom, ITeam } from '@rocket.chat/core-typings'; +import { Box, TableRow, TableCell, Avatar } from '@rocket.chat/fuselage'; +import React from 'react'; + +import MarkdownText from '../../../../../components/MarkdownText'; +import { RoomIcon } from '../../../../../components/RoomIcon'; +import { useFormatDate } from '../../../../../hooks/useFormatDate'; +import { roomCoordinator } from '../../../../../lib/rooms/roomCoordinator'; +import RoomTags from '../../../RoomTags'; + +type ChannelsTableRowProps = { + onClick: (name: IRoom['name'], type: IRoom['t']) => (e: React.KeyboardEvent | React.MouseEvent) => void; + room: IRoom & { belongsTo?: ITeam }; + mediaQuery: boolean; +}; + +const ChannelsTableRow = ({ onClick, room, mediaQuery }: ChannelsTableRowProps) => { + const formatDate = useFormatDate(); + const { _id, ts, t, name, fname, usersCount, lastMessage, topic, belongsTo } = room; + const avatarUrl = roomCoordinator.getRoomDirectives(t)?.getAvatarPath(room); + + return ( + + + + {avatarUrl && } + + + + + {fname || name} + + + + {topic && } + + + + + {usersCount} + + {mediaQuery && ts && ( + + {formatDate(ts)} + + )} + {mediaQuery && ( + + {lastMessage && formatDate(lastMessage.ts)} + + )} + {mediaQuery && ( + + {belongsTo} + + )} + + ); +}; + +export default ChannelsTableRow; diff --git a/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/index.ts b/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/index.ts new file mode 100644 index 00000000000..e67767940ce --- /dev/null +++ b/apps/meteor/client/views/directory/tabs/channels/ChannelsTable/index.ts @@ -0,0 +1 @@ +export { default } from './ChannelsTable'; diff --git a/apps/meteor/client/views/directory/TeamsTab.tsx b/apps/meteor/client/views/directory/tabs/teams/TeamsTab.tsx similarity index 64% rename from apps/meteor/client/views/directory/TeamsTab.tsx rename to apps/meteor/client/views/directory/tabs/teams/TeamsTab.tsx index 0a3d4df1389..feca1b77191 100644 --- a/apps/meteor/client/views/directory/TeamsTab.tsx +++ b/apps/meteor/client/views/directory/tabs/teams/TeamsTab.tsx @@ -2,10 +2,10 @@ import { usePermission } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; -import NotAuthorizedPage from '../notAuthorized/NotAuthorizedPage'; -import TeamsTable from './TeamsTable'; +import NotAuthorizedPage from '../../../notAuthorized/NotAuthorizedPage'; +import TeamsTable from './TeamsTable/TeamsTable'; -function TeamsTab(): ReactElement { +const TeamsTab = (): ReactElement => { const canViewPublicRooms = usePermission('view-c-room'); if (canViewPublicRooms) { @@ -13,6 +13,6 @@ function TeamsTab(): ReactElement { } return ; -} +}; export default TeamsTab; diff --git a/apps/meteor/client/views/directory/tabs/teams/TeamsTable/TeamsTable.tsx b/apps/meteor/client/views/directory/tabs/teams/TeamsTable/TeamsTable.tsx new file mode 100644 index 00000000000..86e06fc4f7f --- /dev/null +++ b/apps/meteor/client/views/directory/tabs/teams/TeamsTable/TeamsTable.tsx @@ -0,0 +1,129 @@ +import type { IRoom } from '@rocket.chat/core-typings'; +import { Pagination, States, StatesIcon, StatesTitle, StatesActions, StatesAction } from '@rocket.chat/fuselage'; +import { useMediaQuery, useDebouncedValue } from '@rocket.chat/fuselage-hooks'; +import { useRoute, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts'; +import { useQuery } from '@tanstack/react-query'; +import React, { useMemo, useState } from 'react'; + +import FilterByText from '../../../../../components/FilterByText'; +import { + GenericTable, + GenericTableHeader, + GenericTableHeaderCell, + GenericTableBody, + GenericTableLoadingTable, +} from '../../../../../components/GenericTable'; +import { usePagination } from '../../../../../components/GenericTable/hooks/usePagination'; +import { useSort } from '../../../../../components/GenericTable/hooks/useSort'; +import { useDirectoryQuery } from '../../../hooks/useDirectoryQuery'; +import TeamsTableRow from './TeamsTableRow'; + +const TeamsTable = () => { + const t = useTranslation(); + + const mediaQuery = useMediaQuery('(min-width: 768px)'); + + const [text, setText] = useState(''); + const debouncedText = useDebouncedValue(text, 500); + + const { current, itemsPerPage, setItemsPerPage: onSetItemsPerPage, setCurrent: onSetCurrent, ...paginationProps } = usePagination(); + const { sortBy, sortDirection, setSort } = useSort<'name' | 'usersCount' | 'lastMessage' | 'createdAt'>('name'); + + const headers = useMemo( + () => + [ + + {t('Name')} + , + + {t('Channels')} + , + mediaQuery && ( + + {t('Created_at')} + + ), + ].filter(Boolean), + [setSort, sortBy, sortDirection, t, mediaQuery], + ); + + const channelsRoute = useRoute('channel'); + const groupsRoute = useRoute('group'); + + const getDirectoryData = useEndpoint('GET', '/v1/directory'); + const query = useDirectoryQuery({ text: debouncedText, current, itemsPerPage }, [sortBy, sortDirection], 'teams'); + const { data, isFetched, isLoading, isError, refetch } = useQuery(['getDirectoryData', query], () => getDirectoryData(query)); + + const onClick = useMemo( + () => (name: IRoom['name'], type: IRoom['t']) => (e: React.KeyboardEvent | React.MouseEvent) => { + if (name && (e.type === 'click' || (e as React.KeyboardEvent).key === 'Enter')) { + type === 'c' ? channelsRoute.push({ name }) : groupsRoute.push({ name }); + } + }, + [channelsRoute, groupsRoute], + ); + + return ( + <> + setText(text)} /> + {isLoading && ( + + {headers} + + + + + )} + {data?.result && data.result.length > 0 && isFetched && ( + <> + + {headers} + + {data.result.map((team) => ( + + ))} + + + + + )} + {isFetched && data?.result.length === 0 && ( + + + {t('No_results_found')} + + )} + {isError && ( + + + {t('Something_went_wrong')} + + refetch()}>{t('Reload_page')} + + + )} + + ); +}; + +export default TeamsTable; diff --git a/apps/meteor/client/views/directory/tabs/teams/TeamsTable/TeamsTableRow.tsx b/apps/meteor/client/views/directory/tabs/teams/TeamsTable/TeamsTableRow.tsx new file mode 100644 index 00000000000..1428feee4b0 --- /dev/null +++ b/apps/meteor/client/views/directory/tabs/teams/TeamsTable/TeamsTableRow.tsx @@ -0,0 +1,51 @@ +import type { IRoom } from '@rocket.chat/core-typings'; +import { Box, TableRow, TableCell, Avatar } from '@rocket.chat/fuselage'; +import React from 'react'; + +import MarkdownText from '../../../../../components/MarkdownText'; +import { RoomIcon } from '../../../../../components/RoomIcon'; +import { useFormatDate } from '../../../../../hooks/useFormatDate'; +import { roomCoordinator } from '../../../../../lib/rooms/roomCoordinator'; +import RoomTags from '../../../RoomTags'; + +type TeamsTableRowProps = { + onClick: (name: IRoom['name'], type: IRoom['t']) => (e: React.KeyboardEvent | React.MouseEvent) => void; + team: IRoom & { roomsCount: number }; + mediaQuery: boolean; +}; + +const TeamsTableRow = ({ onClick, team, mediaQuery }: TeamsTableRowProps) => { + const formatDate = useFormatDate(); + const { _id, ts, t, name, fname, topic, roomsCount } = team; + const avatarUrl = roomCoordinator.getRoomDirectives(t)?.getAvatarPath(team); + + return ( + + + + {avatarUrl && } + + + + + {fname || name} + + + + {topic && } + + + + + {roomsCount} + + {mediaQuery && ts && ( + + {formatDate(ts)} + + )} + + ); +}; + +export default TeamsTableRow; diff --git a/apps/meteor/client/views/directory/tabs/teams/TeamsTable/index.ts b/apps/meteor/client/views/directory/tabs/teams/TeamsTable/index.ts new file mode 100644 index 00000000000..da1d6f92e06 --- /dev/null +++ b/apps/meteor/client/views/directory/tabs/teams/TeamsTable/index.ts @@ -0,0 +1 @@ +export { default } from './TeamsTable'; diff --git a/apps/meteor/client/views/directory/UsersTab.tsx b/apps/meteor/client/views/directory/tabs/users/UsersTab.tsx similarity index 87% rename from apps/meteor/client/views/directory/UsersTab.tsx rename to apps/meteor/client/views/directory/tabs/users/UsersTab.tsx index a8db8960d13..da3134ec8a7 100644 --- a/apps/meteor/client/views/directory/UsersTab.tsx +++ b/apps/meteor/client/views/directory/tabs/users/UsersTab.tsx @@ -2,7 +2,7 @@ import { usePermission } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; -import NotAuthorizedPage from '../notAuthorized/NotAuthorizedPage'; +import NotAuthorizedPage from '../../../notAuthorized/NotAuthorizedPage'; import UsersTable from './UsersTable'; const UsersTab = (props: { workspace?: 'external' | 'local' }): ReactElement => { diff --git a/apps/meteor/client/views/directory/UsersTable/UsersTable.tsx b/apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsx similarity index 82% rename from apps/meteor/client/views/directory/UsersTable/UsersTable.tsx rename to apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsx index de740a5d2af..0077d9b5df0 100644 --- a/apps/meteor/client/views/directory/UsersTable/UsersTable.tsx +++ b/apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTable.tsx @@ -1,22 +1,22 @@ import type { IUser, Serialized } from '@rocket.chat/core-typings'; -import { Pagination, States, StatesIcon, StatesTitle } from '@rocket.chat/fuselage'; +import { Pagination, States, StatesIcon, StatesTitle, StatesActions, StatesAction } from '@rocket.chat/fuselage'; import { useDebouncedValue, useMediaQuery } from '@rocket.chat/fuselage-hooks'; import { usePermission, useRoute, useTranslation, useEndpoint } from '@rocket.chat/ui-contexts'; import { useQuery } from '@tanstack/react-query'; import type { ReactElement } from 'react'; import React, { useCallback, useMemo, useState } from 'react'; -import FilterByText from '../../../components/FilterByText'; +import FilterByText from '../../../../../components/FilterByText'; import { GenericTable, GenericTableHeader, GenericTableHeaderCell, GenericTableBody, GenericTableLoadingTable, -} from '../../../components/GenericTable'; -import { usePagination } from '../../../components/GenericTable/hooks/usePagination'; -import { useSort } from '../../../components/GenericTable/hooks/useSort'; -import { useDirectoryQuery } from '../hooks/useDirectoryQuery'; +} from '../../../../../components/GenericTable'; +import { usePagination } from '../../../../../components/GenericTable/hooks/usePagination'; +import { useSort } from '../../../../../components/GenericTable/hooks/useSort'; +import { useDirectoryQuery } from '../../../hooks/useDirectoryQuery'; import UsersTableRow from './UsersTableRow'; const UsersTable = ({ workspace = 'local' }): ReactElement => { @@ -81,7 +81,7 @@ const UsersTable = ({ workspace = 'local' }): ReactElement => { const query = useDirectoryQuery({ text: debouncedText, current, itemsPerPage }, [sortBy, sortDirection], 'users', workspace); const getDirectoryData = useEndpoint('GET', '/v1/directory'); - const { data, isFetched, isLoading } = useQuery(['getDirectoryData', query], () => getDirectoryData(query)); + const { data, isFetched, isLoading, isError, refetch } = useQuery(['getDirectoryData', query], () => getDirectoryData(query)); const handleClick = useCallback( (username) => (e: React.KeyboardEvent | React.MouseEvent) => { @@ -137,6 +137,15 @@ const UsersTable = ({ workspace = 'local' }): ReactElement => { {t('No_results_found')} )} + {isError && ( + + + {t('Something_went_wrong')} + + refetch()}>{t('Reload_page')} + + + )} ); }; diff --git a/apps/meteor/client/views/directory/UsersTable/UsersTableRow.tsx b/apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTableRow.tsx similarity index 89% rename from apps/meteor/client/views/directory/UsersTable/UsersTableRow.tsx rename to apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTableRow.tsx index 1411c559235..7d1e1b73229 100644 --- a/apps/meteor/client/views/directory/UsersTable/UsersTableRow.tsx +++ b/apps/meteor/client/views/directory/tabs/users/UsersTable/UsersTableRow.tsx @@ -2,9 +2,9 @@ import type { IUser, Serialized } from '@rocket.chat/core-typings'; import { Box, Flex, TableRow, TableCell } from '@rocket.chat/fuselage'; import React from 'react'; -import MarkdownText from '../../../components/MarkdownText'; -import UserAvatar from '../../../components/avatar/UserAvatar'; -import { useFormatDate } from '../../../hooks/useFormatDate'; +import MarkdownText from '../../../../../components/MarkdownText'; +import UserAvatar from '../../../../../components/avatar/UserAvatar'; +import { useFormatDate } from '../../../../../hooks/useFormatDate'; type UsersTableRowProps = { user: Serialized & { domain?: string }; diff --git a/apps/meteor/client/views/directory/UsersTable/index.ts b/apps/meteor/client/views/directory/tabs/users/UsersTable/index.ts similarity index 100% rename from apps/meteor/client/views/directory/UsersTable/index.ts rename to apps/meteor/client/views/directory/tabs/users/UsersTable/index.ts