feat: Refactor session fetching logic

This commit is contained in:
2025-12-05 12:14:00 +02:00
parent f0adbd8093
commit a7426e9c46
2 changed files with 74 additions and 21 deletions

View File

@@ -62,9 +62,7 @@ const App: React.FC = () => {
sohChange={sohChange} sohChange={sohChange}
/> />
)} )}
{screen === "battery" && ( {screen === "battery" && <BottomNav onChange={setScreen} />}
<BottomNav current={screen} onChange={setScreen} />
)}
</div> </div>
); );
}; };
@@ -371,28 +369,17 @@ const BatteryScreen: React.FC<BatteryScreenProps> = ({
/* ---------- BOTTOM NAV ---------- */ /* ---------- BOTTOM NAV ---------- */
interface BottomNavProps { interface BottomNavProps {
current: Screen;
onChange: (screen: Screen) => void; onChange: (screen: Screen) => void;
} }
const BottomNav: React.FC<BottomNavProps> = ({ current, onChange }) => { const BottomNav: React.FC<BottomNavProps> = ({ onChange }) => {
return ( return (
<nav className="bottom-nav"> <nav className="bottom-nav">
<button <button className="nav-button" onClick={() => onChange("home")}>
className={
"nav-button " + (current === "home" ? "nav-button-active" : "")
}
onClick={() => onChange("home")}
>
<span className="nav-icon">🏠</span> <span className="nav-icon">🏠</span>
<span className="nav-label">Home</span> <span className="nav-label">Home</span>
</button> </button>
<button <button className="nav-button">
className={
"nav-button " + (current === "battery" ? "nav-button-active" : "")
}
onClick={() => onChange("battery")}
>
<span className="nav-icon">🚗</span> <span className="nav-icon">🚗</span>
<span className="nav-label">Car</span> <span className="nav-label">Car</span>
</button> </button>

View File

@@ -1,9 +1,59 @@
import type { SessionsResponse } from "./types"; import type { SessionsResponse, ChargingSession } from "./types";
import { generateMockSessions } from "./mocks/mockSessions"; import { generateMockSessions } from "./mocks/mockSessions";
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL ?? "https://example.com"; const API_BASE_URL = import.meta.env.VITE_API_BASE_URL ?? "https://example.com";
const USE_MOCK = import.meta.env.VITE_USE_MOCK_API === "true"; const USE_MOCK = import.meta.env.VITE_USE_MOCK_API === "true";
interface BackendSession {
id: string;
started_at: string;
ended_at: string | null;
soc_start: number | null;
soc_end: number | null;
energy_added_kwh: number | null;
avg_temp_c: number | null;
location_name: string | null;
soh: number | null;
health_grade: string | null;
}
function normalizeSoc(value: number | null | undefined): number | undefined {
if (value == null) return undefined;
if (value <= 1) {
return value * 100;
}
if (value > 100) {
return 100;
}
return value;
}
function normalizeSoh(value: number | null): number {
if (value == null) return 0;
if (value <= 1) {
return value * 100;
}
if (value > 100) {
return 100;
}
return value;
}
function mapBackendSession(raw: BackendSession): ChargingSession {
return {
id: raw.id,
startedAt: raw.started_at,
endedAt: raw.ended_at ?? raw.started_at,
sohStart: normalizeSoh(raw.soh),
sohEnd: normalizeSoh(raw.soh),
socStart: normalizeSoc(raw.soc_start),
socEnd: normalizeSoc(raw.soc_end),
energyAddedKWh: raw.energy_added_kwh ?? undefined,
avgTempC: raw.avg_temp_c ?? undefined,
locationName: raw.location_name ?? undefined,
};
}
export async function fetchSessions(days: number): Promise<SessionsResponse> { export async function fetchSessions(days: number): Promise<SessionsResponse> {
if (USE_MOCK) { if (USE_MOCK) {
await delay(400); await delay(400);
@@ -11,17 +61,33 @@ export async function fetchSessions(days: number): Promise<SessionsResponse> {
return { sessions }; return { sessions };
} }
const res = await fetch(`${API_BASE_URL}/api/sessions?days=${days}`, { const res = await fetch(`${API_BASE_URL}/charge_sessions`, {
headers: { headers: {
Accept: "application/json", Accept: "application/json",
}, },
}); });
if (!res.ok) { if (!res.ok) {
throw new Error(`HTTP ${res.status}`); throw new Error(`Error ${res.status}`);
} }
return (await res.json()) as SessionsResponse; const rawSessions = (await res.json()) as BackendSession[];
const mapped: ChargingSession[] = rawSessions.map(mapBackendSession);
const now = new Date();
const cutoff = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);
const filtered = mapped
.filter((s) => {
const end = new Date(s.endedAt);
return !isNaN(end.getTime()) && end >= cutoff;
})
.sort(
(a, b) => new Date(a.endedAt).getTime() - new Date(b.endedAt).getTime()
);
return { sessions: filtered };
} }
function delay(ms: number): Promise<void> { function delay(ms: number): Promise<void> {