255 lines
7.5 KiB
TypeScript
255 lines
7.5 KiB
TypeScript
import { Box, Grid, Stack } from '@mantine/core';
|
|
import { useDisclosure } from '@mantine/hooks';
|
|
import CurrentWeather from 'components/WeatherModal/CurrentWeather';
|
|
import { useCommonHooks, useOSMAPI, useQueryAPI, useWeatherAPI } from 'hooks';
|
|
import { useEffect, useState } from 'react';
|
|
import { stackClasses } from 'styles';
|
|
import type {
|
|
CurrentWeather as CW,
|
|
ExtendedForecast,
|
|
Message,
|
|
PersonalData,
|
|
} from 'types';
|
|
import {
|
|
Applications,
|
|
Bookmarks,
|
|
Header,
|
|
LargeHeader,
|
|
Search,
|
|
SettingsButton,
|
|
} from './components';
|
|
|
|
export function Homepage() {
|
|
const {
|
|
appFilter,
|
|
bookmarkFilter,
|
|
isMobile,
|
|
setCurrentUser,
|
|
currentLocation,
|
|
setCurrentLocation,
|
|
} = useCommonHooks();
|
|
const dateOptions: Intl.DateTimeFormatOptions = isMobile
|
|
? {}
|
|
: {
|
|
weekday: 'long',
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric',
|
|
};
|
|
|
|
const date = new Date().toLocaleDateString('en-US', dateOptions);
|
|
|
|
const { data: personalData, isFetched: personalIsFetched } = useQueryAPI({
|
|
endpoint: 'api/personalData',
|
|
});
|
|
const { data: messageData } = useQueryAPI({
|
|
endpoint: 'api/displayedGreeting',
|
|
});
|
|
const { data: weatherMetadata } = useOSMAPI({
|
|
address: personalData?.[0]?.physicalAddress,
|
|
});
|
|
const { data: points } = useWeatherAPI({
|
|
endpoint: 'points',
|
|
lat: weatherMetadata?.[0].lat ?? currentLocation.lat,
|
|
lon: weatherMetadata?.[0].lon ?? currentLocation.lon,
|
|
});
|
|
const { data: basicWeather } = useWeatherAPI({
|
|
endpoint: 'baseline',
|
|
office: points?.properties.gridId ?? currentLocation.office,
|
|
x: points?.properties.gridX ?? currentLocation.x,
|
|
y: points?.properties.gridY ?? currentLocation.y,
|
|
});
|
|
const { data: stations } = useWeatherAPI({
|
|
endpoint: 'stations',
|
|
office: points?.properties.gridId ?? currentLocation.office,
|
|
x: points?.properties.gridX ?? currentLocation.x,
|
|
y: points?.properties.gridY ?? currentLocation.y,
|
|
});
|
|
const { data: weather } = useWeatherAPI({
|
|
endpoint: 'current',
|
|
station:
|
|
stations?.features[0].properties.stationIdentifier ?? currentLocation.station,
|
|
});
|
|
const { data: forecast } = useWeatherAPI({
|
|
endpoint: 'forecast',
|
|
office: points?.properties.gridId ?? currentLocation.office,
|
|
x: points?.properties.gridX ?? currentLocation.x,
|
|
y: points?.properties.gridY ?? currentLocation.y,
|
|
});
|
|
|
|
const personal: PersonalData = personalData?.[0];
|
|
const message: Message = messageData?.[0] || {};
|
|
const [displayedGreeting, setDisplayedGreeting] = useState<string | undefined>('');
|
|
const [current, setCurrent] = useState<CW>({
|
|
icon: '',
|
|
textDescription: '',
|
|
temperature: 0,
|
|
highTemp: 0,
|
|
lowTemp: 0,
|
|
precipitation: 'N/A',
|
|
humidity: 0,
|
|
heatIndex: null,
|
|
windChill: null,
|
|
windSpeed: 0,
|
|
windDirection: 0,
|
|
pressure: 0,
|
|
});
|
|
const [providerModalOpened, { open: openProviderModal, close: closeProviderModal }] =
|
|
useDisclosure(false);
|
|
const extendedForecast = forecast?.properties?.periods.map(
|
|
(item: ExtendedForecast) => ({
|
|
detailedForecast: item.detailedForecast,
|
|
isDaytime: item.isDaytime,
|
|
name: item.name,
|
|
shortForecast: item.shortForecast,
|
|
temperature: item.temperature,
|
|
temperatureUnit: item.temperatureUnit,
|
|
}),
|
|
) || [
|
|
{
|
|
detailedForecast: '',
|
|
isDaytime: true,
|
|
name: '',
|
|
shortForecast: '',
|
|
temperature: 0,
|
|
temperatureUnit: 'F',
|
|
},
|
|
];
|
|
const [weatherModalOpened, { open: openWeatherModal, close: closeWeatherModal }] =
|
|
useDisclosure(false);
|
|
|
|
useEffect(() => {
|
|
if (personalData && personalIsFetched) {
|
|
setCurrentUser(personalData[0]);
|
|
}
|
|
}, [personalData, personalIsFetched]);
|
|
useEffect(() => {
|
|
if (personal) {
|
|
setDisplayedGreeting(() => {
|
|
if (Math.floor(Math.random() * 100) > 10 || message.message === undefined) {
|
|
switch (Math.floor(new Date().getHours() / 6)) {
|
|
case 0:
|
|
return `Good night, ${personal?.firstName}!`;
|
|
case 1:
|
|
return `Good morning, ${personal?.firstName}!`;
|
|
case 2:
|
|
return `Good afternoon, ${personal?.firstName}!`;
|
|
case 3:
|
|
return `Good evening, ${personal?.firstName}!`;
|
|
}
|
|
}
|
|
return message?.message;
|
|
});
|
|
}
|
|
}, [message, personal]);
|
|
useEffect(() => {
|
|
if (weather !== undefined && basicWeather !== undefined) {
|
|
setCurrent({
|
|
icon: weather.features[0]?.properties.icon?.replace('medium', 'large') ?? '',
|
|
textDescription: weather.features[0]?.properties.textDescription,
|
|
temperature: Math.round(
|
|
(weather.features?.find((feature: any) => feature.properties.temperature.value)
|
|
.properties.temperature.value *
|
|
9) /
|
|
5 +
|
|
32,
|
|
),
|
|
highTemp: Math.round(
|
|
(basicWeather.properties.maxTemperature.values[0].value * 9) / 5 + 32,
|
|
),
|
|
lowTemp: Math.round(
|
|
(basicWeather.properties.minTemperature.values[0].value * 9) / 5 + 32,
|
|
),
|
|
precipitation:
|
|
weather.features[0]?.properties?.precipitationLastHour?.value ?? 'N/A',
|
|
humidity: Math.round(weather.features[0]?.properties?.relativeHumidity?.value),
|
|
heatIndex:
|
|
basicWeather.properties.heatIndex?.values[0].value === null
|
|
? null
|
|
: Math.round(
|
|
(basicWeather.properties.heatIndex.values[0].value * 9) / 5 + 32,
|
|
),
|
|
windChill:
|
|
basicWeather.properties.windChill?.values[0].value === null
|
|
? null
|
|
: Math.round(
|
|
(basicWeather.properties.windChill.values[0].value * 9) / 5 + 32,
|
|
),
|
|
windSpeed: Math.round(weather.features[0]?.properties.windSpeed.value / 1.60934),
|
|
windDirection: weather.features[0]?.properties.windDirection.value,
|
|
pressure: Math.round(
|
|
weather.features[0]?.properties.barometricPressure.value / 3386.38,
|
|
),
|
|
});
|
|
}
|
|
}, [weather, basicWeather]);
|
|
useEffect(() => {
|
|
if (forecast) {
|
|
setCurrentLocation({
|
|
office: points?.properties.gridId,
|
|
station: stations?.features[0].properties.stationIdentifier,
|
|
x: points?.properties.gridX,
|
|
y: points?.properties.gridY,
|
|
lat: weatherMetadata?.[0].lat,
|
|
lon: weatherMetadata?.[0].lon,
|
|
});
|
|
}
|
|
}, [forecast]);
|
|
|
|
return (
|
|
<Stack
|
|
gap={0}
|
|
h={appFilter.length > 0 || bookmarkFilter.length > 0 ? undefined : '100%'}
|
|
className={stackClasses.containerStack}
|
|
justify='center'
|
|
>
|
|
{appFilter.length > 0 || bookmarkFilter.length > 0 ? (
|
|
<>
|
|
<Search
|
|
current={current}
|
|
extendedForecast={extendedForecast}
|
|
weatherModalOpened={weatherModalOpened}
|
|
closeWeatherModal={closeWeatherModal}
|
|
openWeatherModal={openWeatherModal}
|
|
position='top'
|
|
personal={personal}
|
|
providerModalOpened={providerModalOpened}
|
|
openProviderModal={openProviderModal}
|
|
closeProviderModal={closeProviderModal}
|
|
/>
|
|
<Header
|
|
greet={displayedGreeting}
|
|
date={date}
|
|
current={current}
|
|
openWeatherModal={openWeatherModal}
|
|
/>
|
|
<Applications contentType={appFilter} />
|
|
<Bookmarks contentType={bookmarkFilter} />
|
|
</>
|
|
) : (
|
|
<Box h={'100%'} w={'100%'}>
|
|
<Stack align='center'>
|
|
<LargeHeader greet={displayedGreeting} date={date} />
|
|
<Grid grow columns={24} pos={'absolute'} bottom={'1rem'}>
|
|
<CurrentWeather current={current} />
|
|
</Grid>
|
|
</Stack>
|
|
<Search
|
|
current={current}
|
|
extendedForecast={extendedForecast}
|
|
weatherModalOpened={weatherModalOpened}
|
|
closeWeatherModal={closeWeatherModal}
|
|
openWeatherModal={openWeatherModal}
|
|
position='center'
|
|
personal={personal}
|
|
providerModalOpened={providerModalOpened}
|
|
openProviderModal={openProviderModal}
|
|
closeProviderModal={closeProviderModal}
|
|
/>
|
|
</Box>
|
|
)}
|
|
<SettingsButton openProviderModal={openProviderModal} />
|
|
</Stack>
|
|
);
|
|
}
|