Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions admin-panel/src/components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import AuthPage from './routes/auth'
import AdminPage from './routes/Admin'
import ProtectedRoute from './common/ProtectedRoute'
import PersonPage from './routes/PersonPage'
import EventsPage from './routes/Events'

class App extends Component {
static propTypes = {
Expand All @@ -17,10 +18,12 @@ class App extends Component {
<ul>
<li><NavLink to='/admin' activeStyle = {{color: 'red'}}>admin</NavLink></li>
<li><NavLink to='/people' activeStyle = {{color: 'red'}}>people</NavLink></li>
<li><NavLink to='/events' activeStyle = {{color: 'red'}}>events</NavLink></li>
</ul>
<ProtectedRoute path = '/admin' component = {AdminPage}/>
<ProtectedRoute path="/people" component={PersonPage}/>
<Route path = '/auth' component = {AuthPage}/>
<Route path = '/events' component = {EventsPage}/>
</div>
)
}
Expand Down
61 changes: 34 additions & 27 deletions admin-panel/src/components/people/NewPersonForm.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,47 @@
import React, { Component } from 'react'
import {reduxForm, Field} from 'redux-form'
import { reduxForm, Field } from 'redux-form'
import validateEmail from 'email-validator'
import ErrorField from '../common/ErrorField'

class NewPersonForm extends Component {
static propTypes = {

};

render() {
return (
<div>
<form onSubmit={this.props.handleSubmit}>
<Field name="firstName" label="first name" component={ErrorField}/>
<Field name="lastName" label="last name" component={ErrorField}/>
<Field name="email" label="email" component={ErrorField}/>
<div>
<input type="submit" />
</div>
</form>
</div>
)
}
static propTypes = {

};

submit = (values) => {
return new Promise((resolve) => {
this.props.addPerson(values, resolve)
})
.then(() => this.props.reset())
}

render() {
return (
<div>
<form onSubmit={this.props.handleSubmit(this.submit)}>
<Field name="firstName" label="first name" component={ErrorField} />
<Field name="lastName" label="last name" component={ErrorField} />
<Field name="email" label="email" component={ErrorField} />
<div>
<input type="submit" />
</div>
</form>
</div>
)
}
}

function validate({firstName, email}) {
const errors = {}
if (!firstName) errors.firstName = 'first name is required'
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'
if (!email) errors.email = 'email is required'
else if (!validateEmail.validate(email)) errors.email = 'email is invalid'

return errors
return errors
}

export default reduxForm({
form: 'person',
validate
form: 'person',
validate
})(NewPersonForm)
15 changes: 15 additions & 0 deletions admin-panel/src/components/people/PeopleList.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.people-list {
width: 100%;
border: 1px solid black;
border-collapse: collapse;
}

.people-list caption {
caption-side: top;
font-size: 1.3em;
}

.people-list th,
.people-list td {
border: 1px solid black;
}
28 changes: 28 additions & 0 deletions admin-panel/src/components/people/PeopleList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import './PeopleList.css';

export default function PeopleList(props) {
return (
<React.Fragment>
<table className="people-list">
<caption>People list</caption>
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{props.people.map(person => (
<tr key={person.id}>
<td>{person.firstName}</td>
<td>{person.lastName}</td>
<td>{person.email}</td>
</tr>
))}
</tbody>
</table>
</React.Fragment>
);
}
48 changes: 48 additions & 0 deletions admin-panel/src/components/routes/Events.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react';
import { connect } from 'react-redux';
import Loader from '../common/Loader';
import { dataSelector, loadingSelector, errorSelector, eventsRequest } from '../../ducks/events';

class Events extends React.Component {
componentDidMount() {
this.props.eventsRequest();
}

render() {
if (this.props.loading) return <Loader />;
if (this.props.error) return <h2 style={{ color: 'red' }}>{this.props.error}</h2>;

return (
<table>
<thead>
<tr>
<th>Month</th>
<th>Submission dead line</th>
<th>Title</th>
<th>URL</th>
<th>When</th>
<th>Where</th>
</tr>
</thead>
<tbody>
{this.props.events.map(event => (
<tr key={event.id}>
<td>{event.month}</td>
<td>{event.submissionDeadline}</td>
<td>{event.title}</td>
<td>{event.url}</td>
<td>{event.when}</td>
<td>{event.where}</td>
</tr>
))}
</tbody>
</table>
);
}
}

export default connect(state => ({
events: dataSelector(state),
loading: loadingSelector(state),
error: errorSelector(state),
}), { eventsRequest })(Events);
12 changes: 9 additions & 3 deletions admin-panel/src/components/routes/PersonPage.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { Component } 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 = {
Expand All @@ -12,10 +13,15 @@ class PersonPage extends Component {
return (
<div>
<h2>Add new person</h2>
<NewPersonForm onSubmit={this.props.addPerson}/>
<NewPersonForm addPerson={this.props.addPerson}/>
<PeopleList people={this.props.people}/>
</div>
)
}
}

export default connect(null, {addPerson})(PersonPage)
const mapStateToProps = state => ({
people: peopleSelector(state)
});

export default connect(mapStateToProps, {addPerson})(PersonPage)
6 changes: 3 additions & 3 deletions admin-panel/src/config.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import firebase from 'firebase'

export const appName = 'advreact-04-12'
export const appName = 'advreact-386f6'

const config = {
apiKey: "AIzaSyCmDWlgYIhtEr1pWjgKYds3iXKWBl9wbjE",
apiKey: "AIzaSyDSPRtistNZnrnNMJXCra5uS9Ugpken3F0",
authDomain: `${appName}.firebaseapp.com`,
databaseURL: `https://${appName}.firebaseio.com`,
projectId: appName,
storageBucket: "",
messagingSenderId: "95255462276"
messagingSenderId: "648901552269"
}

firebase.initializeApp(config)
113 changes: 113 additions & 0 deletions admin-panel/src/ducks/auth.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { take, put, call, apply } from 'redux-saga/effects';
import firebase from 'firebase';
import {
signUpSaga,
signInSaga,
SIGN_UP_REQUEST,
SIGN_UP_START,
SIGN_UP_SUCCESS,
SIGN_UP_ERROR,
SIGN_IN_START,
SIGN_IN_SUCCESS,
SIGN_IN_ERROR,
} from './auth';

const action = {
type: SIGN_UP_REQUEST,
payload: {
email: '[email protected]',
password: '8888888',
},
};

const { email, password } = action.payload;

const auth = firebase.auth();

const user = {
userData: 'data',
};

const error = new Error('Something went wrong');

describe('signUpSaga saga', () => {
test('signup has done successfully', () => {
const generator = signUpSaga();

expect(generator.next().value)
.toEqual(take(SIGN_UP_REQUEST));

expect(generator.next(action).value)
.toEqual(put({ type: SIGN_UP_START }));

expect(generator.next().value)
.toEqual(call([auth, auth.createUserWithEmailAndPassword], email, password));

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

expect(generator.next().done).toBe(false);
});

test('signup has done unsuccessfully', () => {
const generator = signUpSaga();

expect(generator.next().value)
.toEqual(take(SIGN_UP_REQUEST));

expect(generator.next(action).value)
.toEqual(put({ type: SIGN_UP_START }));

expect(generator.next().value)
.toEqual(call([auth, auth.createUserWithEmailAndPassword], email, password));

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

expect(generator.next().done).toBe(false);
});
});

describe('signInSaga saga', () => {
test('signin has done successfully, ', () => {
const generator = signInSaga(action);

expect(generator.next().value)
.toEqual(put({ type: SIGN_IN_START }));

expect(generator.next().value)
.toEqual(apply(auth, auth.signInWithEmailAndPassword, [email, password]));

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

expect(generator.next().done).toBe(true);
});

test('signin has done unsuccessfully, ', () => {
const generator = signInSaga(action);

expect(generator.next().value)
.toEqual(put({ type: SIGN_IN_START }));

expect(generator.next().value)
.toEqual(apply(auth, auth.signInWithEmailAndPassword, [email, password]));

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

expect(generator.next().done).toBe(true);
});
});
Loading