This commit is contained in:
@@ -17,7 +17,7 @@ import { datePickerInputClasses, selectClasses } from 'styles';
|
||||
|
||||
declare module '@tanstack/react-table' {
|
||||
//allows us to define custom properties for our columns
|
||||
interface ColumnMeta<TData extends RowData, TValue> {
|
||||
interface ColumnMeta<_TData extends RowData, _TValue> {
|
||||
filterVariant?:
|
||||
| 'text'
|
||||
| 'range'
|
||||
|
||||
@@ -230,6 +230,7 @@ export default function CurrentWeather({
|
||||
? textClasses.autoScrollText
|
||||
: undefined
|
||||
}
|
||||
fz={isMobile ? 12 : 18}
|
||||
classNames={textClasses}
|
||||
style={{ lineHeight: 1 }}
|
||||
>
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
import { ActionIcon, Box, Card, Group, Stack, Text } from '@mantine/core';
|
||||
import { FaArrowDown, FaArrowUp, FaLocationArrow, FaSun, FaWind } from 'react-icons/fa';
|
||||
import { FaX } from 'react-icons/fa6';
|
||||
import { useCommonHooks } from 'hooks';
|
||||
import { FaLocationArrow, FaSun, FaWind } from 'react-icons/fa';
|
||||
import { FaDroplet, FaX } from 'react-icons/fa6';
|
||||
import { WiRain, WiSunrise, WiSunset } from 'react-icons/wi';
|
||||
import { textClasses } from 'styles';
|
||||
import { WeatherCodes } from 'types';
|
||||
import WeatherFeaturePill from './WeatherFeaturePill';
|
||||
import WeatherGraphs from './WeatherGraphs';
|
||||
import WeatherIcon from './WeatherIcon';
|
||||
|
||||
export default function ExtendedForecastDetails({
|
||||
selectedDay,
|
||||
setSelectedDay,
|
||||
selectedHourly,
|
||||
setSelectedHourly,
|
||||
}: {
|
||||
selectedDay: any;
|
||||
setSelectedDay: (day: any) => void;
|
||||
selectedHourly: any;
|
||||
setSelectedHourly: (hourly: any) => void;
|
||||
}) {
|
||||
const { isMobile } = useCommonHooks();
|
||||
return (
|
||||
<Card
|
||||
h={'100%'}
|
||||
@@ -24,7 +32,8 @@ export default function ExtendedForecastDetails({
|
||||
borderRadius: '8px',
|
||||
overflow: 'visible',
|
||||
cursor: 'default',
|
||||
boxShadow: '15px 15px 3px var(--mantine-color-border-0)',
|
||||
boxShadow:
|
||||
'15px 15px 2px color-mix(in srgb, var(--mantine-color-border-0), transparent 50%)',
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
@@ -41,6 +50,7 @@ export default function ExtendedForecastDetails({
|
||||
}}
|
||||
onClick={() => {
|
||||
setSelectedDay(undefined);
|
||||
setSelectedHourly(undefined);
|
||||
}}
|
||||
>
|
||||
<FaX />
|
||||
@@ -64,10 +74,96 @@ export default function ExtendedForecastDetails({
|
||||
</Text>
|
||||
</Group>
|
||||
<Stack align='center' p={16}>
|
||||
<WeatherIcon size={'xl'} code={selectedDay.weatherCode} />
|
||||
<Text fz={'1rem'} fw={600} mt={'-32px'}>
|
||||
{WeatherCodes[Number(selectedDay.weatherCode)]}
|
||||
</Text>
|
||||
<Group>
|
||||
<Stack
|
||||
gap={0}
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
backgroundColor: 'var(--mantine-color-background-0)',
|
||||
border: 'thin solid var(--mantine-color-primary-0)',
|
||||
zIndex: 1,
|
||||
paddingLeft: '2.25rem',
|
||||
paddingRight: '2.25rem',
|
||||
borderRadius: '100%',
|
||||
aspectRatio: 1,
|
||||
}}
|
||||
align='center'
|
||||
justify='center'
|
||||
>
|
||||
<Box m={0} p={0}>
|
||||
<WeatherFeaturePill
|
||||
leftSide={<Text>Feels like</Text>}
|
||||
rightSide={
|
||||
<Text>
|
||||
{selectedDay.apparentTemperatureMax?.toFixed(0) ??
|
||||
selectedDay.temperatureMax?.toFixed(0)}
|
||||
°<sup>F</sup>
|
||||
</Text>
|
||||
}
|
||||
highlight='right'
|
||||
/>
|
||||
</Box>
|
||||
<Group pos={'relative'}>
|
||||
<Text fz={isMobile ? '5rem' : '7rem'} fw={400} style={{ lineHeight: 1 }}>
|
||||
{selectedDay.temperatureMax?.toFixed(0)}
|
||||
<sup style={{ fontSize: '3rem' }}>°F</sup>
|
||||
</Text>
|
||||
|
||||
<Text style={{ lineHeight: 1 }} pos={'absolute'} bottom={20} right={0}>
|
||||
/ {selectedDay.temperatureMin?.toFixed(0)}°<sup>F</sup>
|
||||
</Text>
|
||||
<Box
|
||||
style={{
|
||||
position: 'absolute',
|
||||
backgroundColor:
|
||||
'color-mix(in srgb, var(--mantine-color-accent-0), transparent 80%)',
|
||||
height: '250%',
|
||||
width: '80%',
|
||||
bottom: -96,
|
||||
right: -60,
|
||||
transform: 'skewX(-25deg)',
|
||||
zIndex: -1,
|
||||
borderRadius: '2px',
|
||||
backdropFilter: 'brightness(0.5)',
|
||||
lineHeight: 1,
|
||||
}}
|
||||
/>
|
||||
</Group>
|
||||
<Group
|
||||
justify={
|
||||
WeatherCodes[Number(selectedDay.weatherCode)].length > 25
|
||||
? 'flex-start'
|
||||
: 'center'
|
||||
}
|
||||
style={{
|
||||
width: '100%',
|
||||
maxWidth: '180px',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
boxSizing: 'border-box',
|
||||
position: 'relative',
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
className={
|
||||
WeatherCodes[Number(selectedDay.weatherCode)].length > 25
|
||||
? textClasses.autoScrollText
|
||||
: undefined
|
||||
}
|
||||
classNames={textClasses}
|
||||
style={{ lineHeight: 1 }}
|
||||
>
|
||||
{selectedDay.temperature_2m?.toFixed(0) === '69'
|
||||
? 'Nice'
|
||||
: WeatherCodes[Number(selectedDay.weatherCode)]}
|
||||
</Text>
|
||||
</Group>
|
||||
</Stack>
|
||||
<Stack>
|
||||
<WeatherIcon size={'xl'} code={selectedDay.weatherCode} />
|
||||
</Stack>
|
||||
</Group>
|
||||
|
||||
<Group>
|
||||
<Group justify='space-between'>
|
||||
<Stack gap={4}>
|
||||
@@ -173,76 +269,27 @@ export default function ExtendedForecastDetails({
|
||||
</Stack>
|
||||
</Group>
|
||||
</Group>
|
||||
<Group w={'100%'} gap={4} justify='space-between'>
|
||||
<Box w={'48%'}>
|
||||
<WeatherFeaturePill
|
||||
leftSide={
|
||||
<Group gap={2}>
|
||||
<FaArrowUp size={16} />
|
||||
<Text>High Temp</Text>
|
||||
</Group>
|
||||
}
|
||||
rightSide={
|
||||
<Text>
|
||||
{selectedDay.temperatureMax.toFixed(0)}°<sup>F</sup>
|
||||
</Text>
|
||||
}
|
||||
highlight='right'
|
||||
/>
|
||||
</Box>
|
||||
<Box w={'48%'}>
|
||||
<WeatherFeaturePill
|
||||
leftSide={
|
||||
<Group gap={2}>
|
||||
<FaArrowDown size={16} />
|
||||
<Text>Low Temp</Text>
|
||||
</Group>
|
||||
}
|
||||
rightSide={
|
||||
<Text>
|
||||
{selectedDay.temperatureMin.toFixed(0)}°<sup>F</sup>
|
||||
</Text>
|
||||
}
|
||||
highlight='right'
|
||||
/>
|
||||
</Box>
|
||||
</Group>
|
||||
<Group w={'100%'} gap={4} justify='space-between'>
|
||||
<Box w={'48%'}>
|
||||
<WeatherFeaturePill
|
||||
leftSide={
|
||||
<Group gap={2}>
|
||||
<FaArrowUp size={16} />
|
||||
<Text>Feels Like High</Text>
|
||||
</Group>
|
||||
}
|
||||
rightSide={
|
||||
<Text>
|
||||
{selectedDay.apparentTemperatureMax.toFixed(0)}°<sup>F</sup>
|
||||
</Text>
|
||||
}
|
||||
highlight='right'
|
||||
/>
|
||||
</Box>
|
||||
<Box w={'48%'}>
|
||||
<WeatherFeaturePill
|
||||
leftSide={
|
||||
<Group gap={2}>
|
||||
<FaArrowDown size={16} />
|
||||
<Text>Feels Like Temp</Text>
|
||||
</Group>
|
||||
}
|
||||
rightSide={
|
||||
<Text>
|
||||
{selectedDay.apparentTemperatureMin.toFixed(0)}°<sup>F</sup>
|
||||
</Text>
|
||||
}
|
||||
highlight='right'
|
||||
/>
|
||||
</Box>
|
||||
</Group>
|
||||
<Group w={'100%'} gap={4} justify='space-between'>
|
||||
<Box w={'48%'}>
|
||||
<Group justify='space-between'>
|
||||
<Stack align='center' justify='center' gap={0}>
|
||||
<Box
|
||||
style={{
|
||||
border: '2px solid var(--mantine-color-primary-0)',
|
||||
borderRadius: '100%',
|
||||
aspectRatio: 1,
|
||||
width: 'fit-content',
|
||||
padding: '.75rem',
|
||||
display: 'flex',
|
||||
backgroundColor: 'var(--mantine-color-background-0)',
|
||||
}}
|
||||
>
|
||||
<FaDroplet
|
||||
style={{
|
||||
color: 'var(--mantine-color-accent-0)',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Stack>
|
||||
<Stack gap={4}>
|
||||
<WeatherFeaturePill
|
||||
leftSide={
|
||||
<Group gap={2}>
|
||||
@@ -253,8 +300,6 @@ export default function ExtendedForecastDetails({
|
||||
rightSide={<Text>{selectedDay.precipitationProbability}%</Text>}
|
||||
highlight='right'
|
||||
/>
|
||||
</Box>
|
||||
<Box w={'48%'}>
|
||||
<WeatherFeaturePill
|
||||
leftSide={
|
||||
<Group gap={2}>
|
||||
@@ -265,8 +310,9 @@ export default function ExtendedForecastDetails({
|
||||
rightSide={<Text>{selectedDay.precipitationSum.toFixed(2)} in.</Text>}
|
||||
highlight='right'
|
||||
/>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Group>
|
||||
<WeatherGraphs hourly={selectedHourly} formatted />
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -13,34 +13,42 @@ import {
|
||||
YAxis,
|
||||
} from 'recharts';
|
||||
import { selectClasses } from 'styles';
|
||||
import type { Hourly } from 'types';
|
||||
import WeatherTooltip from './WeatherTooltip';
|
||||
|
||||
export default function WeatherGraphs({ hourly }: { hourly: Hourly | undefined }) {
|
||||
export default function WeatherGraphs({
|
||||
hourly,
|
||||
formatted,
|
||||
}: {
|
||||
hourly: any;
|
||||
formatted?: boolean;
|
||||
}) {
|
||||
const colorPrecipitation = 'colorPrecipitation';
|
||||
const colorHumidity = 'colorHumidity';
|
||||
const [timeFrame, setTimeFrame] = useState(24);
|
||||
const later = new Date();
|
||||
const now = new Date();
|
||||
|
||||
later.setTime(now.getTime() + timeFrame * 60 * 60 * 1000);
|
||||
const hourlyForecast = hourly?.time
|
||||
?.map((_: any, index: number) => {
|
||||
return {
|
||||
dewpoint: hourly.dew_point_2m?.[index].toFixed(0),
|
||||
isDaytime: hourly.is_day?.[index],
|
||||
name: hourly.time[index].toLocaleString('en-us'),
|
||||
startTime: hourly.time[index],
|
||||
endTime: hourly.time[index + 1],
|
||||
probabilityOfPrecipitation: hourly.precipitation_probability?.[index],
|
||||
temperature: hourly.temperature_2m?.[index].toFixed(0),
|
||||
apparentTemperature: hourly.apparent_temperature?.[index].toFixed(0),
|
||||
relativeHumidity: hourly.relative_humidity_2m?.[index].toFixed(0),
|
||||
};
|
||||
})
|
||||
.filter((hour: any) => hour.startTime > now && hour.startTime < later);
|
||||
const hourlyForecast = formatted
|
||||
? hourly
|
||||
: hourly?.time
|
||||
?.map((_: any, index: number) => {
|
||||
return {
|
||||
dewpoint: hourly.dew_point_2m?.[index].toFixed(0),
|
||||
isDaytime: hourly.is_day?.[index],
|
||||
name: hourly.time[index].toLocaleString('en-us'),
|
||||
startTime: hourly.time[index],
|
||||
endTime: hourly.time[index + 1],
|
||||
probabilityOfPrecipitation: hourly.precipitation_probability?.[index],
|
||||
temperature: hourly.temperature_2m?.[index].toFixed(0),
|
||||
apparentTemperature: hourly.apparent_temperature?.[index].toFixed(0),
|
||||
relativeHumidity: hourly.relative_humidity_2m?.[index].toFixed(0),
|
||||
};
|
||||
})
|
||||
.filter((hour: any) => hour.startTime > now && hour.startTime < later);
|
||||
|
||||
return (
|
||||
<Stack
|
||||
w={'100%'}
|
||||
style={{
|
||||
background: 'var(--mantine-color-search-0)',
|
||||
padding: '.5rem',
|
||||
@@ -49,28 +57,30 @@ export default function WeatherGraphs({ hourly }: { hourly: Hourly | undefined }
|
||||
marginTop: '.5rem',
|
||||
}}
|
||||
>
|
||||
<Group m={0} p={0} mt={'-1.5rem'}>
|
||||
<Select
|
||||
classNames={{
|
||||
input: selectClasses.menuSelectInput,
|
||||
label: selectClasses.menuSelectLabel,
|
||||
options: selectClasses.menuSelectOptions,
|
||||
option: selectClasses.menuSelectOption,
|
||||
dropdown: selectClasses.dropdown,
|
||||
}}
|
||||
className={selectClasses.menuSelect}
|
||||
defaultValue={24}
|
||||
value={timeFrame}
|
||||
data={[
|
||||
{ value: 12, label: '12 hours' },
|
||||
{ value: 24, label: '24 hours' },
|
||||
{ value: 48, label: '2 days' },
|
||||
{ value: 72, label: '3 days' },
|
||||
{ value: 168, label: '7 days' },
|
||||
]}
|
||||
onChange={(value: any) => setTimeFrame(value)}
|
||||
/>
|
||||
</Group>
|
||||
{!formatted && (
|
||||
<Group m={0} p={0} mt={'-1.5rem'}>
|
||||
<Select
|
||||
classNames={{
|
||||
input: selectClasses.menuSelectInput,
|
||||
label: selectClasses.menuSelectLabel,
|
||||
options: selectClasses.menuSelectOptions,
|
||||
option: selectClasses.menuSelectOption,
|
||||
dropdown: selectClasses.dropdown,
|
||||
}}
|
||||
className={selectClasses.menuSelect}
|
||||
defaultValue={24}
|
||||
value={timeFrame}
|
||||
data={[
|
||||
{ value: 12, label: '12 hours' },
|
||||
{ value: 24, label: '24 hours' },
|
||||
{ value: 48, label: '2 days' },
|
||||
{ value: 72, label: '3 days' },
|
||||
{ value: 168, label: '7 days' },
|
||||
]}
|
||||
onChange={(value: any) => setTimeFrame(value)}
|
||||
/>
|
||||
</Group>
|
||||
)}
|
||||
<ResponsiveContainer width={'100%'} height={150}>
|
||||
<ComposedChart data={hourlyForecast}>
|
||||
<XAxis
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Group, Modal, Overlay, Stack, Text } from '@mantine/core';
|
||||
import { useCommonHooks } from 'hooks';
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { modalClasses } from 'styles';
|
||||
import type { MeteoWeather } from 'types';
|
||||
import CurrentWeather from './CurrentWeather';
|
||||
@@ -21,6 +21,35 @@ export function WeatherModal({
|
||||
}) {
|
||||
const { isMobile, currentUser } = useCommonHooks();
|
||||
const [selectedDay, setSelectedDay] = useState<any>(undefined);
|
||||
const [selectedHourly, setSelectedHourly] = useState<any>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDay && current) {
|
||||
const later = new Date().setTime(selectedDay.time.getTime() + 24 * 60 * 60 * 1000);
|
||||
setSelectedHourly(
|
||||
current?.hourly.time
|
||||
?.map((_: any, index: number) => {
|
||||
return {
|
||||
dewpoint: current?.hourly.dew_point_2m?.[index].toFixed(0),
|
||||
isDaytime: current?.hourly.is_day?.[index],
|
||||
name: current?.hourly.time[index].toLocaleString('en-us'),
|
||||
startTime: current?.hourly.time[index],
|
||||
endTime: current?.hourly.time[index + 1],
|
||||
probabilityOfPrecipitation:
|
||||
current?.hourly.precipitation_probability?.[index],
|
||||
temperature: current?.hourly.temperature_2m?.[index].toFixed(0),
|
||||
apparentTemperature:
|
||||
current?.hourly.apparent_temperature?.[index].toFixed(0),
|
||||
relativeHumidity: current?.hourly.relative_humidity_2m?.[index].toFixed(0),
|
||||
};
|
||||
})
|
||||
.filter(
|
||||
(hour: any) => hour.startTime >= selectedDay.time && hour.startTime < later,
|
||||
),
|
||||
);
|
||||
}
|
||||
}, [selectedDay]);
|
||||
|
||||
return (
|
||||
<Modal.Root
|
||||
fullScreen={isMobile}
|
||||
@@ -80,6 +109,8 @@ export function WeatherModal({
|
||||
<ExtendedForecastDetails
|
||||
selectedDay={selectedDay}
|
||||
setSelectedDay={setSelectedDay}
|
||||
selectedHourly={selectedHourly}
|
||||
setSelectedHourly={setSelectedHourly}
|
||||
/>
|
||||
</Stack>
|
||||
</Overlay>
|
||||
|
||||
Reference in New Issue
Block a user