Skip to content

Commit

Permalink
date arithmetics, reformatting...
Browse files Browse the repository at this point in the history
  • Loading branch information
lmueller27 committed Jul 10, 2023
1 parent 8f5da87 commit a632e46
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 57 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Trends are computed in line with the National Center for Atmospheric Research St

## Try it out

You can try the app [here](https://codesandbox.io/p/github/lmueller27/daily-weather-history/sandbox) in a sandbox.
You can try the app in a sandbox: [here](https://codesandbox.io/p/github/lmueller27/daily-weather-history/sandbox).

To run it locally, clone the repo and install the dependencies:

Expand Down
42 changes: 36 additions & 6 deletions app/components/collapsibleMap.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { faChevronDown, faChevronUp, faLocationDot, faMapLocation, faMapLocationDot } from "@fortawesome/free-solid-svg-icons"
import { faChevronDown, faChevronUp, faLocationDot, faMapLocationDot } from "@fortawesome/free-solid-svg-icons"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { Draggable, Map, Point } from "pigeon-maps"
import { inputState, myColors } from "../shared/utils"
import { useRef, useState } from "react"
import styles from '../styles/form.module.css'

export default function CollapsibleMap({ inputState, setInputState, center, setCenter }: { inputState: inputState, setInputState: React.Dispatch<React.SetStateAction<inputState>>, center: [number, number], setCenter: React.Dispatch<React.SetStateAction<[number, number]>> }) {
export default function CollapsibleMap({ inputState, setInputState, center, setCenter }:
{
inputState: inputState,
setInputState: React.Dispatch<React.SetStateAction<inputState>>,
center: [number, number], setCenter: React.Dispatch<React.SetStateAction<[number, number]>>
}) {

const [zoom, setZoom] = useState(11)
const [mapOpen, setMapOpen] = useState(true);
Expand All @@ -14,22 +19,47 @@ export default function CollapsibleMap({ inputState, setInputState, center, setC

return (
<div className={styles.mapGroup}>
<button className={styles.mapToggleButton} style={mapOpen ? { borderBottomLeftRadius: '0px' } : { borderBottomLeftRadius: '10px' }} type="button" onClick={() => setMapOpen(!mapOpen)}>{mapOpen ? <p><FontAwesomeIcon icon={faChevronUp} color={myColors.IconBlue} /> Collapse Map</p> : <p><FontAwesomeIcon icon={faChevronDown} color={myColors.IconBlue} /> Expand Map <FontAwesomeIcon icon={faMapLocationDot} color={myColors.IconBlue} /></p>}</button>
<div ref={mapRef} className={styles.mapSpace} style={mapOpen ? { height: '300px' } : { height: "25px" }}>
<button
className={styles.mapToggleButton}
style={mapOpen ? { borderBottomLeftRadius: '0px' } : { borderBottomLeftRadius: '10px' }}
type="button"
onClick={() => setMapOpen(!mapOpen)}>
{mapOpen ?
<p>
<FontAwesomeIcon icon={faChevronUp} color={myColors.IconBlue} />
Collapse Map
</p> :
<p>
<FontAwesomeIcon icon={faChevronDown} color={myColors.IconBlue} />
Expand Map
<FontAwesomeIcon icon={faMapLocationDot} color={myColors.IconBlue} />
</p>}
</button>
<div
ref={mapRef}
className={styles.mapSpace}
style={mapOpen ? { height: '300px' } : { height: "25px" }}>
<Map
height={300}
defaultCenter={[50.8, 6.10]}
defaultZoom={11}
center={center}
zoom={zoom}
mouseEvents={mapOpen}
touchEvents={mapOpen}
onClick={({ latLng }) => updateMarker(latLng)}
onBoundsChanged={({ center, zoom }) => {
setCenter(center)
setZoom(zoom)
}}>
<Draggable offset={[6, 20]} anchor={[Number(inputState.latitude), Number(inputState.longitude)]} onDragEnd={updateMarker}>
{(!Number.isNaN(inputState.latitude) && !Number.isNaN(inputState.longitude)) && (inputState.latitude != undefined && inputState.longitude != undefined) ?
<Draggable
offset={[6, 20]}
anchor={[Number(inputState.latitude), Number(inputState.longitude)]}
onDragEnd={updateMarker}>
{(!Number.isNaN(inputState.latitude)
&& !Number.isNaN(inputState.longitude))
&& (inputState.latitude != undefined
&& inputState.longitude != undefined) ?
<FontAwesomeIcon icon={faLocationDot} color={myColors.IconBlue} /> : null}
</Draggable>
</Map>
Expand Down
18 changes: 11 additions & 7 deletions app/components/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default function Form(props: any) {
latitude: undefined,
longitude: undefined,
targetDate: todaysDate.toISOString().slice(0, -14),
startDate: new Date('1940-01-01').toISOString().slice(0, -14),
startDate: '1940-01-01',
endDate: todaysDate.toISOString().slice(0, -14),
})

Expand Down Expand Up @@ -52,7 +52,10 @@ export default function Form(props: any) {
useEffect(() => {
const triggerCurrentVisMode = async () => {
let inputCheck = { ...inputValidation };
const validInterval = new Date(inputState.startDate).valueOf() < new Date(inputState.endDate).valueOf() && Number(inputState.startDate.slice(0, 4)) >= 1940
const validInterval =
new Date(inputState.startDate).valueOf() < new Date(inputState.endDate).valueOf()
&& Number(inputState.startDate.slice(0, 4)) >= 1940
&& (Date.parse(inputState.endDate) - todaysDate.valueOf() < 0)

inputCheck.lat = !Number.isNaN(inputState.latitude) && inputState.latitude !== undefined
inputCheck.long = !Number.isNaN(inputState.longitude) && inputState.longitude !== undefined
Expand All @@ -62,9 +65,10 @@ export default function Form(props: any) {
// for the interval mode we dont need to check the target date validity but do need to limit the interval borders
if (state.currentVisMode === visualizationModes.Interval) {
inputCheck.target = true;
const ltTenYears = Number(inputState.endDate.slice(0, 4)) - Number(inputState.startDate.slice(0, 4)) <= 10
inputCheck.start = ltTenYears
inputCheck.end = ltTenYears
const ltTenYears =
Number(inputState.endDate.slice(0, 4)) - Number(inputState.startDate.slice(0, 4)) <= 10
inputCheck.start = validInterval && ltTenYears
inputCheck.end = validInterval && ltTenYears
if (Object.values(inputCheck).reduce((a, b) => a && b, true)) {
await getOpenMeteoData(inputState, state, setState);
}
Expand All @@ -90,10 +94,10 @@ export default function Form(props: any) {
return (
<div className={styles.form} >
<InputSpace inputState={inputState} setInputState={setInputState} inputValidation={inputValidation} />
<GenerateButtons state={state} setState={setState} inputState={inputState} setInputState={setInputState} inputValidation={inputValidation} setInputValidation={setInputValidation} />
<GenerateButtons state={state} setState={setState} inputState={inputState} inputValidation={inputValidation} />
{state.formTitle}
<p>{state.formGeoString}</p>
<h4>Click on the series to freeze/unfreeze the tooltip. Drag to zoom in.</h4>
<h4>Click on the series to freeze/unfreeze the tooltip. Drag to zoom in on a period.</h4>
<div className={styles.figureSpace}>
<div className={styles.graphSpace}>
<AutoSizer disableHeight >
Expand Down
63 changes: 53 additions & 10 deletions app/components/generateButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,64 @@ import { getDateHistory, getMonthHistory, getOpenMeteoData, getWeekHistory } fro
import { formState, inputState, inputValidation, visualizationModes } from "../shared/utils";
import styles from '../styles/form.module.css'

export function GenerateButtons({ state, setState, inputState, setInputState, inputValidation, setInputValidation }: { state: formState, setState: React.Dispatch<React.SetStateAction<formState>>, inputState: inputState, setInputState: React.Dispatch<React.SetStateAction<inputState>>, inputValidation:inputValidation, setInputValidation: any }) {
export function GenerateButtons({ state, setState, inputState, inputValidation }:
{
state: formState,
setState: React.Dispatch<React.SetStateAction<formState>>,
inputState: inputState,
inputValidation: inputValidation
}) {
return (
<div className={styles.generateButtons}>
<p>Show Data For:</p>
<button type="button" className={state.currentVisMode === visualizationModes.DateHistory ? styles.activatedMode : undefined} onClick={() => getDateHistory(inputState, state, setState)} disabled={!validateDateInput()}>History of Target Date</button>
<button type="button" className={state.currentVisMode === visualizationModes.WeekHistory ? styles.activatedMode : undefined} onClick={() => getWeekHistory(inputState, state, setState)} disabled={!validateDateInput()}>History of Target Week</button>
<button type="button" className={state.currentVisMode === visualizationModes.MonthHistory ? styles.activatedMode : undefined} onClick={() => getMonthHistory(inputState, state, setState)} disabled={!validateDateInput()}>History of Target Month</button>
<button type="button" className={state.currentVisMode === visualizationModes.Interval ? styles.activatedMode : undefined} onClick={() => getOpenMeteoData(inputState, state, setState)} disabled={!validateIntervalInput()}>Whole Interval (max 10 years)</button>
<button
type="button"
className={state.currentVisMode === visualizationModes.DateHistory ?
styles.activatedMode : undefined}
onClick={() => getDateHistory(inputState, state, setState)}
disabled={!validateDateInput()}>
History of Target Date
</button>
<button
type="button"
className={state.currentVisMode === visualizationModes.WeekHistory ?
styles.activatedMode : undefined}
onClick={() => getWeekHistory(inputState, state, setState)}
disabled={!validateDateInput()}>
History of Target Week
</button>
<button
type="button"
className={state.currentVisMode === visualizationModes.MonthHistory ?
styles.activatedMode : undefined}
onClick={() => getMonthHistory(inputState, state, setState)}
disabled={!validateDateInput()}>
History of Target Month
</button>
<button
type="button"
className={state.currentVisMode === visualizationModes.Interval ?
styles.activatedMode : undefined}
onClick={() => getOpenMeteoData(inputState, state, setState)}
disabled={!validateIntervalInput()}>
Whole Interval (max 10 years)
</button>
</div>
)

/**
*
* @returns true if input is INVALID
*/
function validateIntervalInput() {
// validate input
const ltTenYears = Number(inputState.endDate.slice(0, 4)) - Number(inputState.startDate.slice(0, 4)) <= 10
return inputValidation.lat && inputValidation.long && inputValidation.start && inputValidation.end && ltTenYears

return inputValidation.lat
&& inputValidation.long
&& inputValidation.start
&& inputValidation.end
&& ltTenYears

}

/**
Expand All @@ -30,7 +68,12 @@ export function GenerateButtons({ state, setState, inputState, setInputState, in
*/
function validateDateInput() {
// validate input but check target date and interval extra
const validInterval = new Date(inputState.startDate).valueOf() < new Date(inputState.endDate).valueOf() && Number(inputState.startDate.slice(0, 4)) >= 1940
return inputValidation.lat && inputValidation.long && (inputState.targetDate?true:false) && validInterval
const validInterval = new Date(inputState.startDate).valueOf() < new Date(inputState.endDate).valueOf()
&& Number(inputState.startDate.slice(0, 4)) >= 1940
&& (Date.parse(inputState.endDate) - Date.now() < 0)
return inputValidation.lat
&& inputValidation.long
&& (inputState.targetDate ? true : false)
&& validInterval
}
}
Loading

0 comments on commit a632e46

Please sign in to comment.