Skip to content
This repository was archived by the owner on May 19, 2025. It is now read-only.

Broadcast calendar new feature #556

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-date-range",
"version": "1.3.0",
"name": "605-react-date-range",
"version": "1.3.2",
"description": "A React component for choosing dates and date ranges.",
"main": "dist/index.js",
"scripts": {
Expand Down
33 changes: 22 additions & 11 deletions src/components/Calendar/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { rangeShape } from '../DayCell';
import Month from '../Month';
import DateInput from '../DateInput';
import { calcFocusDate, generateStyles, getMonthDisplayRange } from '../../utils';
import classnames from 'classnames';
import ReactList from 'react-list';
import { shallowEqualObjects } from 'shallow-equal';
import {
addMonths,
format,
Expand All @@ -27,14 +19,26 @@ import {
max,
} from 'date-fns';
import defaultLocale from 'date-fns/locale/en-US';
import coreStyles from '../../styles';
import PropTypes from 'prop-types';
import React, { PureComponent } from 'react';
import ReactList from 'react-list';
import { shallowEqualObjects } from 'shallow-equal';
import { ariaLabelsShape } from '../../accessibility';
import coreStyles from '../../styles';
import { calcFocusDate, generateStyles, getMonthDisplayRange } from '../../utils';
import DateInput from '../DateInput';
import { rangeShape } from '../DayCell';
import Month from '../Month';

class Calendar extends PureComponent {
constructor(props, context) {
super(props, context);
this.dateOptions = { locale: props.locale };
if (props.weekStartsOn !== undefined) this.dateOptions.weekStartsOn = props.weekStartsOn;
if (props.broadcastCalendar) {
this.dateOptions.weekStartsOn = 1;
} else if (props.weekStartsOn !== undefined) {
this.dateOptions.weekStartsOn = props.weekStartsOn;
};
this.styles = generateStyles([coreStyles, props.classNames]);
this.listSizeCache = {};
this.isFirstRender = true;
Expand Down Expand Up @@ -122,7 +126,10 @@ class Calendar extends PureComponent {
date: 'date',
};
const targetProp = propMapper[this.props.displayMode];
if (this.props[targetProp] !== prevProps[targetProp]) {
if (
this.props[targetProp] !== prevProps[targetProp] ||
this.props.focusedRange != prevProps.focusedRange
) {
this.updateShownDate(this.props);
}

Expand Down Expand Up @@ -526,6 +533,7 @@ Calendar.defaultProps = {
dateDisplayFormat: 'MMM d, yyyy',
monthDisplayFormat: 'MMM yyyy',
weekdayDisplayFormat: 'E',
broadcastCalendar: false,
dayDisplayFormat: 'd',
showDateDisplay: true,
showPreview: true,
Expand All @@ -545,6 +553,7 @@ Calendar.defaultProps = {
dragSelectionEnabled: true,
fixedHeight: false,
ariaLabels: {},
weekNumberColor: '#B86EF3',
};

Calendar.propTypes = {
Expand Down Expand Up @@ -572,6 +581,8 @@ Calendar.propTypes = {
monthDisplayFormat: PropTypes.string,
weekdayDisplayFormat: PropTypes.string,
weekStartsOn: PropTypes.number,
broadcastCalendar: PropTypes.bool,
weekNumberColor: PropTypes.string,
dayDisplayFormat: PropTypes.string,
focusedRange: PropTypes.arrayOf(PropTypes.number),
initialFocusedRange: PropTypes.arrayOf(PropTypes.number),
Expand Down
38 changes: 26 additions & 12 deletions src/components/DayCell/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* eslint-disable no-fallthrough */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { startOfDay, format, isSameDay, isAfter, isBefore, endOfDay } from 'date-fns';
import PropTypes from 'prop-types';
import React, { Component } from 'react';

class DayCell extends Component {
constructor(props, context) {
Expand Down Expand Up @@ -58,6 +58,7 @@ class DayCell extends Component {
};
getClassNames = () => {
const {
broadcastCalendar,
isPassive,
isToday,
isWeekend,
Expand All @@ -76,7 +77,7 @@ class DayCell extends Component {
[styles.dayWeekend]: isWeekend,
[styles.dayStartOfWeek]: isStartOfWeek,
[styles.dayEndOfWeek]: isEndOfWeek,
[styles.dayStartOfMonth]: isStartOfMonth,
[styles.dayStartOfMonth]: isStartOfMonth && !broadcastCalendar,
[styles.dayEndOfMonth]: isEndOfMonth,
[styles.dayHovered]: this.state.hover,
[styles.dayActive]: this.state.active,
Expand Down Expand Up @@ -128,7 +129,7 @@ class DayCell extends Component {
...result,
{
isStartEdge,
isEndEdge: isEndEdge,
isEndEdge,
isInRange,
...range,
},
Expand Down Expand Up @@ -166,21 +167,32 @@ class DayCell extends Component {
onKeyUp={this.handleKeyEvent}
className={this.getClassNames(this.props.styles)}
{...(this.props.disabled || this.props.isPassive ? { tabIndex: -1 } : {})}
style={{ color: this.props.color }}>
style={{
color: this.props.color,
backgroundColor: this.props.weekNumber ? '#fff' : '',
width: this.props.broadcastCalendar ? 'calc(100% / 8)' : 'calc(100% / 7)',
}}>
{this.renderSelectionPlaceholders()}
{this.renderPreviewPlaceholder()}
<span className={this.props.styles.dayNumber}>
{
dayContentRenderer?.(this.props.day) ||
<span>{format(this.props.day, this.props.dayDisplayFormat)}</span>
}
</span>
{this.props.weekNumber
? (<span style={{ color: this.props.weekNumberColor }}>
{this.props.weekNumber}
</span>)
: (<span className={this.props.styles.dayNumber}>
{
dayContentRenderer?.(this.props.day) ||
<span>{format(this.props.day, this.props.dayDisplayFormat)}</span>
}
</span>)
}
</button>
);
}
}

DayCell.defaultProps = {};
DayCell.defaultProps = {
weekNumberColor: '#B86EF3',
};

export const rangeShape = PropTypes.shape({
startDate: PropTypes.object,
Expand Down Expand Up @@ -219,6 +231,8 @@ DayCell.propTypes = {
onMouseUp: PropTypes.func,
onMouseEnter: PropTypes.func,
dayContentRenderer: PropTypes.func,
weekNumber: PropTypes.number,
weekNumberColor: PropTypes.string,
};

export default DayCell;
82 changes: 70 additions & 12 deletions src/components/Month/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
/* eslint-disable no-fallthrough */
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import DayCell, { rangeShape } from '../DayCell';
import {
format,
startOfDay,
Expand All @@ -15,20 +12,41 @@ import {
isWithinInterval,
eachDayOfInterval,
} from 'date-fns';
import { getMonthDisplayRange } from '../../utils';
import PropTypes from 'prop-types';
import React, { PureComponent } from 'react';
import {
getMonthDisplayRange,
calculateBroadcastWeekNumber,
shouldRenderBroadcastDay
} from '../../utils';
import DayCell, { rangeShape } from '../DayCell';

function renderWeekdays(styles, dateOptions, weekdayDisplayFormat) {
function renderWeekdays(styles, dateOptions, weekdayDisplayFormat, broadcastCalendar) {
const now = new Date();
return (
<div className={styles.weekDays}>
{eachDayOfInterval({
start: startOfWeek(now, dateOptions),
end: endOfWeek(now, dateOptions),
}).map((day, i) => (
<span className={styles.weekDay} key={i}>
{format(day, weekdayDisplayFormat, dateOptions)}
</span>
))}
}).map((day, i) => {
if (i === 0 && broadcastCalendar) {
return (
<>
<span className={styles.weekDay} key='week-number'>
#
</span>
<span className={styles.weekDay} key={i}>
{format(day, weekdayDisplayFormat, dateOptions)}
</span>
</>
);
}
return (
<span className={styles.weekDay} key={i}>
{format(day, weekdayDisplayFormat, dateOptions)}
</span>
);
})}
</div>
);
}
Expand Down Expand Up @@ -57,6 +75,7 @@ class Month extends PureComponent {
});
}
const showPreview = this.props.showPreview && !drag.disablePreview;
const indexToAddWeekNumber = [0, 7, 14, 21, 28, 35];
return (
<div className={styles.month} style={this.props.style}>
{this.props.showMonthName ? (
Expand All @@ -65,7 +84,7 @@ class Month extends PureComponent {
</div>
) : null}
{this.props.showWeekDays &&
renderWeekdays(styles, this.props.dateOptions, this.props.weekdayDisplayFormat)}
renderWeekdays(styles, this.props.dateOptions, this.props.weekdayDisplayFormat, this.props.broadcastCalendar)}
<div className={styles.days} onMouseLeave={this.props.onMouseLeave}>
{eachDayOfInterval({ start: monthDisplay.start, end: monthDisplay.end }).map(
(day, index) => {
Expand All @@ -77,6 +96,45 @@ class Month extends PureComponent {
isSameDay(disabledDate, day)
);
const isDisabledDay = disabledDay(day);
if (this.props.broadcastCalendar && !shouldRenderBroadcastDay(day, this.props.month.getMonth())) {
return null;
}
if (indexToAddWeekNumber.includes(index) && this.props.broadcastCalendar) {
const weekNumber = calculateBroadcastWeekNumber(day);
return (
<>
<DayCell
{...this.props}
weekNumber={weekNumber}
key={`weekNumber-${weekNumber}`}
disabled
isPassive={false}
styles={styles}
/>
<DayCell
{...this.props}
ranges={ranges}
day={day}
preview={showPreview ? this.props.preview : null}
isWeekend={isWeekend(day, this.props.dateOptions)}
isToday={isSameDay(day, now)}
isStartOfWeek={isSameDay(day, startOfWeek(day, this.props.dateOptions))}
isEndOfWeek={isSameDay(day, endOfWeek(day, this.props.dateOptions))}
isStartOfMonth={isStartOfMonth}
isEndOfMonth={isEndOfMonth}
key={index}
disabled={isOutsideMinMax || isDisabledSpecifically || isDisabledDay}
isPassive={false}
styles={styles}
onMouseDown={this.props.onDragSelectionStart}
onMouseUp={this.props.onDragSelectionEnd}
onMouseEnter={this.props.onDragSelectionMove}
dragRange={drag.range}
drag={drag.status}
/>
</>
);
}
return (
<DayCell
{...this.props}
Expand All @@ -91,7 +149,7 @@ class Month extends PureComponent {
isEndOfMonth={isEndOfMonth}
key={index}
disabled={isOutsideMinMax || isDisabledSpecifically || isDisabledDay}
isPassive={
isPassive={this.props.broadcastCalendar ? false :
!isWithinInterval(day, {
start: monthDisplay.startDateOfMonth,
end: monthDisplay.endDateOfMonth,
Expand Down
55 changes: 54 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import {
differenceInCalendarDays,
differenceInCalendarMonths,
addDays,
subDays,
getWeekOfMonth,
nextSunday,
isSunday,
lastDayOfWeek,
} from 'date-fns';

export function calcFocusDate(currentFocusedDate, props) {
Expand All @@ -27,7 +32,12 @@ export function calcFocusDate(currentFocusedDate, props) {
}
targetInterval.start = startOfMonth(targetInterval.start || new Date());
targetInterval.end = endOfMonth(targetInterval.end || targetInterval.start);
const targetDate = targetInterval.start || targetInterval.end || shownDate || new Date();
const targetDate =
(focusedRange[1]
? targetInterval.end || targetInterval.start
: targetInterval.start || targetInterval.end) ||
shownDate ||
new Date();

// initial focus
if (!currentFocusedDate) return shownDate || targetDate;
Expand Down Expand Up @@ -77,3 +87,46 @@ export function generateStyles(sources) {
}, {});
return generatedStyles;
}

export function calculateBroadcastWeekNumber(currentDate) {
const isDecember = (currentDate.getMonth() + 1) === 12;
if (isDecember && getWeekOfMonth(currentDate) === 6) {
return 1;
}
if (
isDecember
&& getWeekOfMonth(currentDate) === 5
&& !isSunday(currentDate)
&& (nextSunday(currentDate).getMonth() + 1) !== 12
) {
return 1;
};
const firstDayOfTheYearDate = new Date(currentDate.getFullYear(), 0, 1);
const firstDayOfTheYear = firstDayOfTheYearDate.getDay();
const yearStartsOnSunday = firstDayOfTheYear === 0;
const broadcastStartOfWeek1Day = subDays(firstDayOfTheYearDate, yearStartsOnSunday ? 6 : firstDayOfTheYear - 1);
const days = Math.floor((currentDate - broadcastStartOfWeek1Day) / (24 * 60 * 60 * 1000));
const weekNumber = Math.ceil((currentDate.getDay() + 1 + days) / 7);
return weekNumber;
}

export function shouldRenderBroadcastDay(calendarDate, calendarMonth) {
const weekOfMonth = getWeekOfMonth(calendarDate, { weekStartsOn: 1 });
if (weekOfMonth <= 4 && calendarDate.getMonth() === calendarMonth) {
return true;
}
if (weekOfMonth === 6 && calendarDate.getMonth() === calendarMonth) {
return false;
}
if (
weekOfMonth === 5
&& calendarDate.getMonth() === calendarMonth
&& lastDayOfWeek(calendarDate, { weekStartsOn: 1 }).getMonth() !== calendarMonth
) {
return false;
};
if (weekOfMonth === 1 && calendarDate.getMonth() !== calendarMonth) {
return false;
}
return true;
}
Loading