mirror of
https://github.com/elyby/accounts-frontend.git
synced 2024-12-27 23:40:28 +05:30
#14: add captcha support for resend-activation
This commit is contained in:
parent
4f7f1d2273
commit
4716c679b9
@ -103,9 +103,9 @@ export function activate({key = ''}) {
|
||||
);
|
||||
}
|
||||
|
||||
export function resendActivation({email = ''}) {
|
||||
export function resendActivation({email = '', captcha}) {
|
||||
return wrapInLoader((dispatch) =>
|
||||
signup.resendActivation({email})
|
||||
signup.resendActivation({email, captcha})
|
||||
.then((resp) => {
|
||||
dispatch(updateUser({
|
||||
email
|
||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
|
||||
import { FormattedMessage as Message } from 'react-intl';
|
||||
|
||||
import { Input } from 'components/ui/form';
|
||||
import { Input, Captcha } from 'components/ui/form';
|
||||
import registerMessages from 'components/auth/register/Register.intl.json';
|
||||
|
||||
import BaseAuthBody from 'components/auth/BaseAuthBody';
|
||||
@ -25,16 +25,16 @@ export default class ResendActivation extends BaseAuthBody {
|
||||
<Message {...messages.specifyYourEmail} />
|
||||
</div>
|
||||
|
||||
<div className={styles.formRow}>
|
||||
<Input {...this.bindField('email')}
|
||||
icon="envelope"
|
||||
color="blue"
|
||||
type="email"
|
||||
required
|
||||
placeholder={registerMessages.yourEmail}
|
||||
defaultValue={this.context.user.email}
|
||||
/>
|
||||
</div>
|
||||
<Input {...this.bindField('email')}
|
||||
icon="envelope"
|
||||
color="blue"
|
||||
type="email"
|
||||
required
|
||||
placeholder={registerMessages.yourEmail}
|
||||
defaultValue={this.context.user.email}
|
||||
/>
|
||||
|
||||
<Captcha {...this.bindField('captcha')} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
38
src/components/ui/form/Captcha.jsx
Normal file
38
src/components/ui/form/Captcha.jsx
Normal file
@ -0,0 +1,38 @@
|
||||
import React, { PropTypes } from 'react';
|
||||
|
||||
import captcha from 'services/captcha';
|
||||
import { skins, SKIN_DARK } from 'components/ui';
|
||||
|
||||
import styles from './form.scss';
|
||||
import FormInputComponent from './FormInputComponent';
|
||||
|
||||
export default class Captcha extends FormInputComponent {
|
||||
static displayName = 'Captcha';
|
||||
|
||||
static propTypes = {
|
||||
skin: PropTypes.oneOf(skins)
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
skin: SKIN_DARK
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
captcha.render(this.el, {
|
||||
skin: this.props.skin,
|
||||
onSetCode: this.setCode
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div ref={this.setEl} className={styles.captcha} />
|
||||
);
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.state && this.state.code;
|
||||
}
|
||||
|
||||
setCode = (code) => this.setState({code});
|
||||
}
|
@ -295,6 +295,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
.captcha {
|
||||
width: 302px;
|
||||
height: 76px;
|
||||
// minimum captcha width is 302px, which can not be changed
|
||||
// using transform to scale down to 296px
|
||||
transform-origin: 0;
|
||||
transform: scaleX(0.98);
|
||||
}
|
||||
|
||||
/**
|
||||
* Form validation
|
||||
*/
|
||||
|
@ -5,6 +5,7 @@ import Button from './Button';
|
||||
import Form from './Form';
|
||||
import FormModel from './FormModel';
|
||||
import Dropdown from './Dropdown';
|
||||
import Captcha from './Captcha';
|
||||
import FormError from './FormError';
|
||||
|
||||
export {
|
||||
@ -15,5 +16,6 @@ export {
|
||||
Form,
|
||||
FormModel,
|
||||
Dropdown,
|
||||
Captcha,
|
||||
FormError
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { routeActions } from 'react-router-redux';
|
||||
|
||||
import request from 'services/request';
|
||||
import captcha from 'services/captcha';
|
||||
import accounts from 'services/api/accounts';
|
||||
import authentication from 'services/api/authentication';
|
||||
import { setLocale } from 'components/i18n/actions';
|
||||
@ -27,6 +28,9 @@ export function changeLang(lang) {
|
||||
accounts.changeLang(lang);
|
||||
}
|
||||
|
||||
// TODO: probably should be moved from here, because it is side effect
|
||||
captcha.setLang(lang);
|
||||
|
||||
dispatch({
|
||||
type: CHANGE_LANG,
|
||||
payload: {
|
||||
|
@ -3,7 +3,7 @@ import { authenticate, changeLang } from 'components/user/actions';
|
||||
/**
|
||||
* Initializes User state with the fresh data
|
||||
*
|
||||
* @param {Object} store - redux store
|
||||
* @param {object} store - redux store
|
||||
*
|
||||
* @return {Promise} a promise, that resolves in User state
|
||||
*/
|
||||
|
@ -18,3 +18,25 @@ export function omit(obj, keys) {
|
||||
|
||||
return newObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously loads script
|
||||
*
|
||||
* @param {string} src
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
export function loadScript(src) {
|
||||
const script = document.createElement('script');
|
||||
|
||||
script.async = true;
|
||||
script.defer = true;
|
||||
script.src = src;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
script.onlaod = resolve;
|
||||
script.onerror = reject;
|
||||
|
||||
document.body.appendChild(script);
|
||||
});
|
||||
}
|
||||
|
@ -11,6 +11,9 @@ import { IntlProvider } from 'components/i18n';
|
||||
import routesFactory from 'routes';
|
||||
import storeFactory from 'storeFactory';
|
||||
import bsodFactory from 'components/ui/bsod/factory';
|
||||
import captcha from 'services/captcha';
|
||||
|
||||
captcha.setApiKey('6LdUZiYTAAAAAEjDGi9kEu0MRKYHYWskPFNXSYOV'); // TODO
|
||||
|
||||
const store = storeFactory();
|
||||
|
||||
|
@ -22,10 +22,10 @@ export default {
|
||||
);
|
||||
},
|
||||
|
||||
resendActivation({email = ''}) {
|
||||
resendActivation({email = '', captcha}) {
|
||||
return request.post(
|
||||
'/api/signup/repeat-message',
|
||||
{email}
|
||||
{email, captcha}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
59
src/services/captcha.js
Normal file
59
src/services/captcha.js
Normal file
@ -0,0 +1,59 @@
|
||||
import { loadScript } from 'functions';
|
||||
|
||||
let readyPromise;
|
||||
let lang = 'en';
|
||||
let sitekey;
|
||||
|
||||
export default {
|
||||
/**
|
||||
* @param {DOMNode|string} el - dom node or id of element where to render captcha
|
||||
* @param {string} options.skin - skin color (dark|light)
|
||||
* @param {function} options.onSetCode - the callback, that will be called with
|
||||
* captcha verification code, after user successfully solves captcha
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
render(el, {skin: theme, onSetCode: callback}) {
|
||||
if (!sitekey) {
|
||||
throw new Error('Site key is required to render captcha');
|
||||
}
|
||||
|
||||
return loadApi().then(() =>
|
||||
window.grecaptcha.render(el, {
|
||||
sitekey,
|
||||
theme,
|
||||
callback
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {stirng} newLang
|
||||
*
|
||||
* @see https://developers.google.com/recaptcha/docs/language
|
||||
*/
|
||||
setLang(newLang) {
|
||||
lang = newLang;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} apiKey
|
||||
*
|
||||
* @see http://www.google.com/recaptcha/admin
|
||||
*/
|
||||
setApiKey(apiKey) {
|
||||
sitekey = apiKey;
|
||||
}
|
||||
};
|
||||
|
||||
function loadApi() {
|
||||
if (!readyPromise) {
|
||||
readyPromise = new Promise((resolve) => {
|
||||
window.onReCaptchaReady = resolve;
|
||||
});
|
||||
|
||||
loadScript(`https://www.google.com/recaptcha/api.js?onload=onReCaptchaReady&render=explicit&hl=${lang}`);
|
||||
}
|
||||
|
||||
return readyPromise;
|
||||
}
|
Loading…
Reference in New Issue
Block a user