diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/services/content/ErrorHandlers/WebviewErrorHandler.js | 2 | ||||
-rw-r--r-- | src/components/services/content/ErrorHandlers/styles.js | 6 | ||||
-rw-r--r-- | src/components/services/content/ServiceWebview.js | 3 | ||||
-rw-r--r-- | src/components/services/content/Services.js | 3 | ||||
-rw-r--r-- | src/components/settings/account/AccountDashboard.js | 71 | ||||
-rw-r--r-- | src/components/settings/user/EditUserForm.js | 25 | ||||
-rw-r--r-- | src/config.js | 3 | ||||
-rw-r--r-- | src/containers/layout/AppLayoutContainer.js | 1 | ||||
-rw-r--r-- | src/environment.js | 6 | ||||
-rw-r--r-- | src/helpers/asar-helpers.js | 3 | ||||
-rw-r--r-- | src/index.js | 113 | ||||
-rw-r--r-- | src/models/Service.js | 4 | ||||
-rw-r--r-- | src/stores/AppStore.js | 7 | ||||
-rw-r--r-- | src/stores/ServicesStore.js | 15 | ||||
-rw-r--r-- | src/stores/UIStore.js | 7 | ||||
-rw-r--r-- | src/stores/UserStore.js | 27 | ||||
-rw-r--r-- | src/styles/layout.scss | 2 | ||||
-rw-r--r-- | src/styles/toggle.scss | 2 | ||||
-rw-r--r-- | src/theme/dark/index.js | 3 | ||||
-rw-r--r-- | src/theme/default/index.js | 3 |
20 files changed, 175 insertions, 131 deletions
diff --git a/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js b/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js index 415a8d1b5..37ccc8e51 100644 --- a/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js +++ b/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js | |||
@@ -31,7 +31,7 @@ const messages = defineMessages({ | |||
31 | }, | 31 | }, |
32 | }); | 32 | }); |
33 | 33 | ||
34 | export default @injectSheet(styles) @observer class WebviewCrashHandler extends Component { | 34 | export default @injectSheet(styles) @observer class WebviewErrorHandler extends Component { |
35 | static propTypes = { | 35 | static propTypes = { |
36 | name: PropTypes.string.isRequired, | 36 | name: PropTypes.string.isRequired, |
37 | reload: PropTypes.func.isRequired, | 37 | reload: PropTypes.func.isRequired, |
diff --git a/src/components/services/content/ErrorHandlers/styles.js b/src/components/services/content/ErrorHandlers/styles.js index f11386798..9e2509ee5 100644 --- a/src/components/services/content/ErrorHandlers/styles.js +++ b/src/components/services/content/ErrorHandlers/styles.js | |||
@@ -1,4 +1,4 @@ | |||
1 | export default { | 1 | export default theme => ({ |
2 | component: { | 2 | component: { |
3 | left: 0, | 3 | left: 0, |
4 | position: 'absolute', | 4 | position: 'absolute', |
@@ -6,7 +6,7 @@ export default { | |||
6 | width: '100%', | 6 | width: '100%', |
7 | zIndex: 0, | 7 | zIndex: 0, |
8 | alignItems: 'center', | 8 | alignItems: 'center', |
9 | // background: $theme-gray-lighter; | 9 | background: theme.colorWebviewErrorHandlerBackground, |
10 | display: 'flex', | 10 | display: 'flex', |
11 | flexDirection: 'column', | 11 | flexDirection: 'column', |
12 | justifyContent: 'center', | 12 | justifyContent: 'center', |
@@ -22,4 +22,4 @@ export default { | |||
22 | margin: [0, 10, 0, 10], | 22 | margin: [0, 10, 0, 10], |
23 | }, | 23 | }, |
24 | }, | 24 | }, |
25 | }; | 25 | }); |
diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js index b1a2c0207..bb577e4cc 100644 --- a/src/components/services/content/ServiceWebview.js +++ b/src/components/services/content/ServiceWebview.js | |||
@@ -18,7 +18,6 @@ export default @observer class ServiceWebview extends Component { | |||
18 | setWebviewReference: PropTypes.func.isRequired, | 18 | setWebviewReference: PropTypes.func.isRequired, |
19 | reload: PropTypes.func.isRequired, | 19 | reload: PropTypes.func.isRequired, |
20 | edit: PropTypes.func.isRequired, | 20 | edit: PropTypes.func.isRequired, |
21 | isAppMuted: PropTypes.bool.isRequired, | ||
22 | enable: PropTypes.func.isRequired, | 21 | enable: PropTypes.func.isRequired, |
23 | isActive: PropTypes.bool, | 22 | isActive: PropTypes.bool, |
24 | }; | 23 | }; |
@@ -69,7 +68,6 @@ export default @observer class ServiceWebview extends Component { | |||
69 | setWebviewReference, | 68 | setWebviewReference, |
70 | reload, | 69 | reload, |
71 | edit, | 70 | edit, |
72 | isAppMuted, | ||
73 | enable, | 71 | enable, |
74 | } = this.props; | 72 | } = this.props; |
75 | 73 | ||
@@ -137,7 +135,6 @@ export default @observer class ServiceWebview extends Component { | |||
137 | })} | 135 | })} |
138 | onUpdateTargetUrl={this.updateTargetUrl} | 136 | onUpdateTargetUrl={this.updateTargetUrl} |
139 | useragent={service.userAgent} | 137 | useragent={service.userAgent} |
140 | muted={isAppMuted || service.isMuted} | ||
141 | allowpopups | 138 | allowpopups |
142 | /> | 139 | /> |
143 | )} | 140 | )} |
diff --git a/src/components/services/content/Services.js b/src/components/services/content/Services.js index 1aeb17e03..54f16ba12 100644 --- a/src/components/services/content/Services.js +++ b/src/components/services/content/Services.js | |||
@@ -26,7 +26,6 @@ export default @observer class Services extends Component { | |||
26 | openWindow: PropTypes.func.isRequired, | 26 | openWindow: PropTypes.func.isRequired, |
27 | reload: PropTypes.func.isRequired, | 27 | reload: PropTypes.func.isRequired, |
28 | openSettings: PropTypes.func.isRequired, | 28 | openSettings: PropTypes.func.isRequired, |
29 | isAppMuted: PropTypes.bool.isRequired, | ||
30 | update: PropTypes.func.isRequired, | 29 | update: PropTypes.func.isRequired, |
31 | }; | 30 | }; |
32 | 31 | ||
@@ -46,7 +45,6 @@ export default @observer class Services extends Component { | |||
46 | openWindow, | 45 | openWindow, |
47 | reload, | 46 | reload, |
48 | openSettings, | 47 | openSettings, |
49 | isAppMuted, | ||
50 | update, | 48 | update, |
51 | } = this.props; | 49 | } = this.props; |
52 | const { intl } = this.context; | 50 | const { intl } = this.context; |
@@ -81,7 +79,6 @@ export default @observer class Services extends Component { | |||
81 | openWindow={openWindow} | 79 | openWindow={openWindow} |
82 | reload={() => reload({ serviceId: service.id })} | 80 | reload={() => reload({ serviceId: service.id })} |
83 | edit={() => openSettings({ path: `services/edit/${service.id}` })} | 81 | edit={() => openSettings({ path: `services/edit/${service.id}` })} |
84 | isAppMuted={isAppMuted} | ||
85 | enable={() => update({ | 82 | enable={() => update({ |
86 | serviceId: service.id, | 83 | serviceId: service.id, |
87 | serviceData: { | 84 | serviceData: { |
diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js index 9c9543749..f2d3ca8c0 100644 --- a/src/components/settings/account/AccountDashboard.js +++ b/src/components/settings/account/AccountDashboard.js | |||
@@ -169,15 +169,9 @@ export default @observer class AccountDashboard extends Component { | |||
169 | {user.organization && `${user.organization}, `} | 169 | {user.organization && `${user.organization}, `} |
170 | {user.email} | 170 | {user.email} |
171 | <br /> | 171 | <br /> |
172 | {!user.isEnterprise && !user.isPremium && ( | ||
173 | <span className="badge badge">{intl.formatMessage(messages.accountTypeBasic)}</span> | ||
174 | )} | ||
175 | {user.isPremium && ( | 172 | {user.isPremium && ( |
176 | <span className="badge badge--premium">{intl.formatMessage(messages.accountTypePremium)}</span> | 173 | <span className="badge badge--premium">{intl.formatMessage(messages.accountTypePremium)}</span> |
177 | )} | 174 | )} |
178 | {user.isEnterprise && ( | ||
179 | <span className="badge badge--success">{intl.formatMessage(messages.accountTypeEnterprise)}</span> | ||
180 | )} | ||
181 | </div> | 175 | </div> |
182 | <Link to="/settings/user/edit" className="button"> | 176 | <Link to="/settings/user/edit" className="button"> |
183 | {intl.formatMessage(messages.accountEditButton)} | 177 | {intl.formatMessage(messages.accountEditButton)} |
@@ -235,34 +229,7 @@ export default @observer class AccountDashboard extends Component { | |||
235 | ) | 229 | ) |
236 | )} | 230 | )} |
237 | 231 | ||
238 | {user.isEnterprise && ( | 232 | {!user.isPremium && ( |
239 | <div className="account"> | ||
240 | <div className="account__box"> | ||
241 | <h2>{user.company.name}</h2> | ||
242 | <p> | ||
243 | Technical contact: | ||
244 | <Link | ||
245 | className="link" | ||
246 | target="_blank" | ||
247 | to={`mailto:${user.company.contact.technical}?subject=Franz`} | ||
248 | > | ||
249 | {user.company.contact.technical} | ||
250 | </Link> | ||
251 | <br /> | ||
252 | General contact: | ||
253 | <Link | ||
254 | className="link" | ||
255 | target="_blank" | ||
256 | to={`mailto:${user.company.contact.default}?subject=Franz`} | ||
257 | > | ||
258 | {user.company.contact.default} | ||
259 | </Link> | ||
260 | </p> | ||
261 | </div> | ||
262 | </div> | ||
263 | )} | ||
264 | |||
265 | {!user.isEnterprise && !user.isPremium && ( | ||
266 | isLoadingPlans ? ( | 233 | isLoadingPlans ? ( |
267 | <Loader /> | 234 | <Loader /> |
268 | ) : ( | 235 | ) : ( |
@@ -277,27 +244,25 @@ export default @observer class AccountDashboard extends Component { | |||
277 | ) | 244 | ) |
278 | )} | 245 | )} |
279 | 246 | ||
280 | {!user.isEnterprise && ( | 247 | <div className="account franz-form"> |
281 | <div className="account franz-form"> | 248 | <div className="account__box"> |
282 | <div className="account__box"> | 249 | <h2>{intl.formatMessage(messages.headlineDangerZone)}</h2> |
283 | <h2>{intl.formatMessage(messages.headlineDangerZone)}</h2> | 250 | {!isDeleteAccountSuccessful && ( |
284 | {!isDeleteAccountSuccessful && ( | 251 | <div className="account__subscription"> |
285 | <div className="account__subscription"> | 252 | <p>{intl.formatMessage(messages.deleteInfo)}</p> |
286 | <p>{intl.formatMessage(messages.deleteInfo)}</p> | 253 | <Button |
287 | <Button | 254 | label={intl.formatMessage(messages.deleteAccount)} |
288 | label={intl.formatMessage(messages.deleteAccount)} | 255 | buttonType="danger" |
289 | buttonType="danger" | 256 | onClick={() => deleteAccount()} |
290 | onClick={() => deleteAccount()} | 257 | loaded={!isLoadingDeleteAccount} |
291 | loaded={!isLoadingDeleteAccount} | 258 | /> |
292 | /> | ||
293 | </div> | ||
294 | )} | ||
295 | {isDeleteAccountSuccessful && ( | ||
296 | <p>{intl.formatMessage(messages.deleteEmailSent)}</p> | ||
297 | )} | ||
298 | </div> | 259 | </div> |
260 | )} | ||
261 | {isDeleteAccountSuccessful && ( | ||
262 | <p>{intl.formatMessage(messages.deleteEmailSent)}</p> | ||
263 | )} | ||
299 | </div> | 264 | </div> |
300 | )} | 265 | </div> |
301 | </Fragment> | 266 | </Fragment> |
302 | )} | 267 | )} |
303 | </div> | 268 | </div> |
diff --git a/src/components/settings/user/EditUserForm.js b/src/components/settings/user/EditUserForm.js index 0e3ac6b10..a1a353e57 100644 --- a/src/components/settings/user/EditUserForm.js +++ b/src/components/settings/user/EditUserForm.js | |||
@@ -3,11 +3,10 @@ import PropTypes from 'prop-types'; | |||
3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; | 3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; |
4 | import { defineMessages, intlShape } from 'react-intl'; | 4 | import { defineMessages, intlShape } from 'react-intl'; |
5 | import { Link } from 'react-router'; | 5 | import { Link } from 'react-router'; |
6 | 6 | import { Input } from '@meetfranz/forms'; | |
7 | // import { Link } from 'react-router'; | ||
8 | 7 | ||
9 | import Form from '../../../lib/Form'; | 8 | import Form from '../../../lib/Form'; |
10 | import Input from '../../ui/Input'; | 9 | // import Input from '../../ui/Input'; |
11 | import Button from '../../ui/Button'; | 10 | import Button from '../../ui/Button'; |
12 | import Radio from '../../ui/Radio'; | 11 | import Radio from '../../ui/Radio'; |
13 | import Infobox from '../../ui/Infobox'; | 12 | import Infobox from '../../ui/Infobox'; |
@@ -39,13 +38,12 @@ const messages = defineMessages({ | |||
39 | }, | 38 | }, |
40 | }); | 39 | }); |
41 | 40 | ||
42 | export default @observer class EditServiceForm extends Component { | 41 | export default @observer class EditUserForm extends Component { |
43 | static propTypes = { | 42 | static propTypes = { |
44 | status: MobxPropTypes.observableArray.isRequired, | 43 | status: MobxPropTypes.observableArray.isRequired, |
45 | form: PropTypes.instanceOf(Form).isRequired, | 44 | form: PropTypes.instanceOf(Form).isRequired, |
46 | onSubmit: PropTypes.func.isRequired, | 45 | onSubmit: PropTypes.func.isRequired, |
47 | isSaving: PropTypes.bool.isRequired, | 46 | isSaving: PropTypes.bool.isRequired, |
48 | isEnterprise: PropTypes.bool.isRequired, | ||
49 | }; | 47 | }; |
50 | 48 | ||
51 | static contextTypes = { | 49 | static contextTypes = { |
@@ -68,7 +66,6 @@ export default @observer class EditServiceForm extends Component { | |||
68 | // user, | 66 | // user, |
69 | status, | 67 | status, |
70 | form, | 68 | form, |
71 | isEnterprise, | ||
72 | isSaving, | 69 | isSaving, |
73 | } = this.props; | 70 | } = this.props; |
74 | const { intl } = this.context; | 71 | const { intl } = this.context; |
@@ -98,23 +95,21 @@ export default @observer class EditServiceForm extends Component { | |||
98 | )} | 95 | )} |
99 | <h2>{intl.formatMessage(messages.headlineAccount)}</h2> | 96 | <h2>{intl.formatMessage(messages.headlineAccount)}</h2> |
100 | <div className="grid__row"> | 97 | <div className="grid__row"> |
101 | <Input field={form.$('firstname')} focus /> | 98 | <Input {...form.$('firstname').bind()} focus /> |
102 | <Input field={form.$('lastname')} /> | 99 | <Input {...form.$('lastname').bind()} /> |
103 | </div> | 100 | </div> |
104 | <Input field={form.$('email')} /> | 101 | <Input {...form.$('email').bind()} /> |
105 | {!isEnterprise && ( | 102 | <Radio field={form.$('accountType')} /> |
106 | <Radio field={form.$('accountType')} /> | 103 | {form.$('accountType').value === 'company' && ( |
107 | )} | ||
108 | {!isEnterprise && form.$('accountType').value === 'company' && ( | ||
109 | <Input field={form.$('organization')} /> | 104 | <Input field={form.$('organization')} /> |
110 | )} | 105 | )} |
111 | <h2>{intl.formatMessage(messages.headlinePassword)}</h2> | 106 | <h2>{intl.formatMessage(messages.headlinePassword)}</h2> |
112 | <Input | 107 | <Input |
113 | field={form.$('oldPassword')} | 108 | {...form.$('oldPassword').bind()} |
114 | showPasswordToggle | 109 | showPasswordToggle |
115 | /> | 110 | /> |
116 | <Input | 111 | <Input |
117 | field={form.$('newPassword')} | 112 | {...form.$('newPassword').bind()} |
118 | showPasswordToggle | 113 | showPasswordToggle |
119 | scorePassword | 114 | scorePassword |
120 | /> | 115 | /> |
diff --git a/src/config.js b/src/config.js index 789ddd1a0..101a4379a 100644 --- a/src/config.js +++ b/src/config.js | |||
@@ -1,5 +1,6 @@ | |||
1 | import electron from 'electron'; | 1 | import electron from 'electron'; |
2 | import path from 'path'; | 2 | import path from 'path'; |
3 | import { asarPath } from './helpers/asar-helpers'; | ||
3 | 4 | ||
4 | const app = process.type === 'renderer' ? electron.remote.app : electron.app; | 5 | const app = process.type === 'renderer' ? electron.remote.app : electron.app; |
5 | const systemPreferences = process.type === 'renderer' ? electron.remote.systemPreferences : electron.systemPreferences; | 6 | const systemPreferences = process.type === 'renderer' ? electron.remote.systemPreferences : electron.systemPreferences; |
@@ -57,4 +58,4 @@ export const FILE_SYSTEM_SETTINGS_TYPES = [ | |||
57 | export const SETTINGS_PATH = path.join(app.getPath('userData'), 'config'); | 58 | export const SETTINGS_PATH = path.join(app.getPath('userData'), 'config'); |
58 | 59 | ||
59 | // Replacing app.asar is not beautiful but unforunately necessary | 60 | // Replacing app.asar is not beautiful but unforunately necessary |
60 | export const DICTIONARY_PATH = path.join(__dirname, 'dictionaries').replace('app.asar', 'app.asar.unpacked'); | 61 | export const DICTIONARY_PATH = asarPath(path.join(__dirname, 'dictionaries').replace('app.asar', 'app.asar.unpacked')); |
diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js index 430b49b55..749912c59 100644 --- a/src/containers/layout/AppLayoutContainer.js +++ b/src/containers/layout/AppLayoutContainer.js | |||
@@ -108,7 +108,6 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e | |||
108 | openWindow={openWindow} | 108 | openWindow={openWindow} |
109 | reload={reload} | 109 | reload={reload} |
110 | openSettings={openSettings} | 110 | openSettings={openSettings} |
111 | isAppMuted={settings.all.app.isAppMuted} | ||
112 | update={updateService} | 111 | update={updateService} |
113 | /> | 112 | /> |
114 | ); | 113 | ); |
diff --git a/src/environment.js b/src/environment.js index e1762129b..73b1c7ab2 100644 --- a/src/environment.js +++ b/src/environment.js | |||
@@ -1,10 +1,12 @@ | |||
1 | import isDev from 'electron-is-dev'; | ||
2 | |||
1 | import { LIVE_API, DEV_API, LOCAL_API } from './config'; | 3 | import { LIVE_API, DEV_API, LOCAL_API } from './config'; |
2 | 4 | ||
3 | export const isDevMode = Boolean(process.execPath.match(/[\\/]electron/)); | 5 | export const isDevMode = isDev; |
4 | export const useLiveAPI = process.env.LIVE_API; | 6 | export const useLiveAPI = process.env.LIVE_API; |
5 | export const useLocalAPI = process.env.LOCAL_API; | 7 | export const useLocalAPI = process.env.LOCAL_API; |
6 | 8 | ||
7 | let platform = process.platform; | 9 | let { platform } = process; |
8 | if (process.env.OS_PLATFORM) { | 10 | if (process.env.OS_PLATFORM) { |
9 | platform = process.env.OS_PLATFORM; | 11 | platform = process.env.OS_PLATFORM; |
10 | } | 12 | } |
diff --git a/src/helpers/asar-helpers.js b/src/helpers/asar-helpers.js new file mode 100644 index 000000000..9e4380c06 --- /dev/null +++ b/src/helpers/asar-helpers.js | |||
@@ -0,0 +1,3 @@ | |||
1 | export function asarPath(dir = '') { | ||
2 | return dir.replace('app.asar', 'app.asar.unpacked'); | ||
3 | } | ||
diff --git a/src/index.js b/src/index.js index f34df8c17..69cfa77e7 100644 --- a/src/index.js +++ b/src/index.js | |||
@@ -4,25 +4,23 @@ import { | |||
4 | shell, | 4 | shell, |
5 | ipcMain, | 5 | ipcMain, |
6 | } from 'electron'; | 6 | } from 'electron'; |
7 | 7 | import isDevMode from 'electron-is-dev'; | |
8 | import fs from 'fs-extra'; | 8 | import fs from 'fs-extra'; |
9 | import path from 'path'; | 9 | import path from 'path'; |
10 | import windowStateKeeper from 'electron-window-state'; | 10 | import windowStateKeeper from 'electron-window-state'; |
11 | 11 | ||
12 | // Set app directory before loading user modules | ||
13 | if (isDevMode) { | ||
14 | app.setPath('userData', path.join(app.getPath('appData'), 'FranzDev')); | ||
15 | } | ||
16 | |||
17 | /* eslint-disable import/first */ | ||
12 | import { | 18 | import { |
13 | isDevMode, | ||
14 | isMac, | 19 | isMac, |
15 | isWindows, | 20 | isWindows, |
16 | isLinux, | 21 | isLinux, |
17 | } from './environment'; | 22 | } from './environment'; |
18 | |||
19 | import { mainIpcHandler as basicAuthHandler } from './features/basicAuth'; | 23 | import { mainIpcHandler as basicAuthHandler } from './features/basicAuth'; |
20 | |||
21 | // DEV MODE: Save user data into FranzDev | ||
22 | if (isDevMode) { | ||
23 | app.setPath('userData', path.join(app.getPath('appData'), 'FranzDev')); | ||
24 | } | ||
25 | /* eslint-disable import/first */ | ||
26 | import ipcApi from './electron/ipc-api'; | 24 | import ipcApi from './electron/ipc-api'; |
27 | import Tray from './lib/Tray'; | 25 | import Tray from './lib/Tray'; |
28 | import Settings from './electron/Settings'; | 26 | import Settings from './electron/Settings'; |
@@ -35,6 +33,7 @@ import { | |||
35 | DEFAULT_APP_SETTINGS, | 33 | DEFAULT_APP_SETTINGS, |
36 | DEFAULT_WINDOW_OPTIONS, | 34 | DEFAULT_WINDOW_OPTIONS, |
37 | } from './config'; | 35 | } from './config'; |
36 | import { asarPath } from './helpers/asar-helpers'; | ||
38 | /* eslint-enable import/first */ | 37 | /* eslint-enable import/first */ |
39 | 38 | ||
40 | const debug = require('debug')('Franz:App'); | 39 | const debug = require('debug')('Franz:App'); |
@@ -44,6 +43,17 @@ const debug = require('debug')('Franz:App'); | |||
44 | let mainWindow; | 43 | let mainWindow; |
45 | let willQuitApp = false; | 44 | let willQuitApp = false; |
46 | 45 | ||
46 | // Register methods to be called once the window has been loaded. | ||
47 | let onDidLoadFns = []; | ||
48 | |||
49 | function onDidLoad(fn) { | ||
50 | if (onDidLoadFns) { | ||
51 | onDidLoadFns.push(fn); | ||
52 | } else if (mainWindow) { | ||
53 | fn(mainWindow); | ||
54 | } | ||
55 | } | ||
56 | |||
47 | // Ensure that the recipe directory exists | 57 | // Ensure that the recipe directory exists |
48 | fs.emptyDirSync(path.join(app.getPath('userData'), 'recipes', 'temp')); | 58 | fs.emptyDirSync(path.join(app.getPath('userData'), 'recipes', 'temp')); |
49 | fs.ensureFileSync(path.join(app.getPath('userData'), 'window-state.json')); | 59 | fs.ensureFileSync(path.join(app.getPath('userData'), 'window-state.json')); |
@@ -65,28 +75,31 @@ if (!gotTheLock) { | |||
65 | mainWindow.focus(); | 75 | mainWindow.focus(); |
66 | 76 | ||
67 | if (isWindows) { | 77 | if (isWindows) { |
68 | // Keep only command line / deep linked arguments | 78 | onDidLoad((window) => { |
69 | const url = argv.slice(1); | 79 | // Keep only command line / deep linked arguments |
70 | 80 | const url = argv.slice(1); | |
71 | if (url) { | 81 | if (url) { |
72 | handleDeepLink(mainWindow, url.toString()); | 82 | handleDeepLink(window, url.toString()); |
73 | } | 83 | } |
74 | } | 84 | |
75 | 85 | if (argv.includes('--reset-window')) { | |
76 | if (argv.includes('--reset-window')) { | 86 | // Needs to be delayed to not interfere with mainWindow.restore(); |
77 | // Needs to be delayed to not interfere with mainWindow.restore(); | 87 | setTimeout(() => { |
78 | setTimeout(() => { | 88 | debug('Resetting windows via Task'); |
79 | debug('Resetting windows via Task'); | 89 | window.setPosition(DEFAULT_WINDOW_OPTIONS.x + 100, DEFAULT_WINDOW_OPTIONS.y + 100); |
80 | mainWindow.setPosition(DEFAULT_WINDOW_OPTIONS.x + 100, DEFAULT_WINDOW_OPTIONS.y + 100); | 90 | window.setSize(DEFAULT_WINDOW_OPTIONS.width, DEFAULT_WINDOW_OPTIONS.height); |
81 | mainWindow.setSize(DEFAULT_WINDOW_OPTIONS.width, DEFAULT_WINDOW_OPTIONS.height); | 91 | }, 1); |
82 | }, 1); | 92 | } else if (argv.includes('--quit')) { |
93 | // Needs to be delayed to not interfere with mainWindow.restore(); | ||
94 | setTimeout(() => { | ||
95 | debug('Quitting Franz via Task'); | ||
96 | app.quit(); | ||
97 | }, 1); | ||
98 | } | ||
99 | }); | ||
83 | } | 100 | } |
84 | } | 101 | } |
85 | }); | 102 | }); |
86 | |||
87 | // Create myWindow, load the rest of the app, etc... | ||
88 | app.on('ready', () => { | ||
89 | }); | ||
90 | } | 103 | } |
91 | // const isSecondInstance = app.makeSingleInstance((argv) => { | 104 | // const isSecondInstance = app.makeSingleInstance((argv) => { |
92 | // if (mainWindow) { | 105 | // if (mainWindow) { |
@@ -166,6 +179,14 @@ const createWindow = () => { | |||
166 | }, | 179 | }, |
167 | }); | 180 | }); |
168 | 181 | ||
182 | mainWindow.webContents.on('did-finish-load', () => { | ||
183 | const fns = onDidLoadFns; | ||
184 | onDidLoadFns = null; | ||
185 | for (const fn of fns) { | ||
186 | fn(mainWindow); | ||
187 | } | ||
188 | }); | ||
189 | |||
169 | // Initialize System Tray | 190 | // Initialize System Tray |
170 | const trayIcon = new Tray(); | 191 | const trayIcon = new Tray(); |
171 | 192 | ||
@@ -190,6 +211,16 @@ const createWindow = () => { | |||
190 | mainWindow.webContents.openDevTools(); | 211 | mainWindow.webContents.openDevTools(); |
191 | } | 212 | } |
192 | 213 | ||
214 | // Windows deep linking handling on app launch | ||
215 | if (isWindows) { | ||
216 | onDidLoad((window) => { | ||
217 | const url = process.argv.slice(1); | ||
218 | if (url) { | ||
219 | handleDeepLink(window, url.toString()); | ||
220 | } | ||
221 | }); | ||
222 | } | ||
223 | |||
193 | // Emitted when the window is closed. | 224 | // Emitted when the window is closed. |
194 | mainWindow.on('close', (e) => { | 225 | mainWindow.on('close', (e) => { |
195 | // Dereference the window object, usually you would store windows | 226 | // Dereference the window object, usually you would store windows |
@@ -259,14 +290,26 @@ const createWindow = () => { | |||
259 | // initialization and is ready to create browser windows. | 290 | // initialization and is ready to create browser windows. |
260 | // Some APIs can only be used after this event occurs. | 291 | // Some APIs can only be used after this event occurs. |
261 | app.on('ready', () => { | 292 | app.on('ready', () => { |
293 | // Register App URL | ||
294 | app.setAsDefaultProtocolClient('franz'); | ||
295 | |||
296 | if (isDevMode) { | ||
297 | app.setAsDefaultProtocolClient('franz-dev'); | ||
298 | } | ||
299 | |||
262 | if (process.platform === 'win32') { | 300 | if (process.platform === 'win32') { |
263 | app.setUserTasks([{ | 301 | app.setUserTasks([{ |
264 | program: process.execPath, | 302 | program: process.execPath, |
265 | arguments: `${isDevMode ? `${__dirname} ` : ''}--reset-window`, | 303 | arguments: `${isDevMode ? `${__dirname} ` : ''}--reset-window`, |
266 | iconPath: path.join(`${__dirname}`, '../src/assets/images/taskbar/win32/display.ico'), | 304 | iconPath: asarPath(path.join(isDevMode ? `${__dirname}../src/` : __dirname, 'assets/images/taskbar/win32/display.ico')), |
267 | iconIndex: 0, | 305 | iconIndex: 0, |
268 | title: 'Move Franz to Current Display', | 306 | title: 'Move Franz to Current Display', |
269 | description: 'Restore the position and size of Franz', | 307 | description: 'Restore the position and size of Franz', |
308 | }, { | ||
309 | program: process.execPath, | ||
310 | arguments: `${isDevMode ? `${__dirname} ` : ''}--quit`, | ||
311 | iconIndex: 0, | ||
312 | title: 'Quit Franz', | ||
270 | }]); | 313 | }]); |
271 | } | 314 | } |
272 | 315 | ||
@@ -336,13 +379,13 @@ app.on('activate', () => { | |||
336 | }); | 379 | }); |
337 | 380 | ||
338 | app.on('will-finish-launching', () => { | 381 | app.on('will-finish-launching', () => { |
339 | // Protocol handler for osx | 382 | // Protocol handler for macOS |
340 | app.on('open-url', (event, url) => { | 383 | app.on('open-url', (event, url) => { |
341 | event.preventDefault(); | 384 | event.preventDefault(); |
342 | console.log(`open-url event: ${url}`); | 385 | |
343 | handleDeepLink(mainWindow, url); | 386 | onDidLoad((window) => { |
387 | debug('open-url event', url); | ||
388 | handleDeepLink(window, url); | ||
389 | }); | ||
344 | }); | 390 | }); |
345 | }); | 391 | }); |
346 | |||
347 | // Register App URL | ||
348 | app.setAsDefaultProtocolClient('franz'); | ||
diff --git a/src/models/Service.js b/src/models/Service.js index 3b8bebdef..8a2a8d3d8 100644 --- a/src/models/Service.js +++ b/src/models/Service.js | |||
@@ -15,7 +15,7 @@ export default class Service { | |||
15 | 15 | ||
16 | events = {}; | 16 | events = {}; |
17 | 17 | ||
18 | isAttached = false; | 18 | @observable isAttached = false; |
19 | 19 | ||
20 | @observable isActive = false; // Is current webview active | 20 | @observable isActive = false; // Is current webview active |
21 | 21 | ||
@@ -202,7 +202,7 @@ export default class Service { | |||
202 | 202 | ||
203 | this.webview.addEventListener('did-fail-load', (event) => { | 203 | this.webview.addEventListener('did-fail-load', (event) => { |
204 | debug('Service failed to load', this.name, event); | 204 | debug('Service failed to load', this.name, event); |
205 | if (event.isMainFrame && event.errorCode !== -27 && event.errorCode !== -3) { | 205 | if (event.isMainFrame && event.errorCode !== -21 && event.errorCode !== -3) { |
206 | this.isError = true; | 206 | this.isError = true; |
207 | this.errorMessage = event.errorDescription; | 207 | this.errorMessage = event.errorDescription; |
208 | this.isLoading = false; | 208 | this.isLoading = false; |
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js index dd4642d70..b21d48a11 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js | |||
@@ -143,10 +143,13 @@ export default class AppStore extends Store { | |||
143 | 143 | ||
144 | // Handle deep linking (franz://) | 144 | // Handle deep linking (franz://) |
145 | ipcRenderer.on('navigateFromDeepLink', (event, data) => { | 145 | ipcRenderer.on('navigateFromDeepLink', (event, data) => { |
146 | const { url } = data; | 146 | debug('Navigate from deep link', data); |
147 | let { url } = data; | ||
147 | if (!url) return; | 148 | if (!url) return; |
148 | 149 | ||
149 | this.stores.router.push(data.url); | 150 | url = url.replace(/\/$/, ''); |
151 | |||
152 | this.stores.router.push(url); | ||
150 | }); | 153 | }); |
151 | 154 | ||
152 | // Set active the next service | 155 | // Set active the next service |
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 0ab57312a..efd57a09d 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js | |||
@@ -70,6 +70,7 @@ export default class ServicesStore extends Store { | |||
70 | this._mapActiveServiceToServiceModelReaction.bind(this), | 70 | this._mapActiveServiceToServiceModelReaction.bind(this), |
71 | this._saveActiveService.bind(this), | 71 | this._saveActiveService.bind(this), |
72 | this._logoutReaction.bind(this), | 72 | this._logoutReaction.bind(this), |
73 | this._handleMuteSettings.bind(this), | ||
73 | ]); | 74 | ]); |
74 | 75 | ||
75 | // Just bind this | 76 | // Just bind this |
@@ -627,6 +628,20 @@ export default class ServicesStore extends Store { | |||
627 | } | 628 | } |
628 | } | 629 | } |
629 | 630 | ||
631 | _handleMuteSettings() { | ||
632 | const { enabled } = this; | ||
633 | const { isAppMuted } = this.stores.settings.app; | ||
634 | |||
635 | enabled.forEach((service) => { | ||
636 | const { isAttached } = service; | ||
637 | const isMuted = isAppMuted || service.isMuted; | ||
638 | |||
639 | if (isAttached) { | ||
640 | service.webview.setAudioMuted(isMuted); | ||
641 | } | ||
642 | }); | ||
643 | } | ||
644 | |||
630 | _shareSettingsWithServiceProcess() { | 645 | _shareSettingsWithServiceProcess() { |
631 | const settings = this.stores.settings.app; | 646 | const settings = this.stores.settings.app; |
632 | this.actions.service.sendIPCMessageToAllServices({ | 647 | this.actions.service.sendIPCMessageToAllServices({ |
diff --git a/src/stores/UIStore.js b/src/stores/UIStore.js index d37ebe4c7..bb7965a4a 100644 --- a/src/stores/UIStore.js +++ b/src/stores/UIStore.js | |||
@@ -1,8 +1,7 @@ | |||
1 | import { action, observable, computed } from 'mobx'; | 1 | import { action, observable, computed } from 'mobx'; |
2 | import { theme } from '@meetfranz/theme'; | ||
2 | 3 | ||
3 | import Store from './lib/Store'; | 4 | import Store from './lib/Store'; |
4 | import * as themeDefault from '../theme/default'; | ||
5 | import * as themeDark from '../theme/dark'; | ||
6 | 5 | ||
7 | export default class UIStore extends Store { | 6 | export default class UIStore extends Store { |
8 | @observable showServicesUpdatedInfoBar = false; | 7 | @observable showServicesUpdatedInfoBar = false; |
@@ -24,10 +23,10 @@ export default class UIStore extends Store { | |||
24 | 23 | ||
25 | @computed get theme() { | 24 | @computed get theme() { |
26 | if (this.stores.settings.all.app.darkMode) { | 25 | if (this.stores.settings.all.app.darkMode) { |
27 | return Object.assign({}, themeDefault, themeDark); | 26 | return theme('dark'); |
28 | } | 27 | } |
29 | 28 | ||
30 | return themeDefault; | 29 | return theme('default'); |
31 | } | 30 | } |
32 | 31 | ||
33 | // Actions | 32 | // Actions |
diff --git a/src/stores/UserStore.js b/src/stores/UserStore.js index 7addb5760..77d84afe1 100644 --- a/src/stores/UserStore.js +++ b/src/stores/UserStore.js | |||
@@ -129,10 +129,6 @@ export default class UserStore extends Store { | |||
129 | return Boolean(localStorage.getItem('authToken')); | 129 | return Boolean(localStorage.getItem('authToken')); |
130 | } | 130 | } |
131 | 131 | ||
132 | // @computed get isTokenValid() { | ||
133 | // return this.authToken !== null && moment(this.tokenExpiry).isAfter(moment()); | ||
134 | // } | ||
135 | |||
136 | @computed get isTokenExpired() { | 132 | @computed get isTokenExpired() { |
137 | if (!this.authToken) return false; | 133 | if (!this.authToken) return false; |
138 | 134 | ||
@@ -160,6 +156,14 @@ export default class UserStore extends Store { | |||
160 | gaEvent('User', 'login'); | 156 | gaEvent('User', 'login'); |
161 | } | 157 | } |
162 | 158 | ||
159 | @action _tokenLogin(authToken) { | ||
160 | this._setUserData(authToken); | ||
161 | |||
162 | this.stores.router.push('/'); | ||
163 | |||
164 | gaEvent('User', 'tokenLogin'); | ||
165 | } | ||
166 | |||
163 | @action async _signup({ | 167 | @action async _signup({ |
164 | firstname, lastname, email, password, accountType, company, | 168 | firstname, lastname, email, password, accountType, company, |
165 | }) { | 169 | }) { |
@@ -206,6 +210,8 @@ export default class UserStore extends Store { | |||
206 | } | 210 | } |
207 | 211 | ||
208 | @action async _update({ userData }) { | 212 | @action async _update({ userData }) { |
213 | if (!this.isLoggedIn) return; | ||
214 | |||
209 | const response = await this.updateUserInfoRequest.execute(userData)._promise; | 215 | const response = await this.updateUserInfoRequest.execute(userData)._promise; |
210 | 216 | ||
211 | this.getUserInfoRequest.patch(() => response.data); | 217 | this.getUserInfoRequest.patch(() => response.data); |
@@ -222,6 +228,7 @@ export default class UserStore extends Store { | |||
222 | // workaround mobx issue | 228 | // workaround mobx issue |
223 | localStorage.removeItem('authToken'); | 229 | localStorage.removeItem('authToken'); |
224 | window.localStorage.removeItem('authToken'); | 230 | window.localStorage.removeItem('authToken'); |
231 | |||
225 | this.getUserInfoRequest.invalidate().reset(); | 232 | this.getUserInfoRequest.invalidate().reset(); |
226 | this.authToken = null; | 233 | this.authToken = null; |
227 | } | 234 | } |
@@ -262,6 +269,18 @@ export default class UserStore extends Store { | |||
262 | const { router } = this.stores; | 269 | const { router } = this.stores; |
263 | const currentRoute = router.location.pathname; | 270 | const currentRoute = router.location.pathname; |
264 | if (!this.isLoggedIn | 271 | if (!this.isLoggedIn |
272 | && currentRoute.includes('token=')) { | ||
273 | router.push(this.WELCOME_ROUTE); | ||
274 | const token = currentRoute.split('=')[1]; | ||
275 | |||
276 | const data = this._parseToken(token); | ||
277 | if (data) { | ||
278 | // Give this some time to sink | ||
279 | setTimeout(() => { | ||
280 | this._tokenLogin(token); | ||
281 | }, 1000); | ||
282 | } | ||
283 | } else if (!this.isLoggedIn | ||
265 | && !currentRoute.includes(this.BASE_ROUTE)) { | 284 | && !currentRoute.includes(this.BASE_ROUTE)) { |
266 | router.push(this.WELCOME_ROUTE); | 285 | router.push(this.WELCOME_ROUTE); |
267 | } else if (this.isLoggedIn | 286 | } else if (this.isLoggedIn |
diff --git a/src/styles/layout.scss b/src/styles/layout.scss index ebf468cf0..8b7cc512a 100644 --- a/src/styles/layout.scss +++ b/src/styles/layout.scss | |||
@@ -19,7 +19,7 @@ html { overflow: hidden; } | |||
19 | 19 | ||
20 | &:hover, | 20 | &:hover, |
21 | &:active { color: $dark-theme-gray-smoke; } | 21 | &:active { color: $dark-theme-gray-smoke; } |
22 | &.is-muted { color: $dark-theme-gray; } | 22 | &.is-muted { color: $theme-brand-primary; } |
23 | } | 23 | } |
24 | } | 24 | } |
25 | 25 | ||
diff --git a/src/styles/toggle.scss b/src/styles/toggle.scss index 0ce0c3379..52675ceed 100644 --- a/src/styles/toggle.scss +++ b/src/styles/toggle.scss | |||
@@ -41,7 +41,7 @@ $toggle-button-size: 22px; | |||
41 | 41 | ||
42 | &.is-active .franz-form__toggle-button { | 42 | &.is-active .franz-form__toggle-button { |
43 | background: $theme-brand-primary; | 43 | background: $theme-brand-primary; |
44 | left: $toggle-width - $toggle-size - 3;; | 44 | left: $toggle-width - $toggle-size - 3; |
45 | } | 45 | } |
46 | 46 | ||
47 | input { display: none; } | 47 | input { display: none; } |
diff --git a/src/theme/dark/index.js b/src/theme/dark/index.js index 429284f9e..8fdb321f3 100644 --- a/src/theme/dark/index.js +++ b/src/theme/dark/index.js | |||
@@ -8,6 +8,9 @@ export const colorBackgroundSubscriptionContainer = legacyStyles.themeBrandInfo; | |||
8 | export const colorHeadline = legacyStyles.darkThemeTextColor; | 8 | export const colorHeadline = legacyStyles.darkThemeTextColor; |
9 | export const colorText = legacyStyles.darkThemeTextColor; | 9 | export const colorText = legacyStyles.darkThemeTextColor; |
10 | 10 | ||
11 | // Error Handler | ||
12 | export const colorWebviewErrorHandlerBackground = legacyStyles.darkThemeGrayDarkest; | ||
13 | |||
11 | // Loader | 14 | // Loader |
12 | export const colorFullscreenLoaderSpinner = '#FFF'; | 15 | export const colorFullscreenLoaderSpinner = '#FFF'; |
13 | export const colorWebviewLoaderBackground = hexToRgba(legacyStyles.darkThemeGrayDarkest, 0.5); | 16 | export const colorWebviewLoaderBackground = hexToRgba(legacyStyles.darkThemeGrayDarkest, 0.5); |
diff --git a/src/theme/default/index.js b/src/theme/default/index.js index 3ce8e7f0e..61410073d 100644 --- a/src/theme/default/index.js +++ b/src/theme/default/index.js | |||
@@ -23,6 +23,9 @@ export const colorSubscriptionContainerTitle = brandPrimary; | |||
23 | export const colorSubscriptionContainerActionButtonBackground = brandPrimary; | 23 | export const colorSubscriptionContainerActionButtonBackground = brandPrimary; |
24 | export const colorSubscriptionContainerActionButtonColor = '#FFF'; | 24 | export const colorSubscriptionContainerActionButtonColor = '#FFF'; |
25 | 25 | ||
26 | // Error Handler | ||
27 | export const colorWebviewErrorHandlerBackground = legacyStyles.themeGrayLighter; | ||
28 | |||
26 | // Loader | 29 | // Loader |
27 | export const colorAppLoaderSpinner = '#FFF'; | 30 | export const colorAppLoaderSpinner = '#FFF'; |
28 | export const colorFullscreenLoaderSpinner = legacyStyles.themeGrayDark; | 31 | export const colorFullscreenLoaderSpinner = legacyStyles.themeGrayDark; |