Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
d92a03c
feat: add shadcn/ui scroll area
SvenVw Nov 6, 2025
a50bb0f
feat: Show fertilizer icon in the fields table for fertilizers
SvenVw Nov 6, 2025
ada7a6a
feat: add a rotation page
SvenVw Nov 6, 2025
5fc1657
feat: add harvest dates to table
SvenVw Nov 7, 2025
ca700b8
refactor: improve the code for rotation page
SvenVw Nov 7, 2025
4c0f3c3
refactor: improve search bar
SvenVw Nov 7, 2025
5f05efd
feat: add page for adding fertilizer to multiple fields based on cult…
SvenVw Nov 7, 2025
1dc9d50
feat: add page to add harvest to mutliple fields based on cultivation
SvenVw Nov 7, 2025
f974da7
Merge branch 'development' into FDM283
SvenVw Nov 13, 2025
c0519a8
Implement fertilizer management route for the cultivation fertilizer …
BoraIneviNMI Nov 13, 2025
cef087f
Add fieldIds search param to cultivation plan add fertilizer application
BoraIneviNMI Nov 13, 2025
9c224a3
Also to add harvest
BoraIneviNMI Nov 13, 2025
f91b378
Fix wrong path to fields
BoraIneviNMI Nov 13, 2025
044411e
Key using cultivation ids since it is more semantically correct
BoraIneviNMI Nov 13, 2025
64db20d
Catch unharvestable fields early and display a toast notification
BoraIneviNMI Nov 13, 2025
eed53b4
Change not harvestable message
BoraIneviNMI Nov 14, 2025
ed01393
Implement productive field filter client-side
BoraIneviNMI Nov 17, 2025
c978f33
Refactor search
BoraIneviNMI Nov 17, 2025
6bce0bc
Fix filtered column names
BoraIneviNMI Nov 17, 2025
d4b9d74
Fix bug with all cultivations showing harvest dates of all cultivatio…
BoraIneviNMI Nov 17, 2025
a6b5c4d
Always show the harvest date for cultivations that can only be harves…
BoraIneviNMI Nov 17, 2025
d41c554
Implement the confirmation dialog for overwriting a harvest
BoraIneviNMI Nov 18, 2025
7cde4e1
Reset submitted also if the confirmation dialog is rejected
BoraIneviNMI Nov 18, 2025
ebd9277
Resolve nitpicks
BoraIneviNMI Nov 18, 2025
3c1d4f6
Use form isSubmitting state instead of manual tracking
BoraIneviNMI Nov 18, 2025
4e9d752
Load existing harvest properly when the cultivation is only harvestab…
BoraIneviNMI Nov 18, 2025
578a34e
Retrieve harvest form default values properly
BoraIneviNMI Nov 18, 2025
99d0e36
Implement harvest delete functionality for cultivation plan
BoraIneviNMI Nov 18, 2025
0e80b74
Merge branch 'development' into FDM283
BoraIneviNMI Nov 20, 2025
2d6ee49
Get b_lu_harvestable, b_lu_start, and b_lu_end from the cultivation a…
BoraIneviNMI Nov 20, 2025
06611ca
Add inline harvest form
BoraIneviNMI Nov 20, 2025
b0cb510
Change title and description based on if this is a harvest update on …
BoraIneviNMI Nov 20, 2025
4f641ca
Merge branch 'development' into FDM283
BoraIneviNMI Nov 20, 2025
e817ab9
Search in all selected fields for a harvest application
BoraIneviNMI Nov 20, 2025
b0cc642
Replace quick action on the front page with cultivation plan
BoraIneviNMI Nov 20, 2025
a1efd1f
fix: safe sorting of empty array's
SvenVw Nov 21, 2025
d4d8b5b
Get default harvest parameters for all number of allowed harvests
BoraIneviNMI Nov 21, 2025
3ea2fc2
refactor: improve error message for missing harvest parameters
SvenVw Nov 21, 2025
7f74035
Merge remote-tracking branch 'origin/FDM283' into FDM283
SvenVw Nov 21, 2025
477c419
fix: Check for empty object
BoraIneviNMI Nov 21, 2025
a1db2e4
refactor: improve Harvest form components name
SvenVw Nov 21, 2025
9299366
Merge remote-tracking branch 'origin/FDM283' into FDM283
SvenVw Nov 21, 2025
50e5e22
fix: Use action in inline harvest form delete
BoraIneviNMI Nov 21, 2025
a750a35
refactor: use appropiate sorting functions in rotation table
SvenVw Nov 21, 2025
96f0896
refactot: disable addHarvest button when cultivation is not harvestable
SvenVw Nov 21, 2025
a25913c
refactor: improve text on farm dashboard
SvenVw Nov 21, 2025
20875bb
fix: send 400 when cultivation is not known in catalogue
SvenVw Nov 21, 2025
cdb16f1
fix: import
SvenVw Nov 21, 2025
877aad7
refactor: improve text
SvenVw Nov 21, 2025
a7d459d
fix: confirmation check if first field is not harvested yet
SvenVw Nov 21, 2025
d3c673c
fix: Make harvest writes atomic across fields
SvenVw Nov 21, 2025
5504f48
Revert "fix: Make harvest writes atomic across fields"
SvenVw Nov 21, 2025
37f9ec1
fix: Handle the case of no selected fields in loader
BoraIneviNMI Nov 21, 2025
09c5abd
refactor: Improve typechecking in the add harvest to cultivation route
BoraIneviNMI Nov 21, 2025
bfff011
refactor: Parallelize add fertilizer api calls in the add fertilizer …
BoraIneviNMI Nov 21, 2025
4e4a0ce
fix: Handle date input prop value of type Date
BoraIneviNMI Nov 21, 2025
813e01b
refactor: Unify how changes in the open state of the selection dialog…
BoraIneviNMI Nov 21, 2025
66d5e74
refactor: Improve the effect that sets the internal state according t…
BoraIneviNMI Nov 21, 2025
0c2b47d
refactor: Do either internal or external state update per render
BoraIneviNMI Nov 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fluffy-sides-like.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@svenvw/fdm-app": minor
---

Show fertilizer icon in the fields table for fertilizers
5 changes: 5 additions & 0 deletions .changeset/goofy-results-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@svenvw/fdm-app": minor
---

Add a rotation page that shows per cultivation the details in a table
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ import {
FormSchema,
FormSchemaModify,
} from "./formschema"
import type { FertilizerOption } from "./types.d"

export type FertilizerOption = {
value: string
label: string
applicationMethodOptions?: { value: string; label: string }[]
}

export function FertilizerApplicationForm({
options,
Expand Down Expand Up @@ -153,7 +158,7 @@ export function FertilizerApplicationForm({
}

return (
<RemixFormProvider {...form}>
<RemixFormProvider {...(form as any)}>
<Form
id={formId}
action={action}
Expand Down
47 changes: 33 additions & 14 deletions fdm-app/app/components/blocks/fields/columns.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import type { ColumnDef } from "@tanstack/react-table"
import { ArrowUpRightFromSquare, MoreHorizontal } from "lucide-react"
import {
ArrowUpRightFromSquare,
Circle,
Diamond,
MoreHorizontal,
Square,
Triangle,
} from "lucide-react"
import { NavLink } from "react-router-dom"
import { getCultivationColor } from "~/components/custom/cultivation-colors"
import { Badge } from "~/components/ui/badge"
Expand All @@ -21,9 +28,11 @@ export type FieldExtended = {
b_lu_name: string
b_lu_croprotation: string
b_lu_start: Date
}[]
fertilizerApplications: {
}[]
fertilizers: {
p_name_nl: string
p_id: string
p_type: string
}[]
a_som_loi: number
b_soiltype_agr: string
Expand Down Expand Up @@ -119,9 +128,9 @@ export const columns: ColumnDef<FieldExtended>[] = [
enableSorting: true,
sortingFn: (rowA, rowB, _columnId) => {
const fertilizerA =
rowA.original.fertilizerApplications[0]?.p_name_nl || ""
rowA.original.fertilizers[0]?.p_name_nl || ""
const fertilizerB =
rowB.original.fertilizerApplications[0]?.p_name_nl || ""
rowB.original.fertilizers[0]?.p_name_nl || ""
return fertilizerA.localeCompare(fertilizerB)
},
Comment on lines 129 to 135
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix unsafe array access in sorting function.

The sorting function accesses fertilizers[0].p_name_nl without checking if the array is empty, which will cause a runtime error when a field has no fertilizers.

Apply this diff to safely handle empty arrays:

         sortingFn: (rowA, rowB, _columnId) => {
             const fertilizerA =
-                rowA.original.fertilizers[0].p_name_nl || ""
+                rowA.original.fertilizers[0]?.p_name_nl || ""
             const fertilizerB =
-                rowB.original.fertilizers[0].p_name_nl || ""
+                rowB.original.fertilizers[0]?.p_name_nl || ""
             return fertilizerA.localeCompare(fertilizerB)
         },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sortingFn: (rowA, rowB, _columnId) => {
const fertilizerA =
rowA.original.fertilizerApplications[0]?.p_name_nl || ""
rowA.original.fertilizers[0].p_name_nl || ""
const fertilizerB =
rowB.original.fertilizerApplications[0]?.p_name_nl || ""
rowB.original.fertilizers[0].p_name_nl || ""
return fertilizerA.localeCompare(fertilizerB)
},
sortingFn: (rowA, rowB, _columnId) => {
const fertilizerA =
rowA.original.fertilizers[0]?.p_name_nl || ""
const fertilizerB =
rowB.original.fertilizers[0]?.p_name_nl || ""
return fertilizerA.localeCompare(fertilizerB)
},
🤖 Prompt for AI Agents
In fdm-app/app/components/blocks/fields/columns.tsx around lines 129 to 135, the
sorting function directly accesses fertilizers[0].p_name_nl which will throw if
fertilizers is empty or undefined; change the extraction to safely handle
missing arrays/properties (e.g. use optional chaining and a default:
rowA.original.fertilizers?.[0]?.p_name_nl ?? "" and same for rowB) so the
function never accesses index 0 of an empty array and returns a consistent
string for localeCompare.

header: ({ column }) => {
Expand All @@ -130,18 +139,28 @@ export const columns: ColumnDef<FieldExtended>[] = [
)
},
cell: ({ row }) => {
const field = row.original

const uniqueFertilizerNames = [...field.fertilizerApplications]
.map((app) => app.p_name_nl)
.filter((name, index, self) => self.indexOf(name) === index)
.sort((a, b) => a.localeCompare(b))
const fertilizers = row.original.fertilizers

return (
<div className="flex items-start flex-col space-y-2">
{uniqueFertilizerNames.map((fertilizer) => (
<Badge key={fertilizer} variant="outline">
{fertilizer}
{fertilizers.map((fertilizer) => (
<Badge
key={fertilizer.p_id}
variant="outline"
className="text-muted-foreground gap-1"
>
<span>
{fertilizer.p_type === "manure" ? (
<Square className="size-3 text-yellow-600 fill-yellow-600" />
) : fertilizer.p_type === "mineral" ? (
<Circle className="size-3 text-sky-600 fill-sky-600" />
) : fertilizer.p_type === "compost" ? (
<Triangle className="size-3 text-green-600 fill-green-600" />
) : (
<Diamond className="size-3 text-gray-600 fill-gray-600" />
)}
</span>
{fertilizer.p_name_nl}
</Badge>
))}
</div>
Expand Down
4 changes: 2 additions & 2 deletions fdm-app/app/components/blocks/fields/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export function DataTable<TData extends FieldExtended, TValue>({
const memoizedData = useMemo(() => {
return data.map((item) => ({
...item,
searchTarget: `${item.b_name} ${item.cultivations.map((c) => c.b_lu_name).join(" ")} ${item.fertilizerApplications.map((f) => f.p_name_nl).join(" ")} ${item.b_soiltype_agr}`,
searchTarget: `${item.b_name} ${item.cultivations.map((c) => c.b_lu_name).join(" ")} ${item.fertilizers.map((f) => f.p_name_nl).join(" ")} ${item.b_soiltype_agr}`,
}))
}, [data])

Expand Down Expand Up @@ -259,7 +259,7 @@ export function DataTable<TData extends FieldExtended, TValue>({
</TooltipProvider>
</div>
</div>
<div className="rounded-md border flex-grow relative overflow-x-auto">
<div className="rounded-md border grow relative overflow-x-auto">
<Table>
<TableHeader className="sticky top-0 z-10 bg-background">
{table.getHeaderGroups().map((headerGroup) => (
Expand Down
Loading