Skip to content
Open
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
9 changes: 9 additions & 0 deletions admin/src/components/common/loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react'

function Loader() {
return <h1>Loading...</h1>
}

Loader.propTypes = {}

export default Loader
40 changes: 40 additions & 0 deletions admin/src/components/event/event-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { Component } from 'react'
import { connect } from 'react-redux'
import {
loadAllEvents,
eventSelector,
loadingEventsSelector
} from '../../ducks/event'
import Event from './event'
import Loader from '../common/loader'

class EventList extends Component {
static propTypes = {}

constructor(props) {
super(props)
props.fetchData && props.fetchData()
}

render() {
const { events, loading } = this.props
if (loading) return <Loader />
return (
<ul>
{events.map((event, key) => (
<li key={key}>
<Event event={event} />
</li>
))}
</ul>
)
}
}

export default connect(
(state) => ({
events: eventSelector(state),
loading: loadingEventsSelector(state)
}),
{ fetchData: loadAllEvents }
)(EventList)
31 changes: 31 additions & 0 deletions admin/src/components/event/event.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'

class Event extends Component {
static propTypes = {
event: PropTypes.shape({
month: PropTypes.string,
submissionDeadline: PropTypes.string,
title: PropTypes.string,
url: PropTypes.string,
where: PropTypes.string,
when: PropTypes.string
}).isRequired
}

render() {
const { title, url, where, when } = this.props.event
return (
<div>
<a target="_blank" href={url}>
{title}
</a>
<div>
{where}, {when}
</div>
</div>
)
}
}

export default Event
6 changes: 3 additions & 3 deletions admin/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { initializeApp } from 'firebase/app'
import 'firebase/auth'
import 'firebase/database'

export const appName = 'adv-react-25-06'
export const appName = 'advreact2506'

const config = {
apiKey: 'AIzaSyDzqwnZ_39QyqhxYZVPjVH8eBww7DUBmVc',
apiKey: 'AIzaSyASXmuELKMXGJMQYvkdcuVCsYRTpzjED8U',
authDomain: `${appName}.firebaseapp.com`,
databaseURL: `https://${appName}.firebaseio.com`,
projectId: appName,
storageBucket: '',
messagingSenderId: '874599443389'
messagingSenderId: '983731384962'
}

initializeApp(config)
158 changes: 158 additions & 0 deletions admin/src/ducks/auth.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { call, put, take, apply } from 'redux-saga/effects'
Copy link
Owner

Choose a reason for hiding this comment

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

Можно бы еще редюсер протестить

import {
SIGN_UP_ERROR,
SIGN_UP_REQUEST,
SIGN_UP_SUCCESS,
SIGN_IN_REQUEST,
signUpSaga,
signInSaga,
signIn,
SIGN_IN_ERROR,
SIGN_IN_MAX_TRIES_ERROR
} from './auth'
import firebase from 'firebase/app'

describe('signUpSaga', () => {
it('should signup success', () => {
const user = {
email: 'test@javascript.ru',
password: '12345678'
}
const action = {
type: SIGN_UP_REQUEST,
payload: { ...user }
}

const saga = signUpSaga(action)

const auth = firebase.auth()
expect(saga.next().value).toEqual(
call(
[auth, auth.createUserWithEmailAndPassword],
user.email,
user.password
)
)

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

expect(saga.next().done).toBe(true)
})
it('should signup error', () => {
const user = {
email: 'test@javascript.ru',
password: '12345678'
}
const action = {
type: SIGN_UP_REQUEST,
payload: { ...user }
}

const saga = signUpSaga(action)

const auth = firebase.auth()
expect(saga.next().value).toEqual(
call(
[auth, auth.createUserWithEmailAndPassword],
user.email,
user.password
)
)

const error = 'error'
expect(saga.throw(error).value).toEqual(
put({
type: SIGN_UP_ERROR,
error: error
})
)

expect(saga.next().done).toBe(true)
})
})

describe('signInSaga', () => {
it('should signin success', () => {
const user = {
email: 'test@javascript.ru',
password: '12345678'
}

const saga = signInSaga()

const auth = firebase.auth()
expect(saga.next().value).toEqual(take(SIGN_IN_REQUEST))
signIn(user.email, user.password)
expect(
saga.next({
type: SIGN_IN_REQUEST,
payload: user
}).value
).toEqual(
apply(auth, auth.signInWithEmailAndPassword, [user.email, user.password])
)

expect(saga.next().value).toEqual(take(SIGN_IN_REQUEST))
})

it('should signin error if invalid credentials', () => {
const user = {
email: 'test@javascript.ru',
password: '12345678'
}

const saga = signInSaga()

const auth = firebase.auth()
expect(saga.next().value).toEqual(take(SIGN_IN_REQUEST))
signIn(user.email, user.password)

expect(
saga.next({
type: SIGN_IN_REQUEST,
payload: user
}).value
).toEqual(
apply(auth, auth.signInWithEmailAndPassword, [user.email, user.password])
)

const error = 'error'
expect(saga.throw(error).value).toEqual(
put({
type: SIGN_IN_ERROR,
error: error
})
)

expect(saga.next().value).toEqual(take(SIGN_IN_REQUEST))
})
it('should signin error if more then 3 times', () => {
const user = {
email: 'test@javascript.ru',
password: '12345678'
}

const saga = signInSaga()

const auth = firebase.auth()
for (let i = 0; i < 3; i++) {
expect(saga.next().value).toEqual(take(SIGN_IN_REQUEST))
signIn(user.email, user.password)
saga.next({
type: SIGN_IN_REQUEST,
payload: user
})
}

expect(saga.next().value).toEqual(
put({
type: SIGN_IN_MAX_TRIES_ERROR
})
)
})
})
103 changes: 103 additions & 0 deletions admin/src/ducks/event.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { appName } from '../config'
import { Record, List } from 'immutable'
import { createSelector } from 'reselect'
import { takeEvery, call, put } from 'redux-saga/effects'
import firebase from 'firebase/app'
import Immutable from 'immutable'

/**
* Constants
* */
export const moduleName = 'event'
const prefix = `${appName}/${moduleName}`
export const LOAD_ALL_EVENTS = `${prefix}/LOAD_ALL_EVENTS`
export const LOAD_ALL_EVENTS_SUCCESS = `${prefix}/LOAD_ALL_EVENTS_SUCCESS`
export const LOAD_ALL_EVENTS_ERROR = `${prefix}/LOAD_ALL_EVENTS_ERROR`
export const LOAD_ALL_EVENTS_START = `${prefix}/LOAD_ALL_EVENTS_START`

/**
* Reducer
* */
const ReducerState = Record({
entities: new List([]),
loading: false,
error: null
})

const EventRecord = Record({
id: null,
title: null,
url: null,
where: null,
when: null,
submissionDeadline: null,
month: null
})

export default function reducer(state = new ReducerState(), action) {
const { type, payload } = action

switch (type) {
case LOAD_ALL_EVENTS_START:
return state.set('loading', true)
case LOAD_ALL_EVENTS_SUCCESS:
return state.set('entities', payload.events).set('loading', false)

default:
return state
}
}

/**
* Action Creators
* */

export function loadAllEvents() {
return {
type: LOAD_ALL_EVENTS,
payload: {}
}
}

/**
* Selectors
* */
export const stateSelector = (state) => state[moduleName]
export const eventSelector = createSelector(stateSelector, (state) => {
return state.entities.valueSeq().toArray()
})
export const loadingEventsSelector = createSelector(
stateSelector,
(state) => state.loading
)

/**
* Sagas
*/
export function* loadAllEventsSaga(action) {
yield put({
type: LOAD_ALL_EVENTS_START,
payload: { loading: true, events: new List([]) }
})
const eventsRef = firebase.database().ref('/events')
try {
const eventsResponse = yield call([eventsRef, eventsRef.once], 'value')
const events = Immutable.Map(eventsResponse.val()).reduce(
Copy link
Owner

Choose a reason for hiding this comment

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

я бы такое в редюсере делал, а еще лучше - так бы и хранил

(acc, item) => acc.push(new EventRecord(item)),
new List([])
)
yield put({
type: LOAD_ALL_EVENTS_SUCCESS,
payload: { loading: false, events: events }
})
} catch (e) {
yield put({
type: LOAD_ALL_EVENTS_ERROR,
payload: { loading: false, error: e, events: new List([]) }
})
}
}

export function* saga() {
yield takeEvery(LOAD_ALL_EVENTS, loadAllEventsSaga)
}
8 changes: 8 additions & 0 deletions admin/src/mocks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,12 @@ export function saveEventsToFB() {
conferences.forEach((conference) => eventsRef.push(conference))
}

export function readEventsFromFB() {
const eventsRef = firebase.database().ref('/events')
eventsRef.once('value').then(function(snapshot) {
return snapshot.val()
})
}

window.saveEventsToFB = saveEventsToFB
window.readEventsFromFB = readEventsFromFB
4 changes: 3 additions & 1 deletion admin/src/redux/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import { combineReducers } from 'redux'
import { reducer as form } from 'redux-form'
import authReducer, { moduleName as authModule } from '../ducks/auth'
import peopleReducer, { moduleName as peopleModule } from '../ducks/people'
import EventReducer, { moduleName as eventModule } from '../ducks/event'

export default combineReducers({
form,
[authModule]: authReducer,
[peopleModule]: peopleReducer
[peopleModule]: peopleReducer,
[eventModule]: EventReducer
})
Loading