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
Nice blog post..Thanks for sharing such an amazing content
ReplyDeleteDevOps Training institute in Ameerpet