diff --git a/backend/src/lib/cost-calc.js b/backend/src/lib/cost-calc.js index 67c5e2c..d6a4895 100644 --- a/backend/src/lib/cost-calc.js +++ b/backend/src/lib/cost-calc.js @@ -167,9 +167,19 @@ export async function getTrailingDailyRate(meterId, windowDays) { windowStart.setDate(windowStart.getDate() - windowDays) const windowStartStr = windowStart.toISOString().slice(0, 10) - const before = await readingOnOrBefore(meterId, windowStartStr) + let before = await readingOnOrBefore(meterId, windowStartStr) if (!before || before.reading_date >= latest.reading_date) { - return { daily_rate: null, latest } + // Nothing old enough to fill the window (readings are sparse) — fall back + // to the average between the last two readings so the estimate carries + // forward instead of dropping to zero until a new reading is added. + const { rows } = await pool.query( + `SELECT reading_value, reading_date FROM readings + WHERE meter_id = $1 AND reading_date < $2 + ORDER BY reading_date DESC, id DESC LIMIT 1`, + [meterId, latest.reading_date] + ) + before = rows[0] || null + if (!before) return { daily_rate: null, latest } } const days = daysBetween(before.reading_date, latest.reading_date) if (days <= 0) return { daily_rate: null, latest } diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 914608c..0a25c6e 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -7,6 +7,7 @@ import Layout from './components/Layout' import Meters from './pages/Meters' import MeterDetail from './pages/MeterDetail' import Tariffs from './pages/Tariffs' +import AddReading from './pages/AddReading' import Readings from './pages/Readings' import Reports from './pages/Reports' import Estimates from './pages/Estimates' @@ -20,7 +21,7 @@ export default function App() { - } /> + } /> } /> } /> } /> diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index 98faa80..bf3e259 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -1,12 +1,13 @@ import { useState, useEffect } from 'react' import { NavLink, useLocation } from 'react-router-dom' -import { Zap, Gauge, Receipt, BarChart3, TrendingUp, Settings, Menu, LogOut } from 'lucide-react' +import { Zap, PlusCircle, Gauge, Receipt, BarChart3, TrendingUp, Settings, Menu, LogOut } from 'lucide-react' import { useAuth } from './AuthGate' import { can } from '../types' const ICON_PROPS = { size: 16, strokeWidth: 1.75 } const NAV = [ + { to: '/', label: 'Add reading', icon: PlusCircle, cap: 'readings', end: true }, { to: '/meters', label: 'Meters', icon: Gauge, cap: 'meters' }, { to: '/readings', label: 'Readings', icon: Zap, cap: 'readings' }, { to: '/tariffs', label: 'Tariffs', icon: Receipt, cap: 'tariffs' }, @@ -37,7 +38,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {