ref(notifications): replace NotificationWithToggle with Notification

It was decided along with the mute participant dialog reactification
that these types of warning messages should not be toggleable--that
they should simply always display because there is no undo action.
As such, the component NotificationWithToggle is no longer needed.
This commit is contained in:
Leonard Kim 2017-11-16 09:25:04 -08:00 committed by yanas
parent fe411398e3
commit ef813fbf71
9 changed files with 45 additions and 260 deletions

View File

@ -324,20 +324,17 @@
"stopRecordingWarning": "Are you sure you would like to stop the recording?", "stopRecordingWarning": "Are you sure you would like to stop the recording?",
"stopLiveStreaming": "Stop live streaming", "stopLiveStreaming": "Stop live streaming",
"stopRecording": "Stop recording", "stopRecording": "Stop recording",
"doNotShowWarningAgain": "Don't show this warning again",
"doNotShowMessageAgain": "Don't show this message again", "doNotShowMessageAgain": "Don't show this message again",
"permissionDenied": "Permission Denied", "permissionDenied": "Permission Denied",
"screenSharingFailedToInstall": "Oops! Your screen sharing extension failed to install.", "screenSharingFailedToInstall": "Oops! Your screen sharing extension failed to install.",
"screenSharingFailedToInstallTitle": "Screen sharing extension failed to install", "screenSharingFailedToInstallTitle": "Screen sharing extension failed to install",
"screenSharingPermissionDeniedError": "Oops! Something went wrong with your screen sharing extension permissions. Please reload and try again.", "screenSharingPermissionDeniedError": "Oops! Something went wrong with your screen sharing extension permissions. Please reload and try again.",
"micErrorPresent": "There was an error connecting to your microphone.",
"cameraErrorPresent": "There was an error connecting to your camera.",
"cameraUnsupportedResolutionError": "Your camera does not support required video resolution.", "cameraUnsupportedResolutionError": "Your camera does not support required video resolution.",
"cameraUnknownError": "Cannot use camera for a unknown reason.", "cameraUnknownError": "Cannot use camera for an unknown reason.",
"cameraPermissionDeniedError": "You have not granted permission to use your camera. You can still join the conference but others won't see you. Use the camera button in the address bar to fix this.", "cameraPermissionDeniedError": "You have not granted permission to use your camera. You can still join the conference but others won't see you. Use the camera button in the address bar to fix this.",
"cameraNotFoundError": "Camera was not found.", "cameraNotFoundError": "Camera was not found.",
"cameraConstraintFailedError": "Your camera does not satisfy some of the required constraints.", "cameraConstraintFailedError": "Your camera does not satisfy some of the required constraints.",
"micUnknownError": "Cannot use microphone for a unknown reason.", "micUnknownError": "Cannot use microphone for an unknown reason.",
"micPermissionDeniedError": "You have not granted permission to use your microphone. You can still join the conference but others won't hear you. Use the camera button in the address bar to fix this.", "micPermissionDeniedError": "You have not granted permission to use your microphone. You can still join the conference but others won't hear you. Use the camera button in the address bar to fix this.",
"micNotFoundError": "Microphone was not found.", "micNotFoundError": "Microphone was not found.",
"micConstraintFailedError": "Your microphone does not satisfy some of the required constraints.", "micConstraintFailedError": "Your microphone does not satisfy some of the required constraints.",

View File

@ -31,8 +31,8 @@ import {
} from '../../react/features/base/participants'; } from '../../react/features/base/participants';
import { openDisplayNamePrompt } from '../../react/features/display-name'; import { openDisplayNamePrompt } from '../../react/features/display-name';
import { import {
maybeShowNotificationWithDoNotDisplay, setNotificationsEnabled,
setNotificationsEnabled showWarningNotification
} from '../../react/features/notifications'; } from '../../react/features/notifications';
import { import {
checkAutoEnableDesktopSharing, checkAutoEnableDesktopSharing,
@ -1155,8 +1155,6 @@ UI.showMicErrorNotification = function(micError) {
const { message, name } = micError; const { message, name } = micError;
const persistenceKey = `doNotShowErrorAgain-mic-${name}`;
const micJitsiTrackErrorMsg const micJitsiTrackErrorMsg
= JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[name]; = JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[name];
const micErrorMsg = micJitsiTrackErrorMsg const micErrorMsg = micJitsiTrackErrorMsg
@ -1164,18 +1162,13 @@ UI.showMicErrorNotification = function(micError) {
.microphone[JitsiTrackErrors.GENERAL]; .microphone[JitsiTrackErrors.GENERAL];
const additionalMicErrorMsg = micJitsiTrackErrorMsg ? null : message; const additionalMicErrorMsg = micJitsiTrackErrorMsg ? null : message;
APP.store.dispatch(maybeShowNotificationWithDoNotDisplay( APP.store.dispatch(showWarningNotification({
persistenceKey, description: additionalMicErrorMsg,
{ descriptionKey: micErrorMsg,
additionalMessage: additionalMicErrorMsg, titleKey: name === JitsiTrackErrors.PERMISSION_DENIED
messageKey: micErrorMsg, ? 'deviceError.microphonePermission'
showToggle: Boolean(micJitsiTrackErrorMsg), : 'deviceError.microphoneError'
subtitleKey: 'dialog.micErrorPresent', }));
titleKey: name === JitsiTrackErrors.PERMISSION_DENIED
? 'deviceError.microphonePermission'
: 'deviceError.microphoneError',
toggleLabelKey: 'dialog.doNotShowWarningAgain'
}));
}; };
/** /**
@ -1192,8 +1185,6 @@ UI.showCameraErrorNotification = function(cameraError) {
const { message, name } = cameraError; const { message, name } = cameraError;
const persistenceKey = `doNotShowErrorAgain-camera-${name}`;
const cameraJitsiTrackErrorMsg const cameraJitsiTrackErrorMsg
= JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[name]; = JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[name];
const cameraErrorMsg = cameraJitsiTrackErrorMsg const cameraErrorMsg = cameraJitsiTrackErrorMsg
@ -1201,17 +1192,12 @@ UI.showCameraErrorNotification = function(cameraError) {
.camera[JitsiTrackErrors.GENERAL]; .camera[JitsiTrackErrors.GENERAL];
const additionalCameraErrorMsg = cameraJitsiTrackErrorMsg ? null : message; const additionalCameraErrorMsg = cameraJitsiTrackErrorMsg ? null : message;
APP.store.dispatch(maybeShowNotificationWithDoNotDisplay( APP.store.dispatch(showWarningNotification({
persistenceKey, description: additionalCameraErrorMsg,
{ descriptionKey: cameraErrorMsg,
additionalMessage: additionalCameraErrorMsg, titleKey: name === JitsiTrackErrors.PERMISSION_DENIED
messageKey: cameraErrorMsg, ? 'deviceError.cameraPermission' : 'deviceError.cameraError'
showToggle: Boolean(cameraJitsiTrackErrorMsg), }));
subtitleKey: 'dialog.cameraErrorPresent',
titleKey: name === JitsiTrackErrors.PERMISSION_DENIED
? 'deviceError.cameraPermission' : 'deviceError.cameraError',
toggleLabelKey: 'dialog.doNotShowWarningAgain'
}));
}; };
/** /**

25
package-lock.json generated
View File

@ -533,31 +533,6 @@
"styled-components": "1.3.0" "styled-components": "1.3.0"
} }
}, },
"@atlaskit/toggle": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/@atlaskit/toggle/-/toggle-2.6.1.tgz",
"integrity": "sha1-I2R+VzTs9psaPb8VpVw0tlfim90=",
"requires": {
"@atlaskit/icon": "8.1.0",
"@atlaskit/theme": "2.2.0",
"babel-runtime": "6.26.0",
"prop-types": "15.6.0",
"styled-components": "1.3.0",
"uid": "0.0.2"
},
"dependencies": {
"@atlaskit/icon": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@atlaskit/icon/-/icon-8.1.0.tgz",
"integrity": "sha1-HeV48TixTcmMOFkYZbW2h+VYuDo=",
"requires": {
"babel-runtime": "6.26.0",
"prop-types": "15.6.0",
"styled-components": "1.3.0"
}
}
}
},
"@atlaskit/tooltip": { "@atlaskit/tooltip": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/@atlaskit/tooltip/-/tooltip-6.0.0.tgz", "resolved": "https://registry.npmjs.org/@atlaskit/tooltip/-/tooltip-6.0.0.tgz",

View File

@ -30,7 +30,6 @@
"@atlaskit/spinner": "4.0.0", "@atlaskit/spinner": "4.0.0",
"@atlaskit/tabs": "4.0.1", "@atlaskit/tabs": "4.0.1",
"@atlaskit/theme": "2.2.0", "@atlaskit/theme": "2.2.0",
"@atlaskit/toggle": "2.6.1",
"@atlaskit/tooltip": "6.0.0", "@atlaskit/tooltip": "6.0.0",
"@atlassian/aui": "6.0.6", "@atlassian/aui": "6.0.6",
"autosize": "1.18.13", "autosize": "1.18.13",

View File

@ -1,14 +1,9 @@
import jitsiLocalStorage from '../../../modules/util/JitsiLocalStorage';
import { import {
HIDE_NOTIFICATION, HIDE_NOTIFICATION,
SET_NOTIFICATIONS_ENABLED, SET_NOTIFICATIONS_ENABLED,
SHOW_NOTIFICATION SHOW_NOTIFICATION
} from './actionTypes'; } from './actionTypes';
import { import { Notification } from './components';
Notification,
NotificationWithToggle
} from './components';
import { NOTIFICATION_TYPE } from './constants'; import { NOTIFICATION_TYPE } from './constants';
@ -96,33 +91,3 @@ export function showWarningNotification(props) {
appearance: NOTIFICATION_TYPE.WARNING appearance: NOTIFICATION_TYPE.WARNING
}); });
} }
/**
* Displays a notification unless the passed in persistenceKey value exists in
* local storage and has been set to "true".
*
* @param {string} persistenceKey - The local storage key to look up for whether
* or not the notification should display.
* @param {Object} props - The props needed to show the notification component.
* @returns {Function}
*/
export function maybeShowNotificationWithDoNotDisplay(persistenceKey, props) {
return dispatch => {
if (jitsiLocalStorage.getItem(persistenceKey) === 'true') {
return;
}
const newProps = Object.assign({}, props, {
onToggleSubmit: isToggled => {
jitsiLocalStorage.setItem(persistenceKey, isToggled);
}
});
dispatch({
type: SHOW_NOTIFICATION,
component: NotificationWithToggle,
props: newProps,
uid: window.Date.now()
});
};
}

View File

@ -61,7 +61,8 @@ class Notification extends Component<*> {
defaultTitleKey: PropTypes.string, defaultTitleKey: PropTypes.string,
/** /**
* The description string. * A description string that can be used in addition to the prop
* descriptionKey.
*/ */
description: PropTypes.string, description: PropTypes.string,
@ -161,8 +162,7 @@ class Notification extends Component<*> {
<Flag <Flag
actions = { this._mapAppearanceToButtons(hideErrorSupportLink) } actions = { this._mapAppearanceToButtons(hideErrorSupportLink) }
appearance = { appearance } appearance = { appearance }
description = { description description = { this._renderDescription() }
|| t(descriptionKey, descriptionArguments) }
icon = { this._mapAppearanceToIcon() } icon = { this._mapAppearanceToIcon() }
id = { uid } id = { uid }
isDismissAllowed = { isDismissAllowed } isDismissAllowed = { isDismissAllowed }
@ -173,6 +173,30 @@ class Notification extends Component<*> {
_onDismissed: () => void; _onDismissed: () => void;
/**
* Creates a {@code ReactElement} for displaying the contents of the
* notification.
*
* @private
* @returns {ReactElement}
*/
_renderDescription() {
const {
description,
descriptionArguments,
descriptionKey,
t
} = this.props;
return (
<div>
{ descriptionKey
? t(descriptionKey, descriptionArguments) : null }
{ description || null }
</div>
);
}
/** /**
* Calls back into {@code FlagGroup} to dismiss the notification. * Calls back into {@code FlagGroup} to dismiss the notification.
* *

View File

@ -1,160 +0,0 @@
import { ToggleStateless } from '@atlaskit/toggle';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { translate } from '../../base/i18n';
import { default as Notification } from './Notification';
import { NOTIFICATION_TYPE } from '../constants';
/**
* React {@code Component} for displaying a notification with a toggle element.
*
* @extends Component
*/
class NotificationWithToggle extends Component {
/**
* {@code NotificationWithToggle} component's property types.
*
* @static
*/
static propTypes = {
...Notification.propTypes,
/**
* Any additional text to display at the end of the notification message
* body.
*/
additionalMessage: PropTypes.string,
/**
* Optional callback to invoke when the notification is dismissed. The
* current value of the toggle element will be passed in.
*/
onToggleSubmit: PropTypes.func,
/**
* Whether or not the toggle element should be displayed.
*/
showToggle: PropTypes.bool,
/**
* Translation key for a message to display at the top of the
* notification body.
*/
subtitleKey: PropTypes.string,
/*
* The translation key to be used as a label describing what setting the
* toggle will change.
*/
toggleLabelKey: PropTypes.string
};
/**
* Initializes a new {@code NotificationWithToggle} instance.
*
* @param {Object} props - The read-only properties with which the new
* instance is to be initialized.
*/
constructor(props) {
super(props);
this.state = {
/**
* Whether or not the toggle element is active/checked/selected.
*
* @type {boolean}
*/
isToggleChecked: false
};
// Bind event handlers so they are only bound once for every instance.
this._onDismissed = this._onDismissed.bind(this);
this._onToggleChange = this._onToggleChange.bind(this);
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
return (
<Notification
appearance = { NOTIFICATION_TYPE.WARNING }
{ ...this.props }
description = { this._renderDescription() } />
);
}
/**
* Calls back into {@code FlagGroup} to dismiss the notification. Optionally
* will execute a passed in onToggleSubmit callback with the current state
* of the toggle element.
*
* @private
* @returns {void}
*/
_onDismissed() {
const { onDismissed, onToggleSubmit, showToggle, uid } = this.props;
if (showToggle && onToggleSubmit) {
onToggleSubmit(this.state.isToggleChecked);
}
onDismissed(uid);
}
/**
* Updates the current known state of the toggle selection.
*
* @param {Object} event - The DOM event from changing the toggle selection.
* @private
* @returns {void}
*/
_onToggleChange(event) {
this.setState({
isToggleChecked: event.target.checked
});
}
/**
* Creates a React Element for displaying the notification message as well
* as a toggle.
*
* @private
* @returns {ReactElement}
*/
_renderDescription() {
const {
additionalMessage,
descriptionKey,
showToggle,
subtitleKey,
t,
toggleLabelKey
} = this.props;
return (
<div className = 'notification-with-toggle'>
<div>{ t(subtitleKey) }</div>
{ descriptionKey ? <div>{ t(descriptionKey) }</div> : null }
{ additionalMessage ? <div>{ additionalMessage }</div>
: null }
{ showToggle
? <div>
{ t(toggleLabelKey) }
<ToggleStateless
isChecked
= { this.state.isToggleChecked }
onChange = { this._onToggleChange } />
</div>
: null }
</div>
);
}
}
export default translate(NotificationWithToggle);

View File

@ -1,3 +1,2 @@
export { default as Notification } from './Notification'; export { default as Notification } from './Notification';
export { default as NotificationsContainer } from './NotificationsContainer'; export { default as NotificationsContainer } from './NotificationsContainer';
export { default as NotificationWithToggle } from './NotificationWithToggle';