mirror of
https://github.com/quantum5/qcal.git
synced 2025-04-24 09:41:57 -04:00
Factor out <GregorianJumper>
This commit is contained in:
parent
f67bd1bbef
commit
9a69b0ba55
43
common/src/dateJump/GregorianJumper.tsx
Normal file
43
common/src/dateJump/GregorianJumper.tsx
Normal file
|
@ -0,0 +1,43 @@
|
|||
import {DateJumperProps} from './base';
|
||||
import React from 'react';
|
||||
import {gregorianJDN, jdnGregorian} from '../gregorian';
|
||||
|
||||
export default function GregorianJumper({minJDN, maxJDN, todayJDN, onJump}: DateJumperProps): JSX.Element {
|
||||
const {todayYear, todayMonth, todayDay, startYear, endYear} = React.useMemo(() => {
|
||||
const [todayYear, todayMonth, todayDay] = jdnGregorian(todayJDN);
|
||||
const [startYear] = jdnGregorian(minJDN);
|
||||
const [endYear] = jdnGregorian(maxJDN);
|
||||
return {todayYear, todayMonth, todayDay, startYear, endYear};
|
||||
}, [minJDN, maxJDN, todayJDN]);
|
||||
|
||||
const [year, setYear] = React.useState(todayYear.toString());
|
||||
const [month, setMonth] = React.useState(todayMonth.toString());
|
||||
const [day, setDay] = React.useState(todayDay.toString());
|
||||
|
||||
const validYear = /^-?\d+$/.test(year) && startYear <= +year && +year <= endYear;
|
||||
const validMonth = /^\d+$/.test(month) && 1 <= +month && +month <= 12;
|
||||
const validDay = /^\d+$/.test(day) && 1 <= +day && +day <= 31;
|
||||
|
||||
function goToGregorian(event: React.FormEvent) {
|
||||
event.preventDefault();
|
||||
|
||||
if (!validYear || !validMonth || !validDay)
|
||||
return;
|
||||
|
||||
onJump(gregorianJDN(+year, +month, +day));
|
||||
}
|
||||
|
||||
return <form className="input-group" onSubmit={goToGregorian}>
|
||||
<span className="input-group-text">Gregorian<span className="hide-small"> Date</span></span>
|
||||
<input type="number" className={`form-control go-year ${validYear ? '' : 'is-invalid'}`}
|
||||
onChange={e => setYear(e.target.value)} value={year}
|
||||
min={startYear} max={endYear}/>
|
||||
<input type="number" className={`form-control go-month ${validMonth ? '' : 'is-invalid'}`}
|
||||
onChange={e => setMonth(e.target.value)} value={month}
|
||||
min={1} max={12}/>
|
||||
<input type="number" className={`form-control go-day ${validDay ? '' : 'is-invalid'}`}
|
||||
onChange={e => setDay(e.target.value)} value={day}
|
||||
min={1} max={31}/>
|
||||
<button type="submit" className="form-control btn btn-primary go-button">Go</button>
|
||||
</form>;
|
||||
}
|
6
common/src/dateJump/base.ts
Normal file
6
common/src/dateJump/base.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
export type DateJumperProps = {
|
||||
minJDN: number;
|
||||
maxJDN: number;
|
||||
todayJDN: number;
|
||||
onJump: (jdn: number) => void;
|
||||
};
|
3
common/src/dateJump/index.ts
Normal file
3
common/src/dateJump/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
import GregorianJumper from './GregorianJumper';
|
||||
|
||||
export {GregorianJumper};
|
|
@ -1,6 +1,5 @@
|
|||
import data from './cal.json';
|
||||
import ruralName from './rural-days.json';
|
||||
import {jdnGregorian} from '../gregorian';
|
||||
|
||||
// Month 13 is for the complementary days
|
||||
export type FrenchMonth = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13;
|
||||
|
@ -145,9 +144,6 @@ export function dateRuralName(month: FrenchMonth, day: FrenchDay): { name: strin
|
|||
return {name, title};
|
||||
}
|
||||
|
||||
export const startGregorian = jdnGregorian(frStartJD);
|
||||
export const endGregorian = jdnGregorian(frEndJD);
|
||||
|
||||
export function frDateFormat({year, month, day}: { year: number, month: FrenchMonth, day: FrenchDay }): string {
|
||||
return `${dateName(month, day)} ${year}`;
|
||||
}
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
import React, {FormEvent} from 'react';
|
||||
import React from 'react';
|
||||
import {Calendar} from './Calendar';
|
||||
import {
|
||||
endGregorian,
|
||||
frEndJD,
|
||||
FrenchMonth,
|
||||
frSupportedYear,
|
||||
jdnFrench,
|
||||
startGregorian,
|
||||
frStartJD,
|
||||
} from '@common/french';
|
||||
import {dateJDN, gregorianJDN} from '@common/gregorian';
|
||||
import {FrenchMonth, frEndJD, frStartJD, frSupportedYear, jdnFrench} from '@common/french';
|
||||
import {dateJDN} from '@common/gregorian';
|
||||
import {TimeOfDay} from './TimeOfDay';
|
||||
import {GregorianJumper} from '@common/dateJump';
|
||||
|
||||
type YearMonth = {
|
||||
year: number;
|
||||
|
@ -31,9 +24,6 @@ function parseURL(): YearMonth | null {
|
|||
|
||||
type AppState = YearMonth & {
|
||||
todayJDN: number,
|
||||
goYear: string,
|
||||
goMonth: string,
|
||||
goDay: string,
|
||||
};
|
||||
|
||||
class App extends React.Component<{}, AppState> {
|
||||
|
@ -41,16 +31,12 @@ class App extends React.Component<{}, AppState> {
|
|||
|
||||
constructor(props: {}) {
|
||||
super(props);
|
||||
const today = new Date();
|
||||
const todayJDN = dateJDN(today);
|
||||
const todayJDN = dateJDN(new Date());
|
||||
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);
|
||||
}
|
||||
|
@ -75,38 +61,10 @@ class App extends React.Component<{}, AppState> {
|
|||
}
|
||||
}
|
||||
|
||||
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();
|
||||
callback?.();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -114,6 +72,11 @@ class App extends React.Component<{}, AppState> {
|
|||
this.setState({todayJDN});
|
||||
};
|
||||
|
||||
goToJDN = (jdn: number) => {
|
||||
const {year, month} = jdnFrench(Math.min(Math.max(frStartJD, jdn), frEndJD));
|
||||
this.setState({year, month});
|
||||
};
|
||||
|
||||
render() {
|
||||
return <>
|
||||
<Calendar
|
||||
|
@ -126,19 +89,8 @@ class App extends React.Component<{}, AppState> {
|
|||
|
||||
<div className="navigate">
|
||||
<h4>Go to a date</h4>
|
||||
<form className="input-group" onSubmit={this.goToGregorian.bind(this)}>
|
||||
<span className="input-group-text">Gregorian<span className="hide-small"> Date</span></span>
|
||||
<input type="number" className={`form-control go-year ${this.validYear() ? '' : 'is-invalid'}`}
|
||||
onChange={this.changeField.bind(this, 'goYear')} value={this.state.goYear}
|
||||
min={startGregorian[0]} max={endGregorian[0]}/>
|
||||
<input type="number" className={`form-control go-month ${this.validMonth() ? '' : 'is-invalid'}`}
|
||||
onChange={this.changeField.bind(this, 'goMonth')} value={this.state.goMonth}
|
||||
min={1} max={12}/>
|
||||
<input type="number" className={`form-control go-day ${this.validDay() ? '' : 'is-invalid'}`}
|
||||
onChange={this.changeField.bind(this, 'goDay')} value={this.state.goDay}
|
||||
min={1} max={31}/>
|
||||
<button type="submit" className="form-control btn btn-primary go-button">Go</button>
|
||||
</form>
|
||||
<GregorianJumper minJDN={frStartJD} maxJDN={frEndJD} todayJDN={this.state.todayJDN}
|
||||
onJump={this.goToJDN}/>
|
||||
</div>
|
||||
</>;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import React, {FormEvent} from 'react';
|
||||
import React from 'react';
|
||||
import {Calendar} from './Calendar';
|
||||
import {frEndJD, frStartJD} from '@common/french';
|
||||
import {dateJDN, gregorianJDN, JulianMonth} from '@common/gregorian';
|
||||
import {DayChanger} from '@common/DayChanger';
|
||||
import {jdnJulian} from '@common/julian';
|
||||
import {GregorianJumper} from '@common/dateJump';
|
||||
|
||||
// Not real limitations other than JS number precision.
|
||||
const START_YEAR = -10_000_000_000_000;
|
||||
const END_YEAR = 10_000_000_000_000;
|
||||
const START_JDN = gregorianJDN(-10_000_000_000_000, 1, 1);
|
||||
const END_JDN = gregorianJDN(10_000_000_000_000, 12, 31);
|
||||
|
||||
type YearMonth = {
|
||||
year: number;
|
||||
|
@ -28,9 +28,6 @@ function parseURL(): YearMonth | null {
|
|||
|
||||
type AppState = YearMonth & {
|
||||
todayJDN: number,
|
||||
goYear: string,
|
||||
goMonth: string,
|
||||
goDay: string,
|
||||
};
|
||||
|
||||
class App extends React.Component<{}, AppState> {
|
||||
|
@ -38,16 +35,12 @@ class App extends React.Component<{}, AppState> {
|
|||
|
||||
constructor(props: {}) {
|
||||
super(props);
|
||||
const today = new Date();
|
||||
const todayJDN = dateJDN(today);
|
||||
const todayJDN = dateJDN(new Date());
|
||||
const [year, month] = jdnJulian(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);
|
||||
}
|
||||
|
@ -72,33 +65,6 @@ class App extends React.Component<{}, AppState> {
|
|||
}
|
||||
}
|
||||
|
||||
changeField(field: keyof AppState, event: any) {
|
||||
this.setState({[field]: event.target.value});
|
||||
}
|
||||
|
||||
validYear() {
|
||||
return /^-?\d+$/.test(this.state.goYear) && START_YEAR <= +this.state.goYear && +this.state.goYear <= END_YEAR;
|
||||
}
|
||||
|
||||
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] = jdnJulian(Math.min(Math.max(frStartJD, jdn), frEndJD));
|
||||
this.setState({year, month});
|
||||
}
|
||||
|
||||
setState(state: any, callback?: () => void) {
|
||||
super.setState(state, () => {
|
||||
this.updateURL();
|
||||
|
@ -110,6 +76,11 @@ class App extends React.Component<{}, AppState> {
|
|||
this.setState({todayJDN});
|
||||
};
|
||||
|
||||
goToJDN = (jdn: number) => {
|
||||
const [year, month] = jdnJulian(jdn);
|
||||
this.setState({year, month});
|
||||
};
|
||||
|
||||
render() {
|
||||
return <>
|
||||
<Calendar
|
||||
|
@ -122,19 +93,8 @@ class App extends React.Component<{}, AppState> {
|
|||
|
||||
<div className="navigate">
|
||||
<h4>Go to a date</h4>
|
||||
<form className="input-group" onSubmit={this.goToGregorian.bind(this)}>
|
||||
<span className="input-group-text">Gregorian<span className="hide-small"> Date</span></span>
|
||||
<input type="number" className={`form-control go-year ${this.validYear() ? '' : 'is-invalid'}`}
|
||||
onChange={this.changeField.bind(this, 'goYear')} value={this.state.goYear}
|
||||
min={START_YEAR} max={END_YEAR}/>
|
||||
<input type="number" className={`form-control go-month ${this.validMonth() ? '' : 'is-invalid'}`}
|
||||
onChange={this.changeField.bind(this, 'goMonth')} value={this.state.goMonth}
|
||||
min={1} max={12}/>
|
||||
<input type="number" className={`form-control go-day ${this.validDay() ? '' : 'is-invalid'}`}
|
||||
onChange={this.changeField.bind(this, 'goDay')} value={this.state.goDay}
|
||||
min={1} max={31}/>
|
||||
<button type="submit" className="form-control btn btn-primary go-button">Go</button>
|
||||
</form>
|
||||
<GregorianJumper minJDN={START_JDN} maxJDN={END_JDN} todayJDN={this.state.todayJDN}
|
||||
onJump={this.goToJDN}/>
|
||||
</div>
|
||||
</>;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue