diff --git a/admin-panel/package.json b/admin-panel/package.json index 1ada3cf..2dcbe74 100644 --- a/admin-panel/package.json +++ b/admin-panel/package.json @@ -19,7 +19,8 @@ "redux-logger": "^3.0.6", "redux-saga": "^0.16.0", "redux-thunk": "^2.2.0", - "reselect": "^3.0.1" + "reselect": "^3.0.1", + "styled-components": "^2.2.4" }, "scripts": { "start": "react-scripts start", diff --git a/admin-panel/src/App.js b/admin-panel/src/App.js new file mode 100644 index 0000000..fd110f7 --- /dev/null +++ b/admin-panel/src/App.js @@ -0,0 +1,23 @@ +import React, { Component } from 'react' +import {Route} from 'react-router-dom' +import Auth from './components/routes/auth' +import Admin from './components/routes/Admin' +import ProtectedRoute from './components/common/ProtectedRoute' + +class App extends Component { + static propTypes = { + + }; + + render() { + return ( +
+

Hello world

+ + +
+ ) + } +} + +export default App \ No newline at end of file diff --git a/admin-panel/src/components/App.js b/admin-panel/src/components/App.js index 6abd045..d8cc8a3 100644 --- a/admin-panel/src/components/App.js +++ b/admin-panel/src/components/App.js @@ -1,29 +1,23 @@ -import React, { Component } from 'react' +import React from 'react' import {Route, NavLink} from 'react-router-dom' import AuthPage from './routes/auth' import AdminPage from './routes/Admin' import ProtectedRoute from './common/ProtectedRoute' import PersonPage from './routes/PersonPage' +import EventsPage from './routes/EventsPage'; -class App extends Component { - static propTypes = { +const App = () => +
+

Hello world

+ + + + + +
- }; - - render() { - return ( -
-

Hello world

- - - - -
- ) - } -} - -export default App \ No newline at end of file +export default App; \ 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..0a1a4a6 --- /dev/null +++ b/admin-panel/src/components/people/PeopleList.js @@ -0,0 +1,14 @@ +import React from 'react' + +export default ({list}) => +
+

People

+
+
Id. Email Имя Фамилия
+ {list.map((p, idx) => ( +
+ {idx}. {p.email} {p.firstName} {p.lastName} +
+ ))} +
+
diff --git a/admin-panel/src/components/routes/Admin.js b/admin-panel/src/components/routes/Admin.js index 952248e..91dbb03 100644 --- a/admin-panel/src/components/routes/Admin.js +++ b/admin-panel/src/components/routes/Admin.js @@ -1,17 +1,6 @@ -import React, { Component } from 'react' +import React from 'react' -class Admin extends Component { - static propTypes = { - - }; - - render() { - return ( -
-

Admin Page

-
- ) - } -} - -export default Admin \ No newline at end of file +export default () => +
+

Admin Page

+
\ 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..80e4a3b --- /dev/null +++ b/admin-panel/src/components/routes/EventsPage.js @@ -0,0 +1,44 @@ +import React from 'react' +import {connect} from 'react-redux' +import {saveEventsToDb, eventsSelector, loaderSelector} from '../../ducks/event' + +const EventsPage = ({saveEventsToDb,eventList, loading }) => +
+

Events Page

+ + +

Events List

+ + + + + + + + + + + + + + {!loading && eventList.map(value => + value.map((prop,key) => + + + + + + + + + ) + )} + {loading && } + +
monthsubmissionDeadlinetitleurlwhenwhere
{prop.month}{prop.submissionDeadline}{prop.title}{prop.url}{prop.when}{prop.where}

Loading...

+
+ +export default connect(state => ({ + eventList: eventsSelector(state), + loading:loaderSelector(state) +}), {saveEventsToDb})(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 index fd69263..a1708ae 100644 --- a/admin-panel/src/components/routes/PersonPage.js +++ b/admin-panel/src/components/routes/PersonPage.js @@ -1,21 +1,18 @@ -import React, { Component } from 'react' +import React from 'react' import {connect} from 'react-redux' -import {addPerson} from '../../ducks/people' +import {addPerson, peopleSelector} from '../../ducks/people' import NewPersonForm from '../people/NewPersonForm' +import PeopleList from '../people/PeopleList'; -class PersonPage extends Component { - static propTypes = { +const PersonPage = + ({addPerson, peopleList}) => +
+

Add new person

+ + +
- }; - render() { - return ( -
-

Add new person

- -
- ) - } -} - -export default connect(null, {addPerson})(PersonPage) \ No newline at end of file +export default connect(state => ({ + peopleList: peopleSelector(state) +}), {addPerson})(PersonPage) \ No newline at end of file diff --git a/admin-panel/src/components/routes/auth/index.js b/admin-panel/src/components/routes/auth/index.js index 91c9bab..9114b86 100644 --- a/admin-panel/src/components/routes/auth/index.js +++ b/admin-panel/src/components/routes/auth/index.js @@ -1,7 +1,8 @@ import React, { Component } from 'react' import {Route, NavLink} from 'react-router-dom' import {connect} from 'react-redux' -import {signIn, signUp} from '../../../ducks/auth' + +import {signIn, signUp, errorSelector, loadingSelector} from '../../../ducks/auth' import SignInForm from '../../auth/SignInForm' import SignUpForm from '../../auth/SignUpForm' @@ -11,6 +12,7 @@ class Auth extends Component { }; render() { + const {loading, error} = this.props; return (

Auth page

@@ -20,6 +22,12 @@ class Auth extends Component { } /> } /> + {error !== null && +

{error}

+ } + {loading && +
Loading...
+ }
) } @@ -29,4 +37,7 @@ class Auth extends Component { } -export default connect(null, { signIn, signUp })(Auth) \ No newline at end of file +export default connect(state => ({ + error: errorSelector(state), + loading: loadingSelector(state) +}), { signIn, signUp })(Auth) \ No newline at end of file diff --git a/admin-panel/src/components/user/UserForm.js b/admin-panel/src/components/user/UserForm.js new file mode 100644 index 0000000..36541c8 --- /dev/null +++ b/admin-panel/src/components/user/UserForm.js @@ -0,0 +1,46 @@ +import React, { Component } from 'react' +import {reduxForm, Field} from 'redux-form' +import validator from 'email-validator' + +import ErrorField from '../common/ErrorField' + +class UserForm extends Component { + static propTypes = { + + }; + + render() { + const {mode} = this.props; + return ( +
+

{mode === 'add' ? 'Add user' : 'Edit User' }

+
+
+ First name: +
+
+ Last name: +
+
+ email: +
+ +
+ +
+ ) + } +} +const validate = ({ email }) => { + const errors = {} + + if (!email) errors.email = 'email is a required field' + if (email && !validator.validate(email)) errors.email = 'incorrect email format' + + return errors +} + +export default reduxForm({ + form: 'user', + validate +})(UserForm) \ No newline at end of file diff --git a/admin-panel/src/config.js b/admin-panel/src/config.js index 65bba00..8bb4843 100644 --- a/admin-panel/src/config.js +++ b/admin-panel/src/config.js @@ -1,14 +1,15 @@ import firebase from 'firebase' -export const appName = 'advreact-04-12' +export const appName = 'advreact-04-12-vesna' const config = { - apiKey: "AIzaSyCmDWlgYIhtEr1pWjgKYds3iXKWBl9wbjE", + appName: appName, + apiKey: "AIzaSyAkBB770P-MOKox9k6DjFRKi9J-bIoMnJs", authDomain: `${appName}.firebaseapp.com`, databaseURL: `https://${appName}.firebaseio.com`, projectId: appName, storageBucket: "", - messagingSenderId: "95255462276" + messagingSenderId: "786443944884" } firebase.initializeApp(config) \ 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..c89ddb7 --- /dev/null +++ b/admin-panel/src/ducks/auth.test.js @@ -0,0 +1,191 @@ +import {call, put, take} from 'redux-saga/effects' +import { + signInSaga, + SIGN_IN_REQUEST, + SIGN_IN_START, + SIGN_IN_SUCCESS, + SIGN_IN_ERROR, + + signUpSaga, + SIGN_UP_REQUEST, + SIGN_UP_START, + SIGN_UP_SUCCESS, + SIGN_UP_ERROR +} from './auth'; +import firebase from 'firebase' + +describe('auth saga', () => { + + /** + * Sign in tests + */ + + it('should sign in person', () => { + const user = { + password: '123456', + email: 'ivanovasvetlana1991@gmail.com' + } + + const action = { + type: SIGN_IN_REQUEST, + payload: { user } + } + + const generator = signInSaga(action) + + expect(generator.next().value).toEqual(put({ + type: SIGN_IN_START + })) + + const auth = firebase.auth() + + expect(JSON.stringify(generator.next().value)).toEqual(JSON.stringify( + call( + [auth, auth.createUserWithEmailAndPassword], + action.payload.email, + action.payload.password + ) + ) + ) + + expect(generator.next(user).value).toEqual( + put({ + type: SIGN_IN_SUCCESS, + payload: { user } + }) + ) + + expect(generator.next().done).toBe(true) + + }); + + it('should be error in sign in request', () => { + const user = { + password: '1236', + email: 'ivanovasvetlana1991@gmail.com' + } + + const action = { + type: SIGN_IN_REQUEST, + payload: { user } + } + + const generator = signInSaga(action) + + expect(generator.next().value).toEqual(put({ + type: SIGN_IN_START + })) + + const auth = firebase.auth() + + expect(JSON.stringify(generator.next().value)).toEqual(JSON.stringify( + call( + [auth, auth.createUserWithEmailAndPassword], + action.payload.email, + action.payload.password + ) + ) + ) + + const error = new Error('something went wrong') + + expect(generator.throw(error).value).toEqual( + put({ + type: SIGN_IN_ERROR, + payload: { error } + }) + ) + + expect(generator.next().done).toBe(true) + + }); + + /** + * Sign up tests + */ + + it('should sign up person', () => { + const user = { + password: '123456', + email: 'ivanovasvetlana1991@gmail.com' + } + + const action = { + type: SIGN_UP_REQUEST, + payload: { user } + } + + const generator = signUpSaga() + + expect(generator.next().value).toEqual(take(SIGN_UP_REQUEST)) + + expect(generator.next(action).value).toEqual(put({ + type: SIGN_UP_START + })) + + const auth = firebase.auth() + + expect(JSON.stringify(generator.next().value)).toEqual(JSON.stringify( + call( + [auth, auth.createUserWithEmailAndPassword], + action.payload.email, + action.payload.password + ) + ) + ) + + expect(generator.next(user).value).toEqual( + put({ + type: SIGN_UP_SUCCESS, + payload: { user } + }) + ) + + expect(generator.next().value).toEqual(take(SIGN_UP_REQUEST)) + + }); + + it('should throw error in sign up ', () => { + const user = { + password: '123456', + email: 'ivanovasvetlana1991@gmail.com' + } + + const action = { + type: SIGN_UP_REQUEST, + payload: { user } + } + + const generator = signUpSaga() + + expect(generator.next().value).toEqual(take(SIGN_UP_REQUEST)) + + expect(generator.next(action).value).toEqual(put({ + type: SIGN_UP_START + })) + + const auth = firebase.auth() + + expect(JSON.stringify(generator.next().value)).toEqual(JSON.stringify( + call( + [auth, auth.createUserWithEmailAndPassword], + action.payload.email, + action.payload.password + ) + ) + ) + + const error = new Error('something went wrong') + + expect(generator.throw(error).value).toEqual( + put({ + type: SIGN_UP_ERROR, + payload: { error } + }) + ) + + expect(generator.next().value).toEqual(take(SIGN_UP_REQUEST)) + + }); + +}); \ No newline at end of file diff --git a/admin-panel/src/ducks/event.js b/admin-panel/src/ducks/event.js new file mode 100644 index 0000000..e3e69d7 --- /dev/null +++ b/admin-panel/src/ducks/event.js @@ -0,0 +1,130 @@ +import {appName} from '../config' +import {Record, List} from 'immutable' +import {put, call, all, takeEvery} from 'redux-saga/effects' +import {createSelector} from 'reselect' + +import {saveEventsToFB, getEventsFromFB} from '../mocks/index'; + +/** + * Constants + * */ + +export const moduleName = 'event' +const prefix = `${appName}/${moduleName}` + +export const ADD_EVENTS_REQUEST = `${prefix}/ADD_EVENTS_REQUEST` +export const ADD_EVENTS_START = `${prefix}/ADD_EVENTS_START` +export const ADD_EVENTS_SUCCESS = `${prefix}/ADD_EVENTS_SUCCESS` +export const ADD_EVENTS_ERROR = `${prefix}/ADD_EVENTS_ERROR` + +export const GET_EVENTS_REQUEST = `${prefix}/GET_EVENTS_REQUEST` +export const GET_EVENTS_START = `${prefix}/GET_EVENTS_START` +export const GET_EVENTS_SUCCESS = `${prefix}/GET_EVENTS_SUCCESS` +export const GET_EVENTS_ERROR = `${prefix}/GET_EVENTS_ERROR` + +/** + * Reducer + * */ +const ReducerState = Record({ + entities: new List([]), + loading: false, + error: null +}) + + +export default function reducer(state = new ReducerState(), action) { + const {type, payload} = action + + switch (type) { + case ADD_EVENTS_START: + return state + .set('error', null) + .set('loading', true) + + case GET_EVENTS_SUCCESS: + return state + .update('entities', entities => entities.push(Object.values(payload.events))) + .set('loading', false) + + case ADD_EVENTS_ERROR: + case GET_EVENTS_ERROR: + return state + .set('loading', false) + .set('error', payload.error.message) + default: + return state + } +} + +/** + * Selectors + * */ +export const stateSelector = state => state[moduleName] +export const eventsSelector = createSelector(stateSelector, state => state.entities) +export const loaderSelector = createSelector(stateSelector, state => state.loading) + +/** + * Action Creators + * */ + +export function saveEventsToDb() { + return { + type: ADD_EVENTS_REQUEST + } +} + +/** + * Sagas + */ + +export const saveEventsSaga = function * (action) { + try { + yield put({ + type: ADD_EVENTS_START + }) + let events = yield call(getEventsFromFB); + + if(events === null){ + events = yield call(saveEventsToFB) + } + + yield put({ + type: ADD_EVENTS_SUCCESS, + payload: { events } + }) + }catch(error){ + yield put({ + type: ADD_EVENTS_ERROR, + payload: { error } + }) + } +} + +export const fetchEventsSaga = function * (action){ + try{ + yield put({ + type: GET_EVENTS_START + }) + const events = yield call(getEventsFromFB) + + yield put({ + type: GET_EVENTS_SUCCESS, + payload: { events } + }) + + } + catch(error){ + yield put({ + type: GET_EVENTS_ERROR, + payload: { error } + }) + } +} + + +export const saga = function * () { + yield all([ + takeEvery(ADD_EVENTS_REQUEST, saveEventsSaga), + takeEvery(ADD_EVENTS_SUCCESS,fetchEventsSaga) + ]) +} \ No newline at end of file diff --git a/admin-panel/src/ducks/people.js b/admin-panel/src/ducks/people.js index 52bce70..e7063cb 100644 --- a/admin-panel/src/ducks/people.js +++ b/admin-panel/src/ducks/people.js @@ -1,6 +1,8 @@ import {appName} from '../config' import {Record, List} from 'immutable' import {put, call, all, takeEvery} from 'redux-saga/effects' +import {createSelector} from 'reselect' +import {reset} from 'redux-form'; import {generateId} from './utils' /** @@ -10,6 +12,7 @@ export const moduleName = 'people' const prefix = `${appName}/${moduleName}` export const ADD_PERSON = `${prefix}/ADD_PERSON` export const ADD_PERSON_SUCCESS = `${prefix}/ADD_PERSON_SUCCESS` +export const ADD_PERSON_ERROR = `${prefix}/ADD_PERSON_ERROR` /** * Reducer @@ -30,7 +33,7 @@ export default function reducer(state = new ReducerState(), action) { switch (type) { case ADD_PERSON_SUCCESS: - return state.update('entities', entities => entities.push(new PersonRecord(payload.person))) + return state.update('entities', entities => entities.push(new PersonRecord(payload))) default: return state @@ -40,6 +43,8 @@ export default function reducer(state = new ReducerState(), action) { /** * Selectors * */ +export const stateSelector = state => state[moduleName] +export const peopleSelector = createSelector(stateSelector, state => state.entities) /** * Action Creators @@ -59,12 +64,20 @@ export function addPerson(person) { export const addPersonSaga = function * (action) { const { person } = action.payload - const id = yield call(generateId) + try { + const id = yield call(generateId) - yield put({ - type: ADD_PERSON_SUCCESS, - payload: {id, ...person} - }) + yield put({ + type: ADD_PERSON_SUCCESS, + payload: { id, ...person } + }) + yield put(reset('person')) + }catch(error){ + yield put({ + type: ADD_PERSON_ERROR, + payload: { error } + }) + } } export const saga = function * () { diff --git a/admin-panel/src/ducks/user.js b/admin-panel/src/ducks/user.js new file mode 100644 index 0000000..675a121 --- /dev/null +++ b/admin-panel/src/ducks/user.js @@ -0,0 +1,75 @@ +import {appName} from '../config' +import {Record} from 'immutable' +import firebase from 'firebase' + +/** + * Constants + * */ +export const moduleName = 'user' +const prefix = `${appName}/${moduleName}` + +export const ADD_USER_START = `${prefix}/ADD_USER_START` +export const ADD_USER_SUCCESS = `${prefix}/ADD_USER_SUCCESS` +export const ADD_USER_FAIL = `${prefix}/ADD_USER_FAIL` + +/** + * Reducer + * */ +export const ReducerRecord = Record({ + //users: null, + loading: false, + error: null +}) + +export default function reducer(state = new ReducerRecord(), action) { + const {type, payload} = action + + switch (type) { + case ADD_USER_START: + return state.set('loading', true) + + case ADD_USER_SUCCESS: + return state + .set('loading', false) + + case ADD_USER_FAIL: + return state + .set('loading', false) + .set('error', payload.error.message) + + default: + return state + } +} + +/** + * Selectors + * */ + +//export const userListSelector = state => state[moduleName].users +export const userLoaderSelector = state => state[moduleName].loading +export const userErrorSelector = state => state[moduleName].error + +/** + * Action Creators + * */ + +export function addUser(firstName, lastName, email) { + return (dispatch) => { + dispatch({ + type: ADD_USER_START + }) + + const db = firebase.database(); + const users = db.ref().child('users'); + + users.push({firstName, lastName, email}) + .then(answer => dispatch({ + type: ADD_USER_SUCCESS + })) + .catch(error => dispatch({ + type: ADD_USER_FAIL, + payload: { error } + })) + } +} diff --git a/admin-panel/src/mocks/index.js b/admin-panel/src/mocks/index.js index d1a851f..57c2d98 100644 --- a/admin-panel/src/mocks/index.js +++ b/admin-panel/src/mocks/index.js @@ -6,4 +6,11 @@ export function saveEventsToFB() { conferences.forEach(conference => eventsRef.push(conference)) } +export function getEventsFromFB() { + const db = firebase.database() + const eventsRef = db.ref(`/events`) + return eventsRef.once('value').then(result => result.val() + ); +} + window.saveEventsToFB = saveEventsToFB \ No newline at end of file diff --git a/admin-panel/src/redux/reducer.js b/admin-panel/src/redux/reducer.js index cc6e0aa..0eb750b 100644 --- a/admin-panel/src/redux/reducer.js +++ b/admin-panel/src/redux/reducer.js @@ -3,9 +3,11 @@ import {routerReducer as router} from 'react-router-redux' import {reducer as form} from 'redux-form' import authReducer, {moduleName as authModule} from '../ducks/auth' import peopleReducer, {moduleName as peopleModule} from '../ducks/people' +import eventReducer, {moduleName as eventModule} from '../ducks/event' export default combineReducers({ router, form, [authModule]: authReducer, - [peopleModule]: peopleReducer + [peopleModule]: peopleReducer, + [eventModule]: eventReducer }) \ No newline at end of file diff --git a/admin-panel/src/redux/saga.js b/admin-panel/src/redux/saga.js index 4a6c841..c431ce8 100644 --- a/admin-panel/src/redux/saga.js +++ b/admin-panel/src/redux/saga.js @@ -1,10 +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 eventSaga} from '../ducks/event' export default function * rootSaga() { yield all([ peopleSaga(), - authSaga() + authSaga(), + eventSaga() ]) } \ No newline at end of file diff --git a/admin-panel/yarn.lock b/admin-panel/yarn.lock index 5e59e02..653af0e 100644 --- a/admin-panel/yarn.lock +++ b/admin-panel/yarn.lock @@ -1232,6 +1232,13 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" +buffer@^5.0.3: + version "5.0.8" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.0.8.tgz#84daa52e7cf2fa8ce4195bc5cf0f7809e0930b24" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + builtin-modules@^1.0.0, builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -1679,6 +1686,10 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" +css-color-keywords@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" + css-color-names@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" @@ -1719,6 +1730,14 @@ css-selector-tokenizer@^0.7.0: fastparse "^1.1.1" regexpu-core "^1.0.0" +css-to-react-native@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.0.4.tgz#cf4cc407558b3474d4ba8be1a2cd3b6ce713101b" + dependencies: + css-color-keywords "^1.0.0" + fbjs "^0.8.5" + postcss-value-parser "^3.3.0" + css-what@2.1: version "2.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" @@ -2555,7 +2574,7 @@ fb-watchman@^2.0.0: dependencies: bser "^2.0.0" -fbjs@^0.8.16: +fbjs@^0.8.16, fbjs@^0.8.5, fbjs@^0.8.9: version "0.8.16" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" dependencies: @@ -3057,6 +3076,10 @@ hoek@4.x.x: version "4.2.0" resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" +hoist-non-react-statics@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" + hoist-non-react-statics@^2.2.1, hoist-non-react-statics@^2.3.0, hoist-non-react-statics@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0" @@ -3384,6 +3407,10 @@ is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" +is-function@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -3436,6 +3463,12 @@ is-plain-obj@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" +is-plain-object@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" @@ -3520,6 +3553,10 @@ isobject@^2.0.0: dependencies: isarray "1.0.0" +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + isomorphic-fetch@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" @@ -6144,6 +6181,24 @@ style-loader@0.19.0: loader-utils "^1.0.2" schema-utils "^0.3.0" +styled-components@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-2.2.4.tgz#dd87fd3dafd359e7a0d570aec1bd07d691c0b5a2" + dependencies: + buffer "^5.0.3" + css-to-react-native "^2.0.3" + fbjs "^0.8.9" + hoist-non-react-statics "^1.2.0" + is-function "^1.0.1" + is-plain-object "^2.0.1" + prop-types "^15.5.4" + stylis "^3.4.0" + supports-color "^3.2.3" + +stylis@^3.4.0: + version "3.4.5" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.4.5.tgz#d7b9595fc18e7b9c8775eca8270a9a1d3e59806e" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"