Skip to content

Commit de453fd

Browse files
authored
Add settings to standings + ability to reset configs (#31)
1 parent 263c31f commit de453fd

File tree

16 files changed

+249
-40
lines changed

16 files changed

+249
-40
lines changed

.storybook/mockDashboardBridge.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ export const mockDashboardBridge: DashboardBridge = {
88
saveDashboard: () => {
99
// noop
1010
},
11+
resetDashboard: async () => {
12+
// For mock, just return the default dashboard
13+
return defaultDashboard;
14+
},
1115
dashboardUpdated: (callback) => {
1216
callback(defaultDashboard);
1317
return () => {

src/app/bridge/dashboard/dashboardBridge.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ipcMain } from 'electron';
22
import { onDashboardUpdated } from '../../storage/dashboardEvents';
3-
import { getDashboard, saveDashboard } from '../../storage/dashboards';
3+
import { getDashboard, saveDashboard, resetDashboard } from '../../storage/dashboards';
44
import { OverlayManager } from 'src/app/overlayManager';
55

66
export async function publishDashboardUpdates(overlayManager: OverlayManager) {
@@ -18,6 +18,10 @@ export async function publishDashboardUpdates(overlayManager: OverlayManager) {
1818
overlayManager.publishMessage('dashboardUpdated', dashboard);
1919
});
2020

21+
ipcMain.handle('resetDashboard', (_, resetEverything: boolean) => {
22+
return resetDashboard(resetEverything, 'default');
23+
});
24+
2125
ipcMain.handle('toggleLockOverlays', () => {
2226
return overlayManager.toggleLockOverlays();
2327
});

src/app/bridge/rendererExposeBridge.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ export function exposeBridge() {
4545
saveDashboard: (value: DashboardLayout) => {
4646
ipcRenderer.send('saveDashboard', value);
4747
},
48+
resetDashboard: (resetEverything: boolean) => {
49+
return ipcRenderer.invoke('resetDashboard', resetEverything);
50+
},
4851
toggleLockOverlays: () => {
4952
return ipcRenderer.invoke('toggleLockOverlays');
5053
},

src/app/storage/dashboards.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,34 @@ export const saveDashboard = (
115115
emitDashboardUpdated(mergedDashboard);
116116
}
117117
};
118+
119+
export const resetDashboard = (resetEverything = false, dashboardId = 'default') => {
120+
const dashboard = getDashboard(dashboardId);
121+
if (!dashboard) {
122+
throw new Error('Dashboard not found');
123+
}
124+
125+
if (resetEverything) {
126+
// Completely reset to default dashboard
127+
saveDashboard(dashboardId, defaultDashboard);
128+
return defaultDashboard;
129+
} else {
130+
// Reset only widget configurations while preserving positions and enabled states
131+
const resetDashboard: DashboardLayout = {
132+
...dashboard,
133+
widgets: dashboard.widgets.map((widget) => {
134+
const defaultWidget = defaultDashboard.widgets.find((w) => w.id === widget.id);
135+
return {
136+
...widget,
137+
config: defaultWidget?.config || widget.config,
138+
};
139+
}),
140+
generalSettings: {
141+
...defaultDashboard.generalSettings,
142+
},
143+
};
144+
145+
saveDashboard(dashboardId, resetDashboard);
146+
return resetDashboard;
147+
}
148+
};

src/app/storage/defaultDashboard.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ export const defaultDashboard: DashboardLayout = {
1111
width: 400,
1212
height: 600,
1313
},
14+
config: {
15+
iRatingChange: { enabled: true },
16+
badge: { enabled: true },
17+
delta: { enabled: true },
18+
lastTime: { enabled: true },
19+
fastestTime: { enabled: true },
20+
},
1421
},
1522
{
1623
id: 'input',

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

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useState } from 'react';
22
import { useDashboard } from '@irdashies/context';
33

44
export const AdvancedSettings = () => {
5-
const { currentDashboard, onDashboardUpdated } = useDashboard();
5+
const { currentDashboard, onDashboardUpdated, resetDashboard } = useDashboard();
66
const [dashboardInput, setDashboardInput] = useState<string | undefined>(
77
JSON.stringify(currentDashboard, undefined, 2)
88
);
@@ -29,13 +29,58 @@ export const AdvancedSettings = () => {
2929
}
3030
};
3131

32+
const handleResetConfigs = async () => {
33+
if (!confirm('Reset all widget configurations to defaults? This will preserve widget positions and enabled states.')) {
34+
return;
35+
}
36+
37+
try {
38+
const result = await resetDashboard(false);
39+
setDashboardInput(JSON.stringify(result, undefined, 2));
40+
} catch (e) {
41+
console.error('Failed to reset configurations:', e);
42+
alert('Failed to reset configurations');
43+
}
44+
};
45+
46+
const handleResetCompletely = async () => {
47+
if (!confirm('Reset everything to defaults? This will reset all widget positions, enabled states, and configurations.')) {
48+
return;
49+
}
50+
51+
try {
52+
const result = await resetDashboard(true);
53+
setDashboardInput(JSON.stringify(result, undefined, 2));
54+
} catch (e) {
55+
console.error('Failed to reset dashboard:', e);
56+
alert('Failed to reset dashboard');
57+
}
58+
};
59+
3260
return (
3361
<div className="flex flex-col h-full space-y-4">
3462
<div>
3563
<h2 className="text-xl mb-4">Advanced Settings</h2>
3664
<p className="text-slate-400 mb-4">Configure advanced system settings and preferences.</p>
3765
</div>
3866

67+
<div className="flex space-x-2">
68+
<button
69+
type="button"
70+
onClick={handleResetConfigs}
71+
className="flex-1 bg-amber-700 hover:bg-amber-600 rounded px-4 py-2 transition-colors cursor-pointer"
72+
>
73+
Reset Configurations
74+
</button>
75+
<button
76+
type="button"
77+
onClick={handleResetCompletely}
78+
className="flex-1 bg-red-700 hover:bg-red-600 rounded px-4 py-2 transition-colors cursor-pointer"
79+
>
80+
Reset Everything
81+
</button>
82+
</div>
83+
3984
<textarea
4085
className="flex-1 w-full bg-slate-800 p-4 font-mono text-sm rounded border border-slate-600 focus:border-slate-500 focus:outline-none"
4186
value={dashboardInput}

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

Lines changed: 88 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,40 @@ import { useState } from 'react';
22
import { BaseSettingsSection } from '../components/BaseSettingsSection';
33
import { StandingsWidgetSettings } from '../types';
44
import { useDashboard } from '@irdashies/context';
5+
import { ToggleSwitch } from '../components/ToggleSwitch';
6+
7+
const SETTING_ID = 'standings';
8+
9+
const defaultConfig: StandingsWidgetSettings['config'] = {
10+
iRatingChange: { enabled: true },
11+
badge: { enabled: true },
12+
delta: { enabled: true },
13+
lastTime: { enabled: true },
14+
fastestTime: { enabled: true },
15+
};
16+
17+
// Migration function to handle missing properties in the new config format
18+
const migrateConfig = (savedConfig: unknown): StandingsWidgetSettings['config'] => {
19+
if (!savedConfig || typeof savedConfig !== 'object') return defaultConfig;
20+
21+
const config = savedConfig as Record<string, unknown>;
22+
23+
// Handle new format with missing properties
24+
return {
25+
iRatingChange: { enabled: (config.iRatingChange as { enabled?: boolean })?.enabled ?? true },
26+
badge: { enabled: (config.badge as { enabled?: boolean })?.enabled ?? true },
27+
delta: { enabled: (config.delta as { enabled?: boolean })?.enabled ?? true },
28+
lastTime: { enabled: (config.lastTime as { enabled?: boolean })?.enabled ?? true },
29+
fastestTime: { enabled: (config.fastestTime as { enabled?: boolean })?.enabled ?? true },
30+
};
31+
};
532

633
export const StandingsSettings = () => {
734
const { currentDashboard } = useDashboard();
35+
const savedSettings = currentDashboard?.widgets.find(w => w.id === SETTING_ID) as StandingsWidgetSettings | undefined;
836
const [settings, setSettings] = useState<StandingsWidgetSettings>({
9-
enabled: currentDashboard?.widgets.find(w => w.id === 'standings')?.enabled ?? false,
10-
config: currentDashboard?.widgets.find(w => w.id === 'standings')?.config ?? {},
37+
enabled: savedSettings?.enabled ?? false,
38+
config: migrateConfig(savedSettings?.config),
1139
});
1240

1341
if (!currentDashboard) {
@@ -20,12 +48,65 @@ export const StandingsSettings = () => {
2048
description="Configure how the standings widget appears and behaves."
2149
settings={settings}
2250
onSettingsChange={setSettings}
23-
widgetId="standings"
51+
widgetId={SETTING_ID}
2452
>
25-
{/* Add specific settings controls here */}
26-
<div className="text-slate-300">
27-
Additional settings will appear here
28-
</div>
53+
{(handleConfigChange) => (
54+
<div className="space-y-8">
55+
{/* Display Settings */}
56+
<div className="space-y-4">
57+
<div className="flex items-center justify-between">
58+
<h3 className="text-lg font-medium text-slate-200">Display Settings</h3>
59+
</div>
60+
<div className="space-y-3 pl-4">
61+
<div className="flex items-center justify-between">
62+
<span className="text-sm text-slate-300">Show iRating Changes</span>
63+
<ToggleSwitch
64+
enabled={settings.config.iRatingChange.enabled}
65+
onToggle={(enabled) =>
66+
handleConfigChange({ iRatingChange: { enabled } })
67+
}
68+
/>
69+
</div>
70+
<div className="flex items-center justify-between">
71+
<span className="text-sm text-slate-300">Show Driver Badge</span>
72+
<ToggleSwitch
73+
enabled={settings.config.badge.enabled}
74+
onToggle={(enabled) =>
75+
handleConfigChange({ badge: { enabled } })
76+
}
77+
/>
78+
</div>
79+
<div className="flex items-center justify-between">
80+
<span className="text-sm text-slate-300">Show Delta</span>
81+
<ToggleSwitch
82+
enabled={settings.config.delta.enabled}
83+
onToggle={(enabled) =>
84+
handleConfigChange({ delta: { enabled } })
85+
}
86+
/>
87+
</div>
88+
<div className="flex items-center justify-between">
89+
<span className="text-sm text-slate-300">Show Last Time</span>
90+
<ToggleSwitch
91+
enabled={settings.config.lastTime.enabled}
92+
onToggle={(enabled) =>
93+
handleConfigChange({ lastTime: { enabled } })
94+
}
95+
/>
96+
</div>
97+
<div className="flex items-center justify-between">
98+
<span className="text-sm text-slate-300">Show Fastest Time</span>
99+
<ToggleSwitch
100+
enabled={settings.config.fastestTime.enabled}
101+
onToggle={(enabled) =>
102+
handleConfigChange({ fastestTime: { enabled } })
103+
}
104+
/>
105+
</div>
106+
</div>
107+
</div>
108+
</div>
109+
)}
29110
</BaseSettingsSection>
30111
);
31112
};

src/frontend/components/Settings/types.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ export interface BaseWidgetSettings<T = Record<string, unknown>> {
77
}
88

99
export interface StandingsWidgetSettings extends BaseWidgetSettings {
10-
// Add specific standings settings here
10+
config: {
11+
iRatingChange: { enabled: boolean };
12+
badge: { enabled: boolean };
13+
delta: { enabled: boolean };
14+
lastTime: { enabled: boolean };
15+
fastestTime: { enabled: boolean };
16+
};
1117
}
1218

1319
export interface RelativeWidgetSettings extends BaseWidgetSettings {

src/frontend/components/Standings/Standings.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import { DriverRatingBadge } from './components/DriverRatingBadge/DriverRatingBa
66
import { RatingChange } from './components/RatingChange/RatingChange';
77
import { SessionBar } from './components/SessionBar/SessionBar';
88
import { SessionFooter } from './components/SessionFooter/SessionFooter';
9-
import { useCarClassStats, useDriverStandings } from './hooks';
9+
import { useCarClassStats, useDriverStandings, useStandingsSettings } from './hooks';
1010

1111
export const Standings = () => {
1212
const [parent] = useAutoAnimate();
1313
const standings = useDriverStandings({ buffer: 3 });
1414
const classStats = useCarClassStats();
15+
const settings = useStandingsSettings();
1516

1617
return (
1718
<div className="w-full h-full">
@@ -36,20 +37,20 @@ export const Standings = () => {
3637
name={result.driver?.name || ''}
3738
isPlayer={result.isPlayer}
3839
hasFastestTime={result.hasFastestTime}
39-
delta={result.delta}
40+
delta={settings?.delta?.enabled ? result.delta : undefined}
4041
position={result.classPosition}
41-
iratingChange={<RatingChange value={result.iratingChange} />}
42-
lastTime={result.lastTime}
43-
fastestTime={result.fastestTime}
42+
iratingChange={settings?.iRatingChange?.enabled ? <RatingChange value={result.iratingChange} /> : undefined}
43+
lastTime={settings?.lastTime?.enabled ? result.lastTime : undefined}
44+
fastestTime={settings?.fastestTime?.enabled ? result.fastestTime : undefined}
4445
onPitRoad={result.onPitRoad}
4546
onTrack={result.onTrack}
4647
radioActive={result.radioActive}
47-
badge={
48+
badge={settings?.badge?.enabled ? (
4849
<DriverRatingBadge
4950
license={result.driver?.license}
5051
rating={result.driver?.rating}
5152
/>
52-
}
53+
) : undefined}
5354
/>
5455
))}
5556
</Fragment>

0 commit comments

Comments
 (0)