summaryrefslogtreecommitdiffhomepage
path: root/app/components/Support.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/components/Support.js')
-rw-r--r--app/components/Support.js254
1 files changed, 254 insertions, 0 deletions
diff --git a/app/components/Support.js b/app/components/Support.js
new file mode 100644
index 0000000000..04e6c7392d
--- /dev/null
+++ b/app/components/Support.js
@@ -0,0 +1,254 @@
+// @flow
+import React, { Component } from 'react';
+import { Layout, Container, Header } from './Layout';
+import ExternalLinkSVG from '../assets/images/icon-extLink.svg';
+
+import type { AccountReduxState } from '../redux/account/reducers';
+
+export type SupportReport = {
+ email: string,
+ message: string,
+ savedReport: ?string,
+};
+
+export type SupportState = {
+ email: string,
+ message: string,
+ savedReport: ?string,
+ sendState: 'INITIAL' | 'LOADING' | 'SUCCESS' | 'FAILED',
+};
+export type SupportProps = {
+ account: AccountReduxState,
+ onClose: () => void;
+ onViewLog: (string) => void;
+ onCollectLog: (Array<string>) => Promise<string>;
+ onSend: (email: string, message: string, savedReport: string) => void;
+};
+
+export default class Support extends Component {
+ props: SupportProps;
+ state: SupportState = {
+ email: '',
+ message: '',
+ savedReport: null,
+ sendState: 'INITIAL',
+ }
+
+ validate() {
+ return this.state.message.trim().length > 0;
+ }
+
+ onChangeEmail = (e: Event) => {
+ const input = e.target;
+ if(!(input instanceof HTMLInputElement)) {
+ throw new Error('input must be an instance of HTMLInputElement');
+ }
+ this.setState({ email: input.value });
+ }
+
+ onChangeDescription = (e: Event) => {
+ const input = e.target;
+ if(!(input instanceof HTMLTextAreaElement)) {
+ throw new Error('input must be an instance of HTMLTextAreaElement');
+ }
+ this.setState({ message: input.value });
+ }
+
+ onViewLog = () => {
+
+ this._getLog()
+ .then((path) => {
+ this.props.onViewLog(path);
+ });
+ }
+
+ _getLog() {
+ const toRedact = [];
+ if (this.props.account.accountToken) {
+ toRedact.push(this.props.account.accountToken.toString());
+ }
+
+ const { savedReport } = this.state;
+ return savedReport ?
+ Promise.resolve(savedReport) :
+ this.props.onCollectLog(toRedact)
+ .then( path => {
+ return new Promise(resolve => this.setState({ savedReport: path }, () => resolve(path)));
+ });
+ }
+
+ onSend = () => {
+ this.setState({
+ sendState: 'LOADING',
+ }, () => {
+ this._getLog()
+ .then((path) => {
+ return this.props.onSend(this.state.email, this.state.message, path);
+ })
+ .then( () => {
+ this.setState({
+ sendState: 'SUCCESS',
+ });
+ })
+ .catch( () => {
+ this.setState({
+ sendState: 'FAILED',
+ });
+ });
+ });
+ }
+
+ render() {
+
+ const header = <div className="support__header">
+ <h2 className="support__title">Report a problem</h2>
+ { this.state.sendState === 'INITIAL' && <div className="support__subtitle">
+ { `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 encrypted & anonymised before sending.` }
+ </div>
+ }
+ </div>;
+
+ const content = this._renderContent();
+
+ return (
+ <Layout>
+ <Header hidden={ true } style={ 'defaultDark' } />
+ <Container>
+ <div className="support">
+ <div className="support__close" onClick={ this.props.onClose }>
+ <img className="support__close-icon" src="./assets/images/icon-back.svg" />
+ <span className="support__close-title">Settings</span>
+ </div>
+ <div className="support__container">
+
+ { header }
+
+ { content }
+
+ </div>
+ </div>
+ </Container>
+ </Layout>
+ );
+ }
+
+ _renderContent() {
+ switch(this.state.sendState) {
+ case 'INITIAL':
+ return this._renderForm();
+ case 'LOADING':
+ return this._renderLoading();
+ case 'SUCCESS':
+ return this._renderSent();
+ case 'FAILED':
+ return this._renderFailed();
+ default:
+ return null;
+ }
+ }
+
+ _renderForm() {
+ return <div className="support__content">
+ <div className="support__form">
+ <div className="support__form-row">
+ <input className="support__form-email"
+ type="email"
+ placeholder="Your email"
+ value={ this.state.email }
+ onChange={ this.onChangeEmail }
+ autoFocus={ true } />
+ </div>
+ <div className="support__form-row support__form-row-message">
+ <div className="support__form-message-scroll-wrap">
+ <textarea className="support__form-message"
+ placeholder="Describe your problem"
+ value={ this.state.message }
+ onChange={ this.onChangeDescription } />
+ </div>
+ </div>
+ <div className="support__footer">
+ <button type="button"
+ className="support__form-view-logs button button--primary"
+ onClick={ this.onViewLog }>
+ <span className="button-label">View app logs</span>
+ <ExternalLinkSVG className="button-icon button-icon--16" />
+ </button>
+ <button type="button"
+ className="support__form-send button button--positive"
+ disabled={ !this.validate() }
+ onClick={ this.onSend }>Send</button>
+ </div>
+ </div>
+ </div>;
+ }
+
+ _renderLoading() {
+ return <div className="support__content">
+
+ <div className="support__form">
+ <div className="support__form-row">
+ <div className="support__status-icon">
+ <img src="./assets/images/icon-spinner.svg" alt="" />
+ </div>
+ <div className="support__status-security--secure">
+ Secure Connection
+ </div>
+ <div className="support__send-status">
+ <span>Sending...</span>
+ </div>
+ </div>
+ </div>
+ </div>;
+ }
+
+ _renderSent() {
+ return <div className="support__content">
+ <div className="support__form">
+ <div className="support__form-row">
+ <div className="support__status-icon">
+ <img src="./assets/images/icon-success.svg" alt="" />
+ </div>
+ <div className="support__status-security--secure">
+ Secure Connection
+ </div>
+ <div className="support__send-status">
+ <span>Sent</span>
+ </div>
+ <div className="support__subtitle">
+ Thanks! We will look into this. If needed we will contact you on {'\u00A0'}
+ <div className="support__sent-email">{ this.state.email }</div>
+ </div>
+ </div>
+ </div>
+ </div>;
+ }
+
+ _renderFailed() {
+ return <div className="support__content">
+ <div className="support__form">
+ <div className="support__form-row">
+ <div className="support__status-icon">
+ <img src="./assets/images/icon-fail.svg" alt="" />
+ </div>
+ <div className="support__status-security--secure">
+ Secure Connection
+ </div>
+ <div className="support__send-status">
+ <span>Failed to send</span>
+ </div>
+ </div>
+ </div>
+ <div className="support__footer">
+ <button type="button"
+ className="support__form-view-logs button button--primary"
+ onClick={ () => this.setState({ sendState: 'INITIAL' }) }>
+ <span className="button-label">Edit message</span>
+ </button>
+ <button type="button"
+ className="support__form-send button button--positive"
+ onClick={ this.onSend }>Try again</button>
+ </div>
+ </div>;
+ }
+}