diff options
Diffstat (limited to 'src/features/todos/store.js')
-rw-r--r-- | src/features/todos/store.js | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/src/features/todos/store.js b/src/features/todos/store.js new file mode 100644 index 000000000..05eef4ec1 --- /dev/null +++ b/src/features/todos/store.js | |||
@@ -0,0 +1,213 @@ | |||
1 | import { ThemeType } from '@meetfranz/theme'; | ||
2 | import { | ||
3 | computed, | ||
4 | action, | ||
5 | observable, | ||
6 | } from 'mobx'; | ||
7 | import localStorage from 'mobx-localstorage'; | ||
8 | |||
9 | import { todoActions } from './actions'; | ||
10 | import { FeatureStore } from '../utils/FeatureStore'; | ||
11 | import { createReactions } from '../../stores/lib/Reaction'; | ||
12 | import { createActionBindings } from '../utils/ActionBinding'; | ||
13 | import { | ||
14 | DEFAULT_TODOS_WIDTH, TODOS_MIN_WIDTH, DEFAULT_TODOS_VISIBLE, TODOS_ROUTES, DEFAULT_IS_FEATURE_ENABLED_BY_USER, | ||
15 | } from '.'; | ||
16 | import { IPC } from './constants'; | ||
17 | import { state as delayAppState } from '../delayApp'; | ||
18 | |||
19 | const debug = require('debug')('Franz:feature:todos:store'); | ||
20 | |||
21 | export default class TodoStore extends FeatureStore { | ||
22 | @observable isFeatureEnabled = false; | ||
23 | |||
24 | @observable isFeatureActive = false; | ||
25 | |||
26 | webview = null; | ||
27 | |||
28 | @computed get width() { | ||
29 | const width = this.settings.width || DEFAULT_TODOS_WIDTH; | ||
30 | |||
31 | return width < TODOS_MIN_WIDTH ? TODOS_MIN_WIDTH : width; | ||
32 | } | ||
33 | |||
34 | @computed get isTodosPanelForceHidden() { | ||
35 | const { isAnnouncementShown } = this.stores.announcements; | ||
36 | return delayAppState.isDelayAppScreenVisible || !this.settings.isFeatureEnabledByUser || isAnnouncementShown; | ||
37 | } | ||
38 | |||
39 | @computed get isTodosPanelVisible() { | ||
40 | if (this.settings.isTodosPanelVisible === undefined) return DEFAULT_TODOS_VISIBLE; | ||
41 | return this.settings.isTodosPanelVisible; | ||
42 | } | ||
43 | |||
44 | @computed get settings() { | ||
45 | return localStorage.getItem('todos') || {}; | ||
46 | } | ||
47 | |||
48 | // ========== PUBLIC API ========= // | ||
49 | |||
50 | @action start(stores, actions) { | ||
51 | debug('TodoStore::start'); | ||
52 | this.stores = stores; | ||
53 | this.actions = actions; | ||
54 | |||
55 | // ACTIONS | ||
56 | |||
57 | this._registerActions(createActionBindings([ | ||
58 | [todoActions.resize, this._resize], | ||
59 | [todoActions.toggleTodosPanel, this._toggleTodosPanel], | ||
60 | [todoActions.setTodosWebview, this._setTodosWebview], | ||
61 | [todoActions.handleHostMessage, this._handleHostMessage], | ||
62 | [todoActions.handleClientMessage, this._handleClientMessage], | ||
63 | [todoActions.toggleTodosFeatureVisibility, this._toggleTodosFeatureVisibility], | ||
64 | ])); | ||
65 | |||
66 | // REACTIONS | ||
67 | |||
68 | this._allReactions = createReactions([ | ||
69 | this._setFeatureEnabledReaction, | ||
70 | this._updateTodosConfig, | ||
71 | this._firstLaunchReaction, | ||
72 | this._routeCheckReaction, | ||
73 | ]); | ||
74 | |||
75 | this._registerReactions(this._allReactions); | ||
76 | |||
77 | this.isFeatureActive = true; | ||
78 | |||
79 | if (this.settings.isFeatureEnabledByUser === undefined) { | ||
80 | this._updateSettings({ | ||
81 | isFeatureEnabledByUser: DEFAULT_IS_FEATURE_ENABLED_BY_USER, | ||
82 | }); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | @action stop() { | ||
87 | super.stop(); | ||
88 | debug('TodoStore::stop'); | ||
89 | this.reset(); | ||
90 | this.isFeatureActive = false; | ||
91 | } | ||
92 | |||
93 | // ========== PRIVATE METHODS ========= // | ||
94 | |||
95 | _updateSettings = (changes) => { | ||
96 | localStorage.setItem('todos', { | ||
97 | ...this.settings, | ||
98 | ...changes, | ||
99 | }); | ||
100 | }; | ||
101 | |||
102 | // Actions | ||
103 | |||
104 | @action _resize = ({ width }) => { | ||
105 | this._updateSettings({ | ||
106 | width, | ||
107 | }); | ||
108 | }; | ||
109 | |||
110 | @action _toggleTodosPanel = () => { | ||
111 | this._updateSettings({ | ||
112 | isTodosPanelVisible: !this.isTodosPanelVisible, | ||
113 | }); | ||
114 | }; | ||
115 | |||
116 | @action _setTodosWebview = ({ webview }) => { | ||
117 | debug('_setTodosWebview', webview); | ||
118 | this.webview = webview; | ||
119 | }; | ||
120 | |||
121 | @action _handleHostMessage = (message) => { | ||
122 | debug('_handleHostMessage', message); | ||
123 | if (message.action === 'todos:create') { | ||
124 | this.webview.send(IPC.TODOS_HOST_CHANNEL, message); | ||
125 | } | ||
126 | }; | ||
127 | |||
128 | @action _handleClientMessage = (message) => { | ||
129 | debug('_handleClientMessage', message); | ||
130 | switch (message.action) { | ||
131 | case 'todos:initialized': this._onTodosClientInitialized(); break; | ||
132 | case 'todos:goToService': this._goToService(message.data); break; | ||
133 | default: | ||
134 | debug('Unknown client message reiceived', message); | ||
135 | } | ||
136 | }; | ||
137 | |||
138 | @action _toggleTodosFeatureVisibility = () => { | ||
139 | debug('_toggleTodosFeatureVisibility'); | ||
140 | |||
141 | this._updateSettings({ | ||
142 | isFeatureEnabledByUser: !this.settings.isFeatureEnabledByUser, | ||
143 | }); | ||
144 | }; | ||
145 | |||
146 | // Todos client message handlers | ||
147 | |||
148 | _onTodosClientInitialized = () => { | ||
149 | const { authToken } = this.stores.user; | ||
150 | const { isDarkThemeActive } = this.stores.ui; | ||
151 | const { locale } = this.stores.app; | ||
152 | if (!this.webview) return; | ||
153 | this.webview.send(IPC.TODOS_HOST_CHANNEL, { | ||
154 | action: 'todos:configure', | ||
155 | data: { | ||
156 | authToken, | ||
157 | locale, | ||
158 | theme: isDarkThemeActive ? ThemeType.dark : ThemeType.default, | ||
159 | }, | ||
160 | }); | ||
161 | }; | ||
162 | |||
163 | _goToService = ({ url, serviceId }) => { | ||
164 | if (url) { | ||
165 | this.stores.services.one(serviceId).webview.loadURL(url); | ||
166 | } | ||
167 | this.actions.service.setActive({ serviceId }); | ||
168 | }; | ||
169 | |||
170 | // Reactions | ||
171 | |||
172 | _setFeatureEnabledReaction = () => { | ||
173 | const { isTodosEnabled } = this.stores.features.features; | ||
174 | |||
175 | this.isFeatureEnabled = isTodosEnabled; | ||
176 | }; | ||
177 | |||
178 | _updateTodosConfig = () => { | ||
179 | // Resend the config if any part changes in Franz: | ||
180 | this._onTodosClientInitialized(); | ||
181 | }; | ||
182 | |||
183 | _firstLaunchReaction = () => { | ||
184 | const { stats } = this.stores.settings.all; | ||
185 | |||
186 | // Hide todos layer on first app start but show on second | ||
187 | if (stats.appStarts <= 1) { | ||
188 | this._updateSettings({ | ||
189 | isTodosPanelVisible: false, | ||
190 | }); | ||
191 | } else if (stats.appStarts <= 2) { | ||
192 | this._updateSettings({ | ||
193 | isTodosPanelVisible: true, | ||
194 | }); | ||
195 | } | ||
196 | }; | ||
197 | |||
198 | _routeCheckReaction = () => { | ||
199 | const { pathname } = this.stores.router.location; | ||
200 | |||
201 | if (pathname === TODOS_ROUTES.TARGET) { | ||
202 | debug('Router is on todos route, show todos panel'); | ||
203 | // todosStore.start(stores, actions); | ||
204 | this.stores.router.push('/'); | ||
205 | |||
206 | if (!this.isTodosPanelVisible) { | ||
207 | this._updateSettings({ | ||
208 | isTodosPanelVisible: true, | ||
209 | }); | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | } | ||