summaryrefslogtreecommitdiffhomepage
path: root/gui/src
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2020-02-12 13:06:45 +0100
committerOskar Nyberg <oskar@mullvad.net>2020-02-12 21:12:12 +0100
commit75e97041d7c922dff5d0783cc0431b0646283898 (patch)
tree5f2f54681fb823931d76a87ed6b427f8f67d8dbf /gui/src
parent8300c27a0895da2f4aec6d7767dfd178a7ae2c08 (diff)
downloadmullvadvpn-75e97041d7c922dff5d0783cc0431b0646283898.tar.xz
mullvadvpn-75e97041d7c922dff5d0783cc0431b0646283898.zip
Add outdated version dialog when navigating to problem report
Diffstat (limited to 'gui/src')
-rw-r--r--gui/src/renderer/components/AppButton.tsx2
-rw-r--r--gui/src/renderer/components/Modal.tsx126
-rw-r--r--gui/src/renderer/components/Support.tsx106
-rw-r--r--gui/src/renderer/components/SupportStyles.tsx22
-rw-r--r--gui/src/renderer/containers/SupportPage.tsx2
5 files changed, 147 insertions, 111 deletions
diff --git a/gui/src/renderer/components/AppButton.tsx b/gui/src/renderer/components/AppButton.tsx
index 212e5cb1a3..9f6fe860b3 100644
--- a/gui/src/renderer/components/AppButton.tsx
+++ b/gui/src/renderer/components/AppButton.tsx
@@ -84,7 +84,7 @@ interface IState {
textAdjustment: number;
}
-class BaseButton extends Component<IProps, IState> {
+export class BaseButton extends Component<IProps, IState> {
public state: IState = {
hovered: false,
textAdjustment: 0,
diff --git a/gui/src/renderer/components/Modal.tsx b/gui/src/renderer/components/Modal.tsx
index 5742e68f2b..3e7ec4414f 100644
--- a/gui/src/renderer/components/Modal.tsx
+++ b/gui/src/renderer/components/Modal.tsx
@@ -1,52 +1,92 @@
import * as React from 'react';
+import { Component, Styles, Text, View } from 'reactxp';
+import { colors } from '../../config.json';
-export class ModalContent extends React.Component {
- public render() {
- return (
- <div
- style={{
- position: 'absolute',
- display: 'flex',
- flexDirection: 'column',
- flex: 1,
- top: 0,
- left: 0,
- right: 0,
- bottom: 0,
- }}>
- {this.props.children}
- </div>
- );
- }
-}
+const styles = {
+ modalAlertBackground: Styles.createViewStyle({
+ flex: 1,
+ justifyContent: 'center',
+ paddingLeft: 14,
+ paddingRight: 14,
+ }),
+ modalAlert: Styles.createViewStyle({
+ backgroundColor: colors.darkBlue,
+ borderRadius: 11,
+ padding: 16,
+ }),
+ modalAlertMessage: Styles.createTextStyle({
+ fontFamily: 'Open Sans',
+ fontSize: 16,
+ fontWeight: '500',
+ lineHeight: 20,
+ color: colors.white80,
+ }),
+ modalAlertButtonContainer: Styles.createViewStyle({
+ marginTop: 16,
+ }),
+};
-export class ModalAlert extends React.Component {
- public render() {
- return (
- <div
- style={{
- backgroundColor: 'rgba(0,0,0,0.5)',
- position: 'absolute',
- display: 'flex',
- flexDirection: 'column',
- flex: 1,
- top: 0,
- left: 0,
- right: 0,
- bottom: 0,
- }}>
- {this.props.children}
- </div>
- );
- }
-}
+export const ModalContent: React.FC = ({ children }) => {
+ return (
+ <div
+ style={{
+ position: 'absolute',
+ display: 'flex',
+ flexDirection: 'column',
+ flex: 1,
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ }}>
+ {children}
+ </div>
+ );
+};
+
+const ModalBackground: React.FC = ({ children }) => {
+ return (
+ <div
+ style={{
+ backgroundColor: 'rgba(0,0,0,0.5)',
+ position: 'absolute',
+ display: 'flex',
+ flexDirection: 'column',
+ flex: 1,
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ }}>
+ {children}
+ </div>
+ );
+};
-interface IModalContainerProps {
- children?: React.ReactNode;
+export const ModalContainer: React.FC = ({ children }) => {
+ return <div style={{ position: 'relative', flex: 1 }}>{children}</div>;
+};
+
+interface IModalAlertProps {
+ message: string;
+ buttons: React.ReactNode[];
}
-export class ModalContainer extends React.Component<IModalContainerProps> {
+export class ModalAlert extends Component<IModalAlertProps> {
public render() {
- return <div style={{ position: 'relative', flex: 1 }}>{this.props.children}</div>;
+ return (
+ <ModalBackground>
+ <View style={styles.modalAlertBackground}>
+ <View style={styles.modalAlert}>
+ <Text style={styles.modalAlertMessage}>{this.props.message}</Text>
+ {this.props.buttons.map((button, index) => (
+ <View key={index} style={styles.modalAlertButtonContainer}>
+ {button}
+ </View>
+ ))}
+ </View>
+ </View>
+ </ModalBackground>
+ );
}
}
diff --git a/gui/src/renderer/components/Support.tsx b/gui/src/renderer/components/Support.tsx
index 5313e7449c..a840b74340 100644
--- a/gui/src/renderer/components/Support.tsx
+++ b/gui/src/renderer/components/Support.tsx
@@ -1,5 +1,6 @@
import * as React from 'react';
import { Component, Text, TextInput, View } from 'reactxp';
+import { links } from '../../config.json';
import { messages } from '../../shared/gettext';
import * as AppButton from './AppButton';
import ImageView from './ImageView';
@@ -26,6 +27,7 @@ interface ISupportState {
savedReport?: string;
sendState: SendState;
disableActions: boolean;
+ showOutdatedVersionWarning: boolean;
}
interface ISupportProps {
@@ -39,6 +41,8 @@ interface ISupportProps {
clearReportForm: () => void;
collectProblemReport: (accountsToRedact: string[]) => Promise<string>;
sendProblemReport: (email: string, message: string, savedReport: string) => Promise<void>;
+ outdatedVersion: boolean;
+ onExternalLink: (url: string) => void;
}
export default class Support extends Component<ISupportProps, ISupportState> {
@@ -48,6 +52,7 @@ export default class Support extends Component<ISupportProps, ISupportState> {
savedReport: undefined,
sendState: SendState.Initial,
disableActions: false,
+ showOutdatedVersionWarning: false,
};
private collectLogPromise?: Promise<string>;
@@ -58,6 +63,7 @@ export default class Support extends Component<ISupportProps, ISupportState> {
// seed initial data from props
this.state.email = props.defaultEmail;
this.state.message = props.defaultMessage;
+ this.state.showOutdatedVersionWarning = props.outdatedVersion;
}
public validate() {
@@ -110,12 +116,12 @@ export default class Support extends Component<ISupportProps, ISupportState> {
}
};
- public onCancelConfirmation = () => {
+ public onCancelNoEmailDialog = () => {
this.setState({ sendState: SendState.Initial });
};
public render() {
- const { sendState } = this.state;
+ const { sendState, showOutdatedVersionWarning } = this.state;
const header = (
<SettingsHeader>
<HeaderTitle>{messages.pgettext('support-view', 'Report a problem')}</HeaderTitle>
@@ -152,11 +158,8 @@ export default class Support extends Component<ISupportProps, ISupportState> {
</View>
</View>
</ModalContent>
- {sendState === SendState.Confirm ? (
- <ModalAlert>{this.renderConfirm()}</ModalAlert>
- ) : (
- undefined
- )}
+ {sendState === SendState.Confirm && this.renderNoEmailDialog()}
+ {showOutdatedVersionWarning && this.renderOutdateVersionWarningDialog()}
</ModalContainer>
</Container>
</Layout>
@@ -228,8 +231,57 @@ export default class Support extends Component<ISupportProps, ISupportState> {
}
}
- private renderConfirm() {
- return <ConfirmNoEmailDialog onConfirm={this.onSend} onDismiss={this.onCancelConfirmation} />;
+ private renderNoEmailDialog() {
+ const message = messages.pgettext(
+ 'support-view',
+ 'You are about to send the problem report without a way for us to get back to you. If you want an answer to your report you will have to enter an email address.',
+ );
+ return (
+ <ModalAlert
+ message={message}
+ buttons={[
+ <AppButton.RedButton key="proceed" onPress={this.onSend}>
+ {messages.pgettext('support-view', 'Send anyway')}
+ </AppButton.RedButton>,
+ <AppButton.BlueButton key="cancel" onPress={this.onCancelNoEmailDialog}>
+ {messages.pgettext('support-view', 'Back')}
+ </AppButton.BlueButton>,
+ ]}
+ />
+ );
+ }
+
+ private acknowledgeOutdateVersion = () => {
+ this.setState({ showOutdatedVersionWarning: false });
+ };
+
+ private openDownloadLink = () => this.props.onExternalLink(links.download);
+
+ private renderOutdateVersionWarningDialog() {
+ const message = messages.pgettext(
+ 'support-view',
+ 'You are using an old version of the app. Please upgrade and see if the problem still exists before sending a report.',
+ );
+ return (
+ <ModalAlert
+ message={message}
+ buttons={[
+ <AppButton.GreenButton
+ key="upgrade"
+ disabled={this.props.isOffline}
+ onPress={this.openDownloadLink}>
+ <AppButton.Label>{messages.pgettext('support-view', 'Upgrade app')}</AppButton.Label>
+ <AppButton.Icon height={16} width={16} source="icon-extLink" />
+ </AppButton.GreenButton>,
+ <AppButton.RedButton key="proceed" onPress={this.acknowledgeOutdateVersion}>
+ {messages.pgettext('support-view', 'Continue anyway')}
+ </AppButton.RedButton>,
+ <AppButton.BlueButton key="cancel" onPress={this.props.onClose}>
+ {messages.pgettext('support-view', 'Cancel')}
+ </AppButton.BlueButton>,
+ ]}
+ />
+ );
}
private renderForm() {
@@ -388,39 +440,3 @@ export default class Support extends Component<ISupportProps, ISupportState> {
});
}
}
-
-interface IConfirmNoEmailDialogProps {
- onConfirm: () => void;
- onDismiss: () => void;
-}
-
-class ConfirmNoEmailDialog extends Component<IConfirmNoEmailDialogProps> {
- public render() {
- return (
- <View style={styles.confirm_no_email_background}>
- <View style={styles.confirm_no_email_dialog}>
- <Text style={styles.confirm_no_email_warning}>
- {messages.pgettext(
- 'support-view',
- 'You are about to send the problem report without a way for us to get back to you. If you want an answer to your report you will have to enter an email address.',
- )}
- </Text>
- <AppButton.GreenButton onPress={this.confirm}>
- {messages.pgettext('support-view', 'Send anyway')}
- </AppButton.GreenButton>
- <AppButton.RedButton onPress={this.dismiss} style={styles.confirm_no_email_back_button}>
- {messages.pgettext('support-view', 'Back')}
- </AppButton.RedButton>
- </View>
- </View>
- );
- }
-
- private confirm = () => {
- this.props.onConfirm();
- };
-
- private dismiss = () => {
- this.props.onDismiss();
- };
-}
diff --git a/gui/src/renderer/components/SupportStyles.tsx b/gui/src/renderer/components/SupportStyles.tsx
index 05fd89bfd0..d883c806ba 100644
--- a/gui/src/renderer/components/SupportStyles.tsx
+++ b/gui/src/renderer/components/SupportStyles.tsx
@@ -114,26 +114,4 @@ export default {
color: colors.white,
marginBottom: 4,
}),
- confirm_no_email_background: Styles.createViewStyle({
- flex: 1,
- justifyContent: 'center',
- paddingLeft: 14,
- paddingRight: 14,
- }),
- confirm_no_email_dialog: Styles.createViewStyle({
- backgroundColor: colors.darkBlue,
- borderRadius: 11,
- padding: 16,
- }),
- confirm_no_email_warning: Styles.createTextStyle({
- fontFamily: 'Open Sans',
- fontSize: 16,
- fontWeight: '500',
- lineHeight: 20,
- color: colors.white80,
- marginBottom: 12,
- }),
- confirm_no_email_back_button: Styles.createViewStyle({
- marginTop: 16,
- }),
};
diff --git a/gui/src/renderer/containers/SupportPage.tsx b/gui/src/renderer/containers/SupportPage.tsx
index 755e67f4de..d666afbd55 100644
--- a/gui/src/renderer/containers/SupportPage.tsx
+++ b/gui/src/renderer/containers/SupportPage.tsx
@@ -12,6 +12,7 @@ const mapStateToProps = (state: IReduxState) => ({
defaultMessage: state.support.message,
accountHistory: state.account.accountHistory,
isOffline: state.connection.isBlocked,
+ outdatedVersion: state.version.currentIsOutdated,
});
const mapDispatchToProps = (dispatch: ReduxDispatch) => {
@@ -29,6 +30,7 @@ const mapDispatchToProps = (dispatch: ReduxDispatch) => {
clearReportForm,
collectProblemReport,
sendProblemReport,
+ onExternalLink: (url: string) => shell.openExternal(url),
};
};