253 lines
7.6 KiB
TypeScript
253 lines
7.6 KiB
TypeScript
import { 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 as EF,
|
|
Message,
|
|
PersonalData,
|
|
} from 'types';
|
|
import Applications from './components/Applications/Applications';
|
|
import Bookmarks from './components/Bookmarks/Bookmarks';
|
|
import Header from './components/Header/Header';
|
|
import LargeHeader from './components/Header/LargeHeader';
|
|
import Search from './components/Search/Search';
|
|
import SettingsButton from './components/SettingsButton';
|
|
|
|
export function Homepage() {
|
|
const { data: personal, isFetched: personalIsFetched } = useQueryAPI({
|
|
endpoint: 'api/personalData',
|
|
});
|
|
const {
|
|
data: messageData,
|
|
isFetching: isMessagesFetching,
|
|
isFetched: isMessagesFetched,
|
|
} = useQueryAPI({
|
|
endpoint: 'api/messages',
|
|
});
|
|
const {
|
|
appFilter,
|
|
bookmarkFilter,
|
|
isMobile,
|
|
setCurrentUser,
|
|
currentLocation,
|
|
setCurrentLocation,
|
|
} = useCommonHooks();
|
|
const [personalData, setPersonalData] = useState<PersonalData>();
|
|
const [messages, setMessages] = useState<Message[]>([]);
|
|
const [displayedGreeting, setDisplayedGreeting] = useState('');
|
|
const [weatherModalOpened, { open: openWeatherModal, close: closeWeatherModal }] =
|
|
useDisclosure(false);
|
|
const dateOptions: Intl.DateTimeFormatOptions = !isMobile
|
|
? {
|
|
weekday: 'long',
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric',
|
|
}
|
|
: {};
|
|
const date = new Date().toLocaleDateString('en-US', dateOptions);
|
|
useEffect(() => {
|
|
if (messageData && isMessagesFetched) {
|
|
setMessages(messageData);
|
|
}
|
|
}, [messageData, isMessagesFetched]);
|
|
useEffect(() => {
|
|
if (personal && personalIsFetched) {
|
|
setCurrentUser(personal[0]);
|
|
setPersonalData(personal[0]);
|
|
}
|
|
}, [personal, personalIsFetched]);
|
|
useEffect(() => {
|
|
if (messages && personalData) {
|
|
setDisplayedGreeting(() => {
|
|
if (Math.floor(Math.random() * 100) > 10 || messages.length === 0) {
|
|
switch (Math.floor(new Date().getHours() / 6)) {
|
|
case 0:
|
|
return `Good night, ${personalData?.firstName}!`;
|
|
case 1:
|
|
return `Good morning, ${personalData?.firstName}!`;
|
|
case 2:
|
|
return `Good afternoon, ${personalData?.firstName}!`;
|
|
case 3:
|
|
return `Good evening, ${personalData?.firstName}!`;
|
|
}
|
|
}
|
|
return messages[Math.floor(Math.random() * messages.length)].message;
|
|
});
|
|
}
|
|
}, [messages, personalData, isMessagesFetching]);
|
|
|
|
const { data: weatherMetadata } = useOSMAPI({ address: personal?.[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 [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 [extendedForecast, setExtendedForecast] = useState<EF[]>([
|
|
{
|
|
detailedForecast: '',
|
|
isDaytime: true,
|
|
name: '',
|
|
shortForecast: '',
|
|
temperature: 0,
|
|
temperatureUnit: 'F',
|
|
},
|
|
]);
|
|
|
|
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[0]?.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) {
|
|
setExtendedForecast(
|
|
forecast.properties.periods.map((item: any) => ({
|
|
detailedForecast: item.detailedForecast,
|
|
isDaytime: item.isDaytime,
|
|
name: item.name,
|
|
shortForecast: item.shortForecast,
|
|
temperature: item.temperature,
|
|
temperatureUnit: item.temperatureUnit,
|
|
})),
|
|
);
|
|
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}
|
|
/>
|
|
<Header
|
|
greet={displayedGreeting}
|
|
date={date}
|
|
current={current}
|
|
setCurrent={setCurrent}
|
|
weather={weather}
|
|
basicWeather={basicWeather}
|
|
openWeatherModal={openWeatherModal}
|
|
/>
|
|
<Applications contentType={appFilter} />
|
|
<Bookmarks contentType={bookmarkFilter} />
|
|
</>
|
|
) : (
|
|
<>
|
|
<Stack align='center'>
|
|
<LargeHeader
|
|
greet={displayedGreeting}
|
|
date={date}
|
|
weather={weather}
|
|
basicWeather={basicWeather}
|
|
setCurrent={setCurrent}
|
|
/>
|
|
<Grid grow columns={24} pos={'absolute'} bottom={'1rem'} w={'50%'}>
|
|
<CurrentWeather current={current} />
|
|
</Grid>
|
|
</Stack>
|
|
<Search
|
|
current={current}
|
|
extendedForecast={extendedForecast}
|
|
weatherModalOpened={weatherModalOpened}
|
|
closeWeatherModal={closeWeatherModal}
|
|
openWeatherModal={openWeatherModal}
|
|
/>
|
|
</>
|
|
)}
|
|
<SettingsButton />
|
|
</Stack>
|
|
);
|
|
}
|