Skip to content

Commit 166809b

Browse files
authored
feat: add settings for standings for displaying number of drivers (#47)
1 parent aa88356 commit 166809b

File tree

6 files changed

+297
-38
lines changed

6 files changed

+297
-38
lines changed

src/frontend/components/Settings/sections/StandingsSettings.tsx

Lines changed: 141 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,55 @@ const defaultConfig: StandingsWidgetSettings['config'] = {
1313
lastTime: { enabled: true },
1414
fastestTime: { enabled: true },
1515
background: { opacity: 0 },
16+
driverStandings: {
17+
buffer: 3,
18+
numNonClassDrivers: 3,
19+
minPlayerClassDrivers: 10,
20+
numTopDrivers: 3,
21+
},
1622
};
1723

1824
// Migration function to handle missing properties in the new config format
19-
const migrateConfig = (savedConfig: unknown): StandingsWidgetSettings['config'] => {
25+
const migrateConfig = (
26+
savedConfig: unknown
27+
): StandingsWidgetSettings['config'] => {
2028
if (!savedConfig || typeof savedConfig !== 'object') return defaultConfig;
2129

2230
const config = savedConfig as Record<string, unknown>;
2331

2432
// Handle new format with missing properties
2533
return {
26-
iRatingChange: { enabled: (config.iRatingChange as { enabled?: boolean })?.enabled ?? true },
34+
iRatingChange: {
35+
enabled:
36+
(config.iRatingChange as { enabled?: boolean })?.enabled ?? true,
37+
},
2738
badge: { enabled: (config.badge as { enabled?: boolean })?.enabled ?? true },
2839
delta: { enabled: (config.delta as { enabled?: boolean })?.enabled ?? true },
29-
lastTime: { enabled: (config.lastTime as { enabled?: boolean })?.enabled ?? true },
30-
fastestTime: { enabled: (config.fastestTime as { enabled?: boolean })?.enabled ?? true },
31-
background: { opacity: (config.background as { opacity?: number })?.opacity ?? 0 },
40+
lastTime: {
41+
enabled: (config.lastTime as { enabled?: boolean })?.enabled ?? true,
42+
},
43+
fastestTime: {
44+
enabled: (config.fastestTime as { enabled?: boolean })?.enabled ?? true,
45+
},
46+
background: {
47+
opacity: (config.background as { opacity?: number })?.opacity ?? 0,
48+
},
49+
driverStandings: {
50+
buffer:
51+
(config.driverStandings as { buffer?: number })?.buffer ??
52+
defaultConfig.driverStandings.buffer,
53+
numNonClassDrivers:
54+
(config.driverStandings as { numNonClassDrivers?: number })
55+
?.numNonClassDrivers ??
56+
defaultConfig.driverStandings.numNonClassDrivers,
57+
minPlayerClassDrivers:
58+
(config.driverStandings as { minPlayerClassDrivers?: number })
59+
?.minPlayerClassDrivers ??
60+
defaultConfig.driverStandings.minPlayerClassDrivers,
61+
numTopDrivers:
62+
(config.driverStandings as { numTopDrivers?: number })?.numTopDrivers ??
63+
defaultConfig.driverStandings.numTopDrivers,
64+
},
3265
};
3366
};
3467

@@ -105,16 +138,117 @@ export const StandingsSettings = () => {
105138
}
106139
/>
107140
</div>
141+
</div>
142+
</div>
143+
{/* Driver Standings Settings */}
144+
<div className="space-y-4">
145+
<div className="flex items-center justify-between">
146+
<h3 className="text-lg font-medium text-slate-200">
147+
Driver Standings
148+
</h3>
149+
</div>
150+
<div className="space-y-3 pl-4">
151+
<div className="flex items-center justify-between">
152+
<span className="text-sm text-slate-300">
153+
Drivers to show around player
154+
</span>
155+
<input
156+
type="number"
157+
min={0}
158+
value={settings.config.driverStandings.buffer}
159+
onChange={(e) =>
160+
handleConfigChange({
161+
driverStandings: {
162+
...settings.config.driverStandings,
163+
buffer: parseInt(e.target.value),
164+
},
165+
})
166+
}
167+
className="w-20 bg-slate-700 text-white rounded-md px-2 py-1"
168+
/>
169+
</div>
170+
<div className="flex items-center justify-between">
171+
<span className="text-sm text-slate-300">
172+
Drivers to show in other classes
173+
</span>
174+
<input
175+
type="number"
176+
min={0}
177+
value={settings.config.driverStandings.numNonClassDrivers}
178+
onChange={(e) =>
179+
handleConfigChange({
180+
driverStandings: {
181+
...settings.config.driverStandings,
182+
numNonClassDrivers: parseInt(e.target.value),
183+
},
184+
})
185+
}
186+
className="w-20 bg-slate-700 text-white rounded-md px-2 py-1"
187+
/>
188+
</div>
189+
<div className="flex items-center justify-between">
190+
<span className="text-sm text-slate-300">
191+
Minimum drivers in player&apos;s class
192+
</span>
193+
<input
194+
type="number"
195+
min={0}
196+
value={settings.config.driverStandings.minPlayerClassDrivers}
197+
onChange={(e) =>
198+
handleConfigChange({
199+
driverStandings: {
200+
...settings.config.driverStandings,
201+
minPlayerClassDrivers: parseInt(e.target.value),
202+
},
203+
})
204+
}
205+
className="w-20 bg-slate-700 text-white rounded-md px-2 py-1"
206+
/>
207+
</div>
208+
<div className="flex items-center justify-between">
209+
<span className="text-sm text-slate-300">
210+
Top drivers to always show in player&apos;s class
211+
</span>
212+
<input
213+
type="number"
214+
min={0}
215+
value={settings.config.driverStandings.numTopDrivers}
216+
onChange={(e) =>
217+
handleConfigChange({
218+
driverStandings: {
219+
...settings.config.driverStandings,
220+
numTopDrivers: parseInt(e.target.value),
221+
},
222+
})
223+
}
224+
className="w-20 bg-slate-700 text-white rounded-md px-2 py-1"
225+
/>
226+
</div>
227+
</div>
228+
</div>
229+
230+
{/* Background Settings */}
231+
<div className="space-y-4">
232+
<div className="flex items-center justify-between">
233+
<h3 className="text-lg font-medium text-slate-200">
234+
Background
235+
</h3>
236+
</div>
237+
<div className="space-y-3 pl-4">
108238
<div className="flex items-center justify-between">
109-
<span className="text-sm text-slate-300">Background Opacity</span>
239+
<span className="text-sm text-slate-300">
240+
Background Opacity
241+
</span>
110242
<div className="flex items-center gap-2">
111243
<input
112244
type="range"
113245
min="0"
114246
max="100"
115247
value={settings.config.background.opacity}
116248
onChange={(e) =>
117-
handleConfigChange({ background: { opacity: parseInt(e.target.value) } })
249+
handleConfigChange({
250+
background: { opacity: parseInt(e.target.value) },
251+
})
118252
}
119253
className="w-20 h-2 bg-slate-600 rounded-lg appearance-none cursor-pointer"
120254
/>

src/frontend/components/Settings/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ export interface StandingsWidgetSettings extends BaseWidgetSettings {
1414
lastTime: { enabled: boolean };
1515
fastestTime: { enabled: boolean };
1616
background: { opacity: number };
17+
driverStandings: {
18+
buffer: number;
19+
numNonClassDrivers: number;
20+
minPlayerClassDrivers: number;
21+
numTopDrivers: number;
22+
};
1723
};
1824
}
1925

src/frontend/components/Standings/Standings.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ import {
1414

1515
export const Standings = () => {
1616
const [parent] = useAutoAnimate();
17-
const standings = useDriverStandings({ buffer: 3 });
18-
const classStats = useCarClassStats();
1917
const settings = useStandingsSettings();
18+
const standings = useDriverStandings(settings?.driverStandings);
19+
const classStats = useCarClassStats();
2020
return (
2121
<div
2222
className={`w-full bg-slate-800/[var(--bg-opacity)] rounded-sm p-2 text-white overflow-hidden`}

src/frontend/components/Standings/createStandings.spec.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,8 @@ describe('createStandings', () => {
315315

316316
const filteredDrivers = sliceRelevantDrivers(results, 'GT3');
317317

318+
expect(filteredDrivers[0][1]).toHaveLength(10);
319+
318320
expect(filteredDrivers).toEqual([
319321
[
320322
'GT3',
@@ -326,10 +328,88 @@ describe('createStandings', () => {
326328
{ name: '5. David' },
327329
{ name: '6. Sebastian' },
328330
{ name: '7. Nico' },
331+
{ name: '8. Eve' },
332+
{ name: '9. Frank' },
333+
{ name: '10. Max' },
329334
],
330335
],
331336
]);
332337
});
338+
339+
it('should return at least 10 drivers if available', () => {
340+
const results: [string, DummyStanding[]][] = [
341+
[
342+
'GT3',
343+
[
344+
{ name: '1. Bob' },
345+
{ name: '2. Alice' },
346+
{ name: '3. Charlie' },
347+
{ name: '4. David' },
348+
{ name: '5. Eve' },
349+
{ name: '6. Frank' },
350+
{ name: '7. Player', isPlayer: true },
351+
{ name: '8. Hannah' },
352+
{ name: '9. Irene' },
353+
{ name: '10. Jack' },
354+
{ name: '11. Kevin' },
355+
],
356+
],
357+
];
358+
const filteredDrivers = sliceRelevantDrivers(results, 'GT3');
359+
expect(filteredDrivers[0][1].length).toBe(10);
360+
});
361+
362+
it('should allow minPlayerClassDrivers to be configured', () => {
363+
const results: [string, DummyStanding[]][] = [
364+
[
365+
'GT3',
366+
[
367+
{ name: '1. Bob' },
368+
{ name: '2. Alice' },
369+
{ name: '3. Charlie' },
370+
{ name: '4. David' },
371+
{ name: '5. Eve' },
372+
{ name: '6. Frank' },
373+
{ name: '7. Player', isPlayer: true },
374+
{ name: '8. Hannah' },
375+
{ name: '9. Irene' },
376+
{ name: '10. Jack' },
377+
{ name: '11. Kevin' },
378+
],
379+
],
380+
];
381+
const filteredDrivers = sliceRelevantDrivers(results, 'GT3', {
382+
minPlayerClassDrivers: 5,
383+
});
384+
expect(filteredDrivers[0][1].length).toBe(10);
385+
});
386+
387+
it('should allow numTopDrivers to be configured', () => {
388+
const results: [string, DummyStanding[]][] = [
389+
[
390+
'GT3',
391+
[
392+
{ name: '1. Bob' },
393+
{ name: '2. Alice' },
394+
{ name: '3. Charlie' },
395+
{ name: '4. David' },
396+
{ name: '5. Eve' },
397+
{ name: '6. Frank' },
398+
{ name: '7. Player', isPlayer: true },
399+
{ name: '8. Hannah' },
400+
{ name: '9. Irene' },
401+
{ name: '10. Jack' },
402+
{ name: '11. Kevin' },
403+
],
404+
],
405+
];
406+
const filteredDrivers = sliceRelevantDrivers(results, 'GT3', {
407+
numTopDrivers: 1,
408+
});
409+
expect(filteredDrivers[0][1].length).toBe(9);
410+
expect(filteredDrivers[0][1][0].name).toBe('1. Bob');
411+
expect(filteredDrivers[0][1][1].name).toBe('4. David');
412+
});
333413
});
334414
});
335415

@@ -347,6 +427,8 @@ function createStandings(
347427
options?: {
348428
buffer?: number;
349429
numNonClassDrivers?: number;
430+
minPlayerClassDrivers?: number;
431+
numTopDrivers?: number;
350432
}
351433
) {
352434
const standings = createDriverStandings(

0 commit comments

Comments
 (0)