summaryrefslogtreecommitdiffhomepage
path: root/gui
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2018-12-08 11:15:13 -0200
committerAndrej Mihajlov <and@mullvad.net>2019-01-15 16:16:20 +0100
commitb589b008a014a2ea3733796bc31121acd391b1a6 (patch)
tree44a6ed46a7956ab224474f92b2014cbec432574a /gui
parente094b526b94bf75ccf25fc5e575cc641a62071ab (diff)
downloadmullvadvpn-b589b008a014a2ea3733796bc31121acd391b1a6.tar.xz
mullvadvpn-b589b008a014a2ea3733796bc31121acd391b1a6.zip
Add custom modal container
Diffstat (limited to 'gui')
-rw-r--r--gui/packages/components/src/Modal.tsx52
-rw-r--r--gui/packages/components/src/index.ts1
-rw-r--r--gui/packages/desktop/src/renderer/components/Support.js174
-rw-r--r--gui/packages/desktop/src/renderer/components/SupportStyles.js22
4 files changed, 181 insertions, 68 deletions
diff --git a/gui/packages/components/src/Modal.tsx b/gui/packages/components/src/Modal.tsx
new file mode 100644
index 0000000000..6eb070262b
--- /dev/null
+++ b/gui/packages/components/src/Modal.tsx
@@ -0,0 +1,52 @@
+import * as React from 'react';
+
+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>
+ );
+ }
+}
+
+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>
+ );
+ }
+}
+
+interface IModalContainerProps {
+ children?: Array<React.ReactElement<ModalContent | ModalAlert>>;
+}
+
+export class ModalContainer extends React.Component<IModalContainerProps> {
+ public render() {
+ return <div style={{ position: 'relative', flex: 1 }}>{this.props.children}</div>;
+ }
+}
diff --git a/gui/packages/components/src/index.ts b/gui/packages/components/src/index.ts
index 46c4ec3195..31c5ee6fec 100644
--- a/gui/packages/components/src/index.ts
+++ b/gui/packages/components/src/index.ts
@@ -5,3 +5,4 @@ export { default as SecuredLabel, SecuredDisplayStyle } from './SecuredLabel';
export { default as HeaderBar, HeaderBarStyle, Brand, SettingsBarButton } from './HeaderBar';
export { default as SettingsHeader, HeaderTitle, HeaderSubTitle } from './SettingsHeader';
export { default as ImageView } from './ImageView';
+export { ModalContainer, ModalAlert, ModalContent } from './Modal';
diff --git a/gui/packages/desktop/src/renderer/components/Support.js b/gui/packages/desktop/src/renderer/components/Support.js
index 7db2f7458b..0398976589 100644
--- a/gui/packages/desktop/src/renderer/components/Support.js
+++ b/gui/packages/desktop/src/renderer/components/Support.js
@@ -2,7 +2,15 @@
import * as React from 'react';
import { Component, Text, View, TextInput } from 'reactxp';
-import { ImageView, SettingsHeader, HeaderTitle, HeaderSubTitle } from '@mullvad/components';
+import {
+ ImageView,
+ SettingsHeader,
+ HeaderTitle,
+ HeaderSubTitle,
+ ModalContainer,
+ ModalContent,
+ ModalAlert,
+} from '@mullvad/components';
import * as AppButton from './AppButton';
import { Layout, Container } from './Layout';
import { NavigationBar, BackBarItem } from './NavigationBar';
@@ -14,7 +22,7 @@ type SupportState = {
email: string,
message: string,
savedReport: ?string,
- sendState: 'INITIAL' | 'CONFIRM_NO_EMAIL' | 'LOADING' | 'SUCCESS' | 'FAILED',
+ sendState: 'INITIAL' | 'CONFIRM' | 'LOADING' | 'SUCCESS' | 'FAILED',
};
export type SupportProps = {
@@ -103,17 +111,36 @@ export default class Support extends Component<SupportProps, SupportState> {
}
onSend = async (): Promise<void> => {
- if (this.state.sendState === 'INITIAL' && this.state.email.length === 0) {
- return new Promise((resolve) => {
- this.setState({ sendState: 'CONFIRM_NO_EMAIL' }, () => resolve());
- });
- } else {
- try {
- await this._sendReport();
- } catch (error) {
- // No-op
- }
+ switch (this.state.sendState) {
+ case 'INITIAL':
+ if (this.state.email.length === 0) {
+ this.setState({ sendState: 'CONFIRM' });
+ } else {
+ try {
+ await this._sendReport();
+ } catch (error) {
+ // No-op
+ }
+ }
+ return Promise.resolve();
+
+ case 'CONFIRM':
+ try {
+ await this._sendReport();
+ } catch (error) {
+ // No-op
+ }
+ return Promise.resolve();
+
+ default:
+ break;
}
+
+ return Promise.resolve();
+ };
+
+ onCancelConfirmation = () => {
+ this.setState({ sendState: 'INITIAL' });
};
_sendReport(): Promise<void> {
@@ -141,7 +168,7 @@ export default class Support extends Component<SupportProps, SupportState> {
const header = (
<SettingsHeader>
<HeaderTitle>Report a problem</HeaderTitle>
- {(sendState === 'INITIAL' || sendState === 'CONFIRM_NO_EMAIL') && (
+ {(sendState === 'INITIAL' || sendState === 'CONFIRM') && (
<HeaderSubTitle>
{
"To help you more effectively, your app's log file will be attached to this message. Your data will remain secure and private, as it is anonymised before being sent over an encrypted channel."
@@ -156,17 +183,20 @@ export default class Support extends Component<SupportProps, SupportState> {
return (
<Layout>
<Container>
- <View style={styles.support}>
- <NavigationBar>
- <BackBarItem action={this.props.onClose} title={'Settings'} />
- </NavigationBar>
-
- <View style={styles.support__container}>
- {header}
-
- {content}
- </View>
- </View>
+ <ModalContainer>
+ <ModalContent>
+ <View style={styles.support}>
+ <NavigationBar>
+ <BackBarItem action={this.props.onClose} title={'Settings'} />
+ </NavigationBar>
+ <View style={styles.support__container}>
+ {header}
+ {content}
+ </View>
+ </View>
+ </ModalContent>
+ {sendState === 'CONFIRM' && <ModalAlert>{this._renderConfirm()}</ModalAlert>}
+ </ModalContainer>
</Container>
</Layout>
);
@@ -175,7 +205,7 @@ export default class Support extends Component<SupportProps, SupportState> {
_renderContent() {
switch (this.state.sendState) {
case 'INITIAL':
- case 'CONFIRM_NO_EMAIL':
+ case 'CONFIRM':
return this._renderForm();
case 'LOADING':
return this._renderLoading();
@@ -188,6 +218,10 @@ export default class Support extends Component<SupportProps, SupportState> {
}
}
+ _renderConfirm() {
+ return <ConfirmNoEmailDialog onConfirm={this.onSend} onDismiss={this.onCancelConfirmation} />;
+ }
+
_renderForm() {
return (
<View style={styles.support__content}>
@@ -214,52 +248,25 @@ export default class Support extends Component<SupportProps, SupportState> {
</View>
</View>
<View style={styles.support__footer}>
- {this.state.sendState === 'CONFIRM_NO_EMAIL'
- ? this._renderNoEmailWarning()
- : this._renderActionButtons()}
+ <AppButton.BlueButton
+ style={styles.view_logs_button}
+ onPress={this.onViewLog}
+ testName="support__view_logs">
+ <AppButton.Label>View app logs</AppButton.Label>
+ <ImageView source="icon-extLink" height={16} width={16} />
+ </AppButton.BlueButton>
+ <AppButton.GreenButton
+ disabled={!this.validate()}
+ onPress={this.onSend}
+ testName="support__send_logs">
+ Send
+ </AppButton.GreenButton>
</View>
</View>
</View>
);
}
- _renderNoEmailWarning() {
- return (
- <View>
- <Text style={styles.support__no_email_warning}>
- 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
- disabled={!this.validate()}
- onPress={this.onSend}
- testName="support__send_logs">
- {'Send anyway'}
- </AppButton.GreenButton>
- </View>
- );
- }
-
- _renderActionButtons() {
- return (
- <View>
- <AppButton.BlueButton
- style={styles.view_logs_button}
- onPress={this.onViewLog}
- testName="support__view_logs">
- <AppButton.Label>View app logs</AppButton.Label>
- <ImageView source="icon-extLink" height={16} width={16} />
- </AppButton.BlueButton>
- <AppButton.GreenButton
- disabled={!this.validate() || this.props.isOffline}
- onPress={this.onSend}
- testName="support__send_logs">
- Send
- </AppButton.GreenButton>
- </View>
- );
- }
-
_renderLoading() {
return (
<View style={styles.support__content}>
@@ -331,3 +338,40 @@ export default class Support extends Component<SupportProps, SupportState> {
);
}
}
+
+type ConfirmNoEmailDialogProps = {
+ onConfirm: () => void,
+ onDismiss: () => void,
+};
+
+class ConfirmNoEmailDialog extends Component<ConfirmNoEmailDialogProps> {
+ render() {
+ return (
+ <View style={styles.confirm_no_email_background}>
+ <View style={styles.confirm_no_email_dialog}>
+ <Text style={styles.confirm_no_email_warning}>
+ 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.props.onConfirm} testName="support__send_logs">
+ {'Send anyway'}
+ </AppButton.GreenButton>
+ <AppButton.RedButton
+ onPress={this._dismiss}
+ style={styles.confirm_no_email_back_button}
+ testName="support__back">
+ {'Back'}
+ </AppButton.RedButton>
+ </View>
+ </View>
+ );
+ }
+
+ _confirm = () => {
+ this.props.onConfirm();
+ };
+
+ _dismiss = () => {
+ this.props.onDismiss();
+ };
+}
diff --git a/gui/packages/desktop/src/renderer/components/SupportStyles.js b/gui/packages/desktop/src/renderer/components/SupportStyles.js
index e3b8491862..c2b4e2dbb7 100644
--- a/gui/packages/desktop/src/renderer/components/SupportStyles.js
+++ b/gui/packages/desktop/src/renderer/components/SupportStyles.js
@@ -119,11 +119,27 @@ export default {
color: colors.white,
marginBottom: 4,
}),
- support__no_email_warning: Styles.createTextStyle({
+ confirm_no_email_background: Styles.createViewStyle({
+ display: 'flex',
+ 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: 13,
- lineHeight: 16,
+ fontSize: 16,
+ fontWeight: '500',
+ lineHeight: 20,
color: colors.white80,
marginBottom: 12,
}),
+ confirm_no_email_back_button: Styles.createViewStyle({
+ marginTop: 16,
+ }),
};