diff options
| author | Erik Larkö <erik@mullvad.net> | 2017-11-02 10:51:12 +0100 |
|---|---|---|
| committer | Erik Larkö <erik@mullvad.net> | 2017-11-09 12:42:56 +0100 |
| commit | ae8e86bb81cc722d9667c439d3508660398da707 (patch) | |
| tree | 05a467e918755c290194df119d5977862d1e6f4b /app/components/Support.js | |
| parent | 01d617bab821f25412f4874354468afea30bd7b9 (diff) | |
| download | mullvadvpn-ae8e86bb81cc722d9667c439d3508660398da707.tar.xz mullvadvpn-ae8e86bb81cc722d9667c439d3508660398da707.zip | |
Problem report
Diffstat (limited to 'app/components/Support.js')
| -rw-r--r-- | app/components/Support.js | 232 |
1 files changed, 185 insertions, 47 deletions
diff --git a/app/components/Support.js b/app/components/Support.js index 783133568f..2dcb6ad1ee 100644 --- a/app/components/Support.js +++ b/app/components/Support.js @@ -5,25 +5,34 @@ import ExternalLinkSVG from '../assets/images/icon-extLink.svg'; export type SupportReport = { email: string, - description: string + message: string, + savedReport: ?string, }; -export type SupportState = SupportReport; +export type SupportState = { + email: string, + message: string, + savedReport: ?string, + sendState: 'INITIAL' | 'LOADING' | 'SUCCESS' | 'FAILED', +}; export type SupportProps = { onClose: () => void; - onViewLogs: () => void; - onSend: (report: SupportReport) => void; + onViewLog: (string) => void; + onCollectLog: () => Promise<string>; + onSend: (email: string, message: string, savedReport: string) => void; }; export default class Support extends Component { props: SupportProps; state: SupportState = { email: '', - description: '' + message: '', + savedReport: null, + sendState: 'INITIAL', } validate() { - return this.state.description.trim().length > 0; + return this.state.message.trim().length > 0; } onChangeEmail = (e: Event) => { @@ -39,14 +48,61 @@ export default class Support extends Component { if(!(input instanceof HTMLTextAreaElement)) { throw new Error('input must be an instance of HTMLTextAreaElement'); } - this.setState({ description: input.value }); + this.setState({ message: input.value }); + } + + onViewLog = () => { + + this._getLog() + .then((path) => { + this.props.onViewLog(path); + }); + } + + _getLog() { + const { savedReport } = this.state; + return savedReport ? + Promise.resolve(savedReport) : + this.props.onCollectLog() + .then( path => { + return new Promise(resolve => this.setState({ savedReport: path }, () => resolve(path))); + }); } onSend = () => { - this.props.onSend(this.state); + 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' } /> @@ -58,46 +114,9 @@ export default class Support extends Component { </div> <div className="support__container"> - <div className="support__header"> - <h2 className="support__title">Contact support</h2> - <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> + { header } - <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--description"> - <div className="support__form-description-scroll-wrap"> - <textarea className="support__form-description" - placeholder="Describe your problem" - value={ this.state.description } - onChange={ this.onChangeDescription } /> - </div> - </div> - <div className="support__footer"> - <button type="button" - className="button button--primary" - onClick={ this.props.onViewLogs }> - <span className="support__form-view-logs 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> + { content } </div> </div> @@ -105,4 +124,123 @@ export default class Support extends Component { </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>; + } } |
