aboutsummaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/auth/Locked.js115
-rw-r--r--src/components/layout/Sidebar.js27
-rw-r--r--src/components/settings/settings/EditSettingsForm.js42
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 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
5
6import Form from '../../lib/Form';
7import { required } from '../../helpers/validation-helpers';
8import Input from '../ui/Input';
9import Button from '../ui/Button';
10import Infobox from '../ui/Infobox';
11
12import { globalError as globalErrorPropType } from '../../prop-types';
13
14const 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
37export 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';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import ReactTooltip from 'react-tooltip'; 3import ReactTooltip from 'react-tooltip';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, intlShape } from 'react-intl';
5import { observer } from 'mobx-react'; 5import { inject, observer } from 'mobx-react';
6import { Link } from 'react-router'; 6import { Link } from 'react-router';
7 7
8import Tabbar from '../services/tabs/Tabbar'; 8import 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
49export default @observer class Sidebar extends Component { 53export 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')} />