import bindAll from 'lodash.bindall'; import PropTypes from 'prop-types'; import React from 'react'; import {defineMessages, injectIntl, intlShape, FormattedMessage} from 'react-intl'; import ReactModal from 'react-modal'; import Box from '../box/box.jsx'; import styles from './telemetry-modal.css'; const messages = defineMessages({ label: { id: 'gui.telemetryOptIn.label', defaultMessage: 'Report statistics to improve Scratch', description: 'Scratch 3.0 telemetry modal label - for accessibility' }, bodyText1: { defaultMessage: 'The Scratch Team is always looking to better understand how Scratch is used around the ' + 'world. To help support this effort, you can allow Scratch to automatically send usage information to ' + 'the Scratch Team.', description: 'First paragraph of body text for telemetry opt-in modal', id: 'gui.telemetryOptIn.body1' }, bodyText2: { defaultMessage: 'The information we collect includes language selection, blocks usage, and some events like ' + 'saving, loading, and uploading a project. We DO NOT collect any personal information. Please see our ' + '{privacyPolicyLink} for more information.', description: 'First paragraph of body text for telemetry opt-in modal', id: 'gui.telemetryOptIn.body2' }, privacyPolicyLink: { defaultMessage: 'Privacy Policy', description: 'Link to the Scratch privacy policy', id: 'gui.telemetryOptIn.privacyPolicyLink' }, optInText: { defaultMessage: 'Share my usage data with the Scratch Team', description: 'Text for telemetry modal opt-in button', id: 'gui.telemetryOptIn.optInText' }, optInTooltip: { defaultMessage: 'Enable telemetry', description: 'Tooltip for telemetry modal opt-in button', id: 'gui.telemetryOptIn.optInTooltip' }, optOutText: { defaultMessage: 'Do not share my usage data with the Scratch Team', description: 'Text for telemetry modal opt-in button', id: 'gui.telemetryOptIn.optOutText' }, optOutTooltip: { defaultMessage: 'Disable telemetry', description: 'Tooltip for telemetry modal opt-out button', id: 'gui.telemetryOptIn.optOutTooltip' }, settingWasUpdated: { defaultMessage: 'Your setting was updated.', description: 'Message indicating that the telemetry setting was updated and saved', id: 'gui.telemetryOptIn.settingWasUpdated' }, closeButton: { defaultMessage: 'Close', description: 'Text for the button which closes the telemetry modal dialog', id: 'gui.telemetryOptIn.buttonClose' } }); // This should be at least as long as the CSS transition const SETTING_WAS_UPDATED_DURATION_MS = 3000; class TelemetryModal extends React.PureComponent { constructor (props) { super(props); bindAll(this, [ 'handleCancel', 'handleOptInOutChanged' ]); this.state = { // if the settingWasUpdated message is displayed, this will be the ID of its removal timer settingWasUpdatedTimer: null }; } componentWillUnmount () { if (this.state.settingWasUpdatedTimer) { clearTimeout(this.state.settingWasUpdatedTimer); } } handleCancel () { this.props.onRequestClose(); if (this.props.onCancel) { this.props.onCancel(); } } handleOptInOutChanged (e) { if (e.target.value === 'true') { if (this.props.onOptIn) { this.props.onOptIn(); this.handleSettingWasUpdated(); } } else if (e.target.value === 'false') { if (this.props.onOptOut) { this.props.onOptOut(); this.handleSettingWasUpdated(); } } } handleSettingWasUpdated () { if (this.state.settingWasUpdatedTimer) { clearTimeout(this.state.settingWasUpdatedTimer); } const newTimer = setTimeout( () => this.handleSettingWasUpdatedTimeout(newTimer), SETTING_WAS_UPDATED_DURATION_MS ); this.setState({ settingWasUpdatedTimer: newTimer }); } handleSettingWasUpdatedTimeout (thisTimer) { if (thisTimer !== this.state.settingWasUpdatedTimer) { // some other timer has taken over return; } this.setState({ settingWasUpdatedTimer: null }); } render () { const isUndecided = (typeof this.props.isTelemetryEnabled !== 'boolean'); const isOff = (this.props.isTelemetryEnabled === false); const isOn = (this.props.isTelemetryEnabled === true); const settingWasUpdated = this.state.settingWasUpdatedTimer && ( ); return (

) }} />

{settingWasUpdated}
); } } TelemetryModal.propTypes = { intl: intlShape.isRequired, isRtl: PropTypes.bool, isTelemetryEnabled: PropTypes.bool, // false=disabled, true=enabled, undefined=undecided onCancel: PropTypes.func, onOptIn: PropTypes.func.isRequired, onOptOut: PropTypes.func.isRequired, onRequestClose: PropTypes.func, onShowPrivacyPolicy: PropTypes.func }; export default injectIntl(TelemetryModal);