aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/todos
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/todos')
-rw-r--r--src/features/todos/components/TodosWebview.js105
-rw-r--r--src/features/todos/containers/TodosScreen.js13
-rw-r--r--src/features/todos/store.js2
3 files changed, 100 insertions, 20 deletions
diff --git a/src/features/todos/components/TodosWebview.js b/src/features/todos/components/TodosWebview.js
index 9dd313109..143955a7b 100644
--- a/src/features/todos/components/TodosWebview.js
+++ b/src/features/todos/components/TodosWebview.js
@@ -4,12 +4,31 @@ import { observer } from 'mobx-react';
4import injectSheet from 'react-jss'; 4import injectSheet from 'react-jss';
5import Webview from 'react-electron-web-view'; 5import Webview from 'react-electron-web-view';
6import { Icon } from '@meetfranz/ui'; 6import { Icon } from '@meetfranz/ui';
7import { defineMessages, intlShape } from 'react-intl';
7 8
9import { mdiChevronRight, mdiCheckAll } from '@mdi/js';
8import * as environment from '../../../environment'; 10import * as environment from '../../../environment';
11import Appear from '../../../components/ui/effects/Appear';
12import ActivateTrialButton from '../../../components/ui/ActivateTrialButton';
9 13
10const OPEN_TODOS_BUTTON_SIZE = 45; 14const OPEN_TODOS_BUTTON_SIZE = 45;
11const CLOSE_TODOS_BUTTON_SIZE = 35; 15const CLOSE_TODOS_BUTTON_SIZE = 35;
12 16
17const messages = defineMessages({
18 premiumInfo: {
19 id: 'feature.todos.premium.info',
20 defaultMessage: '!!!The Franz Todos Preview is currently only available for Franz Premium accounts.',
21 },
22 upgradeCTA: {
23 id: 'feature.todos.premium.upgrade',
24 defaultMessage: '!!!Upgrade Account',
25 },
26 rolloutInfo: {
27 id: 'feature.todos.premium.rollout',
28 defaultMessage: '!!!Franz Todos will be available to everyone soon.',
29 },
30});
31
13const styles = theme => ({ 32const styles = theme => ({
14 root: { 33 root: {
15 background: theme.colorBackground, 34 background: theme.colorBackground,
@@ -47,7 +66,7 @@ const styles = theme => ({
47 height: OPEN_TODOS_BUTTON_SIZE, 66 height: OPEN_TODOS_BUTTON_SIZE,
48 background: theme.todos.toggleButton.background, 67 background: theme.todos.toggleButton.background,
49 position: 'absolute', 68 position: 'absolute',
50 bottom: 80, 69 bottom: 120,
51 right: props => (props.width + (props.isVisible ? -OPEN_TODOS_BUTTON_SIZE / 2 : 0)), 70 right: props => (props.width + (props.isVisible ? -OPEN_TODOS_BUTTON_SIZE / 2 : 0)),
52 borderRadius: OPEN_TODOS_BUTTON_SIZE / 2, 71 borderRadius: OPEN_TODOS_BUTTON_SIZE / 2,
53 opacity: props => (props.isVisible ? 0 : 1), 72 opacity: props => (props.isVisible ? 0 : 1),
@@ -71,10 +90,10 @@ const styles = theme => ({
71 height: CLOSE_TODOS_BUTTON_SIZE, 90 height: CLOSE_TODOS_BUTTON_SIZE,
72 background: theme.todos.toggleButton.background, 91 background: theme.todos.toggleButton.background,
73 position: 'absolute', 92 position: 'absolute',
74 bottom: 80, 93 bottom: 120,
75 right: ({ width }) => (width + -CLOSE_TODOS_BUTTON_SIZE / 2), 94 right: ({ width }) => (width + -CLOSE_TODOS_BUTTON_SIZE / 2),
76 borderRadius: CLOSE_TODOS_BUTTON_SIZE / 2, 95 borderRadius: CLOSE_TODOS_BUTTON_SIZE / 2,
77 opacity: 0, 96 opacity: ({ isTodosIncludedInCurrentPlan }) => (!isTodosIncludedInCurrentPlan ? 1 : 0),
78 transition: 'opacity 0.5s', 97 transition: 'opacity 0.5s',
79 zIndex: 600, 98 zIndex: 600,
80 display: 'flex', 99 display: 'flex',
@@ -86,6 +105,26 @@ const styles = theme => ({
86 fill: theme.todos.toggleButton.textColor, 105 fill: theme.todos.toggleButton.textColor,
87 }, 106 },
88 }, 107 },
108 premiumContainer: {
109 display: 'flex',
110 flexDirection: 'column',
111 justifyContent: 'center',
112 alignItems: 'center',
113 width: '80%',
114 maxWidth: 300,
115 margin: [-50, 'auto', 0],
116 textAlign: 'center',
117 },
118 premiumIcon: {
119 marginBottom: 40,
120 background: theme.styleTypes.primary.accent,
121 fill: theme.styleTypes.primary.contrast,
122 padding: 10,
123 borderRadius: 10,
124 },
125 premiumCTA: {
126 marginTop: 40,
127 },
89}); 128});
90 129
91@injectSheet(styles) @observer 130@injectSheet(styles) @observer
@@ -99,6 +138,7 @@ class TodosWebview extends Component {
99 resize: PropTypes.func.isRequired, 138 resize: PropTypes.func.isRequired,
100 width: PropTypes.number.isRequired, 139 width: PropTypes.number.isRequired,
101 minWidth: PropTypes.number.isRequired, 140 minWidth: PropTypes.number.isRequired,
141 isTodosIncludedInCurrentPlan: PropTypes.bool.isRequired,
102 }; 142 };
103 143
104 state = { 144 state = {
@@ -106,6 +146,10 @@ class TodosWebview extends Component {
106 width: 300, 146 width: 300,
107 }; 147 };
108 148
149 static contextTypes = {
150 intl: intlShape,
151 };
152
109 componentWillMount() { 153 componentWillMount() {
110 const { width } = this.props; 154 const { width } = this.props;
111 155
@@ -182,9 +226,19 @@ class TodosWebview extends Component {
182 226
183 render() { 227 render() {
184 const { 228 const {
185 classes, isVisible, togglePanel, 229 classes,
230 isVisible,
231 togglePanel,
232 isTodosIncludedInCurrentPlan,
186 } = this.props; 233 } = this.props;
187 const { width, delta, isDragging } = this.state; 234
235 const {
236 width,
237 delta,
238 isDragging,
239 } = this.state;
240
241 const { intl } = this.context;
188 242
189 return ( 243 return (
190 <div 244 <div
@@ -198,7 +252,7 @@ class TodosWebview extends Component {
198 className={isVisible ? classes.closeTodosButton : classes.openTodosButton} 252 className={isVisible ? classes.closeTodosButton : classes.openTodosButton}
199 type="button" 253 type="button"
200 > 254 >
201 <Icon icon={isVisible ? 'mdiChevronRight' : 'mdiCheckAll'} size={2} /> 255 <Icon icon={isVisible ? mdiChevronRight : mdiCheckAll} size={2} />
202 </button> 256 </button>
203 <div 257 <div
204 className={classes.resizeHandler} 258 className={classes.resizeHandler}
@@ -211,18 +265,33 @@ class TodosWebview extends Component {
211 style={{ left: delta }} // This hack is required as resizing with webviews beneath behaves quite bad 265 style={{ left: delta }} // This hack is required as resizing with webviews beneath behaves quite bad
212 /> 266 />
213 )} 267 )}
214 <Webview 268 {isTodosIncludedInCurrentPlan ? (
215 className={classes.webview} 269 <Webview
216 onDidAttach={() => { 270 className={classes.webview}
217 const { setTodosWebview } = this.props; 271 onDidAttach={() => {
218 setTodosWebview(this.webview); 272 const { setTodosWebview } = this.props;
219 this.startListeningToIpcMessages(); 273 setTodosWebview(this.webview);
220 }} 274 this.startListeningToIpcMessages();
221 partition="persist:todos" 275 }}
222 preload="./features/todos/preload.js" 276 partition="persist:todos"
223 ref={(webview) => { this.webview = webview ? webview.view : null; }} 277 preload="./features/todos/preload.js"
224 src={environment.TODOS_FRONTEND} 278 ref={(webview) => { this.webview = webview ? webview.view : null; }}
225 /> 279 src={environment.TODOS_FRONTEND}
280 />
281 ) : (
282 <Appear>
283 <div className={classes.premiumContainer}>
284 <Icon icon={mdiCheckAll} className={classes.premiumIcon} size={5} />
285 <p>{intl.formatMessage(messages.premiumInfo)}</p>
286 <p>{intl.formatMessage(messages.rolloutInfo)}</p>
287 <ActivateTrialButton
288 className={classes.premiumCTA}
289 gaEventInfo={{ category: 'Todos', event: 'upgrade' }}
290 short
291 />
292 </div>
293 </Appear>
294 )}
226 </div> 295 </div>
227 ); 296 );
228 } 297 }
diff --git a/src/features/todos/containers/TodosScreen.js b/src/features/todos/containers/TodosScreen.js
index d071d0677..65afc985b 100644
--- a/src/features/todos/containers/TodosScreen.js
+++ b/src/features/todos/containers/TodosScreen.js
@@ -1,12 +1,14 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import { observer } from 'mobx-react'; 2import { observer, inject } from 'mobx-react';
3import PropTypes from 'prop-types';
3 4
5import FeaturesStore from '../../../stores/FeaturesStore';
4import TodosWebview from '../components/TodosWebview'; 6import TodosWebview from '../components/TodosWebview';
5import ErrorBoundary from '../../../components/util/ErrorBoundary'; 7import ErrorBoundary from '../../../components/util/ErrorBoundary';
6import { TODOS_MIN_WIDTH, todosStore } from '..'; 8import { TODOS_MIN_WIDTH, todosStore } from '..';
7import { todoActions } from '../actions'; 9import { todoActions } from '../actions';
8 10
9@observer 11@inject('stores', 'actions') @observer
10class TodosScreen extends Component { 12class TodosScreen extends Component {
11 render() { 13 render() {
12 if (!todosStore || !todosStore.isFeatureActive) { 14 if (!todosStore || !todosStore.isFeatureActive) {
@@ -23,6 +25,7 @@ class TodosScreen extends Component {
23 width={todosStore.width} 25 width={todosStore.width}
24 minWidth={TODOS_MIN_WIDTH} 26 minWidth={TODOS_MIN_WIDTH}
25 resize={width => todoActions.resize({ width })} 27 resize={width => todoActions.resize({ width })}
28 isTodosIncludedInCurrentPlan={this.props.stores.features.features.isTodosIncludedInCurrentPlan || false}
26 /> 29 />
27 </ErrorBoundary> 30 </ErrorBoundary>
28 ); 31 );
@@ -30,3 +33,9 @@ class TodosScreen extends Component {
30} 33}
31 34
32export default TodosScreen; 35export default TodosScreen;
36
37TodosScreen.wrappedComponent.propTypes = {
38 stores: PropTypes.shape({
39 features: PropTypes.instanceOf(FeaturesStore).isRequired,
40 }).isRequired,
41};
diff --git a/src/features/todos/store.js b/src/features/todos/store.js
index 242b38bf7..170408ebb 100644
--- a/src/features/todos/store.js
+++ b/src/features/todos/store.js
@@ -12,6 +12,7 @@ import { createReactions } from '../../stores/lib/Reaction';
12import { createActionBindings } from '../utils/ActionBinding'; 12import { createActionBindings } from '../utils/ActionBinding';
13import { DEFAULT_TODOS_WIDTH, TODOS_MIN_WIDTH, DEFAULT_TODOS_VISIBLE } from '.'; 13import { DEFAULT_TODOS_WIDTH, TODOS_MIN_WIDTH, DEFAULT_TODOS_VISIBLE } from '.';
14import { IPC } from './constants'; 14import { IPC } from './constants';
15import { state as delayAppState } from '../delayApp';
15 16
16const debug = require('debug')('Franz:feature:todos:store'); 17const debug = require('debug')('Franz:feature:todos:store');
17 18
@@ -29,6 +30,7 @@ export default class TodoStore extends FeatureStore {
29 } 30 }
30 31
31 @computed get isTodosPanelVisible() { 32 @computed get isTodosPanelVisible() {
33 if (this.stores.services.all.length === 0 || delayAppState.isDelayAppScreenVisible) return false;
32 if (this.settings.isTodosPanelVisible === undefined) return DEFAULT_TODOS_VISIBLE; 34 if (this.settings.isTodosPanelVisible === undefined) return DEFAULT_TODOS_VISIBLE;
33 35
34 return this.settings.isTodosPanelVisible; 36 return this.settings.isTodosPanelVisible;