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
135 changes: 104 additions & 31 deletions src/components/grid-views/Year.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import moment from 'moment';
import { throttle } from 'lodash';
import YearMonth from './year-widgets/YearMonth';
import { chunk } from '../../utils/common';
import * as dates from '../../utils/dates';
import { navigate } from '../../constants';
import { DATE_UNIT, MONTHS } from '../../constants/date';
import moment from 'moment';

const OFFSET_THRESHOLD = 200; // for vertical scroll
const PRE_LOADED = 2; // the number of pre-loaded years

class YearView extends React.Component {

constructor(props) {
super(props);
this.state = {
scroll: {scrollLeft: 0, scrollTop: 0},
dayEventsMap: this.getDayEventsMap(props.events),
};
this.rbcYearViewSize = {};
this.handlingScroll = false; // false: the scroll is not to be handled by function 'handleScroll'
}

getDayEventsMap = (events) => {
Expand All @@ -38,45 +41,115 @@ class YearView extends React.Component {
return dayEventsMap;
}

onYearViewScroll = (event) => {
const { scrollLeft, scrollTop } = event.target;
this.setState({scroll: {scrollLeft, scrollTop}});
componentDidUpdate(prevProps) {
if (prevProps.events !== this.props.events) {
const newDayEventsMap = this.getDayEventsMap(this.props.events);
this.setState({dayEventsMap: newDayEventsMap});
}
if (prevProps.date !== this.props.date) {
//setTimeout(this.setInitialScrollTop, 300);
}
}

componentDidMount() {
let { offsetWidth, offsetHeight } = this.rbcYearView;
this.rbcYearViewSize = {height: offsetHeight, width: offsetWidth};
this.setInitialScrollTop();

// important: reduce the 'reflow'
const style = {
position: 'absolute',
width: '100%',
height: this.yearsParentContainer.scrollHeight,
top: 0,
bottom: 0
};
this.setState({
style: style
});
}

componentDidUpdate(prevProps) {
if (prevProps.events !== this.props.events) {
const newDayEventsMap = this.getDayEventsMap(this.props.events);
this.setState({dayEventsMap: newDayEventsMap});
setInitialScrollTop = () => {
this.initialScrollTop = document.getElementById(this.currentYear).offsetTop + 30;
this.rbcYearView.scrollTop = this.initialScrollTop;
this.handlingScroll = false;
}

renderYear = (year) => {
const { localizer, className } = this.props;
const { dayEventsMap } = this.state;
const isCurrentYear = year == this.currentYear;
const style = {
minHeight: this.yearMinHeight
};

return (
<div key={year} id={year}>
<h3 className="h4 text-center font-weight-normal my-0">{year}</h3>
<div className={classnames('rbc-year-view', className)} style={style}>
{MONTHS.map(item => {
const isCurrentMonth = isCurrentYear && parseInt(item) == this.currentMonth;
let monthDate = new Date(`${year}-${item}`);
let month = dates.visibleYearDays(monthDate, localizer);
let weeks = chunk(month, 7);
return <div className="rbc-year-month-view" key={`rbc-year-month-${item}`}>
<YearMonth
{...this.props}
dayEventsMap={dayEventsMap}
weeks={weeks}
monthDate={monthDate}
isCurrentMonth={isCurrentMonth}
/>
</div>;
})}
</div>
</div>
);
}

handleScroll = () => {
if (!this.handlingScroll) {
this.handlingScroll = true;
return;
}
let currentScrollTop = this.rbcYearView.scrollTop;
let newDate;
if (currentScrollTop < this.initialScrollTop &&
this.initialScrollTop - currentScrollTop > OFFSET_THRESHOLD) {
newDate = moment(this.props.date).subtract(1, DATE_UNIT.YEAR).toDate();
}
if (currentScrollTop > this.initialScrollTop &&
currentScrollTop - this.initialScrollTop > document.getElementById(this.currentYear).scrollHeight + 10) {
newDate = moment(this.props.date).add(1, DATE_UNIT.YEAR).toDate();
}
if (newDate) {
this.props.updateCurrentDate(newDate);
this.handlingScroll = false;
}
}

render() {
let { date: todayDate, localizer, className } = this.props;
const { scroll, dayEventsMap } = this.state;
const { date } = this.props;
const currentYear = dates.year(date);
const renderedYears = [currentYear];
for (let i = 0; i < PRE_LOADED; i++) {
renderedYears.unshift(currentYear - i - 1);
renderedYears.push(currentYear + i + 1);
}
this.currentYear = currentYear;
this.currentMonth = dates.month(date) + 1;

// make sure 1 year can take the height of '1 screen'(the height of `this.rbcYearsContainer`)
this.yearMinHeight = this.rbcYearsContainer ? this.rbcYearsContainer.clientHeight : 0;

const { style } = this.state;
return (
<div className={classnames('rbc-year-view', className)} onScroll={this.onYearViewScroll} ref={ref => this.rbcYearView = ref} >
{MONTHS.map(item => {
let year = dates.year(todayDate);
let monthDate = new Date(`${year}-${item}`);
let month = dates.visibleYearDays(monthDate, localizer);
let weeks = chunk(month, 7);
return <div className="rbc-year-month-view" key={`rbc-year-month-${item}`}>
<YearMonth
{...this.props}
rbcYearViewSize={this.rbcYearViewSize}
rbcYearViewScroll={scroll}
dayEventsMap={dayEventsMap}
weeks={weeks}
monthDate={monthDate}
/>
</div>;
})}
<div className="flex-fill o-hidden d-flex" ref={ref => this.rbcYearsContainer = ref}>
<div className="flex-fill o-auto" ref={ref => this.rbcYearView = ref} onScroll={throttle(this.handleScroll, 280)}>
<div className="position-relative">
<div ref={ref => this.yearsParentContainer = ref} style={style}>
{renderedYears.map(this.renderYear)}
</div>
</div>
</div>
</div>
);
}
Expand Down
29 changes: 16 additions & 13 deletions src/components/grid-views/year-widgets/YearDay.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,24 @@ class YearDay extends React.Component {
constructor(props) {
super(props);
this.state = {
isShowEvents: false,
isShowEvents: false
};
this.position = {};
}

componentDidMount() {
let { offsetParent: rbcYearMonth, offsetLeft: rbcYearMonthLeft } = this.rbcYearDayItem;
let { offsetTop: rbcYearTop, offsetParent: rbcYear } = rbcYearMonth;
let { offsetTop, offsetLeft } = rbcYear;

this.position = {left: offsetLeft + rbcYearMonthLeft + 34, top: offsetTop + rbcYearTop};
getPosition = () => {
const { top, right } = this.rbcYearDayItem.getBoundingClientRect();
const innerWidth = window.innerWidth;
let posLeft = right + 5;
if (innerWidth > 1100) {
posLeft = posLeft - (innerWidth - 1100) / 2;
}
this.position = {top: top - 80, left: posLeft};
}

onEventsToggle = () => {
if (!this.state.isShowEvents) {
this.getPosition();
}
this.setState({isShowEvents: !this.state.isShowEvents});
}

Expand All @@ -31,16 +35,16 @@ class YearDay extends React.Component {
}

render() {
let { day, monthDate, localizer, accessors, selected, getters, components, popupOffset, onRowExpand, dayEvents } = this.props;
let { day, monthDate, isCurrentMonth, localizer, accessors, selected, getters, components, popupOffset, onRowExpand, dayEvents } = this.props;
let { isShowEvents } = this.state;
let isOffRange = dates.month(day) !== dates.month(monthDate);
let isCurrentDay = dates.eq(day, new Date(), 'day');
let isCurrentDay = isCurrentMonth && dates.eq(day, new Date(), 'day');
let label = localizer.format(day, 'yearMonthDateFormat');

return (
<div className="rbc-year-day-item" ref={ref => this.rbcYearDayItem = ref}>
<div className="rbc-year-day-content" onClick={this.onEventsToggle}>
<div className={classnames('rbc-year-day', {'rbc-off-range': isOffRange, 'rbc-current': isCurrentDay})} >{label}</div>
<div className={classnames('rbc-year-day', {'rbc-off-range': isOffRange, 'rbc-current': !isOffRange && isCurrentDay})}>{label}</div>
</div>
{dayEvents.length > 0 && <span className="day-events"></span>}
{isShowEvents &&
Expand All @@ -52,7 +56,7 @@ class YearDay extends React.Component {
selected={selected}
components={components}
localizer={localizer}
position={this.position}
position={this.position || {}}
events={dayEvents}
slotStart={day}
onSelect={onRowExpand}
Expand All @@ -68,7 +72,6 @@ YearDay.propTypes = {
dayEvents: PropTypes.array,
monthDate: PropTypes.instanceOf(Date),
localizer: PropTypes.object,
rbcYearViewScroll: PropTypes.object,
accessors: PropTypes.object,
getters: PropTypes.object.isRequired,
selected: PropTypes.bool,
Expand Down
5 changes: 0 additions & 5 deletions src/components/grid-views/year-widgets/YearMonth.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { Fragment } from 'react';
import { findDOMNode } from 'react-dom';
import PropTypes from 'prop-types';
import Header from '../../header/Header';
import * as dates from '../../../utils/dates';
Expand Down Expand Up @@ -58,10 +57,6 @@ class YearMonth extends React.Component {
);
}

getContainer = () => {
return findDOMNode(this);
}

render() {
let { weeks } = this.props;

Expand Down
3 changes: 1 addition & 2 deletions src/css/react-big-calendar.css
Original file line number Diff line number Diff line change
Expand Up @@ -412,10 +412,9 @@ button.rbc-input::-moz-focus-inner {
flex-direction: column;
flex: 1 0 0;
width: 100%;
padding: 0 18px;
padding: 12px 18px 32px;
user-select: none;
-webkit-user-select: none;
overflow-y: auto;
}

.rbc-month-view {
Expand Down