Add cultivation selection for Nutrient and Fertilizer views#362
Conversation
…erview page for nutrient advice
… Fertilizer Application Metrics
🦋 Changeset detectedLatest commit: 4c09c5f The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
WalkthroughAdds cultivation selection across Nutrient Advice and Fertilizer Application Metrics: new CultivationSelector component, loaders fetch cultivations and determine an activeCultivation (URL param or default using May‑15 rule), and UI/layouts updated to display and pass cultivation context. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Browser
participant Route as NutrientAdviceRoute
participant Loader
participant Service as DataServices
participant UI
participant Selector as CultivationSelector
User->>Browser: Navigate to Nutrient Advice (calendar, field, optional cultivation)
Browser->>Route: route request
Route->>Loader: invoke loader
Loader->>Service: getCultivations(field)
Service-->>Loader: cultivations[]
Loader->>Service: getDefaultCultivation(cultivations, date May 15)
Service-->>Loader: defaultCultivation
Loader->>Service: getCurrentSoilData(...) & getNmiApiKey(...)
Service-->>Loader: soilData, nmiKey
Loader->>Service: getNutrientAdvice(activeCultivation, soilData, nmiKey)
Service-->>Loader: nutrientAdvice
Loader-->>Route: return { cultivations, activeCultivation, nutrientAdvice, ... }
Route->>UI: render header + FieldNutrientAdviceLayout (pass headerAction)
UI->>Selector: mount with (cultivations, selectedCultivationId)
User->>Selector: choose different cultivation
Selector->>Browser: update search param "cultivation"
Browser->>Route: route reload with new param -> loader repeats
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## development #362 +/- ##
============================================
Coverage 87.23% 87.23%
============================================
Files 91 91
Lines 4434 4434
Branches 1325 1325
============================================
Hits 3868 3868
Misses 566 566
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (6)
.changeset/cold-jars-know.md (1)
5-5: Minor: Clarify changeset description.The description "Enable to select the cultivation for the Nutrient Advice in the Fertilizer Application Metrics" is slightly ambiguous. Consider clarifying, e.g., "Enable cultivation selection in Nutrient Advice view and Fertilizer Application Metrics."
fdm-app/app/components/blocks/fertilizer-applications/metrics.tsx (2)
97-106: Remove unused wrapper structure.The new flex wrapper around
CardTitleandCardDescriptiondoesn't appear to serve a purpose since noheaderActionor additional element is being rendered in this card's header. This differs from the pattern used inlayout.tsx.Consider removing the extra wrapper if not needed:
<CardHeader> - <div className="flex flex-row items-center justify-between gap-4"> - <div className="space-y-1.5"> - <CardTitle className="flex items-center gap-2"> - Bemestingsdashboard - </CardTitle> - <CardDescription> - Krijg inzicht in de effecten van de bemesting. - </CardDescription> - </div> - </div> + <CardTitle className="flex items-center gap-2"> + Bemestingsdashboard + </CardTitle> + <CardDescription> + Krijg inzicht in de effecten van de bemesting. + </CardDescription> </CardHeader>
513-530: Consider placing CultivationSelector outside ItemTitle for better semantics.The
CultivationSelectoris rendered insideItemTitle, which typically expects text content. Placing an interactive select element inside a title may cause accessibility concerns and unexpected styling behavior.Consider restructuring to separate the link and selector:
<ItemContent> - <div className="flex items-center justify-between w-full"> - <ItemTitle className="hover:underline"> - <NavLink - to={`/farm/${b_id_farm}/${calendar}/nutrient_advice/${b_id}`} - > - Bemestingsadvies - </NavLink> - {activeCultivation && ( - <CultivationSelector - cultivations={cultivations} - selectedCultivationId={ - activeCultivation.b_lu - } - variant="icon" - /> - )} - </ItemTitle> - </div> + <div className="flex items-center justify-between w-full"> + <ItemTitle className="hover:underline"> + <NavLink + to={`/farm/${b_id_farm}/${calendar}/nutrient_advice/${b_id}`} + > + Bemestingsadvies + </NavLink> + </ItemTitle> + {activeCultivation && ( + <CultivationSelector + cultivations={cultivations} + selectedCultivationId={activeCultivation.b_lu} + variant="icon" + /> + )} + </div> </ItemContent>fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx (2)
251-270: Consider reusing FarmTitle component for consistency.This header structure duplicates the pattern from
FarmTitlecomponent (seefdm-app/app/components/blocks/farm/farm-title.tsx). Consider usingFarmTitlewith a custom action prop to maintain UI consistency across farm-related pages.Based on the
FarmTitlecomponent structure infarm-title.tsx, you could potentially reuse it:- <div className="space-y-6 p-10 pb-0"> - <div className="flex items-center gap-4"> - <div className="space-y-0.5 "> - <h2 className="text-2xl font-bold tracking-tight"> - Bemestingsadvies voor{" "} - {asyncData.activeCultivation.b_lu_name.toLowerCase()} - </h2> - </div> - <div className="ml-auto"> - <CultivationSelector - cultivations={asyncData.cultivations} - selectedCultivationId={ - asyncData.activeCultivation.b_lu - } - /> - </div> - </div> - <Separator className="my-6" /> - </div> + <FarmTitle + title={`Bemestingsadvies voor ${asyncData.activeCultivation.b_lu_name.toLowerCase()}`} + description="" + action={ + <CultivationSelector + cultivations={asyncData.cultivations} + selectedCultivationId={asyncData.activeCultivation.b_lu} + /> + } + />Note: This may require extending
FarmTitleto accept a ReactNode for the action prop instead of a link object.
113-126: Simplify cultivation fallback logic.The
getDefaultCultivationfunction can returnundefinedeven when cultivations are available (if none are active on May 15th). The fallback tocultivations[0]is necessary and correct. However, the conditional check can be simplified using the nullish coalescing operator:let activeCultivation = cultivationId ? cultivations.find((c) => c.b_lu === cultivationId) - : getDefaultCultivation(cultivations, calendar) - - if (!activeCultivation && cultivations.length > 0) { - activeCultivation = cultivations[0] - } + : getDefaultCultivation(cultivations, calendar) ?? + cultivations[0]fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx (1)
244-244: RedundantgetCalendar(params)call.
calendaris already computed on line 155. Consider reusing it here to avoid the redundant call.- calendar: getCalendar(params), + calendar: calendar,
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
fdm-app/app/lib/cultivation-helpers.tsis excluded by!fdm-app/app/lib/**
📒 Files selected for processing (11)
.changeset/cold-jars-know.md(1 hunks).changeset/neat-rings-taste.md(1 hunks).changeset/spotty-cars-think.md(1 hunks)fdm-app/app/components/blocks/fertilizer-applications/metrics.tsx(4 hunks)fdm-app/app/components/blocks/nutrient-advice/cards.tsx(1 hunks)fdm-app/app/components/blocks/nutrient-advice/layout.tsx(1 hunks)fdm-app/app/components/custom/cultivation-selector.tsx(1 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx(4 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx(7 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx(6 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsx(1 hunks)
🧰 Additional context used
🧠 Learnings (36)
📓 Common learnings
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: 49
File: fdm-core/src/cultivation.ts:625-671
Timestamp: 2025-01-24T11:39:57.805Z
Learning: Every cultivation has an associated `cultivationTerminating` record created by `addCultivation`, with `b_terminate_date` initially set to null. Therefore, `updateCultivation` can safely assume the record exists and only needs to handle updates.
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: 42
File: fdm-app/app/routes/farm/_b_id_farm/layout.tsx:46-95
Timestamp: 2025-01-09T16:03:37.764Z
Learning: A comprehensive farm layout system has been created in `components/custom/farm-layouts/` with `BaseFarmLayout` and `FarmSidebarLayout` components. The system supports both simple and sidebar-based layouts while maintaining consistent header and farm selection functionality across all farm routes.
📚 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.nutrient_advice.tsxfdm-app/app/components/blocks/nutrient-advice/layout.tsxfdm-app/app/components/custom/cultivation-selector.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsxfdm-app/app/components/blocks/fertilizer-applications/metrics.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx.changeset/neat-rings-taste.md
📚 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 `FarmLayout` component in `components/custom/farm-layout.tsx` provides a reusable layout structure for farm-related pages, with support for farm selection dropdown, customizable breadcrumb titles, and flexible content rendering through either children or Outlet components.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsxfdm-app/app/components/blocks/nutrient-advice/layout.tsxfdm-app/app/components/custom/cultivation-selector.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsxfdm-app/app/components/blocks/fertilizer-applications/metrics.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx.changeset/neat-rings-taste.md
📚 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:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsx.changeset/cold-jars-know.mdfdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx.changeset/neat-rings-taste.md.changeset/spotty-cars-think.md
📚 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.nutrient_advice.tsxfdm-app/app/components/blocks/nutrient-advice/layout.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx.changeset/neat-rings-taste.md
📚 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/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/components/custom/cultivation-selector.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsxfdm-app/app/components/blocks/fertilizer-applications/metrics.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.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 comprehensive farm layout system has been created in `components/custom/farm-layouts/` with `BaseFarmLayout` and `FarmSidebarLayout` components. The system supports both simple and sidebar-based layouts while maintaining consistent header and farm selection functionality across all farm routes.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx.changeset/neat-rings-taste.md
📚 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:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsx.changeset/cold-jars-know.mdfdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/components/blocks/fertilizer-applications/metrics.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx.changeset/neat-rings-taste.md.changeset/spotty-cars-think.md
📚 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:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 Learning: 2025-09-23T10:02:32.123Z
Learnt from: BoraIneviNMI
Repo: SvenVw/fdm PR: 272
File: fdm-app/app/routes/farm.create.$b_id_farm.$calendar.fertilizers.$b_lu_catalogue.manage.$p_id.tsx:151-164
Timestamp: 2025-09-23T10:02:32.123Z
Learning: The getFertilizer function from svenvw/fdm-core throws an exception if the fertilizer doesn't exist, rather than returning null or undefined.
Applied to files:
.changeset/cold-jars-know.mdfdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 Learning: 2025-09-23T12:37:58.711Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 274
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx:113-148
Timestamp: 2025-09-23T12:37:58.711Z
Learning: In the FDM application, the current field data fetching implementation using Promise.all with individual API calls (getCultivations, getFertilizerApplications, getCurrentSoilData) performs acceptably even with farms containing 90+ fields. No performance issues have been observed in practice with this approach.
Applied to files:
.changeset/cold-jars-know.mdfdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsxfdm-app/app/components/blocks/fertilizer-applications/metrics.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx.changeset/neat-rings-taste.md
📚 Learning: 2025-09-24T14:02:48.574Z
Learnt from: BoraIneviNMI
Repo: SvenVw/fdm PR: 272
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer.manage.new.$p_id.tsx:85-101
Timestamp: 2025-09-24T14:02:48.574Z
Learning: The getFertilizer function in svenvw/fdm-core does not perform authorization checks, unlike getFertilizers which includes a checkPermission call to verify farm access. This means getFertilizer(fdm, p_id) can potentially return fertilizer details for any fertilizer ID without validating user permissions.
Applied to files:
.changeset/cold-jars-know.mdfdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx
📚 Learning: 2025-09-24T14:02:48.574Z
Learnt from: BoraIneviNMI
Repo: SvenVw/fdm PR: 272
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer.manage.new.$p_id.tsx:85-101
Timestamp: 2025-09-24T14:02:48.574Z
Learning: Both getFertilizer and getFertilizers functions in svenvw/fdm-core perform authorization checks using the user's principal_id to verify farm access before returning fertilizer data.
Applied to files:
.changeset/cold-jars-know.mdfdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx
📚 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-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.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/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/components/blocks/fertilizer-applications/metrics.tsx
📚 Learning: 2025-04-04T14:27:39.518Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 116
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field.new.tsx:111-154
Timestamp: 2025-04-04T14:27:39.518Z
Learning: In the FDM application, cultivation retrieval logic should be centralized in utility functions rather than duplicated across loader and action functions to improve maintainability and ensure consistent behavior.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx
📚 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:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 Learning: 2025-02-14T09:56:37.606Z
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.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 Learning: 2025-03-04T10:56:35.540Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 88
File: fdm-calculator/src/doses/calculate-dose.ts:18-18
Timestamp: 2025-03-04T10:56:35.540Z
Learning: In the FDM calculator, fertilizer nutrient rates (p_n_rt, p_p_rt, p_k_rt) are measured in g/kg, and are converted to fractions by dividing by 10 during dose calculations.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 Learning: 2025-02-13T09:03:11.890Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 71
File: fdm-app/app/routes/farm.create.$b_id_farm.cultivations.$b_lu_catalogue.crop.harvest._index.tsx:111-135
Timestamp: 2025-02-13T09:03:11.890Z
Learning: When adding multiple harvests in fdm-app, use Promise.all instead of Promise.allSettled to ensure atomic behavior - if one harvest addition fails, all should fail and rollback to maintain data consistency.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.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/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 Learning: 2024-12-16T10:56:07.561Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 16
File: fdm-app/app/routes/app.addfarm.$b_id_farm.cultivations.$b_lu_catalogue.fertilizers.tsx:1-1
Timestamp: 2024-12-16T10:56:07.561Z
Learning: The project uses `react-router` v7, and the `data` function is exported and used for error handling in loaders and actions.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx
📚 Learning: 2025-05-09T14:53:44.578Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 138
File: fdm-app/app/components/custom/combobox.tsx:34-37
Timestamp: 2025-05-09T14:53:44.578Z
Learning: In the context of this React Router v7 project, it's important to follow the pattern of importing only the types (like UseFormReturn) from "react-hook-form" while importing the Form component from "react-router" to avoid naming conflicts.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx
📚 Learning: 2025-05-09T14:58:10.465Z
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.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx
📚 Learning: 2025-04-18T13:49:17.029Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 124
File: fdm-app/app/components/custom/farm/farm-title.tsx:3-3
Timestamp: 2025-04-18T13:49:17.029Z
Learning: In the fdm project, NavLink and other routing components can be imported from either "react-router" or "react-router-dom" as react-router-dom is included in react-router.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsxfdm-app/app/components/blocks/fertilizer-applications/metrics.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx
📚 Learning: 2025-05-09T14:41:43.484Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 138
File: fdm-app/app/components/custom/fertilizer-applications/form.tsx:6-6
Timestamp: 2025-05-09T14:41:43.484Z
Learning: The project uses React Router v7 which exports a Form component directly from the "react-router" package, making importing from "remix-run/react" unnecessary.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 Learning: 2025-05-09T14:41:43.484Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 138
File: fdm-app/app/components/custom/fertilizer-applications/form.tsx:6-6
Timestamp: 2025-05-09T14:41:43.484Z
Learning: The project uses React Router v7 which exports a Form component directly from the "react-router" package, not from "remix-run/react".
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 Learning: 2025-04-29T11:28:44.181Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 132
File: fdm-app/app/routes/farm.create.$b_id_farm.$calendar.access.tsx:54-68
Timestamp: 2025-04-29T11:28:44.181Z
Learning: In React Router v7, the `json()` function has been replaced with `data()` for creating responses in loaders and actions.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 Learning: 2025-06-02T10:31:27.097Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 151
File: fdm-app/app/routes/signin._index.tsx:101-101
Timestamp: 2025-06-02T10:31:27.097Z
Learning: In fdm-app/app/routes/signin._index.tsx, the redirect destinations are intentionally inconsistent by design: the component defaults new sign-ins to "/welcome" (line 101) while the loader redirects authenticated users to "/farm" (line 80) and the action uses "/farm" as fallback (line 434). This creates appropriate user flows where new users complete their profile via the welcome page, while existing authenticated users bypass it and go directly to the main application.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx
📚 Learning: 2025-01-14T16:06:24.294Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 45
File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:1-1
Timestamp: 2025-01-14T16:06:24.294Z
Learning: In the fdm-app codebase, the `redirect` function should be imported from `react-router`, not `react-router-dom`.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx
📚 Learning: 2025-01-14T16:06:21.832Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 45
File: fdm-app/app/routes/farm.$b_id_farm.settings._index.tsx:1-1
Timestamp: 2025-01-14T16:06:21.832Z
Learning: In the fdm project, `redirect` and other routing utilities should be imported from `react-router` instead of `react-router-dom`.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx
📚 Learning: 2025-06-10T15:05:38.163Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 163
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx:27-29
Timestamp: 2025-06-10T15:05:38.163Z
Learning: In the fdm-app codebase, the component directory structure is intentionally organized with `~/components/custom/` containing small reusable components that can be used in both blocks and pages, while `~/components/blocks/` contains larger block-level components. Not all components should be migrated from custom to blocks - the custom directory serves as a library of smaller utility components.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx
📚 Learning: 2025-11-27T13:11:50.398Z
Learnt from: BoraIneviNMI
Repo: SvenVw/fdm PR: 344
File: fdm-app/app/components/blocks/soil/list.tsx:84-86
Timestamp: 2025-11-27T13:11:50.398Z
Learning: In fdm-app, checkPermission (the new function) differs from the old hasPermission function: when checkPermission is called with strict=false in loaders, it returns a boolean (true/false); if errors occur during permission checks, the loader throws and shows an error page rather than failing open. This is an intentional architectural decision by the team.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx
📚 Learning: 2025-01-23T15:17:23.027Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 49
File: fdm-app/app/routes/farm.create.$b_id_farm.atlas.tsx:208-208
Timestamp: 2025-01-23T15:17:23.027Z
Learning: The `addField` function in fdm-core should verify field creation within the same transaction by checking the existence of the field and all its required relations (field data, acquiring info, geometry) before resolving its promise.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx
📚 Learning: 2025-01-23T15:17:23.028Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 49
File: fdm-app/app/routes/farm.create.$b_id_farm.atlas.tsx:208-208
Timestamp: 2025-01-23T15:17:23.028Z
Learning: The `addField` function in fdm-core should use database transactions and field verification to ensure field availability before resolving its promise, eliminating the need for sleep workarounds.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx
📚 Learning: 2025-01-31T15:34:20.850Z
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:34:20.850Z
Learning: The `updateField` function in fdm-core has optional parameters that don't need to be passed as undefined. Only `fdm` and `b_id` are required.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx
🧬 Code graph analysis (4)
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsx (1)
fdm-app/app/components/blocks/farm/farm-title.tsx (1)
FarmTitle(15-36)
fdm-app/app/components/custom/cultivation-selector.tsx (2)
fdm-core/src/db/schema.ts (1)
cultivations(373-385)fdm-app/app/components/custom/cultivation-colors.ts (1)
getCultivationColor(20-28)
fdm-app/app/components/blocks/fertilizer-applications/metrics.tsx (3)
fdm-core/src/index.ts (1)
Cultivation(56-56)fdm-app/app/components/custom/cultivation-selector.tsx (1)
CultivationSelector(24-122)fdm-core/src/db/schema.ts (1)
cultivations(373-385)
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx (3)
fdm-core/src/db/schema.ts (2)
fields(92-108)cultivations(373-385)fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsx (1)
loader(45-119)fdm-app/app/components/custom/cultivation-colors.ts (1)
getCultivationColor(20-28)
🔇 Additional comments (23)
.changeset/neat-rings-taste.md (1)
1-5: Changeset is properly formatted and versioning is appropriate.The entry correctly specifies a minor version bump for "@svenvw/fdm-app" and provides a clear description of the added functionality (cultivation selection in Nutrient Advice). The YAML frontmatter is valid, and the description accurately reflects the PR objectives.
.changeset/spotty-cars-think.md (1)
1-5: LGTM!The changeset description clearly communicates the new cultivation selection feature for Nutrient Advice.
fdm-app/app/components/blocks/nutrient-advice/cards.tsx (1)
94-94: LGTM!The addition of
w-fullensures proper full-width alignment within the updated layout structure.fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.tsx (1)
144-156: LGTM!The conditional FarmTitle rendering when no field is selected (
!loaderData.b_id) provides appropriate context for the index route, while the nested outlet handles field-specific content with its own header.fdm-app/app/components/blocks/nutrient-advice/layout.tsx (2)
16-22: LGTM!The optional
headerActionprop provides a clean extension point for injecting the CultivationSelector or other actions into the header area without coupling the layout to specific components.
28-40: LGTM!The flex layout with
items-start justify-betweenproperly positions the title/description on the left and the action slot on the right, withgap-4providing appropriate spacing.fdm-app/app/components/blocks/fertilizer-applications/metrics.tsx (1)
55-56: LGTM!The interface extension properly includes cultivation data for the metrics card, enabling the cultivation-aware UI rendering.
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx (2)
139-139: LGTM!Good improvement - using
activeCultivation.b_lu_catalogueinstead of always taking the first cultivation ensures nutrient advice is calculated for the user-selected cultivation.
161-162: LGTM!Properly exposing
cultivationsandactiveCultivationin the async data enables the UI to render the cultivation selector with the correct state.fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx (4)
1-6: LGTM on new imports.The new imports for
getNutrientAdvice,getCultivations,getCurrentSoilData,getNmiApiKey, andgetDefaultCultivationalign with the cultivation-aware nutrient advice feature.
146-163: Cultivation selection logic aligns with acceptance criteria.The implementation correctly:
- Fetches cultivations for the field within the timeframe
- Attempts to match URL parameter for explicit selection
- Falls back to
getDefaultCultivation(May 15th logic per issue #356)- Uses first cultivation as final fallback when none match
This satisfies the requirement for defaulting to the cultivation active on May 15th.
165-178: LGTM on nutrient advice calculation.The null-coalescing for
b_lu_cataloguecorrectly handles the case when no cultivation is active, allowinggetNutrientAdviceto proceed with a null catalogue value.
180-200: Enriched metrics data supports cultivation-aware UI.The addition of
cultivationsandactiveCultivationto the metrics payload enables theCultivationSelectorcomponent to render properly in the fertilizer metrics view.fdm-app/app/components/custom/cultivation-selector.tsx (6)
1-22: LGTM on imports and props interface.Clean interface definition with appropriate optional variant prop defaulting to "default".
24-41: LGTM on value change handler and selection lookup.The URL parameter update approach maintains state in the URL, which aligns with the existing pattern in this codebase for cultivation-aware routes.
48-69: LGTM on icon variant trigger.The tooltip provides a good UX when the icon variant is used, and the fallback text handles the no-selection case.
70-86: LGTM on default variant trigger.The badge styling with dynamic background color matches the pattern used in field cards.
88-121: Well-structured Select component.The component correctly:
- Uses controlled value from props
- Renders sorted cultivations with color indicators
- Shows date in localized format aligned to the right
The trigger content handles the case where
selectedCultivationIddoesn't match any cultivation by showing the fallback placeholder.
43-46: Add null-coalescing to handle undefinedb_lu_startin sort.The
b_lu_startfield is nullable in the database schema, so cultivations may havenullorundefinedvalues. Sorting without defensive handling causesnew Date(null).getTime()to returnNaN, leading to unstable sort behavior.Consider:
const sortedCultivations = [...cultivations].sort( (a, b) => (new Date(b.b_lu_start).getTime() || 0) - (new Date(a.b_lu_start).getTime() || 0), )Or filter out cultivations without start dates before sorting.
⛔ Skipped due to learnings
Learnt from: SvenVw Repo: SvenVw/fdm PR: 49 File: fdm-core/src/cultivation.ts:625-671 Timestamp: 2025-01-24T11:39:57.805Z Learning: Every cultivation has an associated `cultivationTerminating` record created by `addCultivation`, with `b_terminate_date` initially set to null. Therefore, `updateCultivation` can safely assume the record exists and only needs to handle updates.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.fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice._index.tsx (4)
1-2: LGTM on updated imports.New imports support the cultivation-aware field cards with colored badges.
Also applies to: 9-10, 12-18, 30-30
73-92: Cultivation enrichment aligns with performance expectations.Per established patterns in this codebase,
Promise.allwith individualgetCultivationscalls performs acceptably even with farms containing 90+ fields. ThemainCultivationfallback chain (getDefaultCultivation→ first cultivation → undefined) correctly implements the May 15th default logic from issue #356.
115-157: Well-designed empty state with permission-aware actions.The empty state:
- Provides clear messaging about missing fields
- Conditionally shows the "Nieuw perceel" button based on write permission
- Offers fallback navigation to the farm overview
This aligns with the existing UX patterns in the codebase.
159-246: Field cards with cultivation display fulfill PR objectives.The implementation:
- Shows crop name in selection list with colored badge (acceptance criterion #1)
- Links to detail view with cultivation query param for default selection
- Allows navigation to other cultivations via secondary badges (acceptance criterion #3)
- The
z-10class on line 211 correctly ensures "Overige teelten" badges remain clickable above the card's overlay linkThis satisfies the key acceptance criteria from issue #356.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (6)
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx (3)
146-164: Cultivation selection logic mostly matches requirements; consider centralizing and confirm ID semanticsThe cultivation selection block correctly:
- Filters cultivations by timeframe.
- Honors a
?cultivation=query override.- Falls back to a default via
getDefaultCultivation(cultivations, calendar)(which should encapsulate the “May 15th in selected year” rule).- Guarantees an
activeCultivationby falling back tocultivations[0].Two follow‑ups worth addressing:
Centralization / reuse
This pattern (URL param → default for calendar → first cultivation) will likely be duplicated in the nutrient‑advice route and others. Given previous learnings about centralizing cultivation retrieval logic, it would be cleaner long‑term to wrap this into a small helper such asgetActiveCultivation({ cultivations, calendar, request })and reuse it across routes, instead of repeating this block. Based on learnings, ...Verify ID type for
cultivationquery param
cultivations.find((c) => c.b_lu === cultivationId)assumesc.b_luand the query param are the same type and identifier (notb_lu_catalogue). Ifb_luis numeric or a different ID than what the UI encodes in the URL, this will silently skip the intended cultivation and always fall back to the default.
180-200: Metrics payload now cultivation‑aware; confirm downstream metrics are filtered byactiveCultivationAdding
nutrientAdvice,calendar,cultivations, andactiveCultivationintofertilizerApplicationMetricsDataand also returningcalendarat the root is a good step towards the PR goal of cultivation‑aware metrics.However, the nitrogen balance and norms are still obtained via:
norms: getNorms({ fdm, principal_id, b_id }), nitrogenBalance: getNitrogenBalanceforField({ fdm, principal_id, b_id_farm, b_id, timeframe }),with no explicit
activeCultivationargument. To fully meet acceptance criterion 4 (“Fertilizer metrics update to reflect the specifically selected cultivation”), please verify that:
- Either
getNitrogenBalanceforField/getNormsthemselves now interpret the cultivation context implicitly (e.g. via timeframe and/or internal cultivation selection), orFertilizerApplicationMetricsCardusescultivations,activeCultivation, and the underlying fertilizer applications to restrict metrics to the selected cultivation, rather than aggregating across all cultivations in the timeframe.If not, consider extending the metrics pipeline so norms / balances are explicitly scoped to
activeCultivation.Also applies to: 244-244
153-153: Minor: avoid re‑parsing the URLYou create a
new URL(request.url)at Line 153 and again at Line 202. For small readability and micro‑perf gains, you can reuse the first instance instead of constructing it twice.This is non‑blocking and can be picked up opportunistically.
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx (3)
113-124: Make cultivation param handling more robust by falling back when the ID is invalid.Right now an invalid
?cultivation=value yieldsactiveCultivation = undefinedand triggers"missing: active cultivation", which shows the error block instead of gracefully defaulting (e.g. when someone opens an old/deleted-cultivation link).You can keep the May‑15 (or first) default while still honoring valid IDs by factoring out a fallback and using it when
.findfails:- const url = new URL(request.url) - const cultivationId = url.searchParams.get("cultivation") - - const activeCultivation = cultivationId - ? cultivations.find((c) => c.b_lu === cultivationId) - : (getDefaultCultivation(cultivations, calendar) ?? - cultivations[0]) - - if (!activeCultivation) { - throw handleLoaderError("missing: active cultivation") - } + const url = new URL(request.url) + const cultivationId = url.searchParams.get("cultivation") + + const fallbackCultivation = + getDefaultCultivation(cultivations, calendar) ?? + cultivations[0] + + const activeCultivation = + (cultivationId && + cultivations.find((c) => c.b_lu === cultivationId)) || + fallbackCultivation + + if (!activeCultivation) { + // Defensive, but should be unreachable as long as + // `cultivations.length > 0`. + throw handleLoaderError("missing: active cultivation") + }This keeps the May‑15 default behavior while avoiding hard failures on bad query params.
135-137: Update the comment to reflect active cultivation usage.The comment still says “For now take the first cultivation”, but the code now intentionally uses the resolved
activeCultivation, which can be a URL‑selected or defaulted cultivation:- // For now take the first cultivation - const b_lu_catalogue = activeCultivation.b_lu_catalogue + // Use the active cultivation resolved above + const b_lu_catalogue = activeCultivation.b_lu_catalogueAligning the comment with the behavior avoids confusion for future readers.
248-303: Header + cultivation selector integration looks good; optional nit on lowercasing.The new header nicely surfaces the active cultivation and wires
CultivationSelectorinto the same data source that drives the advice sections, satisfying the “crop visible + cultivation selection” requirement in a cohesive way.One small stylistic nit: forcing
b_lu_nameto lowercase may fight against data-provided casing (e.g. proper nouns/varieties). If the API already returns the desired presentation form, consider:- {asyncData.activeCultivation.b_lu_name.toLowerCase()} + {asyncData.activeCultivation.b_lu_name}Otherwise this structure and wiring look solid.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
.changeset/cold-jars-know.md(1 hunks)fdm-app/app/components/blocks/fertilizer-applications/metrics.tsx(4 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx(5 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx(7 hunks)
✅ Files skipped from review due to trivial changes (1)
- .changeset/cold-jars-know.md
🧰 Additional context used
🧠 Learnings (29)
📓 Common learnings
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 116
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field.new.tsx:111-154
Timestamp: 2025-04-04T14:27:39.518Z
Learning: In the FDM application, cultivation retrieval logic should be centralized in utility functions rather than duplicated across loader and action functions to improve maintainability and ensure consistent behavior.
📚 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:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 Learning: 2025-09-23T12:37:58.711Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 274
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx:113-148
Timestamp: 2025-09-23T12:37:58.711Z
Learning: In the FDM application, the current field data fetching implementation using Promise.all with individual API calls (getCultivations, getFertilizerApplications, getCurrentSoilData) performs acceptably even with farms containing 90+ fields. No performance issues have been observed in practice with this approach.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 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-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.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/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/components/blocks/fertilizer-applications/metrics.tsx
📚 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:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.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/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsxfdm-app/app/components/blocks/fertilizer-applications/metrics.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.field.$b_id.fertilizer._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsxfdm-app/app/components/blocks/fertilizer-applications/metrics.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:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 Learning: 2025-04-04T14:27:39.518Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 116
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field.new.tsx:111-154
Timestamp: 2025-04-04T14:27:39.518Z
Learning: In the FDM application, cultivation retrieval logic should be centralized in utility functions rather than duplicated across loader and action functions to improve maintainability and ensure consistent behavior.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 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:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 Learning: 2025-02-14T09:56:37.606Z
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.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 Learning: 2025-09-24T14:02:48.574Z
Learnt from: BoraIneviNMI
Repo: SvenVw/fdm PR: 272
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer.manage.new.$p_id.tsx:85-101
Timestamp: 2025-09-24T14:02:48.574Z
Learning: The getFertilizer function in svenvw/fdm-core does not perform authorization checks, unlike getFertilizers which includes a checkPermission call to verify farm access. This means getFertilizer(fdm, p_id) can potentially return fertilizer details for any fertilizer ID without validating user permissions.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 Learning: 2025-09-23T10:02:32.123Z
Learnt from: BoraIneviNMI
Repo: SvenVw/fdm PR: 272
File: fdm-app/app/routes/farm.create.$b_id_farm.$calendar.fertilizers.$b_lu_catalogue.manage.$p_id.tsx:151-164
Timestamp: 2025-09-23T10:02:32.123Z
Learning: The getFertilizer function from svenvw/fdm-core throws an exception if the fertilizer doesn't exist, rather than returning null or undefined.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 Learning: 2025-09-24T14:02:48.574Z
Learnt from: BoraIneviNMI
Repo: SvenVw/fdm PR: 272
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer.manage.new.$p_id.tsx:85-101
Timestamp: 2025-09-24T14:02:48.574Z
Learning: Both getFertilizer and getFertilizers functions in svenvw/fdm-core perform authorization checks using the user's principal_id to verify farm access before returning fertilizer data.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 Learning: 2025-03-04T10:56:35.540Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 88
File: fdm-calculator/src/doses/calculate-dose.ts:18-18
Timestamp: 2025-03-04T10:56:35.540Z
Learning: In the FDM calculator, fertilizer nutrient rates (p_n_rt, p_p_rt, p_k_rt) are measured in g/kg, and are converted to fractions by dividing by 10 during dose calculations.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 Learning: 2025-02-13T09:03:11.890Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 71
File: fdm-app/app/routes/farm.create.$b_id_farm.cultivations.$b_lu_catalogue.crop.harvest._index.tsx:111-135
Timestamp: 2025-02-13T09:03:11.890Z
Learning: When adding multiple harvests in fdm-app, use Promise.all instead of Promise.allSettled to ensure atomic behavior - if one harvest addition fails, all should fail and rollback to maintain data consistency.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.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/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.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 `FarmLayout` component in `components/custom/farm-layout.tsx` provides a reusable layout structure for farm-related pages, with support for farm selection dropdown, customizable breadcrumb titles, and flexible content rendering through either children or Outlet components.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsxfdm-app/app/components/blocks/fertilizer-applications/metrics.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.nutrient_advice.$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 comprehensive farm layout system has been created in `components/custom/farm-layouts/` with `BaseFarmLayout` and `FarmSidebarLayout` components. The system supports both simple and sidebar-based layouts while maintaining consistent header and farm selection functionality across all farm routes.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 Learning: 2024-12-16T10:56:07.561Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 16
File: fdm-app/app/routes/app.addfarm.$b_id_farm.cultivations.$b_lu_catalogue.fertilizers.tsx:1-1
Timestamp: 2024-12-16T10:56:07.561Z
Learning: The project uses `react-router` v7, and the `data` function is exported and used for error handling in loaders and actions.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 Learning: 2025-05-09T14:53:44.578Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 138
File: fdm-app/app/components/custom/combobox.tsx:34-37
Timestamp: 2025-05-09T14:53:44.578Z
Learning: In the context of this React Router v7 project, it's important to follow the pattern of importing only the types (like UseFormReturn) from "react-hook-form" while importing the Form component from "react-router" to avoid naming conflicts.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 Learning: 2025-05-09T14:58:10.465Z
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.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 Learning: 2025-04-18T13:49:17.029Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 124
File: fdm-app/app/components/custom/farm/farm-title.tsx:3-3
Timestamp: 2025-04-18T13:49:17.029Z
Learning: In the fdm project, NavLink and other routing components can be imported from either "react-router" or "react-router-dom" as react-router-dom is included in react-router.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsxfdm-app/app/components/blocks/fertilizer-applications/metrics.tsx
📚 Learning: 2025-05-09T14:41:43.484Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 138
File: fdm-app/app/components/custom/fertilizer-applications/form.tsx:6-6
Timestamp: 2025-05-09T14:41:43.484Z
Learning: The project uses React Router v7 which exports a Form component directly from the "react-router" package, making importing from "remix-run/react" unnecessary.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 Learning: 2025-05-09T14:41:43.484Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 138
File: fdm-app/app/components/custom/fertilizer-applications/form.tsx:6-6
Timestamp: 2025-05-09T14:41:43.484Z
Learning: The project uses React Router v7 which exports a Form component directly from the "react-router" package, not from "remix-run/react".
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 Learning: 2025-04-29T11:28:44.181Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 132
File: fdm-app/app/routes/farm.create.$b_id_farm.$calendar.access.tsx:54-68
Timestamp: 2025-04-29T11:28:44.181Z
Learning: In React Router v7, the `json()` function has been replaced with `data()` for creating responses in loaders and actions.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx
📚 Learning: 2025-01-23T15:18:57.212Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 49
File: fdm-core/src/db/schema.ts:407-426
Timestamp: 2025-01-23T15:18:57.212Z
Learning: In the farm data model, each cultivation (b_lu) can have only one termination date but can have multiple harvest dates. This is enforced through the database schema where cultivationTerminating uses b_lu as primary key while cultivationHarvesting uses a composite primary key of b_id_harvestable and b_lu.
Applied to files:
fdm-app/app/components/blocks/fertilizer-applications/metrics.tsx
🧬 Code graph analysis (1)
fdm-app/app/components/blocks/fertilizer-applications/metrics.tsx (2)
fdm-core/src/index.ts (1)
Cultivation(56-56)fdm-app/app/components/custom/cultivation-selector.tsx (1)
CultivationSelector(24-122)
🔇 Additional comments (6)
fdm-app/app/components/blocks/fertilizer-applications/metrics.tsx (4)
8-8: LGTM! Imports are correct.The new imports for
Cultivationtype andCultivationSelectorcomponent are necessary and correctly sourced for the cultivation selection functionality.Also applies to: 11-11
90-91: LGTM! Destructuring follows existing pattern.The new fields are cleanly destructured alongside existing fields, maintaining consistency with the component's structure.
509-526: LGTM! Cultivation selector integrated correctly.The implementation aligns well with the PR objectives:
- The flex layout with
justify-betweenappropriately positions the selector on the right while keeping the navigation link on the left.- Conditional rendering ensures the selector only appears when an
activeCultivationexists, preventing runtime errors.- The
variant="icon"renders a compact colored dot with tooltip, suitable for this dashboard view.- The safe navigation on line 520-521 (
activeCultivation.b_lu) is protected by the conditional check on line 517.The
CultivationSelectorupdates the URL search parameter "cultivation", which enables context-aware cultivation filtering as specified in the PR objectives.
55-56: Interface extended with cultivation fields.The
cultivationsfield is required (non-nullable array), which means all code that createsFertilizerApplicationMetricsDatamust provide this field. TheactiveCultivationis appropriately optional since a cultivation may not always be selected. The loader properly provides both fields when constructing this data object.fdm-app/app/routes/farm.$b_id_farm.$calendar.nutrient_advice.$b_id.tsx (2)
1-1: New imports are consistent and reuse shared helpers.
Separator,CultivationSelector, andgetDefaultCultivationare wired in cleanly and align with the shared UI and cultivation-helper patterns you’ve been establishing, avoiding duplicated cultivation defaulting logic.
Based on learnings, cultivation retrieval/defaulting being centralized in helpers is preferred over ad‑hoc logic in each loader.Also applies to: 17-17, 30-30
158-159: ExposingcultivationsandactiveCultivationviaasyncDatais appropriate.Including both
cultivationsandactiveCultivationin the async payload fits the new header/selector needs and keeps all cultivation context in one place for downstream components (FieldNutrientAdviceandCultivationSelector). This is a good extension of the loader’s data contract.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx (1)
173-181: Past crash issue successfully resolved!The conditional check for
activeCultivationbefore callinggetNutrientAdvicecorrectly prevents the crash described in the previous review when no cultivations exist. SettingnutrientAdvice = nullwhen no cultivation is available ensures downstream components can handle the absence gracefully.
🧹 Nitpick comments (1)
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx (1)
146-169: Consider parallel fetching for minor performance gain.
getCultivationsandgetCurrentSoilDataare independent and could be fetched in parallel usingPromise.all. This would slightly reduce loader time:- const cultivations = await getCultivations( - fdm, - session.principal_id, - b_id, - timeframe, - ) - const url = new URL(request.url) const cultivationId = url.searchParams.get("cultivation") const calendar = getCalendar(params) - let activeCultivation = cultivationId - ? cultivations.find((c) => c.b_lu === cultivationId) - : getDefaultCultivation(cultivations, calendar) - - if (!activeCultivation && cultivations.length > 0) { - activeCultivation = cultivations[0] - } - - const currentSoilData = await getCurrentSoilData( - fdm, - session.principal_id, - b_id, - ) + const [cultivations, currentSoilData] = await Promise.all([ + getCultivations(fdm, session.principal_id, b_id, timeframe), + getCurrentSoilData(fdm, session.principal_id, b_id), + ]) + + let activeCultivation = cultivationId + ? cultivations.find((c) => c.b_lu === cultivationId) + : getDefaultCultivation(cultivations, calendar) + + if (!activeCultivation && cultivations.length > 0) { + activeCultivation = cultivations[0] + }However, given that learnings indicate acceptable performance with the current approach, this optimization is optional.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx(5 hunks)
🧰 Additional context used
🧠 Learnings (19)
📓 Common learnings
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 116
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field.new.tsx:111-154
Timestamp: 2025-04-04T14:27:39.518Z
Learning: In the FDM application, cultivation retrieval logic should be centralized in utility functions rather than duplicated across loader and action functions to improve maintainability and ensure consistent behavior.
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.
📚 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:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 Learning: 2025-09-23T12:37:58.711Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 274
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx:113-148
Timestamp: 2025-09-23T12:37:58.711Z
Learning: In the FDM application, the current field data fetching implementation using Promise.all with individual API calls (getCultivations, getFertilizerApplications, getCurrentSoilData) performs acceptably even with farms containing 90+ fields. No performance issues have been observed in practice with this approach.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 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-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.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/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 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:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.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/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.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.field.$b_id.fertilizer._index.tsx
📚 Learning: 2025-04-04T14:27:39.518Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 116
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field.new.tsx:111-154
Timestamp: 2025-04-04T14:27:39.518Z
Learning: In the FDM application, cultivation retrieval logic should be centralized in utility functions rather than duplicated across loader and action functions to improve maintainability and ensure consistent behavior.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.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:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 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:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 Learning: 2025-09-23T10:02:32.123Z
Learnt from: BoraIneviNMI
Repo: SvenVw/fdm PR: 272
File: fdm-app/app/routes/farm.create.$b_id_farm.$calendar.fertilizers.$b_lu_catalogue.manage.$p_id.tsx:151-164
Timestamp: 2025-09-23T10:02:32.123Z
Learning: The getFertilizer function from svenvw/fdm-core throws an exception if the fertilizer doesn't exist, rather than returning null or undefined.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.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/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.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/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 Learning: 2025-02-14T09:56:37.606Z
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.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 Learning: 2025-09-24T14:02:48.574Z
Learnt from: BoraIneviNMI
Repo: SvenVw/fdm PR: 272
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer.manage.new.$p_id.tsx:85-101
Timestamp: 2025-09-24T14:02:48.574Z
Learning: The getFertilizer function in svenvw/fdm-core does not perform authorization checks, unlike getFertilizers which includes a checkPermission call to verify farm access. This means getFertilizer(fdm, p_id) can potentially return fertilizer details for any fertilizer ID without validating user permissions.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 Learning: 2025-09-24T14:02:48.574Z
Learnt from: BoraIneviNMI
Repo: SvenVw/fdm PR: 272
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer.manage.new.$p_id.tsx:85-101
Timestamp: 2025-09-24T14:02:48.574Z
Learning: Both getFertilizer and getFertilizers functions in svenvw/fdm-core perform authorization checks using the user's principal_id to verify farm access before returning fertilizer data.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 Learning: 2025-03-04T10:56:35.540Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 88
File: fdm-calculator/src/doses/calculate-dose.ts:18-18
Timestamp: 2025-03-04T10:56:35.540Z
Learning: In the FDM calculator, fertilizer nutrient rates (p_n_rt, p_p_rt, p_k_rt) are measured in g/kg, and are converted to fractions by dividing by 10 during dose calculations.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
📚 Learning: 2025-02-13T09:03:11.890Z
Learnt from: SvenVw
Repo: SvenVw/fdm PR: 71
File: fdm-app/app/routes/farm.create.$b_id_farm.cultivations.$b_lu_catalogue.crop.harvest._index.tsx:111-135
Timestamp: 2025-02-13T09:03:11.890Z
Learning: When adding multiple harvests in fdm-app, use Promise.all instead of Promise.allSettled to ensure atomic behavior - if one harvest addition fails, all should fail and rollback to maintain data consistency.
Applied to files:
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx
🧬 Code graph analysis (1)
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx (4)
fdm-core/src/db/schema.ts (1)
cultivations(373-385)fdm-core/src/index.ts (2)
getCultivations(49-49)getCurrentSoilData(168-168)fdm-app/app/integrations/nmi.ts (1)
getNmiApiKey(6-13)fdm-calculator/src/nutrient-advice/index.ts (1)
getNutrientAdvice(98-102)
🔇 Additional comments (4)
fdm-app/app/routes/farm.$b_id_farm.$calendar.field.$b_id.fertilizer._index.tsx (4)
1-1: LGTM! Imports support the cultivation selection feature.The new imports are all utilized in the loader and align with the PR objective of adding cultivation selection. The use of
getDefaultCultivationfrom a centralized utility follows established patterns for cultivation logic.Based on learnings, cultivation retrieval logic should be centralized in utility functions.
Also applies to: 5-6, 35-36
146-163: Well-implemented cultivation selection logic.The cultivation selection flow correctly implements the PR requirements:
- Fetches cultivations for the field's timeframe
- Prioritizes URL parameter for explicit user selection
- Falls back to the default May 15th rule via
getDefaultCultivation- Provides reasonable fallback to first cultivation when others unavailable
This provides good UX by always showing cultivation data when available.
196-203: LGTM! Computed values used consistently.The computed
calendar,nutrientAdvice,cultivations, andactiveCultivationare correctly passed to both the metrics data payload and the main loader return. The metrics component will now have the context needed to display cultivation-specific information as per the PR objectives.Also applies to: 247-247
165-181: Remove this comment—b_centroidis guaranteed to be present.The
Fieldinterface (field.d.ts) definesb_centroid: [number, number]as a required property (not optional). ThegetField()function always constructsb_centroidfrom the field's geometry using SQL spatial functions (lines 166–189 in field.ts), so if the field object exists (validated at lines 94–100), the centroid is guaranteed to be present. The type system enforces this contract, and no additional null/undefined checks are needed.
Summary by CodeRabbit
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.
Closes #356