Uploading new user...
+ return (
+ users.length ?
+
Sign In
@@ -39,7 +41,10 @@ const validate = ({ email, password }) => {
return errors
}
-export default reduxForm({
+export default connect(state => ({
+ loading: loadingSelector(state),
+ authError: errorSelector(state)
+}))(reduxForm({
form: 'auth',
validate
-})(SignUpForm)
\ No newline at end of file
+})(SignUpForm))
\ No newline at end of file
diff --git a/admin-panel/src/components/common/ErrorField.js b/admin-panel/src/components/common/ErrorField.js
index e9b16d5..50fe711 100644
--- a/admin-panel/src/components/common/ErrorField.js
+++ b/admin-panel/src/components/common/ErrorField.js
@@ -1,20 +1,15 @@
-import React, { Component } from 'react'
-
-class ErrorField extends Component {
- static propTypes = {
-
- };
-
- render() {
- const {input, meta: { error, touched }, type} = this.props
- const errorMessage = error && touched &&
{error}
- return (
-
-
- {errorMessage}
-
- )
- }
+import React from 'react'
+
+function ErrorField(props) {
+ const {label, input, type, meta: {error, touched}} = props
+ const errorText = touched && error &&
{error}
+ return (
+
+ {label || input.name}
+
+ {errorText}
+
+ )
}
export default ErrorField
\ No newline at end of file
diff --git a/admin-panel/src/components/common/Loader.js b/admin-panel/src/components/common/Loader.js
new file mode 100644
index 0000000..9418787
--- /dev/null
+++ b/admin-panel/src/components/common/Loader.js
@@ -0,0 +1,12 @@
+import React from 'react'
+
+function Loader() {
+ return (
+
Loading...
+ )
+}
+
+Loader.propTypes = {
+}
+
+export default Loader
\ No newline at end of file
diff --git a/admin-panel/src/components/events/EventsTable.js b/admin-panel/src/components/events/EventsTable.js
new file mode 100644
index 0000000..432e7a1
--- /dev/null
+++ b/admin-panel/src/components/events/EventsTable.js
@@ -0,0 +1,41 @@
+import React, { Component } from 'react'
+import {connect} from 'react-redux'
+import {fetchAllEvents, selectEvent, eventListSelector, loadedSelector, loadingSelector} from '../../ducks/events'
+import Loader from '../common/Loader'
+
+export class EventsTable extends Component {
+ static propTypes = {
+
+ };
+
+ componentDidMount() {
+ this.props.fetchAllEvents()
+ }
+
+ render() {
+ if (this.props.loading) return
+ return (
+
+ )
+ }
+
+ getRows = () => this.props.events.map(this.getRow)
+
+ getRow = (event) => (
+
this.props.selectEvent(event.uid)}>
+ {event.title}
+ {event.when}
+ {event.where}
+
+ )
+}
+
+export default connect((state) => ({
+ events: eventListSelector(state),
+ loading: loadingSelector(state),
+ loaded: loadedSelector(state)
+}), { fetchAllEvents, selectEvent })(EventsTable)
\ No newline at end of file
diff --git a/admin-panel/src/components/events/EventsTable.test.js b/admin-panel/src/components/events/EventsTable.test.js
new file mode 100644
index 0000000..4cf75c1
--- /dev/null
+++ b/admin-panel/src/components/events/EventsTable.test.js
@@ -0,0 +1,48 @@
+import React from 'react'
+import {shallow} from 'enzyme'
+import events from '../../mocks/conferences'
+
+import {EventsTable} from './EventsTable'
+import Loader from '../common/Loader'
+
+const eventList = events.map(event => ({...event, uid: Math.random()}))
+
+describe('Events Table', () => {
+ it('should render a loader', () => {
+ const table = shallow(
, { disableLifecycleMethods: true })
+
+ expect(table.contains(
))
+ });
+
+ it('should render N rows', () => {
+ const table = shallow(
, { disableLifecycleMethods: true })
+
+ expect(table.find('.test__event_table_row').length).toBe(eventList.length)
+ });
+
+ it('should request fetch all events', function (done) {
+ shallow(
done()}
+ />)
+ });
+
+ it('should select an event', () => {
+ let selected = null
+
+ const table = shallow( selected = uid}
+ />, { disableLifecycleMethods: true })
+
+ table.find('.test__event_table_row').first().simulate('click')
+
+ expect(selected).toEqual(eventList[0].uid)
+
+ });
+
+});
\ No newline at end of file
diff --git a/admin-panel/src/components/events/EventsTableVirtualized.js b/admin-panel/src/components/events/EventsTableVirtualized.js
new file mode 100644
index 0000000..c4f8c3e
--- /dev/null
+++ b/admin-panel/src/components/events/EventsTableVirtualized.js
@@ -0,0 +1,55 @@
+import React, { Component } from 'react'
+import {connect} from 'react-redux'
+import {fetchAllEvents, selectEvent, eventListSelector, loadedSelector, loadingSelector} from '../../ducks/events'
+import Loader from '../common/Loader'
+import {Table, Column} from 'react-virtualized'
+import 'react-virtualized/styles.css'
+
+export class EventsTableVirtualized extends Component {
+ static propTypes = {
+
+ };
+
+ componentDidMount() {
+ this.props.fetchAllEvents()
+ }
+
+ render() {
+ if (this.props.loading) return
+ return (
+
+ )
+ }
+
+ rowGetter = ({ index }) => this.props.events[index]
+}
+
+export default connect((state) => ({
+ events: eventListSelector(state),
+ loading: loadingSelector(state),
+ loaded: loadedSelector(state)
+}), { fetchAllEvents, selectEvent })(EventsTableVirtualized)
\ No newline at end of file
diff --git a/admin-panel/src/components/people/NewPersonForm.js b/admin-panel/src/components/people/NewPersonForm.js
new file mode 100644
index 0000000..6707eb7
--- /dev/null
+++ b/admin-panel/src/components/people/NewPersonForm.js
@@ -0,0 +1,40 @@
+import React, { Component } from 'react'
+import {reduxForm, Field} from 'redux-form'
+import validateEmail from 'email-validator'
+import ErrorField from '../common/ErrorField'
+
+class NewPersonForm extends Component {
+ static propTypes = {
+
+ };
+
+ render() {
+ return (
+
+ )
+ }
+}
+
+function validate({firstName, email}) {
+ const errors = {}
+ if (!firstName) errors.firstName = 'first name is required'
+
+ if (!email) errors.email = 'email is required'
+ else if (!validateEmail.validate(email)) errors.email = 'email is invalid'
+
+ return errors
+}
+
+export default reduxForm({
+ form: 'person',
+ validate
+})(NewPersonForm)
\ No newline at end of file
diff --git a/admin-panel/src/components/people/PeopleList.js b/admin-panel/src/components/people/PeopleList.js
new file mode 100644
index 0000000..1fe2549
--- /dev/null
+++ b/admin-panel/src/components/people/PeopleList.js
@@ -0,0 +1,44 @@
+import React, { Component } from 'react'
+import {connect} from 'react-redux'
+import {peopleListSelector} from '../../ducks/people'
+import {List} from 'react-virtualized'
+import 'react-virtualized/styles.css'
+
+class PeopleList extends Component {
+ static propTypes = {
+
+ };
+
+ render() {
+ return
+
+ }
+
+ rowRenderer = ({ style, index, key }) => {
+ const person = this.props.people[index]
+ return (
+
+
{person.firstName} {person.lastName}
+ {person.email}
+
+ )
+ }
+
+ getRow = (person) => (
+
+ {person.firstName}
+ {person.lastName}
+ {person.email}
+
+ )
+}
+
+export default connect((state) => ({
+ people: peopleListSelector(state)
+}))(PeopleList)
\ No newline at end of file
diff --git a/admin-panel/src/components/people/PeopleTable.js b/admin-panel/src/components/people/PeopleTable.js
new file mode 100644
index 0000000..c658acf
--- /dev/null
+++ b/admin-panel/src/components/people/PeopleTable.js
@@ -0,0 +1,33 @@
+import React, { Component } from 'react'
+import {connect} from 'react-redux'
+import {peopleListSelector} from '../../ducks/people'
+
+class PeopleTable extends Component {
+ static propTypes = {
+
+ };
+
+ render() {
+ return (
+
+ )
+ }
+
+ getRows = () => this.props.people.map(this.getRow)
+
+ getRow = (person) => (
+
+ {person.firstName}
+ {person.lastName}
+ {person.email}
+
+ )
+}
+
+export default connect((state) => ({
+ people: peopleListSelector(state)
+}))(PeopleTable)
\ No newline at end of file
diff --git a/admin-panel/src/components/routes/EventsPage.js b/admin-panel/src/components/routes/EventsPage.js
new file mode 100644
index 0000000..eedf79d
--- /dev/null
+++ b/admin-panel/src/components/routes/EventsPage.js
@@ -0,0 +1,18 @@
+import React, { Component } from 'react'
+import EventsTableVirtualized from '../events/EventsTableVirtualized'
+
+class EventsPage extends Component {
+ static propTypes = {
+
+ };
+
+ render() {
+ return (
+
+
+
+ )
+ }
+}
+
+export default EventsPage
\ No newline at end of file
diff --git a/admin-panel/src/components/routes/PersonPage.js b/admin-panel/src/components/routes/PersonPage.js
new file mode 100644
index 0000000..9bf8df9
--- /dev/null
+++ b/admin-panel/src/components/routes/PersonPage.js
@@ -0,0 +1,23 @@
+import React, { Component } from 'react'
+import {connect} from 'react-redux'
+import {addPerson} from '../../ducks/people'
+import NewPersonForm from '../people/NewPersonForm'
+import PeopleList from '../people/PeopleList'
+
+class PersonPage extends Component {
+ static propTypes = {
+
+ };
+
+ render() {
+ return (
+
+ )
+ }
+}
+
+export default connect(null, {addPerson})(PersonPage)
\ No newline at end of file
diff --git a/admin-panel/src/components/routes/Users.js b/admin-panel/src/components/routes/Users.js
new file mode 100644
index 0000000..82dd334
--- /dev/null
+++ b/admin-panel/src/components/routes/Users.js
@@ -0,0 +1,24 @@
+import React, { Component } from 'react'
+import {Route, NavLink} from 'react-router-dom'
+import {connect} from 'react-redux'
+import {addUser} from '../../ducks/users'
+import UsersList from '../Users'
+
+class Users extends Component {
+ render() {
+ return (
+
+ )
+ }
+
+ onAddUser = ({firstName, lastName, email}) => this.props.addUser({firstName, lastName, email})
+
+}
+
+export default connect(null, { addUser })(Users)
\ No newline at end of file
diff --git a/admin-panel/src/config.js b/admin-panel/src/config.js
index 65bba00..a24ff65 100644
--- a/admin-panel/src/config.js
+++ b/admin-panel/src/config.js
@@ -1,14 +1,14 @@
import firebase from 'firebase'
-export const appName = 'advreact-04-12'
+export const appName = 'react-adv'
const config = {
- apiKey: "AIzaSyCmDWlgYIhtEr1pWjgKYds3iXKWBl9wbjE",
+ apiKey: "AIzaSyAs8-oh5yTEUxC5KQSOSZpaE8xReLZk0qQ",
authDomain: `${appName}.firebaseapp.com`,
databaseURL: `https://${appName}.firebaseio.com`,
projectId: appName,
- storageBucket: "",
- messagingSenderId: "95255462276"
+ storageBucket: `${appName}.appspot.com`,
+ messagingSenderId: "857981968367"
}
firebase.initializeApp(config)
\ No newline at end of file
diff --git a/admin-panel/src/ducks/auth.js b/admin-panel/src/ducks/auth.js
index f031871..92ed143 100644
--- a/admin-panel/src/ducks/auth.js
+++ b/admin-panel/src/ducks/auth.js
@@ -1,6 +1,9 @@
+import {all, takeEvery, take, put, apply, call} from 'redux-saga/effects'
import {appName} from '../config'
+import {createSelector} from 'reselect'
import {Record} from 'immutable'
import firebase from 'firebase'
+import {replace} from 'react-router-redux'
/**
* Constants
@@ -8,10 +11,15 @@ import firebase from 'firebase'
export const moduleName = 'auth'
const prefix = `${appName}/${moduleName}`
+export const SIGN_IN_REQUEST = `${prefix}/SIGN_IN_REQUEST`
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`
+
+export const SIGN_UP_REQUEST = `${prefix}/SIGN_UP_REQUEST`
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`
/**
* Reducer
@@ -28,13 +36,22 @@ export default function reducer(state = new ReducerRecord(), action) {
switch (type) {
case SIGN_IN_START:
case SIGN_UP_START:
- return state.set('loading', true)
+ return state
+ .set('error', null)
+ .set('loading', true)
case SIGN_IN_SUCCESS:
case SIGN_UP_SUCCESS:
return state
.set('loading', false)
.set('user', payload.user)
+
+ case SIGN_IN_ERROR:
+ case SIGN_UP_ERROR:
+ return state
+ .set('loading', false)
+ .set('error', payload.error.message)
+
default:
return state
}
@@ -44,43 +61,94 @@ export default function reducer(state = new ReducerRecord(), action) {
* Selectors
* */
-export const userSelector = state => state[moduleName].user
+export const stateSelector = state => state[moduleName]
+export const userSelector = createSelector(stateSelector, state => state.user)
+export const errorSelector = createSelector(stateSelector, state => state.error)
+export const loadingSelector = createSelector(stateSelector, state => state.loading)
/**
* Action Creators
* */
-export function signIn(email, password) {
- return (dispatch) => {
- dispatch({
- type: SIGN_IN_START
- })
-
- firebase.auth().signInWithEmailAndPassword(email, password)
- .then(user => dispatch({
- type: SIGN_IN_SUCCESS,
- payload: { user }
- }))
+export function signUp(email, password) {
+ return {
+ type: SIGN_UP_REQUEST,
+ payload: { email, password }
}
}
-export function signUp(email, password) {
- return (dispatch) => {
- dispatch({
- type: SIGN_UP_START
- })
- firebase.auth().createUserWithEmailAndPassword(email, password)
- .then(user => dispatch({
- type: SIGN_UP_SUCCESS,
- payload: { user }
- }))
+export function signIn(email, password) {
+ return {
+ type: SIGN_IN_REQUEST,
+ payload: { email, password }
}
}
+
firebase.auth().onAuthStateChanged(user => {
if (user) window.store.dispatch({
type: SIGN_IN_SUCCESS,
payload: { user }
})
-})
\ No newline at end of file
+})
+
+/**
+ * Sagas
+ */
+
+export const signUpSaga = function * () {
+ while (true) {
+ const action = yield take(SIGN_UP_REQUEST)
+ const {email, password} = action.payload
+
+ yield put({
+ type: SIGN_UP_START
+ })
+
+ try {
+ const auth = firebase.auth()
+ yield call([auth, auth.createUserWithEmailAndPassword], email, password)
+ } catch (error) {
+ yield put({
+ type: SIGN_UP_ERROR,
+ payload: {error}
+ })
+ }
+ }
+}
+
+export const signInSaga = function * (action) {
+ const { email, password } = action.payload
+
+ yield put({
+ type: SIGN_IN_START
+ })
+
+ try {
+ const auth = firebase.auth()
+ yield apply(auth, auth.signInWithEmailAndPassword, [email, password])
+ } catch (error) {
+ yield put({
+ type: SIGN_IN_ERROR,
+ payload: { error }
+ })
+ }
+}
+
+export function * watchStatusChangeSaga() {
+ while (true) {
+ yield take(SIGN_IN_SUCCESS)
+
+ yield (put(replace('/events')))
+ }
+}
+
+
+export const saga = function * () {
+ yield all([
+ takeEvery(SIGN_IN_REQUEST, signInSaga),
+ signUpSaga(),
+ watchStatusChangeSaga()
+ ])
+}
\ No newline at end of file
diff --git a/admin-panel/src/ducks/auth.test.js b/admin-panel/src/ducks/auth.test.js
new file mode 100644
index 0000000..ab502c2
--- /dev/null
+++ b/admin-panel/src/ducks/auth.test.js
@@ -0,0 +1,110 @@
+import firebase from 'firebase'
+import reducer, {
+ signUpSaga, signInSaga, watchStatusChangeSaga,
+ SIGN_UP_REQUEST, SIGN_UP_START, SIGN_UP_SUCCESS, SIGN_UP_ERROR,
+ SIGN_IN_REQUEST, SIGN_IN_START, SIGN_IN_SUCCESS, SIGN_IN_ERROR,
+ ReducerRecord
+} from './auth'
+import {take, call, put} from 'redux-saga/effects'
+import {replace} from 'react-router-redux'
+
+/**
+ * Saga tests
+ * */
+
+it('should sign up', () => {
+ const saga = signUpSaga()
+ const auth = firebase.auth()
+ const authData = {
+ email: 'lala@example.com',
+ password: '12341234'
+ }
+
+ const user = {
+ email: authData.email,
+ uid: Math.random().toString()
+ }
+
+ const requestAction = {
+ type: SIGN_UP_REQUEST,
+ payload: authData
+ }
+
+ expect(saga.next().value).toEqual(take(SIGN_UP_REQUEST))
+
+ expect(saga.next(requestAction).value).toEqual(put({type: SIGN_UP_START}))
+
+ expect(saga.next(requestAction).value).toEqual(call(
+ [auth, auth.createUserWithEmailAndPassword],
+ authData.email, authData.password
+ ))
+
+ const error = new Error
+
+ expect(saga.throw(error).value).toEqual(put({
+ type: SIGN_UP_ERROR,
+ payload: {error}
+ }))
+})
+
+it('should sign in', () => {
+ const auth = firebase.auth()
+ const authData = {
+ email: 'lala@example.com',
+ password: '12341234'
+ }
+
+ const user = {
+ email: authData.email,
+ uid: Math.random().toString()
+ }
+
+ const requestAction = {
+ type: SIGN_IN_REQUEST,
+ payload: authData
+ }
+
+ const saga = signInSaga(requestAction)
+
+ expect(saga.next().value).toEqual(put({type: SIGN_IN_START}))
+
+ expect(saga.next().value).toEqual(call(
+ [auth, auth.signInWithEmailAndPassword],
+ authData.email, authData.password
+ ))
+
+ const error = new Error
+
+ expect(saga.throw(error).value).toEqual(put({
+ type: SIGN_IN_ERROR,
+ payload: {error}
+ }))
+})
+
+it('should redirect', () => {
+ const saga = watchStatusChangeSaga()
+
+ expect(saga.next().value).toEqual(take(SIGN_IN_SUCCESS))
+
+ expect(saga.next().value).toEqual(put(replace('/events')))
+})
+
+/**
+ * Reducer Tests
+ * */
+
+it('should sign in', () => {
+ const state = new ReducerRecord()
+ const user = {
+ email: 'lala@example.com',
+ uid: Math.random().toString()
+ }
+
+ const newState = reducer(state, {
+ type: SIGN_IN_SUCCESS,
+ payload: {user}
+ })
+
+ expect(newState).toEqual(new ReducerRecord({user}))
+})
+
diff --git a/admin-panel/src/ducks/events.js b/admin-panel/src/ducks/events.js
new file mode 100644
index 0000000..f13e342
--- /dev/null
+++ b/admin-panel/src/ducks/events.js
@@ -0,0 +1,116 @@
+import {all, takeEvery, put, call} from 'redux-saga/effects'
+import {appName} from '../config'
+import {Record, OrderedSet, OrderedMap} from 'immutable'
+import firebase from 'firebase'
+import {createSelector} from 'reselect'
+import {fbToEntities} from './utils'
+
+/**
+ * Constants
+ * */
+export const moduleName = 'events'
+const prefix = `${appName}/${moduleName}`
+
+export const FETCH_ALL_REQUEST = `${prefix}/FETCH_ALL_REQUEST`
+export const FETCH_ALL_START = `${prefix}/FETCH_ALL_START`
+export const FETCH_ALL_SUCCESS = `${prefix}/FETCH_ALL_SUCCESS`
+
+export const SELECT = `${prefix}/SELECT`
+
+/**
+ * Reducer
+ * */
+export const ReducerRecord = Record({
+ loading: false,
+ loaded: false,
+ selected: new OrderedSet(),
+ entities: new OrderedMap({})
+})
+
+export const EventRecord = Record({
+ uid: null,
+ month: null,
+ submissionDeadline: null,
+ title: null,
+ url: null,
+ when: null,
+ where: null
+})
+
+export default function reducer(state = new ReducerRecord(), action) {
+ const {type, payload} = action
+
+ switch (type) {
+ case FETCH_ALL_START:
+ return state.set('loading', true)
+
+ case FETCH_ALL_SUCCESS:
+ return state
+ .set('loading', false)
+ .set('loaded', true)
+ .set('entities', fbToEntities(payload, EventRecord))
+
+ case SELECT:
+ return state.update('selected', selected => selected.has(payload.uid)
+ ? selected.remove(payload.uid)
+ : selected.add(payload.uid)
+ )
+
+ default:
+ return state
+ }
+}
+
+/**
+ * Selectors
+ * */
+
+export const stateSelector = state => state[moduleName]
+export const entitiesSelector = createSelector(stateSelector, state => state.entities)
+export const loadingSelector = createSelector(stateSelector, state => state.loading)
+export const loadedSelector = createSelector(stateSelector, state => state.loaded)
+export const eventListSelector = createSelector(entitiesSelector, entities => entities.valueSeq().toArray())
+
+/**
+ * Action Creators
+ * */
+
+export function fetchAllEvents() {
+ return {
+ type: FETCH_ALL_REQUEST
+ }
+}
+
+export function selectEvent(uid) {
+ return {
+ type: SELECT,
+ payload: { uid }
+ }
+}
+
+/**
+ * Sagas
+ * */
+
+export function* fetchAllSaga() {
+ const ref = firebase.database().ref('events')
+
+ yield put({
+ type: FETCH_ALL_START
+ })
+
+ const snapshot = yield call([ref, ref.once], 'value')
+
+ console.log('---', snapshot)
+
+ yield put({
+ type: FETCH_ALL_SUCCESS,
+ payload: snapshot.val()
+ })
+}
+
+export function* saga() {
+ yield all([
+ takeEvery(FETCH_ALL_REQUEST, fetchAllSaga)
+ ])
+}
\ No newline at end of file
diff --git a/admin-panel/src/ducks/people.js b/admin-panel/src/ducks/people.js
new file mode 100644
index 0000000..9a5f996
--- /dev/null
+++ b/admin-panel/src/ducks/people.js
@@ -0,0 +1,81 @@
+import {appName} from '../config'
+import {Record, OrderedMap} from 'immutable'
+import {createSelector} from 'reselect'
+import {put, call, all, takeEvery} from 'redux-saga/effects'
+import {reset} from 'redux-form'
+import {generateId} from './utils'
+
+/**
+ * Constants
+ * */
+export const moduleName = 'people'
+const prefix = `${appName}/${moduleName}`
+export const ADD_PERSON = `${prefix}/ADD_PERSON`
+export const ADD_PERSON_SUCCESS = `${prefix}/ADD_PERSON_SUCCESS`
+
+/**
+ * Reducer
+ * */
+const ReducerState = Record({
+ entities: new OrderedMap({})
+})
+
+const PersonRecord = Record({
+ id: null,
+ firstName: null,
+ lastName: null,
+ email: null
+})
+
+export default function reducer(state = new ReducerState(), action) {
+ const {type, payload} = action
+
+ switch (type) {
+ case ADD_PERSON_SUCCESS:
+ return state.setIn(['entities', payload.uid],new PersonRecord(payload))
+
+ default:
+ return state
+ }
+}
+
+/**
+ * Selectors
+ * */
+export const stateSelector = state => state[moduleName]
+export const entitiesSelector = createSelector(stateSelector, state => state.entities)
+export const peopleListSelector = createSelector(entitiesSelector, entities => entities.valueSeq().toArray())
+
+/**
+ * Action Creators
+ * */
+
+export function addPerson(person) {
+ return {
+ type: ADD_PERSON,
+ payload: { person }
+ }
+}
+
+/**
+ * Sagas
+ */
+
+export const addPersonSaga = function * (action) {
+ const { person } = action.payload
+
+ const uid = yield call(generateId)
+
+ yield put({
+ type: ADD_PERSON_SUCCESS,
+ payload: {uid, ...person}
+ })
+
+ yield put(reset('person'))
+}
+
+export const saga = function * () {
+ yield all([
+ takeEvery(ADD_PERSON, addPersonSaga)
+ ])
+}
\ No newline at end of file
diff --git a/admin-panel/src/ducks/people.test.js b/admin-panel/src/ducks/people.test.js
new file mode 100644
index 0000000..d24f765
--- /dev/null
+++ b/admin-panel/src/ducks/people.test.js
@@ -0,0 +1,35 @@
+import {call, put} from 'redux-saga/effects'
+import {addPersonSaga, ADD_PERSON, ADD_PERSON_SUCCESS} from './people'
+import {reset} from 'redux-form'
+import {generateId} from './utils'
+
+describe('people saga', () => {
+ it('should add person', () => {
+ const person = {
+ firstName: 'Roman',
+ lastName: 'Iakobchuk',
+ email: 'r.iakobchuk@javascript.ru'
+ }
+
+ const action = {
+ type: ADD_PERSON,
+ payload: { person }
+ }
+
+ const generator = addPersonSaga(action)
+
+ expect(generator.next().value).toEqual(call(generateId))
+
+ const uid = generateId()
+
+ expect(generator.next(uid).value).toEqual(put({
+ type: ADD_PERSON_SUCCESS,
+ payload: {uid, ...person}
+ }))
+
+ expect(generator.next().value).toEqual(put(reset('person')))
+
+ expect(generator.next().done).toBe(true)
+
+ });
+});
\ No newline at end of file
diff --git a/admin-panel/src/ducks/users.js b/admin-panel/src/ducks/users.js
new file mode 100644
index 0000000..5ad3ac8
--- /dev/null
+++ b/admin-panel/src/ducks/users.js
@@ -0,0 +1,93 @@
+import {appName} from '../config'
+import {Record} from 'immutable'
+import {arrayToMap} from '../helpers'
+import {createSelector} from 'reselect'
+
+/**
+ * Constants
+ * */
+export const moduleName = 'users'
+const prefix = `${appName}/${moduleName}`
+
+export const ADD_USER_START = `${prefix}/_START`
+export const ADD_USER_SUCCESS = `${prefix}/_SUCCESS`
+
+/**
+ * Reducer
+ * */
+
+const UsersListRecord = Record({
+ id : null,
+ firstName : null,
+ lastName : null,
+ email : null,
+})
+
+const ReducerRecord = Record({
+ entities : arrayToMap([], UsersListRecord),
+ loading : false,
+ loaded : false,
+})
+
+const defaultState = new ReducerRecord();
+
+export default function reducer(state = defaultState, action) {
+ const {type, payload} = action
+
+ switch (type) {
+ case ADD_USER_START : {
+ return state.set('loading', true);
+ }
+ case ADD_USER_SUCCESS : {
+ let {randomId : id, firstName, lastName, email} = payload;
+ state = state.set('loading', false);
+ return state.setIn(['entities', id], new UsersListRecord({
+ id,
+ firstName,
+ lastName,
+ email,
+ }))
+ }
+ default:
+ return state
+ }
+}
+
+/**
+ * Selectors
+ * */
+
+export const usersMapSelector = state => state[moduleName].entities
+
+export const usersSelector = createSelector(usersMapSelector, usersMap => usersMap.valueSeq().toArray())
+
+export const usersLoadingSelector = state => state[moduleName].loading
+
+/**
+ * Action Creators
+ * */
+
+export const addUser = (params) => {
+ let {firstName, lastName, email} = params;
+ return (dispatch) => {
+ dispatch({
+ type : ADD_USER_START,
+ });
+ new Promise((resolve) => {
+ setTimeout(() => {
+ resolve()
+ }, 3000)
+ }).then(() => {
+ dispatch({
+ type : ADD_USER_SUCCESS,
+ payload : {
+ generateId : true,
+ firstName,
+ lastName,
+ email
+ }
+ })
+ })
+
+ }
+}
\ No newline at end of file
diff --git a/admin-panel/src/ducks/utils.js b/admin-panel/src/ducks/utils.js
new file mode 100644
index 0000000..df63cc2
--- /dev/null
+++ b/admin-panel/src/ducks/utils.js
@@ -0,0 +1,13 @@
+import {OrderedMap} from 'immutable'
+
+export function generateId() {
+ return Date.now()
+}
+
+export function fbToEntities(values, DataRecord) {
+ return Object.entries(values)
+ .reduce(
+ (acc, [uid, value]) => acc.set(uid, new DataRecord({ uid, ...value })),
+ new OrderedMap({})
+ )
+}
\ No newline at end of file
diff --git a/admin-panel/src/helpers/index.js b/admin-panel/src/helpers/index.js
new file mode 100644
index 0000000..12f9b51
--- /dev/null
+++ b/admin-panel/src/helpers/index.js
@@ -0,0 +1,10 @@
+import {Map} from 'immutable';
+
+export let arrayToMap = (arr, ItemRecord, idKey = 'id') => {
+ let res = arr.reduce(function (acc, item) {
+ return acc.set(item[idKey], ItemRecord ? new ItemRecord(item) : item);
+ }, new Map({}));
+ return res;
+}
+
+export let getRandomId = () => (Date.now() + Math.random()).toString()
\ No newline at end of file
diff --git a/admin-panel/src/index.js b/admin-panel/src/index.js
index ad60938..adb21d9 100644
--- a/admin-panel/src/index.js
+++ b/admin-panel/src/index.js
@@ -2,5 +2,6 @@ import React from 'react'
import ReactDOM from 'react-dom'
import './config'
import Root from './Root'
+import './mocks'
ReactDOM.render( , document.getElementById('root'))
diff --git a/admin-panel/src/mocks/conferences.js b/admin-panel/src/mocks/conferences.js
new file mode 100644
index 0000000..a5bea14
--- /dev/null
+++ b/admin-panel/src/mocks/conferences.js
@@ -0,0 +1,2384 @@
+export default [
+ {
+ "title": "Agent Conf",
+ "url": "http://www.agent.sh/",
+ "where": "Dornbirn, Austria",
+ "when": "January 20-21, 2017",
+ "month": "January",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "O'Reilly Velocity Conference",
+ "url": "http://conferences.oreilly.com/velocity/vl-ca",
+ "where": "San Jose, CA",
+ "when": "January 19-22, 2017",
+ "month": "January",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Script17",
+ "url": "https://scriptconf.org/",
+ "where": "Linz, Austria",
+ "when": "January 27, 2017",
+ "month": "January",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Agile Content Conf",
+ "url": "https://2017.agilecontentconf.com/",
+ "where": "London, UK",
+ "when": "January 30-31, 2017",
+ "month": "January",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Jfokus",
+ "url": "http://www.jfokus.se/jfokus/",
+ "where": "Stockholm, Sweden",
+ "when": "February 6-8, 2017",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Webstock",
+ "url": "http://www.webstock.org.nz/17/",
+ "where": "Wellington, New Zealand",
+ "when": "February 13-17, 2017",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Sustainable UX",
+ "url": "http://sustainableux.com/",
+ "where": "Online",
+ "when": "February 16, 2017",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "The Rolling Scopes Conference",
+ "url": "https://2017.conf.rollingscopes.com/",
+ "where": "Minsk, Belarus",
+ "when": "February 18-19, 2017",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "The Lead Developer New York",
+ "url": "http://2017.theleaddeveloper-ny.com/",
+ "where": "New York City, US",
+ "when": "February 21, 2017",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Voxxed Days - Zurich",
+ "url": "https://voxxeddays.com/zurich/",
+ "where": "Zurich, Switzerland",
+ "when": "February 23, 2017",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "UX Riga",
+ "url": "http://www.uxriga.lv/",
+ "where": "Riga, Latvia",
+ "when": "February 23, 2017",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Typography Day 2017",
+ "url": "http://www.typoday.in/",
+ "where": "Moratuwa, Sri Lanka",
+ "when": "February 23, 2017",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Voxxed Days - Cern",
+ "url": "https://voxxeddays.com/cern/",
+ "where": "Geneva, Switzerland",
+ "when": "February 25, 2017",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Forward JS",
+ "url": "https://forwardjs.com/",
+ "where": "San Francisco, CA",
+ "when": "March 1st, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Voxxed Days - Bristol",
+ "url": "https://voxxeddays.com/bristol/",
+ "where": "Watershed, Bristol",
+ "when": "March 2nd, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "jDays",
+ "url": "http://www.jdays.se/",
+ "where": "Göteborg, Sweden",
+ "when": "March 7-8, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "A Day of REST",
+ "url": "https://adayofrest.hm/boston-2017/",
+ "where": "Boston, MA",
+ "when": "March 9th, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Voxxed Days - Bucharest",
+ "url": "https://voxxeddays.com/bucharest/",
+ "where": "Bucharest, Romania",
+ "when": "March 10th, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "SXSW",
+ "url": "https://www.sxsw.com",
+ "where": "Austin, Texas",
+ "when": "March 10-19, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "React Conf",
+ "url": "http://conf.reactjs.org/",
+ "where": "Santa Clara, CA",
+ "when": "March 13th-14th, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "SmashingConf Oxford 2017",
+ "url": "https://shop.smashingmagazine.com/products/smashingconf-oxford-2017",
+ "where": "Oxford, England",
+ "when": "March 14th–15th, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JS Remote Conf",
+ "url": "https://devchat.tv/conferences/js-remote-conf-2017",
+ "where": "Online",
+ "when": "March 15th–16th, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "NG-NL",
+ "url": "http://ng-nl.org/",
+ "where": "Amsterdam, Netherlands",
+ "when": "March 16, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Voxxed Days - Vienna",
+ "url": "https://voxxeddays.com/vienna/",
+ "where": "Vienna, Austria",
+ "when": "March 16-17, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Wroc_love.rb - Wrocław",
+ "url": "http://www.wrocloverb.com/",
+ "where": "Wrocław, Poland",
+ "when": "March 17th-19th, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JazzCon.Tech",
+ "url": "http://www.jazzcon.tech/",
+ "where": "New Orleans, USA",
+ "when": "March 20th-22nd, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JSUnconf",
+ "url": "http://2017.jsunconf.eu/",
+ "where": "Hamburg, Germany",
+ "when": "March 25th-26th, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "React London",
+ "url": "https://react.london/",
+ "where": "London, UK",
+ "when": "March 28, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Ember Conf",
+ "url": "http://emberconf.com/",
+ "where": "Portland, OR",
+ "when": "March 28-29, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Render Conf 2017",
+ "url": "http://2017.render-conf.com/",
+ "where": "Oxford, England",
+ "when": "March 30-31, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Design it; Build it",
+ "url": "http://www.dibiconference.com",
+ "where": "Edinburgh, Scotland",
+ "when": "March 30-31, 2017",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "AlterConf",
+ "url": "https://www.alterconf.com/conferences/london-england",
+ "where": "London, UK",
+ "when": "April 1, 2017",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "An Event Apart",
+ "url": "https://aneventapart.com/event/seattle-2017",
+ "where": "Seattle, WA",
+ "when": "April 3-5, 2017",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "26th International World Wide Web Conference, 2017",
+ "url": "http://www.www2017.com.au/",
+ "where": "Perth, Australia",
+ "when": "April 3-7, 2017",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "SmashingConf San Francisco 2017",
+ "url": "https://shop.smashingmagazine.com/products/smashingconf-san-francisco-2017",
+ "where": "San Francisco, United States",
+ "when": "April 4th–5th, 2017",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "ng-conf 2017",
+ "url": "https://www.ng-conf.org/",
+ "where": "Salt Lake City, Utah",
+ "when": "April 5-7, 2017",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Bulgaria Web Summit 2017",
+ "url": "https://bulgariawebsummit.com",
+ "where": "Sofia, Bulgaria",
+ "when": "April 7th–8th, 2017",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "ForwardJS: Ottawa",
+ "url": "https://forwardjs.com/ottawa",
+ "where": "Ottawa, Ontario Canada",
+ "when": "April 6th–8th, 2017",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Front End Design Conference",
+ "url": "https://frontenddesignconference.com/",
+ "where": "St. Petersburg, FL",
+ "when": "April 19-21, 2017",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "React Amsterdam",
+ "url": "http://react-amsterdam.com/",
+ "where": "Amsterdam, NL",
+ "when": "April 21, 2017",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "FITC Toronto",
+ "url": "http://fitc.ca/event/to17/",
+ "where": "Toronto, Canada",
+ "when": "April 23-25, 2017",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Open Vis Conf",
+ "url": "https://openvisconf.com/",
+ "where": "Boston, MA",
+ "when": "April 24-25, 2017",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Serverlessconf",
+ "url": "https://austin.serverlessconf.io/",
+ "where": "Austin, TX",
+ "when": "April 26-28, 2017",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Generate",
+ "url": "https://www.generateconf.com/new-york-2017/",
+ "where": "New York City, NY",
+ "when": "April 27-28, 2017",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "CSSConf EU",
+ "url": "http://2017.cssconf.eu",
+ "where": "Arena Berlin, Germany",
+ "when": "May 5, 2017",
+ "month": "May",
+ "submissionDeadline": "Jan 1st, 2017"
+ },
+ {
+ "title": "Voxxed Days - Ticino",
+ "url": "https://voxxeddays.com/ticino/",
+ "where": "Palazzo dei Congressi, Lugano",
+ "when": "May 6, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JSConf EU",
+ "url": "http://2017.jsconf.eu",
+ "where": "Arena Berlin, Germany",
+ "when": "May 6-7, 2017",
+ "month": "May",
+ "submissionDeadline": "Jan 1st, 2017"
+ },
+ {
+ "title": "OSCON",
+ "url": "http://conferences.oreilly.com/oscon/oscon-tx",
+ "where": "Austin, TX",
+ "when": "May 8-11, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Front",
+ "url": "https://www.frontutah.com/",
+ "where": "Salt Lake City, Utah",
+ "when": "May 9-10, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Angular Summit",
+ "url": "https://angularsummit.com/conference/chicago/2017/05/home",
+ "where": "Chicago, IL",
+ "when": "May 9-11, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Riga Dev Days",
+ "url": "http://rigadevdays.lv/",
+ "where": "Riga, Latvia",
+ "when": "May 15th–17th, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "An Event Apart",
+ "url": "https://aneventapart.com/event/boston-2017",
+ "where": "Boston, MA",
+ "when": "May 15th–17th, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Beyond Tellerrand",
+ "url": "http://beyondtellerrand.com/",
+ "where": "Dusseldorf, Germany",
+ "when": "May 15th–17th, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Voxxed Days - Athens",
+ "url": "https://voxxeddays.com/athens/",
+ "where": "Athens, Greece",
+ "when": "May 18-20, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Syntax",
+ "url": "https://2017.syntaxcon.com/",
+ "where": "North Charleston",
+ "when": "May 18-19, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "React Europe",
+ "url": "https://www.react-europe.org/",
+ "where": "Paris, France",
+ "when": "May 18-19, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "DEVit Conference",
+ "url": "http://devitconf.org/",
+ "where": "Thessaloniki, Greece",
+ "when": "May 20-21, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "GraphQL-Europe",
+ "url": "https://graphql-europe.org/",
+ "where": "Berlin, Germany",
+ "when": "May 21st, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "User Experience Lisbon",
+ "url": "https://www.ux-lx.com/",
+ "where": "Lisbon, Portugal",
+ "when": "May 23-26, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Front-Trends",
+ "url": "https://2017.front-trends.com/",
+ "where": "Warsaw, Poland",
+ "when": "May 24-26, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "UX London",
+ "url": "http://2017.uxlondon.com/",
+ "where": "London, UK",
+ "when": "May 24-26, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Frontend United",
+ "url": "http://frontendunited.org/",
+ "where": "Athens, Greece",
+ "when": "May 26-27, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "NG-Cruise",
+ "url": "https://ngcruise.com/#/",
+ "where": "Miami, Florida",
+ "when": "May 29 - June 2, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "RevolutionConf",
+ "url": "https://www.revolutionconf.com",
+ "where": "Virginia Beach, VA",
+ "when": "June 1-2, 2017",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Voxxed Days - Singapore",
+ "url": "https://voxxeddays.com/singapore/",
+ "where": "Marina Bay Sands, Singapore",
+ "when": "June 2, 2017",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Kerning",
+ "url": "http://2017.kerning.it",
+ "where": "Faenza, Italy",
+ "when": "June 7-9, 2017",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "UX Scotland",
+ "url": "http://uxscotland.net/2017/",
+ "where": "Edinburgh, UK",
+ "when": "June 7-9, 2017",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Webconf.asia",
+ "url": "https://webconf.asia/",
+ "where": "Hong Kong",
+ "when": "June 3, 2017",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Elm Europe",
+ "url": "https://elmeurope.org/",
+ "where": "Paris, France",
+ "when": "June 8-9, 2017",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Generate",
+ "url": "https://www.generateconf.com/",
+ "where": "San Francisco, CA",
+ "when": "June 9, 2017",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "ReactJS Day",
+ "url": "https://www.reactjsday.it",
+ "where": "Verona, Italy",
+ "when": "June 10, 2017",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "SmashingConf",
+ "url": "http://lanyrd.com/2017/smashingconf-new-york/",
+ "where": "New York City, NY",
+ "when": "June 13-14, 2017",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "ConvergeSE",
+ "url": "http://convergese.com/",
+ "where": "Columbia, SC",
+ "when": "June 14-16, 2017",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "DinosaurJS",
+ "url": "http://dinosaurjs.org",
+ "where": "Denver, CO",
+ "when": "June 15, 2017",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "O'Reilly Fluent",
+ "url": "http://conferences.oreilly.com/fluent/fl-ca",
+ "where": "San Jose, CA",
+ "when": "June 19-22, 2017",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "An Event Apart",
+ "url": "https://aneventapart.com/event/washington-dc-2017",
+ "where": "Washington, DC",
+ "when": "July 10-12, 2017",
+ "month": "July",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Design & Content Conference",
+ "url": "http://www.designcontentconf.com/",
+ "where": "Vancouver, BC Canada",
+ "when": "July 17-19, 2017",
+ "month": "July",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "React Rally",
+ "url": "http://www.reactrally.com/",
+ "where": "Salt Lake City, UT",
+ "when": "August 24-25, 2017",
+ "month": "August",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "BrazilJS",
+ "url": "https://braziljs.org/conf/",
+ "where": "Porto Alegre, Brazil",
+ "when": "August 25-26, 2017",
+ "month": "August",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "An Event Apart",
+ "url": "https://aneventapart.com/event/chicago-2017",
+ "where": "Chicago, IL",
+ "when": "August 28-30, 2017",
+ "month": "August",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Frontend Conference Zurich",
+ "url": "https://frontendconf.ch/",
+ "where": "Zurich, Switzerland",
+ "when": "August 31 - September 1, 2017",
+ "month": "August",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Nginx Conf",
+ "url": "https://www.nginx.com/nginxconf/",
+ "where": "Portland, Oregon",
+ "when": "September 6-8, 2017",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "React Native EU",
+ "url": "https://react-native.eu/",
+ "where": "Wroclaw, Poland",
+ "when": "September 6-7, 2017",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "NordicJS",
+ "url": "http://nordicjs.com",
+ "where": "Stockholm, Sweden",
+ "when": "September 7-8, 2017",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Refresh",
+ "url": "http://refresh.rocks/",
+ "where": "Tallinn, Estonia",
+ "when": "September 8, 2017",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "FrontTalks",
+ "url": "http://fronttalks.ru/",
+ "where": "Ekaterinburg, Russia",
+ "when": "September 16-17, 2017",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "SmashingConf Freiburg 2017",
+ "url": "https://shop.smashingmagazine.com/products/smashingconf-freiburg-2017",
+ "where": "Freiburg, Germany",
+ "when": "September 11th–12th, 2017",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Generate",
+ "url": "https://www.generateconf.com/",
+ "where": "London, UK",
+ "when": "September 20–22, 2017",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "React Boston",
+ "url": "http://www.reactboston.com/",
+ "where": "Boston, MA",
+ "when": "September 23–24, 2017",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Web Unleashed 2017",
+ "url": "http://fitc.ca/event/webu17/",
+ "where": "Toronto, Ontario Canada",
+ "when": "September 25th–26th, 2017",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Node.js Interactive North America 2017",
+ "url": "http://events.linuxfoundation.org/events/node-interactive",
+ "where": "Vancouver, BC Canada",
+ "when": "October 4th–6th, 2017",
+ "month": "October",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "GitHub Universe",
+ "url": "https://githubuniverse.com/",
+ "where": "San Francisco, California",
+ "when": "October 10-12, 2017",
+ "month": "October",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "SmashingConf Barcelona 2017",
+ "url": "https://shop.smashingmagazine.com/products/smashingconf-barcelona-2017",
+ "where": "Barcelona, Spain",
+ "when": "October 17th–18th, 2017",
+ "month": "October",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Empire JS",
+ "url": "http://2017.empirejs.org/",
+ "where": "New York City, NY",
+ "when": "October 22, 2017",
+ "month": "October",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Full Stack TO",
+ "url": "http://fsto.co/",
+ "where": "Toronto, Ontario Canada",
+ "when": "October 23-24, 2017",
+ "month": "October",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Revolve Conference",
+ "url": "https://2017.revolveconference.com/",
+ "where": "Charleston, SC",
+ "when": "October 25-27, 2017",
+ "month": "October",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "An Event Apart",
+ "url": "https://aneventapart.com/event/san-francisco-2017",
+ "where": "San Francisco, CA",
+ "when": "October 30- November 1, 2017",
+ "month": "October",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Beyond Tellerrand",
+ "url": "http://beyondtellerrand.com/",
+ "where": "Berlin, Germany",
+ "when": "November 6–8, 2017",
+ "month": "November",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Angular Connect",
+ "url": "http://angularconnect.com/",
+ "where": "Excel, London",
+ "when": "November 7-8, 2017",
+ "month": "November",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "An Event Apart",
+ "url": "https://aneventapart.com/event/denver-2017",
+ "where": "Denver, CO",
+ "when": "December 11-13, 2017",
+ "month": "December",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "WordCamp Europe 2017",
+ "url": "https://2017.europe.wordcamp.org/",
+ "where": "Paris, France",
+ "when": "June 15-17, 2017",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Web Rebels",
+ "url": "https://webrebels.org/",
+ "where": "Oslo, Norway",
+ "when": "June 01-02, 2017",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "WeAreDevelopers",
+ "url": "http://www.wearedevelopers.org/",
+ "where": "Vienna, Austria",
+ "when": "May 11-12, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "CodeFest",
+ "url": "https://2017.codefest.ru",
+ "where": "Novosibirsk, Russia",
+ "when": "April 1-2, 2017",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "DUMP",
+ "url": "http://dump-conf.ru/",
+ "where": "Ekaterinburg, Russia",
+ "when": "April 14, 2017",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JS Day Italy",
+ "url": "https://2017.jsday.it/",
+ "where": "Verona, Italy",
+ "when": "May 10-11, 2017",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Holy JS",
+ "url": "https://holyjs-piter.ru/",
+ "where": "Saint-Petersburg, Russia",
+ "when": "June 2-3, 2017",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Frontend Conf",
+ "url": "http://frontendconf.ru/",
+ "where": "Moscow, Russia",
+ "when": "June 5-6, 2017",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "NodeConf Argentina",
+ "url": "https://2017.nodeconf.com.ar/",
+ "where": "Buenos Aires, Argentina",
+ "when": "October 26-28, 2017",
+ "month": "October",
+ "submissionDeadline": "July 15, 2017"
+ },
+ {
+ "title": "Full Stack Fest",
+ "url": "https://fullstackfest.barcelona",
+ "where": "Barcelona, Spain",
+ "when": "September 4-8, 2017",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JS Remote Conf",
+ "url": "http://jsremoteconf.com/",
+ "where": "Online",
+ "when": "January 14–16, 2016",
+ "month": "January",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "O’Reilly Design Conference",
+ "url": "http://oreil.ly/1NRw8kd",
+ "where": "San Francisco, CA, USA",
+ "when": "January 19–22, 2016",
+ "month": "January",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "SVG Summit 2016",
+ "url": "http://environmentsforhumans.com/2016/svg-summit/",
+ "where": "Online",
+ "when": "January 21, 2016",
+ "month": "January",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Awwwards Conference – Amsterdam 2016",
+ "url": "http://conference.awwwards.com/amsterdam-2016/",
+ "where": "Amsterdam, Netherlands",
+ "when": "January 27–29, 2016",
+ "month": "January",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "A Day of REST",
+ "url": "http://feelingrestful.com/",
+ "where": "London, UK",
+ "when": "January 28, 2016",
+ "month": "January",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "VOXXED Days Berlin 2016",
+ "url": "https://voxxeddays.com/berlin16/",
+ "where": "Berlin, Germany",
+ "when": "January 28–29, 2016",
+ "month": "January",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "PhoneGap Day US 2016",
+ "url": "http://pgday.phonegap.com/",
+ "where": "Lehi, UT, USA",
+ "when": "January 28–29, 2016",
+ "month": "January",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Agile Content Conf 2016",
+ "url": "https://2016.agilecontentconf.com/",
+ "where": "London, UK",
+ "when": "February 1–2, 2016",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JFokus 2016",
+ "url": "http://www.jfokus.se/jfokus/",
+ "where": "Stockholm, Sweden",
+ "when": "February 8–10, 2016",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "SustainableUX",
+ "url": "http://sustainableux.com/",
+ "where": "Online",
+ "when": "February 9, 2016",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "ConveyUX 2016",
+ "url": "http://conveyux.com/",
+ "where": "Seattle, WA, USA",
+ "when": "February 9–11, 2016",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Webstock 2016",
+ "url": "http://www.webstock.org.nz/16/",
+ "where": "Wellington, New Zealand",
+ "when": "February 9–12, 2016",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "DevNexus 2016",
+ "url": "http://www.devnexus.com/",
+ "where": "Atlanta, GA, USA",
+ "when": "February 15–17, 2016",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Open Set Soul Edition 2016",
+ "url": "http://www.openset.nl/oskorea/opensetdutchdesignseoulsessions_en.html",
+ "where": "Seoul, South Korea",
+ "when": "February 15–27, 2016",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Mobile Growth Summit 2016",
+ "url": "http://bit.ly/MobileGrowthSummit16",
+ "where": "San Francisco, CA, USA",
+ "when": "February 17–18, 2016",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "World IA Day 2016",
+ "url": "http://www.2016.worldiaday.org/",
+ "where": "At locations on every continent",
+ "when": "February 20, 2016",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Bulgaria Web Summit 2016",
+ "url": "http://bulgariawebsummit.com/",
+ "where": "Sofia, Bulgaria",
+ "when": "February 20, 2016",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "The Rolling Scopes Conference",
+ "url": "http://2016.conf.rollingscopes.com/",
+ "where": "Minsk, Belarus",
+ "when": "February 20–21, 2016",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "React.js Conf",
+ "url": "http://conf.reactjs.com/",
+ "where": "San Francisco, CA, USA",
+ "when": "February 22–23, 2016",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "UX Riga 2016",
+ "url": "http://www.uxriga.lv/",
+ "where": "Riga, Latvia",
+ "when": "February 25, 2016",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Typoday 2016",
+ "url": "http://www.typoday.in/",
+ "where": "Bangalore, India",
+ "when": "February 25–27, 2016",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Planning for a Higher Ed Website Redesign",
+ "url": "http://www.academicimpressions.com/conference/planning-higher-ed-website-redesign",
+ "where": "Cincinnati, OH, USA",
+ "when": "February 29–March 2, 2016",
+ "month": "February",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Interaction16",
+ "url": "http://interaction16.ixda.org/",
+ "where": "Helsinki, Finland",
+ "when": "March 1–4, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Riga Dev Day 2016",
+ "url": "http://www.rigadevday.lv/",
+ "where": "Riga, Latvia",
+ "when": "March 2–4, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Voxxed Days Zurich",
+ "url": "https://voxxeddays.com/zurich16/",
+ "where": "Zurich, Switzerland",
+ "when": "March 3, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "MIDWEST PHP 2016",
+ "url": "http://2016.midwestphp.org/",
+ "where": "Minneapolis, MN, USA",
+ "when": "March 4–5, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "QCon London 2016",
+ "url": "http://qconlondon.com/",
+ "where": "London, UK",
+ "when": "March 7–11, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "O’Reilly Fluent Conference 2016",
+ "url": "http://conferences.oreilly.com/fluent/javascript-html-us",
+ "where": "San Francisco, CA",
+ "when": "March 8–10, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "UXHK 2016",
+ "url": "http://www.uxhongkong.com/",
+ "where": "Hong Kong, China",
+ "when": "March 11–12, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "SXSW 2016",
+ "url": "http://www.sxsw.com/",
+ "where": "Austin, TX, USA",
+ "when": "March 11–20, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Dev Bootcamp San Francisco March Info Session",
+ "url": "https://www.eventbrite.com/…san-francisco-march-info-session-tickets-22132155874?ref=ebapi",
+ "where": "United States,San Francisco",
+ "when": "March 14th, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "MobileTech Conference Spring 2016",
+ "url": "https://mobiletechcon.de/",
+ "where": "Munich, Germany",
+ "when": "March 14–17, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Ruby for Beginners",
+ "url": "https://www.eventbrite.com/e/ruby-for-beginners-tickets-21643963678?ref=ebapi",
+ "where": "United States,San Francisco",
+ "when": "March 15th, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "SmashingConf Oxford 2016",
+ "url": "http://www.smashingconf.com/",
+ "where": "Oxford, UK",
+ "when": "March 15–16, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "DIBI 2016",
+ "url": "http://dibiconference.com/",
+ "where": "Edinburgh, UK",
+ "when": "March 17–18, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Codemotion Roma 2016",
+ "url": "http://rome2016.codemotionworld.com/",
+ "where": "ItalyItaly,Rome",
+ "when": "March 18th–19th, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Phase 0 Virtual Information Session",
+ "url": "https://www.eventbrite.com/e/phase-0-virtual-information-session-tickets-22308315773",
+ "where": "Online conference",
+ "when": "March 19th, 2016",
+ "month": "March"
+ },
+ {
+ "title": "Ruby Remote Conf",
+ "url": "https://allremoteconfs.com/ruby-2016",
+ "where": "Online",
+ "when": "March 23-25, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "EmberConf 2016",
+ "url": "http://emberconf.com/",
+ "where": "Portland, OR, USA",
+ "when": "March 28–30, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "QCon SP 2016",
+ "url": "http://qconsp.com/",
+ "where": "São Paolo, Brazil",
+ "when": "March 28–April 1, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "UX in the City: Oxford 2016",
+ "url": "http://uxinthecity.net/2016/oxford/",
+ "where": "Oxford, UK",
+ "when": "March 31–April 1, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Workshop: Building JavaScript Applications with ReactJS",
+ "url": "http://www.whiteoctoberevents.co.uk/event/reactjs-workshop-march-16/",
+ "where": "England,London",
+ "when": "March 21st, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Dev Bootcamp March Virtual Info Session",
+ "url": "https://www.eventbrite.com/e/dev-bootcamp-march-virtual-info-session-tickets-22477541933",
+ "where": "Online conference",
+ "when": "March 24th, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Meet the TAG - London",
+ "url": "",
+ "where": "England,London",
+ "when": "March 29th, 2016, 6pm",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "RWD Summit 2016",
+ "url": "http://environmentsforhumans.com/2016/responsive-web-design-summit/",
+ "where": "Online conference",
+ "when": "March 29th–31st, 2016",
+ "month": "March",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Fronteers Spring Thing 2016",
+ "url": "https://fronteers.nl/spring",
+ "where": "Amsterdam, Netherlands",
+ "when": "April 1, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Space City JS 2016",
+ "url": "http://spacecity.codes/",
+ "where": "Houston, TX, USA",
+ "when": "April 2, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "MobCon Europe 2016",
+ "url": "http://mobcon.com/mobcon-europe/",
+ "where": "Sofia, Bulgaria",
+ "when": "April 4, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "An Event Apart 2016: Seattle",
+ "url": "http://aneventapart.com/event/seattle-2016",
+ "where": "Seattle, WA, USA",
+ "when": "April 4–6, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "SmashingConf San Francisco 2016",
+ "url": "http://smashingconf.com/sf-2016/",
+ "where": "San Francisco, CA, USA",
+ "when": "April 5–6, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Le Web a Quebec 2016 — 6e edition",
+ "url": "http://www.webaquebec.org/",
+ "where": "Quebec, Canada",
+ "when": "April 6–8, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "WebVisions New York City 2016",
+ "url": "http://www.webvisionsevent.com/",
+ "where": "New York City, NY, USA",
+ "when": "April 7, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Respond 2016",
+ "url": "http://www.webdirections.org/respond16/",
+ "where": "Melbourne, Australia",
+ "when": "April 11-12, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Lone Star PHP 2016",
+ "url": "http://lonestarphp.com/",
+ "where": "Dallas, TX, USA",
+ "when": "April 7–9, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Jazoon Techdays Spring 2016",
+ "url": "http://jazoon.com/",
+ "where": "Berne, Switzerland",
+ "when": "April 8, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Yggdrasil 2016",
+ "url": "http://yggdrasilkonferansen.no/",
+ "where": "Sandefjord, Norway",
+ "when": "April 11–12, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Now What? Conference 2016",
+ "url": "http://www.nowwhatconference.com/",
+ "where": "Sioux Falls, SD, USA",
+ "when": "April 13–14, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Peers Conference 2016",
+ "url": "http://peersconf.com/",
+ "where": "St. Petersburg, FL, USA",
+ "when": "April 13–15, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "ConvergeSE 2016",
+ "url": "http://convergese.com/",
+ "where": "Columbia, SC, USA",
+ "when": "April 13–15, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "ACE! 2016",
+ "url": "http://aceconf.com/",
+ "where": "Krakow, Poland",
+ "when": "April 14–15, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "From Business to Buttons",
+ "url": "http://frombusinesstobuttons.com/",
+ "where": "Stockholm, Sweden",
+ "when": "April 14–16, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JSConf 2016",
+ "url": "https://jsconf.uy/",
+ "where": "Montevideo, Uruguay",
+ "when": "April 15–16, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JavaScript Frameworks Day 2016",
+ "url": "http://frameworksdays.com/event/js-frameworks-day-2016",
+ "where": "Kiev, Ukraine",
+ "when": "April 16, 2016",
+ "month": "April"
+ },
+ {
+ "title": "Ancient City Ruby 2016",
+ "url": "",
+ "where": "United States,St. Augustine",
+ "when": "April 6th–8th, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Lone Star PHP 2016",
+ "url": "",
+ "where": "United States,Addison",
+ "when": "April 7th–9th, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Building a Real-time App with React and Firebase",
+ "url": "",
+ "where": "Online conference",
+ "when": "April 7th, 2016, 9am",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "CoderDojo Nürnberg #1",
+ "url": "",
+ "where": "Germany,Nuremberg",
+ "when": "April 10th 2016, 4pm",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Nürnberg Web Week 2016",
+ "url": "",
+ "where": "Germany,Nuremberg",
+ "when": "April 11th–18th, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Accessibility Club #3",
+ "url": "http://accessibility-club.org/",
+ "where": "Germany,Nürnberg",
+ "when": "April 12th, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Digital Croydon #8 Laura Elizabeth, Jason Bootle, Amy Whitney",
+ "url": "",
+ "where": "England,London Borough of Croydon",
+ "when": "April 14th, 2016, 6:30pm",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Using External Plugins with React",
+ "url": "http://www.oreilly.com/online-training/react-for-web-developers.html",
+ "where": "Online conference",
+ "when": "April 14th, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Hexagon Geospatial IGNITE Session - Atlanta",
+ "url": "https://www.eventbrite.com/e/hexagon-geospatial-ignite-session-atlanta-tickets-22668441920?ref=ebapi",
+ "where": "United States,Norcross",
+ "when": "April 15th, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "2016 DC-Baltimore Perl Workshop",
+ "url": "http://dcbpw.org/dcbpw2016/",
+ "where": "United States,Balitmore",
+ "when": "April 16th–17th, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Workshop: Rapid API development with Node.js and LoopBack",
+ "url": "",
+ "where": "England,Oxford",
+ "when": "April 20th, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Industry Conf",
+ "url": "https://industryconf.com/",
+ "where": "Newcastle upon Tyne, England",
+ "when": "April 20, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "MCE3",
+ "url": "http://mceconf.com/",
+ "where": "Warsaw, Poland",
+ "when": "April 21–22, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Render Conf",
+ "url": "http://www.render-conf.com/",
+ "where": "Oxford, England",
+ "when": "April 21-22, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Generate NYC 2016",
+ "url": "http://www.generateconf.com/new-york-2016",
+ "where": "New York City, NY, USA",
+ "when": "April 22, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "RSJS",
+ "url": "http://rsjs.org/2016/",
+ "where": "Porto Alegre, Brazil",
+ "when": "April 23, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JSUnconf",
+ "url": "http://2016.jsunconf.eu/",
+ "where": "Hamburg, Germany",
+ "when": "April 23-24, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JET Conference",
+ "url": "",
+ "where": "Belarus,Minsk",
+ "when": "April 25th, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Future of Web Design London",
+ "url": "https://futureofwebdesign.com/london-2016/",
+ "where": "London, England",
+ "when": "April 25-27, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Open Vis Conf",
+ "url": "https://openvisconf.com/",
+ "where": "Boston, MA, USA",
+ "when": "April 25–26, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "M2M WORLD CONGRESS 2016",
+ "url": "http://www.m2mconference.com/",
+ "where": "London, UK",
+ "when": "April 26–27, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Squares Conference",
+ "url": "http://squaresconference.com/",
+ "where": "Dallas (Grapevine), Texas USA",
+ "when": "April 27-29, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Workshop: Angular 2",
+ "url": "",
+ "where": "England,London",
+ "when": "April 29th, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JSDayES 2016",
+ "url": "http://jsday.es/",
+ "where": "Madrid, Spain",
+ "when": "April 29-30, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Front in Rio – HTML Edition",
+ "url": "http://frontinrio.com.br/",
+ "where": "Rio de Janeiro, Brazil",
+ "when": "April 30, 2016",
+ "month": "April",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Future Insights Live",
+ "url": "https://futureinsightslive.com/",
+ "where": "Chicago, Illinois USA",
+ "when": "May 2-5, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "ng-conf",
+ "url": "http://www.ng-conf.org/",
+ "where": "Salt Lake City, Utah USA",
+ "when": "May 4-6, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "IA Summit 2016",
+ "url": "http://2016.iasummit.org/",
+ "where": "Atlanta, GA, USA",
+ "when": "May 4–8, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Syntax Convention",
+ "url": "http://syntaxcon.com/",
+ "where": "Charleston, South Carolina USA",
+ "when": "May 6-7, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Beyond Tellerrand",
+ "url": "http://beyondtellerrand.com/",
+ "where": "Düsseldorf, Germany",
+ "when": "May 9-11, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "DRUPALCON",
+ "url": "https://events.drupal.org/neworleans2016",
+ "where": "New Orleans, LA, USA",
+ "when": "May 9–13, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "CSSConf Budapest",
+ "url": "http://cssconfbp.rocks/",
+ "where": "Budapest, Hungary",
+ "when": "May 11, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "jsday",
+ "url": "http://2016.jsday.it/",
+ "where": "Verona, Italy",
+ "when": "May 11-12, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "UX Alive",
+ "url": "http://www.uxalive.com/",
+ "where": "Istanbul, Turkey",
+ "when": "May 11-13, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JsDay",
+ "url": "http://2016.jsday.it/",
+ "where": "Verona, Italy",
+ "when": "May 11–12, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "UX Alive",
+ "url": "http://www.uxalive.com/",
+ "where": "Istanbul, Turkey",
+ "when": "May 11–13, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JSConf Budapest",
+ "url": "http://jsconfbp.com/",
+ "where": "Budapest, Hungary",
+ "when": "May 12-13, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Create Upstate",
+ "url": "http://createupstate.com/",
+ "where": "Syracuse, NY, USA",
+ "when": "May 12–13, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Front",
+ "url": "http://www.frontutah.com/",
+ "where": "Salt Lake City, UT, USA",
+ "when": "May 12–13, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JSConf Budapest",
+ "url": "http://jsconfbp.com/",
+ "where": "Budapest, Hungary",
+ "when": "May 12–13, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "phpDay",
+ "url": "http://2016.phpday.it/",
+ "where": "Verona, Italy",
+ "when": "May 13–14, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "An Event Apart Boston",
+ "url": "http://aneventapart.com/event/boston-2016",
+ "where": "Boston, Massachusetts USA",
+ "when": "May 16-18, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "SDD Conf",
+ "url": "http://www.sddconf.com/",
+ "where": "London, UK",
+ "when": "May 16–20, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "OSCON",
+ "url": "http://conferences.oreilly.com/oscon/open-source-us",
+ "where": "Austin, TX, USA",
+ "when": "May 18–19, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "UX London",
+ "url": "http://2016.uxlondon.com/",
+ "where": "London, UK",
+ "when": "May 18–20, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Front-Trends",
+ "url": "http://front-trends.com/",
+ "where": "Warsaw, Poland",
+ "when": "May 18–20, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "PhoneGap Day EU 2016",
+ "url": "http://pgday.phonegap.com/eu2016/",
+ "where": "Amsterdam, Netherlands",
+ "when": "May 19-20, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Port 80",
+ "url": "http://port80events.co.uk/",
+ "where": "Newport, UK",
+ "when": "May 20, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JandBeyong - An international Joomla! Conference",
+ "url": "http://JandBeyong.org/",
+ "where": "Barcelona, Spain",
+ "when": "May 20-22, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "GOTO Chicago",
+ "url": "http://gotocon.com/chicago-2016",
+ "where": "Chicago, IL, USA",
+ "when": "May 23–26, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "User Experience Lisbon",
+ "url": "https://www.ux-lx.com/",
+ "where": "Lisbon, Portugal",
+ "when": "May 24-27, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "DevSum16",
+ "url": "http://www.devsum.se/",
+ "where": "Stockholm, Sweden",
+ "when": "May 25-27, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Empire JS",
+ "url": "http://empirejs.org/",
+ "where": "New York City, New York USA",
+ "when": "May 26-27, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Frontend United",
+ "url": "http://frontendunited.org/",
+ "where": "Ghent, Belgium",
+ "when": "May 27-28, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "UpFront 2016",
+ "url": "http://upfrontconf.com/",
+ "where": "Manchester, UK",
+ "when": "May 27, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Sud Web 2016",
+ "url": "http://sudweb.fr/",
+ "where": "Bordeaux, France",
+ "when": "May 27–28, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Webinale 2016",
+ "url": "https://webinale.de/",
+ "where": "Berlin, Germany",
+ "when": "May 29–June 02, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "UXPA 2016",
+ "url": "http://www.uxpa2016.org/",
+ "where": "Seattle, WA, USA",
+ "when": "May 31–June 03, 2016",
+ "month": "May",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "CSSconf Nordic 2016",
+ "url": "http://cssconf.no/",
+ "where": "Oslo, Norway",
+ "when": "June 1, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "ScotlandCSS 2016",
+ "url": "http://scotlandcss.launchrock.com/",
+ "where": "Edinburgh, UK",
+ "when": "June 1, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Web Rebels 2016",
+ "url": "https://www.webrebels.org/",
+ "where": "Oslo, Norway",
+ "when": "June 2–3, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Soap! 2016",
+ "url": "http://soapconf.com/",
+ "where": "Krakow, Poland",
+ "when": "June 2–3, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "UXScotland 2016",
+ "url": "http://uxscotland.net/2016/",
+ "where": "Edinburgh, UK",
+ "when": "June 8–10, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "M-Enabling Summit 2016",
+ "url": "http://www.m-enabling.com/",
+ "where": "Washington, D.C., USA",
+ "when": "June 13–14, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "QCon New York 2016",
+ "url": "https://qconnewyork.com/",
+ "where": "New York City, NY, USA",
+ "when": "June 13–17, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Front End Design Conference",
+ "url": "http://frontenddesignconference.com/",
+ "where": "St. Petersburg, Florida USA",
+ "when": "June 15-17, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Droidcon Berlin 2016",
+ "url": "http://droidcon.de/",
+ "where": "Berlin, Germany",
+ "when": "June 15–17, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "DWX Developer Week 2016",
+ "url": "http://www.developer-week.de/",
+ "where": "Nuremberg, Germany",
+ "when": "June 20–23, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "KCDC",
+ "url": "http://www.kcdc.info/#!/",
+ "where": "Kansas City, Utah",
+ "when": "June 22-24, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Dinosaur.js",
+ "url": "http://dinosaurjs.org/",
+ "where": "Denver, Colorado USA",
+ "when": "June 24, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Web Design Day",
+ "url": "http://webdesignday.com",
+ "where": "Pittsburgh, Pennsylvania USA",
+ "when": "June 24, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Devoxx Poland 2016",
+ "url": "http://devoxx.pl/",
+ "where": "Krakow, Poland",
+ "when": "June 22–25, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "The Lead Developer 2016",
+ "url": "http://2016.theleaddeveloper.com/",
+ "where": "London, UK",
+ "when": "June 23–24, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Dutch PHP Conference 2016",
+ "url": "http://www.phpconference.nl/",
+ "where": "Amsterdam, Netherlands",
+ "when": "June 23–25, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Wicked Good Ember Conf",
+ "url": "https://wickedgoodember.com",
+ "where": "Boston, MA, USA",
+ "when": "June 27-28, 2016",
+ "month": "June",
+ "submissionDeadline": "May 13, 2016"
+ },
+ {
+ "title": "CSSconf Nordic",
+ "url": "http://cssconf.no/",
+ "where": "Oslo, Norway",
+ "when": "June 1, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Web Rebels",
+ "url": "https://www.webrebels.org/",
+ "where": "Oslo, Norway",
+ "when": "June 2-3, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "ReactEurope 2016",
+ "url": "https://www.react-europe.org/",
+ "where": "Paris, France",
+ "when": "June 2-3, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "ScotlandJS 2016",
+ "url": "http://scotlandjs.com/",
+ "where": "Edinburgh, Scotland",
+ "when": "June 2-3, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JSCamp Romania",
+ "url": "http://www.jscamp.ro/",
+ "where": "Bucharest, Romania",
+ "when": "June 7, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "UX Scotland",
+ "url": "http://uxscotland.net/2016/",
+ "where": "Edinburgh, Scotland",
+ "when": "June 8, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "enterJS 2016",
+ "url": "https://www.enterjs.de/",
+ "where": "Darmstadt, Germany",
+ "when": "June 14-16, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "CSS Day 2016",
+ "url": "http://cssday.nl/",
+ "where": "Amsterdam, The Netherlands",
+ "when": "June 16-17, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "YGLF",
+ "url": "http://yougottalovefrontend.com/#page-home",
+ "where": "Tel Aviv, Israel",
+ "when": "June 27-28, 2016",
+ "month": "June",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "FrontinSampa",
+ "url": "http://frontinsampa.com.br/",
+ "where": "São Paulo, Brazil",
+ "when": "July 02, 2016",
+ "month": "July",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "FullStack 2016",
+ "url": "https://skillsmatter.com/conferences/7278-fullstack",
+ "where": "England, London",
+ "when": "July 13–15, 2016",
+ "month": "July",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Generate San Francisco 2016",
+ "url": "http://generateconf.com/",
+ "where": "San Francisco, California USA",
+ "when": "July 15, 2016",
+ "month": "July",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "An Event Apart Washington D.C.",
+ "url": "http://aneventapart.com/event/washington-dc-2016",
+ "where": "Washington, D.C. USA",
+ "when": "July 25-27, 2016",
+ "month": "July",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "ForwardJS 5",
+ "url": "http://forwardjs.com/",
+ "where": "San Francisco, California USA",
+ "when": "July 25-31, 2016",
+ "month": "July",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "CSS Summit 2016",
+ "url": "http://environmentsforhumans.com/2016/css-summit/",
+ "where": "online",
+ "when": "July 26-28, 2016",
+ "month": "July",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Mobile & Web CodeCamp",
+ "url": "http://www.mobilewebcodecamp.com/",
+ "where": "Salt Lake City, Utah USA",
+ "when": "July 28-29, 2016",
+ "month": "July",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "NDC Sydney",
+ "url": "http://ndcsydney.com/",
+ "where": "Sydney, Australia",
+ "when": "August 1-5, 2016",
+ "month": "August",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "CSSConf Argentina",
+ "url": "http://cssconfar.com",
+ "where": "Buenos Aires, Argentina",
+ "when": "August 7, 2016",
+ "month": "August",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JSConf Iceland",
+ "url": "http://2016.jsconf.is/",
+ "where": "Reykjavik, Iceland",
+ "when": "August 25-26, 2016",
+ "month": "August",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "React Rally",
+ "url": "http://www.reactrally.com/",
+ "where": "Salt Lake City, Utah",
+ "when": "August 25-26, 2016",
+ "month": "August",
+ "submissionDeadline": "April 28, 2016"
+ },
+ {
+ "title": "BrazilJS Conf",
+ "url": "https://braziljs.org/conf",
+ "where": "Porto Alegre, Brazil",
+ "when": "August 26-27, 2016",
+ "month": "August",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "AltConf",
+ "url": "http://www.alterconf.com/sessions/cape-town-south-africa",
+ "where": "Cape Town, South Africa",
+ "when": "August 27, 2016",
+ "month": "August",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "An Event Apart Chicago",
+ "url": "http://aneventapart.com/event/chicago-2016",
+ "where": "Chicago, Illinois USA",
+ "when": "August 29-31, 2016",
+ "month": "August",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "ColdFront 2016",
+ "url": "https://2016.coldfrontconf.com/",
+ "where": "Copenhagen, Denmark",
+ "when": "September 1, 2016",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Frontend Conference Zurich",
+ "url": "https://frontendconf.ch/",
+ "where": "Zurich, Switzerland",
+ "when": "September 1-2, 2016",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Generate Sydney 2016",
+ "url": "http://generateconf.com/",
+ "where": "Sydney Australia",
+ "when": "September 5, 2016",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Full Stack Fest",
+ "url": "http://2016.fullstackfest.com/",
+ "where": "Barcelona, Spain",
+ "when": "September 5-9, 2016",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "SmashingConf Freiburg 2016",
+ "url": "http://smashingconf.com/",
+ "where": "Freiburg, Germany",
+ "when": "September 12-13, 2016",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "From the Front",
+ "url": "http://2016.fromthefront.it/",
+ "where": "Bologna, Italy",
+ "when": "September 15-16, 2016",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Strange Loop",
+ "url": "http://www.thestrangeloop.com/",
+ "where": "St. Louis, USA",
+ "when": "September 15-17, 2016",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "SmartWeb Conference 2016",
+ "url": "http://www.smartwebconf.com/",
+ "where": "Bucharest, Romania",
+ "when": "September 20, 2016",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Generate London 2016",
+ "url": "http://generateconf.com/",
+ "where": "London England",
+ "when": "September 21-23, 2016",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "AngularConnect 2016",
+ "url": "http://angularconnect.com/",
+ "where": "London, England",
+ "when": "September 27-28, 2016",
+ "month": "September",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "An Event Apart Orlando",
+ "url": "http://aneventapart.com/event/orlando-2016",
+ "where": "Orlando, Florida USA",
+ "when": "October 3-5, 2016",
+ "month": "October",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "LoopConf",
+ "url": "https://loopconf.com/",
+ "where": "Fort Lauderdale, Florida USA",
+ "when": "October 5-7, 2016",
+ "month": "October",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Full Stack Toronto",
+ "url": "https://fsto.co/",
+ "where": "Toronto, Ontario Canada",
+ "when": "October 17-18, 2016",
+ "month": "October",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "CSS Dev Conf",
+ "url": "http://2016.cssdevconf.com/",
+ "where": "San Antonio, Texas USA",
+ "when": "October 17-19, 2016",
+ "month": "October",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Connect.Tech",
+ "url": "http://connect-js.com/",
+ "where": "Atlanta, Georgia USA",
+ "when": "October 20-22, 2016",
+ "month": "October",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "ng-europe 2016",
+ "url": "https://ngeurope.org/",
+ "where": "Paris, France",
+ "when": "October 25-26, 2016",
+ "month": "October",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "An Event Apart San Francisco",
+ "url": "http://aneventapart.com/event/san-francisco-2016",
+ "where": "San Francisco, California USA",
+ "when": "October 31-November 2, 2016",
+ "month": "October",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Thunder Plains",
+ "url": "http://thunderplainsconf.com/",
+ "where": "Oklahoma City, USA",
+ "when": "November 3-4, 2016",
+ "month": "November",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "SenchaCon 2016",
+ "url": "http://www.senchacon.com/",
+ "where": "Las Vegas, Nevada USA",
+ "when": "November 7-9, 2016",
+ "month": "November",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Beyond Tellerrand",
+ "url": "http://beyondtellerrand.com/",
+ "where": "Berlin Germany",
+ "when": "November 7-9, 2016",
+ "month": "November",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "FrontierConf London 2016",
+ "url": "https://www.frontierconf.com/",
+ "where": "London, England",
+ "when": "November 16, 2016",
+ "month": "November",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Generate Bangalore 2016",
+ "url": "http://www.generateconf.com/",
+ "where": "Bangalore, India",
+ "when": "November 25, 2016",
+ "month": "November",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "JS Kongress Munich",
+ "url": "http://js-kongress.de/",
+ "where": "Munich, Germany",
+ "when": "November 28-29, 2016",
+ "month": "November",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "CSSConf Australia",
+ "url": "http://2016.cssconf.com.au/",
+ "where": "Melbourne Australia",
+ "when": "November 30, 2016",
+ "month": "November",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "Decompress",
+ "url": "http://decompress.com.au/",
+ "where": "Melbourne, Australia",
+ "when": "December 2, 2016",
+ "month": "December",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "dotCSS",
+ "url": "http://www.dotcss.io/",
+ "where": "Paris, France",
+ "when": "December 2, 2016",
+ "month": "December",
+ "submissionDeadline": ""
+ },
+ {
+ "title": "dotJS",
+ "url": "http://www.dotjs.io/",
+ "where": "Paris, France",
+ "when": "December 5, 2016",
+ "month": "December",
+ "submissionDeadline": ""
+ }
+]
\ No newline at end of file
diff --git a/admin-panel/src/mocks/index.js b/admin-panel/src/mocks/index.js
new file mode 100644
index 0000000..d1a851f
--- /dev/null
+++ b/admin-panel/src/mocks/index.js
@@ -0,0 +1,9 @@
+import conferences from './conferences'
+import firebase from 'firebase'
+
+export function saveEventsToFB() {
+ const eventsRef = firebase.database().ref('/events')
+ conferences.forEach(conference => eventsRef.push(conference))
+}
+
+window.saveEventsToFB = saveEventsToFB
\ No newline at end of file
diff --git a/admin-panel/src/redux/index.js b/admin-panel/src/redux/index.js
index 1a37261..6c5314d 100644
--- a/admin-panel/src/redux/index.js
+++ b/admin-panel/src/redux/index.js
@@ -4,8 +4,9 @@ import {routerMiddleware} from 'react-router-redux'
import thunk from 'redux-thunk'
import reducer from './reducer'
import history from '../history'
+import {randomId} from './middlewares'
-const store = createStore(reducer, applyMiddleware(thunk, routerMiddleware(history), logger))
+const store = createStore(reducer, applyMiddleware(thunk, routerMiddleware(history), randomId, logger))
//dev only
window.store = store
diff --git a/admin-panel/src/redux/middlewares.js b/admin-panel/src/redux/middlewares.js
new file mode 100644
index 0000000..05ccb06
--- /dev/null
+++ b/admin-panel/src/redux/middlewares.js
@@ -0,0 +1,14 @@
+import {getRandomId} from '../helpers';
+
+export let randomId = store => next => action => {
+ let {payload = {}} = action;
+ let {generateId, ...rest} = payload;
+ if (!generateId) return next(action);
+ next({
+ ...action,
+ payload : {
+ ...rest,
+ randomId : getRandomId()
+ }
+ })
+}
\ No newline at end of file
diff --git a/admin-panel/src/redux/reducer.js b/admin-panel/src/redux/reducer.js
index 34143fe..ddc9f75 100644
--- a/admin-panel/src/redux/reducer.js
+++ b/admin-panel/src/redux/reducer.js
@@ -2,8 +2,10 @@ import {combineReducers} from 'redux'
import {routerReducer as router} from 'react-router-redux'
import {reducer as form} from 'redux-form'
import authReducer, {moduleName as authModule} from '../ducks/auth'
+import usersReducer, {moduleName as userModule} from '../ducks/users'
export default combineReducers({
router, form,
- [authModule]: authReducer
+ [authModule] : authReducer,
+ [userModule] : usersReducer,
})
\ No newline at end of file
diff --git a/admin-panel/src/redux/saga.js b/admin-panel/src/redux/saga.js
new file mode 100644
index 0000000..d9bb32f
--- /dev/null
+++ b/admin-panel/src/redux/saga.js
@@ -0,0 +1,12 @@
+import {all} from 'redux-saga/effects'
+import {saga as peopleSaga} from '../ducks/people'
+import {saga as authSaga} from '../ducks/auth'
+import {saga as eventsSaga} from '../ducks/events'
+
+export default function * rootSaga() {
+ yield all([
+ peopleSaga(),
+ authSaga(),
+ eventsSaga()
+ ])
+}
\ No newline at end of file
diff --git a/admin-panel/src/setupTests.js b/admin-panel/src/setupTests.js
new file mode 100644
index 0000000..88c8c3b
--- /dev/null
+++ b/admin-panel/src/setupTests.js
@@ -0,0 +1,4 @@
+import Enzyme from 'enzyme'
+import Adapter from 'enzyme-adapter-react-16'
+
+Enzyme.configure({ adapter: new Adapter() })
diff --git a/admin-panel/yarn.lock b/admin-panel/yarn.lock
index c9c597c..2efe11e 100644
--- a/admin-panel/yarn.lock
+++ b/admin-panel/yarn.lock
@@ -50,6 +50,10 @@
version "0.2.4"
resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.2.4.tgz#ec8438b780baff09254076efe345f30fdb41243e"
+"@types/node@*":
+ version "8.5.1"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.5.1.tgz#4ec3020bcdfe2abffeef9ba3fbf26fca097514b5"
+
abab@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e"
@@ -963,7 +967,7 @@ babel-register@^6.26.0:
mkdirp "^0.5.1"
source-map-support "^0.4.15"
-babel-runtime@6.26.0, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0:
+babel-runtime@6.26.0, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
dependencies:
@@ -1352,6 +1356,17 @@ chardet@^0.4.0:
version "0.4.2"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2"
+cheerio@^1.0.0-rc.2:
+ version "1.0.0-rc.2"
+ resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db"
+ dependencies:
+ css-select "~1.2.0"
+ dom-serializer "~0.1.0"
+ entities "~1.1.1"
+ htmlparser2 "^3.9.1"
+ lodash "^4.15.0"
+ parse5 "^3.0.1"
+
chokidar@^1.6.0, chokidar@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
@@ -1388,6 +1403,10 @@ clap@^1.0.9:
dependencies:
chalk "^1.1.3"
+classnames@^2.2.3:
+ version "2.2.5"
+ resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d"
+
clean-css@4.1.x:
version "4.1.9"
resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.1.9.tgz#35cee8ae7687a49b98034f70de00c4edd3826301"
@@ -1474,6 +1493,10 @@ colormin@^1.0.5:
css-color-names "0.0.4"
has "^1.0.1"
+colors@0.5.x:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/colors/-/colors-0.5.1.tgz#7d0023eaeb154e8ee9fce75dcb923d0ed1667774"
+
colors@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
@@ -1702,7 +1725,7 @@ css-loader@0.28.7:
postcss-value-parser "^3.3.0"
source-list-map "^2.0.0"
-css-select@^1.1.0:
+css-select@^1.1.0, css-select@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858"
dependencies:
@@ -1935,6 +1958,10 @@ diffie-hellman@^5.0.0:
miller-rabin "^4.0.0"
randombytes "^2.0.0"
+discontinuous-range@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a"
+
dns-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
@@ -1971,7 +1998,11 @@ dom-converter@~0.1:
dependencies:
utila "~0.3"
-dom-serializer@0:
+"dom-helpers@^2.4.0 || ^3.0.0":
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a"
+
+dom-serializer@0, dom-serializer@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
dependencies:
@@ -1992,7 +2023,7 @@ domain-browser@^1.1.1:
version "1.1.7"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
-domelementtype@1:
+domelementtype@1, domelementtype@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2"
@@ -2006,6 +2037,12 @@ domhandler@2.1:
dependencies:
domelementtype "1"
+domhandler@^2.3.0:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.1.tgz#892e47000a99be55bbf3774ffea0561d8879c259"
+ dependencies:
+ domelementtype "1"
+
domutils@1.1:
version "1.1.6"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485"
@@ -2019,6 +2056,13 @@ domutils@1.5.1:
dom-serializer "0"
domelementtype "1"
+domutils@^1.5.1:
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.6.2.tgz#1958cc0b4c9426e9ed367fb1c8e854891b0fa3ff"
+ dependencies:
+ dom-serializer "0"
+ domelementtype "1"
+
dot-prop@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177"
@@ -2096,10 +2140,45 @@ enhanced-resolve@^3.4.0:
object-assign "^4.0.1"
tapable "^0.2.7"
-entities@~1.1.1:
+entities@^1.1.1, entities@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
+enzyme-adapter-react-16@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.1.0.tgz#86c5db7c10f0be6ec25d54ca41b59f2abb397cf4"
+ dependencies:
+ enzyme-adapter-utils "^1.1.0"
+ lodash "^4.17.4"
+ object.assign "^4.0.4"
+ object.values "^1.0.4"
+ prop-types "^15.5.10"
+ react-test-renderer "^16.0.0-0"
+
+enzyme-adapter-utils@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.2.0.tgz#7f4471ee0a70b91169ec8860d2bf0a6b551664b2"
+ dependencies:
+ lodash "^4.17.4"
+ object.assign "^4.0.4"
+ prop-types "^15.5.10"
+
+enzyme@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.2.0.tgz#998bdcda0fc71b8764a0017f7cc692c943f54a7a"
+ dependencies:
+ cheerio "^1.0.0-rc.2"
+ function.prototype.name "^1.0.3"
+ has "^1.0.1"
+ is-subset "^0.1.1"
+ lodash "^4.17.4"
+ object-is "^1.0.1"
+ object.assign "^4.0.4"
+ object.entries "^1.0.4"
+ object.values "^1.0.4"
+ raf "^3.4.0"
+ rst-selector-parser "^2.2.3"
+
errno@^0.1.3, errno@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
@@ -2112,7 +2191,7 @@ error-ex@^1.2.0:
dependencies:
is-arrayish "^0.2.1"
-es-abstract@^1.7.0:
+es-abstract@^1.6.1, es-abstract@^1.7.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864"
dependencies:
@@ -2779,10 +2858,18 @@ fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
mkdirp ">=0.5 0"
rimraf "2"
-function-bind@^1.0.2, function-bind@^1.1.1:
+function-bind@^1.0.2, function-bind@^1.1.0, function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+function.prototype.name@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.0.3.tgz#0099ae5572e9dd6f03c97d023fd92bcc5e639eac"
+ dependencies:
+ define-properties "^1.1.2"
+ function-bind "^1.1.0"
+ is-callable "^1.1.3"
+
functional-red-black-tree@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
@@ -3125,6 +3212,17 @@ html-webpack-plugin@2.29.0:
pretty-error "^2.0.2"
toposort "^1.0.0"
+htmlparser2@^3.9.1:
+ version "3.9.2"
+ resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338"
+ dependencies:
+ domelementtype "^1.3.0"
+ domhandler "^2.3.0"
+ domutils "^1.5.1"
+ entities "^1.1.1"
+ inherits "^2.0.1"
+ readable-stream "^2.0.2"
+
htmlparser2@~3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.3.0.tgz#cc70d05a59f6542e43f0e685c982e14c924a9efe"
@@ -3476,6 +3574,10 @@ is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
+is-subset@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6"
+
is-svg@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9"
@@ -4055,6 +4157,10 @@ lodash.defaults@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
+lodash.flattendeep@^4.4.0:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
+
lodash.memoize@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
@@ -4096,7 +4202,7 @@ longest@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
-loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1:
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.0, loose-envify@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
dependencies:
@@ -4321,6 +4427,14 @@ ncname@1.0.x:
dependencies:
xml-char-classes "^1.0.0"
+nearley@^2.7.10:
+ version "2.11.0"
+ resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.11.0.tgz#5e626c79a6cd2f6ab9e7e5d5805e7668967757ae"
+ dependencies:
+ nomnom "~1.6.2"
+ railroad-diagrams "^1.0.0"
+ randexp "^0.4.2"
+
negotiator@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
@@ -4403,6 +4517,13 @@ node-status-codes@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/node-status-codes/-/node-status-codes-1.0.0.tgz#5ae5541d024645d32a58fcddc9ceecea7ae3ac2f"
+nomnom@~1.6.2:
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.6.2.tgz#84a66a260174408fc5b77a18f888eccc44fb6971"
+ dependencies:
+ colors "0.5.x"
+ underscore "~1.4.4"
+
nopt@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
@@ -4483,10 +4604,31 @@ object-hash@^1.1.4:
version "1.2.0"
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.2.0.tgz#e96af0e96981996a1d47f88ead8f74f1ebc4422b"
-object-keys@^1.0.8:
+object-is@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6"
+
+object-keys@^1.0.10, object-keys@^1.0.8:
version "1.0.11"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
+object.assign@^4.0.4:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.0.4.tgz#b1c9cc044ef1b9fe63606fc141abbb32e14730cc"
+ dependencies:
+ define-properties "^1.1.2"
+ function-bind "^1.1.0"
+ object-keys "^1.0.10"
+
+object.entries@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.0.4.tgz#1bf9a4dd2288f5b33f3a993d257661f05d161a5f"
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.6.1"
+ function-bind "^1.1.0"
+ has "^1.0.1"
+
object.omit@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
@@ -4494,6 +4636,15 @@ object.omit@^2.0.0:
for-own "^0.1.4"
is-extendable "^0.1.1"
+object.values@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.0.4.tgz#e524da09b4f66ff05df457546ec72ac99f13069a"
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.6.1"
+ function-bind "^1.1.0"
+ has "^1.0.1"
+
obuf@^1.0.0, obuf@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.1.tgz#104124b6c602c6796881a042541d36db43a5264e"
@@ -4657,6 +4808,12 @@ parse5@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
+parse5@^3.0.1:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
+ dependencies:
+ "@types/node" "*"
+
parseurl@~1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
@@ -5206,12 +5363,23 @@ querystringify@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb"
-raf@3.4.0:
+raf@3.4.0, raf@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.0.tgz#a28876881b4bc2ca9117d4138163ddb80f781575"
dependencies:
performance-now "^2.1.0"
+railroad-diagrams@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e"
+
+randexp@^0.4.2:
+ version "0.4.6"
+ resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3"
+ dependencies:
+ discontinuous-range "1.0.0"
+ ret "~0.1.10"
+
randomatic@^1.1.3:
version "1.1.7"
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c"
@@ -5375,6 +5543,24 @@ react-scripts@1.0.17:
optionalDependencies:
fsevents "1.1.2"
+react-test-renderer@^16.0.0-0:
+ version "16.2.0"
+ resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.2.0.tgz#bddf259a6b8fcd8555f012afc8eacc238872a211"
+ dependencies:
+ fbjs "^0.8.16"
+ object-assign "^4.1.1"
+ prop-types "^15.6.0"
+
+react-virtualized@^9.13.0:
+ version "9.13.0"
+ resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.13.0.tgz#83e4d984271a37631225e5fe6faeaeada6e59f53"
+ dependencies:
+ babel-runtime "^6.23.0"
+ classnames "^2.2.3"
+ dom-helpers "^2.4.0 || ^3.0.0"
+ loose-envify "^1.3.0"
+ prop-types "^15.5.4"
+
react@^16.2.0:
version "16.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba"
@@ -5497,6 +5683,10 @@ redux-logger@^3.0.6:
dependencies:
deep-diff "^0.3.5"
+redux-saga@^0.16.0:
+ version "0.16.0"
+ resolved "https://registry.yarnpkg.com/redux-saga/-/redux-saga-0.16.0.tgz#0a231db0a1489301dd980f6f2f88d8ced418f724"
+
redux-thunk@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.2.0.tgz#e615a16e16b47a19a515766133d1e3e99b7852e5"
@@ -5726,6 +5916,10 @@ restore-cursor@^2.0.0:
onetime "^2.0.0"
signal-exit "^3.0.2"
+ret@~0.1.10:
+ version "0.1.15"
+ resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
+
right-align@^0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
@@ -5745,6 +5939,13 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
hash-base "^2.0.0"
inherits "^2.0.1"
+rst-selector-parser@^2.2.3:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz#81b230ea2fcc6066c89e3472de794285d9b03d91"
+ dependencies:
+ lodash.flattendeep "^4.4.0"
+ nearley "^2.7.10"
+
run-async@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
@@ -6393,6 +6594,10 @@ uid-number@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
+underscore@~1.4.4:
+ version "1.4.4"
+ resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.4.4.tgz#61a6a32010622afa07963bf325203cf12239d604"
+
uniq@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"