Captcha

Двигаться будем сверху вниз, т.е. DAL – BLL – UI.

  1. Создадим в “апишке” (src\api\api.js) объект для отправки запроса с целью получения url капчи:
    ...
    export const securityAPI = {
        getCaptchaUrl() {
            return instance.get(`security/get-captcha-url`);
        },
      
    }

    2. Теперь добавим санку внизу файла src\redux\auth-reducer.js. Учитываем, что к нам по запросу возвращается объект, у которого есть свойство url (согласно API документации).

    export const getCaptchaUrl = () => async (dispatch) => {
        const response = await securityAPI.getCaptchaUrl();
        const captchaUrl = response.data.url;
    }

    В итоге мы получили url, который должен как-то отобарзиться в UI. А он может попасть туда только если станет стейтом.

  2. Поэтому добавляем в том же файле в стейт свойство captchaUrl со значением null.
    let initialState = {
          userId: null,
          email: null,
          login: null,
          isAuth: false,
          captchaUrl: null //if null, then captcha is not requred
    }

     

  3. Полученный в санке url теперь нужно засестать в стейт вместо null. Для этого:
    1) ложим строку в константу ET_CAPTCHA_URL_SUCCESS;
    2) создадим генератор экшена (экшнкриэйтер) getCaptchaUrlSuccess;
    3) добавляем его обработку внутрь функции-редьюсера authReducer,
    4) диспатчим этот же экшнкриэйтер внутри нашего созданного ранее санккриэйтера getCaptchaUrl;
    5) диспатчим наш санккриэйтер getCaptchaUrl для получения капчи внутри другого санккриэйтера login* для логанизации внутри условия, когда авторизация не прошла ():

    import { authAPI, securityAPI } from "../api/api";
    import { stopSubmit } from "redux-form";
    
    ...
    const GET_CAPTCHA_URL_SUCCESS = 'social/auth/GET_CAPTCHA_URL_SUCCESS';
    
    let initialState = {...}
    
    const authReducer = (state = initialState, action) => {
        switch(action.type) { //обработка обоих экшенов аналогична, поэтому код короче
            case SET_USER_DATA:
            case GET_CAPTCHA_URL_SUCCESS:
                return {
                    ...state,
                    ...action.payload,
                }
        default:
            return state;
        }
    }
    
    export const setAuthUserData = (userId, email, login, isAuth) => ({...}); 
    
    export const getCaptchaUrlSuccess = (captchaUrl) => ({ //экшнкриэйтер
        type: GET_CAPTCHA_URL_SUCCESS, payload: {captchaUrl}   
    });
    
    export const login = (email, password, rememberMe, captcha) => async (dispatch) => {
        let response = await authAPI.login(email, password, rememberMe, captcha)
    
            if (response.data.resultCode === 0) {
                dispatch(getAuthUserData());
            } else { //если логинизация не прошла, то получаем капчу либо выводим ошибку
                if (response.data.resultCode === 10) {
                    dispatch(getCaptchaUrl()); //диспатчим санку, если с сервера resultCode пришел 10
                } else {
                    let message = response.data.messages.length > 0 ? response.data.messages[0] : "Some error";
                    dispatch(stopSubmit("login", {_error: message})); 
                } 
            }
    }
    
    export const getCaptchaUrl = () => async (dispatch) => {
        const response = await securityAPI.getCaptchaUrl();
        const captchaUrl = response.data.url;
        dispatch(getCaptchaUrlSuccess(captchaUrl)); //диспатчим наш экшнкриэйтер
    }

    *мы можем диспатчить санку с UI, а можем и с другой санки (точнее санккриэйтер внутри другого сакнккриэйтера)

  4. Следующим шагом является показать пользователю картинку, если url в стейте присутствует. Для этого в Login.jsx:
    1) подписываемся в mapStateToProps на captchaUrl;
    2) прокидываем через пропсы captchaUrl в нашу редакс-формочку LoginReduxForm;
    3) в параметрах (в скобках) компоненты LoginForm через деструктуризацию мы “ловим” из пропсов captchaUrl;
    4) через тернарное выражение (2 амперсанта), если captchaUrl, то показываем картинку с капчей;
    5) добавляем с аналогичным условием появление поля для воода капчи;
    6) добавляем в параметры санккриэйтера login, который повешен через onSubmit на кнопку для авторизации, введенный текст из поля для ввода капчи на ряду с передачей пароля и логина.

    import React from 'react';
    ...
    
    
    const LoginForm = ({handleSubmit, error, captchaUrl}) => {
        return (
            <form onSubmit={handleSubmit}>
                {createField("Email", "email", [required], Input)}
                {createField("Password", "password", [required], Input, {type: "password"})}
                {createField(null, "rememberMe", [], Input, {type: "checkbox"}, "remember me")}
    
                {captchaUrl && <img src={captchaUrl} />}
                {captchaUrl && createField("Symbols from image", "captcha", [required], Input, {}) }
    
                {error && <div className={style.formSummaryError}>
                    {error}
                </div>
                }
                <div>
                    <button>Login</button>
                </div>
            </form>
        )
    }
    
    const LoginReduxForm = reduxForm({
        form: 'login'
    })(LoginForm)
    
    const Login = (props) => {
            const onSubmit = (formData, dispatch) => {   
                //dispatch(reset("login"));
                props.login(formData.email, formData.password, formData.rememberMe, formData.captcha);
            }
            if (props.isAuth) {
                return <Redirect to={"/profile"} />
            }
    
        return <div>
            <h1>LOGIN</h1>
            <LoginReduxForm onSubmit={onSubmit} captchaUrl={props.captchaUrl} />
        </div>
    
    }
    
    const mapStateToProps = (state) => ({
        captchaUrl: state.auth.captchaUrl,
        isAuth: state.auth.isAuth
    })
    
    
    export default connect(mapStateToProps, {login}) (Login);

     

Результат:

Вывод капчи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *