Skip to content
Open

Ht2 #16

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
499 changes: 268 additions & 231 deletions .idea/workspace.xml

Large diffs are not rendered by default.

15 changes: 7 additions & 8 deletions src/components/auth/SignIn.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React, { Component } from 'react'
import {reduxForm, Field} from 'redux-form'
import {validate} from './utils';
import ErrorField from "../common/ErrorField";

class SignIn extends Component {
static propTypes = {
Expand All @@ -11,14 +13,10 @@ class SignIn extends Component {
<div>
<h3>Sign In</h3>
<form onSubmit = {this.props.handleSubmit}>
<Field name = 'email' component = {ErrorField} type = 'text' label = 'email'/>
<Field name = 'password' component = {ErrorField} type = 'password' label = 'password'/>
<div>
email: <Field name = 'email' component = 'input' type = 'text'/>
</div>
<div>
password: <Field name = 'password' component = 'input' type = 'password'/>
</div>
<div>
<input type = 'submit'/>
<input type = 'submit' disabled={this.props.invalid}/>
</div>
</form>
</div>
Expand All @@ -27,5 +25,6 @@ class SignIn extends Component {
}

export default reduxForm({
form: 'auth'
form: 'auth',
validate
})(SignIn)
14 changes: 1 addition & 13 deletions src/components/auth/SignUp.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { Component } from 'react'
import {reduxForm, Field} from 'redux-form'
import emailValidator from 'email-validator'
import {validate} from './utils'
import ErrorField from '../common/ErrorField'

class SignUp extends Component {
Expand All @@ -24,18 +24,6 @@ class SignUp extends Component {
}
}

const validate = ({ email, password }) => {
const errors = {}

if (!email) errors.email = 'email is a required field'
if (!password) errors.password = 'password is a required field'

if (email && !emailValidator.validate(email)) errors.email = 'invalid email'
if (password && password.length < 8) errors.password = 'to short'

return errors
}

export default reduxForm({
form: 'auth',
validate
Expand Down
13 changes: 13 additions & 0 deletions src/components/auth/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import emailValidator from "email-validator/index";

export const validate = ({ email, password }) => {
const errors = {}

if (!email) errors.email = 'email is a required field'
if (!password) errors.password = 'password is a required field'

if (email && !emailValidator.validate(email)) errors.email = 'invalid email'
if (password && password.length < 8) errors.password = 'to short'

return errors
}
6 changes: 3 additions & 3 deletions src/components/routes/Auth.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { Component } from 'react'
import {Route, NavLink} from 'react-router-dom'
import {connect} from 'react-redux'
import {signUp} from '../../ducks/auth'
import {signUp, signIn} from '../../ducks/auth'
import SignIn from '../auth/SignIn'
import SignUp from '../auth/SignUp'

Expand All @@ -22,8 +22,8 @@ class AuthPage extends Component {
)
}

handleSignIn = (values) => console.log('---', 'sign in', values)
handleSignIn = ({email, password}) => this.props.signIn(email, password)
handleSignUp = ({email, password}) => this.props.signUp(email, password)
}

export default connect(null, { signUp })(AuthPage)
export default connect(null, { signUp, signIn })(AuthPage)
8 changes: 4 additions & 4 deletions src/config.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import firebase from 'firebase'

export const appName = 'advreact-1610'
export const appName = 'react-course-f262b'

firebase.initializeApp({
apiKey: "AIzaSyB31xpTtp4Jln_hb2kAbE4PGf6Mi8EgLyA",
authDomain: `${appName}.firebaseapp.com`,
databaseURL: `https://${appName}.firebaseio.com`,
projectId: appName,
storageBucket: "",
messagingSenderId: "397157634637"
apiKey: "AIzaSyAt-smU_1tqNdkj9pmSpVLxqaOjhDwf4dk",
storageBucket: "react-course-f262b.appspot.com",
messagingSenderId: "447165438476"
})
50 changes: 48 additions & 2 deletions src/ducks/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {Record} from 'immutable'
import firebase from 'firebase'
import {createSelector} from 'reselect'
import {call, put, all, take} from 'redux-saga/effects'
import {reset} from 'redux-form'
import {push} from 'react-router-redux'

/**
* Constants
Expand All @@ -14,7 +16,9 @@ export const SIGN_UP_START = `${prefix}/SIGN_UP_START`
export const SIGN_UP_SUCCESS = `${prefix}/SIGN_UP_SUCCESS`
export const SIGN_UP_ERROR = `${prefix}/SIGN_UP_ERROR`

export const SIGN_IN_START = `${prefix}/SIGN_IN_START`
export const SIGN_IN_SUCCESS = `${prefix}/SIGN_IN_SUCCESS`
export const SIGN_IN_ERROR = `${prefix}/SIGN_IN_ERROR`

/**
* Reducer
Expand Down Expand Up @@ -60,6 +64,13 @@ export function signUp(email, password) {
}
}

export function signIn(email, password) {
return {
type: SIGN_IN_START,
payload: { email, password }
}
}

firebase.auth().onAuthStateChanged(user => {
if (!user) return

Expand All @@ -81,12 +92,13 @@ export function * signUpSaga() {

try {
const user = yield call([auth, auth.createUserWithEmailAndPassword], payload.email, payload.password)
//const user = apply(auth, createUserWithEmailAndPassword, [email, password])

yield put({
type: SIGN_UP_SUCCESS,
payload: {user}
})

yield put(reset('auth'))
} catch (error) {
yield put({
type: SIGN_UP_ERROR,
Expand All @@ -96,8 +108,42 @@ export function * signUpSaga() {
}
}

export function * signInSaga() {
const auth = firebase.auth()

while (true) {
const {payload} = yield take(SIGN_IN_START)

try {
const user = yield call([auth, auth.signInWithEmailAndPassword], payload.email, payload.password)

yield put({
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В общем случае все правильно, хотя нам достаточно onAuthStateChange

type: SIGN_IN_SUCCESS,
payload: {user}
})

yield put(reset('auth'))
} catch (error) {
yield put({
type: SIGN_IN_ERROR,
payload: {error}
})
}
}
}

export function * redirectSaga() {
while (true) {
yield take(SIGN_IN_SUCCESS)

yield put(push('/people'))
}
}

export function * saga() {
yield all([
signUpSaga()
signUpSaga(),
signInSaga(),
redirectSaga()
])
}
146 changes: 146 additions & 0 deletions src/ducks/auth.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Хорошо, но в идеале можно еще и редюсер потестить

signIn,
signUp,
signInSaga,
signUpSaga,
redirectSaga,
SIGN_IN_START,
SIGN_IN_SUCCESS,
SIGN_IN_ERROR,
SIGN_UP_START,
SIGN_UP_SUCCESS,
SIGN_UP_ERROR
} from './auth'
import {call, put, take} from 'redux-saga/effects'
import firebase from 'firebase'
import {reset} from 'redux-form'
import {push} from 'react-router-redux'

/**
* Sign in
* */

it('should sign in successfully', () => {
const authData = {
email: 'test@test.com',
password: '12345678'
}

const mockUser = {
name: 'Ivan',
age: 22
}

const auth = firebase.auth()

const requestAction = signIn(authData)

const gen = signInSaga(requestAction)

expect(gen.next().value).toEqual(take(SIGN_IN_START))

expect(gen.next({payload: authData}).value).toEqual(call([auth, auth.signInWithEmailAndPassword], authData.email, authData.password))

expect(gen.next(mockUser).value).toEqual(put({
type: SIGN_IN_SUCCESS,
payload: {user: mockUser}
}))

expect(gen.next().value).toEqual(put(reset('auth')));
})

it('should sign in with error', () => {
const authData = {
email: 'test@test.com',
password: '12345678'
}

const mockError = new Error('error');

const auth = firebase.auth()

const requestAction = signIn(authData)

const gen = signInSaga(requestAction)

expect(gen.next().value).toEqual(take(SIGN_IN_START))

expect(gen.next({payload: authData}).value).toEqual(call([auth, auth.signInWithEmailAndPassword], authData.email, authData.password))

expect(gen.throw(mockError).value).toEqual(put({
type: SIGN_IN_ERROR,
payload: {error: mockError}
}))
})

/**
* Sign up
* */

it('should sign up successfully', () => {
const authData = {
email: 'test@test.com',
password: '12345678'
}

const mockUser = {
name: 'Ivan',
age: 22
}

const auth = firebase.auth()

const requestAction = signUp(authData)

const gen = signUpSaga(requestAction)

expect(gen.next().value).toEqual(take(SIGN_UP_START))

expect(gen.next({payload: authData}).value).toEqual(call([auth, auth.createUserWithEmailAndPassword], authData.email, authData.password))

expect(gen.next(mockUser).value).toEqual(put({
type: SIGN_UP_SUCCESS,
payload: {user: mockUser}
}))

expect(gen.next().value).toEqual(put(reset('auth')));
})

it('should sign up with error', () => {
const authData = {
email: 'test@test.com',
password: '12345678'
}

const mockError = new Error('error');

const auth = firebase.auth()

const requestAction = signUp(authData)

const gen = signUpSaga(requestAction)

expect(gen.next().value).toEqual(take(SIGN_UP_START))

expect(gen.next({payload: authData}).value).toEqual(call([auth, auth.createUserWithEmailAndPassword], authData.email, authData.password))

expect(gen.throw(mockError).value).toEqual(put({
type: SIGN_UP_ERROR,
payload: {error: mockError}
}))
})


/**
* Redirect
* */

it('should redirect after successful login', () => {
const gen = redirectSaga()

expect(gen.next().value).toEqual(take(SIGN_IN_SUCCESS));

expect(gen.next().value).toEqual(put(push('/people')))
})


3 changes: 3 additions & 0 deletions src/ducks/people.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {appName} from '../config'
import {Record, List} from 'immutable'
import {put, call, takeEvery} from 'redux-saga/effects'
import {generateId} from './utils'
import {reset} from 'redux-form';

/**
* Constants
Expand Down Expand Up @@ -66,6 +67,8 @@ export function * addPersonSaga(action) {
console.log('---', effect)

yield effect

yield put(reset('person'))
}

export function * saga() {
Expand Down