I try to build the calendar with possibility of adding notes for the day. The structure of my components is as follows: App component is common component which renders main Build component. Build component uses CellBuild components to buils calendar's days and one DayEventBuilder which will show when the cell is clicked.
I try to change the Builder's "day" state in CellBuild component by click and after that to change DayEventBuilder's state to display actual day. I have the problem with changing DayEventBuilder's state because it isn't get the state by Builder's component.
The "day" state in CellBuild changes only after two clicks. DayEventBuilder component doesn't get any state from Builder.
App component
import 'bootstrap/dist/css/bootstrap.css';
import React from 'react';
import './App.css';
import Builder from './Components/Builder.js';
let helpDate = new Date();
class App extends React.Component {
render() {
return (
<div className="App">
<Builder helpDate={helpDate}/>
</div>
);
}
}
export default App;
Builder component
import React from 'react';
import 'bootstrap/dist/css/bootstrap.css';
import CellBuild from './CellBuild.js';
import DayEventBuilder from './DayEventBuilder.js';
import $ from 'jquery';
let currentDate= new Date();
let months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
//let month = currentDate.getMonth(); //current month
//let year = currentDate.getFullYear(); //current year
//Builder calendar body
class Builder extends React.Component {
constructor(props) {
super(props);
this.state = {
dataState: this.props.helpDate, //set date to build and display
};
}
//help function to control date parameters in cell which is clicked
clickCell=x=>{
this.setState({day:x});
};
createTable =(data)=>{
let helpDate = new Date(data.getFullYear(), data.getMonth(), data.getDate()); //help date for drawing
let helpOther = new Date(data.getFullYear(), data.getMonth(), data.getDate()); //help date for build previous month days
helpDate.setDate(1);
helpOther.setDate(1);
let table=[]; //create table container
let rows=[]; //create rows container
//outer loop for rows creating (filling rows container)
for(let i=0;i<6;i++){
let cells=[]; //create empty cells container
//inner loop for cells creating in row (filling cells container)
for (let j=0;j<7;j++){
//loop for draw previous month days and padding current 1st days relative days of week
if(i===0&&j<helpDate.getDay()-1){
helpOther.setDate(-helpDate.getDay()+2+j);
cells.push(<CellBuild date={helpOther.getDate()} month={helpOther.getMonth()} isNowDate="numbers otherMonth"/>);
}
//continue drawing calendar
else{
//if current month
if(helpDate.getMonth()===data.getMonth()){
//checking for today
if(helpDate.getDate()===currentDate.getDate()&&helpDate.getMonth()===currentDate.getMonth()&&helpDate.getFullYear()===currentDate.getFullYear()){
cells.push(<CellBuild clickCell={this.clickCell} date={helpDate.getDate()} month={helpDate.getMonth()} isNowDate="numbers nowDate"/>); //join cell to cells container
}
else{
cells.push(<CellBuild clickCell={this.clickCell} date={helpDate.getDate()} month={helpDate.getMonth()} isNowDate="numbers" />); //join cell to cells container
}
}
//next month days
else{
cells.push(<CellBuild clickCell={this.clickCell} date={helpDate.getDate()} month={helpDate.getMonth()} isNowDate="numbers otherMonth" />); //join cell to cells container
}
helpDate.setDate(helpDate.getDate()+1);
}
}
rows.push(<tr>{cells}</tr>); //join filled cells container to rows container (join a row)
}
table.push(<table className="main col-lg-12 col-md-12 col-sm-12 col-xs-12"><thead><tr><th colSpan={2}><button className="decrease" onClick=
{() =>
{
data.setMonth(data.getMonth()-1);
this.setState({dataState:data});
}}>←</button><div className="head">{months[data.getMonth()]}</div><div className="head">{data.getFullYear()}</div><button className="increase" onClick=
{() =>
{
data.setMonth(data.getMonth()+1);
this.setState({dataState:data});
}}>→</button></th></tr></thead><tbody>{rows}</tbody></table>); //join filled rows container to table and make header
return table;
};
render() {
return (
<div className="container">
<div className="calendar">{this.createTable(this.state.dataState)}</div>
<DayEventBuilder day={this.state.day}/>
</div>
)
}
}
export default Builder;
CellBuild
import React from 'react';
import 'bootstrap/dist/css/bootstrap.css';
import $ from 'jquery';
//holidays list
let holidays = [
{id:0,
name:"New year",
date:'01.01'},
{id:1,
name:"Christmas",
date:'01.07'},
{id:2,
name:"Men's day",
date:'02.23'},
{id:3,
name:"Women's day",
date:'03.08'},
{id:4,
name:"Labor day",
date:'05.01'},
{id:5,
name:"Victory Day",
date:'05.09'},
{id:6,
name:"Independence day",
date:'07.03'},
{id:7,
name:"November revolution day",
date:'11.07'}];
class CellBuild extends React.Component {
constructor() {
super();
this.state = {
holidaysState: holidays,
};
}
render(){
//do default cell value if not holiday
let cell=<td tabIndex="0" onClick={() => {
console.log(this.props.date);
this.setState({day:this.props.date}); //set day in state to render actual DayEventBuilderComponent
console.log(this.state.day);
//this.setState({month:this.props.month}); //set day in state to render actual DayEventBuilderComponent
this.props.clickCell(this.state.day);
$(function () {
$('table.main').css('opacity','.5');
$('table.dayEvents').css('display','table');
})
}
}><div tabIndex="0" className={this.props.isNowDate}><p>{this.props.date}</p></div></td>;
//check for holiday day
this.state.holidaysState.map(function(holiday){
//create temporary date object from date parameter of holiday
let tempDate = new Date(holiday.date);
//if current day is holiday change a cell value for this day in calendar
if(tempDate.getMonth()===this.props.month&&tempDate.getDate()===this.props.date ){
cell=<td tabIndex="0" onClick={() => {
$(function () {
$('table.main').css('opacity','.5');
$('table.dayEvents').css('display','table');
});
}
} className="holiday"><div tabIndex="0" className={this.props.isNowDate}><p>{this.props.date}</p></div><p className="holiday">{holiday.name}</p></td>;
}
},this); //give CellBuilder as the context of map-function
return cell;
}
}
export default CellBuild;
DayEventBuilder
import React from 'react';
import 'bootstrap/dist/css/bootstrap.css';
import $ from 'jquery';
let events = [
{id:0,
date:"2019.01.20",
name:"Event 1 for this day",
time1:"15:00",
time2:"19:00"
},
];
class DayEventBuilder extends React.Component {
constructor(props) {
super(props);
this.state = {
day:this.props.day, //take actual day and month of the clicked cell from CellBuild
month:this.props.month,
};
}
render(){
let table=[]; //create table container
let rows=[]; //create rows container
let skip=0; //skip <td> adding if needed
//build table
for (let i=0;i<25;i++){
let cells=[]; //create empty cells container
cells.push(<td>{i+':00'}</td>);
if((i+':00')===events[0].time1){
let rowspan = events[0].time2.substring(0, 2)-events[0].time1.substring(0, 2); //calculate how long will the event be
cells.push(<td rowSpan={rowspan} className="setEvent">{events[0].name}</td>);
skip=rowspan; //set skip counter
}
if(skip<=0){ //if we finished skip <td> adding while event was
cells.push(<td onClick={() => {
$(function () {
$('table.main').css('opacity','.3');
$('table.dayEvents').css('opacity','.5');
$('.form').css('display', 'block');
})
}}/>);
}
--skip;
rows.push(<tr>{cells}</tr>);
}
//create table and create exit button from events list
//console.log('DayEventBuilder state.day ='+this.state.day);
table.push(<table className="dayEvents col-lg-6 col-md-8 col-sm-10 col-xs-10"><thead><tr><th>{this.state.day}</th><th><button onClick={() => {
$(function () {
$('table.main').css('opacity','1');
$('table.dayEvents').css('display','none');
})
}
}>×</button></th></tr></thead><tbody>{rows}</tbody></table>);
return (<div>
<div>{table}</div>
<div className="form col-lg-6 col-md-6 col-sm-8 col-xs-8">
<button onClick={() => {
$(function () {
$('table').css('display', 'table');
$('.form').css('display', 'none');
$('table.dayEvents').css('opacity','1');
$('table.main').css('opacity','.5');
})
}}>←</button>
<form>
<fieldset>
<select className="form-control">
<option value="one">One</option>
<option value="two">Two</option>
<option value="three">Three</option>
<option value="four">Four</option>
<option value="five">Five</option>
</select>
<legend>Add the event</legend>
<p>Description <input name="login"/></p>
<p><input type="submit" value="Add"/></p>
</fieldset>
</form>
</div>
</div>);
}
}
export default DayEventBuilder;