From b3b9446d40fbfbf7e90f66515fe3628150ba8c5f Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 2 Sep 2024 12:01:05 -0600 Subject: [PATCH 1/5] UI changes after update rooms.info endpoint --- .../client/lib/rooms/roomCoordinator.tsx | 3 + .../client/views/room/Header/ParentRoom.tsx | 7 ++- .../views/room/Header/ParentRoomWithData.tsx | 21 ++++--- .../Header/ParentRoomWithEndpointData.tsx | 12 ++++ .../client/views/room/Header/ParentTeam.tsx | 56 ++++------------- .../client/views/room/Header/RoomHeader.tsx | 3 +- .../client/views/room/HeaderV2/ParentRoom.tsx | 7 ++- .../room/HeaderV2/ParentRoomWithData.tsx | 21 ++++--- .../HeaderV2/ParentRoomWithEndpointData.tsx | 13 ++++ .../client/views/room/HeaderV2/ParentTeam.tsx | 61 +++++-------------- .../client/views/room/HeaderV2/RoomHeader.tsx | 3 +- apps/meteor/definition/IRoomTypeConfig.ts | 1 + 12 files changed, 98 insertions(+), 110 deletions(-) diff --git a/apps/meteor/client/lib/rooms/roomCoordinator.tsx b/apps/meteor/client/lib/rooms/roomCoordinator.tsx index 31eda2982a12..11bbe0ef3a49 100644 --- a/apps/meteor/client/lib/rooms/roomCoordinator.tsx +++ b/apps/meteor/client/lib/rooms/roomCoordinator.tsx @@ -63,6 +63,9 @@ class RoomCoordinatorClient extends RoomCoordinator { canSendMessage(rid: string): boolean { return ChatSubscription.find({ rid }).count() > 0; }, + hasSubscription(rid: string): boolean { + return ChatSubscription.find({ rid }).count() > 0; + }, ...directives, config: roomConfig, }); diff --git a/apps/meteor/client/views/room/Header/ParentRoom.tsx b/apps/meteor/client/views/room/Header/ParentRoom.tsx index 5907b3019084..bbe2ec1e2652 100644 --- a/apps/meteor/client/views/room/Header/ParentRoom.tsx +++ b/apps/meteor/client/views/room/Header/ParentRoom.tsx @@ -13,7 +13,12 @@ type ParentRoomProps = { const ParentRoom = ({ room }: ParentRoomProps): ReactElement => { const icon = useRoomIcon(room); - const handleRedirect = (): void => roomCoordinator.openRouteLink(room.t, { rid: room._id, ...room }); + const handleRedirect = (): void => { + if (!roomCoordinator.getRoomDirectives(room.t).hasSubscription(room._id)) { + return; + } + roomCoordinator.openRouteLink(room.t, { rid: room._id, ...room }); + }; return ( { - const { prid } = room; +const getParentId = ({ prid, teamId }: IRoom): string => { + if (prid) { + return prid; + } - if (!prid) { - throw new Error('Parent room ID is missing'); + if (teamId) { + return teamId; } - const subscription = useUserSubscription(prid); + throw new Error('Parent room ID is missing'); +}; + +const ParentRoomWithData = ({ room }: ParentRoomWithDataProps): ReactElement => { + const parentId = getParentId(room); + const subscription = useUserSubscription(parentId); if (subscription) { - return ; + return ; } - return ; + return ; }; export default ParentRoomWithData; diff --git a/apps/meteor/client/views/room/Header/ParentRoomWithEndpointData.tsx b/apps/meteor/client/views/room/Header/ParentRoomWithEndpointData.tsx index 06571dd02cce..6418fa47f3cc 100644 --- a/apps/meteor/client/views/room/Header/ParentRoomWithEndpointData.tsx +++ b/apps/meteor/client/views/room/Header/ParentRoomWithEndpointData.tsx @@ -5,6 +5,7 @@ import React from 'react'; import { HeaderTagSkeleton } from '../../../components/Header'; import { useRoomInfoEndpoint } from '../../../hooks/useRoomInfoEndpoint'; import ParentRoom from './ParentRoom'; +import ParentTeam from './ParentTeam'; type ParentRoomWithEndpointDataProps = { rid: IRoom['_id']; @@ -21,6 +22,17 @@ const ParentRoomWithEndpointData = ({ rid }: ParentRoomWithEndpointDataProps): R return null; } + if (data.parent) { + return ; + } + + if (data.team) { + if (data.team.roomId === rid) { + return null; + } + + return ; + } return ; }; diff --git a/apps/meteor/client/views/room/Header/ParentTeam.tsx b/apps/meteor/client/views/room/Header/ParentTeam.tsx index ed4a4588ef21..1381aef14014 100644 --- a/apps/meteor/client/views/room/Header/ParentTeam.tsx +++ b/apps/meteor/client/views/room/Header/ParentTeam.tsx @@ -1,50 +1,27 @@ -import type { IRoom } from '@rocket.chat/core-typings'; +import type { ITeam } from '@rocket.chat/core-typings'; import { TEAM_TYPE } from '@rocket.chat/core-typings'; -import { useUserId, useEndpoint } from '@rocket.chat/ui-contexts'; -import { useQuery } from '@tanstack/react-query'; +import { useUserSubscription } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import React from 'react'; -import { HeaderTag, HeaderTagIcon, HeaderTagSkeleton } from '../../../components/Header'; +import { HeaderTag, HeaderTagIcon } from '../../../components/Header'; import { goToRoomById } from '../../../lib/utils/goToRoomById'; -type APIErrorResult = { success: boolean; error: string }; +const ParentTeam = ({ team }: { team: Pick }): ReactElement | null => { + const isTeamPublic = team.type === TEAM_TYPE.PUBLIC; -const ParentTeam = ({ room }: { room: IRoom }): ReactElement | null => { - const { teamId } = room; - const userId = useUserId(); - - if (!teamId) { - throw new Error('invalid rid'); - } - - if (!userId) { - throw new Error('invalid uid'); - } - - const teamsInfoEndpoint = useEndpoint('GET', '/v1/teams.info'); - const userTeamsListEndpoint = useEndpoint('GET', '/v1/users.listTeams'); - - const { - data: teamInfoData, - isLoading: teamInfoLoading, - isError: teamInfoError, - } = useQuery(['teamId', teamId], async () => teamsInfoEndpoint({ teamId }), { - keepPreviousData: true, - retry: (_, error) => (error as APIErrorResult)?.error === 'unauthorized' && false, - }); - - const { data: userTeams, isLoading: userTeamsLoading } = useQuery(['userId', userId], async () => userTeamsListEndpoint({ userId })); - - const userBelongsToTeam = userTeams?.teams?.find((team) => team._id === teamId) || false; - const isTeamPublic = teamInfoData?.teamInfo.type === TEAM_TYPE.PUBLIC; + const subscription = useUserSubscription(team.roomId); const redirectToMainRoom = (): void => { - const rid = teamInfoData?.teamInfo.roomId; + const rid = team.roomId; if (!rid) { return; } + const isTeamPublic = team.type === TEAM_TYPE.PUBLIC; + + const userBelongsToTeam = !!subscription; + if (!(isTeamPublic || userBelongsToTeam)) { return; } @@ -52,14 +29,6 @@ const ParentTeam = ({ room }: { room: IRoom }): ReactElement | null => { goToRoomById(rid); }; - if (teamInfoLoading || userTeamsLoading) { - return ; - } - - if (teamInfoError) { - return null; - } - return ( { onClick={redirectToMainRoom} > - {teamInfoData?.teamInfo.name} + + {team.name} ); }; diff --git a/apps/meteor/client/views/room/Header/RoomHeader.tsx b/apps/meteor/client/views/room/Header/RoomHeader.tsx index 2e38e2110bbe..b2aeca55885b 100644 --- a/apps/meteor/client/views/room/Header/RoomHeader.tsx +++ b/apps/meteor/client/views/room/Header/RoomHeader.tsx @@ -47,8 +47,7 @@ const RoomHeader = ({ room, topic = '', slots = {}, roomToolbox }: RoomHeaderPro - {room.prid && } - {room.teamId && !room.teamMain && } + {(room.prid || room.teamId) && } {isRoomFederated(room) && } diff --git a/apps/meteor/client/views/room/HeaderV2/ParentRoom.tsx b/apps/meteor/client/views/room/HeaderV2/ParentRoom.tsx index 0c53d790caf8..24f3d9e0bf14 100644 --- a/apps/meteor/client/views/room/HeaderV2/ParentRoom.tsx +++ b/apps/meteor/client/views/room/HeaderV2/ParentRoom.tsx @@ -12,7 +12,12 @@ type ParentRoomProps = { const ParentRoom = ({ room }: ParentRoomProps) => { const icon = useRoomIcon(room); - const handleRedirect = (): void => roomCoordinator.openRouteLink(room.t, { rid: room._id, ...room }); + const handleRedirect = (): void => { + if (!roomCoordinator.getRoomDirectives(room.t).hasSubscription(room._id)) { + return; + } + roomCoordinator.openRouteLink(room.t, { rid: room._id, ...room }); + }; return ( { - const { prid } = room; +const getParentId = ({ prid, teamId }: IRoom): string => { + if (prid) { + return prid; + } - if (!prid) { - throw new Error('Parent room ID is missing'); + if (teamId) { + return teamId; } - const subscription = useUserSubscription(prid); + throw new Error('Parent room ID is missing'); +}; + +const ParentRoomWithData = ({ room }: ParentRoomWithDataProps) => { + const parentId = getParentId(room); + const subscription = useUserSubscription(parentId); if (subscription) { - return ; + return ; } - return ; + return ; }; export default ParentRoomWithData; diff --git a/apps/meteor/client/views/room/HeaderV2/ParentRoomWithEndpointData.tsx b/apps/meteor/client/views/room/HeaderV2/ParentRoomWithEndpointData.tsx index 89d0ea1f8220..6345dd54fe68 100644 --- a/apps/meteor/client/views/room/HeaderV2/ParentRoomWithEndpointData.tsx +++ b/apps/meteor/client/views/room/HeaderV2/ParentRoomWithEndpointData.tsx @@ -4,6 +4,7 @@ import React from 'react'; import { HeaderTagSkeleton } from '../../../components/Header'; import { useRoomInfoEndpoint } from '../../../hooks/useRoomInfoEndpoint'; import ParentRoom from './ParentRoom'; +import ParentTeam from './ParentTeam'; type ParentRoomWithEndpointDataProps = { rid: IRoom['_id']; @@ -20,6 +21,18 @@ const ParentRoomWithEndpointData = ({ rid }: ParentRoomWithEndpointDataProps) => return null; } + if (data.parent) { + return ; + } + + if (data.team) { + if (data.team.roomId === rid) { + return null; + } + + return ; + } + return ; }; diff --git a/apps/meteor/client/views/room/HeaderV2/ParentTeam.tsx b/apps/meteor/client/views/room/HeaderV2/ParentTeam.tsx index 2f8bfa57c566..1381aef14014 100644 --- a/apps/meteor/client/views/room/HeaderV2/ParentTeam.tsx +++ b/apps/meteor/client/views/room/HeaderV2/ParentTeam.tsx @@ -1,53 +1,27 @@ -import type { IRoom } from '@rocket.chat/core-typings'; +import type { ITeam } from '@rocket.chat/core-typings'; import { TEAM_TYPE } from '@rocket.chat/core-typings'; -import { useUserId, useEndpoint } from '@rocket.chat/ui-contexts'; -import { useQuery } from '@tanstack/react-query'; +import { useUserSubscription } from '@rocket.chat/ui-contexts'; +import type { ReactElement } from 'react'; import React from 'react'; -import { HeaderTag, HeaderTagIcon, HeaderTagSkeleton } from '../../../components/Header'; +import { HeaderTag, HeaderTagIcon } from '../../../components/Header'; import { goToRoomById } from '../../../lib/utils/goToRoomById'; -type APIErrorResult = { success: boolean; error: string }; +const ParentTeam = ({ team }: { team: Pick }): ReactElement | null => { + const isTeamPublic = team.type === TEAM_TYPE.PUBLIC; -type ParentTeamProps = { - room: IRoom; -}; - -const ParentTeam = ({ room }: ParentTeamProps) => { - const { teamId } = room; - const userId = useUserId(); - - if (!teamId) { - throw new Error('invalid rid'); - } - - if (!userId) { - throw new Error('invalid uid'); - } - - const teamsInfoEndpoint = useEndpoint('GET', '/v1/teams.info'); - const userTeamsListEndpoint = useEndpoint('GET', '/v1/users.listTeams'); - - const { - data: teamInfoData, - isLoading: teamInfoLoading, - isError: teamInfoError, - } = useQuery(['teamId', teamId], async () => teamsInfoEndpoint({ teamId }), { - keepPreviousData: true, - retry: (_, error) => (error as APIErrorResult)?.error === 'unauthorized' && false, - }); - - const { data: userTeams, isLoading: userTeamsLoading } = useQuery(['userId', userId], async () => userTeamsListEndpoint({ userId })); - - const userBelongsToTeam = userTeams?.teams?.find((team) => team._id === teamId) || false; - const isTeamPublic = teamInfoData?.teamInfo.type === TEAM_TYPE.PUBLIC; + const subscription = useUserSubscription(team.roomId); const redirectToMainRoom = (): void => { - const rid = teamInfoData?.teamInfo.roomId; + const rid = team.roomId; if (!rid) { return; } + const isTeamPublic = team.type === TEAM_TYPE.PUBLIC; + + const userBelongsToTeam = !!subscription; + if (!(isTeamPublic || userBelongsToTeam)) { return; } @@ -55,14 +29,6 @@ const ParentTeam = ({ room }: ParentTeamProps) => { goToRoomById(rid); }; - if (teamInfoLoading || userTeamsLoading) { - return ; - } - - if (teamInfoError) { - return null; - } - return ( { onClick={redirectToMainRoom} > - {teamInfoData?.teamInfo.name} + + {team.name} ); }; diff --git a/apps/meteor/client/views/room/HeaderV2/RoomHeader.tsx b/apps/meteor/client/views/room/HeaderV2/RoomHeader.tsx index 8ef21aecf0cd..9a4ca3b7135f 100644 --- a/apps/meteor/client/views/room/HeaderV2/RoomHeader.tsx +++ b/apps/meteor/client/views/room/HeaderV2/RoomHeader.tsx @@ -45,8 +45,7 @@ const RoomHeader = ({ room, slots = {}, roomToolbox }: RoomHeaderProps) => { - {room.prid && } - {room.teamId && !room.teamMain && } + {(room.prid || room.teamId) && } {isRoomFederated(room) && } diff --git a/apps/meteor/definition/IRoomTypeConfig.ts b/apps/meteor/definition/IRoomTypeConfig.ts index 12a4bea39f05..83c0c28053c5 100644 --- a/apps/meteor/definition/IRoomTypeConfig.ts +++ b/apps/meteor/definition/IRoomTypeConfig.ts @@ -86,6 +86,7 @@ export interface IRoomTypeClientDirectives { showJoinLink: (roomId: string) => boolean; isLivechatRoom: () => boolean; canSendMessage: (rid: string) => boolean; + hasSubscription: (rid: string) => boolean; readOnly?: (rid: string, user: AtLeast) => boolean; } From e8f034f9e1b1435f6fa91f9b94ac5dcebc8b8f7d Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 2 Sep 2024 12:06:58 -0600 Subject: [PATCH 2/5] Create twenty-spiders-do.md --- .changeset/twenty-spiders-do.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/twenty-spiders-do.md diff --git a/.changeset/twenty-spiders-do.md b/.changeset/twenty-spiders-do.md new file mode 100644 index 000000000000..26a165e7edae --- /dev/null +++ b/.changeset/twenty-spiders-do.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Show `parent` and `team` information on the header of rooms From 6755ba2c538e794c662b308d3e9fab57f0adfc4b Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Fri, 6 Sep 2024 08:12:49 -0600 Subject: [PATCH 3/5] Update RoomHeader.tsx --- apps/meteor/client/views/room/Header/RoomHeader.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/meteor/client/views/room/Header/RoomHeader.tsx b/apps/meteor/client/views/room/Header/RoomHeader.tsx index b2aeca55885b..34a6299068fa 100644 --- a/apps/meteor/client/views/room/Header/RoomHeader.tsx +++ b/apps/meteor/client/views/room/Header/RoomHeader.tsx @@ -8,7 +8,6 @@ import { Header, HeaderAvatar, HeaderContent, HeaderContentRow, HeaderSubtitle, import MarkdownText from '../../../components/MarkdownText'; import FederatedRoomOriginServer from './FederatedRoomOriginServer'; import ParentRoomWithData from './ParentRoomWithData'; -import ParentTeam from './ParentTeam'; import RoomTitle from './RoomTitle'; import RoomToolbox from './RoomToolbox'; import Encrypted from './icons/Encrypted'; From 07a746f8738755b6c1f292ce179a7212e0388471 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Fri, 6 Sep 2024 08:13:07 -0600 Subject: [PATCH 4/5] Update RoomHeader.tsx --- apps/meteor/client/views/room/HeaderV2/RoomHeader.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/meteor/client/views/room/HeaderV2/RoomHeader.tsx b/apps/meteor/client/views/room/HeaderV2/RoomHeader.tsx index 9a4ca3b7135f..07c6f1713fec 100644 --- a/apps/meteor/client/views/room/HeaderV2/RoomHeader.tsx +++ b/apps/meteor/client/views/room/HeaderV2/RoomHeader.tsx @@ -7,7 +7,6 @@ import React, { Suspense } from 'react'; import { Header, HeaderAvatar, HeaderContent, HeaderContentRow, HeaderToolbar } from '../../../components/Header'; import FederatedRoomOriginServer from './FederatedRoomOriginServer'; import ParentRoomWithData from './ParentRoomWithData'; -import ParentTeam from './ParentTeam'; import RoomTitle from './RoomTitle'; import RoomToolbox from './RoomToolbox'; import Encrypted from './icons/Encrypted'; From e04123a9ef4cf61bab0bbae22fdb72ec040e93cb Mon Sep 17 00:00:00 2001 From: juliajforesti Date: Mon, 7 Oct 2024 11:19:16 -0300 Subject: [PATCH 5/5] review: ad condition to tag click when cannot redirect --- .../meteor/client/views/room/Header/ParentRoom.tsx | 14 +++++++------- .../client/views/room/HeaderV2/ParentRoom.tsx | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/meteor/client/views/room/Header/ParentRoom.tsx b/apps/meteor/client/views/room/Header/ParentRoom.tsx index bbe2ec1e2652..3eb393474bf3 100644 --- a/apps/meteor/client/views/room/Header/ParentRoom.tsx +++ b/apps/meteor/client/views/room/Header/ParentRoom.tsx @@ -10,21 +10,21 @@ type ParentRoomProps = { room: Pick; }; +const hasSubscription = (room: ParentRoomProps['room']): boolean => roomCoordinator.getRoomDirectives(room.t).hasSubscription(room._id); const ParentRoom = ({ room }: ParentRoomProps): ReactElement => { const icon = useRoomIcon(room); - const handleRedirect = (): void => { - if (!roomCoordinator.getRoomDirectives(room.t).hasSubscription(room._id)) { - return; - } - roomCoordinator.openRouteLink(room.t, { rid: room._id, ...room }); - }; + const handleRedirect = hasSubscription(room) + ? (): void => { + roomCoordinator.openRouteLink(room.t, { rid: room._id, ...room }); + } + : undefined; return ( (e.code === 'Space' || e.code === 'Enter') && handleRedirect()} + onKeyDown={(e) => (e.code === 'Space' || e.code === 'Enter') && handleRedirect?.()} onClick={handleRedirect} > diff --git a/apps/meteor/client/views/room/HeaderV2/ParentRoom.tsx b/apps/meteor/client/views/room/HeaderV2/ParentRoom.tsx index 24f3d9e0bf14..f56d81a07d87 100644 --- a/apps/meteor/client/views/room/HeaderV2/ParentRoom.tsx +++ b/apps/meteor/client/views/room/HeaderV2/ParentRoom.tsx @@ -9,21 +9,21 @@ type ParentRoomProps = { room: Pick; }; +const hasSubscription = (room: ParentRoomProps['room']): boolean => roomCoordinator.getRoomDirectives(room.t).hasSubscription(room._id); const ParentRoom = ({ room }: ParentRoomProps) => { const icon = useRoomIcon(room); - const handleRedirect = (): void => { - if (!roomCoordinator.getRoomDirectives(room.t).hasSubscription(room._id)) { - return; - } - roomCoordinator.openRouteLink(room.t, { rid: room._id, ...room }); - }; + const handleRedirect = hasSubscription(room) + ? (): void => { + roomCoordinator.openRouteLink(room.t, { rid: room._id, ...room }); + } + : undefined; return ( (e.code === 'Space' || e.code === 'Enter') && handleRedirect()} + onKeyDown={(e) => (e.code === 'Space' || e.code === 'Enter') && handleRedirect?.()} onClick={handleRedirect} >