Skip to content

Enhance Balance Chart with Detailed Event Contributions#366

Merged
SvenVw merged 37 commits into
developmentfrom
FDM310
Dec 12, 2025
Merged

Enhance Balance Chart with Detailed Event Contributions#366
SvenVw merged 37 commits into
developmentfrom
FDM310

Conversation

@BoraIneviNMI
Copy link
Copy Markdown
Collaborator

@BoraIneviNMI BoraIneviNMI commented Dec 5, 2025

New Features

  • Nitrogen balance chart now has further breakdown based on fertilizer types, and the contribution of crop residues, harvests, and fixation.

Summary by CodeRabbit

  • New Features

    • Detailed nitrogen breakdowns by source (fixation, deposition, mineralization) and per-fertilizer type; removal split into harvests vs residues.
  • Improvements

    • Charts and overview pages present per-fertilizer and source breakdowns with richer interactive detail and a unified farm/field data interface.
  • Breaking Changes

    • Balance results use a nested structure for supply, removal, and ammonia emissions — consumers must adapt to the updated data shape.

✏️ Tip: You can customize this high-level summary in your review settings.

@BoraIneviNMI BoraIneviNMI self-assigned this Dec 5, 2025
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Dec 5, 2025

🦋 Changeset detected

Latest commit: 32c077d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@svenvw/fdm-calculator Minor
@svenvw/fdm-app Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 5, 2025

Walkthrough

Restructures farm- and field-level nitrogen balance outputs to include nested supply, removal, and ammonia-emission breakdowns by fertilizer type; updates calculator types/tests and rewires app routes and NitrogenBalanceChart to a discriminated-union, data-driven interface with per‑fertilizer chart config and interactive tooltips.

Changes

Cohort / File(s) Summary
Changesets
\.changeset/bold-spoons-work.md, \.changeset/spicy-roses-write.md
Adds minor-release changelog entries for @svenvw/fdm-calculator and @svenvw/fdm-app, documenting data-shape alignment and enhanced nitrogen-balance/chart breakdowns.
Calculator Types
fdm-calculator/src/balance/nitrogen/types.d.ts
Introduces types for per‑fertilizer ammonia/residue breakdowns; changes NitrogenBalance/NitrogenBalanceNumeric to nested objects for supply, removal, and emission.ammonia.
Calculator Implementation
fdm-calculator/src/balance/nitrogen/index.ts
Implements per‑fertilizer aggregation (supply/removal/emission), accumulates deposition/fixation/mineralisation, computes per‑ha averages, and returns enriched farm-level NitrogenBalance with nested structures.
Calculator Tests
fdm-calculator/src/balance/nitrogen/index.test.ts
Replaces scalar assertions with structured validations; adds assertValidFertilizerBreakdown helper to validate per‑type fertilizer/ammonia maps.
App Component
fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
Rewrites NitrogenBalanceChart to discriminated-union props (`type: "farm"
App Route — Field
fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen.$b_id.tsx
Switches chart wiring to pass type="field", balanceData={result}, and fieldInput={fieldInput} instead of separate numeric props.
App Route — Farm Overview
fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsx
Reads nested totals (e.g., supply.total, removal.total, emission.ammonia.total) and passes type="farm" with balanceData={resolvedNitrogenBalanceResult} to the chart.

Sequence Diagram(s)

sequenceDiagram
  participant Browser as Browser (UI)
  participant Route as App Route (loader)
  participant Calc as fdm-calculator
  participant Chart as NitrogenBalanceChart

  Browser->>Route: Request farm/field nitrogen page
  Route->>Calc: compute enriched NitrogenBalance (field→farm)
  Calc-->>Route: return nested supply/removal/emission by fertilizer
  Route->>Browser: render page with props (type, balanceData, fieldInput)
  Browser->>Chart: mount Chart with discriminated-union props
  Chart->>Chart: buildChartDataAndLegend(balanceData, fieldInput)
  Chart-->>Browser: render bars, stacks and legend
  Browser->>Chart: hover bar (tooltip focus)
  Chart->>Chart: resolve dataKey, show Card detail
  Browser->>Chart: mouseleave/blur
  Chart-->>Browser: hide Card
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Pay extra attention to aggregation correctness and Decimal/number conversions in fdm-calculator/src/balance/nitrogen/index.ts.
  • Verify type alignment between types.d.ts, numeric variants, and updated tests.
  • Review fdm-app/app/components/blocks/balance/nitrogen-chart.tsx for discriminated-union handling, dynamic dataKey generation, stacked-bar rendering, and tooltip lifecycle.
  • Confirm route loaders supply the expected balanceData and fieldInput shapes for both farm and field modes.

Possibly related issues

  • Issue #310 — Matches chart API and wiring changes to accept detailed balanceData and per‑fertilizer stacked breakdowns.

Possibly related PRs

  • PR #330 — Modifies calculator types/aggregation; overlaps on per‑fertilizer and emission structure changes.
  • PR #303 — Adds/propagates fieldInput and updates route→chart wiring; strongly related to the chart prop changes.
  • PR #169 — Adjusts farm-level aggregation and area handling; relevant to correctness of the enriched farm return shape.

Suggested reviewers

  • SvenVw
  • gerardhros

"I hop through fields where numbers grow,
I tally mineral, manure, compost, and sow.
Deposition, fixation, residues align,
Charts stack like carrots in tidy line.
Tiny paws point — each per‑type sign — hooray!" 🐰🌱

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Enhance Balance Chart with Detailed Event Contributions' aligns with the main changes: restructuring the nitrogen balance chart to display granular breakdowns by fertilizer types and event contributions (fixation, harvests, residues).
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch FDM310

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7e050bf and 5b85525.

📒 Files selected for processing (1)
  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx (2 hunks)
🧰 Additional context used
🧠 Learnings (13)
📓 Common learnings
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 143
File: fdm-app/app/components/custom/balance/nitrogen-chart.tsx:73-85
Timestamp: 2025-05-27T19:56:48.556Z
Learning: In nitrogen balance charts, supply should be in a separate stack from removal and emission. Supply represents nitrogen inputs while removal and emission represent different types of nitrogen outputs, so they should be visually grouped differently using different stackId values.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 236
File: fdm-calculator/src/balance/nitrogen/index.ts:173-0
Timestamp: 2025-08-14T14:31:55.384Z
Learning: In nitrogen balance calculations for agricultural systems, the balance should only include ammonia emissions (emission.ammonia.total) and should not include nitrate leaching from the emission calculation. The nitrate component (emission.nitrate) should be excluded from the balance formula.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:236-238
Timestamp: 2025-05-26T10:32:15.538Z
Learning: In nitrogen balance calculations for agricultural systems, removal and volatilization are calculated as negative values by definition since they represent nitrogen losses from the system. The balance calculation uses addition (.add()) for all components because removal and volatilization are already negative, so adding them effectively subtracts the losses from the supply.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 343
File: fdm-app/app/components/blocks/balance/organic-matter-chart.tsx:19-25
Timestamp: 2025-11-24T10:43:09.278Z
Learning: In the organic matter balance chart (fdm-app), degradation values are multiplied by -1 before plotting to show supply and degradation bars side-by-side with positive magnitudes, enabling direct visual comparison. This is a deliberate design choice for the organic matter chart visualization, different from the nitrogen balance chart which uses separate stacks.
📚 Learning: 2025-05-27T19:56:48.556Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 143
File: fdm-app/app/components/custom/balance/nitrogen-chart.tsx:73-85
Timestamp: 2025-05-27T19:56:48.556Z
Learning: In nitrogen balance charts, supply should be in a separate stack from removal and emission. Supply represents nitrogen inputs while removal and emission represent different types of nitrogen outputs, so they should be visually grouped differently using different stackId values.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-01-09T16:03:37.764Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 42
File: fdm-app/app/routes/farm/_b_id_farm/layout.tsx:46-95
Timestamp: 2025-01-09T16:03:37.764Z
Learning: A shared layout component `FarmLayoutBase` has been created in `components/custom/farm-layout-base.tsx` to maintain consistency across farm-related pages. The component handles farm selection dropdown, breadcrumb navigation, and provides a common layout structure.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-05-26T10:32:00.674Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:162-168
Timestamp: 2025-05-26T10:32:00.674Z
Learning: In the nitrogen balance calculation system (fdm-calculator), removal and volatilization values are negative by definition. This means the balance calculation using supply.total.add(removal.total).add(volatilization.total) is correct, as it effectively computes supply - |removal| - |volatilization|.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-05-26T10:32:15.538Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:236-238
Timestamp: 2025-05-26T10:32:15.538Z
Learning: In nitrogen balance calculations for agricultural systems, removal and volatilization are calculated as negative values by definition since they represent nitrogen losses from the system. The balance calculation uses addition (.add()) for all components because removal and volatilization are already negative, so adding them effectively subtracts the losses from the supply.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-11-24T10:43:09.278Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 343
File: fdm-app/app/components/blocks/balance/organic-matter-chart.tsx:19-25
Timestamp: 2025-11-24T10:43:09.278Z
Learning: In the organic matter balance chart (fdm-app), degradation values are multiplied by -1 before plotting to show supply and degradation bars side-by-side with positive magnitudes, enabling direct visual comparison. This is a deliberate design choice for the organic matter chart visualization, different from the nitrogen balance chart which uses separate stacks.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-08-11T11:55:26.053Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 233
File: fdm-app/app/integrations/nmi.ts:54-0
Timestamp: 2025-08-11T11:55:26.053Z
Learning: The NMI API Estimates endpoint (`https://api.nmi-agro.nl/estimates`) always returns the fields `b_gwl_ghg`, `b_gwl_glg`, and `cultivations` according to its specification. These fields should be kept as required (not optional) in the TypeScript return type and Zod validation schema in `fdm-app/app/integrations/nmi.ts`.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-01-31T15:05:14.310Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 67
File: fdm-app/app/routes/farm.create.$b_id_farm.fields.$b_id.tsx:601-610
Timestamp: 2025-01-31T15:05:14.310Z
Learning: The `updateField` function in fdm-core has optional parameters after `fdm` and `b_id`. The TypeScript definitions might show 8 required parameters due to a potential version mismatch.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-08-11T12:24:32.200Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 233
File: fdm-app/app/components/blocks/atlas-fields/cultivation-history.tsx:53-53
Timestamp: 2025-08-11T12:24:32.200Z
Learning: In `fdm-app/app/components/blocks/atlas-fields/cultivation-history.tsx`, the NMI API for cultivations guarantees that each year will be unique in the cultivation history data, so using `cultivation.year` as a React list key is safe and won't cause duplicate key warnings.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-02-13T08:35:59.306Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 71
File: fdm-app/app/routes/farm.$b_id_farm.field.$b_id.cultivation.$b_lu.harvest.$b_id_harvesting.tsx:114-124
Timestamp: 2025-02-13T08:35:59.306Z
Learning: The HarvestForm component in fdm-app expects undefined (not 0) for b_lu_yield when no yield information is available, as 0 would incorrectly imply that yield data exists.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2024-11-27T12:15:36.425Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 9
File: fdm-data/src/cultivations/index.test.ts:57-59
Timestamp: 2024-11-27T12:15:36.425Z
Learning: In `fdm-data/src/cultivations/index.test.ts`, the `fdm` object created by `drizzle` does not have an `.end()` method. Cleanup code should not attempt to call `fdm.end();`.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-12-11T13:23:13.089Z
Learnt from: BoraIneviNMI
Repo: SvenVw/fdm PR: 366
File: fdm-app/app/components/blocks/balance/nitrogen-chart.tsx:436-452
Timestamp: 2025-12-11T13:23:13.089Z
Learning: In the fdm project using shadcn/ui Chart components with Recharts 2.15.4, the Bar component's onMouseEnter and onMouseLeave event handlers receive an event object that includes a tooltipPayload property with the structure { tooltipPayload: { dataKey: string }[] }, which differs from standard Recharts v2 documentation but is confirmed to work in practice. This appears to be a modification made by shadcn/ui's Chart wrapper components.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-01-31T15:41:43.741Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 67
File: fdm-app/app/components/custom/atlas/atlas-panels.tsx:28-28
Timestamp: 2025-01-31T15:41:43.741Z
Learning: When handling different map event types in react-map-gl v7.1.8, use MapLayerMouseEvent for mouse events (which have the point property) and ViewStateChangeEvent for view state changes. Use a type guard like 'point' in evt to safely access event-specific properties.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
🧬 Code graph analysis (1)
fdm-app/app/components/blocks/balance/nitrogen-chart.tsx (3)
fdm-calculator/src/balance/nitrogen/types.d.ts (2)
  • FieldInput (460-480)
  • NitrogenBalanceFieldResultNumeric (639-644)
fdm-calculator/src/balance/nitrogen/index.ts (1)
  • getNitrogenBalance (129-133)
fdm-app/app/components/custom/cultivation-colors.ts (1)
  • getCultivationColor (20-28)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 5, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.41%. Comparing base (4dee34a) to head (32c077d).
⚠️ Report is 38 commits behind head on development.

Additional details and impacted files
@@               Coverage Diff               @@
##           development     #366      +/-   ##
===============================================
+ Coverage        87.23%   87.41%   +0.17%     
===============================================
  Files               91       91              
  Lines             4434     4497      +63     
  Branches          1325     1345      +20     
===============================================
+ Hits              3868     3931      +63     
  Misses             566      566              
Flag Coverage Δ
fdm-calculator 87.36% <100.00%> (+0.35%) ⬆️
fdm-core 87.08% <ø> (ø)
fdm-data 92.12% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@BoraIneviNMI BoraIneviNMI marked this pull request as ready for review December 10, 2025 11:42
@coderabbitai coderabbitai Bot added branch:development Issue only affecting development, not the main branch (yet) enhancement New feature or request fdm-app fdm-calculator labels Dec 10, 2025
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (2)
fdm-app/app/components/blocks/balance/nitrogen-chart.tsx (2)

420-443: State mutation inside setState callback.

The pattern of mutating tooltipFocus before returning a new Set (e.g., line 424 tooltipFocus.add(dataKey)) works but is an anti-pattern that could cause issues with React's concurrent features.

Consider creating a new Set from scratch:

     const onTooltipFocus = (e: ChartMouseEvent) => {
         const dataKey = e.tooltipPayload[0].dataKey
         if (!tooltipFocus.has(dataKey))
             setTooltipFocus((tooltipFocus) => {
-                tooltipFocus.add(dataKey)
-                return new Set(tooltipFocus)
+                return new Set([...tooltipFocus, dataKey])
             })
     }

31-395: Consider extracting helper functions outside the component.

The buildChartDataAndLegend function is ~360 lines and defined at module scope, which is good. The nested helper functions addFertilizerApplication and addCultivation (lines 168-236) could be extracted to improve testability.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1634b92 and 8b8faa8.

📒 Files selected for processing (9)
  • .changeset/bold-spoons-work.md (1 hunks)
  • .changeset/spicy-roses-write.md (1 hunks)
  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx (2 hunks)
  • fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen.$b_id.tsx (1 hunks)
  • fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsx (4 hunks)
  • fdm-calculator/src/balance/nitrogen/emission/ammonia/fertilizers.ts (4 hunks)
  • fdm-calculator/src/balance/nitrogen/index.test.ts (1 hunks)
  • fdm-calculator/src/balance/nitrogen/index.ts (4 hunks)
  • fdm-calculator/src/balance/nitrogen/types.d.ts (4 hunks)
🧰 Additional context used
🧠 Learnings (15)
📓 Common learnings
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 0
File: :0-0
Timestamp: 2025-08-13T10:33:05.313Z
Learning: In the fdm project, fdm-calculator integration for new features like b_lu_variety is handled in separate updates from the core data model changes. When fdm-core functions are updated to support new fields, fdm-calculator can consume these enhanced APIs without requiring changes in the same PR that introduces the core functionality.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 343
File: fdm-app/app/components/blocks/balance/organic-matter-chart.tsx:19-25
Timestamp: 2025-11-24T10:43:09.278Z
Learning: In the organic matter balance chart (fdm-app), degradation values are multiplied by -1 before plotting to show supply and degradation bars side-by-side with positive magnitudes, enabling direct visual comparison. This is a deliberate design choice for the organic matter chart visualization, different from the nitrogen balance chart which uses separate stacks.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 143
File: fdm-app/app/components/custom/balance/nitrogen-chart.tsx:73-85
Timestamp: 2025-05-27T19:56:48.556Z
Learning: In nitrogen balance charts, supply should be in a separate stack from removal and emission. Supply represents nitrogen inputs while removal and emission represent different types of nitrogen outputs, so they should be visually grouped differently using different stackId values.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 236
File: fdm-calculator/src/balance/nitrogen/index.ts:173-0
Timestamp: 2025-08-14T14:31:55.384Z
Learning: In nitrogen balance calculations for agricultural systems, the balance should only include ammonia emissions (emission.ammonia.total) and should not include nitrate leaching from the emission calculation. The nitrate component (emission.nitrate) should be excluded from the balance formula.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 274
File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:160-163
Timestamp: 2025-09-23T12:29:34.184Z
Learning: In the FDM application, the fertilizer application route intentionally uses `${calendar}/field/fertilizer` instead of the originally planned `/farm/{farmId}/add/fertilizer` structure. This design decision prioritizes starting from the field list view to provide better field selection workflow before applying fertilizer, rather than direct dashboard-to-action navigation.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:162-168
Timestamp: 2025-05-26T10:32:00.674Z
Learning: In the nitrogen balance calculation system (fdm-calculator), removal and volatilization values are negative by definition. This means the balance calculation using supply.total.add(removal.total).add(volatilization.total) is correct, as it effectively computes supply - |removal| - |volatilization|.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:236-238
Timestamp: 2025-05-26T10:32:15.538Z
Learning: In nitrogen balance calculations for agricultural systems, removal and volatilization are calculated as negative values by definition since they represent nitrogen losses from the system. The balance calculation uses addition (.add()) for all components because removal and volatilization are already negative, so adding them effectively subtracts the losses from the supply.
📚 Learning: 2025-08-13T10:33:05.313Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 0
File: :0-0
Timestamp: 2025-08-13T10:33:05.313Z
Learning: In the fdm project, fdm-calculator integration for new features like b_lu_variety is handled in separate updates from the core data model changes. When fdm-core functions are updated to support new fields, fdm-calculator can consume these enhanced APIs without requiring changes in the same PR that introduces the core functionality.

Applied to files:

  • .changeset/bold-spoons-work.md
  • fdm-calculator/src/balance/nitrogen/index.ts
📚 Learning: 2025-09-23T12:29:34.184Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 274
File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:160-163
Timestamp: 2025-09-23T12:29:34.184Z
Learning: In the FDM application, the fertilizer application route intentionally uses `${calendar}/field/fertilizer` instead of the originally planned `/farm/{farmId}/add/fertilizer` structure. This design decision prioritizes starting from the field list view to provide better field selection workflow before applying fertilizer, rather than direct dashboard-to-action navigation.

Applied to files:

  • .changeset/bold-spoons-work.md
  • fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsx
  • fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen.$b_id.tsx
📚 Learning: 2025-09-26T08:34:50.413Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 279
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsx:277-283
Timestamp: 2025-09-26T08:34:50.413Z
Learning: In the fdm project, fdm-core and fdm-app are updated together as part of a monorepo structure, which eliminates legacy data concerns when new fields like b_isproductive are introduced. Both packages are synchronized, so there's no need for defensive coding against undefined values for newly introduced database fields.

Applied to files:

  • .changeset/bold-spoons-work.md
📚 Learning: 2025-07-21T12:06:07.070Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 156
File: fdm-calculator/src/norms/nl/2025/stikstofgebruiksnorm.ts:295-303
Timestamp: 2025-07-21T12:06:07.070Z
Learning: Functions in the fdm-calculator with "NL2025" in their names are specifically designed for Netherlands 2025 agricultural norms calculation and hardcoded 2025 dates are appropriate in this context, as different years would have separate calculation modules.

Applied to files:

  • .changeset/bold-spoons-work.md
📚 Learning: 2025-11-24T10:43:09.278Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 343
File: fdm-app/app/components/blocks/balance/organic-matter-chart.tsx:19-25
Timestamp: 2025-11-24T10:43:09.278Z
Learning: In the organic matter balance chart (fdm-app), degradation values are multiplied by -1 before plotting to show supply and degradation bars side-by-side with positive magnitudes, enabling direct visual comparison. This is a deliberate design choice for the organic matter chart visualization, different from the nitrogen balance chart which uses separate stacks.

Applied to files:

  • .changeset/bold-spoons-work.md
  • fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsx
  • .changeset/spicy-roses-write.md
  • fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen.$b_id.tsx
📚 Learning: 2025-05-26T10:32:00.674Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:162-168
Timestamp: 2025-05-26T10:32:00.674Z
Learning: In the nitrogen balance calculation system (fdm-calculator), removal and volatilization values are negative by definition. This means the balance calculation using supply.total.add(removal.total).add(volatilization.total) is correct, as it effectively computes supply - |removal| - |volatilization|.

Applied to files:

  • .changeset/bold-spoons-work.md
  • fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsx
  • fdm-calculator/src/balance/nitrogen/types.d.ts
  • fdm-calculator/src/balance/nitrogen/index.ts
📚 Learning: 2025-08-11T11:55:26.053Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 233
File: fdm-app/app/integrations/nmi.ts:54-0
Timestamp: 2025-08-11T11:55:26.053Z
Learning: The NMI API Estimates endpoint (`https://api.nmi-agro.nl/estimates`) always returns the fields `b_gwl_ghg`, `b_gwl_glg`, and `cultivations` according to its specification. These fields should be kept as required (not optional) in the TypeScript return type and Zod validation schema in `fdm-app/app/integrations/nmi.ts`.

Applied to files:

  • .changeset/bold-spoons-work.md
  • fdm-calculator/src/balance/nitrogen/index.test.ts
  • fdm-calculator/src/balance/nitrogen/types.d.ts
  • fdm-calculator/src/balance/nitrogen/emission/ammonia/fertilizers.ts
  • fdm-calculator/src/balance/nitrogen/index.ts
📚 Learning: 2025-09-23T12:27:07.391Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 274
File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:151-204
Timestamp: 2025-09-23T12:27:07.391Z
Learning: In the FDM application, field overview functionality is implemented as a dedicated page accessible via `farm/{farmId}/{calendar}/field` rather than as a direct listing on the dashboard. The dashboard includes a "Perceelsoverzicht" quick action card that provides navigation to this comprehensive field management interface.

Applied to files:

  • .changeset/bold-spoons-work.md
📚 Learning: 2025-05-27T19:56:48.556Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 143
File: fdm-app/app/components/custom/balance/nitrogen-chart.tsx:73-85
Timestamp: 2025-05-27T19:56:48.556Z
Learning: In nitrogen balance charts, supply should be in a separate stack from removal and emission. Supply represents nitrogen inputs while removal and emission represent different types of nitrogen outputs, so they should be visually grouped differently using different stackId values.

Applied to files:

  • fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsx
  • fdm-calculator/src/balance/nitrogen/types.d.ts
  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
  • fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen.$b_id.tsx
📚 Learning: 2025-01-09T16:03:37.764Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 42
File: fdm-app/app/routes/farm/_b_id_farm/layout.tsx:46-95
Timestamp: 2025-01-09T16:03:37.764Z
Learning: A shared layout component `FarmLayoutBase` has been created in `components/custom/farm-layout-base.tsx` to maintain consistency across farm-related pages. The component handles farm selection dropdown, breadcrumb navigation, and provides a common layout structure.

Applied to files:

  • fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsx
  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
  • fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen.$b_id.tsx
📚 Learning: 2025-01-09T16:03:37.764Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 42
File: fdm-app/app/routes/farm/_b_id_farm/layout.tsx:46-95
Timestamp: 2025-01-09T16:03:37.764Z
Learning: The farm layout system has been reorganized into separate components (`FarmHeader`, `ContentLayout`, `PaginationLayout`) to support different navigation patterns (sidebar, pagination) while maintaining consistent styling. Each layout component is designed to be used independently or combined as needed.

Applied to files:

  • fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsx
📚 Learning: 2025-05-26T10:32:15.538Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:236-238
Timestamp: 2025-05-26T10:32:15.538Z
Learning: In nitrogen balance calculations for agricultural systems, removal and volatilization are calculated as negative values by definition since they represent nitrogen losses from the system. The balance calculation uses addition (.add()) for all components because removal and volatilization are already negative, so adding them effectively subtracts the losses from the supply.

Applied to files:

  • fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsx
  • fdm-calculator/src/balance/nitrogen/types.d.ts
  • fdm-calculator/src/balance/nitrogen/index.ts
📚 Learning: 2025-08-14T14:31:55.384Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 236
File: fdm-calculator/src/balance/nitrogen/index.ts:173-0
Timestamp: 2025-08-14T14:31:55.384Z
Learning: In nitrogen balance calculations for agricultural systems, the balance should only include ammonia emissions (emission.ammonia.total) and should not include nitrate leaching from the emission calculation. The nitrate component (emission.nitrate) should be excluded from the balance formula.

Applied to files:

  • fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsx
  • fdm-calculator/src/balance/nitrogen/index.test.ts
  • fdm-calculator/src/balance/nitrogen/types.d.ts
  • fdm-calculator/src/balance/nitrogen/index.ts
📚 Learning: 2025-11-21T10:02:25.556Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 343
File: fdm-calculator/src/balance/organic-matter/types.d.ts:12-132
Timestamp: 2025-11-21T10:02:25.556Z
Learning: In the organic matter balance calculation system (fdm-calculator), degradation values are negative by definition. This means the balance calculation using supply.total.plus(degradation.total) is correct, as it effectively computes supply - |degradation|. This follows the same pattern as the nitrogen balance system.

Applied to files:

  • fdm-calculator/src/balance/nitrogen/index.ts
🧬 Code graph analysis (2)
fdm-calculator/src/balance/nitrogen/emission/ammonia/fertilizers.ts (1)
fdm-calculator/src/balance/nitrogen/types.d.ts (1)
  • NitrogenEmissionAmmoniaFertilizers (208-229)
fdm-calculator/src/balance/nitrogen/index.ts (1)
fdm-calculator/src/balance/nitrogen/types.d.ts (1)
  • NitrogenBalance (365-422)
🪛 LanguageTool
.changeset/spicy-roses-write.md

[grammar] ~5-~5: Ensure spelling is correct
Context: ...of harvest, fixed vs crop residues, and dfferent fertilizer types.

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🔇 Additional comments (16)
.changeset/bold-spoons-work.md (1)

1-5: LGTM!

The changeset correctly documents the minor version bump for the calculator package, and the description accurately summarizes the data shape unification and new breakdown capabilities.

fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsx (4)

263-263: LGTM!

The access pattern correctly updated to use the nested supply.total property, aligning with the new structured data shape from the calculator.


279-279: LGTM!

Correctly accessing removal.total from the nested structure.


295-298: LGTM!

Properly accesses the nested emission.ammonia.total path. Based on learnings, this aligns with the nitrogen balance calculation system where ammonia emissions are tracked separately from nitrate.


335-338: LGTM!

The updated chart component usage with type="farm" and balanceData prop aligns with the discriminated union API introduced in NitrogenBalanceChart. This cleanly separates farm-level from field-level visualization concerns.

fdm-calculator/src/balance/nitrogen/emission/ammonia/fertilizers.ts (3)

36-36: LGTM!

Adding the explicit type annotation (acc: NitrogenEmissionAmmoniaFertilizers, application) improves type safety and makes the reduce callback's intent clearer.


77-83: LGTM!

The enriched application record with p_id_catalogue, p_type, and p_app_date enables richer downstream reporting and aligns with the updated NitrogenEmissionFertilizer type structure.


141-149: No action needed; p_app_date is guaranteed to be non-null by the type system.

The FertilizerApplication type definition marks p_app_date as a required Date property, not optional. TypeScript will prevent any FertilizerApplication objects without a valid date from reaching this code. The comparisons are type-safe.

Likely an incorrect or invalid review comment.

fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen.$b_id.tsx (1)

396-400: LGTM!

The updated chart props correctly implement the field-mode interface with type="field", balanceData, and fieldInput. This enables the richer per-fertilizer and per-cultivation visualization capabilities. Based on learnings about nitrogen balance charts, the separation between farm and field modes with structured data inputs is a clean approach.

fdm-calculator/src/balance/nitrogen/index.test.ts (2)

94-105: LGTM!

The assertValidFertilizerBreakdown helper provides a clean, reusable way to validate the per-type fertilizer breakdown structure. The type annotation correctly captures the expected shape with total and the four fertilizer categories.


109-121: The test is correctly written; removal has a flat structure and does not require nested validation like supply or emission.ammonia.

The removal field in NitrogenBalance (the return type being tested) contains only simple scalar fields (total, harvests, and residues as Decimal values), unlike supply.fertilizers and emission.ammonia.fertilizers which have complex nested structures with arrays and sub-objects. Additional validation for removal is unnecessary.

fdm-calculator/src/balance/nitrogen/types.d.ts (4)

186-202: LGTM!

The new NitrogenEmissionFertilizer type properly captures individual application-level detail with metadata fields (p_id_catalogue, p_type, p_app_date) that enable richer chart tooltips.


231-252: LGTM!

NitrogenEmissionAmmoniaFertilizersTotal provides a clean aggregated structure for farm-level totals by fertilizer type.


373-405: LGTM!

The expanded NitrogenBalance type with nested supply, removal, and emission structures properly exposes the per-category breakdowns needed for the enhanced chart visualization.


627-658: LGTM!

The NitrogenBalanceNumeric type correctly mirrors the NitrogenBalance structure with number instead of Decimal, maintaining type consistency for the conversion layer.

fdm-app/app/components/blocks/balance/nitrogen-chart.tsx (1)

612-613: LGTM!

Supply and removal/emission correctly use separate stackId values ("a" and "b"), which aligns with the nitrogen balance chart design pattern where supply inputs should be visually separated from removal and emission outputs. Based on learnings.

Comment thread .changeset/spicy-roses-write.md Outdated
Comment thread fdm-app/app/components/blocks/balance/nitrogen-chart.tsx Outdated
Comment thread fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
Comment thread fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
Comment thread fdm-calculator/src/balance/nitrogen/index.ts
Comment thread fdm-calculator/src/balance/nitrogen/index.ts
Comment thread fdm-calculator/src/balance/nitrogen/index.ts
Comment thread fdm-calculator/src/balance/nitrogen/index.ts Outdated
Comment thread fdm-calculator/src/balance/nitrogen/index.ts
@BoraIneviNMI BoraIneviNMI requested a review from SvenVw December 10, 2025 14:45
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c92e266 and 2e78559.

📒 Files selected for processing (1)
  • .changeset/spicy-roses-write.md (1 hunks)
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 143
File: fdm-app/app/components/custom/balance/nitrogen-chart.tsx:73-85
Timestamp: 2025-05-27T19:56:48.556Z
Learning: In nitrogen balance charts, supply should be in a separate stack from removal and emission. Supply represents nitrogen inputs while removal and emission represent different types of nitrogen outputs, so they should be visually grouped differently using different stackId values.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 236
File: fdm-calculator/src/balance/nitrogen/index.ts:173-0
Timestamp: 2025-08-14T14:31:55.384Z
Learning: In nitrogen balance calculations for agricultural systems, the balance should only include ammonia emissions (emission.ammonia.total) and should not include nitrate leaching from the emission calculation. The nitrate component (emission.nitrate) should be excluded from the balance formula.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:236-238
Timestamp: 2025-05-26T10:32:15.538Z
Learning: In nitrogen balance calculations for agricultural systems, removal and volatilization are calculated as negative values by definition since they represent nitrogen losses from the system. The balance calculation uses addition (.add()) for all components because removal and volatilization are already negative, so adding them effectively subtracts the losses from the supply.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:162-168
Timestamp: 2025-05-26T10:32:00.674Z
Learning: In the nitrogen balance calculation system (fdm-calculator), removal and volatilization values are negative by definition. This means the balance calculation using supply.total.add(removal.total).add(volatilization.total) is correct, as it effectively computes supply - |removal| - |volatilization|.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 343
File: fdm-app/app/components/blocks/balance/organic-matter-chart.tsx:19-25
Timestamp: 2025-11-24T10:43:09.278Z
Learning: In the organic matter balance chart (fdm-app), degradation values are multiplied by -1 before plotting to show supply and degradation bars side-by-side with positive magnitudes, enabling direct visual comparison. This is a deliberate design choice for the organic matter chart visualization, different from the nitrogen balance chart which uses separate stacks.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 343
File: fdm-calculator/src/balance/organic-matter/types.d.ts:12-132
Timestamp: 2025-11-21T10:02:25.556Z
Learning: In the organic matter balance calculation system (fdm-calculator), degradation values are negative by definition. This means the balance calculation using supply.total.plus(degradation.total) is correct, as it effectively computes supply - |degradation|. This follows the same pattern as the nitrogen balance system.
📚 Learning: 2025-11-24T10:43:09.278Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 343
File: fdm-app/app/components/blocks/balance/organic-matter-chart.tsx:19-25
Timestamp: 2025-11-24T10:43:09.278Z
Learning: In the organic matter balance chart (fdm-app), degradation values are multiplied by -1 before plotting to show supply and degradation bars side-by-side with positive magnitudes, enabling direct visual comparison. This is a deliberate design choice for the organic matter chart visualization, different from the nitrogen balance chart which uses separate stacks.

Applied to files:

  • .changeset/spicy-roses-write.md
📚 Learning: 2025-05-27T19:56:48.556Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 143
File: fdm-app/app/components/custom/balance/nitrogen-chart.tsx:73-85
Timestamp: 2025-05-27T19:56:48.556Z
Learning: In nitrogen balance charts, supply should be in a separate stack from removal and emission. Supply represents nitrogen inputs while removal and emission represent different types of nitrogen outputs, so they should be visually grouped differently using different stackId values.

Applied to files:

  • .changeset/spicy-roses-write.md
📚 Learning: 2025-05-26T10:32:00.674Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:162-168
Timestamp: 2025-05-26T10:32:00.674Z
Learning: In the nitrogen balance calculation system (fdm-calculator), removal and volatilization values are negative by definition. This means the balance calculation using supply.total.add(removal.total).add(volatilization.total) is correct, as it effectively computes supply - |removal| - |volatilization|.

Applied to files:

  • .changeset/spicy-roses-write.md
📚 Learning: 2025-11-21T10:02:25.556Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 343
File: fdm-calculator/src/balance/organic-matter/types.d.ts:12-132
Timestamp: 2025-11-21T10:02:25.556Z
Learning: In the organic matter balance calculation system (fdm-calculator), degradation values are negative by definition. This means the balance calculation using supply.total.plus(degradation.total) is correct, as it effectively computes supply - |degradation|. This follows the same pattern as the nitrogen balance system.

Applied to files:

  • .changeset/spicy-roses-write.md
📚 Learning: 2025-05-26T10:32:15.538Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:236-238
Timestamp: 2025-05-26T10:32:15.538Z
Learning: In nitrogen balance calculations for agricultural systems, removal and volatilization are calculated as negative values by definition since they represent nitrogen losses from the system. The balance calculation uses addition (.add()) for all components because removal and volatilization are already negative, so adding them effectively subtracts the losses from the supply.

Applied to files:

  • .changeset/spicy-roses-write.md
📚 Learning: 2025-08-14T14:31:55.384Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 236
File: fdm-calculator/src/balance/nitrogen/index.ts:173-0
Timestamp: 2025-08-14T14:31:55.384Z
Learning: In nitrogen balance calculations for agricultural systems, the balance should only include ammonia emissions (emission.ammonia.total) and should not include nitrate leaching from the emission calculation. The nitrate component (emission.nitrate) should be excluded from the balance formula.

Applied to files:

  • .changeset/spicy-roses-write.md
🔇 Additional comments (1)
.changeset/spicy-roses-write.md (1)

1-3: Changeset structure and version bump look good.

The YAML frontmatter is correctly formatted, and the minor version bump is appropriate for the feature additions described in this PR.

Comment thread .changeset/spicy-roses-write.md Outdated
Copy link
Copy Markdown
Collaborator

@SvenVw SvenVw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, just a remark about the output data of the balance. Also when hovering over the chart the tooltip does not always update. Also the highlighted outline is not always visible and could be made a bit more visible, e.g. use a bigger width

Comment thread fdm-calculator/src/balance/nitrogen/emission/ammonia/fertilizers.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
fdm-app/app/components/blocks/balance/nitrogen-chart.tsx (1)

418-426: Props type has conflicting removal shape.

The base props { balanceData: { balance: number; removal: number } } expects removal to be a number, but FarmBalanceData.removal is an object { total, harvests, residues }. This intersection creates an impossible type for farm mode.

Remove the base props constraint since the discriminated union already provides the correct types:

 export function NitrogenBalanceChart(
-    props: { balanceData: { balance: number; removal: number } } & (
+    props:
         | { type: "farm"; balanceData: FarmBalanceData; fieldInput: unknown }
         | {
               type: "field"
               balanceData: FieldBalanceData
               fieldInput: FieldInput
-          }
-    ),
+          },
 ) {
🧹 Nitpick comments (1)
fdm-app/app/components/blocks/balance/nitrogen-chart.tsx (1)

440-456: Add defensive checks for tooltip payload access.

Accessing e.tooltipPayload[0].dataKey without guards could throw if the array is empty or undefined during edge cases.

     const onTooltipFocus = (e: ChartMouseEvent) => {
+        if (!e.tooltipPayload?.[0]?.dataKey) return
         const dataKey = e.tooltipPayload[0].dataKey
         if (!tooltipFocus.has(dataKey))
             setTooltipFocus(
                 (tooltipFocus) => new Set([...tooltipFocus, dataKey]),
             )
     }

     const onTooltipBlur = (e: ChartMouseEvent) => {
+        if (!e.tooltipPayload?.[0]?.dataKey) return
         const dataKey = e.tooltipPayload[0].dataKey
         if (tooltipFocus.has(dataKey))
             setTooltipFocus((tooltipFocus) => {
                 const newTooltipFocus = new Set(tooltipFocus)
                 newTooltipFocus.delete(dataKey)
                 return newTooltipFocus
             })
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e80e39f and 636a5d4.

📒 Files selected for processing (1)
  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx (2 hunks)
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 236
File: fdm-calculator/src/balance/nitrogen/index.ts:173-0
Timestamp: 2025-08-14T14:31:55.384Z
Learning: In nitrogen balance calculations for agricultural systems, the balance should only include ammonia emissions (emission.ammonia.total) and should not include nitrate leaching from the emission calculation. The nitrate component (emission.nitrate) should be excluded from the balance formula.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 143
File: fdm-app/app/components/custom/balance/nitrogen-chart.tsx:73-85
Timestamp: 2025-05-27T19:56:48.556Z
Learning: In nitrogen balance charts, supply should be in a separate stack from removal and emission. Supply represents nitrogen inputs while removal and emission represent different types of nitrogen outputs, so they should be visually grouped differently using different stackId values.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:236-238
Timestamp: 2025-05-26T10:32:15.538Z
Learning: In nitrogen balance calculations for agricultural systems, removal and volatilization are calculated as negative values by definition since they represent nitrogen losses from the system. The balance calculation uses addition (.add()) for all components because removal and volatilization are already negative, so adding them effectively subtracts the losses from the supply.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:162-168
Timestamp: 2025-05-26T10:32:00.674Z
Learning: In the nitrogen balance calculation system (fdm-calculator), removal and volatilization values are negative by definition. This means the balance calculation using supply.total.add(removal.total).add(volatilization.total) is correct, as it effectively computes supply - |removal| - |volatilization|.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 343
File: fdm-app/app/components/blocks/balance/organic-matter-chart.tsx:19-25
Timestamp: 2025-11-24T10:43:09.278Z
Learning: In the organic matter balance chart (fdm-app), degradation values are multiplied by -1 before plotting to show supply and degradation bars side-by-side with positive magnitudes, enabling direct visual comparison. This is a deliberate design choice for the organic matter chart visualization, different from the nitrogen balance chart which uses separate stacks.
📚 Learning: 2025-01-09T16:03:37.764Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 42
File: fdm-app/app/routes/farm/_b_id_farm/layout.tsx:46-95
Timestamp: 2025-01-09T16:03:37.764Z
Learning: A shared layout component `FarmLayoutBase` has been created in `components/custom/farm-layout-base.tsx` to maintain consistency across farm-related pages. The component handles farm selection dropdown, breadcrumb navigation, and provides a common layout structure.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-05-27T19:56:48.556Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 143
File: fdm-app/app/components/custom/balance/nitrogen-chart.tsx:73-85
Timestamp: 2025-05-27T19:56:48.556Z
Learning: In nitrogen balance charts, supply should be in a separate stack from removal and emission. Supply represents nitrogen inputs while removal and emission represent different types of nitrogen outputs, so they should be visually grouped differently using different stackId values.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-05-26T10:32:00.674Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:162-168
Timestamp: 2025-05-26T10:32:00.674Z
Learning: In the nitrogen balance calculation system (fdm-calculator), removal and volatilization values are negative by definition. This means the balance calculation using supply.total.add(removal.total).add(volatilization.total) is correct, as it effectively computes supply - |removal| - |volatilization|.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-05-26T10:32:15.538Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:236-238
Timestamp: 2025-05-26T10:32:15.538Z
Learning: In nitrogen balance calculations for agricultural systems, removal and volatilization are calculated as negative values by definition since they represent nitrogen losses from the system. The balance calculation uses addition (.add()) for all components because removal and volatilization are already negative, so adding them effectively subtracts the losses from the supply.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-11-24T10:43:09.278Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 343
File: fdm-app/app/components/blocks/balance/organic-matter-chart.tsx:19-25
Timestamp: 2025-11-24T10:43:09.278Z
Learning: In the organic matter balance chart (fdm-app), degradation values are multiplied by -1 before plotting to show supply and degradation bars side-by-side with positive magnitudes, enabling direct visual comparison. This is a deliberate design choice for the organic matter chart visualization, different from the nitrogen balance chart which uses separate stacks.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-08-11T11:55:26.053Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 233
File: fdm-app/app/integrations/nmi.ts:54-0
Timestamp: 2025-08-11T11:55:26.053Z
Learning: The NMI API Estimates endpoint (`https://api.nmi-agro.nl/estimates`) always returns the fields `b_gwl_ghg`, `b_gwl_glg`, and `cultivations` according to its specification. These fields should be kept as required (not optional) in the TypeScript return type and Zod validation schema in `fdm-app/app/integrations/nmi.ts`.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
🔇 Additional comments (4)
fdm-app/app/components/blocks/balance/nitrogen-chart.tsx (4)

1-29: LGTM!

Type aliases derived from Awaited<ReturnType<...>> ensure type consistency with the calculator module. The ApplicationChartConfigItem type is well-structured with appropriate optional fields.


149-184: LGTM!

Farm mode data population correctly handles fertilizer types and aggregates values. The per-fertilizer breakdown aligns with the PR objectives to enhance the nitrogen balance chart with detailed event contributions.


186-257: Well-structured helper functions for field mode.

The addFertilizerApplication and addCultivation helpers cleanly handle dynamic dataKey construction and config population. The fallback to "onbekend" for missing application/cultivation data provides graceful degradation.


629-630: Correct stack separation for supply vs removal/emission.

Using different stackId values ("a" for supply, "b" for removal/emission) correctly groups nitrogen inputs separately from outputs, aligning with the established chart design pattern. Based on learnings, supply represents nitrogen inputs while removal and emission represent different types of nitrogen outputs.

Comment thread fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
fdm-calculator/src/balance/nitrogen/types.d.ts (2)

186-199: Shared fertilizer emission type looks good; consider numeric twin and unit note

The NitrogenEmissionFertilizer helper nicely centralizes the { total, applications[] } shape used for fertilizer emissions. For symmetry and future refactors, you could:

  • Introduce a NitrogenEmissionFertilizerNumeric and use it in NitrogenEmissionAmmoniaFertilizersNumeric to DRY the numeric side.
  • Optionally mirror other docs by explicitly stating the kg N/ha units in this JSDoc, even though it is indirectly covered by the parent ammonia type.

228-248: Aggregated NitrogenEmissionAmmoniaFertilizersTotal matches intended chart aggregate; consider a numeric alias

The aggregate { total, mineral, manure, compost, other } shape is exactly what you need for farm-level/chart summaries and cleanly separates it from the per-application structure.

To keep Decimal and numeric models parallel and avoid repeating this shape, consider adding a NitrogenEmissionAmmoniaFertilizersTotalNumeric and using it in NitrogenBalanceNumeric.emission.ammonia.fertilizers.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4c6a5cc and c524ddf.

📒 Files selected for processing (1)
  • fdm-calculator/src/balance/nitrogen/types.d.ts (4 hunks)
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 143
File: fdm-app/app/components/custom/balance/nitrogen-chart.tsx:73-85
Timestamp: 2025-05-27T19:56:48.556Z
Learning: In nitrogen balance charts, supply should be in a separate stack from removal and emission. Supply represents nitrogen inputs while removal and emission represent different types of nitrogen outputs, so they should be visually grouped differently using different stackId values.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 236
File: fdm-calculator/src/balance/nitrogen/index.ts:173-0
Timestamp: 2025-08-14T14:31:55.384Z
Learning: In nitrogen balance calculations for agricultural systems, the balance should only include ammonia emissions (emission.ammonia.total) and should not include nitrate leaching from the emission calculation. The nitrate component (emission.nitrate) should be excluded from the balance formula.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:236-238
Timestamp: 2025-05-26T10:32:15.538Z
Learning: In nitrogen balance calculations for agricultural systems, removal and volatilization are calculated as negative values by definition since they represent nitrogen losses from the system. The balance calculation uses addition (.add()) for all components because removal and volatilization are already negative, so adding them effectively subtracts the losses from the supply.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:162-168
Timestamp: 2025-05-26T10:32:00.674Z
Learning: In the nitrogen balance calculation system (fdm-calculator), removal and volatilization values are negative by definition. This means the balance calculation using supply.total.add(removal.total).add(volatilization.total) is correct, as it effectively computes supply - |removal| - |volatilization|.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 343
File: fdm-app/app/components/blocks/balance/organic-matter-chart.tsx:19-25
Timestamp: 2025-11-24T10:43:09.278Z
Learning: In the organic matter balance chart (fdm-app), degradation values are multiplied by -1 before plotting to show supply and degradation bars side-by-side with positive magnitudes, enabling direct visual comparison. This is a deliberate design choice for the organic matter chart visualization, different from the nitrogen balance chart which uses separate stacks.
📚 Learning: 2025-08-14T14:31:55.384Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 236
File: fdm-calculator/src/balance/nitrogen/index.ts:173-0
Timestamp: 2025-08-14T14:31:55.384Z
Learning: In nitrogen balance calculations for agricultural systems, the balance should only include ammonia emissions (emission.ammonia.total) and should not include nitrate leaching from the emission calculation. The nitrate component (emission.nitrate) should be excluded from the balance formula.

Applied to files:

  • fdm-calculator/src/balance/nitrogen/types.d.ts
📚 Learning: 2025-08-11T11:55:26.053Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 233
File: fdm-app/app/integrations/nmi.ts:54-0
Timestamp: 2025-08-11T11:55:26.053Z
Learning: The NMI API Estimates endpoint (`https://api.nmi-agro.nl/estimates`) always returns the fields `b_gwl_ghg`, `b_gwl_glg`, and `cultivations` according to its specification. These fields should be kept as required (not optional) in the TypeScript return type and Zod validation schema in `fdm-app/app/integrations/nmi.ts`.

Applied to files:

  • fdm-calculator/src/balance/nitrogen/types.d.ts
📚 Learning: 2025-05-26T10:32:00.674Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:162-168
Timestamp: 2025-05-26T10:32:00.674Z
Learning: In the nitrogen balance calculation system (fdm-calculator), removal and volatilization values are negative by definition. This means the balance calculation using supply.total.add(removal.total).add(volatilization.total) is correct, as it effectively computes supply - |removal| - |volatilization|.

Applied to files:

  • fdm-calculator/src/balance/nitrogen/types.d.ts
📚 Learning: 2025-08-13T10:33:05.313Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 0
File: :0-0
Timestamp: 2025-08-13T10:33:05.313Z
Learning: In the fdm project, fdm-calculator integration for new features like b_lu_variety is handled in separate updates from the core data model changes. When fdm-core functions are updated to support new fields, fdm-calculator can consume these enhanced APIs without requiring changes in the same PR that introduces the core functionality.

Applied to files:

  • fdm-calculator/src/balance/nitrogen/types.d.ts
📚 Learning: 2025-05-27T19:56:48.556Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 143
File: fdm-app/app/components/custom/balance/nitrogen-chart.tsx:73-85
Timestamp: 2025-05-27T19:56:48.556Z
Learning: In nitrogen balance charts, supply should be in a separate stack from removal and emission. Supply represents nitrogen inputs while removal and emission represent different types of nitrogen outputs, so they should be visually grouped differently using different stackId values.

Applied to files:

  • fdm-calculator/src/balance/nitrogen/types.d.ts
📚 Learning: 2025-05-26T10:32:15.538Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:236-238
Timestamp: 2025-05-26T10:32:15.538Z
Learning: In nitrogen balance calculations for agricultural systems, removal and volatilization are calculated as negative values by definition since they represent nitrogen losses from the system. The balance calculation uses addition (.add()) for all components because removal and volatilization are already negative, so adding them effectively subtracts the losses from the supply.

Applied to files:

  • fdm-calculator/src/balance/nitrogen/types.d.ts
🔇 Additional comments (2)
fdm-calculator/src/balance/nitrogen/types.d.ts (2)

205-225: Refactor to NitrogenEmissionFertilizer in ammonia sources is type-safe and reduces duplication

Using NitrogenEmissionFertilizer for mineral, manure, compost, and other keeps these sources consistent and matches the existing numeric shape (total + applications). This is a clean, non-breaking refactor from a typing perspective.


370-382: Nested supply/removal/emission aggregates look consistent; please re-check balance formula and sign conventions

The new nested structures in NitrogenBalance and NitrogenBalanceNumeric (per-source supply, per-cause removal, and ammonia emission aggregates) are internally consistent and mirror each other well, which should work nicely for the enhanced charting.

Please double-check in the calculator logic (index.ts and tests) that:

  • supply.* remains positive, while removal.* and emission.ammonia.* still use negative values as before.
  • The overall balance continues to use emission.ammonia.total only (excluding nitrate) together with supply.total and removal.total when computing balance.

Based on learnings, removal and volatilization are negative by definition and nitrate emissions must be excluded from the nitrogen balance formula.

Also applies to: 386-390, 396-400, 624-636, 637-641, 644-654

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
fdm-app/app/components/blocks/balance/nitrogen-chart.tsx (2)

75-81: Fix CSS variable syntax for fixation legend color

farmFixationLegend.fixation.color is missing the closing ) in the var() call:

color: "var(--color-slate-400",

This makes the CSS value invalid and will break the color for that legend and any styles inheriting from it.

-            color: "var(--color-slate-400",
+            color: "var(--color-slate-400)",

418-427: Base props type for balanceData.removal conflicts with farm data shape

The component props are currently:

export function NitrogenBalanceChart(
    props: { balanceData: { balance: number; removal: number } } & (
        | { type: "farm"; balanceData: FarmBalanceData; ... }
        | { type: "field"; balanceData: FieldBalanceData; ... }
    ),
) { ... }

But in farm mode, FarmBalanceData.removal is now { total, harvests, residues }, not a number. This base { balanceData: { balance: number; removal: number } } intersection makes balanceData.removal an impossible type and adds confusion, even though buildChartDataAndLegend uses the more precise union type.

You can simplify and avoid this conflict by dropping the rigid base:

-export function NitrogenBalanceChart(
-    props: { balanceData: { balance: number; removal: number } } & (
+export function NitrogenBalanceChart(
+    props:
         | { type: "farm"; balanceData: FarmBalanceData; fieldInput: unknown }
         | {
               type: "field"
               balanceData: FieldBalanceData
               fieldInput: FieldInput
           }
-    ),
+    ,
) {
🧹 Nitpick comments (1)
fdm-app/app/components/blocks/balance/nitrogen-chart.tsx (1)

541-587: Tooltip content correctly reuses chartConfig but depends on chartData key presence

The custom ChartTooltip content uses tooltipFocus plus chartConfig and chartData to show a detail card. Structurally this is solid and gives a nice, consistent view (label, detail lines from detail[], unit fallback to "kg N / ha").

Just be aware this assumes every tooltipFocus value always exists as a key in both chartConfig and chartData. Given how buildChartDataAndLegend constructs them, that should hold, but if new bar keys are added later without corresponding config/data entries, this will silently render incomplete info. Worth keeping in mind when extending the chart.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c524ddf and 413e39b.

📒 Files selected for processing (2)
  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx (2 hunks)
  • fdm-calculator/src/balance/nitrogen/types.d.ts (3 hunks)
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 0
File: :0-0
Timestamp: 2025-08-13T10:33:05.313Z
Learning: In the fdm project, fdm-calculator integration for new features like b_lu_variety is handled in separate updates from the core data model changes. When fdm-core functions are updated to support new fields, fdm-calculator can consume these enhanced APIs without requiring changes in the same PR that introduces the core functionality.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 143
File: fdm-app/app/components/custom/balance/nitrogen-chart.tsx:73-85
Timestamp: 2025-05-27T19:56:48.556Z
Learning: In nitrogen balance charts, supply should be in a separate stack from removal and emission. Supply represents nitrogen inputs while removal and emission represent different types of nitrogen outputs, so they should be visually grouped differently using different stackId values.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 236
File: fdm-calculator/src/balance/nitrogen/index.ts:173-0
Timestamp: 2025-08-14T14:31:55.384Z
Learning: In nitrogen balance calculations for agricultural systems, the balance should only include ammonia emissions (emission.ammonia.total) and should not include nitrate leaching from the emission calculation. The nitrate component (emission.nitrate) should be excluded from the balance formula.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:236-238
Timestamp: 2025-05-26T10:32:15.538Z
Learning: In nitrogen balance calculations for agricultural systems, removal and volatilization are calculated as negative values by definition since they represent nitrogen losses from the system. The balance calculation uses addition (.add()) for all components because removal and volatilization are already negative, so adding them effectively subtracts the losses from the supply.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 343
File: fdm-app/app/components/blocks/balance/organic-matter-chart.tsx:19-25
Timestamp: 2025-11-24T10:43:09.278Z
Learning: In the organic matter balance chart (fdm-app), degradation values are multiplied by -1 before plotting to show supply and degradation bars side-by-side with positive magnitudes, enabling direct visual comparison. This is a deliberate design choice for the organic matter chart visualization, different from the nitrogen balance chart which uses separate stacks.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:162-168
Timestamp: 2025-05-26T10:32:00.674Z
Learning: In the nitrogen balance calculation system (fdm-calculator), removal and volatilization values are negative by definition. This means the balance calculation using supply.total.add(removal.total).add(volatilization.total) is correct, as it effectively computes supply - |removal| - |volatilization|.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 274
File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:160-163
Timestamp: 2025-09-23T12:29:34.184Z
Learning: In the FDM application, the fertilizer application route intentionally uses `${calendar}/field/fertilizer` instead of the originally planned `/farm/{farmId}/add/fertilizer` structure. This design decision prioritizes starting from the field list view to provide better field selection workflow before applying fertilizer, rather than direct dashboard-to-action navigation.
📚 Learning: 2025-05-27T19:56:48.556Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 143
File: fdm-app/app/components/custom/balance/nitrogen-chart.tsx:73-85
Timestamp: 2025-05-27T19:56:48.556Z
Learning: In nitrogen balance charts, supply should be in a separate stack from removal and emission. Supply represents nitrogen inputs while removal and emission represent different types of nitrogen outputs, so they should be visually grouped differently using different stackId values.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
  • fdm-calculator/src/balance/nitrogen/types.d.ts
📚 Learning: 2025-01-09T16:03:37.764Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 42
File: fdm-app/app/routes/farm/_b_id_farm/layout.tsx:46-95
Timestamp: 2025-01-09T16:03:37.764Z
Learning: A shared layout component `FarmLayoutBase` has been created in `components/custom/farm-layout-base.tsx` to maintain consistency across farm-related pages. The component handles farm selection dropdown, breadcrumb navigation, and provides a common layout structure.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-05-26T10:32:00.674Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:162-168
Timestamp: 2025-05-26T10:32:00.674Z
Learning: In the nitrogen balance calculation system (fdm-calculator), removal and volatilization values are negative by definition. This means the balance calculation using supply.total.add(removal.total).add(volatilization.total) is correct, as it effectively computes supply - |removal| - |volatilization|.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
  • fdm-calculator/src/balance/nitrogen/types.d.ts
📚 Learning: 2025-05-26T10:32:15.538Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 134
File: fdm-calculator/src/balance/nitrogen/index.ts:236-238
Timestamp: 2025-05-26T10:32:15.538Z
Learning: In nitrogen balance calculations for agricultural systems, removal and volatilization are calculated as negative values by definition since they represent nitrogen losses from the system. The balance calculation uses addition (.add()) for all components because removal and volatilization are already negative, so adding them effectively subtracts the losses from the supply.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
  • fdm-calculator/src/balance/nitrogen/types.d.ts
📚 Learning: 2025-11-24T10:43:09.278Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 343
File: fdm-app/app/components/blocks/balance/organic-matter-chart.tsx:19-25
Timestamp: 2025-11-24T10:43:09.278Z
Learning: In the organic matter balance chart (fdm-app), degradation values are multiplied by -1 before plotting to show supply and degradation bars side-by-side with positive magnitudes, enabling direct visual comparison. This is a deliberate design choice for the organic matter chart visualization, different from the nitrogen balance chart which uses separate stacks.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
📚 Learning: 2025-08-11T11:55:26.053Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 233
File: fdm-app/app/integrations/nmi.ts:54-0
Timestamp: 2025-08-11T11:55:26.053Z
Learning: The NMI API Estimates endpoint (`https://api.nmi-agro.nl/estimates`) always returns the fields `b_gwl_ghg`, `b_gwl_glg`, and `cultivations` according to its specification. These fields should be kept as required (not optional) in the TypeScript return type and Zod validation schema in `fdm-app/app/integrations/nmi.ts`.

Applied to files:

  • fdm-app/app/components/blocks/balance/nitrogen-chart.tsx
  • fdm-calculator/src/balance/nitrogen/types.d.ts
📚 Learning: 2025-08-14T14:31:55.384Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 236
File: fdm-calculator/src/balance/nitrogen/index.ts:173-0
Timestamp: 2025-08-14T14:31:55.384Z
Learning: In nitrogen balance calculations for agricultural systems, the balance should only include ammonia emissions (emission.ammonia.total) and should not include nitrate leaching from the emission calculation. The nitrate component (emission.nitrate) should be excluded from the balance formula.

Applied to files:

  • fdm-calculator/src/balance/nitrogen/types.d.ts
🧬 Code graph analysis (1)
fdm-app/app/components/blocks/balance/nitrogen-chart.tsx (4)
fdm-calculator/src/balance/nitrogen/types.d.ts (1)
  • FieldInput (460-480)
fdm-calculator/src/balance/nitrogen/index.ts (1)
  • getNitrogenBalance (129-133)
fdm-core/src/index.ts (2)
  • addFertilizerApplication (84-84)
  • addCultivation (45-45)
fdm-app/app/components/custom/cultivation-colors.ts (1)
  • getCultivationColor (20-28)
🔇 Additional comments (6)
fdm-calculator/src/balance/nitrogen/types.d.ts (3)

253-274: Totals-only fertilizer ammonia type looks consistent with detailed per-source shape

NitrogenEmissionAmmoniaFertilizersTotal cleanly mirrors the per-type keys of NitrogenEmissionAmmoniaFertilizers while intentionally omitting per-application arrays, which is appropriate for farm-level aggregation and chart usage. No issues from a type-shape perspective.


395-407: Farm-level NitrogenBalance structure matches intended breakdown

The new NitrogenBalance.supply, removal, and emission.ammonia objects give exactly the farm-level totals you need for the chart (per-source supply, per-loss-category removal, per-fertilizer and residue ammonia totals) while staying compatible with the field-level detailed types. This aligns with the PR objective to expose fertilizer-type and residues/harvest/fixation contributions explicitly.

Please double-check all fdm-calculator callers that previously treated supply, removal, or emission.ammonia as plain Decimal/number are updated to use the new nested shape, especially any serialization or API response mapping.

Also applies to: 411-415, 421-425


649-661: Numeric NitrogenBalance mirrors Decimal structure correctly

NitrogenBalanceNumeric’s supply, removal, and emission.ammonia structures are the numeric counterparts of the updated NitrogenBalance type (including per-fertilizer totals and residue ammonia), which will keep calculator outputs and fdm-app consumption in sync. The per-type keys are consistent across Decimal and numeric forms.

Also applies to: 662-666, 669-679

fdm-app/app/components/blocks/balance/nitrogen-chart.tsx (3)

162-183: Farm-mode aggregation logic for fixation, removal, and fertilizer breakdown looks sound

The farm branch correctly:

  • Uses supply.fixation, removal.harvests, removal.residues, and emission.ammonia.residues as already-aggregated farm totals.
  • Iterates ["mineral","manure","compost","other"] to populate supply and ammonia emissions per fertilizer type from the new supply.fertilizers and emission.ammonia.fertilizers maps.
  • Applies Math.abs to keep bar magnitudes positive while still respecting the sign semantics from the calculator.

This matches the new farm-level NitrogenBalanceNumeric structure and the PR goal of exposing per-fertilizer and residues/harvest contributions.


395-415: Supply vs removal/emission are correctly split into separate stacks

supplyBar and allRemovalBar are rendered with different stackId values ("a" and "b"), so supply is visually separated from removal and emission as per the nitrogen chart design guidelines. The way you compose supplyBar and allRemovalBar (including nitrate, fertilizer ammonia, and residues) matches the new balance breakdown and keeps the stacking semantics clear.

Also applies to: 619-620


1-8: Fix date-fns import and correct FieldInput type alias

Two critical issues:

  1. date-fns import is invalid
    import { format } from "date-fns/format" mixes named import syntax with a subpath, which will fail at build time. Use:
import { format } from "date-fns"
  1. FieldInput type alias is wrong
    Line 19 aliases FieldInput to the entire NitrogenBalanceInput (which has shape { fields: FieldInput[], fertilizerDetails, cultivationDetails, timeFrame }), but the component uses per-field properties like fieldInput.fertilizerApplications, fieldInput.cultivations, and fieldInput.harvests. These belong to the per-field FieldInput type, not the wrapper. Correct the alias to:
type FieldInput = Awaited<ReturnType<typeof collectInputForNitrogenBalance>>["fields"][number]

Alternatively, import the actual FieldInput type directly from @svenvw/fdm-calculator.

⛔ Skipped due to learnings
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 138
File: fdm-app/app/components/custom/combobox.tsx:34-37
Timestamp: 2025-05-09T14:58:10.465Z
Learning: When updating React components that use both react-hook-form and React Router v7, it's important to only import types (like UseFormReturn, FieldValues) from react-hook-form to avoid naming conflicts with React Router's Form component. Use `import type { ... } from 'react-hook-form'` syntax to ensure only types are imported.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 233
File: fdm-app/app/integrations/nmi.ts:54-0
Timestamp: 2025-08-11T11:55:26.053Z
Learning: The NMI API Estimates endpoint (`https://api.nmi-agro.nl/estimates`) always returns the fields `b_gwl_ghg`, `b_gwl_glg`, and `cultivations` according to its specification. These fields should be kept as required (not optional) in the TypeScript return type and Zod validation schema in `fdm-app/app/integrations/nmi.ts`.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 75
File: fdm-app/app/routes/farm.$b_id_farm.field.$b_id.fertilizer.tsx:68-71
Timestamp: 2025-02-14T09:56:37.606Z
Learning: The `calculateDose` function in `svenvw/fdm-calculator` is a synchronous function that includes built-in validation for negative application amounts and nutrient rates.
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 156
File: fdm-calculator/src/norms/nl/2025/stikstofgebruiksnorm.ts:295-303
Timestamp: 2025-07-21T12:06:07.070Z
Learning: Functions in the fdm-calculator with "NL2025" in their names are specifically designed for Netherlands 2025 agricultural norms calculation and hardcoded 2025 dates are appropriate in this context, as different years would have separate calculation modules.

Comment on lines +186 to +221
if (type === "field") {
type ExtendedChartConfig = Record<string, ApplicationChartConfigItem>

function addFertilizerApplication(
fieldInput: FieldInput,
dataKeyPrefix: string,
label: string,
applicationResult: { id: string; value: number },
unit: string,
bar: BarDataType,
) {
const dataKey = `${dataKeyPrefix}_${applicationResult.id}`
const application = fieldInput.fertilizerApplications.find(
(fa: { p_app_id: string }) =>
fa.p_app_id === applicationResult.id,
)
chartData[dataKey] = Math.abs(applicationResult.value)
;(chartConfig as ExtendedChartConfig)[dataKey] = application
? {
styleId: dataKeyPrefix,
label: label,
unit: unit,
detail: [
application.p_name_nl,
format(application.p_app_date, "PP", {
locale: nl,
}),
],
}
: {
styleId: dataKeyPrefix,
label: label,
unit: unit,
detail: ["onbekend"],
}
bar.push(dataKey)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find the FieldInput type definition and related files
fd -t f "(FieldInput|cultivation|harvest)" --extension ts --extension tsx | head -20

Repository: SvenVw/fdm

Length of output: 1596


🏁 Script executed:

# Search for FieldInput type definition
rg "type FieldInput|interface FieldInput" -A 10 --max-count 5

Repository: SvenVw/fdm

Length of output: 2829


🏁 Script executed:

# Look at the nitrogen-chart.tsx file to see what properties are being accessed
cat -n fdm-app/app/components/blocks/balance/nitrogen-chart.tsx | head -100

Repository: SvenVw/fdm

Length of output: 3852


🏁 Script executed:

# Read the nitrogen-chart.tsx file to see the specific code at lines 186-221 and beyond
sed -n '180,400p' fdm-app/app/components/blocks/balance/nitrogen-chart.tsx | cat -n

Repository: SvenVw/fdm

Length of output: 9283


🏁 Script executed:

# Look at the full FieldInput type definition in nitrogen types
cat -n fdm-calculator/src/balance/nitrogen/types.d.ts | head -80

Repository: SvenVw/fdm

Length of output: 3195


🏁 Script executed:

# Search for collectInputForNitrogenBalance to understand how FieldInput is constructed
rg "collectInputForNitrogenBalance" -A 30 --max-count 2

Repository: SvenVw/fdm

Length of output: 34605


🏁 Script executed:

# Read the collectInputForNitrogenBalance implementation to see what is actually returned
sed -n '1,150p' fdm-calculator/src/balance/nitrogen/input.ts | cat -n

Repository: SvenVw/fdm

Length of output: 6543


🏁 Script executed:

# Look at FertilizerApplication and Harvest types from fdm-core
rg "type FertilizerApplication|interface FertilizerApplication" -A 15 --max-count 2

Repository: SvenVw/fdm

Length of output: 13543


🏁 Script executed:

# Look for Harvest type definition
rg "type Harvest|interface Harvest" -A 20 --max-count 2

Repository: SvenVw/fdm

Length of output: 14680


🏁 Script executed:

# Look for Cultivation type definition in fdm-core
rg "interface Cultivation|type Cultivation" -A 20 fdm-core/src/

Repository: SvenVw/fdm

Length of output: 4053


🏁 Script executed:

# Check getCultivations function return type
rg "export.*getCultivations|function getCultivations" -A 10

Repository: SvenVw/fdm

Length of output: 1281


🏁 Script executed:

# Verify what the nitrogen/types.d.ts actually declares for FieldInput
cat -n fdm-calculator/src/balance/nitrogen/types.d.ts | grep -A 30 "export type FieldInput"

Repository: SvenVw/fdm

Length of output: 1143


Update nitrogen balance types to reflect actual data used in charts

The FieldInput type in fdm-calculator/src/balance/nitrogen/types.d.ts declares cultivations as a Pick<Cultivation, "b_lu" | "b_lu_start" | "b_lu_end" | "b_lu_catalogue" | "m_cropresidue">, but the nitrogen chart component accesses b_lu_name and b_lu_croprotation directly on cultivation objects (lines 63, 67, 74). While collectInputForNitrogenBalance returns full Cultivation objects at runtime, the type definition should include these properties to ensure type safety and clarity. Either expand the Pick to include "b_lu_name" | "b_lu_croprotation" if they are always present, or document why the type intentionally restricts these fields and adjust the chart component to always access them through b_lu_catalogue instead.

Comment on lines +436 to +452
type ChartMouseEvent = {
tooltipPayload: { dataKey: string }[]
}

const onTooltipFocus = (e: ChartMouseEvent) => {
const dataKey = e.tooltipPayload[0].dataKey
if (tooltipFocus !== dataKey) setTooltipFocus(dataKey)
}

const onTooltipBlur = (e: ChartMouseEvent) => {
const dataKey = e.tooltipPayload[0].dataKey
if (tooltipFocus === dataKey) setTooltipFocus(undefined)
}

const clearTooltipFocus = () => {
setTooltipFocus(undefined)
}
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find the file and check its size
wc -l fdm-app/app/components/blocks/balance/nitrogen-chart.tsx

Repository: SvenVw/fdm

Length of output: 114


🏁 Script executed:

# Find Recharts version
find . -name "package.json" -type f | head -5 | xargs grep -l "recharts" 2>/dev/null

Repository: SvenVw/fdm

Length of output: 76


🏁 Script executed:

# Look at the actual file around the mentioned lines
cat -n fdm-app/app/components/blocks/balance/nitrogen-chart.tsx | sed -n '430,530p'

Repository: SvenVw/fdm

Length of output: 4329


🏁 Script executed:

# Check Recharts version in package.json
grep -A 2 -B 2 "recharts" fdm-app/package.json

Repository: SvenVw/fdm

Length of output: 226


🏁 Script executed:

# Check lines around 621-629 mentioned in "Also applies to"
cat -n fdm-app/app/components/blocks/balance/nitrogen-chart.tsx | sed -n '615,635p'

Repository: SvenVw/fdm

Length of output: 774


🏁 Script executed:

# Look for Recharts imports and any type definitions used
head -50 fdm-app/app/components/blocks/balance/nitrogen-chart.tsx

Repository: SvenVw/fdm

Length of output: 1649


🌐 Web query:

Recharts 2.15.4 Bar component onMouseEnter onMouseLeave event type shape

💡 Result:

Signature: (payload: any, index: number, event: React.MouseEvent<SVGElement, MouseEvent>) => void.

In other words, Bar's onMouseEnter / onMouseLeave are called with (dataItem, itemIndex, reactMouseEvent). [1][2][3]

Sources:

  • Recharts Bar API (events documented). [1]
  • Recharts Pie example/discussion showing handlers receive (payload, index, event). [2]
  • Community TypeScript example showing Bar event typing (data: any, index: number, event: React.MouseEvent). [3]

References:
[1] https://recharts.github.io/en-US/api/Bar/
[2] recharts/recharts#4098
[3] https://blog.csdn.net/gitblog_01229/article/details/143039759


🌐 Web query:

Recharts Bar component event handler payload structure tooltipPayload

💡 Result:

Short answer — Bar event handlers receive (data, index, event). The first argument is the "entry" / graphical item for that bar; the tooltip payload (what Tooltip renders) is an array of objects shaped like:

  • name: string (label shown)
  • value: number | string (formatted/unformatted value)
  • payload: object (the original data object for that x/tick)
  • dataKey: string | number (the Bar's dataKey)
  • unit?: string
  • color/stroke/fill?: string (series color)
  • others depending on formatter/customizations

Example onMouseEnter signature and how you might read tooltip info:
onMouseEnter={(entry, index, e) => {
// entry often looks like: { value: 2400, payload: { name: 'Page A', uv: 2400, pv: 2400 }, dataKey: 'uv', name: 'uv', color: '#8884d8' }
// Tooltip payload (Tooltip.props.payload) is an array of similar objects:
// [{ name:'Page A', value:2400, unit:'kg', payload: {...}, dataKey:'uv', fill:'#8884d8' }]
}}

Sources: Recharts Tooltip API (payload/coordinate/label shape) and Bar docs (event handler signatures). [1][2].

References
[1] Recharts — Tooltip API (payload examples and fields).
[2] Recharts — Bar API (event handler signatures and dataKey/name/unit usage).


🏁 Script executed:

# Verify if tooltipPayload is used anywhere else in the file
grep -n "tooltipPayload" fdm-app/app/components/blocks/balance/nitrogen-chart.tsx

Repository: SvenVw/fdm

Length of output: 215


🏁 Script executed:

# Double-check the exact handler usage with onMouseEnter/onMouseLeave
grep -n "onMouseEnter\|onMouseLeave" fdm-app/app/components/blocks/balance/nitrogen-chart.tsx

Repository: SvenVw/fdm

Length of output: 366


Recharts Bar event handlers use incorrect event shape

The onTooltipFocus and onTooltipBlur handlers assume a tooltipPayload structure that Recharts Bar components do not provide. Recharts 2.15.4 Bar onMouseEnter/onMouseLeave handlers receive (dataItem, index, event) where dataItem is an object containing the dataKey property directly, not a tooltipPayload array.

The current code will throw a runtime error when hovering over bars:

const dataKey = e.tooltipPayload[0].dataKey  // ❌ e.tooltipPayload is undefined

Use destructuring to access dataKey directly:

const onTooltipFocus = ({ dataKey }: { dataKey: string }) => {
    if (dataKey && tooltipFocus !== dataKey) setTooltipFocus(dataKey)
}

const onTooltipBlur = ({ dataKey }: { dataKey: string }) => {
    if (dataKey && tooltipFocus === dataKey) setTooltipFocus(undefined)
}

Remove the incorrect ChartMouseEvent type definition and update the handlers at lines 440–448 and their usages at lines 497–498 and 515–516.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi. Are you sure you actually checked the Recharts 2 documentation for this? If so can you give a link to the documentation?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🌐 Web query:

Recharts Bar component official documentation onMouseEnter event handler signature

💡 Result:

Short answer: the handler signature is (data, index, event) — e.g. onMouseEnter={(data, index, e) => { ... }}. Source: Bar API lists onMouseEnter prop, and Recharts' internal dispatch helpers call handlers with (data, index, e). [1][2]

Sources:

  • Recharts Bar API (onMouseEnter prop). [1]
  • Explanation / excerpt from Recharts source showing handlers invoked as (data, index, React.MouseEvent). [2]

🌐 Web query:

recharts.org Bar API documentation URL

💡 Result:

The Bar API docs are at: https://recharts.github.io/en-US/api/Bar/ [1]

Related BarChart page: https://recharts.github.io/en-US/api/BarChart/ [2]

Sources:
[1] Recharts — Bar API.
[2] Recharts — BarChart API.


🌐 Web query:

Recharts Bar onMouseEnter data parameter properties dataKey

💡 Result:

Short answer: Bar's onMouseEnter handler receives (data, index, event).

  • data — the datum for the hovered bar (the object/value resolved by the Bar's dataKey).
  • index — the index of that datum in the chart data array.
  • event — the native mouse event (optional third argument).

Example:
<Bar dataKey="value" onMouseEnter={(data, index, event) => { /* data.value or data['valueKey'] */ }} />

Sources: Recharts Bar API (props & dataKey) and common examples showing onMouseEnter usage. [1][2]

References

  1. Recharts Bar API (dataKey / props). [1]
  2. Example usage showing onMouseEnter((data, index) => …). [2]

🌐 Web query:

Recharts Bar onMouseEnter how to get which dataKey bar was hovered

💡 Result:

Use the Bar's event handler args (data, index, event) or capture the Bar's dataKey in a closure. Example patterns:

  1. Handler receives the hovered bar's datum and index — you can derive dataKey from index or datum:
    const handleEnter = (datum, index, e) => {
    // datum is the row object for that bar; index is the bar's index
    console.log(datum, index);
    };
    . [1][2]

  2. If you need the Bar's dataKey (when multiple Bars), capture it in the handler/closure:
    const onBarEnter = dataKey => (datum, index, e) => {
    console.log('hovered dataKey:', dataKey, 'value:', datum[dataKey]);
    };
    <Bar dataKey="pv" onMouseEnter={onBarEnter('pv')} />
    <Bar dataKey="uv" onMouseEnter={onBarEnter('uv')} />. [1][3]

  3. Another common pattern: store the hovered dataKey via onMouseOver/onMouseEnter and read it from the Tooltip's payload (custom tooltip uses payload entries with .dataKey). [2]

References:

  • Recharts Bar API (events/props). [1]
  • Examples using onMouseEnter/onMouseOver to detect hovered bar and index/assign a dataKey to a tooltip. [2][3]

🏁 Script executed:

#!/bin/bash
# Check the chart component implementation to see if it's shadcn/ui or custom
cat fdm-app/app/components/ui/chart.tsx | head -100

Length of output: 67


🏁 Script executed:

#!/bin/bash
# Find chart component files
fd -e tsx -e ts "chart" fdm-app/app/components/ui/

Length of output: 113


🏁 Script executed:

#!/bin/bash
# Find chart component files in the app
fd -t f "chart" fdm-app/app/components/

Length of output: 119


🏁 Script executed:

#!/bin/bash
# Check the imports structure and find chart ui components
rg -n "ChartContainer|ChartTooltip|ChartLegend" fdm-app/app/components/ -A 2 -B 2 | head -50

Length of output: 3775


🏁 Script executed:

#!/bin/bash
# Find the chart.tsx or chart.ts file in ui components
find fdm-app -name "chart.tsx" -o -name "chart.ts" | head -5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if chart components might be installed via a package
grep -r "shadcn\|@/components/ui/chart" fdm-app/package.json fdm-app/components.json 2>/dev/null || echo "Not found in config"

Length of output: 75


🌐 Web query:

shadcn/ui chart component Recharts Bar onMouseEnter event handler

💡 Result:

Short answer: Use Recharts' onMouseEnter on the Bar (or BarChart) exactly as you would in Recharts — shadcn/ui's Chart components are just Recharts + small helpers. Attach an onMouseEnter handler to ; the handler receives (data, index, event) and you can use that to show/move a custom Tooltip or update component state.

Minimal example (inside a shadcn ChartContainer):

"use client"
import { Bar, BarChart, XAxis, Tooltip } from "recharts"
import { ChartContainer, ChartTooltipContent } from "@/components/ui/chart"

const data = [{ month: "Jan", value: 10 }, { month: "Feb", value: 20 }]

export function MyChart() {
  const handleBarEnter = (datum, index, e) => {
    // datum = hovered bar's data object
    // index = index in data array
    // e = mouse event (contains e.x, e.y for positioning)
    console.log(datum, index, e.clientX, e.clientY)
    // e.g. set tooltip position or mark active index
  }

  return (
    <ChartContainer className="min-h-[200px] w-full">
      <BarChart data={data}>
        <XAxis dataKey="month" />
        <Tooltip content={<ChartTooltipContent />} />
        <Bar dataKey="value" fill="var(--chart-1)" onMouseEnter={handleBarEnter} />
      </BarChart>
    </ChartContainer>
  )
}

References:

  • shadcn/ui charts use Recharts and expose ChartContainer/ChartTooltip helpers. [1]
  • Recharts Bar API (lists onMouseEnter/onMouseLeave for Bar and event handlers for charts). [2]
  • Example pattern: capture e.x/e.y in Bar onMouseEnter to position a custom Tooltip. [3]

Sources:
[1] shadcn/ui Chart docs.
[2] Recharts Bar API docs.
[3] Recharts examples / community guidance on using Bar onMouseEnter to position tooltip.


@BoraIneviNMI, yes, I checked the official Recharts documentation. The official Recharts Bar API documentation is available at:

https://recharts.github.io/en-US/api/Bar/

According to the official documentation and multiple sources, the onMouseEnter and onMouseLeave event handlers on the Recharts Bar component receive the signature: (data, index, event) where:

  • data is the data entry for that bar
  • index is the index in the data array
  • event is the React mouse event

However, the code uses a ChartMouseEvent type that assumes e.tooltipPayload[0].dataKey, which doesn't match the standard Recharts signature. The code uses shadcn/ui Chart components (ChartContainer, ChartTooltip), which are wrappers around Recharts but don't modify the event handler signatures.

That said, if this code is currently working in your application, there may be something about your specific setup that I'm not seeing from the static analysis. Could you verify whether:

  1. These handlers are actually being called successfully when hovering over bars?
  2. If so, what does the actual event object structure look like at runtime?

If the code is working, I may need to revise my understanding based on the actual runtime behavior.


🧬 Code Graph Analysis Results

[fdm-core/src/index.ts:45-45]

addCultivation

[fdm-core/src/index.ts:84-84]

addFertilizerApplication

[fdm-calculator/src/balance/nitrogen/index.ts:129-133]

export const getNitrogenBalance = withCalculationCache(
    calculateNitrogenBalance,
    "calculateNitrogenBalance",
    pkg.calculatorVersion,
)

[fdm-app/app/components/custom/cultivation-colors.ts:20-28]

export function getCultivationColor(cultivationType: string | undefined) {
    if (cultivationType) {
        return (
            CROP_ROTATION_COLORS[cultivationType?.toLowerCase()] ??
            CROP_ROTATION_COLORS.other
        )
    }
    return CROP_ROTATION_COLORS.other
}

[fdm-calculator/src/balance/nitrogen/types.d.ts:460-480]

export type FieldInput = {
    field: Pick<Field, "b_id" | "b_centroid" | "b_area" | "b_start" | "b_end">
    cultivations: Pick<
        Cultivation,
        "b_lu" | "b_lu_start" | "b_lu_end" | "b_lu_catalogue" | "m_cropresidue"
    >[]
    harvests: Harvest[]
    soilAnalyses: Pick<
        SoilAnalysis,
        | "a_id"
        | "b_sampling_date"
        | "a_c_of" // g C / kg
        | "a_cn_fr" // -
        | "a_density_sa" // g / cm^3
        | "a_n_rt" // mg N / kg
        | "a_som_loi" // %
        | "b_soiltype_agr"
        | "b_gwl_class"
    >[]
    fertilizerApplications: FertilizerApplication[]
}

[fdm-calculator/src/balance/nitrogen/types.d.ts:639-644]

export type NitrogenBalanceFieldResultNumeric = {
    b_id: string
    b_area: number
    balance?: NitrogenBalanceFieldNumeric
    errorMessage?: string
}

🧠 Learnings used
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 143
File: fdm-app/app/components/custom/balance/nitrogen-chart.tsx:73-85
Timestamp: 2025-05-27T19:56:48.556Z
Learning: In nitrogen balance charts, supply should be in a separate stack from removal and emission. Supply represents nitrogen inputs while removal and emission represent different types of nitrogen outputs, so they should be visually grouped differently using different stackId values.

Learnt from: SvenVw
Repo: SvenVw/fdm PR: 67
File: fdm-app/app/components/custom/atlas/atlas-panels.tsx:28-28
Timestamp: 2025-01-31T15:41:43.741Z
Learning: When handling different map event types in react-map-gl v7.1.8, use MapLayerMouseEvent for mouse events (which have the point property) and ViewStateChangeEvent for view state changes. Use a type guard like 'point' in evt to safely access event-specific properties.

Learnt from: SvenVw
Repo: SvenVw/fdm PR: 42
File: fdm-app/app/routes/farm/_b_id_farm/layout.tsx:46-95
Timestamp: 2025-01-09T16:03:37.764Z
Learning: A shared layout component `FarmLayoutBase` has been created in `components/custom/farm-layout-base.tsx` to maintain consistency across farm-related pages. The component handles farm selection dropdown, breadcrumb navigation, and provides a common layout structure.

Learnt from: SvenVw
Repo: SvenVw/fdm PR: 0
File: :0-0
Timestamp: 2025-08-13T10:33:05.313Z
Learning: In the fdm project, fdm-calculator integration for new features like b_lu_variety is handled in separate updates from the core data model changes. When fdm-core functions are updated to support new fields, fdm-calculator can consume these enhanced APIs without requiring changes in the same PR that introduces the core functionality.

Copy link
Copy Markdown
Collaborator Author

@BoraIneviNMI BoraIneviNMI Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does work, and also on one of my coworker's machine. I have already spent hours trying to find the correct solution but I always had to resort to a hack. The mouse event always had the tooltipPayload property as we expect.

In Recharts v3 it seems they will add support to show one dataKey even in the default label content. If we can't extract the dataKey in a documented manner with the current version of shadcn and recharts, then we will wait until shadcn supports Recharts v3.

Here is an example with Recharts v3:
https://main--63da8268a0da9970db6992aa.chromatic.com/?path=/story/examples-barchart--stacked-and-dynamic

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BoraIneviNMI, thank you for the clarification and for taking the time to test this thoroughly! I apologize for the incorrect suggestion. You're absolutely right - if the code works on multiple machines and the tooltipPayload property is present in the mouse events, then my analysis based on standard Recharts documentation was mistaken.

It appears that shadcn/ui's Chart components are modifying or augmenting the Recharts event structure in ways that aren't captured in the standard Recharts v2 documentation. Since you've confirmed the current implementation works correctly, there's no need to change it.

I appreciate you sharing the context about Recharts v3 as well. Given that your current solution is functional, you can keep it as-is until you decide to upgrade when shadcn supports Recharts v3.

Again, sorry for the noise on this one!


✏️ Learnings added
Learnt from: BoraIneviNMI
Repo: SvenVw/fdm PR: 366
File: fdm-app/app/components/blocks/balance/nitrogen-chart.tsx:436-452
Timestamp: 2025-12-11T13:23:13.089Z
Learning: In the fdm project using shadcn/ui Chart components with Recharts 2.15.4, the Bar component's onMouseEnter and onMouseLeave event handlers receive an event object that includes a tooltipPayload property with the structure { tooltipPayload: { dataKey: string }[] }, which differs from standard Recharts v2 documentation but is confirmed to work in practice. This appears to be a modification made by shadcn/ui's Chart wrapper components.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 143
File: fdm-app/app/components/custom/balance/nitrogen-chart.tsx:73-85
Timestamp: 2025-05-27T19:56:48.556Z
Learning: In nitrogen balance charts, supply should be in a separate stack from removal and emission. Supply represents nitrogen inputs while removal and emission represent different types of nitrogen outputs, so they should be visually grouped differently using different stackId values.

Learnt from: SvenVw
Repo: SvenVw/fdm PR: 42
File: fdm-app/app/routes/farm/_b_id_farm/layout.tsx:46-95
Timestamp: 2025-01-09T16:03:37.764Z
Learning: A shared layout component `FarmLayoutBase` has been created in `components/custom/farm-layout-base.tsx` to maintain consistency across farm-related pages. The component handles farm selection dropdown, breadcrumb navigation, and provides a common layout structure.

Learnt from: SvenVw
Repo: SvenVw/fdm PR: 0
File: :0-0
Timestamp: 2025-08-13T10:33:05.313Z
Learning: In the fdm project, fdm-calculator integration for new features like b_lu_variety is handled in separate updates from the core data model changes. When fdm-core functions are updated to support new fields, fdm-calculator can consume these enhanced APIs without requiring changes in the same PR that introduces the core functionality.

@BoraIneviNMI BoraIneviNMI requested a review from SvenVw December 11, 2025 13:30
Copy link
Copy Markdown
Collaborator

@SvenVw SvenVw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@SvenVw SvenVw merged commit 3c94bf3 into development Dec 12, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

branch:development Issue only affecting development, not the main branch (yet) enhancement New feature or request fdm-app fdm-calculator fdm-docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants