Skip to content

feat(bm-dashboard): Add Cost Breakdown by Category donut chart to Financials#4821

Open
Aditya-gam wants to merge 4 commits intodevelopmentfrom
Aditya-feature/cost-breakdown-donut-chart-wip
Open

feat(bm-dashboard): Add Cost Breakdown by Category donut chart to Financials#4821
Aditya-gam wants to merge 4 commits intodevelopmentfrom
Aditya-feature/cost-breakdown-donut-chart-wip

Conversation

@Aditya-gam
Copy link
Contributor

@Aditya-gam Aditya-gam commented Feb 10, 2026

Description

Restores and implements the Cost Breakdown by Category donut chart in the Financials section of the Phase 2 Summary Dashboard. The chart was not rendering because the frontend had no integration with the cost breakdown API.
IssueDescription

This PR adds full frontend integration: Redux state, API calls to GET /api/costs/breakdown, and an interactive Recharts donut chart with project/date filters, hover tooltips (dollar amount and percentage), click-to-drill-down by category, dynamic center label (e.g. "All Projects" vs selected project name), responsive layout, and dark mode support. Color mapping is consistent with the spec: Labor – Purple, Materials – Green, Equipment – Yellow.

Related PRs (if any):

  • Backend (required): HGNRest PR #2036 - Restore Cost Breakdown by Category API for Financials donut chart (registers router, cost aggregation service, breakdown/detail endpoints).
  • Previous frontend (closed): PR #3659 - Shashank summary dashboard donut chart UI; closed; this PR is a reimplementation using current patterns and the backend from PR Frontend Release to Main [3.34] #2036.
  • Previous backend: HGNRest PR #1300 - Created costs API; router was never registered in routes.js.

Main changes explained:

Created/Updated Files:

  • src/constants/bmdashboard/costBreakdownConstants.js

    • Action types: FETCH_COST_BREAKDOWN_START/SUCCESS/ERROR, FETCH_COST_DETAIL_START/SUCCESS/ERROR, CLEAR_COST_DETAIL.
  • src/actions/bmdashboard/costBreakdownActions.js

    • fetchCostBreakdown({ projectId, startDate, endDate }) — calls GET /api/costs/breakdown with optional query params for chart data.
    • fetchCostDetail({ projectId, startDate, endDate }) — same endpoint with categoryDetail=true for per-project breakdown on slice click.
    • clearCostDetail() — resets drill-down state.
    • Uses ENDPOINTS.BM_COST_BREAKDOWN() from URL.js; errors surface error.response?.data?.error or fallback message.
  • src/reducers/bmdashboard/costBreakdownReducer.js

    • State: loading, data, error (main breakdown); detailLoading, detailData, detailError (drill-down).
    • Handles all seven action types with immutable updates.
  • src/components/BMDashboard/WeeklyProjectSummary/Financials/CostBreakDown/CostBreakDown.jsx

    • Donut chart built with Recharts: PieChart, Pie, Cell, Tooltip, ResponsiveContainer.
    • Filters: Project select (from GET /bm/projectsNames), From/To date inputs; 500 ms debounce before refetch.
    • Center label: Project name (from data.project) + total cost; uses fitLabelInDonut() to size and wrap text (max 2 lines, ellipsis if needed) to prevent overflow.
    • Tooltip: Category label, amount (formatCurrency), and percentage share.
    • Click: Segment or legend toggles detail panel; second request with categoryDetail=true populates per-project breakdown (name, amount, %).
    • Responsive: Breakpoints at 480px and 768px for inner/outer radius and chart height.
    • Dark mode: Uses state.theme.darkMode to apply .wrapperDark; tooltip and detail panel use CSS variables.
    • States: Loading spinner, error + Retry, empty state when no breakdown data.
  • src/components/BMDashboard/WeeklyProjectSummary/Financials/CostBreakDown/CostBreakDown.module.css

    • CSS variables for light/dark: --cb-text-color, --cb-input-bg, --cb-input-border, --cb-tooltip-bg, --cb-detail-bg.
    • .wrapperDark overrides for the Financials card in dark mode.
    • color-scheme: dark on filter container so native date picker and <select> render in dark theme.
    • Responsive and print media; prefers-reduced-motion and prefers-contrast: high where applicable.
  • src/utils/URL.js

    • BM_COST_BREAKDOWN(projectId, startDate, endDate, categoryDetail) — builds GET ${APIEndpoint}/costs/breakdown with optional projectId, startDate, endDate, categoryDetail=true.
  • src/reducers/index.js

    • Import and register costBreakdownReducer as costBreakdown in localReducers; state at state.costBreakdown.
  • src/components/BMDashboard/WeeklyProjectSummary/WeeklyProjectSummary.jsx

    • Import CostBreakDown; replace Financials “Big Card” placeholder with <CostBreakDown /> in the financial-big grid cell.

Key Implementation Details:

  • Center label overflow: fitLabelInDonut(text, availableWidth, maxFontSize, minFontSize) computes usable width from inner radius, tries font sizes 7–14px, word-wraps into up to 2 lines with SVG <tspan>, and truncates with ellipsis at min size so long names (e.g. “Commercial Test - Project”) stay inside the donut.
  • Category mapping: CATEGORY_CONFIG maps API category names to short labels and hex colors: Labor #9333EA, Materials #22C55E, Equipment #EAB308.
  • Debounce: Filter changes to the schedule fetchCostBreakdown after 500 ms; cleanup on unmount or next effect cancels pending timeout.
  • Detail flow: Clicking a slice sets selectedCategory and dispatches fetchCostDetail; response breakdown[].projectBreakdown is rendered in the detail panel; same slice/legend click clears selection and clearCostDetail.
  • Dark mode native controls: color-scheme: dark in the wrapper ensures <input type="date"> and <select> use dark styling without extra JS.

How to test:

  1. Check into current branch: Aditya-feature/cost-breakdown-donut-chart-wip
  2. Run yarn install (or npm install) to install dependencies.
  3. Ensure backend is running with Cost Breakdown API (e.g., HGNRest branch from PR #2036); base URL via REACT_APP_APIENDPOINT (default http://localhost:4500/api).
  4. Start the app: npm run start:local (or project’s frontend start command).
  5. Navigate: Dashboard → Reports → Total Construction Summary → Financials (or equivalent: BM Dashboard → Total Construction Summary → Financials). The “Cost Breakdown by Category” donut should appear in the large Financials card.
  6. Chart rendering:
    • Segments: Purple (Labor), Green (Materials), Yellow (Equipment).
    • Center: “All Projects” and total cost when no project is selected.
    • Legend below the chart with the same colors and labels.
  7. Filters:
    • Select a project → chart and center label update to that project.
    • Set From/To dates → chart updates after debounce.
    • Clear project/date → returns to “All Projects” view.
  8. Interactions:
    • Hover segment → tooltip shows category, amount, percentage.
    • Click segment or legend → detail panel opens with per-project breakdown; click again to close.
    • Long project name → center text wraps/shrinks and does not overflow.
  9. Dark mode: Toggle theme → chart, filters, tooltip, legend, detail panel use dark styles; date picker and project dropdown use dark native UI.
  10. Responsive: Resize to <480px, 480–768px, >768px → chart and filters adapt; no horizontal overflow.
  11. Edge cases:
    • No data for filters → “No cost data available” with subtext.
    • API error → error message and Retry button.
    • Backend unreachable → appropriate error message.

Screenshots or videos of changes:

  • Donut chart (All Projects, with legend):
    LightModeAllProjects
    DarkModeAllProjects

  • Single project selected (center label shows project name):
    LightModeSingleProject
    DarkModeSingleProject

  • Drill-down panel opens after clicking a category:
    LightModeCategoryPanel
    DarkModeCategoryPanel

  • All Filters + Category Panel (chart + date picker):
    LightModeAllFilters
    DarkModeAllFilters

  • Test Video:

Test.Video.mov

Note:

  • Performance Considerations: Breakdown and detail requests are debounced (500 ms). Chart uses isAnimationActive={false} for stable rendering. Detail is fetched only when a category is selected.
  • Backend dependency: Requires HGNRest PR #2036 merged so GET /api/costs/breakdown (and optional categoryDetail=true) is available.
  • Accessibility: Chart has role="img" and aria-label; loading uses aria-live="polite" and aria-busy; errors use role="alert"; form controls have associated <label>; legend items are buttons with aria-label including value; detail panel has role="region" and aria-label.

Add interactive Recharts donut chart to the Financials section of the
Phase 2 Summary Dashboard, replacing the placeholder Big Card. The
chart visualizes cost distribution across Labor, Materials, and
Equipment categories with project/date filters, hover tooltips, click
drill-down for per-project detail, responsive layout, and dark mode
support.

New files:
- Redux constants, actions, and reducer for cost breakdown state
- CostBreakDown component with CSS module styling

Modified files:
- URL.js: add BM_COST_BREAKDOWN endpoint builder
- reducers/index.js: register costBreakdownReducer
- WeeklyProjectSummary.jsx: render CostBreakDown in financials grid
Long project names overflowed the donut hole. Add fitLabelInDonut()
that dynamically calculates font size and word-wraps into SVG tspan
elements based on available inner radius width.
…elect

Add color-scheme: dark to filter inputs and selects in dark mode so
the browser renders native date calendar popups and select dropdowns
with dark theme colors.
@netlify
Copy link

netlify bot commented Feb 10, 2026

Deploy Preview for highestgoodnetwork-dev ready!

Name Link
🔨 Latest commit c21c58d
🔍 Latest deploy log https://app.netlify.com/projects/highestgoodnetwork-dev/deploys/698bef7f56a12e00087db74f
😎 Deploy Preview https://deploy-preview-4821--highestgoodnetwork-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Show a Clear Filters button when any filter is active that resets project, start date, and end date in a single click and dismisses any open drill-down panel.
@sonarqubecloud
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant