diff --git a/apps/meteor/client/hooks/useTeamInfoQuery.ts b/apps/meteor/client/hooks/useTeamInfoQuery.ts new file mode 100644 index 0000000000000..4044a65a60d39 --- /dev/null +++ b/apps/meteor/client/hooks/useTeamInfoQuery.ts @@ -0,0 +1,26 @@ +import type { ITeam, Serialized } from '@rocket.chat/core-typings'; +import { useEndpoint } from '@rocket.chat/ui-contexts'; +import type { UseQueryOptions } from '@tanstack/react-query'; +import { keepPreviousData, useQuery } from '@tanstack/react-query'; + +import { teamsQueryKeys } from '../lib/queryKeys'; + +type TeamInfoQueryOptions>> = Omit< + UseQueryOptions>, Error, TData, ReturnType>, + 'queryKey' | 'queryFn' +>; + +export const useTeamInfoQuery = >>(teamId: string, options: TeamInfoQueryOptions = {}) => { + const teamsInfoEndpoint = useEndpoint('GET', '/v1/teams.info'); + + return useQuery({ + queryKey: teamsQueryKeys.teamInfo(teamId), + queryFn: async () => { + const result = await teamsInfoEndpoint({ teamId }); + return result.teamInfo; + }, + placeholderData: keepPreviousData, + enabled: teamId !== '', + ...options, + }); +}; diff --git a/apps/meteor/client/lib/queryKeys.ts b/apps/meteor/client/lib/queryKeys.ts index ea54fabadae8d..7d7db6163f833 100644 --- a/apps/meteor/client/lib/queryKeys.ts +++ b/apps/meteor/client/lib/queryKeys.ts @@ -104,6 +104,8 @@ export const usersQueryKeys = { export const teamsQueryKeys = { all: ['teams'] as const, team: (teamId: ITeam['_id']) => [...teamsQueryKeys.all, teamId] as const, + teamInfo: (teamId: ITeam['_id']) => [...teamsQueryKeys.team(teamId), 'info'] as const, roomsOfUser: (teamId: ITeam['_id'], userId: IUser['_id'], options?: { canUserDelete: boolean }) => [...teamsQueryKeys.team(teamId), 'rooms-of-user', userId, options] as const, + listUserTeams: (userId: IUser['_id']) => [...teamsQueryKeys.all, 'listUserTeams', userId] as const, }; diff --git a/apps/meteor/client/views/hooks/roomActions/useDeleteRoom.tsx b/apps/meteor/client/views/hooks/roomActions/useDeleteRoom.tsx index b7343d0acc16b..155097874efdc 100644 --- a/apps/meteor/client/views/hooks/roomActions/useDeleteRoom.tsx +++ b/apps/meteor/client/views/hooks/roomActions/useDeleteRoom.tsx @@ -3,9 +3,10 @@ import { isRoomFederated } from '@rocket.chat/core-typings'; import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { GenericModal } from '@rocket.chat/ui-client'; import { useSetModal, useToastMessageDispatch, useRouter, usePermission, useEndpoint } from '@rocket.chat/ui-contexts'; -import { keepPreviousData, useMutation, useQuery } from '@tanstack/react-query'; +import { useMutation } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; +import { useTeamInfoQuery } from '../../../hooks/useTeamInfoQuery'; import DeleteTeamModal from '../../teams/contextualBar/info/DeleteTeam'; export const useDeleteRoom = (room: IRoom | Pick, { reload }: { reload?: () => void } = {}) => { @@ -19,19 +20,12 @@ export const useDeleteRoom = (room: IRoom | Pick, { const deleteRoomEndpoint = useEndpoint('POST', '/v1/rooms.delete'); const deleteTeamEndpoint = useEndpoint('POST', '/v1/teams.delete'); - const teamsInfoEndpoint = useEndpoint('GET', '/v1/teams.info'); const teamId = room.teamId || ''; - const { data: teamInfoData } = useQuery({ - queryKey: ['teamId', teamId], - queryFn: async () => teamsInfoEndpoint({ teamId }), - placeholderData: keepPreviousData, - retry: false, - enabled: room.teamId !== '', - }); + const { data: teamInfo } = useTeamInfoQuery(teamId); const hasPermissionToDeleteRoom = usePermission(`delete-${room.t}`, room._id); - const hasPermissionToDeleteTeamRoom = usePermission(`delete-team-${room.t === 'c' ? 'channel' : 'group'}`, teamInfoData?.teamInfo.roomId); + const hasPermissionToDeleteTeamRoom = usePermission(`delete-team-${room.t === 'c' ? 'channel' : 'group'}`, teamInfo?.roomId); const isTeamRoom = room.teamId; const canDeleteRoom = isRoomFederated(room) ? false : hasPermissionToDeleteRoom && (!isTeamRoom || hasPermissionToDeleteTeamRoom); diff --git a/apps/meteor/client/views/room/Header/ParentTeam.tsx b/apps/meteor/client/views/room/Header/ParentTeam.tsx index 726657c23e9ad..009362a3391f8 100644 --- a/apps/meteor/client/views/room/Header/ParentTeam.tsx +++ b/apps/meteor/client/views/room/Header/ParentTeam.tsx @@ -1,12 +1,13 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { TEAM_TYPE } from '@rocket.chat/core-typings'; import { useButtonPattern } from '@rocket.chat/fuselage-hooks'; -import { useUserId, useEndpoint } from '@rocket.chat/ui-contexts'; -import { keepPreviousData, useQuery } from '@tanstack/react-query'; +import { useUserId } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; import { HeaderTag, HeaderTagIcon, HeaderTagSkeleton } from '../../../components/Header'; +import { useTeamInfoQuery } from '../../../hooks/useTeamInfoQuery'; import { goToRoomById } from '../../../lib/utils/goToRoomById'; +import { useUserTeamsQuery } from '../hooks/useUserTeamsQuery'; type APIErrorResult = { success: boolean; error: string }; @@ -22,30 +23,19 @@ const ParentTeam = ({ room }: { room: IRoom }): ReactElement | null => { throw new Error('invalid uid'); } - const teamsInfoEndpoint = useEndpoint('GET', '/v1/teams.info'); - const userTeamsListEndpoint = useEndpoint('GET', '/v1/users.listTeams'); - const { - data: teamInfoData, + data: teamInfo, isLoading: teamInfoLoading, isError: teamInfoError, - } = useQuery({ - queryKey: ['teamId', teamId], - queryFn: async () => teamsInfoEndpoint({ teamId }), - placeholderData: keepPreviousData, - retry: (_, error: APIErrorResult) => error?.error === 'unauthorized' && false, - }); + } = useTeamInfoQuery(teamId, { retry: (_, error) => (error as unknown as APIErrorResult)?.error !== 'unauthorized' }); - const { data: userTeams, isLoading: userTeamsLoading } = useQuery({ - queryKey: ['userId', userId], - queryFn: async () => userTeamsListEndpoint({ userId }), - }); + const { data: userTeams, isLoading: userTeamsLoading } = useUserTeamsQuery(userId); - const userBelongsToTeam = userTeams?.teams?.find((team) => team._id === teamId) || false; - const isTeamPublic = teamInfoData?.teamInfo.type === TEAM_TYPE.PUBLIC; + const userBelongsToTeam = userTeams?.find((team) => team._id === teamId) || false; + const isTeamPublic = teamInfo?.type === TEAM_TYPE.PUBLIC; const redirectToMainRoom = (): void => { - const rid = teamInfoData?.teamInfo.roomId; + const rid = teamInfo?.roomId; if (!rid) { return; } @@ -70,7 +60,7 @@ const ParentTeam = ({ room }: { room: IRoom }): ReactElement | null => { return ( - {teamInfoData?.teamInfo.name} + {teamInfo?.name} ); }; diff --git a/apps/meteor/client/views/room/HeaderV2/ParentRoom/ParentTeam.tsx b/apps/meteor/client/views/room/HeaderV2/ParentRoom/ParentTeam.tsx index 9c9460f0a4820..722fece0605c5 100644 --- a/apps/meteor/client/views/room/HeaderV2/ParentRoom/ParentTeam.tsx +++ b/apps/meteor/client/views/room/HeaderV2/ParentRoom/ParentTeam.tsx @@ -1,11 +1,12 @@ import type { IRoom } from '@rocket.chat/core-typings'; import { TEAM_TYPE } from '@rocket.chat/core-typings'; -import { useUserId, useEndpoint } from '@rocket.chat/ui-contexts'; -import { keepPreviousData, useQuery } from '@tanstack/react-query'; +import { useUserId } from '@rocket.chat/ui-contexts'; import { useTranslation } from 'react-i18next'; import ParentRoomButton from './ParentRoomButton'; +import { useTeamInfoQuery } from '../../../../hooks/useTeamInfoQuery'; import { goToRoomById } from '../../../../lib/utils/goToRoomById'; +import { useUserTeamsQuery } from '../../hooks/useUserTeamsQuery'; type APIErrorResult = { success: boolean; error: string }; @@ -27,31 +28,20 @@ const ParentTeam = ({ room }: ParentTeamProps) => { throw new Error('invalid uid'); } - const teamsInfoEndpoint = useEndpoint('GET', '/v1/teams.info'); - const userTeamsListEndpoint = useEndpoint('GET', '/v1/users.listTeams'); - const { - data: teamInfoData, + data: teamInfo, isLoading: teamInfoLoading, isError: teamInfoError, - } = useQuery({ - queryKey: ['teamId', teamId], - queryFn: async () => teamsInfoEndpoint({ teamId }), - placeholderData: keepPreviousData, - retry: (_, error: APIErrorResult) => error?.error === 'unauthorized' && false, - }); + } = useTeamInfoQuery(teamId, { retry: (_, error) => (error as unknown as APIErrorResult)?.error !== 'unauthorized' }); - const { data: userTeams, isLoading: userTeamsLoading } = useQuery({ - queryKey: ['userId', userId], - queryFn: async () => userTeamsListEndpoint({ userId }), - }); + const { data: userTeams, isLoading: userTeamsLoading } = useUserTeamsQuery(userId); - const userBelongsToTeam = Boolean(userTeams?.teams?.find((team) => team._id === teamId)) || false; - const isPublicTeam = teamInfoData?.teamInfo.type === TEAM_TYPE.PUBLIC; + const userBelongsToTeam = Boolean(userTeams?.find((team) => team._id === teamId)) || false; + const isPublicTeam = teamInfo?.type === TEAM_TYPE.PUBLIC; const shouldDisplayTeam = isPublicTeam || userBelongsToTeam; const redirectToMainRoom = (): void => { - const rid = teamInfoData?.teamInfo.roomId; + const rid = teamInfo?.roomId; if (!rid) { return; } @@ -67,7 +57,7 @@ const ParentTeam = ({ room }: ParentTeamProps) => { ); }; diff --git a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomPermissions.ts b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomPermissions.ts index 1f0d11046eeda..92a1426b13dac 100644 --- a/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomPermissions.ts +++ b/apps/meteor/client/views/room/contextualBar/Info/EditRoomInfo/useEditRoomPermissions.ts @@ -1,10 +1,10 @@ import type { IRoom, IRoomWithRetentionPolicy } from '@rocket.chat/core-typings'; -import { usePermission, useAtLeastOnePermission, useRole, useEndpoint } from '@rocket.chat/ui-contexts'; -import { keepPreviousData, useQuery } from '@tanstack/react-query'; +import { usePermission, useAtLeastOnePermission, useRole } from '@rocket.chat/ui-contexts'; import { useMemo } from 'react'; import { E2EEState } from '../../../../../../app/e2e/client/E2EEState'; import { RoomSettingsEnum } from '../../../../../../definition/IRoomTypeConfig'; +import { useTeamInfoQuery } from '../../../../../hooks/useTeamInfoQuery'; import { roomCoordinator } from '../../../../../lib/rooms/roomCoordinator'; import { useE2EEState } from '../../../hooks/useE2EEState'; @@ -17,19 +17,12 @@ export const useEditRoomPermissions = (room: IRoom | IRoomWithRetentionPolicy) = const isE2EEReady = e2eeState === E2EEState.READY || e2eeState === E2EEState.SAVE_PASSWORD; const canCreateChannel = usePermission('create-c'); const canCreateGroup = usePermission('create-p'); - const teamsInfoEndpoint = useEndpoint('GET', '/v1/teams.info'); const teamId = room.teamId || ''; - const { data: teamInfoData } = useQuery({ - queryKey: ['teamId', teamId], - queryFn: async () => teamsInfoEndpoint({ teamId }), - placeholderData: keepPreviousData, - retry: false, - enabled: room.teamId !== '', - }); + const { data: teamInfo } = useTeamInfoQuery(teamId); - const canCreateTeamChannel = usePermission('create-team-channel', teamInfoData?.teamInfo.roomId); - const canCreateTeamGroup = usePermission('create-team-group', teamInfoData?.teamInfo.roomId); + const canCreateTeamChannel = usePermission('create-team-channel', teamInfo?.roomId); + const canCreateTeamGroup = usePermission('create-team-group', teamInfo?.roomId); const canChangeType = getCanChangeType( room, diff --git a/apps/meteor/client/views/room/hooks/useUserTeamsQuery.ts b/apps/meteor/client/views/room/hooks/useUserTeamsQuery.ts new file mode 100644 index 0000000000000..cd9a4859f9d8c --- /dev/null +++ b/apps/meteor/client/views/room/hooks/useUserTeamsQuery.ts @@ -0,0 +1,24 @@ +import type { ITeam, Serialized } from '@rocket.chat/core-typings'; +import { useEndpoint } from '@rocket.chat/ui-contexts'; +import type { UseQueryOptions } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; + +import { teamsQueryKeys } from '../../../lib/queryKeys'; + +type UserTeamsQueryOptions = Omit< + UseQueryOptions, Error, TData, ReturnType>, + 'queryKey' | 'queryFn' +>; + +export const useUserTeamsQuery = (userId: string, options: UserTeamsQueryOptions = {}) => { + const userTeamsListEndpoint = useEndpoint('GET', '/v1/users.listTeams'); + + return useQuery({ + queryKey: teamsQueryKeys.listUserTeams(userId), + queryFn: async () => { + const response = await userTeamsListEndpoint({ userId }); + return response.teams; + }, + ...options, + }); +};