From d36660466595d5178ccd5cb3a9c1efcc130963d5 Mon Sep 17 00:00:00 2001 From: Quantum Date: Sat, 12 Feb 2022 16:25:44 -0500 Subject: [PATCH] Implement state in URL --- src/App.tsx | 80 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 9 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 51c77f8..a2c3557 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,16 +1,78 @@ -import React, {useState} from 'react'; +import React from 'react'; import './App.css'; import {Calendar} from './Calendar'; import {gregorianJDN, Month} from "./dates"; -function App() { - const today = new Date(); - const todayJDN = gregorianJDN(today.getFullYear(), today.getMonth() + 1, today.getDay()); - const [yearMonth, setYearMonth] = useState([230, 5]); - return ( - setYearMonth([year, month])}/> - ); +type YearMonth = { + year: number; + month: Month; +} + +function parseURL(): YearMonth | null { + const match = /\/(-?\d+)\/(\d+)/.exec(window.location.pathname); + if (!match) + return null; + + const month = +match[2]; + if (month < 1 || month > 13) + return null; + return {year: +match[1], month: month as Month}; +} + +type AppState = YearMonth & { + todayJDN: number, +}; + +class App extends React.Component<{}, AppState> { + state: AppState; + + constructor(props: {}) { + super(props); + const current = {year: 230, month: 5}; + const today = new Date(); + + this.state = { + ...(parseURL() || current as YearMonth), + todayJDN: gregorianJDN(today.getFullYear(), today.getMonth() + 1, today.getDay()), + }; + this.updateURL(); + 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); + } + } + + setState(state: any, callback?: () => void) { + super.setState(state, () => { + this.updateURL(); + callback && callback(); + }); + } + + render() { + return { + this.setState({year, month}) + }}/>; + } } export default App;