Skip to content

Commit

Permalink
fix(DialInNumber,InviteByEmailSection):give user a feedback that copy…
Browse files Browse the repository at this point in the history
… is done
  • Loading branch information
HazemAbdo committed Apr 3, 2024
1 parent 2c6f4e2 commit 8344adc
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 67 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import React, { Component } from 'react';
import React, { useEffect, useState } from 'react';
import { WithTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux';

import { translate } from '../../../../base/i18n/functions';
import Icon from '../../../../base/icons/components/Icon';
import { IconCopy } from '../../../../base/icons/svg';
import { IconCheck, IconCopy } from '../../../../base/icons/svg';
import Tooltip from '../../../../base/tooltip/components/Tooltip';
import { copyText } from '../../../../base/util/copyText.web';
import { showSuccessNotification } from '../../../../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../../../../notifications/constants';
import { _formatConferenceIDPin } from '../../../_utils';

let mounted: boolean;

/**
* The type of the React {@code Component} props of {@link DialInNumber}.
*/
Expand All @@ -25,83 +31,108 @@ interface IProps extends WithTranslation {
phoneNumber: string;
}


/**
* React {@code Component} responsible for displaying a telephone number and
* conference ID for dialing into a conference.
* Component responsible for displaying a telephone number and
* conference ID for dialing into a conference and copying them to clipboard.
*
* @augments Component
* @returns {ReactNode}
*/
class DialInNumber extends Component<IProps> {
function DialInNumber({ conferenceID, phoneNumber, t }: IProps) {
const dispatch = useDispatch();
const [ isClicked, setIsClicked ] = useState(false);
const dialInLabel = t('info.dialInNumber');
const passcode = t('info.dialInConferenceID');
const conferenceIDPin = `${_formatConferenceIDPin(conferenceID)}#`;
const textToCopy = `${dialInLabel} ${phoneNumber} ${passcode} ${conferenceIDPin}`;


useEffect(() => {
mounted = true;

return () => {
mounted = false;
};
}, []);

/**
* Initializes a new DialInNumber instance.
* Copies the conference ID and phone number to the clipboard.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props: IProps) {
super(props);
* @returns {void}
*/
function _onCopyText() {
copyText(textToCopy);
dispatch(showSuccessNotification({
titleKey: 'dialog.copied'
}, NOTIFICATION_TIMEOUT_TYPE.SHORT));
setIsClicked(true);
setTimeout(() => {
// avoid: Can't perform a React state update on an unmounted component
if (mounted) {
setIsClicked(false);
}
}, 2500);

// Bind event handler so it is only bound once for every instance.
this._onCopyText = this._onCopyText.bind(this);
}

/**
* Copies the dial-in information to the clipboard.
* Copies the conference invitation to the clipboard.
*
* @param {Object} e - The key event to handle.
*
* @returns {void}
*/
_onCopyText() {
const { conferenceID, phoneNumber, t } = this.props;
const dialInLabel = t('info.dialInNumber');
const passcode = t('info.dialInConferenceID');
const conferenceIDPin = `${_formatConferenceIDPin(conferenceID)}#`;
const textToCopy = `${dialInLabel} ${phoneNumber} ${passcode} ${conferenceIDPin}`;

copyText(textToCopy);
function _onCopyTextKeyPress(e: React.KeyboardEvent) {
if (e.key === ' ' || e.key === 'Enter') {
e.preventDefault();
_onCopyText();
}
}

/**
* Implements React's {@link Component#render()}.
* Renders section that shows the phone number and conference ID
* and give user the ability to copy them to the clipboard.
*
* @inheritdoc
* @returns {ReactElement}
* @returns {ReactNode}
*/
render() {
const { conferenceID, phoneNumber, t } = this.props;

return (
<div className = 'dial-in-number'>
<p>
<span className = 'phone-number'>
<span className = 'info-label'>
{ t('info.dialInNumber') }
</span>
<span className = 'spacer'>&nbsp;</span>
<span className = 'info-value'>
{ phoneNumber }
</span>
return (
<div className = 'dial-in-number'>
<p>
<span className = 'phone-number'>
<span className = 'info-label'>
{ t('info.dialInNumber') }
</span>
<br />
<span className = 'conference-id'>
<span className = 'info-label'>
{ t('info.dialInConferenceID') }
</span>
<span className = 'spacer'>&nbsp;</span>
<span className = 'info-value'>
{ `${_formatConferenceIDPin(conferenceID)}#` }
</span>
<span className = 'spacer'>&nbsp;</span>
<span className = 'info-value'>
{ phoneNumber }
</span>
</p>
</span>
<br />
<span className = 'conference-id'>
<span className = 'info-label'>
{ t('info.dialInConferenceID') }
</span>
<span className = 'spacer'>&nbsp;</span>
<span className = 'info-value'>
{ `${_formatConferenceIDPin(conferenceID)}#` }
</span>
</span>
</p>
<Tooltip
content = { t('info.copyNumber') }
position = 'top'>
<button
aria-label = { t('info.copyNumber') }
className = 'dial-in-copy invisible-button'
onClick = { this._onCopyText }>
<Icon src = { IconCopy } />
// eslint-disable-next-line react/jsx-no-bind
onClick = { _onCopyText }
// eslint-disable-next-line react/jsx-no-bind
onKeyPress = { _onCopyTextKeyPress }>
<Icon src = { isClicked ? IconCheck : IconCopy } />
</button>
</div>
);
}
</Tooltip>
</div>
);
}

export default translate(DialInNumber);
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import React, { useEffect, useState } from 'react';
import { WithTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux';
import { makeStyles } from 'tss-react/mui';

import { isIosMobileBrowser } from '../../../../base/environment/utils';
import { translate } from '../../../../base/i18n/functions';
import Icon from '../../../../base/icons/components/Icon';
import {
IconCheck,
IconCopy,
IconEnvelope,
IconGoogle,
Expand All @@ -16,7 +18,10 @@ import Tooltip from '../../../../base/tooltip/components/Tooltip';
import { copyText } from '../../../../base/util/copyText.web';
import { showSuccessNotification } from '../../../../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../../../../notifications/constants';
interface IProps {

let mounted: boolean;

interface IProps extends WithTranslation {

/**
* The encoded invitation subject.
Expand Down Expand Up @@ -63,26 +68,41 @@ const useStyles = makeStyles()(theme => {
*
* @returns {ReactNode}
*/
function InviteByEmailSection({ inviteSubject, inviteText, inviteTextiOS }: IProps) {
function InviteByEmailSection({ inviteSubject, inviteText, inviteTextiOS, t }: IProps) {
const dispatch = useDispatch();
const { classes } = useStyles();
const { t } = useTranslation();
const [ isClicked, setIsClicked ] = useState(false);
const encodedInviteSubject = encodeURIComponent(inviteSubject);
const encodedInviteText = encodeURIComponent(inviteText);
const encodedInviteTextiOS = encodeURIComponent(inviteTextiOS);

const encodedDefaultEmailText = isIosMobileBrowser() ? encodedInviteTextiOS : encodedInviteText;

useEffect(() => {
mounted = true;

return () => {
mounted = false;
};
}, []);

/**
* Copies the conference invitation to the clipboard.
*
* @returns {void}
*/
function _onCopyText() {
copyText(inviteText);
dispatch(showSuccessNotification({
titleKey: 'dialog.copied'
}, NOTIFICATION_TIMEOUT_TYPE.SHORT));
copyText(inviteText);
setIsClicked(true);
setTimeout(() => {
// avoid: Can't perform a React state update on an unmounted component
if (mounted) {
setIsClicked(false);
}
}, 2500);
}

/**
Expand All @@ -95,10 +115,7 @@ function InviteByEmailSection({ inviteSubject, inviteText, inviteTextiOS }: IPro
function _onCopyTextKeyPress(e: React.KeyboardEvent) {
if (e.key === ' ' || e.key === 'Enter') {
e.preventDefault();
dispatch(showSuccessNotification({
titleKey: 'dialog.copied'
}, NOTIFICATION_TIMEOUT_TYPE.SHORT));
copyText(inviteText);
_onCopyText();
}
}

Expand Down Expand Up @@ -174,7 +191,7 @@ function InviteByEmailSection({ inviteSubject, inviteText, inviteTextiOS }: IPro
onKeyPress = { _onCopyTextKeyPress }
role = 'button'
tabIndex = { 0 }>
<Icon src = { IconCopy } />
<Icon src = { isClicked ? IconCheck : IconCopy } />
</div>
</Tooltip>
{renderEmailIcons()}
Expand All @@ -184,4 +201,4 @@ function InviteByEmailSection({ inviteSubject, inviteText, inviteTextiOS }: IPro
);
}

export default InviteByEmailSection;
export default translate(InviteByEmailSection);

0 comments on commit 8344adc

Please sign in to comment.