bigbluebutton-Github/bigbluebutton-html5/imports/ui/components/join-handler/presenceManager/component.tsx
João Victor Nunes 06500be757
refactor(storage): replace Tracker.Dependency with observer hook (#20322)
* refactor(storage): replace Tracker.Dependency with observer hook

* fix(storage): set initial value

* refactor(storage): stop using Meteor's Session singleton
2024-06-06 10:50:03 -03:00

264 lines
7.1 KiB
TypeScript

import { useMutation, useQuery } from '@apollo/client';
import React, { useContext, useEffect, useState } from 'react';
import Session from '/imports/ui/services/storage/in-memory';
import {
getUserCurrent,
GetUserCurrentResponse,
getUserInfo,
GetUserInfoResponse,
userJoinMutation,
} from './queries';
import { setAuthData } from '/imports/ui/core/local-states/useAuthData';
import MeetingEndedContainer from '../../meeting-ended/component';
import { setUserDataToSessionStorage } from './service';
import { LoadingContext } from '../../common/loading-screen/loading-screen-HOC/component';
import useDeduplicatedSubscription from '/imports/ui/core/hooks/useDeduplicatedSubscription';
import logger from '/imports/startup/client/logger';
import deviceInfo from '/imports/utils/deviceInfo';
import GuestWaitContainer, { GUEST_STATUSES } from '../guest-wait/component';
const connectionTimeout = 60000;
const MESSAGE_TIMEOUT = 3000;
interface PresenceManagerContainerProps {
children: React.ReactNode;
}
interface PresenceManagerProps extends PresenceManagerContainerProps {
authToken: string;
logoutUrl: string;
meetingId: string;
meetingName: string;
userName: string;
extId: string;
userId: string;
joinErrorCode: string;
joinErrorMessage: string;
joined: boolean;
meetingEnded: boolean;
endedReasonCode: string;
endedBy: string;
ejectReasonCode: string;
bannerColor: string;
bannerText: string;
customLogoUrl: string;
loggedOut: boolean;
guestStatus: string;
guestLobbyMessage: string | null;
positionInWaitingQueue: number | null;
}
const PresenceManager: React.FC<PresenceManagerProps> = ({
authToken,
children,
logoutUrl,
meetingId,
meetingName,
userName,
extId,
userId,
joinErrorCode,
joinErrorMessage,
joined,
meetingEnded,
endedReasonCode,
endedBy,
ejectReasonCode,
bannerColor,
bannerText,
customLogoUrl,
loggedOut,
guestLobbyMessage,
guestStatus,
positionInWaitingQueue,
}) => {
const [allowToRender, setAllowToRender] = React.useState(false);
const [dispatchUserJoin] = useMutation(userJoinMutation);
const timeoutRef = React.useRef<ReturnType<typeof setTimeout>>();
const loadingContextInfo = useContext(LoadingContext);
const [isGuestAllowed, setIsGuestAllowed] = useState(guestStatus === GUEST_STATUSES.ALLOW);
useEffect(() => {
const allowed = guestStatus === GUEST_STATUSES.ALLOW;
if (allowed) {
setTimeout(() => {
setIsGuestAllowed(true);
}, MESSAGE_TIMEOUT);
} else {
setIsGuestAllowed(false);
}
}, [guestStatus]);
useEffect(() => {
const urlParams = new URLSearchParams(window.location.search);
const sessionToken = urlParams.get('sessionToken') as string;
setAuthData({
meetingId,
userId,
authToken,
logoutUrl,
sessionToken,
userName,
extId,
meetingName,
});
setUserDataToSessionStorage({
meetingId,
userId,
authToken,
logoutUrl,
sessionToken,
userName,
extId,
meetingName,
customLogoUrl,
});
}, []);
useEffect(() => {
if (isGuestAllowed) {
timeoutRef.current = setTimeout(() => {
loadingContextInfo.setLoading(false, '');
throw new Error('Authentication timeout');
}, connectionTimeout);
}
}, [isGuestAllowed]);
useEffect(() => {
if (bannerColor || bannerText) {
Session.setItem('bannerText', bannerText);
Session.setItem('bannerColor', bannerColor);
}
}, [bannerColor, bannerText]);
useEffect(() => {
if (authToken && !joined && isGuestAllowed) {
dispatchUserJoin({
variables: {
authToken,
clientType: 'HTML5',
clientIsMobile: deviceInfo.isMobile,
},
});
}
}, [joined, authToken, isGuestAllowed]);
useEffect(() => {
if (joined) {
clearTimeout(timeoutRef.current);
setAllowToRender(true);
}
}, [joined]);
useEffect(() => {
if (joinErrorCode) {
loadingContextInfo.setLoading(false, '');
}
},
[joinErrorCode, joinErrorMessage]);
const errorCode = loggedOut ? 'user_logged_out_reason' : joinErrorCode || ejectReasonCode;
return (
<>
{allowToRender && !(meetingEnded || joinErrorCode || ejectReasonCode || loggedOut) ? children : null}
{
meetingEnded || joinErrorCode || ejectReasonCode || loggedOut
? (
<MeetingEndedContainer
meetingEndedCode={endedReasonCode}
endedBy={endedBy}
joinErrorCode={errorCode}
/>
)
: null
}
{
!isGuestAllowed && !(meetingEnded || joinErrorCode || ejectReasonCode || loggedOut)
? (
<GuestWaitContainer
guestLobbyMessage={guestLobbyMessage}
guestStatus={guestStatus}
logoutUrl={logoutUrl}
positionInWaitingQueue={positionInWaitingQueue}
/>
)
: null
}
</>
);
};
const PresenceManagerContainer: React.FC<PresenceManagerContainerProps> = ({ children }) => {
const { loading, error, data } = useDeduplicatedSubscription<GetUserCurrentResponse>(getUserCurrent);
const {
loading: userInfoLoading,
error: userInfoError,
data: userInfoData,
} = useQuery<GetUserInfoResponse>(getUserInfo);
const loadingContextInfo = useContext(LoadingContext);
if (loading || userInfoLoading) return null;
if (error || userInfoError) {
loadingContextInfo.setLoading(false, '');
logger.debug(`Error on user authentication: ${error}`);
throw new Error('Error on user authentication');
}
if (!data || data.user_current.length === 0) return null;
if (!userInfoData
|| userInfoData.meeting.length === 0
|| userInfoData.user_current.length === 0) return null;
const {
authToken,
joinErrorCode,
joinErrorMessage,
joined,
ejectReasonCode,
meeting,
loggedOut,
guestStatusDetails,
guestStatus,
} = data.user_current[0];
const {
logoutUrl,
meetingId,
name: meetingName,
bannerColor,
bannerText,
customLogoUrl,
} = userInfoData.meeting[0];
const { extId, name: userName, userId } = userInfoData.user_current[0];
return (
<PresenceManager
authToken={authToken}
logoutUrl={logoutUrl}
meetingId={meetingId}
meetingName={meetingName}
userName={userName}
extId={extId}
userId={userId}
joined={joined}
joinErrorCode={joinErrorCode}
joinErrorMessage={joinErrorMessage}
meetingEnded={meeting.ended}
endedReasonCode={meeting.endedReasonCode}
endedBy={meeting.endedByUserName}
ejectReasonCode={ejectReasonCode}
bannerColor={bannerColor}
bannerText={bannerText}
loggedOut={loggedOut}
customLogoUrl={customLogoUrl}
guestLobbyMessage={guestStatusDetails?.guestLobbyMessage ?? null}
positionInWaitingQueue={guestStatusDetails?.positionInWaitingQueue ?? null}
guestStatus={guestStatus}
>
{children}
</PresenceManager>
);
};
export default PresenceManagerContainer;