import { useIsFocused } from "@react-navigation/native"; import React, { useCallback, useEffect, useLayoutEffect, useMemo, useState, } from "react"; import { useTranslation } from "react-i18next"; import { BackHandler, Platform, StyleProp, Text, TextStyle, View, ViewStyle, } from "react-native"; import { useDispatch, useSelector } from "react-redux"; import { setPermanentProperty } from "../../../analytics/actions"; import { appNavigate } from "../../../app/actions.native"; import { IReduxState } from "../../../app/types"; import { setAudioOnly } from "../../../base/audio-only/actions"; import { getConferenceName } from "../../../base/conference/functions"; import { isNameReadOnly } from "../../../base/config/functions.any"; import { connect } from "../../../base/connection/actions.native"; import { PREJOIN_PAGE_HIDE_DISPLAY_NAME } from "../../../base/flags/constants"; import { getFeatureFlag } from "../../../base/flags/functions"; import { IconCloseLarge } from "../../../base/icons/svg"; import JitsiScreen from "../../../base/modal/components/JitsiScreen"; import { getLocalParticipant } from "../../../base/participants/functions"; import { getFieldValue } from "../../../base/react/functions"; import { ASPECT_RATIO_NARROW } from "../../../base/responsive-ui/constants"; import { updateSettings } from "../../../base/settings/actions"; import Button from "../../../base/ui/components/native/Button"; import Input from "../../../base/ui/components/native/Input"; import { BUTTON_TYPES } from "../../../base/ui/constants.native"; import { openDisplayNamePrompt } from "../../../display-name/actions"; import BrandingImageBackground from "../../../dynamic-branding/components/native/BrandingImageBackground"; import LargeVideo from "../../../large-video/components/LargeVideo.native"; import HeaderNavigationButton from "../../../mobile/navigation/components/HeaderNavigationButton"; import { navigateRoot } from "../../../mobile/navigation/rootNavigationContainerRef"; import { screen } from "../../../mobile/navigation/routes"; import AudioMuteButton from "../../../toolbox/components/native/AudioMuteButton"; import VideoMuteButton from "../../../toolbox/components/native/VideoMuteButton"; import { isDisplayNameRequired, isRoomNameEnabled } from "../../functions"; import { IPrejoinProps } from "../../types"; import { hasDisplayName } from "../../utils"; import { preJoinStyles as styles } from "./styles"; const Prejoin: React.FC = ({ navigation }: IPrejoinProps) => { const dispatch = useDispatch(); const isFocused = useIsFocused(); const { t } = useTranslation(); const aspectRatio = useSelector( (state: IReduxState) => state["features/base/responsive-ui"]?.aspectRatio ); const localParticipant = useSelector((state: IReduxState) => getLocalParticipant(state) ); const isDisplayNameMandatory = useSelector((state: IReduxState) => isDisplayNameRequired(state) ); const isDisplayNameVisible = useSelector( (state: IReduxState) => !getFeatureFlag(state, PREJOIN_PAGE_HIDE_DISPLAY_NAME, false) ); const isDisplayNameReadonly = useSelector(isNameReadOnly); const roomName = useSelector((state: IReduxState) => getConferenceName(state) ); const roomNameEnabled = useSelector((state: IReduxState) => isRoomNameEnabled(state) ); const participantName = localParticipant?.name; const [displayName, setDisplayName] = useState(participantName || ""); const isDisplayNameMissing = useMemo( () => !displayName && isDisplayNameMandatory, [displayName, isDisplayNameMandatory] ); const showDisplayNameError = useMemo( () => !isDisplayNameReadonly && isDisplayNameMissing && isDisplayNameVisible, [isDisplayNameMissing, isDisplayNameReadonly, isDisplayNameVisible] ); const showDisplayNameInput = useMemo( () => isDisplayNameVisible && (displayName || !isDisplayNameReadonly), [displayName, isDisplayNameReadonly, isDisplayNameVisible] ); const [isJoining, setIsJoining] = useState(false); const onChangeDisplayName = useCallback( (event) => { const fieldValue = getFieldValue(event); setDisplayName(fieldValue); dispatch( updateSettings({ displayName: fieldValue, }) ); }, [displayName] ); const onJoin = useCallback(() => { console.log("---conference.root---"); setIsJoining(true); dispatch(connect()); navigateRoot(screen.conference.root); }, [dispatch]); const maybeJoin = useCallback(() => { if (isDisplayNameMissing) { console.log("---isDisplayNameMissing---"); dispatch( openDisplayNamePrompt({ onPostSubmit: onJoin, validateInput: hasDisplayName, }) ); } else { console.log("---onJoin---"); onJoin(); } }, [dispatch, hasDisplayName, isDisplayNameMissing, onJoin]); const onJoinLowBandwidth = useCallback(() => { dispatch(setAudioOnly(true)); maybeJoin(); }, [dispatch]); const goBack = useCallback(() => { dispatch(appNavigate(undefined)); return true; }, [dispatch]); const { PRIMARY, TERTIARY } = BUTTON_TYPES; useEffect(() => { BackHandler.addEventListener("hardwareBackPress", goBack); dispatch( setPermanentProperty({ wasPrejoinDisplayed: true, }) ); return () => BackHandler.removeEventListener("hardwareBackPress", goBack); }, []); // dispatch is not in the dependancy list because we want the action to be dispatched only once when // the component is mounted. const headerLeft = () => { if (Platform.OS === "ios") { return ( ); } return ; }; useLayoutEffect(() => { navigation.setOptions({ headerLeft, headerTitle: t("prejoin.joinMeeting"), }); }, [navigation]); let contentWrapperStyles; let contentContainerStyles; let largeVideoContainerStyles; if (aspectRatio === ASPECT_RATIO_NARROW) { contentWrapperStyles = styles.contentWrapper; contentContainerStyles = styles.contentContainer; largeVideoContainerStyles = styles.largeVideoContainer; } else { contentWrapperStyles = styles.contentWrapperWide; contentContainerStyles = styles.contentContainerWide; largeVideoContainerStyles = styles.largeVideoContainerWide; } return ( {isFocused && ( }> }> {roomNameEnabled && ( } > } > {roomName} )} )} {showDisplayNameInput && ( )} {showDisplayNameError && ( }> }> {t("prejoin.errorMissingName")} )}