UNPKG

@nateradebaugh/react-datetime

Version:

A lightweight but complete datetime picker React.js component

232 lines (207 loc) 6.62 kB
import React, { Component } from "react"; import addDays from "date-fns/add_days"; import format from "date-fns/format"; import getDaysInMonth from "date-fns/get_days_in_month"; import getMonth from "date-fns/get_month"; import getYear from "date-fns/get_year"; import startOfWeek from "date-fns/start_of_week"; import isSameDay from "date-fns/is_same_day"; import isToday from "date-fns/is_today"; import setDate from "date-fns/set_date"; import subMonths from "date-fns/sub_months"; import getDate from "date-fns/get_date"; import onClickOutside from "react-onclickoutside"; class DaysView extends Component { constructor(props) { super(props); // Bind functions this.renderDays = this.renderDays.bind(this); this.updateSelectedDate = this.updateSelectedDate.bind(this); this.renderDay = this.renderDay.bind(this); this.renderFooter = this.renderFooter.bind(this); this.alwaysValidDate = this.alwaysValidDate.bind(this); this.getFormatOptions = this.getFormatOptions.bind(this); } getFormatOptions() { return { locale: this.props.locale }; } render() { const date = this.props.viewDate || new Date(); const theStartOfWeek = startOfWeek(date); return ( <div className="rdtDays"> <table> <thead> <tr> <th className="rdtPrev" onClick={this.props.subtractTime(1, "months")} > <span>‹</span> </th> <th className="rdtSwitch" onClick={this.props.showView("months")} colSpan={5} data-value={getMonth(this.props.viewDate)} > {format(date, "MMMM YYYY", this.getFormatOptions())} </th> <th className="rdtNext" onClick={this.props.addTime(1, "months")}> <span>›</span> </th> </tr> <tr> <th className="dow"> {format( addDays(theStartOfWeek, 0), "dd", this.getFormatOptions() )} </th> <th className="dow"> {format( addDays(theStartOfWeek, 1), "dd", this.getFormatOptions() )} </th> <th className="dow"> {format( addDays(theStartOfWeek, 2), "dd", this.getFormatOptions() )} </th> <th className="dow"> {format( addDays(theStartOfWeek, 3), "dd", this.getFormatOptions() )} </th> <th className="dow"> {format( addDays(theStartOfWeek, 4), "dd", this.getFormatOptions() )} </th> <th className="dow"> {format( addDays(theStartOfWeek, 5), "dd", this.getFormatOptions() )} </th> <th className="dow"> {format( addDays(theStartOfWeek, 6), "dd", this.getFormatOptions() )} </th> </tr> </thead> <tbody>{this.renderDays()}</tbody> {this.renderFooter()} </table> </div> ); } renderDays() { const date = this.props.viewDate || new Date(); const selectedDate = this.props.selectedDate ? this.props.selectedDate : undefined; const prevMonth = subMonths(date, 1); const currentYear = getYear(date); const currentMonth = getMonth(date); const weeks = []; let days = []; const renderer = this.props.renderDay || this.renderDay; const isValid = this.props.isValidDate || this.alwaysValidDate; const prevMonthLastWeekStart = startOfWeek( setDate(prevMonth, getDaysInMonth(prevMonth)) ); const lastDay = addDays(prevMonthLastWeekStart, 42); for ( let workingDate = prevMonthLastWeekStart; workingDate < lastDay; workingDate = addDays(workingDate, 1) ) { let classes = "rdtDay"; const workingYear = getYear(workingDate); const workingMonth = getMonth(workingDate); if ( (workingYear === currentYear && workingMonth < currentMonth) || workingYear < currentYear ) { classes += " rdtOld"; } else if ( (workingYear === currentYear && workingMonth > currentMonth) || workingYear > currentYear ) { classes += " rdtNew"; } if (selectedDate && isSameDay(workingDate, selectedDate)) { classes += " rdtActive"; } if (isToday(workingDate)) { classes += " rdtToday"; } const isDisabled = !isValid(workingDate, selectedDate); if (isDisabled) { classes += " rdtDisabled"; } const dayProps = { key: getDate(workingDate), className: classes, "data-value": getDate(workingDate) }; if (!isDisabled) { dayProps.onClick = this.updateSelectedDate; } days.push(renderer(dayProps, workingDate, selectedDate)); if (days.length === 7) { weeks.push(<tr key={workingDate}>{days}</tr>); days = []; } } return weeks; } updateSelectedDate(event) { this.props.updateSelectedDate(event, true); } renderDay(props, currentDate) { return ( <td {...props}>{format(currentDate, "D", this.getFormatOptions())}</td> ); } renderFooter() { if (!this.props.timeFormat) { return null; } const date = this.props.selectedDate || this.props.viewDate; return ( <tfoot> <tr> <td onClick={this.props.showView("time")} colSpan={7} className="rdtTimeToggle" > {format(date, this.props.timeFormat, this.getFormatOptions())} </td> </tr> </tfoot> ); } alwaysValidDate() { return 1; } handleClickOutside() { this.props.handleClickOutside(); } } export default onClickOutside(DaysView);