summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnike Arni <anikarni@gmail.com>2017-02-08 13:51:11 -0200
committerGitHub <noreply@github.com>2017-02-08 13:51:11 -0200
commita1c384cebd80e177389ef79c2de6400db986aaa6 (patch)
tree7d2e14fbf931fd50769510bfc5809f41e5c48dbf
parent48e5acd386123a06586c20bf192fc18b5471da13 (diff)
parentaa26a47abac48d817a04a4f2375f1378767fa83c (diff)
Merge pull request #964 from pixelated/backup-email-page
Refactoring react code
-rw-r--r--web-ui/.jshintignore5
-rw-r--r--web-ui/app/js/account_recovery.js18
-rw-r--r--web-ui/app/js/account_recovery/page.js28
-rw-r--r--web-ui/config/alias-webpack.js1
-rw-r--r--web-ui/config/copy-webpack.js2
-rw-r--r--web-ui/karma.conf.js2
-rw-r--r--web-ui/package.json3
-rw-r--r--web-ui/src/account_recovery/account_recovery.html (renamed from web-ui/app/account_recovery.html)0
-rw-r--r--web-ui/src/account_recovery/account_recovery.js35
-rw-r--r--web-ui/src/account_recovery/page.js44
-rw-r--r--web-ui/src/account_recovery/page.scss (renamed from web-ui/app/scss/account_recovery/page.scss)94
-rw-r--r--web-ui/src/common/input_field/input-field.scss77
-rw-r--r--web-ui/src/common/input_field/input_field.js29
-rw-r--r--web-ui/src/common/submit_button/submit-button.scss48
-rw-r--r--web-ui/src/common/submit_button/submit_button.js26
-rw-r--r--web-ui/src/i18n.js (renamed from web-ui/app/js/account_recovery/i18n.js)0
-rw-r--r--web-ui/test/jasmine.json9
-rw-r--r--web-ui/test/spec/account_recovery/page.spec.js12
-rw-r--r--web-ui/test/test-main.js2
-rw-r--r--web-ui/test/unit/account_recovery/page.spec.js25
-rw-r--r--web-ui/webpack.config.js2
-rw-r--r--web-ui/webpack.production.config.js2
22 files changed, 316 insertions, 148 deletions
diff --git a/web-ui/.jshintignore b/web-ui/.jshintignore
index df04d870..b28da15f 100644
--- a/web-ui/.jshintignore
+++ b/web-ui/.jshintignore
@@ -2,6 +2,5 @@ app/node_modules
app/bower_components
app/js/lib
app/js/generated
-app/js/account_recovery.js
-app/js/account_recovery
-test/spec/account_recovery
+src/
+test/unit
diff --git a/web-ui/app/js/account_recovery.js b/web-ui/app/js/account_recovery.js
deleted file mode 100644
index cd01378d..00000000
--- a/web-ui/app/js/account_recovery.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react'
-import { render } from 'react-dom'
-import a11y from 'react-a11y'
-import { I18nextProvider } from 'react-i18next'
-
-import Page from 'js/account_recovery/page'
-import i18n from 'js/account_recovery/i18n'
-
-import 'font-awesome/scss/font-awesome.scss'
-
-if(process.env.NODE_ENV === 'development') a11y(React);
-
-render(
- <I18nextProvider i18n={ i18n }>
- <Page/>
- </I18nextProvider>,
- document.getElementById('root')
-);
diff --git a/web-ui/app/js/account_recovery/page.js b/web-ui/app/js/account_recovery/page.js
deleted file mode 100644
index a94c2c45..00000000
--- a/web-ui/app/js/account_recovery/page.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import React from 'react'
-import { translate } from 'react-i18next'
-
-import 'scss/account_recovery/page.scss'
-
-export const Page = ({ t }) => (
- <div className='container'>
- <img src='assets/images/forgot-my-password.svg' alt={t('backup-account.image-description')}/>
- <form>
- <h1>{t('backup-account.title')}</h1>
- <p>{t('backup-account.paragraph1')}</p>
- <p>{t('backup-account.paragraph2')}</p>
- <div className="field-group">
- <input type="text" name="email" className="email" required/>
- <label className="animated-label" htmlFor="email">{t('backup-account.input-label')}</label>
- </div>
- <button>{t('backup-account.button')}</button>
- <div>
- <a href="/">
- <i className="fa fa-angle-left" aria-hidden="true"></i>
- <span>{t('back-to-inbox')}</span>
- </a>
- </div>
- </form>
- </div>
-)
-
-export default translate('', { wait: true })(Page)
diff --git a/web-ui/config/alias-webpack.js b/web-ui/config/alias-webpack.js
index 43b23836..d316bb2d 100644
--- a/web-ui/config/alias-webpack.js
+++ b/web-ui/config/alias-webpack.js
@@ -7,6 +7,7 @@ module.exports = {
'flight': path.join(__dirname, '../app/bower_components/flight'),
'found': path.join(__dirname, '../app/bower_components/foundation'),
'js': path.join(__dirname, '../app/js'),
+ 'src': path.join(__dirname, '../src'),
'scss': path.join(__dirname, '../app/scss'),
'mail_list': path.join(__dirname, '../app/js/mail_list'),
'page': path.join(__dirname, '../app/js/page'),
diff --git a/web-ui/config/copy-webpack.js b/web-ui/config/copy-webpack.js
index a2567be6..8e9f9dd3 100644
--- a/web-ui/config/copy-webpack.js
+++ b/web-ui/config/copy-webpack.js
@@ -4,7 +4,7 @@ module.exports = new CopyWebpackPlugin([
{ context: 'app/', from: '404.html' },
{ context: 'app/', from: 'index.html' },
{ context: 'app/', from: 'sandbox.html' },
- { context: 'app/', from: 'account_recovery.html' },
+ { context: 'src/account_recovery/', from: 'account_recovery.html' },
{ context: 'app/', from: 'css/*' },
{ context: 'app/', from: 'fonts/*' },
{ context: 'app/', from: 'locales/**/*' },
diff --git a/web-ui/karma.conf.js b/web-ui/karma.conf.js
index d10667e9..2895dc42 100644
--- a/web-ui/karma.conf.js
+++ b/web-ui/karma.conf.js
@@ -68,7 +68,7 @@ module.exports = function (config) {
reporters: ['dots', 'junit', 'coverage'],
preprocessors: {
- 'app/js/!(lib|account_recovery)/**/*.js': ['coverage']
+ 'app/js/!(lib)/**/*.js': ['coverage']
},
// enable / disable watching file and executing tests whenever any file changes
diff --git a/web-ui/package.json b/web-ui/package.json
index ff4201c0..dba34e97 100644
--- a/web-ui/package.json
+++ b/web-ui/package.json
@@ -65,7 +65,8 @@
},
"scripts": {
"test": "npm run jshint --silent && npm run build-statics --silent && npm run mocha-test && npm run karma-test",
- "mocha-test": "mocha-webpack --webpack-config webpack.test.config.js \"test/spec/account_recovery/**/*.spec.js\"",
+ "mocha-test": "mocha-webpack --webpack-config webpack.test.config.js \"test/unit/**/*.spec.js\"",
+ "mocha-watch": "mocha-webpack --watch --webpack-config webpack.test.config.js \"test/unit/**/*.spec.js\"",
"karma-test": "karma start --single-run $GRUNT_OPTS",
"debug": "npm run build && karma start --browsers Chrome $GRUNT_OPTS",
"watch": "npm run compass-watch & npm run handlebars-watch & npm run build-js-watch",
diff --git a/web-ui/app/account_recovery.html b/web-ui/src/account_recovery/account_recovery.html
index bd451ebc..bd451ebc 100644
--- a/web-ui/app/account_recovery.html
+++ b/web-ui/src/account_recovery/account_recovery.html
diff --git a/web-ui/src/account_recovery/account_recovery.js b/web-ui/src/account_recovery/account_recovery.js
new file mode 100644
index 00000000..6c12e326
--- /dev/null
+++ b/web-ui/src/account_recovery/account_recovery.js
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import React from 'react'
+import { render } from 'react-dom'
+import a11y from 'react-a11y'
+import { I18nextProvider } from 'react-i18next'
+
+import Page from './page'
+import i18n from '../i18n'
+
+import 'font-awesome/scss/font-awesome.scss'
+
+if(process.env.NODE_ENV === 'development') a11y(React);
+
+render(
+ <I18nextProvider i18n={ i18n }>
+ <Page/>
+ </I18nextProvider>,
+ document.getElementById('root')
+);
diff --git a/web-ui/src/account_recovery/page.js b/web-ui/src/account_recovery/page.js
new file mode 100644
index 00000000..d1bcb464
--- /dev/null
+++ b/web-ui/src/account_recovery/page.js
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import React from 'react'
+import { translate } from 'react-i18next'
+import SubmitButton from 'src/common/submit_button/submit_button'
+import InputField from 'src/common/input_field/input_field'
+
+import './page.scss'
+
+export const Page = ({ t }) => (
+ <div className='container'>
+ <img src='assets/images/forgot-my-password.svg' alt={t('backup-account.image-description')} />
+ <form>
+ <h1>{t('backup-account.title')}</h1>
+ <p>{t('backup-account.paragraph1')}</p>
+ <p>{t('backup-account.paragraph2')}</p>
+ <InputField name='email' label={t('backup-account.input-label')} />
+ <SubmitButton buttonText={t('backup-account.button')} />
+ <div>
+ <a href="/">
+ <i className="fa fa-angle-left" aria-hidden="true"></i>
+ <span>{t('back-to-inbox')}</span>
+ </a>
+ </div>
+ </form>
+ </div>
+)
+
+export default translate('', { wait: true })(Page)
diff --git a/web-ui/app/scss/account_recovery/page.scss b/web-ui/src/account_recovery/page.scss
index 8bba1b5a..c928d815 100644
--- a/web-ui/app/scss/account_recovery/page.scss
+++ b/web-ui/src/account_recovery/page.scss
@@ -1,6 +1,23 @@
-@import "../vendor/reset";
-@import "../base/colors";
-@import "../base/fonts";
+/*
+ * Copyright (c) 2017 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+@import "~scss/vendor/reset";
+@import "~scss/base/colors";
+@import "~scss/base/fonts";
html {
min-height: 100%;
@@ -43,63 +60,6 @@ a {
}
-.field-group {
- position:relative;
- margin: 1.5em 0;
- width: 100%;
-
- label {
- font-size: 0.9em;
- margin-bottom: 10px;
- display: inline-block;
- }
-
- input {
- display: block;
- border: none;
- border-bottom: solid 1px #4da3b6;
- width: 100%;
- height: auto;
- padding: 0.3em 0px;
- }
-
- input:focus {
- outline:none;
- border-width: 2px;
- }
-
- input:focus ~ .animated-label, input:valid ~ .animated-label {
- top:-12px;
- left: 0;
- font-size:0.7em;
- color:#4da3b6;
- }
-
- .animated-label {
- color:#999;
- position:absolute;
- pointer-events:none;
- left: 6px;
- top:10px;
- transition:0.2s ease all;
- -moz-transition:0.2s ease all;
- -webkit-transition:0.2s ease all;
- }
-}
-
-
-button {
- background: $dark_blue;
- padding: 0.8em;
- color: $white;
- text-align: center;
- border: none;
- border-radius: 2px;
- font-weight: 300;
- width: 100%;
- margin-bottom: 1em;
-}
-
.container {
background: $white;
width: 84%;
@@ -131,7 +91,7 @@ img {
-webkit-flex-direction: column;
flex-direction: column;
- .field-group, button, div {
+ div {
width: 70%;
-webkit-align-self: center;
align-self: center;
@@ -153,24 +113,14 @@ img {
form {
margin-left: 2.5em;
- .field-group, button, div {
+ div {
width: 300px;
-webkit-align-self: flex-start;
align-self: flex-start;
}
-
- .field-group {
- margin-top: 3em;
- font-size: 1em;
- }
}
img {
width: 300px;
}
-
- button {
- font-size: 0.8em;
- margin-bottom: 1em;
- }
}
diff --git a/web-ui/src/common/input_field/input-field.scss b/web-ui/src/common/input_field/input-field.scss
new file mode 100644
index 00000000..6ec827ab
--- /dev/null
+++ b/web-ui/src/common/input_field/input-field.scss
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+@import "~scss/base/colors";
+
+.input-field-group {
+ position:relative;
+ margin: 1.5em 0;
+ width: 100%;
+}
+
+.input-field-label {
+ font-size: 0.9em;
+ margin-bottom: 10px;
+ display: inline-block;
+ color:#999;
+ position:absolute;
+ pointer-events:none;
+ left: 6px;
+ top:10px;
+ transition:0.2s ease all;
+ -moz-transition:0.2s ease all;
+ -webkit-transition:0.2s ease all;
+}
+
+.input-field {
+ display: block;
+ border: none;
+ border-bottom: solid 1px $dark_blue;
+ width: 100%;
+ height: auto;
+ padding: 0.3em 0px;
+
+ &:focus {
+ outline:none;
+ border-width: 2px;
+ }
+}
+
+.input-field:focus ~ .input-field-label, .input-field:valid ~ .input-field-label {
+ top:-12px;
+ left: 0;
+ font-size:0.7em;
+ color: $dark_blue;
+}
+
+@media only screen and (min-width : 500px) {
+ .input-field-group {
+ width: 70%;
+ -webkit-align-self: center;
+ align-self: center;
+ }
+}
+
+@media only screen and (min-width : 960px) {
+ .input-field-group {
+ width: 300px;
+ -webkit-align-self: flex-start;
+ align-self: flex-start;
+ margin-top: 3em;
+ font-size: 1em;
+ }
+}
diff --git a/web-ui/src/common/input_field/input_field.js b/web-ui/src/common/input_field/input_field.js
new file mode 100644
index 00000000..43899419
--- /dev/null
+++ b/web-ui/src/common/input_field/input_field.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2017 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import React from 'react'
+
+import './input-field.scss'
+
+const InputField = ({ label, name }) => (
+ <div className='input-field-group'>
+ <input type='text' name={name} className='input-field' required />
+ <label className='input-field-label' htmlFor={name}>{label}</label>
+ </div>
+)
+
+export default InputField
diff --git a/web-ui/src/common/submit_button/submit-button.scss b/web-ui/src/common/submit_button/submit-button.scss
new file mode 100644
index 00000000..ccd0bef4
--- /dev/null
+++ b/web-ui/src/common/submit_button/submit-button.scss
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+@import "~scss/base/colors";
+
+.submit-button {
+ background: $dark_blue;
+ padding: 0.8em;
+ color: $white;
+ text-align: center;
+ border: none;
+ border-radius: 2px;
+ font-weight: 300;
+ width: 100%;
+ margin-bottom: 1em;
+}
+
+@media only screen and (min-width : 500px) {
+ .submit-button {
+ width: 70%;
+ -webkit-align-self: center;
+ align-self: center;
+ }
+}
+
+@media only screen and (min-width : 960px) {
+ .submit-button {
+ width: 300px;
+ -webkit-align-self: flex-start;
+ align-self: flex-start;
+ font-size: 0.8em;
+ margin-bottom: 1em;
+ }
+}
diff --git a/web-ui/src/common/submit_button/submit_button.js b/web-ui/src/common/submit_button/submit_button.js
new file mode 100644
index 00000000..89cfc55b
--- /dev/null
+++ b/web-ui/src/common/submit_button/submit_button.js
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2017 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import React from 'react'
+
+import './submit-button.scss'
+
+const SubmitButton = ({ buttonText }) => (
+ <input type='submit' className='submit-button' value={buttonText} />
+)
+
+export default SubmitButton
diff --git a/web-ui/app/js/account_recovery/i18n.js b/web-ui/src/i18n.js
index 9c6ad550..9c6ad550 100644
--- a/web-ui/app/js/account_recovery/i18n.js
+++ b/web-ui/src/i18n.js
diff --git a/web-ui/test/jasmine.json b/web-ui/test/jasmine.json
deleted file mode 100644
index 969304b6..00000000
--- a/web-ui/test/jasmine.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "spec_dir": "test/spec/account_recovery/",
- "spec_files": [
- "**/*[sS]pec.js"
- ],
- "helpers": [
- "helpers/**/*.js"
- ]
-}
diff --git a/web-ui/test/spec/account_recovery/page.spec.js b/web-ui/test/spec/account_recovery/page.spec.js
deleted file mode 100644
index 3e19f244..00000000
--- a/web-ui/test/spec/account_recovery/page.spec.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import {shallow} from 'enzyme'
-import expect from 'expect'
-import React from 'react'
-import { Page } from '../../../app/js/account_recovery/page'
-
-describe('Page', () => {
- it('renders backup email page title', () => {
- const mockT = key => key;
- const page = shallow(<Page t={mockT}/>);
- expect(page.find('h1').text()).toEqual('backup-account.title');
- });
-});
diff --git a/web-ui/test/test-main.js b/web-ui/test/test-main.js
index b7dc430f..4396993f 100644
--- a/web-ui/test/test-main.js
+++ b/web-ui/test/test-main.js
@@ -1,7 +1,7 @@
var tests = Object.keys(window.__karma__.files).filter(function (file) {
'use strict';
- return !(/account_recovery/.test(file)) && (/\.spec\.js$/.test(file));
+ return (/\.spec\.js$/.test(file));
});
beforeEach(function() {
diff --git a/web-ui/test/unit/account_recovery/page.spec.js b/web-ui/test/unit/account_recovery/page.spec.js
new file mode 100644
index 00000000..590d1de8
--- /dev/null
+++ b/web-ui/test/unit/account_recovery/page.spec.js
@@ -0,0 +1,25 @@
+import { shallow } from 'enzyme'
+import expect from 'expect'
+import React from 'react'
+import { Page } from 'src/account_recovery/page'
+
+describe('Page', () => {
+ let mockT, page
+
+ beforeEach(() => {
+ mockT = (key) => (key)
+ page = shallow(<Page t={mockT}/>)
+ })
+
+ it('renders backup email page title', () => {
+ expect(page.find('h1').text()).toEqual('backup-account.title')
+ })
+
+ it('renders backup account email input field', () => {
+ expect(page.find('InputField').props().name).toEqual('email')
+ })
+
+ it('renders backup account submit button', () => {
+ expect(page.find('SubmitButton').props().buttonText).toEqual('backup-account.button')
+ })
+})
diff --git a/web-ui/webpack.config.js b/web-ui/webpack.config.js
index 5886154a..9171b8f5 100644
--- a/web-ui/webpack.config.js
+++ b/web-ui/webpack.config.js
@@ -7,7 +7,7 @@ var aliases = require('./config/alias-webpack');
module.exports = {
entry: {
app: './app/js/index.js',
- account_recovery: './app/js/account_recovery.js',
+ account_recovery: './src/account_recovery/account_recovery.js',
sandbox: './app/js/sandbox.js'
},
node: { fs: 'empty' },
diff --git a/web-ui/webpack.production.config.js b/web-ui/webpack.production.config.js
index cf8ab8ff..6948d78e 100644
--- a/web-ui/webpack.production.config.js
+++ b/web-ui/webpack.production.config.js
@@ -7,7 +7,7 @@ var aliases = require('./config/alias-webpack');
module.exports = {
entry: {
app: './app/js/index.js',
- account_recovery: './app/js/account_recovery.js',
+ account_recovery: './src/account_recovery/index.js',
sandbox: './app/js/sandbox.js'
},
node: { fs: 'empty' },