diff options
author | Dominik Guzei <dominik.guzei@gmail.com> | 2019-04-11 16:54:01 +0200 |
---|---|---|
committer | Stefan Malzner <stefan@adlk.io> | 2019-04-11 16:54:01 +0200 |
commit | 47c1c99d893517efc679ab29d675cc0bf44be8be (patch) | |
tree | 9cab9697096bef0ce56d8ee8709bc1c2c3a42deb /src/features/workspaces/components/WorkspacesDashboard.js | |
parent | test package order (diff) | |
download | ferdium-app-47c1c99d893517efc679ab29d675cc0bf44be8be.tar.gz ferdium-app-47c1c99d893517efc679ab29d675cc0bf44be8be.tar.zst ferdium-app-47c1c99d893517efc679ab29d675cc0bf44be8be.zip |
feat(App): Added Workspaces for all your daily routines 🥳
* merge default and fetched feature configs
* ignore intellij project files
* basic setup for workspaces feature
* define workspaces as premium feature
* add workspaces menu item in settings dialog
* basic setup of workspaces settings screen
* fix eslint error
* assign react key prop to workspace items
* add styles for workspace table
* setup logic to display workspace edit page
* consolidate workspace feature for further development
* prepare basic workspace edit form
* add on enter key handler for form input component
* add form for creating workspaces
* small fixes
* adds flow for deleting workspaces
* stop tracking google analytics in components
* pin gulp-sass-variables version to 1.1.1
* fix merge conflict
* fix bug in form input library
* improve workspace form setup
* finish basic workspace settings
* finish workspaces mvp
* fix eslint issues
* remove dev logs
* detach service when underlying webview unmounts
* disable no-param-reassign eslint rule
* add workspace drawer
* change workspace switch shortcuts to start with zero
* add workspace drawer toggle menu item and shortcut
* improve workspace switching ux
* style add workspace icon in drawer like the sidebar icons
* improve workspace drawer layout
* add i18n messages for service loading and workspace switching
* small fixes
* add tooltip to add workspace button in drawer
* add workspaces count badge in settings navigation
* fix merge conflicts with latest develop
* refactor state management for workspace feature
* reset api requests when workspace feature is stopped
* hide workspace feature if it is disabled
* handle get workspaces request errors in the ui
* show infobox when updating workspaces
* indicate any server interaction with spinners and infoboxes
* add analytic events for workspace actions
* improve styling of workspace switch indicator
* add workspace premium notice to dashboard
* add workspace feature info in drawer for free users
* add workspace premium badge in settings nav
* fix premium workspace badge in settings menu for light theme
* fix active workspaces settings premium badge in light theme
* give upgrade account button a bit more padding
* add open last used workspace logic
* use mobx-localstorage directly in the store
* fix wrong workspace tooltip shortcut in sidebar
* fix bug in workspace feature initialization
* show workspaces intro in drawer when user has none yet
* fix issues for users that have workspace but downgraded to free
* border radius for premium intro in workspace settings
* close workspace drawer after clicking on a workspace
* add hover effect for drawer workspace items
* ensure drawer is open on workspace settings routes
* add small text label for adding new workspace to drawer
* make workspace settings list items taller
* refactor workspace table css away from legacy styles
* render workspace service list like services + toggle
* change plus icon in workspace drawer to settings icon
* autofocus create workspace input field
* add css transition to drawer workspace item hover
* fix drawer add workspace label styles
* refactors workspace theme vars into object structure
* improve contrast of workspace switching indicator
* added generic pro badge component for settings nav
* add premium badge to workspace drawer headline
* add context menu for workspace drawer items
* handle deleted services that are attached to workspaces
Diffstat (limited to 'src/features/workspaces/components/WorkspacesDashboard.js')
-rw-r--r-- | src/features/workspaces/components/WorkspacesDashboard.js | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js new file mode 100644 index 000000000..dd4381a15 --- /dev/null +++ b/src/features/workspaces/components/WorkspacesDashboard.js | |||
@@ -0,0 +1,195 @@ | |||
1 | import React, { Component, Fragment } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; | ||
4 | import { defineMessages, intlShape } from 'react-intl'; | ||
5 | import injectSheet from 'react-jss'; | ||
6 | import { Infobox } from '@meetfranz/ui'; | ||
7 | |||
8 | import Loader from '../../../components/ui/Loader'; | ||
9 | import WorkspaceItem from './WorkspaceItem'; | ||
10 | import CreateWorkspaceForm from './CreateWorkspaceForm'; | ||
11 | import Request from '../../../stores/lib/Request'; | ||
12 | import Appear from '../../../components/ui/effects/Appear'; | ||
13 | import { workspaceStore } from '../index'; | ||
14 | import PremiumFeatureContainer from '../../../components/ui/PremiumFeatureContainer'; | ||
15 | |||
16 | const messages = defineMessages({ | ||
17 | headline: { | ||
18 | id: 'settings.workspaces.headline', | ||
19 | defaultMessage: '!!!Your workspaces', | ||
20 | }, | ||
21 | noServicesAdded: { | ||
22 | id: 'settings.workspaces.noWorkspacesAdded', | ||
23 | defaultMessage: '!!!You haven\'t added any workspaces yet.', | ||
24 | }, | ||
25 | workspacesRequestFailed: { | ||
26 | id: 'settings.workspaces.workspacesRequestFailed', | ||
27 | defaultMessage: '!!!Could not load your workspaces', | ||
28 | }, | ||
29 | tryReloadWorkspaces: { | ||
30 | id: 'settings.workspaces.tryReloadWorkspaces', | ||
31 | defaultMessage: '!!!Try again', | ||
32 | }, | ||
33 | updatedInfo: { | ||
34 | id: 'settings.workspaces.updatedInfo', | ||
35 | defaultMessage: '!!!Your changes have been saved', | ||
36 | }, | ||
37 | deletedInfo: { | ||
38 | id: 'settings.workspaces.deletedInfo', | ||
39 | defaultMessage: '!!!Workspace has been deleted', | ||
40 | }, | ||
41 | workspaceFeatureInfo: { | ||
42 | id: 'settings.workspaces.workspaceFeatureInfo', | ||
43 | defaultMessage: '!!!Info about workspace feature', | ||
44 | }, | ||
45 | workspaceFeatureHeadline: { | ||
46 | id: 'settings.workspaces.workspaceFeatureHeadline', | ||
47 | defaultMessage: '!!!Less is More: Introducing Franz Workspaces', | ||
48 | }, | ||
49 | }); | ||
50 | |||
51 | const styles = theme => ({ | ||
52 | table: { | ||
53 | width: '100%', | ||
54 | '& td': { | ||
55 | padding: '10px', | ||
56 | }, | ||
57 | }, | ||
58 | createForm: { | ||
59 | height: 'auto', | ||
60 | }, | ||
61 | appear: { | ||
62 | height: 'auto', | ||
63 | }, | ||
64 | premiumAnnouncement: { | ||
65 | padding: '20px', | ||
66 | backgroundColor: '#3498db', | ||
67 | marginLeft: '-20px', | ||
68 | marginBottom: '20px', | ||
69 | height: 'auto', | ||
70 | color: 'white', | ||
71 | borderRadius: theme.borderRadius, | ||
72 | }, | ||
73 | }); | ||
74 | |||
75 | @injectSheet(styles) @observer | ||
76 | class WorkspacesDashboard extends Component { | ||
77 | static propTypes = { | ||
78 | classes: PropTypes.object.isRequired, | ||
79 | getUserWorkspacesRequest: PropTypes.instanceOf(Request).isRequired, | ||
80 | createWorkspaceRequest: PropTypes.instanceOf(Request).isRequired, | ||
81 | deleteWorkspaceRequest: PropTypes.instanceOf(Request).isRequired, | ||
82 | updateWorkspaceRequest: PropTypes.instanceOf(Request).isRequired, | ||
83 | onCreateWorkspaceSubmit: PropTypes.func.isRequired, | ||
84 | onWorkspaceClick: PropTypes.func.isRequired, | ||
85 | workspaces: MobxPropTypes.arrayOrObservableArray.isRequired, | ||
86 | }; | ||
87 | |||
88 | static contextTypes = { | ||
89 | intl: intlShape, | ||
90 | }; | ||
91 | |||
92 | render() { | ||
93 | const { | ||
94 | classes, | ||
95 | getUserWorkspacesRequest, | ||
96 | createWorkspaceRequest, | ||
97 | deleteWorkspaceRequest, | ||
98 | updateWorkspaceRequest, | ||
99 | onCreateWorkspaceSubmit, | ||
100 | onWorkspaceClick, | ||
101 | workspaces, | ||
102 | } = this.props; | ||
103 | const { intl } = this.context; | ||
104 | return ( | ||
105 | <div className="settings__main"> | ||
106 | <div className="settings__header"> | ||
107 | <h1>{intl.formatMessage(messages.headline)}</h1> | ||
108 | </div> | ||
109 | <div className="settings__body"> | ||
110 | |||
111 | {/* ===== Workspace updated info ===== */} | ||
112 | {updateWorkspaceRequest.wasExecuted && updateWorkspaceRequest.result && ( | ||
113 | <Appear className={classes.appear}> | ||
114 | <Infobox | ||
115 | type="success" | ||
116 | icon="mdiCheckboxMarkedCircleOutline" | ||
117 | dismissable | ||
118 | onUnmount={updateWorkspaceRequest.reset} | ||
119 | > | ||
120 | {intl.formatMessage(messages.updatedInfo)} | ||
121 | </Infobox> | ||
122 | </Appear> | ||
123 | )} | ||
124 | |||
125 | {/* ===== Workspace deleted info ===== */} | ||
126 | {deleteWorkspaceRequest.wasExecuted && deleteWorkspaceRequest.result && ( | ||
127 | <Appear className={classes.appear}> | ||
128 | <Infobox | ||
129 | type="success" | ||
130 | icon="mdiCheckboxMarkedCircleOutline" | ||
131 | dismissable | ||
132 | onUnmount={deleteWorkspaceRequest.reset} | ||
133 | > | ||
134 | {intl.formatMessage(messages.deletedInfo)} | ||
135 | </Infobox> | ||
136 | </Appear> | ||
137 | )} | ||
138 | |||
139 | {workspaceStore.isPremiumUpgradeRequired && ( | ||
140 | <div className={classes.premiumAnnouncement}> | ||
141 | <h2>{intl.formatMessage(messages.workspaceFeatureHeadline)}</h2> | ||
142 | <p>{intl.formatMessage(messages.workspaceFeatureInfo)}</p> | ||
143 | </div> | ||
144 | )} | ||
145 | |||
146 | <PremiumFeatureContainer | ||
147 | condition={workspaceStore.isPremiumFeature} | ||
148 | gaEventInfo={{ category: 'User', event: 'upgrade', label: 'workspaces' }} | ||
149 | > | ||
150 | {/* ===== Create workspace form ===== */} | ||
151 | <div className={classes.createForm}> | ||
152 | <CreateWorkspaceForm | ||
153 | isSubmitting={createWorkspaceRequest.isExecuting} | ||
154 | onSubmit={onCreateWorkspaceSubmit} | ||
155 | /> | ||
156 | </div> | ||
157 | {getUserWorkspacesRequest.isExecuting ? ( | ||
158 | <Loader /> | ||
159 | ) : ( | ||
160 | <Fragment> | ||
161 | {/* ===== Workspace could not be loaded error ===== */} | ||
162 | {getUserWorkspacesRequest.error ? ( | ||
163 | <Infobox | ||
164 | icon="alert" | ||
165 | type="danger" | ||
166 | ctaLabel={intl.formatMessage(messages.tryReloadWorkspaces)} | ||
167 | ctaLoading={getUserWorkspacesRequest.isExecuting} | ||
168 | ctaOnClick={getUserWorkspacesRequest.retry} | ||
169 | > | ||
170 | {intl.formatMessage(messages.workspacesRequestFailed)} | ||
171 | </Infobox> | ||
172 | ) : ( | ||
173 | <table className={classes.table}> | ||
174 | {/* ===== Workspaces list ===== */} | ||
175 | <tbody> | ||
176 | {workspaces.map(workspace => ( | ||
177 | <WorkspaceItem | ||
178 | key={workspace.id} | ||
179 | workspace={workspace} | ||
180 | onItemClick={w => onWorkspaceClick(w)} | ||
181 | /> | ||
182 | ))} | ||
183 | </tbody> | ||
184 | </table> | ||
185 | )} | ||
186 | </Fragment> | ||
187 | )} | ||
188 | </PremiumFeatureContainer> | ||
189 | </div> | ||
190 | </div> | ||
191 | ); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | export default WorkspacesDashboard; | ||