diff options
Diffstat (limited to 'src/components/auth/Invite.js')
-rw-r--r-- | src/components/auth/Invite.js | 128 |
1 files changed, 103 insertions, 25 deletions
diff --git a/src/components/auth/Invite.js b/src/components/auth/Invite.js index c1d815dcd..f1c16986b 100644 --- a/src/components/auth/Invite.js +++ b/src/components/auth/Invite.js | |||
@@ -3,13 +3,20 @@ import PropTypes from 'prop-types'; | |||
3 | import { observer } from 'mobx-react'; | 3 | import { observer } from 'mobx-react'; |
4 | import { defineMessages, intlShape } from 'react-intl'; | 4 | import { defineMessages, intlShape } from 'react-intl'; |
5 | import { Link } from 'react-router'; | 5 | import { Link } from 'react-router'; |
6 | import classnames from 'classnames'; | ||
6 | 7 | ||
8 | import Infobox from '../ui/Infobox'; | ||
9 | import Appear from '../ui/effects/Appear'; | ||
7 | import Form from '../../lib/Form'; | 10 | import Form from '../../lib/Form'; |
8 | import { email } from '../../helpers/validation-helpers'; | 11 | import { email } from '../../helpers/validation-helpers'; |
9 | import Input from '../ui/Input'; | 12 | import Input from '../ui/Input'; |
10 | import Button from '../ui/Button'; | 13 | import Button from '../ui/Button'; |
11 | 14 | ||
12 | const messages = defineMessages({ | 15 | const messages = defineMessages({ |
16 | settingsHeadline: { | ||
17 | id: 'settings.invite.headline', | ||
18 | defaultMessage: '!!!Invite Friends', | ||
19 | }, | ||
13 | headline: { | 20 | headline: { |
14 | id: 'invite.headline.friends', | 21 | id: 'invite.headline.friends', |
15 | defaultMessage: '!!!Invite 3 of your friends or colleagues', | 22 | defaultMessage: '!!!Invite 3 of your friends or colleagues', |
@@ -30,41 +37,77 @@ const messages = defineMessages({ | |||
30 | id: 'invite.skip.label', | 37 | id: 'invite.skip.label', |
31 | defaultMessage: '!!!I want to do this later', | 38 | defaultMessage: '!!!I want to do this later', |
32 | }, | 39 | }, |
40 | inviteSuccessInfo: { | ||
41 | id: 'invite.successInfo', | ||
42 | defaultMessage: '!!!Invitations sent successfully', | ||
43 | }, | ||
33 | }); | 44 | }); |
34 | 45 | ||
35 | @observer | 46 | @observer |
36 | export default class Invite extends Component { | 47 | export default class Invite extends Component { |
37 | static propTypes = { | 48 | static propTypes = { |
38 | onSubmit: PropTypes.func.isRequired, | 49 | onSubmit: PropTypes.func.isRequired, |
50 | embed: PropTypes.bool, | ||
51 | isInviteSuccessful: PropTypes.bool, | ||
52 | isLoadingInvite: PropTypes.bool, | ||
53 | }; | ||
54 | |||
55 | static defaultProps = { | ||
56 | embed: false, | ||
57 | isInviteSuccessful: false, | ||
58 | isLoadingInvite: false, | ||
39 | }; | 59 | }; |
40 | 60 | ||
41 | static contextTypes = { | 61 | static contextTypes = { |
42 | intl: intlShape, | 62 | intl: intlShape, |
43 | }; | 63 | }; |
44 | 64 | ||
45 | form = new Form({ | 65 | state = { showSuccessInfo: false }; |
46 | fields: { | 66 | |
47 | invite: [...Array(3).fill({ | 67 | componentWillMount() { |
48 | name: { | 68 | const handlers = { |
49 | label: this.context.intl.formatMessage(messages.nameLabel), | 69 | onChange: () => { |
50 | // value: '', | 70 | this.setState({ showSuccessInfo: false }); |
51 | placeholder: this.context.intl.formatMessage(messages.nameLabel), | 71 | }, |
52 | }, | 72 | }; |
53 | email: { | 73 | |
54 | label: this.context.intl.formatMessage(messages.emailLabel), | 74 | this.form = new Form({ |
55 | // value: '', | 75 | fields: { |
56 | validate: [email], | 76 | invite: [...Array(3).fill({ |
57 | placeholder: this.context.intl.formatMessage(messages.emailLabel), | 77 | fields: { |
58 | }, | 78 | name: { |
59 | })], | 79 | label: this.context.intl.formatMessage(messages.nameLabel), |
60 | }, | 80 | placeholder: this.context.intl.formatMessage(messages.nameLabel), |
61 | }, this.context.intl); | 81 | handlers, |
82 | // related: ['invite.0.email'], // path accepted but does not work | ||
83 | }, | ||
84 | email: { | ||
85 | label: this.context.intl.formatMessage(messages.emailLabel), | ||
86 | placeholder: this.context.intl.formatMessage(messages.emailLabel), | ||
87 | handlers, | ||
88 | validators: [email], | ||
89 | }, | ||
90 | }, | ||
91 | })], | ||
92 | }, | ||
93 | }, this.context.intl); | ||
94 | } | ||
95 | |||
96 | componentDidMount() { | ||
97 | document.querySelector('input:first-child').focus(); | ||
98 | } | ||
62 | 99 | ||
63 | submit(e) { | 100 | submit(e) { |
64 | e.preventDefault(); | 101 | e.preventDefault(); |
102 | |||
65 | this.form.submit({ | 103 | this.form.submit({ |
66 | onSuccess: (form) => { | 104 | onSuccess: (form) => { |
67 | this.props.onSubmit({ invites: form.values().invite }); | 105 | this.props.onSubmit({ invites: form.values().invite }); |
106 | |||
107 | this.form.clear(); | ||
108 | // this.form.$('invite.0.name').focus(); // path accepted but does not focus ;( | ||
109 | document.querySelector('input:first-child').focus(); | ||
110 | this.setState({ showSuccessInfo: true }); | ||
68 | }, | 111 | }, |
69 | onError: () => {}, | 112 | onError: () => {}, |
70 | }); | 113 | }); |
@@ -73,16 +116,38 @@ export default class Invite extends Component { | |||
73 | render() { | 116 | render() { |
74 | const { form } = this; | 117 | const { form } = this; |
75 | const { intl } = this.context; | 118 | const { intl } = this.context; |
119 | const { embed, isInviteSuccessful, isLoadingInvite } = this.props; | ||
120 | |||
121 | const atLeastOneEmailAddress = form.$('invite') | ||
122 | .map(invite => invite.$('email').value) | ||
123 | .some(emailValue => emailValue.trim() !== ''); | ||
124 | |||
125 | const sendButtonClassName = classnames({ | ||
126 | auth__button: true, | ||
127 | 'invite__embed--button': embed, | ||
128 | }); | ||
129 | |||
130 | const renderForm = ( | ||
131 | <div> | ||
132 | {this.state.showSuccessInfo && isInviteSuccessful && ( | ||
133 | <Appear> | ||
134 | <Infobox | ||
135 | type="success" | ||
136 | icon="checkbox-marked-circle-outline" | ||
137 | dismissable | ||
138 | > | ||
139 | {intl.formatMessage(messages.inviteSuccessInfo)} | ||
140 | </Infobox> | ||
141 | </Appear> | ||
142 | )} | ||
76 | 143 | ||
77 | return ( | ||
78 | <div className="auth__container auth__container--signup"> | ||
79 | <form className="franz-form auth__form" onSubmit={e => this.submit(e)}> | 144 | <form className="franz-form auth__form" onSubmit={e => this.submit(e)}> |
80 | <img | 145 | {!embed && (<img |
81 | src="./assets/images/logo.svg" | 146 | src="./assets/images/logo.svg" |
82 | className="auth__logo" | 147 | className="auth__logo" |
83 | alt="" | 148 | alt="" |
84 | /> | 149 | />)} |
85 | <h1> | 150 | <h1 className={embed && 'invite__embed'}> |
86 | {intl.formatMessage(messages.headline)} | 151 | {intl.formatMessage(messages.headline)} |
87 | </h1> | 152 | </h1> |
88 | {form.$('invite').map(invite => ( | 153 | {form.$('invite').map(invite => ( |
@@ -95,17 +160,30 @@ export default class Invite extends Component { | |||
95 | ))} | 160 | ))} |
96 | <Button | 161 | <Button |
97 | type="submit" | 162 | type="submit" |
98 | className="auth__button" | 163 | className={sendButtonClassName} |
164 | disabled={!atLeastOneEmailAddress} | ||
99 | label={intl.formatMessage(messages.submitButtonLabel)} | 165 | label={intl.formatMessage(messages.submitButtonLabel)} |
166 | loaded={!isLoadingInvite} | ||
100 | /> | 167 | /> |
101 | <Link | 168 | {!embed && (<Link |
102 | to="/" | 169 | to="/" |
103 | className="franz-form__button franz-form__button--secondary auth__button auth__button--skip" | 170 | className="franz-form__button franz-form__button--secondary auth__button auth__button--skip" |
104 | > | 171 | > |
105 | {intl.formatMessage(messages.skipButtonLabel)} | 172 | {intl.formatMessage(messages.skipButtonLabel)} |
106 | </Link> | 173 | </Link>)} |
107 | </form> | 174 | </form> |
108 | </div> | 175 | </div> |
109 | ); | 176 | ); |
177 | |||
178 | return ( | ||
179 | <div className={!embed ? 'auth__container auth__container--signup' : 'settings__main'}> | ||
180 | {embed && ( | ||
181 | <div className="settings__header"> | ||
182 | <h1>{this.context.intl.formatMessage(messages.settingsHeadline)}</h1> | ||
183 | </div> | ||
184 | )} | ||
185 | {!embed ? <div>{renderForm}</div> : <div className="settings__body invite__form">{renderForm}</div>} | ||
186 | </div> | ||
187 | ); | ||
110 | } | 188 | } |
111 | } | 189 | } |