Files
TriggerFrontend/src/pages/homepage/Homepage.tsx
2025-03-12 17:30:41 -05:00

300 lines
9.4 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, OutlookWeather } from 'types';
import type { ExtendedForecast as EF } from 'types/weather';
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 [personalData, setPersonalData] = useState<any>(null);
const [messages, setMessages] = useState<any>(null);
const [displayedGreeting, setDisplayedGreeting] = useState('');
const [weatherModalOpened, { open: openWeatherModal, close: closeWeatherModal }] =
useDisclosure(false);
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);
useEffect(() => {
if (messageData && isMessagesFetched) {
setMessages(messageData);
}
}, [messageData, isMessagesFetched]);
useEffect(() => {
if (personal && personalIsFetched) {
setCurrentUser(personal[0]);
setPersonalData(personal);
}
}, [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?.[0]?.firstName}!`;
case 1:
return `Good morning, ${personalData?.[0]?.firstName}!`;
case 2:
return `Good afternoon, ${personalData?.[0]?.firstName}!`;
case 3:
return `Good evening, ${personalData?.[0]?.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 [outlook, setOutlook] = useState<OutlookWeather[]>([
{
name: '',
icon: '',
isDayTime: true,
temperature: 0,
precipitation: 0,
windSpeed: '0 mph',
windDirection: 'N',
},
]);
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) {
setOutlook([
{
name: forecast.properties.periods[0].name,
icon: forecast.properties.periods[0].icon.replace('medium', 'large'),
isDayTime: forecast.properties.periods[0].isDaytime,
temperature: forecast.properties.periods[0].temperature,
precipitation: Math.round(
forecast.properties.periods[0].probabilityOfPrecipitation.value,
),
windSpeed: forecast.properties.periods[0].windSpeed,
windDirection: forecast.properties.periods[0].windDirection,
},
{
name: forecast.properties.periods[1].name,
icon: forecast.properties.periods[1].icon.replace('medium', 'large'),
isDayTime: forecast.properties.periods[1].isDaytime,
temperature: forecast.properties.periods[1].temperature,
precipitation: Math.round(
forecast.properties.periods[1].probabilityOfPrecipitation.value,
),
windSpeed: forecast.properties.periods[1].windSpeed,
windDirection: forecast.properties.periods[1].windDirection,
},
]);
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}
outlook={outlook}
extendedForecast={extendedForecast}
weather={weather}
basicWeather={basicWeather}
weatherModalOpened={weatherModalOpened}
closeWeatherModal={closeWeatherModal}
openWeatherModal={openWeatherModal}
/>
<Header
date={date}
greet={displayedGreeting}
current={current}
setCurrent={setCurrent}
outlook={outlook}
extendedForecast={extendedForecast}
weather={weather}
basicWeather={basicWeather}
weatherModalOpened={weatherModalOpened}
closeWeatherModal={closeWeatherModal}
openWeatherModal={openWeatherModal}
/>
<Applications contentType={appFilter} />
<Bookmarks contentType={bookmarkFilter} />
</>
) : (
<>
<Stack align='center'>
<LargeHeader
date={date}
greet={displayedGreeting}
current={current}
setCurrent={setCurrent}
outlook={outlook}
extendedForecast={extendedForecast}
weather={weather}
basicWeather={basicWeather}
weatherModalOpened={weatherModalOpened}
closeWeatherModal={closeWeatherModal}
openWeatherModal={openWeatherModal}
/>
<Grid grow columns={24} pos={'absolute'} bottom={'1rem'} w={'50%'}>
<CurrentWeather span={18} current={current} />
</Grid>
</Stack>
<Search
current={current}
outlook={outlook}
extendedForecast={extendedForecast}
weather={weather}
basicWeather={basicWeather}
weatherModalOpened={weatherModalOpened}
closeWeatherModal={closeWeatherModal}
openWeatherModal={openWeatherModal}
/>
</>
)}
<SettingsButton />
</Stack>
);
}