// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; import { Alert, Image, Linking, ScrollView, TouchableOpacity, View, } from 'react-native'; import {intlShape} from 'react-intl'; import FormattedText from 'app/components/formatted_text'; import StatusBar from 'app/components/status_bar'; import {UpgradeTypes} from 'app/constants'; import logo from 'assets/images/logo.png'; import {checkUpgradeType, isUpgradeAvailable} from 'app/utils/client_upgrade'; import {changeOpacity, makeStyleSheetFromTheme, setNavigatorStyles} from 'app/utils/theme'; export default class ClientUpgrade extends PureComponent { static propTypes = { actions: PropTypes.shape({ logError: PropTypes.func.isRequired, setLastUpgradeCheck: PropTypes.func.isRequired, }).isRequired, currentVersion: PropTypes.string, closeAction: PropTypes.func, userCheckedForUpgrade: PropTypes.bool, downloadLink: PropTypes.string.isRequired, forceUpgrade: PropTypes.bool, latestVersion: PropTypes.string, navigator: PropTypes.object, theme: PropTypes.object.isRequired, upgradeType: PropTypes.string, }; static contextTypes = { intl: intlShape, }; constructor(props) { super(props); this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent); this.state = { upgradeType: UpgradeTypes.NO_UPGRADE, }; } componentDidMount() { if (this.props.userCheckedForUpgrade) { this.checkUpgrade(this.props); } } componentWillReceiveProps(nextProps) { if (this.props.theme !== nextProps.theme) { setNavigatorStyles(this.props.navigator, nextProps.theme); } } checkUpgrade = ({minVersion, latestVersion}) => { const {actions, currentVersion, downloadLink} = this.props; // We need at least minVersion or latestVersion and the app downloadlink if (!(latestVersion || minVersion) || !downloadLink) { return; } const upgradeType = checkUpgradeType(currentVersion, minVersion, latestVersion, actions.logError); if (upgradeType === UpgradeTypes.NO_UPGRADE) { return; } this.setState({ upgradeType, }); actions.setLastUpgradeCheck(); } handleClose = () => { if (this.props.closeAction) { this.props.closeAction(); } else if (this.props.userCheckedForUpgrade) { this.props.navigator.pop(); } else { this.props.navigator.dismissModal(); } }; handleDownload = () => { const {downloadLink} = this.props; const {intl} = this.context; Linking.canOpenURL(downloadLink).then((supported) => { if (supported) { return Linking.openURL(downloadLink); } Alert.alert( intl.formatMessage({ id: 'mobile.client_upgrade.download_error.title', defaultMessage: 'Upgrade Error', }), intl.formatMessage({ id: 'mobile.client_upgrade.download_error.message', defaultMessage: 'An error occurred while trying to open the download link.', }) ); return false; }); }; onNavigatorEvent = (event) => { if (event.type === 'NavBarButtonPress') { if (event.id === 'close-upgrade') { this.props.navigator.dismissModal({ animationType: 'slide-down', }); } } }; renderMustUpgrade() { const {theme} = this.props; const styles = getStyleFromTheme(theme); return ( ); } renderCanUpgrade() { const {theme} = this.props; const styles = getStyleFromTheme(theme); return ( ); } renderNoUpgrade() { const {theme} = this.props; const styles = getStyleFromTheme(theme); return ( ); } renderMessageContent = () => { const {currentVersion, forceUpgrade, latestVersion, upgradeType: passedUpgradeType, userCheckedForUpgrade, theme} = this.props; const styles = getStyleFromTheme(theme); const upgradeType = userCheckedForUpgrade ? this.state.upgradeType : passedUpgradeType; let messageComponent; switch (upgradeType) { case UpgradeTypes.CAN_UPGRADE: messageComponent = this.renderCanUpgrade(); break; case UpgradeTypes.MUST_UPGRADE: messageComponent = this.renderMustUpgrade(); break; default: case UpgradeTypes.NO_UPGRADE: case UpgradeTypes.IS_BETA: messageComponent = this.renderNoUpgrade(); break; } return ( {messageComponent} {upgradeType !== UpgradeTypes.IS_BETA && ( )} {isUpgradeAvailable(this.state.upgradeType) && {!forceUpgrade && } } ); } render() { const {theme} = this.props; const styles = getStyleFromTheme(theme); return ( {this.renderMessageContent()} ); } } const getStyleFromTheme = makeStyleSheetFromTheme((theme) => { return { container: { flex: 1, backgroundColor: theme.centerChannelBg, }, image: { marginTop: 75, width: 76, height: 75, }, messageButton: { marginBottom: 15, borderWidth: 2, borderRadius: 2, alignItems: 'center', justifyContent: 'center', borderColor: theme.buttonBg, }, messageButtonText: { paddingVertical: 10, paddingHorizontal: 20, fontWeight: '600', color: theme.buttonBg, }, messageContainer: { marginTop: 25, flex: 1, alignSelf: 'stretch', alignItems: 'center', }, messageCloseButton: { marginBottom: 15, alignItems: 'center', justifyContent: 'center', }, messageSubtitle: { fontSize: 16, marginBottom: 20, color: theme.centerChannelColor, textAlign: 'center', paddingHorizontal: 30, }, messageTitle: { fontSize: 24, marginBottom: 20, fontWeight: '600', color: theme.centerChannelColor, textAlign: 'center', paddingHorizontal: 30, }, scrollView: { flex: 1, backgroundColor: changeOpacity(theme.centerChannelColor, 0.03), }, scrollViewContent: { paddingBottom: 20, alignItems: 'center', }, }; });