/* eslint-disable react/jsx-no-bind */ import React, { useRef, useState } from 'react'; import { WithTranslation } from 'react-i18next'; import { translate } from '../../../../base/i18n/functions'; import { copyText } from '../../../../base/util/copyText.web'; import { LOCKED_LOCALLY } from '../../../../room-lock/constants'; import { NOTIFY_CLICK_MODE } from '../../../../toolbox/constants'; import PasswordForm from './PasswordForm'; import { INotifyClick } from './SecurityDialog'; const DIGITS_ONLY = /^\d+$/; const KEY = 'add-passcode'; interface IProps extends WithTranslation { /** * Toolbar buttons which have their click exposed through the API. */ buttonsWithNotifyClick: Array; /** * Whether or not the current user can modify the current password. */ canEditPassword: boolean; /** * The JitsiConference for which to display a lock state and change the * password. */ conference: any; /** * The value for how the conference is locked (or undefined if not locked) * as defined by room-lock constants. */ locked: string; /** * The current known password for the JitsiConference. */ password: string; /** * Whether or not to show the password in editing mode. */ passwordEditEnabled: boolean; /** * The number of digits to be used in the password. */ passwordNumberOfDigits?: number; /** * Action that sets the conference password. */ setPassword: Function; /** * Method that sets whether the password editing is enabled or not. */ setPasswordEditEnabled: Function; } /** * Component that handles the password manipulation from the invite dialog. * * @returns {React$Element} */ function PasswordSection({ buttonsWithNotifyClick, canEditPassword, conference, locked, password, passwordEditEnabled, passwordNumberOfDigits, setPassword, setPasswordEditEnabled, t }: IProps) { const formRef = useRef(null); const [ passwordVisible, setPasswordVisible ] = useState(false); /** * Callback invoked to set a password on the current JitsiConference. * * @param {string} enteredPassword - The new password to be used to lock the * current JitsiConference. * @private * @returns {void} */ function onPasswordSubmit(enteredPassword: string) { if (enteredPassword && passwordNumberOfDigits && !DIGITS_ONLY.test(enteredPassword)) { // Don't set the password. return; } setPassword(conference, conference.lock, enteredPassword); } /** * Toggles whether or not the password should currently be shown as being * edited locally. * * @private * @returns {void} */ function onTogglePasswordEditState() { if (typeof APP === 'undefined' || !buttonsWithNotifyClick?.length) { setPasswordEditEnabled(!passwordEditEnabled); return; } let notifyMode; const notify = buttonsWithNotifyClick.find( (btn: string | INotifyClick) => (typeof btn === 'string' && btn === KEY) || (typeof btn === 'object' && btn.key === KEY) ); if (notify) { notifyMode = typeof notify === 'string' || notify.preventExecution ? NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY : NOTIFY_CLICK_MODE.ONLY_NOTIFY; APP.API.notifyToolbarButtonClicked( KEY, notifyMode === NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY ); } if (notifyMode === NOTIFY_CLICK_MODE.ONLY_NOTIFY) { setPasswordEditEnabled(!passwordEditEnabled); } } /** * Method to remotely submit the password from outside of the password form. * * @returns {void} */ function onPasswordSave() { if (formRef.current) { // @ts-ignore const { value } = formRef.current.querySelector('div > input'); if (value) { onPasswordSubmit(value); } } } /** * Callback invoked to unlock the current JitsiConference. * * @returns {void} */ function onPasswordRemove() { onPasswordSubmit(''); } /** * Copies the password to the clipboard. * * @returns {void} */ function onPasswordCopy() { copyText(password); } /** * Toggles whether or not the password should currently be shown as being * edited locally. * * @param {Object} e - The key event to handle. * * @private * @returns {void} */ function onTogglePasswordEditStateKeyPressHandler(e: React.KeyboardEvent) { if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); onTogglePasswordEditState(); } } /** * Method to remotely submit the password from outside of the password form. * * @param {Object} e - The key event to handle. * * @private * @returns {void} */ function onPasswordSaveKeyPressHandler(e: React.KeyboardEvent) { if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); onPasswordSave(); } } /** * Callback invoked to unlock the current JitsiConference. * * @param {Object} e - The key event to handle. * * @private * @returns {void} */ function onPasswordRemoveKeyPressHandler(e: React.KeyboardEvent) { if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); onPasswordRemove(); } } /** * Copies the password to the clipboard. * * @param {Object} e - The key event to handle. * * @private * @returns {void} */ function onPasswordCopyKeyPressHandler(e: React.KeyboardEvent) { if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); onPasswordCopy(); } } /** * Callback invoked to show the current password. * * @returns {void} */ function onPasswordShow() { setPasswordVisible(true); } /** * Callback invoked to show the current password. * * @param {Object} e - The key event to handle. * * @returns {void} */ function onPasswordShowKeyPressHandler(e: React.KeyboardEvent) { if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); setPasswordVisible(true); } } /** * Callback invoked to hide the current password. * * @returns {void} */ function onPasswordHide() { setPasswordVisible(false); } /** * Callback invoked to hide the current password. * * @param {Object} e - The key event to handle. * * @returns {void} */ function onPasswordHideKeyPressHandler(e: React.KeyboardEvent) { if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); setPasswordVisible(false); } } /** * Method that renders the password action(s) based on the current * locked-status of the conference. * * @returns {React$Element} */ function renderPasswordActions() { if (!canEditPassword) { return null; } if (passwordEditEnabled) { return ( <> { t('dialog.Cancel') } { t('dialog.add') } ); } if (locked) { return ( <> { t('dialog.Remove') } { // There are cases like lobby and grant moderator when password is not available password ? <> { t('dialog.copy') } : null } {locked === LOCKED_LOCALLY && ( {t(passwordVisible ? 'dialog.hide' : 'dialog.show')} )} ); } return ( { t('info.addPassword') } ); } return (

{ t(canEditPassword ? 'security.about' : 'security.aboutReadOnly') }

{ renderPasswordActions() }
); } export default translate(PasswordSection);