import React from 'react';
import './Calendar.scss';
import {
dateName,
dateRuralName,
Day,
decadeNames,
endYear,
frIsLeap,
frJDN,
jdnFrench,
jdnGregorian,
jdnLongCount,
Month,
monthName,
startYear
} from './dates';
type MonthProps = {
year: number;
month: Month;
};
type DateProps = MonthProps & {
day: Day;
};
function DecadeName({name}: { name: string }): JSX.Element {
return
{name}
;
}
function DayDetail({jdn}: { jdn: number }): JSX.Element {
return
{jdnGregorian(jdn).toDateString()}
{jdnLongCount(jdn)}
;
}
function NormalDay({year, month, day, todayJDN}: DateProps & { todayJDN: number }): JSX.Element {
const jdn = frJDN(year, month, day);
const rural = dateRuralName(month, day)!;
return
{day}
{decadeNames[(day - 1) % 10]}
{rural.name}
;
}
function NormalMonth({year, month, todayJDN}: MonthProps & { todayJDN: number }): JSX.Element {
const decadeHeads = decadeNames.map((name, i) => );
return
{decadeHeads}
{
Array.from(Array(3).keys()).map(i =>
{
Array.from(Array(10).keys()).map(j =>
{j % 2 === 1 && }
{j === 4 && }
)
}
)
}
;
}
function ComplementaryDay({year, month, day, todayJDN}: DateProps & { todayJDN: number }): JSX.Element {
const jdn = frJDN(year, month, day);
return ;
}
function ComplementaryDays({year, todayJDN}: { year: number, todayJDN: number }): JSX.Element {
const leap = frIsLeap(year);
return {
Array.from(Array(6).keys()).map(i =>
{(i < 5 || leap) && }
{i === 5 && !leap && }
{i % 2 === 1 && }
)
}
;
}
export type CalendarProps = MonthProps & {
todayJDN: number;
onSwitch?: (year: number, month: Month) => void,
};
type CalendarState = {
selecting: boolean,
yearStr: string,
};
export class Calendar extends React.Component {
selection: React.RefObject;
constructor(props: CalendarProps) {
super(props);
this.state = {
selecting: false,
yearStr: this.props.year.toString(),
};
this.selection = React.createRef();
}
componentDidMount() {
document.addEventListener('click', this.handleClickOutside, true);
}
componentWillUnmount() {
document.removeEventListener('click', this.handleClickOutside, true);
}
private goToNormalized(year: number, month: number) {
if (month < 1) {
--year;
month += 13;
}
if (month > 13) {
++year;
month -= 13;
}
if (year < startYear) {
year = startYear;
month = 1;
} else if (year > endYear) {
year = endYear;
month = 13;
}
this.props.onSwitch && this.props.onSwitch(year, month as Month);
}
prevYear = () => {
this.goToNormalized(this.props.year - 1, this.props.month);
}
prevMonth = () => {
this.goToNormalized(this.props.year, this.props.month - 1);
}
nextYear = () => {
this.goToNormalized(this.props.year + 1, this.props.month);
}
nextMonth = () => {
this.goToNormalized(this.props.year, this.props.month + 1);
}
startSelection = () => {
this.setState({selecting: true});
}
handleClickOutside = (event: any) => {
if (this.state.selecting && this.selection.current && !this.selection.current.contains(event.target))
this.setState({selecting: false});
}
handleKeyUp = (event: any) => {
if (event.key === 'Escape')
this.setState({selecting: false});
}
monthChange = (event: any) => {
this.goToNormalized(this.props.year, +event.target.value as Month);
}
yearChange = (event: any) => {
if (/^-?\d+/.test(event.target.value)) {
this.goToNormalized(+event.target.value, this.props.month);
}
this.setState({yearStr: event.target.value});
}
goToToday = () => {
const {year, month} = jdnFrench(this.props.todayJDN);
this.goToNormalized(year, month);
this.setState({selecting: false});
}
componentDidUpdate(prevProps: CalendarProps) {
if (prevProps.year !== this.props.year) {
const yearStr = this.props.year.toString();
if (this.state.yearStr !== yearStr) {
this.setState({
yearStr: yearStr,
});
}
}
}
render(): JSX.Element {
return
{!this.state.selecting &&
{this.props.month < 13 && monthName(this.props.month)} {this.props.year}
}
{this.state.selecting &&
}
{this.props.month < 13 &&
}
{this.props.month === 13 && }
;
}
}