Skip to content

Commit e73c15b

Browse files
committed
tidy up weather component
1 parent b70dc7f commit e73c15b

File tree

10 files changed

+183
-51
lines changed

10 files changed

+183
-51
lines changed

src/app/storage/defaultDashboard.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ export const defaultDashboard: DashboardLayout = {
6565
layout: {
6666
x: 1000,
6767
y: 1000,
68-
width: 400,
69-
height: 700,
68+
width: 150,
69+
height: 330,
7070
},
7171
},
7272
],

src/frontend/components/Weather/Weather.stories.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import { TelemetryDecorator } from '../../../../.storybook/telemetryDecorator';
44

55
export default {
66
component: Weather,
7+
decorators: [(Story) => (
8+
<div style={{ width: '150px' }}>
9+
<Story />
10+
</div>
11+
)],
712
} as Meta;
813

914
type Story = StoryObj<typeof Weather>;

src/frontend/components/Weather/Weather.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useAutoAnimate } from '@formkit/auto-animate/react';
22
import { useTrackTemperature } from './hooks/useTrackTemperature';
3-
import { useTrackWeather } from './hooks/useWeather';
3+
import { useTrackWeather } from './hooks/useTrackWeather';
44
import { WeatherTemp } from './WeatherTemp/WeatherTemp';
55
import { WeatherTrackWetness } from './WeatherTrackWetness/WeatherTrackWetness';
66
import { WindDirection } from './WindDirection/WindDirection';
@@ -19,17 +19,17 @@ export const Weather = () => {
1919

2020
return (
2121
<div
22-
className="h-full inline-flex flex-row bg-slate-800/25 rounded-sm"
22+
className="w-full inline-flex flex-row bg-slate-800/25 rounded-sm"
2323
ref={parent}
2424
>
25-
<div className="flex flex-col p-2 basis-full rounded-sm gap-2">
26-
<WeatherTemp title="Track Temp" value={trackTemp.trackTemp} />
27-
<WeatherTemp title="Air Temp" value={trackTemp.airTemp} />
25+
<div className="flex flex-col p-2 w-full rounded-sm gap-2">
26+
<WeatherTemp title="Track" value={trackTemp.trackTemp} />
27+
<WeatherTemp title="Air" value={trackTemp.airTemp} />
28+
<WindDirection speed={windSpeed} direction={windDirectionValue} />
2829
<WeatherTrackWetness
2930
trackWetnessPct={trackWetnessPct}
3031
trackState={weather.trackState}
3132
/>
32-
<WindDirection speed={windSpeed} direction={windDirectionValue} />
3333
</div>
3434
</div>
3535
);

src/frontend/components/Weather/WeatherTemp/WeatherTemp.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ export interface WeatherTempProps {
77

88
export const WeatherTemp = ({ title, value }: WeatherTempProps) => {
99
return (
10-
<div className="font-extrabold text-xl uppercase text-center bg-slate-800 p-2 rounded-sm items-center">
11-
<div className="flex flex-row gap-x-2 items-center">
10+
<div className="bg-slate-800/70 p-2 rounded-sm w-full">
11+
<div className="flex flex-row gap-x-2 items-center text-sm">
1212
<Thermometer />
1313
<span className="grow">{title}</span>
14+
<div className="text-center">{value}</div>
1415
</div>
15-
<div className="font-bold text-lg text-center">{value}</div>
1616
</div>
1717
);
1818
};

src/frontend/components/Weather/WeatherTrackWetness/WeatherTrackWetness.tsx

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,18 @@ export const WeatherTrackWetness = ({
1010
trackState,
1111
}: WeatherTrackWetnessProps) => {
1212
return (
13-
<div className="font-extrabold text-xl uppercase text-center bg-slate-800 p-2 rounded-sm items-center">
14-
TRACK WETNESS
15-
<div className="font-bold text-lg text-center">
16-
<div className="flex items-center flex-row gap-x-1">
17-
<Sun />
18-
<div className="w-full bg-gray-200 rounded-full h-2.5 dark:bg-gray-700 align-center">
19-
<div
20-
style={{ width: `${trackWetnessPct}%` }}
21-
className={`bg-blue-600 h-2.5 rounded-full`}
22-
></div>
23-
</div>
24-
<Drop />
13+
<div className="bg-slate-800/70 p-2 rounded-sm">
14+
<div className="flex items-center flex-row gap-x-1 mt-1">
15+
<Sun />
16+
<div className="w-full bg-gray-700 rounded-full h-2.5">
17+
<div
18+
style={{ width: `${trackWetnessPct}%` }}
19+
className="bg-blue-600 h-2.5 rounded-full"
20+
></div>
2521
</div>
26-
<div className="font-normal">{trackState ?? 'Unknown'}</div>
22+
<Drop />
2723
</div>
24+
<div className="text-center text-sm mt-1">{trackState ?? 'Unknown'}</div>
2825
</div>
2926
);
3027
};

src/frontend/components/Weather/WindDirection/WindDirection.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useAutoAnimate } from '@formkit/auto-animate/react';
2+
import { Wind } from '@phosphor-icons/react';
23

34
export interface WindDirectionProps {
45
speed: number;
@@ -8,23 +9,27 @@ export interface WindDirectionProps {
89
export const WindDirection = ({ speed, direction }: WindDirectionProps) => {
910
const [parent] = useAutoAnimate();
1011
return (
11-
<div className="font-extrabold text-xl uppercase text-center bg-slate-800 p-2 rounded-sm items-center">
12+
<div className="bg-slate-800/70 p-2 rounded-sm">
13+
<div className="flex flex-row gap-x-2 items-center text-sm mb-3">
14+
<Wind />
15+
<span className="grow">Wind</span>
16+
</div>
1217
<div
1318
id="wind"
1419
ref={parent}
15-
className="flex shrink h-full relative min-h-[200px] bg-slate-800"
20+
className="flex aspect-square relative w-full max-w-[120px] mx-auto"
1621
>
1722
<svg
1823
xmlns="http://www.w3.org/2000/svg"
19-
viewBox="-2 -2 64 64"
20-
className={`absolute stroke-current stroke-4 w-full h-full box-border fill-none origin-center transform-gpu`}
24+
viewBox="0 0 60 60"
25+
className="absolute stroke-current stroke-[3] w-full h-full box-border fill-none origin-center transform-gpu"
2126
style={{
2227
rotate: `calc(${direction} * 1rad + 0.5turn)`,
2328
}}
2429
>
25-
<path d="M50.0262 7.6624A29.9248 29.9248 90 0160 30c0 16.5685-13.4315 30-30 30S0 46.5685 0 30A29.9254 29.9254 90 0110.0078 7.632M21.5147 8.5 30 .0147 38.4853 8.5" />
30+
<path d="M48 8A28 28 90 0158 30c0 15.464-12.536 28-28 28S2 45.464 2 30A28 28 90 0112 8M22 9 30 1l8 8" />
2631
</svg>
27-
<div className="absolute w-full h-full flex justify-center items-center text-[50px]">
32+
<div className="absolute w-full h-full flex justify-center items-center text-[32px]">
2833
{speed.toFixed()}
2934
</div>
3035
</div>
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { renderHook } from '@testing-library/react';
2+
import { beforeEach, describe, expect, it, vi } from 'vitest';
3+
import { useTrackTemperature } from './useTrackTemperature';
4+
import type { TelemetryVar } from '@irdashies/types';
5+
import { useTelemetry } from '@irdashies/context';
6+
7+
vi.mock('@irdashies/context');
8+
9+
describe('useTrackTemperature', () => {
10+
beforeEach(() => {
11+
vi.resetAllMocks();
12+
});
13+
14+
const mockTelemetryVar = (value: number[], unit?: string): TelemetryVar<number[]> => ({
15+
value,
16+
name: 'Mock',
17+
description: 'Mock telemetry variable',
18+
unit: unit ?? '',
19+
countAsTime: false,
20+
length: value.length,
21+
varType: 0,
22+
});
23+
24+
it('should return the track temperature', () => {
25+
vi.mocked(useTelemetry).mockImplementation((key) => {
26+
const mockValues = {
27+
TrackTempCrew: mockTelemetryVar([25], 'C'),
28+
AirTemp: mockTelemetryVar([25], 'C'),
29+
};
30+
return mockValues[key as keyof typeof mockValues];
31+
});
32+
33+
const { result } = renderHook(() => useTrackTemperature());
34+
35+
expect(result.current.trackTemp).toBe('25°C');
36+
expect(result.current.airTemp).toBe('25°C');
37+
});
38+
it('should return an empty string if the telemetry variable is not found', () => {
39+
vi.mocked(useTelemetry).mockImplementation(() => {
40+
return mockTelemetryVar([], '');
41+
});
42+
43+
const { result } = renderHook(() => useTrackTemperature());
44+
45+
expect(result.current.trackTemp).toBe('0°C');
46+
expect(result.current.airTemp).toBe('0°C');
47+
});
48+
49+
it('should return temperature in Fahrenheit if the unit is Fahrenheit', () => {
50+
vi.mocked(useTelemetry).mockImplementation(() => {
51+
return mockTelemetryVar([77], 'F');
52+
});
53+
54+
const { result } = renderHook(() => useTrackTemperature());
55+
56+
expect(result.current.trackTemp).toBe('77°F');
57+
expect(result.current.airTemp).toBe('77°F');
58+
});
59+
});

src/frontend/components/Weather/hooks/useTrackTemperature.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ export const useTrackTemperature = () => {
88
const trackTemp = useMemo(() => {
99
const trackTemp = trackTempVal?.value[0] ?? 0;
1010
if (trackTemp === null || trackTemp === undefined) return '';
11-
return `${trackTemp.toFixed(0)}°${trackTempVal?.unit ?? 'C'}`;
11+
return `${trackTemp.toFixed(0)}°${trackTempVal?.unit || 'C'}`;
1212
}, [trackTempVal?.unit, trackTempVal?.value]);
1313

1414
const airTemp = useMemo(() => {
1515
const airTemp = airTempVal?.value[0] ?? 0;
1616
if (airTemp === null || airTemp === undefined) return '';
17-
return `${airTemp.toFixed(0)}°${airTempVal?.unit ?? 'C'}`;
17+
return `${airTemp.toFixed(0)}°${airTempVal?.unit || 'C'}`;
1818
}, [airTempVal?.unit, airTempVal?.value]);
1919

2020
return { trackTemp, airTemp };
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { useTelemetry } from '@irdashies/context';
2+
import { TelemetryVar } from '@irdashies/types';
3+
import { renderHook } from '@testing-library/react';
4+
import { describe, beforeEach, vi, it, expect } from 'vitest';
5+
import { useTrackWeather } from './useTrackWeather';
6+
7+
vi.mock('@irdashies/context');
8+
9+
describe('useTrackWeather', () => {
10+
beforeEach(() => {
11+
vi.resetAllMocks();
12+
});
13+
14+
const mockTelemetryVar = (value: number[]): TelemetryVar<number[]> => ({
15+
value,
16+
name: 'Mock',
17+
description: 'Mock telemetry variable',
18+
unit: '',
19+
countAsTime: false,
20+
length: value.length,
21+
varType: 0,
22+
});
23+
24+
it('should return track weather data from telemetry values', () => {
25+
vi.mocked(useTelemetry).mockImplementation((key) => {
26+
const mockValues = {
27+
TrackWetness: mockTelemetryVar([2]),
28+
YawNorth: mockTelemetryVar([45]),
29+
WindDir: mockTelemetryVar([270]),
30+
WindVel: mockTelemetryVar([8.3]),
31+
};
32+
return mockValues[key as keyof typeof mockValues];
33+
});
34+
35+
const { result } = renderHook(() => useTrackWeather());
36+
37+
expect(result.current).toEqual({
38+
trackState: 'Mostly Dry',
39+
trackMoisture: mockTelemetryVar([2]),
40+
windDirection: mockTelemetryVar([270]),
41+
windVelo: mockTelemetryVar([8.3]),
42+
windYaw: mockTelemetryVar([45]),
43+
});
44+
});
45+
46+
it('should handle undefined telemetry values', () => {
47+
const mockFn = vi.fn();
48+
mockFn.mockReturnValue(undefined);
49+
vi.mocked(useTelemetry).mockImplementation(mockFn);
50+
51+
const { result } = renderHook(() => useTrackWeather());
52+
53+
expect(result.current).toEqual({
54+
trackState: '',
55+
trackMoisture: undefined,
56+
windDirection: undefined,
57+
windVelo: undefined,
58+
windYaw: undefined,
59+
});
60+
});
61+
62+
it('should return correct track state for different wetness levels', () => {
63+
const testCases = [
64+
{ wetness: 0, expected: '' },
65+
{ wetness: 1, expected: 'Dry' },
66+
{ wetness: 2, expected: 'Mostly Dry' },
67+
{ wetness: 3, expected: 'Very Lightly Wet' },
68+
{ wetness: 4, expected: 'Lightly Wet' },
69+
{ wetness: 5, expected: 'Moderately Wet' },
70+
{ wetness: 6, expected: 'Very Wet' },
71+
{ wetness: 7, expected: 'Extremely Wet' },
72+
{ wetness: 8, expected: '' }, // Invalid wetness level
73+
];
74+
75+
testCases.forEach(({ wetness, expected }) => {
76+
vi.mocked(useTelemetry).mockImplementation((key) => {
77+
return key === 'TrackWetness' ? mockTelemetryVar([wetness]) : mockTelemetryVar([0]);
78+
});
79+
80+
const { result } = renderHook(() => useTrackWeather());
81+
expect(result.current.trackState).toBe(expected);
82+
});
83+
});
84+
});

src/frontend/components/Weather/hooks/useWeather.tsx renamed to src/frontend/components/Weather/hooks/useTrackWeather.tsx

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useTelemetry, useTelemetryValue } from '@irdashies/context';
1+
import { useTelemetry } from '@irdashies/context';
22
import { useMemo } from 'react';
33

44
const wetnessLevels: Record<number, string> = {
@@ -12,24 +12,6 @@ const wetnessLevels: Record<number, string> = {
1212
7: 'Extremely Wet',
1313
};
1414

15-
export const useWeather = () => {
16-
const humidity = useTelemetryValue('RelativeHumidity');
17-
const weatherType = useTelemetryValue('WeatherType');
18-
const trackAirTemp = useTelemetryValue('AirTemp');
19-
const trackSurfaceTemp = useTelemetryValue('PlayerTrackSurface');
20-
const windVelocity = useTelemetryValue('WindVel');
21-
const windDirection = useTelemetryValue('WindDir');
22-
23-
return {
24-
humidity,
25-
weatherType,
26-
trackAirTemp,
27-
trackSurfaceTemp,
28-
windVelocity,
29-
windDirection,
30-
};
31-
};
32-
3315
export const useTrackWeather = () => {
3416
const trackMoisture = useTelemetry('TrackWetness');
3517
const windYaw = useTelemetry('YawNorth');

0 commit comments

Comments
 (0)