aboutsummaryrefslogtreecommitdiffstats
path: root/src/features
diff options
context:
space:
mode:
authorLibravatar Stefan Malzner <stefan@adlk.io>2019-09-05 09:49:25 +0200
committerLibravatar Stefan Malzner <stefan@adlk.io>2019-09-05 09:49:25 +0200
commit24d0223fee38c36ec19d9c662579dba7d787f8b4 (patch)
tree17a50e725cef1266506fc9ac6352c15a120cba78 /src/features
parentdon't warn on react/destructuring-assignment (diff)
downloadferdium-app-24d0223fee38c36ec19d9c662579dba7d787f8b4.tar.gz
ferdium-app-24d0223fee38c36ec19d9c662579dba7d787f8b4.tar.zst
ferdium-app-24d0223fee38c36ec19d9c662579dba7d787f8b4.zip
polishing
Diffstat (limited to 'src/features')
-rw-r--r--src/features/todos/components/TodosWebview.js8
-rw-r--r--src/features/todos/store.js18
-rw-r--r--src/features/workspaces/components/WorkspacesDashboard.js167
-rw-r--r--src/features/workspaces/containers/WorkspacesScreen.js13
4 files changed, 119 insertions, 87 deletions
diff --git a/src/features/todos/components/TodosWebview.js b/src/features/todos/components/TodosWebview.js
index 9a50f7e8d..fa530daed 100644
--- a/src/features/todos/components/TodosWebview.js
+++ b/src/features/todos/components/TodosWebview.js
@@ -9,7 +9,7 @@ import { defineMessages, intlShape } from 'react-intl';
9import { mdiChevronRight, mdiCheckAll } from '@mdi/js'; 9import { mdiChevronRight, mdiCheckAll } from '@mdi/js';
10import * as environment from '../../../environment'; 10import * as environment from '../../../environment';
11import Appear from '../../../components/ui/effects/Appear'; 11import Appear from '../../../components/ui/effects/Appear';
12import ActivateTrialButton from '../../../components/ui/ActivateTrialButton'; 12import UpgradeButton from '../../../components/ui/UpgradeButton';
13 13
14const OPEN_TODOS_BUTTON_SIZE = 45; 14const OPEN_TODOS_BUTTON_SIZE = 45;
15const CLOSE_TODOS_BUTTON_SIZE = 35; 15const CLOSE_TODOS_BUTTON_SIZE = 35;
@@ -116,7 +116,7 @@ const styles = theme => ({
116 alignItems: 'center', 116 alignItems: 'center',
117 width: '80%', 117 width: '80%',
118 maxWidth: 300, 118 maxWidth: 300,
119 margin: [-50, 'auto', 0], 119 margin: [0, 'auto'],
120 textAlign: 'center', 120 textAlign: 'center',
121 }, 121 },
122 premiumIcon: { 122 premiumIcon: {
@@ -286,10 +286,10 @@ class TodosWebview extends Component {
286 ) : ( 286 ) : (
287 <Appear> 287 <Appear>
288 <div className={classes.premiumContainer}> 288 <div className={classes.premiumContainer}>
289 <Icon icon={mdiCheckAll} className={classes.premiumIcon} size={5} /> 289 <Icon icon={mdiCheckAll} className={classes.premiumIcon} size={4} />
290 <p>{intl.formatMessage(messages.premiumInfo)}</p> 290 <p>{intl.formatMessage(messages.premiumInfo)}</p>
291 <p>{intl.formatMessage(messages.rolloutInfo)}</p> 291 <p>{intl.formatMessage(messages.rolloutInfo)}</p>
292 <ActivateTrialButton 292 <UpgradeButton
293 className={classes.premiumCTA} 293 className={classes.premiumCTA}
294 gaEventInfo={{ category: 'Todos', event: 'upgrade' }} 294 gaEventInfo={{ category: 'Todos', event: 'upgrade' }}
295 short 295 short
diff --git a/src/features/todos/store.js b/src/features/todos/store.js
index 56e117c6c..5c6abff4c 100644
--- a/src/features/todos/store.js
+++ b/src/features/todos/store.js
@@ -30,7 +30,7 @@ export default class TodoStore extends FeatureStore {
30 } 30 }
31 31
32 @computed get isTodosPanelVisible() { 32 @computed get isTodosPanelVisible() {
33 if (this.stores.services.all.length === 0 || delayAppState.isDelayAppScreenVisible) return false; 33 if (delayAppState.isDelayAppScreenVisible) return false;
34 if (this.settings.isTodosPanelVisible === undefined) return DEFAULT_TODOS_VISIBLE; 34 if (this.settings.isTodosPanelVisible === undefined) return DEFAULT_TODOS_VISIBLE;
35 35
36 return this.settings.isTodosPanelVisible; 36 return this.settings.isTodosPanelVisible;
@@ -61,6 +61,7 @@ export default class TodoStore extends FeatureStore {
61 61
62 this._allReactions = createReactions([ 62 this._allReactions = createReactions([
63 this._setFeatureEnabledReaction, 63 this._setFeatureEnabledReaction,
64 this._firstLaunchReaction,
64 ]); 65 ]);
65 66
66 this._registerReactions(this._allReactions); 67 this._registerReactions(this._allReactions);
@@ -146,4 +147,19 @@ export default class TodoStore extends FeatureStore {
146 147
147 this.isFeatureEnabled = isTodosEnabled; 148 this.isFeatureEnabled = isTodosEnabled;
148 }; 149 };
150
151 _firstLaunchReaction = () => {
152 const { stats } = this.stores.settings.all;
153
154 // Hide todos layer on first app start but show on second
155 if (stats.appStarts <= 1) {
156 this._updateSettings({
157 isTodosPanelVisible: false,
158 });
159 } else if (stats.appStarts <= 2) {
160 this._updateSettings({
161 isTodosPanelVisible: true,
162 });
163 }
164 };
149} 165}
diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js
index 059a681de..fc636dd95 100644
--- a/src/features/workspaces/components/WorkspacesDashboard.js
+++ b/src/features/workspaces/components/WorkspacesDashboard.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes, inject } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes, inject } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, intlShape } from 'react-intl';
5import injectSheet from 'react-jss'; 5import injectSheet from 'react-jss';
6import { Infobox } from '@meetfranz/ui'; 6import { Infobox, Badge } from '@meetfranz/ui';
7 7
8import Loader from '../../../components/ui/Loader'; 8import Loader from '../../../components/ui/Loader';
9import WorkspaceItem from './WorkspaceItem'; 9import WorkspaceItem from './WorkspaceItem';
@@ -11,9 +11,9 @@ import CreateWorkspaceForm from './CreateWorkspaceForm';
11import Request from '../../../stores/lib/Request'; 11import Request from '../../../stores/lib/Request';
12import Appear from '../../../components/ui/effects/Appear'; 12import Appear from '../../../components/ui/effects/Appear';
13import { workspaceStore } from '../index'; 13import { workspaceStore } from '../index';
14import PremiumFeatureContainer from '../../../components/ui/PremiumFeatureContainer';
15import UIStore from '../../../stores/UIStore'; 14import UIStore from '../../../stores/UIStore';
16import ActivateTrialButton from '../../../components/ui/ActivateTrialButton'; 15import globalMessages from '../../../i18n/globalMessages';
16import UpgradeButton from '../../../components/ui/UpgradeButton';
17 17
18const messages = defineMessages({ 18const messages = defineMessages({
19 headline: { 19 headline: {
@@ -64,23 +64,24 @@ const styles = theme => ({
64 height: 'auto', 64 height: 'auto',
65 }, 65 },
66 premiumAnnouncement: { 66 premiumAnnouncement: {
67 padding: 20,
68 // backgroundColor: '#3498db',
69 marginLeft: -20,
70 marginBottom: 40,
71 paddingBottom: 40,
72 height: 'auto', 67 height: 'auto',
68 },
69 premiumAnnouncementContainer: {
73 display: 'flex', 70 display: 'flex',
74 borderBottom: [1, 'solid', theme.inputBackground], 71 },
72 announcementHeadline: {
73 marginBottom: 0,
75 }, 74 },
76 teaserImage: { 75 teaserImage: {
77 width: 200, 76 width: 250,
78 height: '100%', 77 margin: [-8, 0, 0, 20],
79 float: 'left', 78 alignSelf: 'center',
80 margin: [-8, 0, 0, -20],
81 }, 79 },
82 upgradeCTA: { 80 upgradeCTA: {
83 marginTop: 20, 81 margin: [40, 'auto'],
82 },
83 proRequired: {
84 margin: [10, 0, 40],
84 }, 85 },
85}); 86});
86 87
@@ -95,6 +96,8 @@ class WorkspacesDashboard extends Component {
95 onCreateWorkspaceSubmit: PropTypes.func.isRequired, 96 onCreateWorkspaceSubmit: PropTypes.func.isRequired,
96 onWorkspaceClick: PropTypes.func.isRequired, 97 onWorkspaceClick: PropTypes.func.isRequired,
97 workspaces: MobxPropTypes.arrayOrObservableArray.isRequired, 98 workspaces: MobxPropTypes.arrayOrObservableArray.isRequired,
99 isPersonalUser: PropTypes.bool.isRequired,
100 onUpgradeAccount: PropTypes.func.isRequired,
98 }; 101 };
99 102
100 static contextTypes = { 103 static contextTypes = {
@@ -152,76 +155,80 @@ class WorkspacesDashboard extends Component {
152 155
153 {workspaceStore.isPremiumUpgradeRequired && ( 156 {workspaceStore.isPremiumUpgradeRequired && (
154 <div className={classes.premiumAnnouncement}> 157 <div className={classes.premiumAnnouncement}>
155 <img src={`./assets/images/workspaces/teaser_${this.props.stores.ui.isDarkThemeActive ? 'dark' : 'light'}.png`} className={classes.teaserImage} alt="" /> 158
156 <div> 159 <h1 className={classes.announcementHeadline}>{intl.formatMessage(messages.workspaceFeatureHeadline)}</h1>
157 <h2>{intl.formatMessage(messages.workspaceFeatureHeadline)}</h2> 160 <Badge className={classes.proRequired}>{intl.formatMessage(globalMessages.proRequired)}</Badge>
158 <p>{intl.formatMessage(messages.workspaceFeatureInfo)}</p> 161 <div className={classes.premiumAnnouncementContainer}>
159 <ActivateTrialButton 162 <div className={classes.premiumAnnouncementContent}>
160 className={classes.upgradeCTA} 163 <p>{intl.formatMessage(messages.workspaceFeatureInfo)}</p>
161 gaEventInfo={{ category: 'Workspaces', event: 'upgrade' }} 164 <UpgradeButton
162 short 165 className={classes.upgradeCTA}
163 /> 166 gaEventInfo={{ category: 'Workspaces', event: 'upgrade' }}
167 short
168 requiresPro
169 />
170 </div>
171 <img src={`https://cdn.franzinfra.com/announcements/assets/workspaces_${this.props.stores.ui.isDarkThemeActive ? 'dark' : 'light'}.png`} className={classes.teaserImage} alt="" />
164 </div> 172 </div>
165 </div> 173 </div>
166 )} 174 )}
167 175
168 <PremiumFeatureContainer 176 {!workspaceStore.isPremiumUpgradeRequired && (
169 condition={() => workspaceStore.isPremiumUpgradeRequired} 177 <>
170 gaEventInfo={{ category: 'User', event: 'upgrade', label: 'workspaces' }} 178 {/* ===== Create workspace form ===== */}
171 > 179 <div className={classes.createForm}>
172 {/* ===== Create workspace form ===== */} 180 <CreateWorkspaceForm
173 <div className={classes.createForm}> 181 isSubmitting={createWorkspaceRequest.isExecuting}
174 <CreateWorkspaceForm 182 onSubmit={onCreateWorkspaceSubmit}
175 isSubmitting={createWorkspaceRequest.isExecuting} 183 />
176 onSubmit={onCreateWorkspaceSubmit} 184 </div>
177 /> 185 {getUserWorkspacesRequest.isExecuting ? (
178 </div> 186 <Loader />
179 {getUserWorkspacesRequest.isExecuting ? ( 187 ) : (
180 <Loader /> 188 <Fragment>
181 ) : ( 189 {/* ===== Workspace could not be loaded error ===== */}
182 <Fragment> 190 {getUserWorkspacesRequest.error ? (
183 {/* ===== Workspace could not be loaded error ===== */} 191 <Infobox
184 {getUserWorkspacesRequest.error ? ( 192 icon="alert"
185 <Infobox 193 type="danger"
186 icon="alert" 194 ctaLabel={intl.formatMessage(messages.tryReloadWorkspaces)}
187 type="danger" 195 ctaLoading={getUserWorkspacesRequest.isExecuting}
188 ctaLabel={intl.formatMessage(messages.tryReloadWorkspaces)} 196 ctaOnClick={getUserWorkspacesRequest.retry}
189 ctaLoading={getUserWorkspacesRequest.isExecuting} 197 >
190 ctaOnClick={getUserWorkspacesRequest.retry} 198 {intl.formatMessage(messages.workspacesRequestFailed)}
191 > 199 </Infobox>
192 {intl.formatMessage(messages.workspacesRequestFailed)} 200 ) : (
193 </Infobox> 201 <Fragment>
194 ) : ( 202 {workspaces.length === 0 ? (
195 <Fragment> 203 <div className="align-middle settings__empty-state">
196 {workspaces.length === 0 ? ( 204 {/* ===== Workspaces empty state ===== */}
197 <div className="align-middle settings__empty-state"> 205 <p className="settings__empty-text">
198 {/* ===== Workspaces empty state ===== */} 206 <span className="emoji">
199 <p className="settings__empty-text"> 207 <img src="./assets/images/emoji/sad.png" alt="" />
200 <span className="emoji"> 208 </span>
201 <img src="./assets/images/emoji/sad.png" alt="" /> 209 {intl.formatMessage(messages.noServicesAdded)}
202 </span> 210 </p>
203 {intl.formatMessage(messages.noServicesAdded)} 211 </div>
204 </p> 212 ) : (
205 </div> 213 <table className={classes.table}>
206 ) : ( 214 {/* ===== Workspaces list ===== */}
207 <table className={classes.table}> 215 <tbody>
208 {/* ===== Workspaces list ===== */} 216 {workspaces.map(workspace => (
209 <tbody> 217 <WorkspaceItem
210 {workspaces.map(workspace => ( 218 key={workspace.id}
211 <WorkspaceItem 219 workspace={workspace}
212 key={workspace.id} 220 onItemClick={w => onWorkspaceClick(w)}
213 workspace={workspace} 221 />
214 onItemClick={w => onWorkspaceClick(w)} 222 ))}
215 /> 223 </tbody>
216 ))} 224 </table>
217 </tbody> 225 )}
218 </table> 226 </Fragment>
219 )} 227 )}
220 </Fragment> 228 </Fragment>
221 )} 229 )}
222 </Fragment> 230 </>
223 )} 231 )}
224 </PremiumFeatureContainer>
225 </div> 232 </div>
226 </div> 233 </div>
227 ); 234 );
diff --git a/src/features/workspaces/containers/WorkspacesScreen.js b/src/features/workspaces/containers/WorkspacesScreen.js
index 2ab565fa1..5fbb0c31d 100644
--- a/src/features/workspaces/containers/WorkspacesScreen.js
+++ b/src/features/workspaces/containers/WorkspacesScreen.js
@@ -10,29 +10,38 @@ import {
10 getUserWorkspacesRequest, 10 getUserWorkspacesRequest,
11 updateWorkspaceRequest, 11 updateWorkspaceRequest,
12} from '../api'; 12} from '../api';
13import UserStore from '../../../stores/UserStore';
13 14
14@inject('actions') @observer 15@inject('stores', 'actions') @observer
15class WorkspacesScreen extends Component { 16class WorkspacesScreen extends Component {
16 static propTypes = { 17 static propTypes = {
18 stores: PropTypes.shape({
19 user: PropTypes.instanceOf(UserStore),
20 }).isRequired,
17 actions: PropTypes.shape({ 21 actions: PropTypes.shape({
18 workspace: PropTypes.shape({ 22 workspace: PropTypes.shape({
19 edit: PropTypes.func.isRequired, 23 edit: PropTypes.func.isRequired,
20 }), 24 }),
25 ui: PropTypes.shape({
26 openSettings: PropTypes.func.isRequired,
27 }),
21 }).isRequired, 28 }).isRequired,
22 }; 29 };
23 30
24 render() { 31 render() {
25 const { actions } = this.props; 32 const { stores, actions } = this.props;
26 return ( 33 return (
27 <ErrorBoundary> 34 <ErrorBoundary>
28 <WorkspacesDashboard 35 <WorkspacesDashboard
29 workspaces={workspaceStore.workspaces} 36 workspaces={workspaceStore.workspaces}
37 isPersonalUser={stores.user.isPersonal}
30 getUserWorkspacesRequest={getUserWorkspacesRequest} 38 getUserWorkspacesRequest={getUserWorkspacesRequest}
31 createWorkspaceRequest={createWorkspaceRequest} 39 createWorkspaceRequest={createWorkspaceRequest}
32 deleteWorkspaceRequest={deleteWorkspaceRequest} 40 deleteWorkspaceRequest={deleteWorkspaceRequest}
33 updateWorkspaceRequest={updateWorkspaceRequest} 41 updateWorkspaceRequest={updateWorkspaceRequest}
34 onCreateWorkspaceSubmit={data => actions.workspaces.create(data)} 42 onCreateWorkspaceSubmit={data => actions.workspaces.create(data)}
35 onWorkspaceClick={w => actions.workspaces.edit({ workspace: w })} 43 onWorkspaceClick={w => actions.workspaces.edit({ workspace: w })}
44 onUpgradeAccount={() => actions.ui.openSettings({ path: 'user' })}
36 /> 45 />
37 </ErrorBoundary> 46 </ErrorBoundary>
38 ); 47 );