aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/workspaces/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/workspaces/components')
-rw-r--r--src/features/workspaces/components/CreateWorkspaceForm.js93
-rw-r--r--src/features/workspaces/components/EditWorkspaceForm.js192
-rw-r--r--src/features/workspaces/components/ServiceListItem.js48
-rw-r--r--src/features/workspaces/components/WorkspaceItem.js42
-rw-r--r--src/features/workspaces/components/WorkspacesDashboard.js85
5 files changed, 460 insertions, 0 deletions
diff --git a/src/features/workspaces/components/CreateWorkspaceForm.js b/src/features/workspaces/components/CreateWorkspaceForm.js
new file mode 100644
index 000000000..83f6e07f7
--- /dev/null
+++ b/src/features/workspaces/components/CreateWorkspaceForm.js
@@ -0,0 +1,93 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
5import { Input, Button } from '@meetfranz/forms';
6import injectSheet from 'react-jss';
7import Form from '../../../lib/Form';
8import { required } from '../../../helpers/validation-helpers';
9
10const messages = defineMessages({
11 submitButton: {
12 id: 'settings.workspace.add.form.submitButton',
13 defaultMessage: '!!!Save workspace',
14 },
15 name: {
16 id: 'settings.workspace.add.form.name',
17 defaultMessage: '!!!Name',
18 },
19});
20
21const styles = () => ({
22 form: {
23 display: 'flex',
24 },
25 input: {
26 flexGrow: 1,
27 marginRight: '10px',
28 },
29 submitButton: {
30 height: 'inherit',
31 marginTop: '3px',
32 },
33});
34
35@injectSheet(styles) @observer
36class CreateWorkspaceForm extends Component {
37 static contextTypes = {
38 intl: intlShape,
39 };
40
41 static propTypes = {
42 classes: PropTypes.object.isRequired,
43 onSubmit: PropTypes.func.isRequired,
44 };
45
46 form = (() => {
47 const { intl } = this.context;
48 return new Form({
49 fields: {
50 name: {
51 label: intl.formatMessage(messages.name),
52 placeholder: intl.formatMessage(messages.name),
53 value: '',
54 validators: [required],
55 },
56 },
57 });
58 })();
59
60 submitForm() {
61 const { form } = this;
62 form.submit({
63 onSuccess: async (f) => {
64 const { onSubmit } = this.props;
65 onSubmit(f.values());
66 },
67 });
68 }
69
70 render() {
71 const { intl } = this.context;
72 const { classes } = this.props;
73 const { form } = this;
74 return (
75 <div className={classes.form}>
76 <Input
77 className={classes.input}
78 {...form.$('name').bind()}
79 showLabel={false}
80 onEnterKey={this.submitForm.bind(this, form)}
81 />
82 <Button
83 className={classes.submitButton}
84 type="submit"
85 label={intl.formatMessage(messages.submitButton)}
86 onClick={this.submitForm.bind(this, form)}
87 />
88 </div>
89 );
90 }
91}
92
93export default CreateWorkspaceForm;
diff --git a/src/features/workspaces/components/EditWorkspaceForm.js b/src/features/workspaces/components/EditWorkspaceForm.js
new file mode 100644
index 000000000..48090f608
--- /dev/null
+++ b/src/features/workspaces/components/EditWorkspaceForm.js
@@ -0,0 +1,192 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
5import { Link } from 'react-router';
6import { Input, Button } from '@meetfranz/forms';
7import injectSheet from 'react-jss';
8
9import Workspace from '../models/Workspace';
10import Service from '../../../models/Service';
11import Form from '../../../lib/Form';
12import { required } from '../../../helpers/validation-helpers';
13import ServiceListItem from './ServiceListItem';
14
15const messages = defineMessages({
16 buttonDelete: {
17 id: 'settings.workspace.form.buttonDelete',
18 defaultMessage: '!!!Delete workspace',
19 },
20 buttonSave: {
21 id: 'settings.workspace.form.buttonSave',
22 defaultMessage: '!!!Save workspace',
23 },
24 name: {
25 id: 'settings.workspace.form.name',
26 defaultMessage: '!!!Name',
27 },
28 yourWorkspaces: {
29 id: 'settings.workspace.form.yourWorkspaces',
30 defaultMessage: '!!!Your workspaces',
31 },
32 servicesInWorkspaceHeadline: {
33 id: 'settings.workspace.form.servicesInWorkspaceHeadline',
34 defaultMessage: '!!!Services in this Workspace',
35 },
36});
37
38const styles = () => ({
39 nameInput: {
40 height: 'auto',
41 },
42 serviceList: {
43 height: 'auto',
44 },
45});
46
47@injectSheet(styles) @observer
48class EditWorkspaceForm extends Component {
49 static contextTypes = {
50 intl: intlShape,
51 };
52
53 static propTypes = {
54 classes: PropTypes.object.isRequired,
55 isDeleting: PropTypes.bool.isRequired,
56 isSaving: PropTypes.bool.isRequired,
57 onDelete: PropTypes.func.isRequired,
58 onSave: PropTypes.func.isRequired,
59 services: PropTypes.arrayOf(PropTypes.instanceOf(Service)).isRequired,
60 workspace: PropTypes.instanceOf(Workspace).isRequired,
61 };
62
63 form = this.prepareWorkspaceForm(this.props.workspace);
64
65 componentWillReceiveProps(nextProps) {
66 const { workspace } = this.props;
67 if (workspace.id !== nextProps.workspace.id) {
68 this.form = this.prepareWorkspaceForm(nextProps.workspace);
69 }
70 }
71
72 prepareWorkspaceForm(workspace) {
73 const { intl } = this.context;
74 return new Form({
75 fields: {
76 name: {
77 label: intl.formatMessage(messages.name),
78 placeholder: intl.formatMessage(messages.name),
79 value: workspace.name,
80 validators: [required],
81 },
82 services: {
83 value: workspace.services.slice(),
84 },
85 },
86 });
87 }
88
89 submitForm(form) {
90 form.submit({
91 onSuccess: async (f) => {
92 const { onSave } = this.props;
93 const values = f.values();
94 onSave(values);
95 },
96 onError: async () => {},
97 });
98 }
99
100 toggleService(service) {
101 const servicesField = this.form.$('services');
102 const serviceIds = servicesField.value;
103 if (serviceIds.includes(service.id)) {
104 serviceIds.splice(serviceIds.indexOf(service.id), 1);
105 } else {
106 serviceIds.push(service.id);
107 }
108 servicesField.set(serviceIds);
109 }
110
111 render() {
112 const { intl } = this.context;
113 const {
114 classes,
115 isDeleting,
116 isSaving,
117 onDelete,
118 workspace,
119 services,
120 } = this.props;
121 const { form } = this;
122 const workspaceServices = form.$('services').value;
123 return (
124 <div className="settings__main">
125 <div className="settings__header">
126 <span className="settings__header-item">
127 <Link to="/settings/workspaces">
128 {intl.formatMessage(messages.yourWorkspaces)}
129 </Link>
130 </span>
131 <span className="separator" />
132 <span className="settings__header-item">
133 {workspace.name}
134 </span>
135 </div>
136 <div className="settings__body">
137 <div className={classes.nameInput}>
138 <Input {...form.$('name').bind()} />
139 </div>
140 <h2>{intl.formatMessage(messages.servicesInWorkspaceHeadline)}</h2>
141 <div className={classes.serviceList}>
142 {services.map(s => (
143 <ServiceListItem
144 key={s.id}
145 service={s}
146 isInWorkspace={workspaceServices.includes(s.id)}
147 onToggle={() => this.toggleService(s)}
148 />
149 ))}
150 </div>
151 </div>
152 <div className="settings__controls">
153 {/* ===== Delete Button ===== */}
154 {isDeleting ? (
155 <Button
156 label={intl.formatMessage(messages.buttonDelete)}
157 loaded={false}
158 buttonType="secondary"
159 className="settings__delete-button"
160 disabled
161 />
162 ) : (
163 <Button
164 buttonType="danger"
165 label={intl.formatMessage(messages.buttonDelete)}
166 className="settings__delete-button"
167 onClick={onDelete}
168 />
169 )}
170 {/* ===== Save Button ===== */}
171 {isSaving ? (
172 <Button
173 type="submit"
174 label={intl.formatMessage(messages.buttonSave)}
175 loaded={!isSaving}
176 buttonType="secondary"
177 disabled
178 />
179 ) : (
180 <Button
181 type="submit"
182 label={intl.formatMessage(messages.buttonSave)}
183 onClick={this.submitForm.bind(this, form)}
184 />
185 )}
186 </div>
187 </div>
188 );
189 }
190}
191
192export default EditWorkspaceForm;
diff --git a/src/features/workspaces/components/ServiceListItem.js b/src/features/workspaces/components/ServiceListItem.js
new file mode 100644
index 000000000..146cc5a36
--- /dev/null
+++ b/src/features/workspaces/components/ServiceListItem.js
@@ -0,0 +1,48 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react';
4import injectSheet from 'react-jss';
5import { Toggle } from '@meetfranz/forms';
6
7import Service from '../../../models/Service';
8
9const styles = () => ({
10 service: {
11 height: 'auto',
12 display: 'flex',
13 },
14 name: {
15 marginTop: '4px',
16 },
17});
18
19@injectSheet(styles) @observer
20class ServiceListItem extends Component {
21 static propTypes = {
22 classes: PropTypes.object.isRequired,
23 isInWorkspace: PropTypes.bool.isRequired,
24 onToggle: PropTypes.func.isRequired,
25 service: PropTypes.instanceOf(Service).isRequired,
26 };
27
28 render() {
29 const {
30 classes,
31 isInWorkspace,
32 onToggle,
33 service,
34 } = this.props;
35
36 return (
37 <div className={classes.service}>
38 <Toggle
39 checked={isInWorkspace}
40 onChange={onToggle}
41 label={service.name}
42 />
43 </div>
44 );
45 }
46}
47
48export default ServiceListItem;
diff --git a/src/features/workspaces/components/WorkspaceItem.js b/src/features/workspaces/components/WorkspaceItem.js
new file mode 100644
index 000000000..b2c2a4830
--- /dev/null
+++ b/src/features/workspaces/components/WorkspaceItem.js
@@ -0,0 +1,42 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { intlShape } from 'react-intl';
4import { observer } from 'mobx-react';
5import classnames from 'classnames';
6import Workspace from '../models/Workspace';
7
8// const messages = defineMessages({});
9
10@observer
11class WorkspaceItem extends Component {
12 static propTypes = {
13 workspace: PropTypes.instanceOf(Workspace).isRequired,
14 onItemClick: PropTypes.func.isRequired,
15 };
16
17 static contextTypes = {
18 intl: intlShape,
19 };
20
21 render() {
22 const { workspace, onItemClick } = this.props;
23 // const { intl } = this.context;
24
25 return (
26 <tr
27 className={classnames({
28 'workspace-table__row': true,
29 })}
30 >
31 <td
32 className="workspace-table__column-name"
33 onClick={() => onItemClick(workspace)}
34 >
35 {workspace.name}
36 </td>
37 </tr>
38 );
39 }
40}
41
42export default WorkspaceItem;
diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js
new file mode 100644
index 000000000..917807302
--- /dev/null
+++ b/src/features/workspaces/components/WorkspacesDashboard.js
@@ -0,0 +1,85 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
5import injectSheet from 'react-jss';
6
7import Loader from '../../../components/ui/Loader';
8import WorkspaceItem from './WorkspaceItem';
9import CreateWorkspaceForm from './CreateWorkspaceForm';
10
11const messages = defineMessages({
12 headline: {
13 id: 'settings.workspaces.headline',
14 defaultMessage: '!!!Your workspaces',
15 },
16 noServicesAdded: {
17 id: 'settings.workspaces.noWorkspacesAdded',
18 defaultMessage: '!!!You haven\'t added any workspaces yet.',
19 },
20});
21
22const styles = () => ({
23 createForm: {
24 height: 'auto',
25 marginBottom: '20px',
26 },
27});
28
29@observer @injectSheet(styles)
30class WorkspacesDashboard extends Component {
31 static propTypes = {
32 classes: PropTypes.object.isRequired,
33 isLoading: PropTypes.bool.isRequired,
34 onCreateWorkspaceSubmit: PropTypes.func.isRequired,
35 onWorkspaceClick: PropTypes.func.isRequired,
36 workspaces: MobxPropTypes.arrayOrObservableArray.isRequired,
37 };
38
39 static contextTypes = {
40 intl: intlShape,
41 };
42
43 render() {
44 const {
45 workspaces,
46 isLoading,
47 onCreateWorkspaceSubmit,
48 onWorkspaceClick,
49 classes,
50 } = this.props;
51 const { intl } = this.context;
52
53 return (
54 <div className="settings__main">
55 <div className="settings__header">
56 <h1>{intl.formatMessage(messages.headline)}</h1>
57 </div>
58 <div className="settings__body">
59 <div className={classes.body}>
60 <div className={classes.createForm}>
61 <CreateWorkspaceForm onSubmit={onCreateWorkspaceSubmit} />
62 </div>
63 {isLoading ? (
64 <Loader />
65 ) : (
66 <table className="workspace-table">
67 <tbody>
68 {workspaces.map(workspace => (
69 <WorkspaceItem
70 key={workspace.id}
71 workspace={workspace}
72 onItemClick={w => onWorkspaceClick(w)}
73 />
74 ))}
75 </tbody>
76 </table>
77 )}
78 </div>
79 </div>
80 </div>
81 );
82 }
83}
84
85export default WorkspacesDashboard;