project link: http://chuanshuoge1.github.io/react-redux-schedule
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { Provider } from "react-redux";
import store from "./store";
import 'bootstrap/dist/css/bootstrap.min.css';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById('root'));
registerServiceWorker();
---------------------------------------------------------------------------------
App.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import './App.css';
import AddForm from './forms/add';
import DeleteForm from './forms/delete';
import UpdateForm from './forms/update'
import { display_rawSchedules } from './quickFunctions.js';
class App extends Component {
render() {
return (
<div>
{display_rawSchedules(this.props.schedules)}
<AddForm />
<DeleteForm schedules={this.props.schedules} />
<UpdateForm schedules={this.props.schedules} />
</div>
);
}
}
export default connect(
(store) => {
return {
schedules: store.schedules.schedules,
};
}
)(App);
store.js
import { applyMiddleware, createStore } from 'redux';
import logger from 'redux-logger';
import thunk from 'redux-thunk';
import promiseMiddleware from 'redux-promise-middleware';
import reducer from "./reducers";
const middleware = applyMiddleware(promiseMiddleware(), thunk, logger);
export default createStore(reducer, middleware);
------------------------------------------------------------------------------
quickFunctions.js
import React from 'react';
export const display_rawSchedules = (data) => {
const scheduleView = data.map((item, index) => {
const matchView = data[index].matches.map((item2, index2) =>
<div key={index2}>
{"{"}
home: {item2.home}, away: {item2.away},
home score: {item2.homeScore}, away score: {item2.awayScore}
{"}, "}
</div>
);
return (<div key={index}>
date: {item.date.toDateString()}<br />
matches: {matchView}<br />
</div>);
})
return (<div>{scheduleView}</div>);
}
export const dateToString = (date) => {
const year = date.getFullYear().toString();
const month = date.getMonth() + 1;
const month0 = month < 10 ? '0' + month.toString() : month.toString();
const day = date.getDate();
const day0 = day < 10 ? '0' + day.toString() : day.toString();
const newDate = year + '-' + month0 + '-' + day0;
return newDate;
};
export const stringToDate = (input_string) => {
const year_month_day = input_string.split('-');
const year = parseInt(year_month_day[0]);
const month = parseInt(year_month_day[1]) - 1;
const day = parseInt(year_month_day[2]);
return new Date(year, month, day);
}
----------------------------------------------------------------------
actions/scheduleAction.js
export function addSchedule(form) {
return {
type: "add_schedule",
payload: form
}
}
export function deleteAll(schedule_index) {
return {
type: "delete_all",
payload: schedule_index
}
}
export function deleteSingle(schedule_index, match_index) {
return {
type: "delete_single",
payload: {
scheduleIndex: schedule_index,
matchIndex: match_index,
}
}
}
export function updateSchedule(form, schedule_index, match_index) {
return {
type: "update_schedule",
payload: {
form: form,
scheduleIndex: schedule_index,
matchIndex: match_index,
}
}
}
--------------------------------------------------------------------
reducers/index.js
import { combineReducers } from 'redux';
import schedules from "./scheduleReducer";
export default combineReducers(
{
schedules
})
-------------------------------------------------------
reducers/scheduleReducer.js
import { stringToDate, dateToString } from '../quickFunctions'
export default function reducer(
state = {
schedules: [
{
date: new Date(2018, 4, 22),
matches: [
{ home: "santos", away: "real garcilaso", homeScore: 0, awayScore: 0 },
{ home: "atletico nacional", away: "colo colo", homeScore: 0, awayScore: 0 },
{ home: "corinthians", away: "millonarios", homeScore: 0, awayScore: 1 },
{ home: "independiente", away: "deportivolara", homeScore: 2, awayScore: 0 },
]
},
{
date: new Date(2018, 4, 21),
matches: [
{ home: "toronto fc", away: "fc dallas", homeScore: 0, awayScore: 2 },
{ home: "houston dynamo", away: "new york city fc", homeScore: 2, awayScore: 1 },
{ home: "portland thorns fc", away: "utah royals fc", homeScore: 2, awayScore: 1 },
{ home: "los angeles galaxy", away: "san joes earthquakes", homeScore: 0, awayScore: 0 },
]
},
{
date: new Date(2018, 5, 4),
matches: [
{ home: "thailand", away: "china pr", homeScore: 0, awayScore: 1 },
{ home: "austria", away: "germany", homeScore: 3, awayScore: 1 },
{ home: "england", away: "nigeria", homeScore: 1, awayScore: 0 },
{ home: "sweden", away: "denmark", homeScore: 0, awayScore: 0 },
]
},
{
date: new Date(2018, 4, 28),
matches: [
{ home: "brazil", away: "croatia", homeScore: 2, awayScore: 0 },
{ home: "costa rica", away: "northern ireland", homeScore: 3, awayScore: 0 },
{ home: "saudi arabia", away: "peru", homeScore: 0, awayScore: 3 },
{ home: "bahia", away: "gremio", homeScore: 0, awayScore: 1 },
]
},
],
activeTab: "Monday",
dateFilter: "",
},
action
) {
switch (action.type) {
case "add_schedule": {
const newMatch = {
home: action.payload.home,
away: action.payload.away,
homeScore: action.payload.homeScore,
awayScore: action.payload.awayScore,
};
const newSchedules = [...state.schedules];
const findDate_index = newSchedules.findIndex(x => dateToString(x.date) === action.payload.date);
//add to existing schedule
if (findDate_index >= 0) {
newSchedules[findDate_index].matches.push(newMatch);
}
//create new schedule
else {
const newSchedule =
{
date: stringToDate(action.payload.date),
matches: [
newMatch,
]
};
newSchedules.push(newSchedule);
}
return { ...state, schedules: newSchedules }
}
case "delete_all": {
const newSchedules = [...state.schedules];
newSchedules.splice(action.payload, 1);
return { ...state, schedules: newSchedules }
}
case "delete_single": {
const newSchedules = [...state.schedules];
newSchedules[action.payload.scheduleIndex].
matches.splice(action.payload.matchIndex, 1);
return { ...state, schedules: newSchedules }
}
case "update_schedule": {
const newSchedules = [...state.schedules];
newSchedules[action.payload.scheduleIndex].
matches[action.payload.matchIndex] = {
home: action.payload.form.home,
away: action.payload.form.away,
homeScore: action.payload.form.homeScore,
awayScore: action.payload.form.awayScore,
}
return { ...state, schedules: newSchedules }
}
default:
break;
}
return state;
}
-------------------------------------------------------------------------------
forms/add.jsimport React, { Component } from 'react';
import { Button, Form, FormGroup, Input } from 'reactstrap';
import { stringToDate } from '../quickFunctions.js';
import { connect } from 'react-redux';
import { addSchedule } from '../actions/scheduleAction';
import '../App.css';
export class AddForm extends Component {
constructor(props) {
super(props);
this.state = {
date: "",
home: "",
away: "",
homeScore: 0,
awayScore: 0,
status: "",
};
}
handle_submit(e) {
if (this.state.home === "" || this.state.away === "" || this.state.date === "") {
return false;
}
else {
const formData = {
date: this.state.date,
home: this.state.home,
away: this.state.away,
homeScore: this.state.homeScore,
awayScore: this.state.awayScore,
};
this.props.dispatch(addSchedule(formData));
}
e.preventDefault();
const messageStatus = "successfully added to " + stringToDate(this.state.date).toDateString();
this.setState({ status: messageStatus });
}
render() {
return (
<div className="my-schedule-form-add">
<h4>Add Schedule <span className="my-status">{this.state.status}</span></h4>
<Form inline onSubmit={(e) => this.handle_submit(e)}>
<FormGroup >
<Input type="date" bsSize="sm" name="matchDate" placeholder="Match Date" required="required"
onChange={(e) => this.setState({ date: e.target.value })} />
</FormGroup>
<FormGroup >
<Input bsSize="sm" placeholder="Home Team" required="required"
onChange={(e) => this.setState({ home: e.target.value })} />
</FormGroup>
<FormGroup >
<Input bsSize="sm" placeholder="Away Team" required="required"
onChange={(e) => this.setState({ away: e.target.value })} />
</FormGroup>
<FormGroup >
<Input type="number" bsSize="sm" placeholder="Home Score"
onChange={(e) => this.setState({ homeScore: e.target.value })} />
</FormGroup>
<FormGroup >
<Input type="number" bsSize="sm" placeholder="Away Score"
onChange={(e) => this.setState({ awayScore: e.target.value })} />
</FormGroup>
<Button size="sm" type="submit" onClick={() => this.setState({ status: "" })}> Submit</Button>
</Form>
</div>
);
}
}
export default connect(
(store) => {
return {
schedules: store.schedules.schedules,
};
}
)(AddForm);
------------------------------------------------------------------
forms/delete.js
import React, { Component } from 'react';
import { Button, Input, Row, Col } from 'reactstrap';
import { dateToString } from '../quickFunctions.js';
import { connect } from 'react-redux';
import { deleteAll, deleteSingle } from '../actions/scheduleAction.js';
import '../App.css';
export class DeleteForm extends Component {
constructor(props) {
super(props);
this.state = {
selectedMatch: 0,
selectedDate: "",
dateDisable: false,
matchDisable: false,
status:"",
};
}
handle_selectDate(e) {
this.setState({
dateDisable: true,
selectedDate: e.target.value,
});
}
handle_selectMatch(e) {
this.setState({
matchDisable: true,
selectedMatch: parseInt(e.target.value.split(' ')[0].slice(1)) - 1,
});
}
handle_deleteSingle() {
const selectedSchedule_index = this.props.schedules.findIndex(
x => dateToString(x.date) === this.state.selectedDate);
this.props.dispatch(
deleteSingle(selectedSchedule_index, this.state.selectedMatch));
const messageStatus = "deleted " + this.state.selectedDate + " match " +
(this.state.selectedMatch + 1).toString();
this.setState({ status: messageStatus });
}
handle_deleteAll() {
const selectedSchedule_index = this.props.schedules.findIndex(
x => dateToString(x.date) === this.state.selectedDate);
this.props.dispatch(deleteAll(selectedSchedule_index));
const messageStatus = "deleted " + this.state.selectedDate;
this.setState({ status: messageStatus });
}
render() {
const dateOptions = this.props.schedules.
map((item, index) => {
const dateString = dateToString(item.date);
return (
<option key={dateString}>{dateString}</option>);
}).
sort((a, b) => {
return a.key.localeCompare(b.key)
});
dateOptions.unshift(<option key={-1} disabled={this.state.dateDisable}>
select date</option>);
const selectedSchedule_index = this.props.schedules.findIndex(
x => dateToString(x.date) === this.state.selectedDate);
const matchOptions = selectedSchedule_index >= 0 ?
this.props.schedules[selectedSchedule_index].matches.
map((item, index) =>
<option key={index}>#{index + 1} {item.home} vs {item.away}</option>
)
: [];
matchOptions.unshift(<option key={-1} disabled={this.state.matchDisable}>
select match</option>);
return (
<div className="my-schedule-form-delete">
<h4>Delete Schedule <span className="my-status">{this.state.status}</span></h4>
<Row>
<Col xs="3">
<Input type="select" bsSize="sm"
onChange={(e) => this.handle_selectDate(e)}>
{dateOptions}</Input>
</Col>
<Col xs="5">
<Input type="select" bsSize="sm" disabled={!this.state.dateDisable}
onChange={(e) => this.handle_selectMatch(e)}>
{matchOptions}</Input>
</Col>
<Col xs="2">
<Button size="sm" disabled={!this.state.matchDisable}
onClick={() => this.handle_deleteSingle()}>
Delete single</Button>
</Col>
<Col xs="2">
<Button size="sm" disabled={!this.state.dateDisable}
onClick={() => this.handle_deleteAll()}>
Delete all</Button>
</Col>
</Row>
</div>
);
}
}
export default connect(
(store) => {
return {
schedules: store.schedules.schedules,
};
}
)(DeleteForm);
------------------------------------------------------------------
forms/update.js
import React, { Component } from 'react';
import { Button, Form, FormGroup, Input, Row, Col } from 'reactstrap';
import { dateToString, stringToDate } from '../quickFunctions.js';
import { connect } from 'react-redux';
import { updateSchedule} from '../actions/scheduleAction.js';
import '../App.css';
export class UpdateForm extends Component {
constructor(props) {
super(props);
this.state = {
selectedMatch: 0,
selectedDate: "",
dateDisable: false,
matchDisable: false,
home: "Home Team",
away: "Away Team",
homeScore: 0,
awayScore: 0,
status:"select date -> match -> update input -> submit",
};
}
handle_selectDate(e) {
this.setState({
dateDisable: true,
selectedDate: e.target.value,
});
}
handle_selectMatch(e) {
const matchIndex = parseInt(e.target.value.split(' ')[0].slice(1)) - 1;
const scheduleIndex = this.props.schedules.findIndex(
x => dateToString(x.date) === this.state.selectedDate);
const matchSelected = this.props.schedules[scheduleIndex].matches[matchIndex];
this.setState({
matchDisable: true,
selectedMatch: matchIndex,
home: matchSelected.home,
away: matchSelected.away,
homeScore: matchSelected.homeScore,
awayScore: matchSelected.awayScore,
});
}
handle_submit(e) {
if (this.state.home === "" || this.state.away === "") {
return false;
}
else {
const formData = {
home: this.state.home,
away: this.state.away,
homeScore: this.state.homeScore,
awayScore: this.state.awayScore,
};
const selectedSchedule_index = this.props.schedules.findIndex(
x => dateToString(x.date) === this.state.selectedDate);
this.props.dispatch(updateSchedule(
formData,
selectedSchedule_index,
this.state.selectedMatch,
));
}
e.preventDefault();
const messageStatus = "updated " + this.state.selectedDate + " match " +
(this.state.selectedMatch+1).toString();
this.setState({ status: messageStatus });
}
render() {
const dateOptions = this.props.schedules.
map((item, index) => {
const dateString = dateToString(item.date);
return (
<option key={dateString}>{dateString}</option>);
}).
sort((a, b) => {
return a.key.localeCompare(b.key)
});
dateOptions.unshift(<option key={-1} disabled={this.state.dateDisable}>
select date</option>);
const selectedSchedule_index = this.props.schedules.findIndex(
x => dateToString(x.date) === this.state.selectedDate);
const matchOptions = selectedSchedule_index >= 0 ?
this.props.schedules[selectedSchedule_index].matches.
map((item, index) =>
<option key={index}>#{index + 1} {item.home} vs {item.away}</option>
)
: [];
matchOptions.unshift(<option key={-1} disabled={this.state.matchDisable}>
select match</option>);
return (
<div className="my-schedule-form-update">
<h4>update Schedule <span className="my-status">{this.state.status}</span></h4>
<Row>
<Col xs="3">
<Input type="select" bsSize="sm"
onChange={(e) => this.handle_selectDate(e)}>
{dateOptions}</Input>
</Col>
<Col xs="5">
<Input type="select" bsSize="sm" disabled={!this.state.dateDisable}
onChange={(e) => this.handle_selectMatch(e)}>
{matchOptions}</Input>
</Col>
</Row>
<Form inline onSubmit={(e) => this.handle_submit(e)} >
<FormGroup >
<Input bsSize="sm" placeholder={this.state.home}
onChange={(e) => this.setState({ home: e.target.value })} />
</FormGroup>
<FormGroup >
<Input bsSize="sm" placeholder={this.state.away}
onChange={(e) => this.setState({ away: e.target.value })} />
</FormGroup>
<FormGroup >
<span id="update_homeScore">
<span className="my-tooltip">home score</span>
<Input type="number" bsSize="sm" placeholder={this.state.homeScore}
onChange={(e) => e.target.value !== "" ? this.setState({ homeScore: e.target.value }) : null}
disabled={this.state.disable_input} />
</span>
</FormGroup>
<FormGroup >
<span id="update_awayScore">
<span className="my-tooltip">away score</span>
<Input type="number" bsSize="sm" placeholder={this.state.awayScore}
onChange={(e) => e.target.value !== "" ? this.setState({ awayScore: e.target.value }) : null}
disabled={this.state.disable_input} />
</span>
</FormGroup>
<Button size="sm" type="submit" disabled={!this.state.matchDisable}
onClick={() => this.setState({ status: "select date -> match -> update input -> submit" })}>
Submit</Button>
</Form>
</div>
);
}
}
export default connect(
(store) => {
return {
schedules: store.schedules.schedules,
};
}
)(UpdateForm);
----------------------------------------------------------
reference:
http://chuanshuoge2.blogspot.com/search?q=react-redux
http://chuanshuoge2.blogspot.com/search?q=react+schedule
http://chuanshuoge2.blogspot.com/search?q=react+git
http://chuanshuoge2.blogspot.com/2018/06/react-redux-schedule.html
ReplyDeleteNice Blog.Thanks for sharing. Please keep sharing.
Full Stack online Training
Full Stack Training
Full Stack Developer Online Training