Water Neutrality
A sustainability dashboard that measures how much water an organisation credits (augments, replenishes, offsets) against how much it debits (consumes), and expresses the balance as a single Water Neutrality %.
- Route:
/water_neutrality→WaterNeutrality(libs/waterNeutrality/src/WaterNeutrality.jsx) - Permission:
WATER_NEUTRALITY(gates the sidebar entry; the route element isn't wrapped — see Permissions) - Library:
libs/waterNeutrality/— standarddataSource → controller → store → componentslayering
The idea
Summary: The page fetches credited and debited water for a chosen date range, shows each as a treemap broken down by sub-category, and reduces the pair to a neutrality percentage (target 100%) with a plain-language status.
Formula (shown in the "See How?" popup): Water Augmented / Water Consumed x 100.
Status labels
The percentage maps to one of four statuses:
| Status | Meaning |
|---|---|
| Water Positive | Crediting more than consumed (≥ 100%) |
| Water Neutral | Roughly balanced (~90–100%) |
| Nearing Neutrality | Approaching balance (~75–90%) |
| Critically Low | Well below target (< 75%) |
The controller caps the displayed value at 120%. When it can't be computed it shows "Unable to calculate."
What's on the page
| Area | Component | What it shows | On click |
|---|---|---|---|
| Date header | WaterNeutralityDateHeader | A range picker (AppDatePickerSelection, up to 365 days), the current Status, and a "See How?" link | "See How?" opens the concept popup |
| Balance figure | WaterTotalValue | Water Neutrality : <value> with (Target : 100%) | — |
| Legend | WaterNeutralityLegends | Credited / Debited swatches + the deviation-arrow key | — |
| Treemaps | WaterNeutralityTreeGraphComponent (×2) | One card each for credited and debited, sub-category tiles sized by value | Clicking a card's header expands it full-width (and collapses the other) |
| Treemap render | TreemapChart | The actual tiles (see below) | — |
| Summary | WaterNeutralitySummary | Optional bulleted insights (hidden when empty) | — |
| Concept popup | WaterNeutralityPopup | Static explanation + the status-range table + formula | Close button / backdrop dismiss |
Despite its name,
WaterNeutralityTreeGraphComponentis not a node-link tree — it wraps a treemap. There is no React Flow / D3 here.
The treemap (chart.js)
Tiles are rendered with chart.js via react-chartjs-2 and the
chartjs-chart-treemap plugin — this is the only chart.js use in the app
(everything else uses Recharts):
import { Chart as ChartJS, LinearScale, Tooltip } from 'chart.js';
import { TreemapController, TreemapElement } from 'chartjs-chart-treemap';
import { Chart } from 'react-chartjs-2';
Each tile is sized by its normalizedValue; the label carries an up/down
deviation arrow vs. target, the value, and the sub-category name; the tooltip
lists the per-unit rows.
Data & API
Neutrality data (the only endpoint)
dataSource/neutrality.js → controller/neutralityController.js → store init():
| Endpoint | GET neutrality/ (Urls.getNeutralityData) |
| Params | date1, date2 (both DD/MM/YYYY) — the selected range |
| Triggered by | initial load and any date-range change (no polling) |
The controller reshapes the response: it derives neutralityStatus from the
percentage and caps waterNeutrality at 120. The response carries the credited
(ID_WATER_CREDITED) and debited (ID_WATER_DEBITED) branches — each with a
total, a displayTotal, and a subCategory array (the treemap tiles) — plus
an optional summary array. A PAGE_VIEW analytics event fires on mount.
State (WaterNeutralityStore)
A React Context (WaterNeutralityProvider / WaterNeutralityContext) exposing
neutralityData, params / setParams, and isLoading. See
State Management and
API Call Flow.
Edge cases & guards
| Case | Handling |
|---|---|
| Loading | A centered loader while isLoading |
| No data | A "Data Not Found" panel with a button to Water Monitoring |
| Empty selected range | When either credited or debited total is missing, a "Data Not Found for selected range" block replaces the treemaps |
| Expand / collapse | Selecting one treemap hides the other; selecting again restores both |
| Value cap | The neutrality percentage is clamped to 120 before display |
| Static popup | The "See How?" content (concept, ranges, formula) is hardcoded, not data-driven |
Underlying libraries
| Purpose | Library |
|---|---|
| Treemap | chart.js + react-chartjs-2 + chartjs-chart-treemap |
| UI / theming | @mui/material (MUI 7) |
| Dates | moment |
Exact versions live in package.json.
Code reference
| File | Role |
|---|---|
WaterNeutrality.jsx | Page shell + provider |
dataSource/neutrality.js | The neutrality/ call |
controller/neutralityController.js | Status derivation + 120% cap |
store/WaterNeutralityStore.js | Context state |
helper/neutralityHelperInstance.js | Display config (colours, ranges, formatters) |
components/BuildWaterNeutralityDetails.jsx | Layout, date header, empty states |
components/WaterNeutralityTreeGraphComponent.jsx | Per-treemap card + expand |
components/TreemapChart.jsx | The chart.js treemap |
components/WaterNeutralitySummary.jsx · WaterNeutralityPopup.jsx | Summary + concept popup |
Related
- Water Balance · Water Usage Ratio — sibling efficiency features
- Application Routes · Permissions
- API Call Flow · State Management
- Component Library → Charts — why the treemap uses chart.js