/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format */ import {styled, colors} from '../ui'; import React, {Component} from 'react'; import {connect} from 'react-redux'; import { setActiveSheet, ActiveSheet, ACTIVE_SHEET_DOCTOR, ACTIVE_SHEET_SETTINGS, } from '../reducers/application'; import {State as Store} from '../reducers/index'; import {ButtonGroup, Button} from '../ui'; import {FlexColumn, FlexRow} from '../ui'; import runHealthchecks, { HealthcheckSettings, HealthcheckEventsHandler, } from '../utils/runHealthchecks'; import { updateHealthcheckResult, startHealthchecks, finishHealthchecks, HealthcheckReport, HealthcheckResult, } from '../reducers/healthchecks'; import {reportUsage} from '../utils/metrics'; type StateFromProps = { healthcheckReport: HealthcheckReport; } & HealthcheckSettings; type DispatchFromProps = { setActiveSheet: (payload: ActiveSheet) => void; } & HealthcheckEventsHandler; type State = {visible: boolean; message: string; showSettingsButton: boolean}; type Props = DispatchFromProps & StateFromProps; class DoctorBar extends Component { constructor(props: Props) { super(props); this.state = { visible: false, message: '', showSettingsButton: false, }; } componentDidMount() { this.showMessageIfChecksFailed(); } static getDerivedStateFromProps(props: Props, state: State): State | null { const failedCategories = Object.values( props.healthcheckReport.categories, ).filter((cat) => hasProblems(cat.result)); if (failedCategories.length == 1) { const failedCat = failedCategories[0]; if (failedCat.key === 'ios' || failedCat.key === 'android') { return { ...state, message: `Doctor has discovered problems with your ${failedCat.label} setup. If you are not interested in ${failedCat.label} development you can disable it in Settings.`, showSettingsButton: true, }; } } if (failedCategories.length) { return { ...state, message: 'Doctor has discovered problems with your installation.', showSettingsButton: false, }; } return null; } async showMessageIfChecksFailed() { await runHealthchecks(this.props); const result = this.props.healthcheckReport.result; if (hasProblems(result)) { if (result.isAcknowledged) { reportUsage('doctor:warning:suppressed'); } else { this.setVisible(true); reportUsage('doctor:warning:shown'); } } } render() { return ( this.state.visible && ( {this.state.showSettingsButton && ( )} {this.state.message} ) ); } setVisible(visible: boolean) { this.setState((prevState) => { return { ...prevState, visible, }; }); } } export default connect( ({settingsState, healthchecks: {healthcheckReport}}) => ({ healthcheckReport, settings: settingsState, }), { setActiveSheet, updateHealthcheckResult, startHealthchecks, finishHealthchecks, }, )(DoctorBar); const Container = styled.div({ boxShadow: '2px 2px 2px #ccc', userSelect: 'text', }); const WarningContainer = styled.div({ backgroundColor: colors.orange, color: '#fff', maxHeight: '600px', overflowY: 'auto', overflowX: 'hidden', transition: 'max-height 0.3s ease', '&.collapsed': { maxHeight: '0px', }, padding: '4px 12px', borderBottom: '1px solid ' + colors.orangeDark3, verticalAlign: 'middle', lineHeight: '28px', }); const ButtonSection = styled(FlexColumn)({ marginLeft: '8px', flexShrink: 0, flexGrow: 0, }); function hasProblems(result: HealthcheckResult) { return result.status === 'WARNING' || result.status === 'FAILED'; }