import React, {FormEvent} from 'react'; import {Calendar} from './Calendar'; import { endGregorian, frEndJD, FrenchMonth, frSupportedYear, jdnFrench, startGregorian, frStartJD, } from '@common/french'; import {dateJDN, gregorianJDN} from '@common/gregorian'; import {TimeOfDay} from './TimeOfDay'; type YearMonth = { year: number; month: FrenchMonth; } function parseURL(): YearMonth | null { const match = /\/(-?\d+)\/(\d+)/.exec(window.location.pathname); if (!match) return null; const month = +match[2]; const year = +match[1]; if (!frSupportedYear(year) || month < 1 || month > 13) return null; return {year: year, month: month as FrenchMonth}; } type AppState = YearMonth & { todayJDN: number, goYear: string, goMonth: string, goDay: string, }; class App extends React.Component<{}, AppState> { state: AppState; constructor(props: {}) { super(props); const today = new Date(); const todayJDN = dateJDN(today); const {year, month} = jdnFrench(todayJDN); this.state = { ...(parseURL() || {year, month}), todayJDN, goYear: today.getFullYear().toString(), goMonth: (today.getMonth() + 1).toString(), goDay: today.getDate().toString(), }; this.updateStateFromURL = this.updateStateFromURL.bind(this); } componentDidMount() { window.addEventListener('popstate', this.updateStateFromURL); } componentWillUnmount() { window.removeEventListener('popstate', this.updateStateFromURL); } private updateStateFromURL(event: PopStateEvent) { this.setState(event.state); } private updateURL() { const {year, month} = this.state; const path = `/${year}/${month}`; if (path !== window.location.pathname) { window.history.pushState({year, month}, '', path); } } changeField(field: keyof AppState, event: any) { this.setState({[field]: event.target.value}); } validYear() { return /^-?\d+$/.test(this.state.goYear) && startGregorian[0] <= +this.state.goYear && +this.state.goYear <= endGregorian[0]; } validMonth() { return /^\d+$/.test(this.state.goMonth) && 1 <= +this.state.goMonth && +this.state.goMonth <= 12; } validDay() { return /^\d+$/.test(this.state.goDay) && 1 <= +this.state.goDay && +this.state.goDay <= 31; } goToGregorian(event: FormEvent) { event.preventDefault(); if (!this.validYear() || !this.validMonth() || !this.validDay()) return; const jdn = gregorianJDN(+this.state.goYear, +this.state.goMonth, +this.state.goDay); const {year, month} = jdnFrench(Math.min(Math.max(frStartJD, jdn), frEndJD)); this.setState({year, month}); } setState(state: any, callback?: () => void) { super.setState(state, () => { this.updateURL(); callback && callback(); }); } onDateChange = (todayJDN: number) => { this.setState({todayJDN}); }; render() { return <> { this.setState({year, month}); }}/>

Go to a date

Gregorian Date
; } } export default App;