import React, { useEffect, useRef, useState } from 'react'; import { useSessionStorage } from 'react-use'; import { match } from 'ts-pattern'; import { v4 as uuid } from 'uuid'; import { HMSException, useHMSActions } from '@100mslive/react-sdk'; import { Dialog } from '../../Modal'; import { Text } from '../../Text'; import { useHMSPrebuiltContext } from '../AppContext'; import { PrebuiltStates } from '../AppStateContext'; // @ts-ignore: No implicit Any import errorImage from '../images/transaction_error.svg'; // @ts-ignore: No implicit Any import { useSetAppDataByKey } from './AppData/useUISettings'; // @ts-ignore: No implicit Any import { UserPreferencesKeys } from './hooks/useUserPreferences'; import { APP_DATA } from '../common/constants'; /** * query params exposed - * skip_preview=true => used by recording and streaming service, skips preview and directly joins * header and footer don't show up in this case * skip_preview_headful=true => used by automation testing to skip preview without impacting the UI * name=abc => gives the initial name for the peer joining * auth_token=123 => uses the passed in token to join instead of fetching from token endpoint * ui_mode=activespeaker => lands in active speaker mode after joining the room */ const AuthToken = React.memo<{ authTokenByRoomCodeEndpoint?: string; defaultAuthToken?: string; activeState?: PrebuiltStates; }>(({ authTokenByRoomCodeEndpoint, defaultAuthToken, activeState }) => { const hmsActions = useHMSActions(); const { roomCode, userId } = useHMSPrebuiltContext(); const [error, setError] = useState({ title: '', body: '' }); const authToken = defaultAuthToken; const [tokenInAppData, setAuthTokenInAppData] = useSetAppDataByKey(APP_DATA.authToken); const [savedUserId, setSavedUserId] = useSessionStorage(UserPreferencesKeys.USER_ID); const progressRef = useRef(null); useEffect(() => { if (authToken) { setAuthTokenInAppData(authToken); return; } if (tokenInAppData || progressRef.current || activeState === PrebuiltStates.LEAVE) { return; } if (!roomCode) { console.error('room code not provided'); return; } let userIdForAuthToken = userId || savedUserId; if (!userIdForAuthToken) { userIdForAuthToken = uuid(); setSavedUserId(userIdForAuthToken); } progressRef.current = true; hmsActions .getAuthTokenByRoomCode({ roomCode, userId: userIdForAuthToken }, { endpoint: authTokenByRoomCodeEndpoint }) .then(token => setAuthTokenInAppData(token)) .catch(error => setError(convertError(error))) .finally(() => { progressRef.current = false; }); }, [ hmsActions, authToken, authTokenByRoomCodeEndpoint, setAuthTokenInAppData, roomCode, userId, savedUserId, tokenInAppData, setSavedUserId, activeState, ]); if (error.title) { return ( Token Error {error.title} {error.body} ); } return null; }); const convertError = (error: HMSException) => { console.error('[error]', { error }); console.warn( 'If you think this is a mistake on our side, please reach out to us on Dashboard:', 'https://dashboard.100ms.live/dashboard', ); return match([error.action, error.code]) .with(['GET_TOKEN', 403], () => ({ title: 'Psst! This room is currently inactive.', body: 'Please feel free to join another open room for more conversations. Thanks for stopping by!', })) .with(['GET_TOKEN', 404], () => ({ title: 'Room code does not exist', body: 'We could not find a room code corresponding to this link.', })) .with(['GET_TOKEN', 2003], () => ({ title: 'Endpoint is not reachable', body: `Endpoint is not reachable. ${error.description}.`, })) .otherwise(() => // @ts-ignore match(error.response?.status) .with(404, () => ({ title: 'Room does not exist', body: 'We could not find a room corresponding to this link.', })) .with(403, () => ({ title: 'Accessing room using this link format is disabled', body: 'You can re-enable this from the developer section in Dashboard.', })) .otherwise(() => { console.error('Token API Error', error); return { title: 'Error fetching token', body: 'An error occurred while fetching the app token. Please look into logs for more details.', }; }), ); }; export default AuthToken;