aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/auth/SetupAssistant.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/auth/SetupAssistant.jsx')
-rw-r--r--src/components/auth/SetupAssistant.jsx336
1 files changed, 336 insertions, 0 deletions
diff --git a/src/components/auth/SetupAssistant.jsx b/src/components/auth/SetupAssistant.jsx
new file mode 100644
index 000000000..8d15e36d1
--- /dev/null
+++ b/src/components/auth/SetupAssistant.jsx
@@ -0,0 +1,336 @@
1import { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react';
4import { defineMessages, injectIntl } from 'react-intl';
5import injectSheet from 'react-jss';
6import classnames from 'classnames';
7
8import Input from '../ui/input/index';
9import Button from '../ui/button';
10import Badge from '../ui/badge';
11import Modal from '../ui/Modal';
12import Infobox from '../ui/Infobox';
13import Appear from '../ui/effects/Appear';
14import globalMessages from '../../i18n/globalMessages';
15
16import { CDN_URL } from '../../config';
17import { H1, H2 } from '../ui/headline';
18
19const SLACK_ID = 'slack';
20
21const messages = defineMessages({
22 headline: {
23 id: 'setupAssistant.headline',
24 defaultMessage: "Let's get started",
25 },
26 subHeadline: {
27 id: 'setupAssistant.subheadline',
28 defaultMessage:
29 'Choose from our most used services and get back on top of your messaging now.',
30 },
31 submitButtonLabel: {
32 id: 'setupAssistant.submit.label',
33 defaultMessage: "Let's go",
34 },
35 skipButtonLabel: {
36 id: 'setupAssistant.skip.label',
37 defaultMessage: 'Skip',
38 },
39 inviteSuccessInfo: {
40 id: 'invite.successInfo',
41 defaultMessage: 'Invitations sent successfully',
42 },
43});
44
45let transition = 'none';
46
47if (window && window.matchMedia('(prefers-reduced-motion: no-preference)')) {
48 transition = 'all 0.25s';
49}
50
51const styles = theme => ({
52 root: {
53 width: '500px !important',
54 textAlign: 'center',
55 padding: 20,
56
57 '& h1': {},
58 },
59 servicesGrid: {
60 display: 'flex',
61 flexWrap: 'wrap',
62 justifyContent: 'space-between',
63 },
64 serviceContainer: {
65 background: theme.colorBackground,
66 position: 'relative',
67 width: '32%',
68 display: 'flex',
69 alignItems: 'center',
70 flexDirection: 'column',
71 justifyContent: 'center',
72 padding: 20,
73 borderRadius: theme.borderRadius,
74 marginBottom: 10,
75 opacity: 0.5,
76 transition,
77 border: [3, 'solid', 'transparent'],
78
79 '& h2': {
80 margin: [10, 0, 0],
81 color: theme.colorText,
82 },
83
84 '&:hover': {
85 border: [3, 'solid', theme.brandPrimary],
86 '& $serviceIcon': {},
87 },
88 },
89 selected: {
90 border: [3, 'solid', theme.brandPrimary],
91 background: `${theme.brandPrimary}47`,
92 opacity: 1,
93 },
94 serviceIcon: {
95 width: 50,
96 transition,
97 },
98
99 slackModalContent: {
100 textAlign: 'center',
101
102 '& img': {
103 width: 50,
104 marginBottom: 20,
105 },
106 },
107 modalActionContainer: {
108 display: 'flex',
109 flexDirection: 'column',
110 justifyContent: 'center',
111 alignItems: 'center',
112 },
113 ctaCancel: {
114 background: 'none !important',
115 },
116 slackBadge: {
117 position: 'absolute',
118 bottom: 4,
119 height: 'auto',
120 padding: '0px 4px',
121 borderRadius: theme.borderRadiusSmall,
122 margin: 0,
123 display: 'flex',
124 overflow: 'hidden',
125 },
126 clearSlackWorkspace: {
127 background: theme.inputPrefixColor,
128 marginLeft: 5,
129 height: '100%',
130 color: theme.colorText,
131 display: 'inline-flex',
132 justifyContent: 'center',
133 alignItems: 'center',
134 marginRight: -4,
135 padding: [0, 5],
136 },
137});
138
139class SetupAssistant extends Component {
140 static propTypes = {
141 classes: PropTypes.object.isRequired,
142 onSubmit: PropTypes.func.isRequired,
143 isInviteSuccessful: PropTypes.bool,
144 services: PropTypes.object.isRequired,
145 isSettingUpServices: PropTypes.bool.isRequired,
146 };
147
148 static defaultProps = {
149 isInviteSuccessful: false,
150 };
151
152 constructor() {
153 super();
154
155 this.state = {
156 services: [],
157 isSlackModalOpen: false,
158 slackWorkspace: '',
159 };
160 }
161
162 slackWorkspaceHandler() {
163 const { slackWorkspace = '', services } = this.state;
164
165 const sanitizedWorkspace = slackWorkspace
166 .trim()
167 .replace(/^https?:\/\//, '');
168
169 if (sanitizedWorkspace) {
170 const index = services.findIndex(s => s.id === SLACK_ID);
171
172 if (index === -1) {
173 const newServices = services;
174 newServices.push({ id: SLACK_ID, team: sanitizedWorkspace });
175 this.setState({ services: newServices });
176 }
177 }
178
179 this.setState({
180 isSlackModalOpen: false,
181 slackWorkspace: sanitizedWorkspace,
182 });
183 }
184
185 render() {
186 const { intl } = this.props;
187 const {
188 classes,
189 isInviteSuccessful,
190 onSubmit,
191 services,
192 isSettingUpServices,
193 } = this.props;
194 const {
195 isSlackModalOpen,
196 slackWorkspace,
197 services: addedServices,
198 } = this.state;
199
200 return (
201 <div className={`auth__container ${classes.root}`}>
202 {this.state.showSuccessInfo && isInviteSuccessful && (
203 <Appear>
204 <Infobox
205 type="success"
206 icon="checkbox-marked-circle-outline"
207 dismissable
208 >
209 {intl.formatMessage(messages.inviteSuccessInfo)}
210 </Infobox>
211 </Appear>
212 )}
213
214 <img src="./assets/images/logo.svg" className="auth__logo" alt="" />
215 <H1>{intl.formatMessage(messages.headline)}</H1>
216 <H2>{intl.formatMessage(messages.subHeadline)}</H2>
217 <div className={classnames('grid', classes.servicesGrid)}>
218 {Object.keys(services).map(id => {
219 const service = services[id];
220 return (
221 <button
222 className={classnames({
223 [classes.serviceContainer]: true,
224 [classes.selected]:
225 this.state.services.findIndex(s => s.id === id) !== -1,
226 })}
227 key={id}
228 onClick={() => {
229 const index = this.state.services.findIndex(s => s.id === id);
230 if (index === -1) {
231 if (id === SLACK_ID) {
232 this.setState({ isSlackModalOpen: true });
233 } else {
234 addedServices.push({ id });
235 }
236 } else {
237 addedServices.splice(index, 1);
238 if (id === SLACK_ID) {
239 this.setState({
240 slackWorkspace: '',
241 });
242 }
243 }
244
245 this.setState({ services: addedServices });
246 }}
247 type="button"
248 >
249 <img
250 src={`${CDN_URL}/recipes/dist/${id}/src/icon.svg`}
251 className={classes.serviceIcon}
252 alt=""
253 />
254 <H2>{service.name}</H2>
255 {id === SLACK_ID && slackWorkspace && (
256 <Badge type="secondary" className={classes.slackBadge}>
257 {slackWorkspace}
258 <button
259 type="button"
260 className={classes.clearSlackWorkspace}
261 onClick={() => {
262 this.setState({
263 slackWorkspace: '',
264 });
265 }}
266 >
267 x
268 </button>
269 </Badge>
270 )}
271 </button>
272 );
273 })}
274 </div>
275 <Modal
276 isOpen={isSlackModalOpen}
277 // isBlocking={false}
278 close={() => this.setState({ isSlackModalOpen: false })}
279 >
280 <div className={classes.slackModalContent}>
281 <img src={`${CDN_URL}/recipes/dist/slack/src/icon.svg`} alt="" />
282 <H1>Create your first Slack workspace</H1>
283 <form
284 onSubmit={e => {
285 e.preventDefault();
286 this.slackWorkspaceHandler();
287 }}
288 >
289 <Input
290 suffix=".slack.com"
291 placeholder="workspace-url"
292 onChange={e =>
293 this.setState({ slackWorkspace: e.target.value })
294 }
295 value={slackWorkspace}
296 />
297 <div className={classes.modalActionContainer}>
298 <Button
299 type="submit"
300 label={intl.formatMessage(globalMessages.save)}
301 />
302 <Button
303 type="link"
304 buttonType="secondary"
305 label={intl.formatMessage(globalMessages.cancel)}
306 className={classes.ctaCancel}
307 onClick={() => this.setState({ slackWorkspace: '' })}
308 />
309 </div>
310 </form>
311 </div>
312 </Modal>
313 <Button
314 type="button"
315 className="auth__button"
316 // disabled={!atLeastOneEmailAddress}
317 label={intl.formatMessage(messages.submitButtonLabel)}
318 onClick={() => onSubmit(this.state.services)}
319 busy={isSettingUpServices}
320 disabled={isSettingUpServices || addedServices.length === 0}
321 />
322 <Button
323 type="button"
324 className="auth__button auth__button--skip"
325 label={intl.formatMessage(messages.skipButtonLabel)}
326 onClick={() => onSubmit([])}
327 buttonType="secondary"
328 />
329 </div>
330 );
331 }
332}
333
334export default injectIntl(
335 injectSheet(styles, { injectTheme: true })(observer(SetupAssistant)),
336);