diff options
Diffstat (limited to 'src/components')
-rw-r--r-- | src/components/auth/Locked.js | 115 | ||||
-rw-r--r-- | src/components/layout/Sidebar.js | 27 | ||||
-rw-r--r-- | src/components/settings/settings/EditSettingsForm.js | 42 |
3 files changed, 181 insertions, 3 deletions
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/layout/Sidebar.js b/src/components/layout/Sidebar.js index 729bd35af..d26eb852d 100644 --- a/src/components/layout/Sidebar.js +++ b/src/components/layout/Sidebar.js | |||
@@ -2,7 +2,7 @@ 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 | import { Link } from 'react-router'; |
7 | 7 | ||
8 | import Tabbar from '../services/tabs/Tabbar'; | 8 | import Tabbar from '../services/tabs/Tabbar'; |
@@ -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 = ( |
@@ -107,6 +113,23 @@ export default @observer class Sidebar extends Component { | |||
107 | /> | 113 | /> |
108 | { isLoggedIn ? ( | 114 | { isLoggedIn ? ( |
109 | <> | 115 | <> |
116 | { stores.settings.all.app.lockingFeatureEnabled ? ( | ||
117 | <button | ||
118 | type="button" | ||
119 | className={`sidebar__button sidebar__button--audio ${isAppMuted ? 'is-muted' : ''}`} | ||
120 | onClick={() => { | ||
121 | actions.settings.update({ | ||
122 | type: 'app', | ||
123 | data: { | ||
124 | locked: true, | ||
125 | }, | ||
126 | }); | ||
127 | }} | ||
128 | data-tip={`${intl.formatMessage(messages.lockFerdi)} (${ctrlKey}+Shift+L)`} | ||
129 | > | ||
130 | <i className="mdi mdi-lock" /> | ||
131 | </button> | ||
132 | ) : null} | ||
110 | {todosStore.isFeatureEnabled && todosStore.isFeatureEnabledByUser ? ( | 133 | {todosStore.isFeatureEnabled && todosStore.isFeatureEnabledByUser ? ( |
111 | <button | 134 | <button |
112 | type="button" | 135 | type="button" |
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js index b4e6e08a1..0152857a6 100644 --- a/src/components/settings/settings/EditSettingsForm.js +++ b/src/components/settings/settings/EditSettingsForm.js | |||
@@ -30,6 +30,14 @@ const messages = defineMessages({ | |||
30 | id: 'settings.app.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)', | 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 | }, | 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 | }, | ||
33 | headlineLanguage: { | 41 | headlineLanguage: { |
34 | id: 'settings.app.headlineLanguage', | 42 | id: 'settings.app.headlineLanguage', |
35 | defaultMessage: '!!!Language', | 43 | defaultMessage: '!!!Language', |
@@ -159,6 +167,7 @@ export default @observer class EditSettingsForm extends Component { | |||
159 | } | 167 | } |
160 | 168 | ||
161 | const isLoggedIn = Boolean(localStorage.getItem('authToken')); | 169 | const isLoggedIn = Boolean(localStorage.getItem('authToken')); |
170 | const lockingFeatureEnabled = window.ferdi.stores.settings.all.app.lockingFeatureEnabled; | ||
162 | 171 | ||
163 | return ( | 172 | return ( |
164 | <div className="settings__main"> | 173 | <div className="settings__main"> |
@@ -205,6 +214,7 @@ export default @observer class EditSettingsForm extends Component { | |||
205 | Please still consider | 214 | Please still consider |
206 | {' '} | 215 | {' '} |
207 | <a href="https://www.meetfranz.com/pricing" target="_blank">paying for a Franz account</a> | 216 | <a href="https://www.meetfranz.com/pricing" target="_blank">paying for a Franz account</a> |
217 | {' '} | ||
208 | or | 218 | or |
209 | {' '} | 219 | {' '} |
210 | <a href="https://github.com/vantezzen/ferdi-server" target="_blank">using a self-hosted ferdi-server</a> | 220 | <a href="https://github.com/vantezzen/ferdi-server" target="_blank">using a self-hosted ferdi-server</a> |
@@ -225,12 +235,42 @@ export default @observer class EditSettingsForm extends Component { | |||
225 | placeholder="Todo Server" | 235 | placeholder="Todo Server" |
226 | onChange={e => this.submit(e)} | 236 | onChange={e => this.submit(e)} |
227 | field={form.$('todoServer')} | 237 | field={form.$('todoServer')} |
228 | autoFocus | ||
229 | /> | 238 | /> |
230 | <p>{ intl.formatMessage(messages.todoServerInfo) }</p> | 239 | <p>{ intl.formatMessage(messages.todoServerInfo) }</p> |
231 | </> | 240 | </> |
232 | )} | 241 | )} |
233 | 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 | |||
234 | {/* Appearance */} | 274 | {/* Appearance */} |
235 | <h2 id="apperance">{intl.formatMessage(messages.headlineAppearance)}</h2> | 275 | <h2 id="apperance">{intl.formatMessage(messages.headlineAppearance)}</h2> |
236 | <Toggle field={form.$('showDisabledServices')} /> | 276 | <Toggle field={form.$('showDisabledServices')} /> |