Add persistent non-productive fields filter; sort cultivations by area#279
Conversation
…ending total area instead of random order
🦋 Changeset detectedLatest commit: f0b1e79 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
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 a persistent UI toggle to hide non-productive fields, computes and exposes field geometry properties ( Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Toggle as FieldFilterToggle
participant Store as useFieldFilterStore
participant Page as App Page (route/component)
participant Loader as Route Loader (returns fields with geometry props)
Note over Loader: Loader returns fields with b_area, b_perimeter, b_isproductive
User->>Toggle: click toggle
Toggle->>Store: toggleShowProductiveOnly()
Store-->>Page: showProductiveOnly (subscribed)
Page->>Loader: read loaderData.fields
alt showProductiveOnly = true
Page->>Page: filtered = fields.filter(f => f.b_isproductive)
else
Page->>Page: filtered = fields
end
Page-->>User: render lists/tables/cards using filtered
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
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❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## development #279 +/- ##
============================================
Coverage 92.92% 92.93%
============================================
Files 79 79
Lines 12926 12951 +25
Branches 1266 1268 +2
============================================
+ Hits 12012 12036 +24
- Misses 912 913 +1
Partials 2 2
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: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
fdm-core/src/soil.test.ts (1)
147-164: Fix the async rejection assertion
.rejectsexpects a promise, but here you're passing a function. Vitest now throws before reaching the assertion, breaking the test. CalladdSoilAnalysisand pass its promise directly.- await expect(async () => { - await addSoilAnalysis( - fdm, - principal_id, - a_date, - a_source, - b_id, - a_depth_lower, - b_sampling_date, - { - a_p_al: a_p_al, - a_p_cc: a_p_cc, - b_soiltype_agr: b_soiltype_agr, - b_gwl_class: b_gwl_class, - }, - a_depth_upper, - ) - }).rejects.toThrowError("Exception for addSoilAnalysis") + await expect( + addSoilAnalysis( + fdm, + principal_id, + a_date, + a_source, + b_id, + a_depth_lower, + b_sampling_date, + { + a_p_al: a_p_al, + a_p_cc: a_p_cc, + b_soiltype_agr: b_soiltype_agr, + b_gwl_class: b_gwl_class, + }, + a_depth_upper, + ), + ).rejects.toThrowError("Exception for addSoilAnalysis")
🧹 Nitpick comments (15)
fdm-core/src/field.test.ts (2)
92-95: Remove noisy console.log from testsKeep test output clean.
Apply this diff:
- console.log(field) expect(field.b_perimeter).toBeGreaterThan(0) expect(field.b_isproductive).toBe(true)
189-192: DRY up repeated perimeter/productivity assertionsExtract a small helper (e.g., expectFieldMetrics(field)) to reduce duplication across these loops.
Also applies to: 331-333, 349-352, 370-373, 388-391, 401-404
fdm-app/app/routes/farm.create.$b_id_farm.$calendar.fields.tsx (5)
2-2: Remove unused icon import
Caris not used.Apply this diff:
-import { ArrowLeft, Car } from "lucide-react" +import { ArrowLeft } from "lucide-react"
10-10: Add useMemo import for computed sidebar itemsPreps for memoization change below.
Apply this diff:
} from "react-router" +import { useMemo } from "react"
23-31: Prefer alias imports for consistencyUse
~alias like the rest of the file.Apply this diff:
-import { FieldFilterToggle } from "../components/custom/field-filter-toggle" +import { FieldFilterToggle } from "~/components/custom/field-filter-toggle" import { - Card, - CardContent, - CardFooter, - CardHeader, - CardTitle, -} from "../components/ui/card" + Card, + CardContent, + CardFooter, + CardHeader, + CardTitle, +} from "~/components/ui/card"
47-63: Update loader JSDoc to match returned shapeDocs still mention sidebarPageItems/cultivationOptions/mapboxToken but loader now returns fields.
Apply this diff:
- * The fields are sorted alphabetically by name and converted into sidebar navigation items for use in the UI. + * The fields are returned for client-side filtering/sorting into sidebar navigation items. @@ - * - sidebarPageItems: Navigation items for each field. - * - cultivationOptions: A list of available cultivation options. - * - mapboxToken: The Mapbox access token. + * - fields: Array of fields for the farm (respects timeframe). * - b_id_farm: The farm ID. * - b_name_farm: The name of the farm. * - action: The URL for field update submissions.Also applies to: 93-97
109-117: Memoize and sort sidebar items for stable UXPrevents re-compute on every render and ensures deterministic alpha order.
Apply this diff:
- // Create the sidenav - const sidebarPageItems = fields - .filter((field) => (showProductiveOnly ? field.b_isproductive : true)) - .map((field) => { - return { - title: field.b_name, - to: `/farm/create/${b_id_farm}/${calendar}/fields/${field.b_id}`, - } - }) + // Create the sidenav + const sidebarPageItems = useMemo( + () => + fields + .filter((field) => + showProductiveOnly ? field.b_isproductive : true, + ) + .slice() + .sort((a, b) => a.b_name.localeCompare(b.b_name)) + .map((field) => ({ + title: field.b_name, + to: `/farm/create/${b_id_farm}/${calendar}/fields/${field.b_id}`, + })), + [fields, showProductiveOnly, b_id_farm, calendar], + ).changeset/pretty-comics-drop.md (1)
5-6: Changeset wording likely inaccurate: b_area already existedIf b_area was already part of the Field output, this entry should only mention b_perimeter to avoid confusion.
Proposed tweak:
-Adds `b_perimeter` and `b_area` to output of `getField` and `getFields` +Expose `b_perimeter` in the output of `getField` and `getFields`.changeset/five-hairs-chew.md (1)
5-6: Polish the changeset sentence for claritySmall grammar/style improvement.
-At farm create wizard show the cultivations in bouwplan on descending total area instead of random order +In the farm create wizard, show the cultivations in the bouwplan sorted by descending total area (instead of a random order)fdm-app/app/components/custom/field-filter-toggle.tsx (1)
20-45: Remove unnecessary wrapper divThe outer div with an empty className is not needed.
- return ( - <div className=""> - <TooltipProvider> + return ( + <TooltipProvider> <Tooltip> <TooltipTrigger asChild> <Button variant="outline" size="icon" onClick={toggleShowProductiveOnly} className="border hover:bg-accent hover:text-accent-foreground" aria-label={tooltipContent} aria-pressed={showProductiveOnly} > {showProductiveOnly ? ( <Square className="h-4 w-4 text-primary" /> ) : ( <PanelsRightBottom className="h-4 w-4" /> )} </Button> </TooltipTrigger> <TooltipContent> <p>{tooltipContent}</p> </TooltipContent> </Tooltip> - </TooltipProvider> - </div> + </TooltipProvider> )fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx (2)
30-31: Remove unused import.
FieldFilterToggleis imported but not rendered here. The DataTable header already includes it; drop this import to avoid duplicate UI and reduce bundle size.-import { FieldFilterToggle } from "~/components/custom/field-filter-toggle"
153-154: Default b_isproductive to true for backward compatibility
Replace in fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx (line 153):- b_isproductive: field.b_isproductive, + b_isproductive: field.b_isproductive ?? true,fdm-core/src/cultivation.ts (2)
620-622: Avoid rounding in SQL for area/perimeter (round at presentation).Rounding here propagates precision loss into classification (b_isproductive) and summed areas. Prefer raw floats and round only in the UI.
- b_area: sql<number>`ROUND((ST_Area(b_geometry::geography)/10000)::NUMERIC, 2)::FLOAT`, - b_perimeter: sql<number>`ROUND((ST_Perimeter(b_geometry::geography))::NUMERIC, 2)::FLOAT`, + b_area: sql<number>`(ST_Area(b_geometry::geography)/10000)::FLOAT`, + b_perimeter: sql<number>`ST_Perimeter(b_geometry::geography)::FLOAT`,
775-780: Verify shape ratio choice for b_isproductive.The current ratio uses perimeter (m) / area (m²), which is not dimensionless and scales with size. Consider a dimensionless metric (e.g., 4πA/P² or P/√A) to improve robustness, then recalibrate the constant. At minimum, document units explicitly.
I can propose a drop-in calculation using the isoperimetric quotient if you confirm the desired threshold.
fdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsx (1)
196-204: Consider exposing the toggle in this view’s header.You use the store but don’t render a toggle here. If
HeaderNormsdoesn’t include it, addFieldFilterTogglenear the title for discoverability.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (19)
.changeset/clear-bats-find.md(1 hunks).changeset/five-hairs-chew.md(1 hunks).changeset/lemon-spies-cheat.md(1 hunks).changeset/pretty-comics-drop.md(1 hunks)fdm-app/app/components/blocks/cultivation/list-plan.tsx(3 hunks)fdm-app/app/components/blocks/fields/table.tsx(2 hunks)fdm-app/app/components/blocks/norms/field-norms.tsx(2 hunks)fdm-app/app/components/custom/field-filter-toggle.tsx(1 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsx(6 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx(5 hunks)fdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsx(6 hunks)fdm-app/app/routes/farm.create.$b_id_farm.$calendar.fields.tsx(6 hunks)fdm-app/app/store/field-filter.ts(1 hunks)fdm-core/src/cultivation.d.ts(3 hunks)fdm-core/src/cultivation.ts(3 hunks)fdm-core/src/field.d.ts(1 hunks)fdm-core/src/field.test.ts(12 hunks)fdm-core/src/field.ts(5 hunks)fdm-core/src/soil.test.ts(8 hunks)
🧰 Additional context used
🧠 Learnings (24)
📚 Learning: 2025-01-31T15:05:14.310Z
Learnt from: SvenVw
PR: SvenVw/fdm#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-core/src/field.d.ts.changeset/pretty-comics-drop.md
📚 Learning: 2025-01-31T15:05:14.310Z
Learnt from: SvenVw
PR: SvenVw/fdm#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 requires 8 parameters: fdm, b_id (required), and 6 optional parameters (b_name, b_id_source, b_geometry, b_acquiring_date, b_acquiring_method, b_discarding_date).
Applied to files:
fdm-core/src/field.d.ts
📚 Learning: 2025-01-31T15:34:20.850Z
Learnt from: SvenVw
PR: SvenVw/fdm#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-core/src/field.d.ts.changeset/pretty-comics-drop.md
📚 Learning: 2025-01-31T15:05:14.310Z
Learnt from: SvenVw
PR: SvenVw/fdm#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: When using `updateField` from fdm-core, all 8 parameters must be provided in order: fdm, b_id, b_name, b_geometry, b_area, b_id_source, b_id_farm, and b_id_farm_source.
Applied to files:
fdm-core/src/field.d.ts
📚 Learning: 2025-08-11T11:55:26.053Z
Learnt from: SvenVw
PR: SvenVw/fdm#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-core/src/cultivation.d.ts
📚 Learning: 2025-01-23T15:18:57.212Z
Learnt from: SvenVw
PR: SvenVw/fdm#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-core/src/cultivation.d.ts
📚 Learning: 2025-02-13T08:28:00.183Z
Learnt from: SvenVw
PR: SvenVw/fdm#71
File: fdm-core/src/cultivation.ts:572-597
Timestamp: 2025-02-13T08:28:00.183Z
Learning: In the FDM database schema, `b_id_harvesting` is a primary key in the `cultivationHarvesting` table, ensuring no duplicate harvest entries can exist. Therefore, duplicate checking is not needed when processing harvest records from database queries.
Applied to files:
fdm-core/src/cultivation.d.ts
📚 Learning: 2025-02-13T08:35:59.306Z
Learnt from: SvenVw
PR: SvenVw/fdm#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-core/src/cultivation.d.tsfdm-core/src/field.test.ts
📚 Learning: 2025-01-09T16:03:37.764Z
Learnt from: SvenVw
PR: SvenVw/fdm#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._index.tsxfdm-app/app/components/blocks/cultivation/list-plan.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsxfdm-app/app/routes/farm.create.$b_id_farm.$calendar.fields.tsx
📚 Learning: 2025-09-23T12:27:07.359Z
Learnt from: SvenVw
PR: SvenVw/fdm#274
File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:151-204
Timestamp: 2025-09-23T12:27:07.359Z
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._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsxfdm-app/app/routes/farm.create.$b_id_farm.$calendar.fields.tsx
📚 Learning: 2025-09-23T12:29:34.158Z
Learnt from: SvenVw
PR: SvenVw/fdm#274
File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:160-163
Timestamp: 2025-09-23T12:29:34.158Z
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._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsxfdm-app/app/routes/farm.create.$b_id_farm.$calendar.fields.tsx
📚 Learning: 2025-09-23T12:37:58.700Z
Learnt from: SvenVw
PR: SvenVw/fdm#274
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx:113-148
Timestamp: 2025-09-23T12:37:58.700Z
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._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsxfdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsx
📚 Learning: 2025-01-09T16:03:37.764Z
Learnt from: SvenVw
PR: SvenVw/fdm#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.field._index.tsxfdm-app/app/routes/farm.create.$b_id_farm.$calendar.fields.tsx
📚 Learning: 2025-08-11T12:24:32.200Z
Learnt from: SvenVw
PR: SvenVw/fdm#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/cultivation/list-plan.tsx
📚 Learning: 2025-04-18T13:49:17.029Z
Learnt from: SvenVw
PR: SvenVw/fdm#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.balance.nitrogen._index.tsx
📚 Learning: 2024-12-16T10:56:07.561Z
Learnt from: SvenVw
PR: SvenVw/fdm#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.balance.nitrogen._index.tsx
📚 Learning: 2025-05-09T14:58:10.465Z
Learnt from: SvenVw
PR: SvenVw/fdm#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.balance.nitrogen._index.tsx
📚 Learning: 2025-05-09T14:53:44.578Z
Learnt from: SvenVw
PR: SvenVw/fdm#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.balance.nitrogen._index.tsx
📚 Learning: 2025-05-09T14:41:43.484Z
Learnt from: SvenVw
PR: SvenVw/fdm#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.balance.nitrogen._index.tsx
📚 Learning: 2025-05-09T14:41:43.484Z
Learnt from: SvenVw
PR: SvenVw/fdm#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.balance.nitrogen._index.tsx
📚 Learning: 2025-01-23T15:17:23.027Z
Learnt from: SvenVw
PR: SvenVw/fdm#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-core/src/field.test.ts
📚 Learning: 2025-08-11T12:14:28.354Z
Learnt from: SvenVw
PR: SvenVw/fdm#233
File: fdm-core/src/db/schema.ts:370-0
Timestamp: 2025-08-11T12:14:28.354Z
Learning: In the FDM database schema, the field `b_lu_rest_oravib` in the `cultivations_catalogue` table is intentionally nullable (can be undefined). When undefined, it should be treated as `false` in the UI layer. This allows distinguishing between "explicitly set to false" and "not set" at the database level while providing simplified boolean logic in the UI.
Applied to files:
fdm-core/src/field.test.ts
📚 Learning: 2025-01-09T16:03:37.764Z
Learnt from: SvenVw
PR: SvenVw/fdm#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.create.$b_id_farm.$calendar.fields.tsx
📚 Learning: 2025-01-09T16:03:37.764Z
Learnt from: SvenVw
PR: SvenVw/fdm#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.create.$b_id_farm.$calendar.fields.tsx
🧬 Code graph analysis (14)
fdm-core/src/field.d.ts (1)
fdm-core/src/db/schema.ts (2)
fieldAcquiringTypeSelect(83-83)fieldDiscardingTypeSelect(127-127)
fdm-app/app/components/blocks/norms/field-norms.tsx (1)
fdm-app/app/components/custom/field-filter-toggle.tsx (1)
FieldFilterToggle(11-46)
fdm-core/src/cultivation.d.ts (2)
fdm-core/src/db/schema.ts (3)
cultivationHarvestingTypeSelect(474-475)harvestablesTypeSelect(397-397)cultivationsCatalogueTypeSelect(381-382)fdm-core/src/index.ts (1)
CultivationCatalogue(49-49)
fdm-app/app/components/custom/field-filter-toggle.tsx (1)
fdm-app/app/store/field-filter.ts (1)
useFieldFilterStore(9-23)
fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx (2)
fdm-app/app/store/field-filter.ts (1)
useFieldFilterStore(9-23)fdm-app/app/components/blocks/fields/table.tsx (1)
DataTable(51-339)
fdm-app/app/components/blocks/cultivation/list-plan.tsx (1)
fdm-core/src/db/schema.ts (1)
fields(87-103)
fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsx (2)
fdm-app/app/store/field-filter.ts (1)
useFieldFilterStore(9-23)fdm-app/app/components/custom/field-filter-toggle.tsx (1)
FieldFilterToggle(11-46)
fdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsx (2)
fdm-core/src/db/schema.ts (1)
fields(87-103)fdm-app/app/store/field-filter.ts (1)
useFieldFilterStore(9-23)
fdm-core/src/soil.test.ts (1)
fdm-core/src/db/schema.ts (1)
fieldsTypeInsert(106-106)
fdm-app/app/components/blocks/fields/table.tsx (1)
fdm-app/app/components/custom/field-filter-toggle.tsx (1)
FieldFilterToggle(11-46)
fdm-core/src/field.ts (1)
fdm-core/src/db/schema.ts (1)
fields(87-103)
fdm-core/src/field.test.ts (2)
fdm-core/src/db/schema.ts (1)
fields(87-103)fdm-core/src/field.ts (2)
addField(48-129)getField(145-202)
fdm-app/app/routes/farm.create.$b_id_farm.$calendar.fields.tsx (3)
fdm-app/app/store/field-filter.ts (1)
useFieldFilterStore(9-23)fdm-app/app/components/custom/field-filter-toggle.tsx (1)
FieldFilterToggle(11-46)fdm-app/app/components/custom/sidebar-page.tsx (1)
SidebarPage(12-49)
fdm-core/src/cultivation.ts (1)
fdm-core/src/field.ts (1)
BUFFERSTROKEN_CONSTANT(23-23)
🔇 Additional comments (23)
fdm-core/src/field.test.ts (4)
59-63: Unit-square geometry change LGTMSimple, valid polygon. Good for deterministic area/perimeter in tests.
427-431: Unit-square geometry in update test LGTM
506-510: Unit-square geometry in partial-update test LGTM
731-733: Catalogue defaults updated LGTMExplicit boolean and empty array are sensible defaults for test data.
fdm-app/app/routes/farm.create.$b_id_farm.$calendar.fields.tsx (3)
106-108: Loader data destructuring LGTM
139-147: Proceed button disabling condition LGTMDisables when no visible fields (respects current filter).
156-179: Sidebar Card composition LGTMGood integration of the filter toggle into the header and a clear back-to-map footer.
.changeset/clear-bats-find.md (1)
5-6: Changeset LGTMClear and aligned with the PR intent.
.changeset/lemon-spies-cheat.md (1)
5-6: Changeset LGTMAccurately documents the new b_isproductive in getCultivationPlan output.
fdm-app/app/components/blocks/norms/field-norms.tsx (1)
8-9: Good UX addition; confirm data is filtered when toggledHeader integration looks good. Please confirm the list of fieldNorms respects showProductiveOnly (either filtered upstream or handled here); otherwise the toggle won’t affect this view.
If needed, mirror the optional approach from the table: read showProductiveOnly from the store and filter out entries where b_isproductive === false before mapping.
Also applies to: 43-46
fdm-core/src/field.d.ts (1)
11-11: Types extended appropriately; document null semanticsb_perimeter: number | null and b_isproductive: boolean | null are fine. Please document how null is treated downstream (e.g., null => treat as productive) to keep filtering consistent across UI and loaders.
Ensure the following are updated accordingly:
- getField/getFields return shapes include these props.
- Any CSV/GeoJSON export or shapefile processing that serializes fields accounts for the new keys (either emitting null or omitting).
Also applies to: 15-15
fdm-app/app/components/custom/field-filter-toggle.tsx (1)
1-1: PanelsRightBottom support confirmed lucide-react is pinned to ^0.544.0, which includes PanelsRightBottom (introduced in v0.302.0).fdm-app/app/components/blocks/fields/table.tsx (1)
44-44: Toggle added but DataTable doesn’t filter by productive flag
Confirm that parent routes filter thedataarray byb_isproductivebefore passing it into this component; otherwise toggling “productive only” won’t change the table. If you’d prefer local handling, wrapdatain auseMemothat appliesshowProductiveOnlyfromuseFieldFilterStore(e.g. filter out items whereb_isproductive === false) before passing touseReactTable.fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx (3)
184-191: Client-side filtering looks good.Filter guard reads well and matches the toggle semantics.
242-247: Title wrapper LGTM.Structure change is fine and non-breaking.
252-253: Passing filtered data to the table is correct.Right source connected to the DataTable.
fdm-app/app/routes/farm.$b_id_farm.$calendar.balance.nitrogen._index.tsx (1)
144-145: Productive-only filtering is wired correctly; clarify totals behavior.
- Using the store, filtering the field list, and rendering the toggle in the card header all look correct.
- Confirm whether the toggle should also affect company-level totals (balance/supply/removal/emission). Currently, only the list respects the filter, which may be surprising to users.
If totals should respect the filter, we can derive filtered aggregates from
resolvedNitrogenBalanceResult.fieldssimilarly to the list.Also applies to: 216-223, 325-328, 333-365
fdm-core/src/cultivation.d.ts (2)
32-32: Type addition LGTM.
b_isproductive: booleanon fields aligns with runtime changes.
42-46: Type fixes LGTM.Corrected
b_id_harvestingandb_id_harvestablereferences reflect schema types.fdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsx (3)
175-176: Returning fields (not fieldOptions) is fine.Downstream transformation to options is handled locally; this keeps the loader generic.
267-283: Filtering logic is correct and consistent.Using a
fieldsMapto consultb_isproductiveis efficient and clear.
300-302: Props wiring LGTM.Filtered norms and rebuilt fieldOptions are correctly passed.
fdm-app/app/components/blocks/cultivation/list-plan.tsx (1)
100-103: Area formatting LGTM.Threshold display for small areas is clear and user-friendly.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
fdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsx (1)
169-177: Avoid sending full field objects (likely includes geometry); return minimal shape.Returning
fieldsdirectly can bloat the streamed payload (SSR) and leak unnecessary data (e.g., geometry). Return only{ b_id, b_name, b_isproductive }.Apply this diff to the return:
- fields: fields, + fields: fieldsBasic,Add this mapping after fetching
fields:// Keep client payload minimal (avoid b_geometry and other heavy props) const fieldsBasic = fields.map((f) => ({ b_id: f.b_id, b_name: f.b_name, b_isproductive: f.b_isproductive, }))
🧹 Nitpick comments (8)
fdm-core/src/soil.test.ts (1)
147-165: Correct use ofawait expect(...).rejects.
Assertion matches error wrapping behavior fromhandleError.Consider asserting on the specific cause too to reduce brittleness:
await expect(addSoilAnalysis(/*...*/)).rejects.toThrowError(/addSoilAnalysis/)fdm-core/src/field.ts (3)
190-193: Avoid using rounded area for classification.
b_areais rounded to 2 decimals (ha). Near the 2.5 ha boundary this can misclassify fields. Compute the heuristic with unrounded area.Proposed approach (outside this range):
- Add an unrounded area alias in both queries (e.g.,
b_area_ha_raw) and use it fordetermineIfFieldIsProductiveByShape, keeping roundedb_areafor display.Example change in both select projections:
b_area: sql<number>`ROUND((ST_Area(b_geometry::geography)/10000)::NUMERIC, 2)::FLOAT`, b_area_ha_raw: sql<number>`(ST_Area(b_geometry::geography)/10000)::FLOAT`,Then update usage:
field[0].b_isproductive = determineIfFieldIsProductiveByShape( field[0].b_area_ha_raw, field[0].b_perimeter, )
303-306: Same: use unrounded area forb_isproductivein the loop.
Mirror the change here to keep consistency between single and batch fetch.
654-665: Minor: declare an explicit return type.
Make the function signature explicit and slightly more defensive.Apply:
-export function determineIfFieldIsProductiveByShape( - b_area: number, - b_perimeter: number, -) { +export function determineIfFieldIsProductiveByShape( + b_area: number, + b_perimeter: number, +): boolean { const BUFFERSTROKEN_CONSTANT = 20 return ( b_perimeter / Math.sqrt(b_area * 10000) < BUFFERSTROKEN_CONSTANT || b_area >= 2.5 ) }fdm-app/app/store/storage.ts (1)
3-14: Harden storage detection and add a resilient fallback.
windowexisting doesn’t guaranteelocalStorageis usable (e.g., Safari private mode). Wrap in try/catch and use in-memory fallback.Apply:
-const createSSRStorage = (): StateStorage => { - if (typeof window !== "undefined") { - return localStorage - } - - // Return a no-op storage for SSR - return { - getItem: (_name: string) => null, - setItem: (_name: string, _value: string) => {}, - removeItem: (_name: string) => {}, - } -} +const createSSRStorage = (): StateStorage => { + if (typeof window !== "undefined") { + try { + const testKey = "__z_test__" + window.localStorage.setItem(testKey, "1") + window.localStorage.removeItem(testKey) + return window.localStorage + } catch { + // fall through to memory storage + } + } + + // Memory storage for SSR or blocked storage environments + const memory = new Map<string, string>() + return { + getItem: (name: string) => memory.get(name) ?? null, + setItem: (name: string, value: string) => { + memory.set(name, value) + }, + removeItem: (name: string) => { + memory.delete(name) + }, + } +}fdm-app/app/routes/farm.create.$b_id_farm.$calendar.fields.tsx (2)
105-122: Use a selector to reduce re-renders.
Select justshowProductiveOnlyfrom the store.Apply:
- const { showProductiveOnly } = useFieldFilterStore() + const showProductiveOnly = useFieldFilterStore((s) => s.showProductiveOnly)
108-122: Optional: micro-optimizations.
UseIntl.NumberFormatif you later display areas here; stable formatting across locales.fdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsx (1)
224-224: Use a selector with zustand to avoid unnecessary re-renders.Select only
showProductiveOnlyinstead of subscribing to the entire store.Apply this diff:
- const { showProductiveOnly } = useFieldFilterStore() + const showProductiveOnly = useFieldFilterStore((s) => s.showProductiveOnly)Based on learnings
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
-
.changeset/five-hairs-chew.md(1 hunks) -
.changeset/pretty-comics-drop.md(1 hunks) -
fdm-app/app/components/blocks/cultivation/list-plan.tsx(4 hunks) -
fdm-app/app/components/custom/field-filter-toggle.tsx(1 hunks) -
fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx(5 hunks) -
fdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsx(5 hunks) -
fdm-app/app/routes/farm.create.$b_id_farm.$calendar.fields.tsx(6 hunks) -
fdm-app/app/store/changelog.ts(2 hunks) -
fdm-app/app/store/field-filter.ts(1 hunks) -
fdm-app/app/store/storage.ts(1 hunks) -
fdm-core/src/cultivation.ts(3 hunks) -
fdm-core/src/field.test.ts(12 hunks) -
fdm-core/src/field.ts(5 hunks) -
fdm-core/src/soil.test.ts(9 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
- fdm-app/app/components/custom/field-filter-toggle.tsx
- fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx
- .changeset/five-hairs-chew.md
- fdm-core/src/field.test.ts
- fdm-core/src/cultivation.ts
- fdm-app/app/store/field-filter.ts
🧰 Additional context used
🧠 Learnings (13)
📚 Learning: 2025-01-31T15:05:14.310Z
Learnt from: SvenVw
PR: SvenVw/fdm#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:
.changeset/pretty-comics-drop.md
📚 Learning: 2025-01-31T15:34:20.850Z
Learnt from: SvenVw
PR: SvenVw/fdm#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:
.changeset/pretty-comics-drop.md
📚 Learning: 2025-09-25T15:10:59.699Z
Learnt from: SvenVw
PR: SvenVw/fdm#272
File: fdm-app/app/store/field-fertilizer-form.tsx:45-47
Timestamp: 2025-09-25T15:10:59.699Z
Learning: In the FDM application, Zustand stores with persist middleware using sessionStorage/localStorage don't require SSR hardening guards. The existing store patterns in fdm-app work without typeof window checks or memory storage fallbacks, as evidenced by the changelog store using createJSONStorage(() => localStorage) directly.
Applied to files:
fdm-app/app/store/storage.tsfdm-app/app/store/changelog.ts
📚 Learning: 2025-09-25T15:10:59.699Z
Learnt from: SvenVw
PR: SvenVw/fdm#272
File: fdm-app/app/store/field-fertilizer-form.tsx:45-47
Timestamp: 2025-09-25T15:10:59.699Z
Learning: In the FDM application, Zustand stores with persist middleware using sessionStorage/localStorage don't require SSR hardening guards. The existing store patterns in fdm-app work without typeof window checks or memory storage fallbacks.
Applied to files:
fdm-app/app/store/storage.tsfdm-app/app/store/changelog.ts
📚 Learning: 2025-08-11T12:24:32.200Z
Learnt from: SvenVw
PR: SvenVw/fdm#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/cultivation/list-plan.tsx
📚 Learning: 2025-04-18T13:49:17.029Z
Learnt from: SvenVw
PR: SvenVw/fdm#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/components/blocks/cultivation/list-plan.tsx
📚 Learning: 2025-01-14T16:06:24.294Z
Learnt from: SvenVw
PR: SvenVw/fdm#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/components/blocks/cultivation/list-plan.tsx
📚 Learning: 2025-01-14T16:06:21.832Z
Learnt from: SvenVw
PR: SvenVw/fdm#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/components/blocks/cultivation/list-plan.tsx
📚 Learning: 2025-01-09T16:03:37.764Z
Learnt from: SvenVw
PR: SvenVw/fdm#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.create.$b_id_farm.$calendar.fields.tsx
📚 Learning: 2025-09-23T12:27:07.359Z
Learnt from: SvenVw
PR: SvenVw/fdm#274
File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:151-204
Timestamp: 2025-09-23T12:27:07.359Z
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.create.$b_id_farm.$calendar.fields.tsx
📚 Learning: 2025-01-09T16:03:37.764Z
Learnt from: SvenVw
PR: SvenVw/fdm#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.create.$b_id_farm.$calendar.fields.tsx
📚 Learning: 2025-09-23T12:29:34.158Z
Learnt from: SvenVw
PR: SvenVw/fdm#274
File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:160-163
Timestamp: 2025-09-23T12:29:34.158Z
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.norms.tsx
📚 Learning: 2025-09-23T12:37:58.700Z
Learnt from: SvenVw
PR: SvenVw/fdm#274
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx:113-148
Timestamp: 2025-09-23T12:37:58.700Z
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.norms.tsx
🧬 Code graph analysis (6)
fdm-app/app/components/blocks/cultivation/list-plan.tsx (1)
fdm-core/src/db/schema.ts (1)
fields(87-103)
fdm-app/app/routes/farm.create.$b_id_farm.$calendar.fields.tsx (4)
fdm-app/app/store/field-filter.ts (1)
useFieldFilterStore(10-24)fdm-app/app/components/blocks/header/create-farm.tsx (1)
HeaderFarmCreate(8-80)fdm-app/app/components/custom/field-filter-toggle.tsx (1)
FieldFilterToggle(11-44)fdm-app/app/components/custom/sidebar-page.tsx (1)
SidebarPage(12-49)
fdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsx (2)
fdm-core/src/db/schema.ts (1)
fields(87-103)fdm-app/app/store/field-filter.ts (1)
useFieldFilterStore(10-24)
fdm-core/src/soil.test.ts (2)
fdm-core/src/db/schema.ts (1)
fieldsTypeInsert(106-106)fdm-core/src/soil.ts (1)
addSoilAnalysis(35-98)
fdm-core/src/field.ts (1)
fdm-core/src/db/schema.ts (1)
fields(87-103)
fdm-app/app/store/changelog.ts (1)
fdm-app/app/store/storage.ts (1)
ssrSafeJSONStorage(16-16)
🔇 Additional comments (13)
fdm-core/src/soil.test.ts (3)
19-19: Nice type alias to keep tests aligned with schema.
Keeps geometry typing DRY and resilient to future changes.
52-63: LGTM: Geometry typed via alias.
Clear and correct GeoJSON polygon for test setup.
410-419: Good switch from.mapto.forEachfor side-effect assertions.
Avoids creating unused arrays while keeping per-item checks.Also applies to: 431-439, 452-460, 473-478, 491-496
fdm-core/src/field.ts (1)
281-282: Same perimeter issue in fields list query.
Duplicate of the above; switch toST_Perimeter(...)here as well..changeset/pretty-comics-drop.md (1)
5-5: Changeset reads well.
Scope and API surface changes are clear.fdm-app/app/store/changelog.ts (2)
4-4: Good move to SSR-safe storage.
Prevents server-side crashes while keeping client persistence.
49-50: Storage provider integration looks correct.
createJSONStorage(() => ssrSafeJSONStorage)matches the new adapter.fdm-app/app/routes/farm.create.$b_id_farm.$calendar.fields.tsx (3)
91-96: Loader shape change is clear and aligns with client-side filtering.
Returning rawfieldsenables local sort/filter without extra roundtrips.
142-156: Continue button disablement respects filtered list.
Nice UX detail; prevents navigating with no visible fields.
160-184: Good: Toggle exposed in the sidebar header and applied to items.
Matches the persistent filter objective.fdm-app/app/components/blocks/cultivation/list-plan.tsx (1)
33-54: Apply productive-only filter/toggle and ensure unique React keys
- Read
showProductiveOnlyfromuseFieldFilterStore(), filtercultivation.fieldsbefore computingb_area, add<FieldFilterToggle />to the header, and formattotalAreawithNumber(totalArea.toFixed(1)).- Confirm
b_lu_catalogueis unique before using it askey={cultivation.b_lu_catalogue}in each<NavLink>(e.g. line 73); if duplicates are possible, append an index (\${b_lu_catalogue}-${index}``) or use a stable unique ID.fdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsx (2)
29-35: Imports LGTM.Correct integration of the filter store and UI components.
300-302: Prop wiring LGTM.Passing
filteredFieldNormsand computedfieldOptionsis correct.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
fdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsx (2)
271-276: Memoize filtering to avoid recomputation on re-renders.Logic
=== trueis fine given the monorepo guarantee; wrap the map and filter inuseMemofor stability/perf.As per learnings
Apply:
- const fieldsMap = new Map(loaderData.fields.map((f) => [f.b_id, f])) - const filteredFieldNorms = fieldNorms.filter((fieldNorm) => { - if (!showProductiveOnly) return true - const fieldData = fieldsMap.get(fieldNorm.b_id) - return fieldData ? fieldData.b_isproductive === true : false - }) + const fieldsMap = useMemo( + () => new Map(loaderData.fields.map((f) => [f.b_id, f])), + [loaderData.fields], + ) + const filteredFieldNorms = useMemo( + () => + !showProductiveOnly + ? fieldNorms + : fieldNorms.filter((fieldNorm) => { + const fieldData = fieldsMap.get(fieldNorm.b_id) + return fieldData + ? fieldData.b_isproductive === true + : false + }), + [showProductiveOnly, fieldNorms, fieldsMap], + )And add import:
-import { Suspense, use } from "react" +import { Suspense, use, useMemo } from "react"
294-296: Sorting by area: ensure desired ordering before render.If
FieldNormsdoesn’t sort, consider pre-sorting byb_areato satisfy the PR goal.Option:
- <FieldNorms - fieldNorms={filteredFieldNorms} - fieldOptions={fieldOptions} - /> + <FieldNorms + fieldNorms={[...filteredFieldNorms].sort((a, b) => b.b_area - a.b_area)} + fieldOptions={fieldOptions} + />If
FieldNormsalready handles sorting, ignore this.
📜 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.norms.tsx(5 hunks)
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-01-09T16:03:37.764Z
Learnt from: SvenVw
PR: SvenVw/fdm#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.norms.tsx
📚 Learning: 2025-09-23T12:29:34.158Z
Learnt from: SvenVw
PR: SvenVw/fdm#274
File: fdm-app/app/routes/farm.$b_id_farm._index.tsx:160-163
Timestamp: 2025-09-23T12:29:34.158Z
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.norms.tsx
📚 Learning: 2025-09-26T08:34:50.347Z
Learnt from: SvenVw
PR: SvenVw/fdm#279
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsx:277-283
Timestamp: 2025-09-26T08:34:50.347Z
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.norms.tsx
📚 Learning: 2025-08-13T10:33:05.313Z
Learnt from: SvenVw
PR: SvenVw/fdm#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.norms.tsx
📚 Learning: 2025-09-23T12:37:58.700Z
Learnt from: SvenVw
PR: SvenVw/fdm#274
File: fdm-app/app/routes/farm.$b_id_farm.$calendar.field._index.tsx:113-148
Timestamp: 2025-09-23T12:37:58.700Z
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.norms.tsx
🧬 Code graph analysis (1)
fdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsx (2)
fdm-core/src/db/schema.ts (1)
fields(87-103)fdm-app/app/store/field-filter.ts (1)
useFieldFilterStore(10-24)
🔇 Additional comments (4)
fdm-app/app/routes/farm.$b_id_farm.$calendar.norms.tsx (4)
29-34: Imports integration looks good.All newly added imports are used. No dead code introduced.
224-224: Good: persistent filter state wired in.Using
useFieldFilterStore()here aligns with the persisted toggle from zustand.
267-270: Nice fix: filter invalid fields instead of throwing.Pre-filtering
loaderData.fieldsforb_idandb_nameavoids render-time exceptions and matches prior feedback.
169-177: NoloaderData.fieldOptionsusages in norms route
This file usesloaderData.fieldsand derivesfieldOptionslocally.
Summary by CodeRabbit
New Features
UI/UX
Chores
Closes #249