Skip to main content

True Cost of Water

A dashboard that breaks the cost of water into Raw Water, Energy, and Chemicals & Consumables, with KPI cards, a cost trend line, a cost-distribution donut, and a per-category detail table.

Demo-only prototype — every number is fabricated

True Cost runs entirely on static dummy data (dummyData/trueCostDummyData.js), makes no API calls, and has no dataSource, controller, or store layer. Its route exists only in the demo app. Every figure on the page — amounts, percentages, totals — is illustrative. Never present this as a live or production feature.

What True Cost does NOT do
  • It does not read live data. There is no API call, and no dataSource, controller, or store layer to add one to.
  • It does not exist outside the demo build — neither the route nor the sidebar item.
  • TRUE_COST is not a defined permission. The gate is isDemoOption.
  • It does not compute anything. Amounts and percentages are pre-formatted strings.
  • It has no loading, empty, or error states, because nothing is fetched.

At a glance

Route/true_costTrueCostPage — registered only in apps/demo
Available indemo only
SidebarA TRUE_COST item in the Efficiency submenu, marked isDemoOption: true
PermissionpermissionId: 'TRUE_COST' is referenced by the nav config, but TRUE_COST is not defined in the Permissions enum
DatadummyData/trueCostDummyData.js, imported directly
Librarylibs/trueCost/ — components + a helper, nothing else
Chartsrecharts — consistent with the app standard
StateOne local useState object; no context

Why you only see it in demo

Summary: The real gate is isDemoOption, not the permission — the sidebar drops any demo-only item when the build is not the demo app. The same flag hides the feature's entry in the feature-locked catalogue (TRUE_COST_OF_WATER).


What's on the page

Selecting a period swaps which slice of the dummy dataset is displayed.

AreaComponentWhat it showsAction
Title barSubHeadingView"True Cost of Water"
Filter barTrueCostFormControlCurrent / Custom selector, the period sub-menu, a date picker for custom day and monthChanging a selector re-slices the data. "+ Edit expense" has no handler
KPI cardsTrueCostHeaderCardsTotal Water Cost, Average Water Cost, Total Water Used
Cost trendTrueCostCardTotalViewGraph / SplitGraphViewA line chart, Total or Split by categoryTotal/Split radio; in Split, three category checkboxes — unchecking all reverts to Total
Cost distributionTrueCostPiechartA donut of the three categories with a centred total
Category detailTrueCostTableComponent + TrueCostTableCost lines for the selected categoryTabs switch category; the sort menu offers A - Z or Cost High to Low

The dummy data contract

Summary: Two top-level branches, nine periods between them, and the same five blocks inside each — so every selector combination renders the same shape.

Block-by-block shape
BlockShapeFeeds
headercard{ totalWaterCost, averageWaterCost, totalWaterUsed }The three KPI cards
tableCard{ rawWater, energy, chemicals }The detail table
pieChartDataCategory totalsThe distribution donut
totalGraphA single combined seriesThe trend line in Total view
splitGraphPer-category seriesThe trend line in Split view

Each tableCard category carries:

FieldPurpose
displayNameHeading, including the period, e.g. "Raw Water (Last 7 Days)"
type[]The cost-line names
cost[]The matching amounts, pre-formatted strings with currency symbols
totalCostThe category total, also pre-formatted
distribution[]Percentage strings
lastUpdatedGenerated from moment() at import time

Because the amounts are formatted strings rather than numbers, nothing on the page can recompute or re-aggregate them — the display is the data.

Date labels are generated with moment() at module import, so they always read as relative to today even though the figures never change.


State

All page state lives in a single object in TrueCostPage:

FieldPurpose
selectioncurrent or custom
currentType · customTypeWhich period within that branch
selectedMonthThe custom date picker value
viewtotal or split
splitView{ rawWater, energy, chemicals } checkbox state
tabIndexThe active category tab
sortOrder · sortTextSort direction and its button label
anchorElThe sort menu anchor
currentTimePeriod · customTimePeriodUnused — duplicates of currentType / customType

helper/trueCostHelper.js supplies the period enum and a set of curried change handlers. It performs no data access.


Render states

Because the data is a synchronous local object, there is no loading, empty, or error state. The only conditional behaviour is:

CaseHandling
Split view with everything uncheckedFalls back to the Total view
Non-array chart dataThe donut renders nothing rather than throwing
Custom periodThe date picker appears for day and month selections

Visibility & access

Which apps register the route

AppPathRenders
demo/true_costTrueCostPage
production · uwms · rwi · lakepulseNot registered

Route-level gating: none

The demo app's route element is a bare <TrueCostPage />.

PropertyValue
Nav keyTRUE_COST, inside the Efficiency submenu
Display nameTrue Cost of Water
permissionIdTRUE_COSTnot defined in the Permissions enum
isDemoOptiontrue — this is the effective gate

SideBarMenus drops any item whose isDemoOption is true when constants.isDemo is false, and FeatureLockedPage skips demo-only rows the same way. So the feature disappears outside the demo build regardless of permissions. See Permissions → Sidebar access modes.

Feature-locked catalogue

lockedFeatureHelper carries a TRUE_COST_OF_WATER entry pointing at the same TRUE_COST permission id, also demo-gated.


Dependencies

Shared store & services

ImportUsed for
SubPageWrapper · FixedBarPage shell

That is the whole list. This feature touches no store, no apiClient, no Urls, no analytics service, and no navigation helper — a useful signal of how shallow the prototype is.

Component library

SubPageWrapper, FixedBar, and MUI primitives for the cards, table, tabs, and filter bar.

Lib-internal

TrueCostHelper (period enum + curried change handlers), trueCostDummyData, and the eight TrueCost* components. There is deliberately no dataSource, controller, or store directory.

External npm

recharts (line charts and the donut), @mui/material, moment — the last only to stamp relative date labels into the dummy data at import time.


Usage examples

Select a slice of the dummy dataset

import { TrueCostHelper } from '@aquagen-mf-webapp/trueCost/helper/trueCostHelper';
import { trueCostDummyData } from '@aquagen-mf-webapp/trueCost/dummyData/trueCostDummyData';

const { CURRENT, LAST_7_DAYS } = TrueCostHelper.TrueCostTimeperiodEnum;

// this is exactly what the page's effect does
const period = trueCostDummyData[CURRENT][LAST_7_DAYS];
period.headercard; // { totalWaterCost, averageWaterCost, totalWaterUsed }
period.tableCard.rawWater; // { displayName, type[], cost[], totalCost, ... }

Read the available periods

Object.keys(trueCostDummyData.current);
// ['last7DaysData', 'month', 'lastMonth', 'last3Months', 'year', 'lastYear']
Object.keys(trueCostDummyData.custom);
// ['days', 'months', 'years']

Wire a change handler the way the page does

const handleStateChange = (key) => (value) =>
setTrueCostState((prev) => ({ ...prev, [key]: value }));

// the helpers are curried: pass the setter, get an event handler back
const onViewChange = TrueCostHelper.handleViewChange(handleStateChange('view'));
const onSplitChange = TrueCostHelper.handleSplitViewChange(
handleStateChange('splitView')
); // reads event.target.name and .checked

Troubleshooting

The page is missing entirely

It is only routed in the demo app, and its sidebar item is isDemoOption: true. Outside a demo build there is neither a link nor a route.

A permission check against TRUE_COST never matches

TRUE_COST is referenced by the nav and feature-locked configs but is not defined in libs/shared/src/enums/permissions.js. Gate on constants.isDemo instead.

"+ Edit expense" does nothing

It has no click handler. The button is decorative.

The figures never change

Every number is a hardcoded string in trueCostDummyData.js. Only the date labels are dynamic, generated by moment() at import.

I cannot recompute the totals

Costs and percentages are stored pre-formatted with currency symbols, so no arithmetic is possible on them. The display is the data.

The trend chart reverted to Total on its own

Unchecking all three category boxes in Split view falls back to Total by design.

There is no loading or error state to test

Correct — the data is a synchronous local import, so no async states exist.


Known issues & gotchas

Verified against the code
IssueWhereImpact
The whole feature is fabricated datadummyData/trueCostDummyData.jsAnyone treating this page as real reporting will be misled. It has no data layer to swap in
TRUE_COST is not a real permissionThe nav config and the feature-locked catalogue both reference permissionId: 'TRUE_COST', but permissions.js does not define itPermission checks against it can never match a defined key; the effective gate is isDemoOption
Sidebar entry can point nowhereThe nav item is registered app-wide but the route exists only in apps/demoWere the demo flag ever relaxed, the link would resolve to no route
"+ Edit expense" is inertThe button is rendered in TrueCostFormControl with no click handlerLooks actionable, does nothing
Dead duplicated statecurrentTimePeriod and customTimePeriod are initialised and never readConfusing alongside the fields that are used
Redundant propsTrueCostCard receives both splitView and the three showRawWater / showEnergy / showChemicals booleans, plus period and currentType carrying the same valueTwo sources of truth for one piece of state
Amounts are stringsCosts and percentages are pre-formatted with symbolsNo client-side maths is possible; totals cannot be verified

Code reference

FileRole
TrueCostPage.jsxOrchestrator; selects the dummy-data slice
dummyData/trueCostDummyData.jsAll figures — static
helper/trueCostHelper.jsPeriod enum + curried change handlers
components/TrueCostFormControl.jsxPeriod filter bar (and the inert expense button)
components/TrueCostHeaderCards.jsxKPI cards
components/TrueCostCard.jsxTrend card, Total/Split switching
components/TotalViewGraph.jsx · SplitGraphView.jsxThe two recharts line views
components/TrueCostPiechart.jsxThe distribution donut
components/TrueCostTableComponent.jsx · TrueCostTable.jsxCategory tabs, sort menu, detail table