diff options
Diffstat (limited to 'src/components')
26 files changed, 431 insertions, 135 deletions
diff --git a/src/components/AppUpdateInfoBar.js b/src/components/AppUpdateInfoBar.js index 4fb3a8b71..4108fdf12 100644 --- a/src/components/AppUpdateInfoBar.js +++ b/src/components/AppUpdateInfoBar.js | |||
@@ -8,7 +8,7 @@ import InfoBar from './ui/InfoBar'; | |||
8 | const messages = defineMessages({ | 8 | const messages = defineMessages({ |
9 | updateAvailable: { | 9 | updateAvailable: { |
10 | id: 'infobar.updateAvailable', | 10 | id: 'infobar.updateAvailable', |
11 | defaultMessage: '!!!A new update for Franz is available.', | 11 | defaultMessage: '!!!A new update for Ferdi is available.', |
12 | }, | 12 | }, |
13 | changelog: { | 13 | changelog: { |
14 | id: 'infobar.buttonChangelog', | 14 | id: 'infobar.buttonChangelog', |
diff --git a/src/components/auth/AuthLayout.js b/src/components/auth/AuthLayout.js index 75a8cfc61..641b754ed 100644 --- a/src/components/auth/AuthLayout.js +++ b/src/components/auth/AuthLayout.js | |||
@@ -52,7 +52,7 @@ export default @observer class AuthLayout extends Component { | |||
52 | 52 | ||
53 | return ( | 53 | return ( |
54 | <> | 54 | <> |
55 | {isWindows && !isFullScreen && <TitleBar menu={window.franz.menu.template} icon="assets/images/logo.svg" />} | 55 | {isWindows && !isFullScreen && <TitleBar menu={window.ferdi.menu.template} icon="assets/images/logo.svg" />} |
56 | <div className="auth"> | 56 | <div className="auth"> |
57 | {!isOnline && ( | 57 | {!isOnline && ( |
58 | <InfoBar | 58 | <InfoBar |
@@ -87,7 +87,7 @@ export default @observer class AuthLayout extends Component { | |||
87 | })} | 87 | })} |
88 | </div> | 88 | </div> |
89 | {/* </div> */} | 89 | {/* </div> */} |
90 | <Link to="https://adlk.io" className="auth__adlk" target="_blank"> | 90 | <Link to="https://github.com/kytwb/ferdi" className="auth__adlk" target="_blank"> |
91 | <img src="./assets/images/adlk.svg" alt="" /> | 91 | <img src="./assets/images/adlk.svg" alt="" /> |
92 | </Link> | 92 | </Link> |
93 | </div> | 93 | </div> |
diff --git a/src/components/auth/Import.js b/src/components/auth/Import.js index 0d5feb274..3e34c3162 100644 --- a/src/components/auth/Import.js +++ b/src/components/auth/Import.js | |||
@@ -12,11 +12,11 @@ import Button from '../ui/Button'; | |||
12 | const messages = defineMessages({ | 12 | const messages = defineMessages({ |
13 | headline: { | 13 | headline: { |
14 | id: 'import.headline', | 14 | id: 'import.headline', |
15 | defaultMessage: '!!!Import your Franz 4 services', | 15 | defaultMessage: '!!!Import your Ferdi 4 services', |
16 | }, | 16 | }, |
17 | notSupportedHeadline: { | 17 | notSupportedHeadline: { |
18 | id: 'import.notSupportedHeadline', | 18 | id: 'import.notSupportedHeadline', |
19 | defaultMessage: '!!!Services not yet supported in Franz 5', | 19 | defaultMessage: '!!!Services not yet supported in Ferdi 5', |
20 | }, | 20 | }, |
21 | submitButtonLabel: { | 21 | submitButtonLabel: { |
22 | id: 'import.submit.label', | 22 | id: 'import.submit.label', |
diff --git a/src/components/auth/Locked.js b/src/components/auth/Locked.js new file mode 100644 index 000000000..045621d0a --- /dev/null +++ b/src/components/auth/Locked.js | |||
@@ -0,0 +1,115 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer } from 'mobx-react'; | ||
4 | import { defineMessages, intlShape } from 'react-intl'; | ||
5 | |||
6 | import Form from '../../lib/Form'; | ||
7 | import { required } from '../../helpers/validation-helpers'; | ||
8 | import Input from '../ui/Input'; | ||
9 | import Button from '../ui/Button'; | ||
10 | import Infobox from '../ui/Infobox'; | ||
11 | |||
12 | import { globalError as globalErrorPropType } from '../../prop-types'; | ||
13 | |||
14 | const messages = defineMessages({ | ||
15 | headline: { | ||
16 | id: 'locked.headline', | ||
17 | defaultMessage: '!!!Locked', | ||
18 | }, | ||
19 | info: { | ||
20 | id: 'locked.info', | ||
21 | defaultMessage: '!!!Ferdi is currently locked. Please unlock Ferdi with your password to see your messages.', | ||
22 | }, | ||
23 | passwordLabel: { | ||
24 | id: 'locked.password.label', | ||
25 | defaultMessage: '!!!Password', | ||
26 | }, | ||
27 | submitButtonLabel: { | ||
28 | id: 'locked.submit.label', | ||
29 | defaultMessage: '!!!Unlock', | ||
30 | }, | ||
31 | invalidCredentials: { | ||
32 | id: 'locked.invalidCredentials', | ||
33 | defaultMessage: '!!!Password invalid', | ||
34 | }, | ||
35 | }); | ||
36 | |||
37 | export default @observer class Locked extends Component { | ||
38 | static propTypes = { | ||
39 | onSubmit: PropTypes.func.isRequired, | ||
40 | isSubmitting: PropTypes.bool.isRequired, | ||
41 | error: globalErrorPropType.isRequired, | ||
42 | }; | ||
43 | |||
44 | static contextTypes = { | ||
45 | intl: intlShape, | ||
46 | }; | ||
47 | |||
48 | form = new Form({ | ||
49 | fields: { | ||
50 | password: { | ||
51 | label: this.context.intl.formatMessage(messages.passwordLabel), | ||
52 | value: '', | ||
53 | validators: [required], | ||
54 | type: 'password', | ||
55 | }, | ||
56 | }, | ||
57 | }, this.context.intl); | ||
58 | |||
59 | submit(e) { | ||
60 | e.preventDefault(); | ||
61 | this.form.submit({ | ||
62 | onSuccess: (form) => { | ||
63 | this.props.onSubmit(form.values()); | ||
64 | }, | ||
65 | onError: () => { }, | ||
66 | }); | ||
67 | } | ||
68 | |||
69 | render() { | ||
70 | const { form } = this; | ||
71 | const { intl } = this.context; | ||
72 | const { | ||
73 | isSubmitting, | ||
74 | error, | ||
75 | } = this.props; | ||
76 | |||
77 | return ( | ||
78 | <div className="auth__container"> | ||
79 | <form className="franz-form auth__form" onSubmit={e => this.submit(e)}> | ||
80 | <img | ||
81 | src="./assets/images/logo.svg" | ||
82 | className="auth__logo" | ||
83 | alt="" | ||
84 | /> | ||
85 | <h1>{intl.formatMessage(messages.headline)}</h1> | ||
86 | <Infobox type="warning"> | ||
87 | {intl.formatMessage(messages.info)} | ||
88 | </Infobox> | ||
89 | <Input | ||
90 | field={form.$('password')} | ||
91 | showPasswordToggle | ||
92 | /> | ||
93 | {error.code === 'invalid-credentials' && ( | ||
94 | <p className="error-message center">{intl.formatMessage(messages.invalidCredentials)}</p> | ||
95 | )} | ||
96 | {isSubmitting ? ( | ||
97 | <Button | ||
98 | className="auth__button is-loading" | ||
99 | buttonType="secondary" | ||
100 | label={`${intl.formatMessage(messages.submitButtonLabel)} ...`} | ||
101 | loaded={false} | ||
102 | disabled | ||
103 | /> | ||
104 | ) : ( | ||
105 | <Button | ||
106 | type="submit" | ||
107 | className="auth__button" | ||
108 | label={intl.formatMessage(messages.submitButtonLabel)} | ||
109 | /> | ||
110 | )} | ||
111 | </form> | ||
112 | </div> | ||
113 | ); | ||
114 | } | ||
115 | } | ||
diff --git a/src/components/auth/Login.js b/src/components/auth/Login.js index 5d21f8b60..270dff30b 100644 --- a/src/components/auth/Login.js +++ b/src/components/auth/Login.js | |||
@@ -34,6 +34,14 @@ const messages = defineMessages({ | |||
34 | id: 'login.invalidCredentials', | 34 | id: 'login.invalidCredentials', |
35 | defaultMessage: '!!!Email or password not valid', | 35 | defaultMessage: '!!!Email or password not valid', |
36 | }, | 36 | }, |
37 | customServerQuestion: { | ||
38 | id: 'login.customServerQuestion', | ||
39 | defaultMessage: '!!!Using a custom Ferdi server?', | ||
40 | }, | ||
41 | customServerSuggestion: { | ||
42 | id: 'login.customServerSuggestion', | ||
43 | defaultMessage: '!!!Try importing your Franz account', | ||
44 | }, | ||
37 | tokenExpired: { | 45 | tokenExpired: { |
38 | id: 'login.tokenExpired', | 46 | id: 'login.tokenExpired', |
39 | defaultMessage: '!!!Your session expired, please login again.', | 47 | defaultMessage: '!!!Your session expired, please login again.', |
@@ -137,7 +145,22 @@ export default @observer class Login extends Component { | |||
137 | showPasswordToggle | 145 | showPasswordToggle |
138 | /> | 146 | /> |
139 | {error.code === 'invalid-credentials' && ( | 147 | {error.code === 'invalid-credentials' && ( |
140 | <p className="error-message center">{intl.formatMessage(messages.invalidCredentials)}</p> | 148 | <> |
149 | <p className="error-message center">{intl.formatMessage(messages.invalidCredentials)}</p> | ||
150 | { window.ferdi.stores.settings.all.app.server !== 'https://api.franzinfra.com' && ( | ||
151 | <p className="error-message center"> | ||
152 | {intl.formatMessage(messages.customServerQuestion)} | ||
153 | {' '} | ||
154 | <Link | ||
155 | to={`${window.ferdi.stores.settings.all.app.server.replace('v1', '')}/import`} | ||
156 | target="_blank" | ||
157 | style={{ cursor: 'pointer', textDecoration: 'underline' }} | ||
158 | > | ||
159 | {intl.formatMessage(messages.customServerSuggestion)} | ||
160 | </Link> | ||
161 | </p> | ||
162 | )} | ||
163 | </> | ||
141 | )} | 164 | )} |
142 | {isSubmitting ? ( | 165 | {isSubmitting ? ( |
143 | <Button | 166 | <Button |
@@ -156,6 +179,7 @@ export default @observer class Login extends Component { | |||
156 | )} | 179 | )} |
157 | </form> | 180 | </form> |
158 | <div className="auth__links"> | 181 | <div className="auth__links"> |
182 | <Link to="/settings/app">Change server</Link> | ||
159 | <Link to={signupRoute}>{intl.formatMessage(messages.signupLink)}</Link> | 183 | <Link to={signupRoute}>{intl.formatMessage(messages.signupLink)}</Link> |
160 | <Link to={passwordRoute}>{intl.formatMessage(messages.passwordLink)}</Link> | 184 | <Link to={passwordRoute}>{intl.formatMessage(messages.passwordLink)}</Link> |
161 | </div> | 185 | </div> |
diff --git a/src/components/auth/Pricing.js b/src/components/auth/Pricing.js index cbeaaa5d9..a77ad7742 100644 --- a/src/components/auth/Pricing.js +++ b/src/components/auth/Pricing.js | |||
@@ -42,7 +42,7 @@ const messages = defineMessages({ | |||
42 | }, | 42 | }, |
43 | ctaSkip: { | 43 | ctaSkip: { |
44 | id: 'pricing.trial.cta.skip', | 44 | id: 'pricing.trial.cta.skip', |
45 | defaultMessage: '!!!Continue to Franz', | 45 | defaultMessage: '!!!Continue to Ferdi', |
46 | }, | 46 | }, |
47 | featuresHeadline: { | 47 | featuresHeadline: { |
48 | id: 'pricing.trial.features.headline', | 48 | id: 'pricing.trial.features.headline', |
diff --git a/src/components/auth/Signup.js b/src/components/auth/Signup.js index 0499d764b..b36e71ce1 100644 --- a/src/components/auth/Signup.js +++ b/src/components/auth/Signup.js | |||
@@ -40,7 +40,7 @@ const messages = defineMessages({ | |||
40 | }, | 40 | }, |
41 | legalInfo: { | 41 | legalInfo: { |
42 | id: 'signup.legal.info', | 42 | id: 'signup.legal.info', |
43 | defaultMessage: '!!!By creating a Franz account you accept the', | 43 | defaultMessage: '!!!By creating a Ferdi account you accept the', |
44 | }, | 44 | }, |
45 | terms: { | 45 | terms: { |
46 | id: 'signup.legal.terms', | 46 | id: 'signup.legal.terms', |
@@ -117,6 +117,8 @@ export default @observer class Signup extends Component { | |||
117 | const { intl } = this.context; | 117 | const { intl } = this.context; |
118 | const { isSubmitting, loginRoute, error } = this.props; | 118 | const { isSubmitting, loginRoute, error } = this.props; |
119 | 119 | ||
120 | const termsBase = window.ferdi.stores.settings.all.app.server !== 'https://api.franzinfra.com' ? window.ferdi.stores.settings.all.app.server : 'https://meetfranz.com'; | ||
121 | |||
120 | return ( | 122 | return ( |
121 | <div className="auth__scroll-container"> | 123 | <div className="auth__scroll-container"> |
122 | <div className="auth__container auth__container--signup"> | 124 | <div className="auth__container auth__container--signup"> |
@@ -163,7 +165,7 @@ export default @observer class Signup extends Component { | |||
163 | {intl.formatMessage(messages.legalInfo)} | 165 | {intl.formatMessage(messages.legalInfo)} |
164 | <br /> | 166 | <br /> |
165 | <Link | 167 | <Link |
166 | to="https://meetfranz.com/terms" | 168 | to={`${termsBase}/terms`} |
167 | target="_blank" | 169 | target="_blank" |
168 | className="link" | 170 | className="link" |
169 | > | 171 | > |
@@ -171,7 +173,7 @@ export default @observer class Signup extends Component { | |||
171 | </Link> | 173 | </Link> |
172 | & | 174 | & |
173 | <Link | 175 | <Link |
174 | to="https://meetfranz.com/privacy" | 176 | to={`${termsBase}/privacy`} |
175 | target="_blank" | 177 | target="_blank" |
176 | className="link" | 178 | className="link" |
177 | > | 179 | > |
@@ -181,6 +183,7 @@ export default @observer class Signup extends Component { | |||
181 | </p> | 183 | </p> |
182 | </form> | 184 | </form> |
183 | <div className="auth__links"> | 185 | <div className="auth__links"> |
186 | <Link to="/settings/app">Change server</Link> | ||
184 | <Link to={loginRoute}>{intl.formatMessage(messages.loginLink)}</Link> | 187 | <Link to={loginRoute}>{intl.formatMessage(messages.loginLink)}</Link> |
185 | </div> | 188 | </div> |
186 | </div> | 189 | </div> |
diff --git a/src/components/auth/Welcome.js b/src/components/auth/Welcome.js index f6d77f70f..ef917e336 100644 --- a/src/components/auth/Welcome.js +++ b/src/components/auth/Welcome.js | |||
@@ -41,7 +41,7 @@ export default @observer class Login extends Component { | |||
41 | <img src="./assets/images/logo.svg" className="welcome__logo" alt="" /> | 41 | <img src="./assets/images/logo.svg" className="welcome__logo" alt="" /> |
42 | {/* <img src="./assets/images/welcome.png" className="welcome__services" alt="" /> */} | 42 | {/* <img src="./assets/images/welcome.png" className="welcome__services" alt="" /> */} |
43 | <div className="welcome__text"> | 43 | <div className="welcome__text"> |
44 | <h1>Franz</h1> | 44 | <h1>Ferdi</h1> |
45 | </div> | 45 | </div> |
46 | </div> | 46 | </div> |
47 | <div className="welcome__buttons"> | 47 | <div className="welcome__buttons"> |
@@ -51,6 +51,19 @@ export default @observer class Login extends Component { | |||
51 | <Link to={loginRoute} className="button"> | 51 | <Link to={loginRoute} className="button"> |
52 | {intl.formatMessage(messages.loginButton)} | 52 | {intl.formatMessage(messages.loginButton)} |
53 | </Link> | 53 | </Link> |
54 | <br /> | ||
55 | <br /> | ||
56 | |||
57 | <Link to="settings/app"> | ||
58 | <span style={{ | ||
59 | textAlign: 'center', | ||
60 | width: '100%', | ||
61 | cursor: 'pointer', | ||
62 | }} | ||
63 | > | ||
64 | Change server | ||
65 | </span> | ||
66 | </Link> | ||
54 | </div> | 67 | </div> |
55 | <div className="welcome__featured-services"> | 68 | <div className="welcome__featured-services"> |
56 | {recipes.map(recipe => ( | 69 | {recipes.map(recipe => ( |
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js index 200777ae6..e82275b9f 100644 --- a/src/components/layout/AppLayout.js +++ b/src/components/layout/AppLayout.js | |||
@@ -6,7 +6,6 @@ import { TitleBar } from 'electron-react-titlebar'; | |||
6 | import injectSheet from 'react-jss'; | 6 | import injectSheet from 'react-jss'; |
7 | 7 | ||
8 | import InfoBar from '../ui/InfoBar'; | 8 | import InfoBar from '../ui/InfoBar'; |
9 | import { Component as DelayApp } from '../../features/delayApp'; | ||
10 | import { Component as BasicAuth } from '../../features/basicAuth'; | 9 | import { Component as BasicAuth } from '../../features/basicAuth'; |
11 | import { Component as ShareFranz } from '../../features/shareFranz'; | 10 | import { Component as ShareFranz } from '../../features/shareFranz'; |
12 | import ErrorBoundary from '../util/ErrorBoundary'; | 11 | import ErrorBoundary from '../util/ErrorBoundary'; |
@@ -37,6 +36,10 @@ const messages = defineMessages({ | |||
37 | id: 'infobar.requiredRequestsFailed', | 36 | id: 'infobar.requiredRequestsFailed', |
38 | defaultMessage: '!!!Could not load services and user information', | 37 | defaultMessage: '!!!Could not load services and user information', |
39 | }, | 38 | }, |
39 | authRequestFailed: { | ||
40 | id: 'infobar.authRequestFailed', | ||
41 | defaultMessage: '!!!There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.', | ||
42 | }, | ||
40 | }); | 43 | }); |
41 | 44 | ||
42 | const styles = theme => ({ | 45 | const styles = theme => ({ |
@@ -63,6 +66,7 @@ class AppLayout extends Component { | |||
63 | showServicesUpdatedInfoBar: PropTypes.bool.isRequired, | 66 | showServicesUpdatedInfoBar: PropTypes.bool.isRequired, |
64 | appUpdateIsDownloaded: PropTypes.bool.isRequired, | 67 | appUpdateIsDownloaded: PropTypes.bool.isRequired, |
65 | nextAppReleaseVersion: PropTypes.string, | 68 | nextAppReleaseVersion: PropTypes.string, |
69 | authRequestFailed: PropTypes.bool.isRequired, | ||
66 | removeNewsItem: PropTypes.func.isRequired, | 70 | removeNewsItem: PropTypes.func.isRequired, |
67 | reloadServicesAfterUpdate: PropTypes.func.isRequired, | 71 | reloadServicesAfterUpdate: PropTypes.func.isRequired, |
68 | installAppUpdate: PropTypes.func.isRequired, | 72 | installAppUpdate: PropTypes.func.isRequired, |
@@ -70,7 +74,6 @@ class AppLayout extends Component { | |||
70 | areRequiredRequestsSuccessful: PropTypes.bool.isRequired, | 74 | areRequiredRequestsSuccessful: PropTypes.bool.isRequired, |
71 | retryRequiredRequests: PropTypes.func.isRequired, | 75 | retryRequiredRequests: PropTypes.func.isRequired, |
72 | areRequiredRequestsLoading: PropTypes.bool.isRequired, | 76 | areRequiredRequestsLoading: PropTypes.bool.isRequired, |
73 | isDelayAppScreenVisible: PropTypes.bool.isRequired, | ||
74 | hasActivatedTrial: PropTypes.bool.isRequired, | 77 | hasActivatedTrial: PropTypes.bool.isRequired, |
75 | }; | 78 | }; |
76 | 79 | ||
@@ -95,6 +98,7 @@ class AppLayout extends Component { | |||
95 | showServicesUpdatedInfoBar, | 98 | showServicesUpdatedInfoBar, |
96 | appUpdateIsDownloaded, | 99 | appUpdateIsDownloaded, |
97 | nextAppReleaseVersion, | 100 | nextAppReleaseVersion, |
101 | authRequestFailed, | ||
98 | removeNewsItem, | 102 | removeNewsItem, |
99 | reloadServicesAfterUpdate, | 103 | reloadServicesAfterUpdate, |
100 | installAppUpdate, | 104 | installAppUpdate, |
@@ -102,7 +106,6 @@ class AppLayout extends Component { | |||
102 | areRequiredRequestsSuccessful, | 106 | areRequiredRequestsSuccessful, |
103 | retryRequiredRequests, | 107 | retryRequiredRequests, |
104 | areRequiredRequestsLoading, | 108 | areRequiredRequestsLoading, |
105 | isDelayAppScreenVisible, | ||
106 | hasActivatedTrial, | 109 | hasActivatedTrial, |
107 | } = this.props; | 110 | } = this.props; |
108 | 111 | ||
@@ -111,7 +114,7 @@ class AppLayout extends Component { | |||
111 | return ( | 114 | return ( |
112 | <ErrorBoundary> | 115 | <ErrorBoundary> |
113 | <div className="app"> | 116 | <div className="app"> |
114 | {isWindows && !isFullScreen && <TitleBar menu={window.franz.menu.template} icon="assets/images/logo.svg" />} | 117 | {isWindows && !isFullScreen && <TitleBar menu={window.ferdi.menu.template} icon="assets/images/logo.svg" />} |
115 | <div className={`app__content ${classes.appContent}`}> | 118 | <div className={`app__content ${classes.appContent}`}> |
116 | {workspacesDrawer} | 119 | {workspacesDrawer} |
117 | {sidebar} | 120 | {sidebar} |
@@ -151,6 +154,18 @@ class AppLayout extends Component { | |||
151 | {intl.formatMessage(messages.requiredRequestsFailed)} | 154 | {intl.formatMessage(messages.requiredRequestsFailed)} |
152 | </InfoBar> | 155 | </InfoBar> |
153 | )} | 156 | )} |
157 | {authRequestFailed && ( | ||
158 | <InfoBar | ||
159 | type="danger" | ||
160 | ctaLabel="Try again" | ||
161 | ctaLoading={areRequiredRequestsLoading} | ||
162 | sticky | ||
163 | onClick={retryRequiredRequests} | ||
164 | > | ||
165 | <span className="mdi mdi-flash" /> | ||
166 | {intl.formatMessage(messages.authRequestFailed)} | ||
167 | </InfoBar> | ||
168 | )} | ||
154 | {showServicesUpdatedInfoBar && ( | 169 | {showServicesUpdatedInfoBar && ( |
155 | <InfoBar | 170 | <InfoBar |
156 | type="primary" | 171 | type="primary" |
@@ -168,7 +183,6 @@ class AppLayout extends Component { | |||
168 | onInstallUpdate={installAppUpdate} | 183 | onInstallUpdate={installAppUpdate} |
169 | /> | 184 | /> |
170 | )} | 185 | )} |
171 | {isDelayAppScreenVisible && (<DelayApp />)} | ||
172 | <BasicAuth /> | 186 | <BasicAuth /> |
173 | <ShareFranz /> | 187 | <ShareFranz /> |
174 | {services} | 188 | {services} |
diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js index 918298011..52de16508 100644 --- a/src/components/layout/Sidebar.js +++ b/src/components/layout/Sidebar.js | |||
@@ -2,13 +2,13 @@ import React, { Component } from 'react'; | |||
2 | import PropTypes from 'prop-types'; | 2 | import PropTypes from 'prop-types'; |
3 | import ReactTooltip from 'react-tooltip'; | 3 | import ReactTooltip from 'react-tooltip'; |
4 | import { defineMessages, intlShape } from 'react-intl'; | 4 | import { defineMessages, intlShape } from 'react-intl'; |
5 | import { observer } from 'mobx-react'; | 5 | import { inject, observer } from 'mobx-react'; |
6 | import { Link } from 'react-router'; | ||
6 | 7 | ||
7 | import Tabbar from '../services/tabs/Tabbar'; | 8 | import Tabbar from '../services/tabs/Tabbar'; |
8 | import { ctrlKey } from '../../environment'; | 9 | import { ctrlKey } from '../../environment'; |
9 | import { GA_CATEGORY_WORKSPACES, workspaceStore } from '../../features/workspaces'; | 10 | import { workspaceStore } from '../../features/workspaces'; |
10 | import { gaEvent } from '../../lib/analytics'; | 11 | import { todosStore } from '../../features/todos'; |
11 | import { todosStore, GA_CATEGORY_TODOS } from '../../features/todos'; | ||
12 | import { todoActions } from '../../features/todos/actions'; | 12 | import { todoActions } from '../../features/todos/actions'; |
13 | 13 | ||
14 | const messages = defineMessages({ | 14 | const messages = defineMessages({ |
@@ -44,9 +44,13 @@ const messages = defineMessages({ | |||
44 | id: 'sidebar.closeTodosDrawer', | 44 | id: 'sidebar.closeTodosDrawer', |
45 | defaultMessage: '!!!Close Franz Todos', | 45 | defaultMessage: '!!!Close Franz Todos', |
46 | }, | 46 | }, |
47 | lockFerdi: { | ||
48 | id: 'sidebar.lockFerdi', | ||
49 | defaultMessage: '!!!Lock Ferdi', | ||
50 | }, | ||
47 | }); | 51 | }); |
48 | 52 | ||
49 | export default @observer class Sidebar extends Component { | 53 | export default @inject('stores', 'actions') @observer class Sidebar extends Component { |
50 | static propTypes = { | 54 | static propTypes = { |
51 | openSettings: PropTypes.func.isRequired, | 55 | openSettings: PropTypes.func.isRequired, |
52 | toggleMuteApp: PropTypes.func.isRequired, | 56 | toggleMuteApp: PropTypes.func.isRequired, |
@@ -87,6 +91,8 @@ export default @observer class Sidebar extends Component { | |||
87 | isAppMuted, | 91 | isAppMuted, |
88 | isWorkspaceDrawerOpen, | 92 | isWorkspaceDrawerOpen, |
89 | toggleWorkspaceDrawer, | 93 | toggleWorkspaceDrawer, |
94 | stores, | ||
95 | actions, | ||
90 | } = this.props; | 96 | } = this.props; |
91 | const { intl } = this.context; | 97 | const { intl } = this.context; |
92 | const todosToggleMessage = ( | 98 | const todosToggleMessage = ( |
@@ -96,6 +102,7 @@ export default @observer class Sidebar extends Component { | |||
96 | const workspaceToggleMessage = ( | 102 | const workspaceToggleMessage = ( |
97 | isWorkspaceDrawerOpen ? messages.closeWorkspaceDrawer : messages.openWorkspaceDrawer | 103 | isWorkspaceDrawerOpen ? messages.closeWorkspaceDrawer : messages.openWorkspaceDrawer |
98 | ); | 104 | ); |
105 | const isLoggedIn = Boolean(localStorage.getItem('authToken')); | ||
99 | 106 | ||
100 | return ( | 107 | return ( |
101 | <div className="sidebar"> | 108 | <div className="sidebar"> |
@@ -104,53 +111,81 @@ export default @observer class Sidebar extends Component { | |||
104 | enableToolTip={() => this.enableToolTip()} | 111 | enableToolTip={() => this.enableToolTip()} |
105 | disableToolTip={() => this.disableToolTip()} | 112 | disableToolTip={() => this.disableToolTip()} |
106 | /> | 113 | /> |
107 | {todosStore.isFeatureEnabled && todosStore.isFeatureEnabledByUser ? ( | 114 | { isLoggedIn ? ( |
108 | <button | 115 | <> |
109 | type="button" | 116 | { stores.settings.all.app.lockingFeatureEnabled ? ( |
110 | onClick={() => { | 117 | <button |
111 | todoActions.toggleTodosPanel(); | 118 | type="button" |
112 | this.updateToolTip(); | 119 | className={`sidebar__button sidebar__button--audio ${isAppMuted ? 'is-muted' : ''}`} |
113 | gaEvent(GA_CATEGORY_TODOS, 'toggleDrawer', 'sidebar'); | 120 | onClick={() => { |
114 | }} | 121 | actions.settings.update({ |
115 | className={`sidebar__button sidebar__button--todos ${todosStore.isTodosPanelVisible ? 'is-active' : ''}`} | 122 | type: 'app', |
116 | data-tip={`${intl.formatMessage(todosToggleMessage)} (${ctrlKey}+T)`} | 123 | data: { |
117 | > | 124 | locked: true, |
118 | <i className="mdi mdi-check-all" /> | 125 | }, |
119 | </button> | 126 | }); |
120 | ) : null} | 127 | }} |
121 | {workspaceStore.isFeatureEnabled ? ( | 128 | data-tip={`${intl.formatMessage(messages.lockFerdi)} (${ctrlKey}+Shift+L)`} |
122 | <button | 129 | > |
123 | type="button" | 130 | <i className="mdi mdi-lock" /> |
124 | onClick={() => { | 131 | </button> |
125 | toggleWorkspaceDrawer(); | 132 | ) : null} |
126 | this.updateToolTip(); | 133 | {todosStore.isFeatureEnabled && todosStore.isFeatureEnabledByUser ? ( |
127 | gaEvent(GA_CATEGORY_WORKSPACES, 'toggleDrawer', 'sidebar'); | 134 | <button |
128 | }} | 135 | type="button" |
129 | className={`sidebar__button sidebar__button--workspaces ${isWorkspaceDrawerOpen ? 'is-active' : ''}`} | 136 | onClick={() => { |
130 | data-tip={`${intl.formatMessage(workspaceToggleMessage)} (${ctrlKey}+D)`} | 137 | todoActions.toggleTodosPanel(); |
138 | this.updateToolTip(); | ||
139 | gaEvent(GA_CATEGORY_TODOS, 'toggleDrawer', 'sidebar'); | ||
140 | }} | ||
141 | className={`sidebar__button sidebar__button--todos ${todosStore.isTodosPanelVisible ? 'is-active' : ''}`} | ||
142 | data-tip={`${intl.formatMessage(todosToggleMessage)} (${ctrlKey}+T)`} | ||
143 | > | ||
144 | <i className="mdi mdi-check-all" /> | ||
145 | </button> | ||
146 | ) : null} | ||
147 | {workspaceStore.isFeatureEnabled ? ( | ||
148 | <button | ||
149 | type="button" | ||
150 | onClick={() => { | ||
151 | toggleWorkspaceDrawer(); | ||
152 | this.updateToolTip(); | ||
153 | }} | ||
154 | className={`sidebar__button sidebar__button--workspaces ${isWorkspaceDrawerOpen ? 'is-active' : ''}`} | ||
155 | data-tip={`${intl.formatMessage(workspaceToggleMessage)} (${ctrlKey}+D)`} | ||
156 | > | ||
157 | <i className="mdi mdi-view-grid" /> | ||
158 | </button> | ||
159 | ) : null} | ||
160 | <button | ||
161 | type="button" | ||
162 | onClick={() => { | ||
163 | toggleMuteApp(); | ||
164 | this.updateToolTip(); | ||
165 | }} | ||
166 | className={`sidebar__button sidebar__button--audio ${isAppMuted ? 'is-muted' : ''}`} | ||
167 | data-tip={`${intl.formatMessage(isAppMuted ? messages.unmute : messages.mute)} (${ctrlKey}+Shift+M)`} | ||
168 | > | ||
169 | <i className={`mdi mdi-bell${isAppMuted ? '-off' : ''}`} /> | ||
170 | </button> | ||
171 | <button | ||
172 | type="button" | ||
173 | onClick={() => openSettings({ path: 'recipes' })} | ||
174 | className="sidebar__button sidebar__button--new-service" | ||
175 | data-tip={`${intl.formatMessage(messages.addNewService)} (${ctrlKey}+N)`} | ||
176 | > | ||
177 | <i className="mdi mdi-plus-box" /> | ||
178 | </button> | ||
179 | </> | ||
180 | ) : ( | ||
181 | <Link | ||
182 | to="/auth/welcome" | ||
183 | className="sidebar__button sidebar__button--new-service" | ||
184 | data-tip="Login" | ||
131 | > | 185 | > |
132 | <i className="mdi mdi-view-grid" /> | 186 | <i className="mdi mdi-login-variant" /> |
133 | </button> | 187 | </Link> |
134 | ) : null} | 188 | )} |
135 | <button | ||
136 | type="button" | ||
137 | onClick={() => { | ||
138 | toggleMuteApp(); | ||
139 | this.updateToolTip(); | ||
140 | }} | ||
141 | className={`sidebar__button sidebar__button--audio ${isAppMuted ? 'is-muted' : ''}`} | ||
142 | data-tip={`${intl.formatMessage(isAppMuted ? messages.unmute : messages.mute)} (${ctrlKey}+Shift+M)`} | ||
143 | > | ||
144 | <i className={`mdi mdi-bell${isAppMuted ? '-off' : ''}`} /> | ||
145 | </button> | ||
146 | <button | ||
147 | type="button" | ||
148 | onClick={() => openSettings({ path: 'recipes' })} | ||
149 | className="sidebar__button sidebar__button--new-service" | ||
150 | data-tip={`${intl.formatMessage(messages.addNewService)} (${ctrlKey}+N)`} | ||
151 | > | ||
152 | <i className="mdi mdi-plus-box" /> | ||
153 | </button> | ||
154 | <button | 189 | <button |
155 | type="button" | 190 | type="button" |
156 | onClick={() => openSettings({ path: 'app' })} | 191 | onClick={() => openSettings({ path: 'app' })} |
diff --git a/src/components/services/content/ServiceView.js b/src/components/services/content/ServiceView.js index f65f51346..59d1c1dc3 100644 --- a/src/components/services/content/ServiceView.js +++ b/src/components/services/content/ServiceView.js | |||
@@ -10,7 +10,6 @@ import WebviewLoader from '../../ui/WebviewLoader'; | |||
10 | import WebviewCrashHandler from './WebviewCrashHandler'; | 10 | import WebviewCrashHandler from './WebviewCrashHandler'; |
11 | import WebviewErrorHandler from './ErrorHandlers/WebviewErrorHandler'; | 11 | import WebviewErrorHandler from './ErrorHandlers/WebviewErrorHandler'; |
12 | import ServiceDisabled from './ServiceDisabled'; | 12 | import ServiceDisabled from './ServiceDisabled'; |
13 | import ServiceRestricted from './ServiceRestricted'; | ||
14 | import ServiceWebview from './ServiceWebview'; | 13 | import ServiceWebview from './ServiceWebview'; |
15 | 14 | ||
16 | export default @observer class ServiceView extends Component { | 15 | export default @observer class ServiceView extends Component { |
@@ -22,7 +21,6 @@ export default @observer class ServiceView extends Component { | |||
22 | edit: PropTypes.func.isRequired, | 21 | edit: PropTypes.func.isRequired, |
23 | enable: PropTypes.func.isRequired, | 22 | enable: PropTypes.func.isRequired, |
24 | isActive: PropTypes.bool, | 23 | isActive: PropTypes.bool, |
25 | upgrade: PropTypes.func.isRequired, | ||
26 | }; | 24 | }; |
27 | 25 | ||
28 | static defaultProps = { | 26 | static defaultProps = { |
@@ -74,7 +72,6 @@ export default @observer class ServiceView extends Component { | |||
74 | reload, | 72 | reload, |
75 | edit, | 73 | edit, |
76 | enable, | 74 | enable, |
77 | upgrade, | ||
78 | } = this.props; | 75 | } = this.props; |
79 | 76 | ||
80 | const webviewClasses = classnames({ | 77 | const webviewClasses = classnames({ |
@@ -130,19 +127,11 @@ export default @observer class ServiceView extends Component { | |||
130 | </Fragment> | 127 | </Fragment> |
131 | ) : ( | 128 | ) : ( |
132 | <> | 129 | <> |
133 | {service.isServiceAccessRestricted ? ( | 130 | <ServiceWebview |
134 | <ServiceRestricted | 131 | service={service} |
135 | name={service.recipe.name} | 132 | setWebviewReference={setWebviewReference} |
136 | upgrade={upgrade} | 133 | detachService={detachService} |
137 | type={service.restrictionType} | 134 | /> |
138 | /> | ||
139 | ) : ( | ||
140 | <ServiceWebview | ||
141 | service={service} | ||
142 | setWebviewReference={setWebviewReference} | ||
143 | detachService={detachService} | ||
144 | /> | ||
145 | )} | ||
146 | </> | 135 | </> |
147 | )} | 136 | )} |
148 | {statusBar} | 137 | {statusBar} |
diff --git a/src/components/services/content/Services.js b/src/components/services/content/Services.js index 73c27bfb6..1afbaabc4 100644 --- a/src/components/services/content/Services.js +++ b/src/components/services/content/Services.js | |||
@@ -13,12 +13,20 @@ import Appear from '../../ui/effects/Appear'; | |||
13 | const messages = defineMessages({ | 13 | const messages = defineMessages({ |
14 | welcome: { | 14 | welcome: { |
15 | id: 'services.welcome', | 15 | id: 'services.welcome', |
16 | defaultMessage: '!!!Welcome to Franz', | 16 | defaultMessage: '!!!Welcome to Ferdi', |
17 | }, | 17 | }, |
18 | getStarted: { | 18 | getStarted: { |
19 | id: 'services.getStarted', | 19 | id: 'services.getStarted', |
20 | defaultMessage: '!!!Get started', | 20 | defaultMessage: '!!!Get started', |
21 | }, | 21 | }, |
22 | login: { | ||
23 | id: 'services.login', | ||
24 | defaultMessage: '!!!Please login to use Ferdi.', | ||
25 | }, | ||
26 | serverInfo: { | ||
27 | id: 'services.serverInfo', | ||
28 | defaultMessage: '!!!Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner.', | ||
29 | }, | ||
22 | }); | 30 | }); |
23 | 31 | ||
24 | 32 | ||
@@ -86,6 +94,7 @@ export default @observer @injectSheet(styles) class Services extends Component { | |||
86 | } = this.state; | 94 | } = this.state; |
87 | 95 | ||
88 | const { intl } = this.context; | 96 | const { intl } = this.context; |
97 | const isLoggedIn = Boolean(localStorage.getItem('authToken')); | ||
89 | 98 | ||
90 | return ( | 99 | return ( |
91 | <div className="services"> | 100 | <div className="services"> |
@@ -104,14 +113,20 @@ export default @observer @injectSheet(styles) class Services extends Component { | |||
104 | transitionName="slideUp" | 113 | transitionName="slideUp" |
105 | > | 114 | > |
106 | <div className="services__no-service"> | 115 | <div className="services__no-service"> |
107 | <img src="./assets/images/logo.svg" alt="" /> | 116 | <img src="./assets/images/logo.svg" alt="Logo" style={{ maxHeight: '50vh' }} /> |
108 | <h1>{intl.formatMessage(messages.welcome)}</h1> | 117 | <h1>{intl.formatMessage(messages.welcome)}</h1> |
118 | { !isLoggedIn && ( | ||
119 | <> | ||
120 | <p>{intl.formatMessage(messages.login)}</p> | ||
121 | <p>{intl.formatMessage(messages.serverInfo)}</p> | ||
122 | </> | ||
123 | ) } | ||
109 | <Appear | 124 | <Appear |
110 | timeout={300} | 125 | timeout={300} |
111 | transitionName="slideUp" | 126 | transitionName="slideUp" |
112 | > | 127 | > |
113 | <Link to="/settings/recipes" className="button"> | 128 | <Link to={isLoggedIn ? '/settings/services' : '/auth/welcome'} className="button"> |
114 | {intl.formatMessage(messages.getStarted)} | 129 | { isLoggedIn ? intl.formatMessage(messages.getStarted) : 'Login' } |
115 | </Link> | 130 | </Link> |
116 | </Appear> | 131 | </Appear> |
117 | </div> | 132 | </div> |
diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js index ac2594604..f588449f4 100644 --- a/src/components/settings/account/AccountDashboard.js +++ b/src/components/settings/account/AccountDashboard.js | |||
@@ -69,7 +69,7 @@ const messages = defineMessages({ | |||
69 | }, | 69 | }, |
70 | deleteInfo: { | 70 | deleteInfo: { |
71 | id: 'settings.account.deleteInfo', | 71 | id: 'settings.account.deleteInfo', |
72 | defaultMessage: '!!!If you don\'t need your Franz account any longer, you can delete your account and all related data here.', | 72 | defaultMessage: '!!!If you don\'t need your Ferdi account any longer, you can delete your account and all related data here.', |
73 | }, | 73 | }, |
74 | deleteEmailSent: { | 74 | deleteEmailSent: { |
75 | id: 'settings.account.deleteEmailSent', | 75 | id: 'settings.account.deleteEmailSent', |
diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js index 4696b82eb..201819526 100644 --- a/src/components/settings/navigation/SettingsNavigation.js +++ b/src/components/settings/navigation/SettingsNavigation.js | |||
@@ -64,6 +64,7 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp | |||
64 | const { isDarkThemeActive } = stores.ui; | 64 | const { isDarkThemeActive } = stores.ui; |
65 | const { router, user } = stores; | 65 | const { router, user } = stores; |
66 | const { intl } = this.context; | 66 | const { intl } = this.context; |
67 | const isLoggedIn = Boolean(localStorage.getItem('authToken')); | ||
67 | 68 | ||
68 | return ( | 69 | return ( |
69 | <div className="settings-navigation"> | 70 | <div className="settings-navigation"> |
@@ -136,10 +137,10 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp | |||
136 | </Link> | 137 | </Link> |
137 | <span className="settings-navigation__expander" /> | 138 | <span className="settings-navigation__expander" /> |
138 | <Link | 139 | <Link |
139 | to="/auth/logout" | 140 | to={isLoggedIn ? '/auth/logout' : '/auth/welcome'} |
140 | className="settings-navigation__link" | 141 | className="settings-navigation__link" |
141 | > | 142 | > |
142 | {intl.formatMessage(messages.logout)} | 143 | { isLoggedIn ? intl.formatMessage(messages.logout) : 'Login'} |
143 | </Link> | 144 | </Link> |
144 | </div> | 145 | </div> |
145 | ); | 146 | ); |
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js index 5cde0db8e..5fe00cb8b 100644 --- a/src/components/settings/services/EditServiceForm.js +++ b/src/components/settings/services/EditServiceForm.js | |||
@@ -63,7 +63,7 @@ const messages = defineMessages({ | |||
63 | }, | 63 | }, |
64 | customUrlPremiumInfo: { | 64 | customUrlPremiumInfo: { |
65 | id: 'settings.service.form.customUrlPremiumInfo', | 65 | id: 'settings.service.form.customUrlPremiumInfo', |
66 | defaultMessage: '!!!To add self hosted services, you need a Franz Premium Supporter Account.', | 66 | defaultMessage: '!!!To add self hosted services, you need a Ferdi Premium Supporter Account.', |
67 | }, | 67 | }, |
68 | customUrlUpgradeAccount: { | 68 | customUrlUpgradeAccount: { |
69 | id: 'settings.service.form.customUrlUpgradeAccount', | 69 | id: 'settings.service.form.customUrlUpgradeAccount', |
@@ -103,11 +103,11 @@ const messages = defineMessages({ | |||
103 | }, | 103 | }, |
104 | proxyRestartInfo: { | 104 | proxyRestartInfo: { |
105 | id: 'settings.service.form.proxy.restartInfo', | 105 | id: 'settings.service.form.proxy.restartInfo', |
106 | defaultMessage: '!!!Please restart Franz after changing proxy Settings.', | 106 | defaultMessage: '!!!Please restart Ferdi after changing proxy Settings.', |
107 | }, | 107 | }, |
108 | proxyInfo: { | 108 | proxyInfo: { |
109 | id: 'settings.service.form.proxy.info', | 109 | id: 'settings.service.form.proxy.info', |
110 | defaultMessage: '!!!Proxy settings will not be synchronized with the Franz servers.', | 110 | defaultMessage: '!!!Proxy settings will not be synchronized with the Ferdi servers.', |
111 | }, | 111 | }, |
112 | }); | 112 | }); |
113 | 113 | ||
@@ -155,7 +155,7 @@ export default @observer class EditServiceForm extends Component { | |||
155 | const values = form.values(); | 155 | const values = form.values(); |
156 | let isValid = true; | 156 | let isValid = true; |
157 | 157 | ||
158 | const files = form.$('customIcon').files; | 158 | const { files } = form.$('customIcon'); |
159 | if (files) { | 159 | if (files) { |
160 | values.iconFile = files[0]; | 160 | values.iconFile = files[0]; |
161 | } | 161 | } |
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js index 0b69f7514..0152857a6 100644 --- a/src/components/settings/settings/EditSettingsForm.js +++ b/src/components/settings/settings/EditSettingsForm.js | |||
@@ -9,6 +9,7 @@ import Button from '../../ui/Button'; | |||
9 | import Toggle from '../../ui/Toggle'; | 9 | import Toggle from '../../ui/Toggle'; |
10 | import Select from '../../ui/Select'; | 10 | import Select from '../../ui/Select'; |
11 | import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer'; | 11 | import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer'; |
12 | import Input from '../../ui/Input'; | ||
12 | 13 | ||
13 | import { FRANZ_TRANSLATION } from '../../../config'; | 14 | import { FRANZ_TRANSLATION } from '../../../config'; |
14 | 15 | ||
@@ -21,6 +22,22 @@ const messages = defineMessages({ | |||
21 | id: 'settings.app.headlineGeneral', | 22 | id: 'settings.app.headlineGeneral', |
22 | defaultMessage: '!!!General', | 23 | defaultMessage: '!!!General', |
23 | }, | 24 | }, |
25 | serverInfo: { | ||
26 | id: 'settings.app.serverInfo', | ||
27 | defaultMessage: '!!!We advice you to logout after changing your server as your settings might not be saved otherwise.', | ||
28 | }, | ||
29 | todoServerInfo: { | ||
30 | id: 'settings.app.todoServerInfo', | ||
31 | defaultMessage: '!!!This server will be used for the "Franz Todo" feature. The default server will only work for premium users. (default: https://app.franztodos.com)', | ||
32 | }, | ||
33 | lockedPassword: { | ||
34 | id: 'settings.app.lockedPassword', | ||
35 | defaultMessage: '!!!Ferdi Lock Password', | ||
36 | }, | ||
37 | lockedPasswordInfo: { | ||
38 | id: 'settings.app.lockedPasswordInfo', | ||
39 | defaultMessage: '!!!Please make sure to set a password you\'ll remember.\nIf you loose this password, you will have to reinstall Ferdi.', | ||
40 | }, | ||
24 | headlineLanguage: { | 41 | headlineLanguage: { |
25 | id: 'settings.app.headlineLanguage', | 42 | id: 'settings.app.headlineLanguage', |
26 | defaultMessage: '!!!Language', | 43 | defaultMessage: '!!!Language', |
@@ -39,7 +56,7 @@ const messages = defineMessages({ | |||
39 | }, | 56 | }, |
40 | translationHelp: { | 57 | translationHelp: { |
41 | id: 'settings.app.translationHelp', | 58 | id: 'settings.app.translationHelp', |
42 | defaultMessage: '!!!Help us to translate Franz into your language.', | 59 | defaultMessage: '!!!Help us to translate Ferdi into your language.', |
43 | }, | 60 | }, |
44 | subheadlineCache: { | 61 | subheadlineCache: { |
45 | id: 'settings.app.subheadlineCache', | 62 | id: 'settings.app.subheadlineCache', |
@@ -47,7 +64,7 @@ const messages = defineMessages({ | |||
47 | }, | 64 | }, |
48 | cacheInfo: { | 65 | cacheInfo: { |
49 | id: 'settings.app.cacheInfo', | 66 | id: 'settings.app.cacheInfo', |
50 | defaultMessage: '!!!Franz cache is currently using {size} of disk space.', | 67 | defaultMessage: '!!!Ferdi cache is currently using {size} of disk space.', |
51 | }, | 68 | }, |
52 | buttonClearAllCache: { | 69 | buttonClearAllCache: { |
53 | id: 'settings.app.buttonClearAllCache', | 70 | id: 'settings.app.buttonClearAllCache', |
@@ -71,7 +88,7 @@ const messages = defineMessages({ | |||
71 | }, | 88 | }, |
72 | updateStatusUpToDate: { | 89 | updateStatusUpToDate: { |
73 | id: 'settings.app.updateStatusUpToDate', | 90 | id: 'settings.app.updateStatusUpToDate', |
74 | defaultMessage: '!!!You are using the latest version of Franz', | 91 | defaultMessage: '!!!You are using the latest version of Ferdi', |
75 | }, | 92 | }, |
76 | currentVersion: { | 93 | currentVersion: { |
77 | id: 'settings.app.currentVersion', | 94 | id: 'settings.app.currentVersion', |
@@ -103,6 +120,7 @@ export default @observer class EditSettingsForm extends Component { | |||
103 | isSpellcheckerIncludedInCurrentPlan: PropTypes.bool.isRequired, | 120 | isSpellcheckerIncludedInCurrentPlan: PropTypes.bool.isRequired, |
104 | isTodosEnabled: PropTypes.bool.isRequired, | 121 | isTodosEnabled: PropTypes.bool.isRequired, |
105 | isWorkspaceEnabled: PropTypes.bool.isRequired, | 122 | isWorkspaceEnabled: PropTypes.bool.isRequired, |
123 | server: PropTypes.string.isRequired, | ||
106 | }; | 124 | }; |
107 | 125 | ||
108 | static contextTypes = { | 126 | static contextTypes = { |
@@ -135,6 +153,7 @@ export default @observer class EditSettingsForm extends Component { | |||
135 | isSpellcheckerIncludedInCurrentPlan, | 153 | isSpellcheckerIncludedInCurrentPlan, |
136 | isTodosEnabled, | 154 | isTodosEnabled, |
137 | isWorkspaceEnabled, | 155 | isWorkspaceEnabled, |
156 | server, | ||
138 | } = this.props; | 157 | } = this.props; |
139 | const { intl } = this.context; | 158 | const { intl } = this.context; |
140 | 159 | ||
@@ -147,6 +166,9 @@ export default @observer class EditSettingsForm extends Component { | |||
147 | updateButtonLabelMessage = messages.buttonSearchForUpdate; | 166 | updateButtonLabelMessage = messages.buttonSearchForUpdate; |
148 | } | 167 | } |
149 | 168 | ||
169 | const isLoggedIn = Boolean(localStorage.getItem('authToken')); | ||
170 | const lockingFeatureEnabled = window.ferdi.stores.settings.all.app.lockingFeatureEnabled; | ||
171 | |||
150 | return ( | 172 | return ( |
151 | <div className="settings__main"> | 173 | <div className="settings__main"> |
152 | <div className="settings__header"> | 174 | <div className="settings__header"> |
@@ -163,16 +185,92 @@ export default @observer class EditSettingsForm extends Component { | |||
163 | <Toggle field={form.$('autoLaunchOnStart')} /> | 185 | <Toggle field={form.$('autoLaunchOnStart')} /> |
164 | <Toggle field={form.$('runInBackground')} /> | 186 | <Toggle field={form.$('runInBackground')} /> |
165 | <Toggle field={form.$('enableSystemTray')} /> | 187 | <Toggle field={form.$('enableSystemTray')} /> |
188 | <Toggle field={form.$('privateNotifications')} /> | ||
166 | {process.platform === 'win32' && ( | 189 | {process.platform === 'win32' && ( |
167 | <Toggle field={form.$('minimizeToSystemTray')} /> | 190 | <Toggle field={form.$('minimizeToSystemTray')} /> |
168 | )} | 191 | )} |
192 | <Input | ||
193 | placeholder="Server" | ||
194 | onChange={e => this.submit(e)} | ||
195 | field={form.$('server')} | ||
196 | autoFocus | ||
197 | /> | ||
198 | {isLoggedIn && ( | ||
199 | <p>{ intl.formatMessage(messages.serverInfo) }</p> | ||
200 | )} | ||
201 | {server === 'https://api.franzinfra.com' && ( | ||
202 | <p | ||
203 | className="settings__message" | ||
204 | style={{ | ||
205 | borderTop: 0, marginTop: 0, paddingTop: 0, marginBottom: '2rem', | ||
206 | }} | ||
207 | > | ||
208 | <span> | ||
209 | You are using the official Franz Server for Ferdi. | ||
210 | <br /> | ||
211 | We know that Ferdi allows you to use all its features for free but you are | ||
212 | still using Franz's server resources - which Franz's creator has to pay for. | ||
213 | <br /> | ||
214 | Please still consider | ||
215 | {' '} | ||
216 | <a href="https://www.meetfranz.com/pricing" target="_blank">paying for a Franz account</a> | ||
217 | {' '} | ||
218 | or | ||
219 | {' '} | ||
220 | <a href="https://github.com/vantezzen/ferdi-server" target="_blank">using a self-hosted ferdi-server</a> | ||
221 | {' '} | ||
222 | (if you have the knowledge and resources to do so). | ||
223 | <br /> | ||
224 | By using Ferdi, you still profit greatly from Franz's recipe store, server resources and its development. | ||
225 | </span> | ||
226 | </p> | ||
227 | )} | ||
169 | {isWorkspaceEnabled && ( | 228 | {isWorkspaceEnabled && ( |
170 | <Toggle field={form.$('keepAllWorkspacesLoaded')} /> | 229 | <Toggle field={form.$('keepAllWorkspacesLoaded')} /> |
171 | )} | 230 | )} |
172 | {isTodosEnabled && ( | 231 | {isTodosEnabled && ( |
173 | <Toggle field={form.$('enableTodos')} /> | 232 | <> |
233 | <Toggle field={form.$('enableTodos')} /> | ||
234 | <Input | ||
235 | placeholder="Todo Server" | ||
236 | onChange={e => this.submit(e)} | ||
237 | field={form.$('todoServer')} | ||
238 | /> | ||
239 | <p>{ intl.formatMessage(messages.todoServerInfo) }</p> | ||
240 | </> | ||
174 | )} | 241 | )} |
175 | 242 | ||
243 | <Toggle field={form.$('lockingFeatureEnabled')} /> | ||
244 | {lockingFeatureEnabled && ( | ||
245 | <> | ||
246 | <Input | ||
247 | placeholder={intl.formatMessage(messages.lockedPassword)} | ||
248 | onChange={e => this.submit(e)} | ||
249 | field={form.$('lockedPassword')} | ||
250 | type="password" | ||
251 | /> | ||
252 | <p> | ||
253 | { intl.formatMessage(messages.lockedPasswordInfo) } | ||
254 | </p> | ||
255 | </> | ||
256 | )} | ||
257 | <p | ||
258 | className="settings__message" | ||
259 | style={{ | ||
260 | borderTop: 0, marginTop: 0, paddingTop: 0, marginBottom: '2rem', | ||
261 | }} | ||
262 | > | ||
263 | <span> | ||
264 | Ferdi password lock allows you to keep your messages protected. | ||
265 | <br /> | ||
266 | Using Ferdi password lock, you will be prompted to enter your password everytime you | ||
267 | start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut | ||
268 | {' '} | ||
269 | <code>CMD/CTRL+Shift+L</code> | ||
270 | </span> | ||
271 | </p> | ||
272 | |||
273 | |||
176 | {/* Appearance */} | 274 | {/* Appearance */} |
177 | <h2 id="apperance">{intl.formatMessage(messages.headlineAppearance)}</h2> | 275 | <h2 id="apperance">{intl.formatMessage(messages.headlineAppearance)}</h2> |
178 | <Toggle field={form.$('showDisabledServices')} /> | 276 | <Toggle field={form.$('showDisabledServices')} /> |
@@ -257,6 +355,18 @@ export default @observer class EditSettingsForm extends Component { | |||
257 | <span className="mdi mdi-information" /> | 355 | <span className="mdi mdi-information" /> |
258 | {intl.formatMessage(messages.languageDisclaimer)} | 356 | {intl.formatMessage(messages.languageDisclaimer)} |
259 | </p> | 357 | </p> |
358 | <p className="settings__message"> | ||
359 | <span className="mdi mdi-github-face" /> | ||
360 | <span> | ||
361 | Ferdi is based on | ||
362 | {' '} | ||
363 | <a href="https://github.com/meetfranz/franz" target="_blank">Franz</a> | ||
364 | , a project published | ||
365 | under the | ||
366 | {' '} | ||
367 | <a href="https://github.com/meetfranz/franz/blob/master/LICENSE" target="_blank">Apache-2.0 License</a> | ||
368 | </span> | ||
369 | </p> | ||
260 | </form> | 370 | </form> |
261 | </div> | 371 | </div> |
262 | </div> | 372 | </div> |
diff --git a/src/components/settings/team/TeamDashboard.js b/src/components/settings/team/TeamDashboard.js index 366b0113a..2bf46b48d 100644 --- a/src/components/settings/team/TeamDashboard.js +++ b/src/components/settings/team/TeamDashboard.js | |||
@@ -20,7 +20,7 @@ const messages = defineMessages({ | |||
20 | }, | 20 | }, |
21 | contentHeadline: { | 21 | contentHeadline: { |
22 | id: 'settings.team.contentHeadline', | 22 | id: 'settings.team.contentHeadline', |
23 | defaultMessage: '!!!Franz for Teams', | 23 | defaultMessage: '!!!Ferdi for Teams', |
24 | }, | 24 | }, |
25 | intro: { | 25 | intro: { |
26 | id: 'settings.team.intro', | 26 | id: 'settings.team.intro', |
@@ -28,7 +28,7 @@ const messages = defineMessages({ | |||
28 | }, | 28 | }, |
29 | copy: { | 29 | copy: { |
30 | id: 'settings.team.copy', | 30 | id: 'settings.team.copy', |
31 | defaultMessage: '!!!Franz for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!', | 31 | defaultMessage: '!!!Ferdi for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!', |
32 | }, | 32 | }, |
33 | manageButton: { | 33 | manageButton: { |
34 | id: 'settings.team.manageAction', | 34 | id: 'settings.team.manageAction', |
diff --git a/src/components/ui/ActivateTrialButton/index.js b/src/components/ui/ActivateTrialButton/index.js index e0637da90..340123c2f 100644 --- a/src/components/ui/ActivateTrialButton/index.js +++ b/src/components/ui/ActivateTrialButton/index.js | |||
@@ -5,7 +5,6 @@ import { defineMessages, intlShape } from 'react-intl'; | |||
5 | import classnames from 'classnames'; | 5 | import classnames from 'classnames'; |
6 | 6 | ||
7 | import { Button } from '@meetfranz/forms'; | 7 | import { Button } from '@meetfranz/forms'; |
8 | import { gaEvent } from '../../../lib/analytics'; | ||
9 | 8 | ||
10 | import UserStore from '../../../stores/UserStore'; | 9 | import UserStore from '../../../stores/UserStore'; |
11 | 10 | ||
@@ -63,25 +62,9 @@ class ActivateTrialButton extends Component { | |||
63 | }; | 62 | }; |
64 | 63 | ||
65 | handleCTAClick() { | 64 | handleCTAClick() { |
66 | const { actions, stores, gaEventInfo } = this.props; | 65 | const { actions } = this.props; |
67 | const { hadSubscription } = stores.user.data; | ||
68 | // const { defaultTrialPlan } = stores.features.features; | ||
69 | |||
70 | let label = ''; | ||
71 | if (!hadSubscription) { | ||
72 | // actions.user.activateTrial({ planId: defaultTrialPlan }); | ||
73 | |||
74 | label = 'Start Trial'; | ||
75 | } else { | ||
76 | label = 'Upgrade Account'; | ||
77 | } | ||
78 | 66 | ||
79 | actions.ui.openSettings({ path: 'user' }); | 67 | actions.ui.openSettings({ path: 'user' }); |
80 | |||
81 | if (gaEventInfo) { | ||
82 | const { category, event } = gaEventInfo; | ||
83 | gaEvent(category, event, label); | ||
84 | } | ||
85 | } | 68 | } |
86 | 69 | ||
87 | render() { | 70 | render() { |
diff --git a/src/components/ui/AppLoader/index.js b/src/components/ui/AppLoader/index.js index b0c7fed7b..a9a87707b 100644 --- a/src/components/ui/AppLoader/index.js +++ b/src/components/ui/AppLoader/index.js | |||
@@ -49,7 +49,7 @@ export default @injectSheet(styles) @withTheme class AppLoader extends Component | |||
49 | 49 | ||
50 | return ( | 50 | return ( |
51 | <FullscreenLoader | 51 | <FullscreenLoader |
52 | title="Franz" | 52 | title="Ferdi" |
53 | className={classes.component} | 53 | className={classes.component} |
54 | spinnerColor={theme.colorAppLoaderSpinner} | 54 | spinnerColor={theme.colorAppLoaderSpinner} |
55 | > | 55 | > |
diff --git a/src/components/ui/Button.js b/src/components/ui/Button.js index ffc7f7051..e2d7cea83 100644 --- a/src/components/ui/Button.js +++ b/src/components/ui/Button.js | |||
@@ -69,7 +69,7 @@ export default @observer class Button extends Component { | |||
69 | loaded={loaded} | 69 | loaded={loaded} |
70 | lines={10} | 70 | lines={10} |
71 | scale={0.4} | 71 | scale={0.4} |
72 | color={buttonType !== 'secondary' ? '#FFF' : '#373a3c'} | 72 | color={buttonType !== 'secondary' ? '#FFF' : '#7367F0'} |
73 | component="span" | 73 | component="span" |
74 | /> | 74 | /> |
75 | {label} | 75 | {label} |
diff --git a/src/components/ui/FullscreenLoader/styles.js b/src/components/ui/FullscreenLoader/styles.js index 64d24e4ce..d516781a8 100644 --- a/src/components/ui/FullscreenLoader/styles.js +++ b/src/components/ui/FullscreenLoader/styles.js | |||
@@ -4,6 +4,7 @@ export default { | |||
4 | alignItems: 'center', | 4 | alignItems: 'center', |
5 | position: 'absolute', | 5 | position: 'absolute', |
6 | width: '100%', | 6 | width: '100%', |
7 | background: 'linear-gradient( 135deg, #CE9FFC 10%, #7367F0 100%)', | ||
7 | }, | 8 | }, |
8 | component: { | 9 | component: { |
9 | width: '100%', | 10 | width: '100%', |
diff --git a/src/components/ui/Input.js b/src/components/ui/Input.js index 9b070c4df..4e3eb4ab8 100644 --- a/src/components/ui/Input.js +++ b/src/components/ui/Input.js | |||
@@ -68,7 +68,7 @@ export default @observer class Input extends Component { | |||
68 | 68 | ||
69 | const { passwordScore } = this.state; | 69 | const { passwordScore } = this.state; |
70 | 70 | ||
71 | let type = field.type; | 71 | let { type } = field; |
72 | if (type === 'password' && this.state.showPassword) { | 72 | if (type === 'password' && this.state.showPassword) { |
73 | type = 'text'; | 73 | type = 'text'; |
74 | } | 74 | } |
diff --git a/src/components/ui/Link.js b/src/components/ui/Link.js index b88686d5e..5f729844b 100644 --- a/src/components/ui/Link.js +++ b/src/components/ui/Link.js | |||
@@ -25,6 +25,7 @@ export default @inject('stores') @observer class Link extends Component { | |||
25 | className, | 25 | className, |
26 | activeClassName, | 26 | activeClassName, |
27 | strictFilter, | 27 | strictFilter, |
28 | style, | ||
28 | } = this.props; | 29 | } = this.props; |
29 | const { router } = stores; | 30 | const { router } = stores; |
30 | 31 | ||
@@ -44,6 +45,7 @@ export default @inject('stores') @observer class Link extends Component { | |||
44 | <a | 45 | <a |
45 | href={router.history.createHref(to)} | 46 | href={router.history.createHref(to)} |
46 | className={linkClasses} | 47 | className={linkClasses} |
48 | style={style} | ||
47 | onClick={e => this.onClick(e)} | 49 | onClick={e => this.onClick(e)} |
48 | > | 50 | > |
49 | {children} | 51 | {children} |
@@ -65,6 +67,7 @@ Link.wrappedComponent.propTypes = { | |||
65 | activeClassName: PropTypes.string, | 67 | activeClassName: PropTypes.string, |
66 | strictFilter: PropTypes.bool, | 68 | strictFilter: PropTypes.bool, |
67 | target: PropTypes.string, | 69 | target: PropTypes.string, |
70 | style: PropTypes.object, | ||
68 | }; | 71 | }; |
69 | 72 | ||
70 | Link.wrappedComponent.defaultProps = { | 73 | Link.wrappedComponent.defaultProps = { |
@@ -72,4 +75,5 @@ Link.wrappedComponent.defaultProps = { | |||
72 | activeClassName: '', | 75 | activeClassName: '', |
73 | strictFilter: false, | 76 | strictFilter: false, |
74 | target: '', | 77 | target: '', |
78 | style: {}, | ||
75 | }; | 79 | }; |
diff --git a/src/components/ui/Loader.js b/src/components/ui/Loader.js index f73296bb6..de8769b6c 100644 --- a/src/components/ui/Loader.js +++ b/src/components/ui/Loader.js | |||
@@ -16,7 +16,7 @@ export default class LoaderComponent extends Component { | |||
16 | children: null, | 16 | children: null, |
17 | loaded: false, | 17 | loaded: false, |
18 | className: '', | 18 | className: '', |
19 | color: '#373a3c', | 19 | color: '#7367F0', |
20 | }; | 20 | }; |
21 | 21 | ||
22 | render() { | 22 | render() { |
diff --git a/src/components/ui/PremiumFeatureContainer/index.js b/src/components/ui/PremiumFeatureContainer/index.js index 8d2746e22..7ba353be3 100644 --- a/src/components/ui/PremiumFeatureContainer/index.js +++ b/src/components/ui/PremiumFeatureContainer/index.js | |||
@@ -9,8 +9,7 @@ import { oneOrManyChildElements } from '../../../prop-types'; | |||
9 | import UserStore from '../../../stores/UserStore'; | 9 | import UserStore from '../../../stores/UserStore'; |
10 | 10 | ||
11 | import styles from './styles'; | 11 | import styles from './styles'; |
12 | import { gaEvent } from '../../../lib/analytics'; | 12 | import FeatureStore from '../../../stores/FeaturesStore'; |
13 | import { FeatureStore } from '../../../features/utils/FeatureStore'; | ||
14 | 13 | ||
15 | const messages = defineMessages({ | 14 | const messages = defineMessages({ |
16 | action: { | 15 | action: { |
@@ -50,7 +49,6 @@ class PremiumFeatureContainer extends Component { | |||
50 | actions, | 49 | actions, |
51 | condition, | 50 | condition, |
52 | stores, | 51 | stores, |
53 | gaEventInfo, | ||
54 | } = this.props; | 52 | } = this.props; |
55 | 53 | ||
56 | const { intl } = this.context; | 54 | const { intl } = this.context; |
@@ -75,10 +73,6 @@ class PremiumFeatureContainer extends Component { | |||
75 | type="button" | 73 | type="button" |
76 | onClick={() => { | 74 | onClick={() => { |
77 | actions.ui.openSettings({ path: 'user' }); | 75 | actions.ui.openSettings({ path: 'user' }); |
78 | if (gaEventInfo) { | ||
79 | const { category, event, label } = gaEventInfo; | ||
80 | gaEvent(category, event, label); | ||
81 | } | ||
82 | }} | 76 | }} |
83 | > | 77 | > |
84 | {intl.formatMessage(messages.action)} | 78 | {intl.formatMessage(messages.action)} |
diff --git a/src/components/ui/UpgradeButton/index.js b/src/components/ui/UpgradeButton/index.js index 73762f0bf..1b764bd90 100644 --- a/src/components/ui/UpgradeButton/index.js +++ b/src/components/ui/UpgradeButton/index.js | |||
@@ -4,7 +4,6 @@ import { inject, observer } from 'mobx-react'; | |||
4 | import { defineMessages, intlShape } from 'react-intl'; | 4 | import { defineMessages, intlShape } from 'react-intl'; |
5 | 5 | ||
6 | import { Button } from '@meetfranz/forms'; | 6 | import { Button } from '@meetfranz/forms'; |
7 | import { gaEvent } from '../../../lib/analytics'; | ||
8 | 7 | ||
9 | import UserStore from '../../../stores/UserStore'; | 8 | import UserStore from '../../../stores/UserStore'; |
10 | import ActivateTrialButton from '../ActivateTrialButton'; | 9 | import ActivateTrialButton from '../ActivateTrialButton'; |
@@ -41,13 +40,9 @@ class UpgradeButton extends Component { | |||
41 | }; | 40 | }; |
42 | 41 | ||
43 | handleCTAClick() { | 42 | handleCTAClick() { |
44 | const { actions, gaEventInfo } = this.props; | 43 | const { actions } = this.props; |
45 | 44 | ||
46 | actions.ui.openSettings({ path: 'user' }); | 45 | actions.ui.openSettings({ path: 'user' }); |
47 | if (gaEventInfo) { | ||
48 | const { category, event } = gaEventInfo; | ||
49 | gaEvent(category, event, 'Upgrade Account'); | ||
50 | } | ||
51 | } | 46 | } |
52 | 47 | ||
53 | render() { | 48 | render() { |