Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
50 changes: 25 additions & 25 deletions admin-panel/src/components/people/NewPersonForm.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
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 = {
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>
)
}
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>
)
}
}

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);
10 changes: 8 additions & 2 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 @@ -13,9 +14,14 @@ class PersonPage extends Component {
<div>
<h2>Add new person</h2>
<NewPersonForm onSubmit={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: 'test@email.com',
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