+>(({ className, ...props }, ref) => (
+ | [role=checkbox]]:translate-y-[2px]",
+ className
+ )}
+ {...props}
+ />
+))
+TableCell.displayName = "TableCell"
+
+const TableCaption = React.forwardRef<
+ HTMLTableCaptionElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+TableCaption.displayName = "TableCaption"
+
+export {
+ Table,
+ TableHeader,
+ TableBody,
+ TableFooter,
+ TableHead,
+ TableRow,
+ TableCell,
+ TableCaption,
+}
diff --git a/fdm-app/app/routes/farm.$b_id_farm.fertilizers._index.tsx b/fdm-app/app/routes/farm.$b_id_farm.fertilizers._index.tsx
index d8859f310..62cdc6079 100644
--- a/fdm-app/app/routes/farm.$b_id_farm.fertilizers._index.tsx
+++ b/fdm-app/app/routes/farm.$b_id_farm.fertilizers._index.tsx
@@ -1,10 +1,17 @@
import { FarmHeader } from "@/components/custom/farm/farm-header"
import { FarmTitle } from "@/components/custom/farm/farm-title"
+import { columns, Fertilizer } from "@/components/custom/fertilizer/columns"
+import { DataTable } from "@/components/custom/fertilizer/table"
import { SidebarInset } from "@/components/ui/sidebar"
import { getSession } from "@/lib/auth.server"
import { handleLoaderError } from "@/lib/error"
import { fdm } from "@/lib/fdm.server"
-import { getFarm, getFarms } from "@svenvw/fdm-core"
+import {
+ getFarm,
+ getFarms,
+ getFertilizer,
+ getFertilizers,
+} from "@svenvw/fdm-core"
import {
type LoaderFunctionArgs,
Outlet,
@@ -12,8 +19,6 @@ import {
useLoaderData,
} from "react-router"
-
-
export async function loader({ request, params }: LoaderFunctionArgs) {
try {
// Get the farm id
@@ -53,11 +58,20 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
}
})
+ // Get the available fertilizers
+ const fertilizers: Fertilizer[] = await getFertilizers(
+ fdm,
+ session.principal_id,
+ b_id_farm,
+ )
+ // console.log(fertilizers)
+
// Return user information from loader
return {
farm: farm,
b_id_farm: b_id_farm,
farmOptions: farmOptions,
+ fertilizers: fertilizers,
}
} catch (error) {
throw handleLoaderError(error)
@@ -88,7 +102,10 @@ export default function FarmFertilizersBlock() {
title={"Meststoffen"}
description={"Beheer de meststoffen van dit bedrijf"}
/>
-
+
+ {/* */}
+
+ {/* */}
)
diff --git a/fdm-app/package.json b/fdm-app/package.json
index 295d7dad6..6f810c5af 100644
--- a/fdm-app/package.json
+++ b/fdm-app/package.json
@@ -37,6 +37,7 @@
"@sentry/vite-plugin": "^3.2.2",
"@svenvw/fdm-calculator": "workspace:^",
"@svenvw/fdm-core": "workspace:^",
+ "@tanstack/react-table": "^8.21.2",
"@turf/centroid": "^7.2.0",
"better-auth": "catalog:",
"class-variance-authority": "^0.7.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5d81a0d80..95aaa6de2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -121,6 +121,9 @@ importers:
'@svenvw/fdm-core':
specifier: workspace:^
version: link:../fdm-core
+ '@tanstack/react-table':
+ specifier: ^8.21.2
+ version: 8.21.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@turf/centroid':
specifier: ^7.2.0
version: 7.2.0
@@ -3638,6 +3641,17 @@ packages:
resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==}
engines: {node: '>=14.16'}
+ '@tanstack/react-table@8.21.2':
+ resolution: {integrity: sha512-11tNlEDTdIhMJba2RBH+ecJ9l1zgS2kjmexDPAraulc8jeNA4xocSNeyzextT0XJyASil4XsCYlJmf5jEWAtYg==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ react: '>=16.8'
+ react-dom: '>=16.8'
+
+ '@tanstack/table-core@8.21.2':
+ resolution: {integrity: sha512-uvXk/U4cBiFMxt+p9/G7yUWI/UbHYbyghLCjlpWZ3mLeIZiUBSKcUnw9UnKkdRz7Z/N4UBuFLWQdJCjUe7HjvA==}
+ engines: {node: '>=12'}
+
'@trysound/sax@0.2.0':
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
engines: {node: '>=10.13.0'}
@@ -13212,6 +13226,14 @@ snapshots:
dependencies:
defer-to-connect: 2.0.1
+ '@tanstack/react-table@8.21.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@tanstack/table-core': 8.21.2
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+
+ '@tanstack/table-core@8.21.2': {}
+
'@trysound/sax@0.2.0': {}
'@turf/centroid@7.2.0':
From 404250b6aec865b82bd33b2c329f9ab4e4465dc9 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Wed, 26 Mar 2025 13:34:10 +0100
Subject: [PATCH 03/55] Add header options
---
.../custom/fertilizer/column-header.tsx | 66 +++++++++
.../components/custom/fertilizer/columns.tsx | 11 +-
.../components/custom/fertilizer/table.tsx | 135 +++++++++++-------
.../farm.$b_id_farm.fertilizers._index.tsx | 26 ++--
4 files changed, 176 insertions(+), 62 deletions(-)
create mode 100644 fdm-app/app/components/custom/fertilizer/column-header.tsx
diff --git a/fdm-app/app/components/custom/fertilizer/column-header.tsx b/fdm-app/app/components/custom/fertilizer/column-header.tsx
new file mode 100644
index 000000000..279503ebd
--- /dev/null
+++ b/fdm-app/app/components/custom/fertilizer/column-header.tsx
@@ -0,0 +1,66 @@
+import type { Column } from "@tanstack/react-table"
+import { ArrowDown, ArrowUp, ChevronsUpDown, EyeOff } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+import { Button } from "@/components/ui/button"
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuSeparator,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu"
+
+interface DataTableColumnHeaderProps
+ extends React.HTMLAttributes {
+ column: Column
+ title: string
+}
+
+export function DataTableColumnHeader({
+ column,
+ title,
+ className,
+}: DataTableColumnHeaderProps) {
+ if (!column.getCanSort()) {
+ return {title}
+ }
+
+ return (
+
+
+
+
+
+
+ column.toggleSorting(false)}>
+
+ Oplopend
+
+ column.toggleSorting(true)}>
+
+ Aflopend
+
+
+ column.toggleVisibility(false)}>
+
+ Verberg
+
+
+
+
+ )
+}
diff --git a/fdm-app/app/components/custom/fertilizer/columns.tsx b/fdm-app/app/components/custom/fertilizer/columns.tsx
index 7804dc585..68b8c3240 100644
--- a/fdm-app/app/components/custom/fertilizer/columns.tsx
+++ b/fdm-app/app/components/custom/fertilizer/columns.tsx
@@ -1,4 +1,7 @@
+import { Button } from "@/components/ui/button"
import type { ColumnDef } from "@tanstack/react-table"
+import { ArrowUpDown } from "lucide-react"
+import { DataTableColumnHeader } from "./column-header"
export type Fertilizer = {
p_id: string
@@ -19,10 +22,14 @@ export const columns: ColumnDef[] = [
},
{
accessorKey: "p_n_rt",
- header: "N",
+ header: ({ column }) => {
+ return
+ },
},
{
accessorKey: "p_p_rt",
- header: "P",
+ header: ({ column }) => {
+ return
+ },
},
]
diff --git a/fdm-app/app/components/custom/fertilizer/table.tsx b/fdm-app/app/components/custom/fertilizer/table.tsx
index 4ff7f439b..02d3a61d9 100644
--- a/fdm-app/app/components/custom/fertilizer/table.tsx
+++ b/fdm-app/app/components/custom/fertilizer/table.tsx
@@ -1,7 +1,11 @@
import {
type ColumnDef,
+ ColumnFiltersState,
flexRender,
getCoreRowModel,
+ getFilteredRowModel,
+ getSortedRowModel,
+ SortingState,
useReactTable,
} from "@tanstack/react-table"
import {
@@ -12,6 +16,8 @@ import {
TableHeader,
TableRow,
} from "@/components/ui/table"
+import { useState } from "react"
+import { Input } from "@/components/ui/input"
interface DataTableProps {
columns: ColumnDef[]
@@ -22,63 +28,94 @@ export function DataTable({
columns,
data,
}: DataTableProps) {
+ const [sorting, setSorting] = useState([])
+ const [columnFilters, setColumnFilters] = useState([])
+
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
+ onSortingChange: setSorting,
+ getSortedRowModel: getSortedRowModel(),
+ onColumnFiltersChange: setColumnFilters,
+ getFilteredRowModel: getFilteredRowModel(),
+ state: {
+ sorting,
+ columnFilters,
+ },
})
return (
-
-
-
- {table.getHeaderGroups().map((headerGroup) => (
-
- {headerGroup.headers.map((header) => {
- return (
-
- {header.isPlaceholder
- ? null
- : flexRender(
- header.column.columnDef
- .header,
- header.getContext(),
- )}
-
- )
- })}
-
- ))}
-
-
- {table.getRowModel().rows?.length ? (
- table.getRowModel().rows.map((row) => (
-
- {row.getVisibleCells().map((cell) => (
-
- {flexRender(
- cell.column.columnDef.cell,
- cell.getContext(),
- )}
-
- ))}
+
+
+
+ table
+ .getColumn("p_name_nl")
+ ?.setFilterValue(event.target.value)
+ }
+ className="max-w-sm"
+ />
+
+
+
+
+ {table.getHeaderGroups().map((headerGroup) => (
+
+ {headerGroup.headers.map((header) => {
+ return (
+
+ {header.isPlaceholder
+ ? null
+ : flexRender(
+ header.column.columnDef
+ .header,
+ header.getContext(),
+ )}
+
+ )
+ })}
+
+ ))}
+
+
+ {table.getRowModel().rows?.length ? (
+ table.getRowModel().rows.map((row) => (
+
+ {row.getVisibleCells().map((cell) => (
+
+ {flexRender(
+ cell.column.columnDef.cell,
+ cell.getContext(),
+ )}
+
+ ))}
+
+ ))
+ ) : (
+
+
+ Geen resultaten.
+
- ))
- ) : (
-
-
- Geen resultaten.
-
-
- )}
-
-
+ )}
+
+
+
)
}
diff --git a/fdm-app/app/routes/farm.$b_id_farm.fertilizers._index.tsx b/fdm-app/app/routes/farm.$b_id_farm.fertilizers._index.tsx
index 62cdc6079..1313f32b3 100644
--- a/fdm-app/app/routes/farm.$b_id_farm.fertilizers._index.tsx
+++ b/fdm-app/app/routes/farm.$b_id_farm.fertilizers._index.tsx
@@ -1,17 +1,15 @@
import { FarmHeader } from "@/components/custom/farm/farm-header"
import { FarmTitle } from "@/components/custom/farm/farm-title"
-import { columns, Fertilizer } from "@/components/custom/fertilizer/columns"
+import {
+ columns,
+ type Fertilizer,
+} from "@/components/custom/fertilizer/columns"
import { DataTable } from "@/components/custom/fertilizer/table"
import { SidebarInset } from "@/components/ui/sidebar"
import { getSession } from "@/lib/auth.server"
import { handleLoaderError } from "@/lib/error"
import { fdm } from "@/lib/fdm.server"
-import {
- getFarm,
- getFarms,
- getFertilizer,
- getFertilizers,
-} from "@svenvw/fdm-core"
+import { getFarm, getFarms, getFertilizers } from "@svenvw/fdm-core"
import {
type LoaderFunctionArgs,
Outlet,
@@ -102,10 +100,16 @@ export default function FarmFertilizersBlock() {
title={"Meststoffen"}
description={"Beheer de meststoffen van dit bedrijf"}
/>
-
- {/* */}
-
- {/* */}
+
)
From 4e5bf7a58bc9a8889592dcee1b08219db5fa052c Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Wed, 26 Mar 2025 13:56:06 +0100
Subject: [PATCH 04/55] Add button to go to page with details about fertilizer
---
.../components/custom/fertilizer/columns.tsx | 31 +++++++++++++++++--
1 file changed, 29 insertions(+), 2 deletions(-)
diff --git a/fdm-app/app/components/custom/fertilizer/columns.tsx b/fdm-app/app/components/custom/fertilizer/columns.tsx
index 68b8c3240..c9ebcd712 100644
--- a/fdm-app/app/components/custom/fertilizer/columns.tsx
+++ b/fdm-app/app/components/custom/fertilizer/columns.tsx
@@ -1,7 +1,15 @@
-import { Button } from "@/components/ui/button"
import type { ColumnDef } from "@tanstack/react-table"
-import { ArrowUpDown } from "lucide-react"
+import {
+ SquareArrowOutUpRight,
+} from "lucide-react"
import { DataTableColumnHeader } from "./column-header"
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger,
+} from "@/components/ui/tooltip"
+import { NavLink } from "react-router"
export type Fertilizer = {
p_id: string
@@ -32,4 +40,23 @@ export const columns: ColumnDef[] = [
return
},
},
+ {
+ accessorKey: "Opties",
+ cell: ({ row }) => {
+ const fertilizer = row.original
+
+ return (
+
+
+
+
+
+
+
+ {`Bekijk details over ${fertilizer.p_name_nl}`}
+
+
+ )
+ },
+ },
]
From 1bacbc21063e4f81453edbbd3da8e630e8e1ec44 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Wed, 26 Mar 2025 16:53:26 +0100
Subject: [PATCH 05/55] Add page for to see details of fertilizer
---
.../custom/fertilizer/formschema.tsx | 28 +
.../farm.$b_id_farm.fertilizers.$p_id.tsx | 578 ++++++++++++++++++
2 files changed, 606 insertions(+)
create mode 100644 fdm-app/app/components/custom/fertilizer/formschema.tsx
create mode 100644 fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
diff --git a/fdm-app/app/components/custom/fertilizer/formschema.tsx b/fdm-app/app/components/custom/fertilizer/formschema.tsx
new file mode 100644
index 000000000..bd0d56f6f
--- /dev/null
+++ b/fdm-app/app/components/custom/fertilizer/formschema.tsx
@@ -0,0 +1,28 @@
+import { z } from "zod"
+
+export const FormSchema = z.object({
+ p_n_rt: z.coerce.number({
+ invalid_type_error: "Ongeldige waarde",
+ }),
+ p_p_rt: z.coerce.number({
+ invalid_type_error: "Ongeldige waarde",
+ }),
+ p_k_rt: z.coerce.number({
+ invalid_type_error: "Ongeldige waarde",
+ }),
+ p_om: z.coerce.number({
+ invalid_type_error: "Ongeldige waarde",
+ }),
+ p_c_rt: z.coerce.number({
+ invalid_type_error: "Ongeldige waarde",
+ }),
+ p_s_rt: z.coerce.number({
+ invalid_type_error: "Ongeldige waarde",
+ }),
+ p_ca_rt: z.coerce.number({
+ invalid_type_error: "Ongeldige waarde",
+ }),
+ p_mg_rt: z.coerce.number({
+ invalid_type_error: "Ongeldige waarde",
+ }),
+})
diff --git a/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx b/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
new file mode 100644
index 000000000..614aeebdb
--- /dev/null
+++ b/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
@@ -0,0 +1,578 @@
+import { FarmHeader } from "@/components/custom/farm/farm-header"
+import { FarmTitle } from "@/components/custom/farm/farm-title"
+import { FormSchema } from "@/components/custom/fertilizer/formschema"
+import { Badge } from "@/components/ui/badge"
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from "@/components/ui/card"
+import {
+ FormControl,
+ FormDescription,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from "@/components/ui/form"
+import { Input } from "@/components/ui/input"
+import { SidebarInset } from "@/components/ui/sidebar"
+import { getSession } from "@/lib/auth.server"
+import { handleLoaderError } from "@/lib/error"
+import { fdm } from "@/lib/fdm.server"
+import { zodResolver } from "@hookform/resolvers/zod"
+import { getFarm, getFarms, getFertilizer } from "@svenvw/fdm-core"
+import { useEffect } from "react"
+import {
+ Form,
+ type LoaderFunctionArgs,
+ data,
+ useLoaderData,
+} from "react-router"
+import { RemixFormProvider, useRemixForm } from "remix-hook-form"
+import type { z } from "zod"
+
+export async function loader({ request, params }: LoaderFunctionArgs) {
+ try {
+ // Get the farm id
+ const b_id_farm = params.b_id_farm
+ if (!b_id_farm) {
+ throw data("invalid: b_id_farm", {
+ status: 400,
+ statusText: "invalid: b_id_farm",
+ })
+ }
+
+ // Get the fertilizer id
+ const p_id = params.p_id
+ if (!p_id) {
+ throw data("invalid: p_id", {
+ status: 400,
+ statusText: "invalid: p_id",
+ })
+ }
+
+ // Get the session
+ const session = await getSession(request)
+
+ // Get details of farm
+ const farm = await getFarm(fdm, session.principal_id, b_id_farm)
+ if (!farm) {
+ throw data("not found: b_id_farm", {
+ status: 404,
+ statusText: "not found: b_id_farm",
+ })
+ }
+
+ // Get a list of possible farms of the user
+ const farms = await getFarms(fdm, session.principal_id)
+ if (!farms || farms.length === 0) {
+ throw data("not found: farms", {
+ status: 404,
+ statusText: "not found: farms",
+ })
+ }
+
+ const farmOptions = farms.map((farm) => {
+ return {
+ b_id_farm: farm.b_id_farm,
+ b_name_farm: farm.b_name_farm,
+ }
+ })
+
+ // Get the available fertilizers
+ const fertilizer = await getFertilizer(fdm, p_id)
+
+ // Return user information from loader
+ return {
+ farm: farm,
+ b_id_farm: b_id_farm,
+ farmOptions: farmOptions,
+ fertilizer: fertilizer,
+ editable: true,
+ }
+ } catch (error) {
+ throw handleLoaderError(error)
+ }
+}
+
+/**
+ * Renders the layout for managing farm settings.
+ *
+ * This component displays a sidebar that includes the farm header, navigation options, and a link to farm fields.
+ * It also renders a main section containing the farm title, description, nested routes via an Outlet, and a notification toaster.
+ */
+export default function FarmFertilizerBlock() {
+ const loaderData = useLoaderData()
+ const fertilizer = loaderData.fertilizer
+
+ const form = useRemixForm>({
+ mode: "onTouched",
+ resolver: zodResolver(FormSchema),
+ defaultValues: {
+ p_n_rt: fertilizer.p_n_rt,
+ p_p_rt: fertilizer.p_p_rt,
+ p_k_rt: fertilizer.p_k_rt,
+ p_om: fertilizer.p_om,
+ p_c_rt: fertilizer.p_c_rt,
+ p_s_rt: fertilizer.p_s_rt,
+ p_ca_rt: fertilizer.p_ca_rt,
+ p_mg_rt: fertilizer.p_mg_rt,
+ },
+ })
+
+ useEffect(() => {
+ form.reset({
+ p_n_rt: fertilizer.p_n_rt,
+ p_p_rt: fertilizer.p_p_rt,
+ p_k_rt: fertilizer.p_k_rt,
+ p_om: fertilizer.p_om,
+ p_c_rt: fertilizer.p_c_rt,
+ p_s_rt: fertilizer.p_s_rt,
+ p_ca_rt: fertilizer.p_ca_rt,
+ p_mg_rt: fertilizer.p_mg_rt,
+ })
+ }, [fertilizer, form.reset])
+
+ return (
+
+
+
+
+
+
+
+ )
+}
From 542f55b8002389a47533f955a59c4bdc8cdd79c3 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Wed, 26 Mar 2025 17:13:45 +0100
Subject: [PATCH 06/55] When farm is created enable fertilizer catalogue with
custom fertilizers for that specific farm
---
.changeset/light-rockets-fly.md | 5 +++++
fdm-app/app/routes/farm.create._index.tsx | 7 +++++++
2 files changed, 12 insertions(+)
create mode 100644 .changeset/light-rockets-fly.md
diff --git a/.changeset/light-rockets-fly.md b/.changeset/light-rockets-fly.md
new file mode 100644
index 000000000..618351a5b
--- /dev/null
+++ b/.changeset/light-rockets-fly.md
@@ -0,0 +1,5 @@
+---
+"@svenvw/fdm-app": minor
+---
+
+When farm is created enable fertilizer catalogue with custom fertilizers for that specific farm
diff --git a/fdm-app/app/routes/farm.create._index.tsx b/fdm-app/app/routes/farm.create._index.tsx
index 3df2f86ae..41628384a 100644
--- a/fdm-app/app/routes/farm.create._index.tsx
+++ b/fdm-app/app/routes/farm.create._index.tsx
@@ -125,6 +125,13 @@ export async function action({ request }: ActionFunctionArgs) {
b_id_farm,
"srm",
)
+ // Enable catalogue with custom user fertilizers
+ await enableFertilizerCatalogue(
+ fdm,
+ session.principal_id,
+ b_id_farm,
+ b_id_farm,
+ )
await enableCultivationCatalogue(
fdm,
session.principal_id,
From 7e6623136d276b6aa5ca99b8f4540e8ccc10e6c7 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Wed, 26 Mar 2025 17:45:40 +0100
Subject: [PATCH 07/55] Add function `hashFertilizer` to create hash for
fertilizer
---
.changeset/dirty-pumas-cry.md | 5 ++
fdm-data/src/fertilizers/catalogues/srm.ts | 6 +-
fdm-data/src/fertilizers/d.ts | 94 +++++++++++-----------
fdm-data/src/fertilizers/hash.ts | 9 +++
fdm-data/src/index.ts | 3 +-
5 files changed, 65 insertions(+), 52 deletions(-)
create mode 100644 .changeset/dirty-pumas-cry.md
create mode 100644 fdm-data/src/fertilizers/hash.ts
diff --git a/.changeset/dirty-pumas-cry.md b/.changeset/dirty-pumas-cry.md
new file mode 100644
index 000000000..2e79bee7c
--- /dev/null
+++ b/.changeset/dirty-pumas-cry.md
@@ -0,0 +1,5 @@
+---
+"@svenvw/fdm-data": minor
+---
+
+Add function `hashFertilizer` to create hash for fertilizer
diff --git a/fdm-data/src/fertilizers/catalogues/srm.ts b/fdm-data/src/fertilizers/catalogues/srm.ts
index d5d09dcbb..5a3a150a2 100644
--- a/fdm-data/src/fertilizers/catalogues/srm.ts
+++ b/fdm-data/src/fertilizers/catalogues/srm.ts
@@ -1,8 +1,6 @@
import type { CatalogueFertilizer, CatalogueFertilizerItem } from "../d"
+import { hashFertilizer } from "../hash"
import srm from "./srm.json"
-import xxhash from "xxhash-wasm"
-
-const { h32ToString } = await xxhash()
/**
* Retrieves the SRM (Sluiting Regionale Kringlopen) fertilizer catalogue.
@@ -75,7 +73,7 @@ export function getCatalogueSrm(): CatalogueFertilizer {
}
// Hash the item
- item.hash = h32ToString(JSON.stringify(item))
+ item.hash = hashFertilizer(item)
return item
})
diff --git a/fdm-data/src/fertilizers/d.ts b/fdm-data/src/fertilizers/d.ts
index 3322684cf..f5c3a3162 100644
--- a/fdm-data/src/fertilizers/d.ts
+++ b/fdm-data/src/fertilizers/d.ts
@@ -1,55 +1,55 @@
export type CatalogueFertilizerName = "srm"
export interface CatalogueFertilizerItem {
- p_source: CatalogueFertilizerName
+ p_source: CatalogueFertilizerName | string
p_id_catalogue: string
p_name_nl: string
- p_name_en: string | null
- p_description: string | null
- p_dm: number | null
- p_density: number | null
- p_om: number | null
- p_a: number | null
- p_hc: number | null
- p_eom: number | null
- p_eoc: number | null
- p_c_rt: number | null
- p_c_of: number | null
- p_c_if: number | null
- p_c_fr: number | null
- p_cn_of: number | null
- p_n_rt: number | null
- p_n_if: number | null
- p_n_of: number | null
- p_n_wc: number | null
- p_p_rt: number | null
- p_k_rt: number | null
- p_mg_rt: number | null
- p_ca_rt: number | null
- p_ne: number | null
- p_s_rt: number | null
- p_s_wc: number | null
- p_cu_rt: number | null
- p_zn_rt: number | null
- p_na_rt: number | null
- p_si_rt: number | null
- p_b_rt: number | null
- p_mn_rt: number | null
- p_ni_rt: number | null
- p_fe_rt: number | null
- p_mo_rt: number | null
- p_co_rt: number | null
- p_as_rt: number | null
- p_cd_rt: number | null
- p_cr_rt: number | null
- p_cr_vi: number | null
- p_pb_rt: number | null
- p_hg_rt: number | null
- p_cl_cr: number | null
- p_type_manure: boolean | null
- p_type_mineral: boolean | null
- p_type_compost: boolean | null
- hash: string | null
+ p_name_en?: string | null | undefined
+ p_description?: string | null | undefined
+ p_dm?: number | null
+ p_density?: number | null
+ p_om?: number | null
+ p_a?: number | null
+ p_hc?: number | null
+ p_eom?: number | null
+ p_eoc?: number | null
+ p_c_rt?: number | null
+ p_c_of?: number | null
+ p_c_if?: number | null
+ p_c_fr?: number | null
+ p_cn_of?: number | null
+ p_n_rt?: number | null
+ p_n_if?: number | null
+ p_n_of?: number | null
+ p_n_wc?: number | null
+ p_p_rt?: number | null
+ p_k_rt?: number | null
+ p_mg_rt?: number | null
+ p_ca_rt?: number | null
+ p_ne?: number | null
+ p_s_rt?: number | null
+ p_s_wc?: number | null
+ p_cu_rt?: number | null
+ p_zn_rt?: number | null
+ p_na_rt?: number | null
+ p_si_rt?: number | null
+ p_b_rt?: number | null
+ p_mn_rt?: number | null
+ p_ni_rt?: number | null
+ p_fe_rt?: number | null
+ p_mo_rt?: number | null
+ p_co_rt?: number | null
+ p_as_rt?: number | null
+ p_cd_rt?: number | null
+ p_cr_rt?: number | null
+ p_cr_vi?: number | null
+ p_pb_rt?: number | null
+ p_hg_rt?: number | null
+ p_cl_cr?: number | null
+ p_type_manure?: boolean | null
+ p_type_mineral?: boolean | null
+ p_type_compost?: boolean | null
+ hash?: string | null | undefined
}
export type CatalogueFertilizer = CatalogueFertilizerItem[]
diff --git a/fdm-data/src/fertilizers/hash.ts b/fdm-data/src/fertilizers/hash.ts
new file mode 100644
index 000000000..218de4c07
--- /dev/null
+++ b/fdm-data/src/fertilizers/hash.ts
@@ -0,0 +1,9 @@
+import type { CatalogueFertilizerItem } from "./d"
+import xxhash from "xxhash-wasm"
+
+const { h32ToString } = await xxhash()
+
+export function hashFertilizer(fertilizer: CatalogueFertilizerItem) {
+ const hash = h32ToString(JSON.stringify(fertilizer))
+ return hash
+}
diff --git a/fdm-data/src/index.ts b/fdm-data/src/index.ts
index 1023c9216..ccc27fa66 100644
--- a/fdm-data/src/index.ts
+++ b/fdm-data/src/index.ts
@@ -11,5 +11,6 @@
* @packageDocumentation
*/
-export { getFertilizersCatalogue } from "./fertilizers"
+export { getFertilizersCatalogue} from "./fertilizers"
export { getCultivationCatalogue } from "./cultivations"
+export { hashFertilizer} from "./fertilizers/hash"
From c2404860dcd23fdee3685de5bddd84b84cbf8661 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Thu, 27 Mar 2025 12:01:51 +0100
Subject: [PATCH 08/55] Adapt function `addFertilizerToCatalogue` to add custom
fertilizers for a farm
---
.changeset/bright-buckets-rush.md | 5 +
fdm-core/src/cultivation.test.ts | 109 +++---
fdm-core/src/db/schema.ts | 2 +-
fdm-core/src/fertilizer.test.ts | 533 +++++++++++++++---------------
fdm-core/src/fertilizer.ts | 33 +-
5 files changed, 360 insertions(+), 322 deletions(-)
create mode 100644 .changeset/bright-buckets-rush.md
diff --git a/.changeset/bright-buckets-rush.md b/.changeset/bright-buckets-rush.md
new file mode 100644
index 000000000..3a5221fca
--- /dev/null
+++ b/.changeset/bright-buckets-rush.md
@@ -0,0 +1,5 @@
+---
+"@svenvw/fdm-core": minor
+---
+
+Adapt function `addFertilizerToCatalogue` to add custom fertilizers for a farm
diff --git a/fdm-core/src/cultivation.test.ts b/fdm-core/src/cultivation.test.ts
index da6702301..7dda3a37b 100644
--- a/fdm-core/src/cultivation.test.ts
+++ b/fdm-core/src/cultivation.test.ts
@@ -469,7 +469,6 @@ describe("Cultivation Data Model", () => {
let b_lu_catalogue: string
let p_id: string
let b_lu_source: string
- let p_source: string
beforeEach(async () => {
const farmName = "Test Farm"
@@ -492,13 +491,11 @@ describe("Cultivation Data Model", () => {
b_id_farm,
b_lu_source,
)
-
- p_source = "custom"
await enableFertilizerCatalogue(
fdm,
principal_id,
b_id_farm,
- p_source,
+ b_id_farm,
)
b_id = await addField(
@@ -544,63 +541,65 @@ describe("Cultivation Data Model", () => {
)
// Add fertilizer to catalogue (needed for fertilizer application)
- const p_id_catalogue = createId()
const p_name_nl = "Test Fertilizer"
const p_name_en = "Test Fertilizer (EN)"
const p_description = "This is a test fertilizer"
const p_acquiring_amount = 1000
const p_acquiring_date = new Date()
- await addFertilizerToCatalogue(fdm, {
- p_id_catalogue,
- p_source,
- p_name_nl,
- p_name_en,
- p_description,
- p_dm: 37,
- p_density: 20,
- p_om: 20,
- p_a: 30,
- p_hc: 40,
- p_eom: 50,
- p_eoc: 60,
- p_c_rt: 70,
- p_c_of: 80,
- p_c_if: 90,
- p_c_fr: 100,
- p_cn_of: 110,
- p_n_rt: 120,
- p_n_if: 130,
- p_n_of: 140,
- p_n_wc: 150,
- p_p_rt: 160,
- p_k_rt: 170,
- p_mg_rt: 180,
- p_ca_rt: 190,
- p_ne: 200,
- p_s_rt: 210,
- p_s_wc: 220,
- p_cu_rt: 230,
- p_zn_rt: 240,
- p_na_rt: 250,
- p_si_rt: 260,
- p_b_rt: 270,
- p_mn_rt: 280,
- p_ni_rt: 290,
- p_fe_rt: 300,
- p_mo_rt: 310,
- p_co_rt: 320,
- p_as_rt: 330,
- p_cd_rt: 340,
- pr_cr_rt: 350,
- p_cr_vi: 360,
- p_pb_rt: 370,
- p_hg_rt: 380,
- p_cl_rt: 390,
- p_type_manure: true,
- p_type_mineral: false,
- p_type_compost: false,
- })
+ const p_id_catalogue = await addFertilizerToCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm,
+ {
+ p_name_nl,
+ p_name_en,
+ p_description,
+ p_dm: 37,
+ p_density: 20,
+ p_om: 20,
+ p_a: 30,
+ p_hc: 40,
+ p_eom: 50,
+ p_eoc: 60,
+ p_c_rt: 70,
+ p_c_of: 80,
+ p_c_if: 90,
+ p_c_fr: 100,
+ p_cn_of: 110,
+ p_n_rt: 120,
+ p_n_if: 130,
+ p_n_of: 140,
+ p_n_wc: 150,
+ p_p_rt: 160,
+ p_k_rt: 170,
+ p_mg_rt: 180,
+ p_ca_rt: 190,
+ p_ne: 200,
+ p_s_rt: 210,
+ p_s_wc: 220,
+ p_cu_rt: 230,
+ p_zn_rt: 240,
+ p_na_rt: 250,
+ p_si_rt: 260,
+ p_b_rt: 270,
+ p_mn_rt: 280,
+ p_ni_rt: 290,
+ p_fe_rt: 300,
+ p_mo_rt: 310,
+ p_co_rt: 320,
+ p_as_rt: 330,
+ p_cd_rt: 340,
+ pr_cr_rt: 350,
+ p_cr_vi: 360,
+ p_pb_rt: 370,
+ p_hg_rt: 380,
+ p_cl_rt: 390,
+ p_type_manure: true,
+ p_type_mineral: false,
+ p_type_compost: false,
+ },
+ )
p_id = await addFertilizer(
fdm,
diff --git a/fdm-core/src/db/schema.ts b/fdm-core/src/db/schema.ts
index 43a700274..8a0f076b7 100644
--- a/fdm-core/src/db/schema.ts
+++ b/fdm-core/src/db/schema.ts
@@ -181,7 +181,7 @@ export const fertilizersCatalogue = fdmSchema.table(
{
p_id_catalogue: text().primaryKey(),
p_source: text().notNull(),
- p_name_nl: text(),
+ p_name_nl: text().notNull(),
p_name_en: text(),
p_description: text(),
p_dm: numericCasted(),
diff --git a/fdm-core/src/fertilizer.test.ts b/fdm-core/src/fertilizer.test.ts
index 51a383a12..0c451a859 100644
--- a/fdm-core/src/fertilizer.test.ts
+++ b/fdm-core/src/fertilizer.test.ts
@@ -24,15 +24,15 @@ import {
updateFertilizerApplication,
} from "./fertilizer"
import { addField } from "./field"
-import { createId } from "./id"
-import { disableFertilizerCatalogue, enableFertilizerCatalogue } from "./catalogues"
+import {
+ disableFertilizerCatalogue,
+ enableFertilizerCatalogue,
+} from "./catalogues"
describe("Fertilizer Data Model", () => {
let fdm: FdmServerType
- let p_id_catalogue: string
let principal_id: string
let b_id_farm: string
- let p_source: string
beforeEach(async () => {
const host = inject("host")
@@ -56,10 +56,7 @@ describe("Fertilizer Data Model", () => {
farmPostalCode,
)
- p_source = "custom"
- await enableFertilizerCatalogue(fdm, principal_id, b_id_farm, p_source)
-
- p_id_catalogue = createId()
+ await enableFertilizerCatalogue(fdm, principal_id, b_id_farm, b_id_farm)
})
afterAll(async () => {})
@@ -78,56 +75,59 @@ describe("Fertilizer Data Model", () => {
const p_name_nl = "Test Fertilizer"
const p_name_en = "Test Fertilizer (EN)"
const p_description = "This is a test fertilizer"
- await addFertilizerToCatalogue(fdm, {
- p_id_catalogue,
- p_source,
- p_name_nl,
- p_name_en,
- p_description,
- p_dm: 37,
- p_density: 20,
- p_om: 20,
- p_a: 30,
- p_hc: 40,
- p_eom: 50,
- p_eoc: 60,
- p_c_rt: 70,
- p_c_of: 80,
- p_c_if: 90,
- p_c_fr: 100,
- p_cn_of: 110,
- p_n_rt: 120,
- p_n_if: 130,
- p_n_of: 140,
- p_n_wc: 150,
- p_p_rt: 160,
- p_k_rt: 170,
- p_mg_rt: 180,
- p_ca_rt: 190,
- p_ne: 200,
- p_s_rt: 210,
- p_s_wc: 220,
- p_cu_rt: 230,
- p_zn_rt: 240,
- p_na_rt: 250,
- p_si_rt: 260,
- p_b_rt: 270,
- p_mn_rt: 280,
- p_ni_rt: 290,
- p_fe_rt: 300,
- p_mo_rt: 310,
- p_co_rt: 320,
- p_as_rt: 330,
- p_cd_rt: 340,
- pr_cr_rt: 350,
- p_cr_vi: 360,
- p_pb_rt: 370,
- p_hg_rt: 380,
- p_cl_rt: 390,
- p_type_manure: true,
- p_type_mineral: false,
- p_type_compost: false,
- })
+ const p_id_catalogue = await addFertilizerToCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm,
+ {
+ p_name_nl,
+ p_name_en,
+ p_description,
+ p_dm: 37,
+ p_density: 20,
+ p_om: 20,
+ p_a: 30,
+ p_hc: 40,
+ p_eom: 50,
+ p_eoc: 60,
+ p_c_rt: 70,
+ p_c_of: 80,
+ p_c_if: 90,
+ p_c_fr: 100,
+ p_cn_of: 110,
+ p_n_rt: 120,
+ p_n_if: 130,
+ p_n_of: 140,
+ p_n_wc: 150,
+ p_p_rt: 160,
+ p_k_rt: 170,
+ p_mg_rt: 180,
+ p_ca_rt: 190,
+ p_ne: 200,
+ p_s_rt: 210,
+ p_s_wc: 220,
+ p_cu_rt: 230,
+ p_zn_rt: 240,
+ p_na_rt: 250,
+ p_si_rt: 260,
+ p_b_rt: 270,
+ p_mn_rt: 280,
+ p_ni_rt: 290,
+ p_fe_rt: 300,
+ p_mo_rt: 310,
+ p_co_rt: 320,
+ p_as_rt: 330,
+ p_cd_rt: 340,
+ pr_cr_rt: 350,
+ p_cr_vi: 360,
+ p_pb_rt: 370,
+ p_hg_rt: 380,
+ p_cl_rt: 390,
+ p_type_manure: true,
+ p_type_mineral: false,
+ p_type_compost: false,
+ },
+ )
const fertilizers = await getFertilizersFromCatalogue(
fdm,
@@ -139,7 +139,7 @@ describe("Fertilizer Data Model", () => {
(f) => f.p_id_catalogue === p_id_catalogue,
)
expect(fertilizer).toBeDefined()
- expect(fertilizer?.p_source).toBe(p_source)
+ expect(fertilizer?.p_source).toBe(b_id_farm)
expect(fertilizer?.p_name_nl).toBe(p_name_nl)
expect(fertilizer?.p_name_en).toBe(p_name_en)
expect(fertilizer?.p_description).toBe(p_description)
@@ -150,56 +150,59 @@ describe("Fertilizer Data Model", () => {
const p_name_nl = "Test Fertilizer"
const p_name_en = "Test Fertilizer (EN)"
const p_description = "This is a test fertilizer"
- await addFertilizerToCatalogue(fdm, {
- p_id_catalogue,
- p_source,
- p_name_nl,
- p_name_en,
- p_description,
- p_dm: 37,
- p_density: 20,
- p_om: 20,
- p_a: 30,
- p_hc: 40,
- p_eom: 50,
- p_eoc: 60,
- p_c_rt: 70,
- p_c_of: 80,
- p_c_if: 90,
- p_c_fr: 100,
- p_cn_of: 110,
- p_n_rt: 120,
- p_n_if: 130,
- p_n_of: 140,
- p_n_wc: 150,
- p_p_rt: 160,
- p_k_rt: 170,
- p_mg_rt: 180,
- p_ca_rt: 190,
- p_ne: 200,
- p_s_rt: 210,
- p_s_wc: 220,
- p_cu_rt: 230,
- p_zn_rt: 240,
- p_na_rt: 250,
- p_si_rt: 260,
- p_b_rt: 270,
- p_mn_rt: 280,
- p_ni_rt: 290,
- p_fe_rt: 300,
- p_mo_rt: 310,
- p_co_rt: 320,
- p_as_rt: 330,
- p_cd_rt: 340,
- pr_cr_rt: 350,
- p_cr_vi: 360,
- p_pb_rt: 370,
- p_hg_rt: 380,
- p_cl_rt: 390,
- p_type_manure: true,
- p_type_mineral: false,
- p_type_compost: false,
- })
+ const p_id_catalogue = await addFertilizerToCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm,
+ {
+ p_name_nl,
+ p_name_en,
+ p_description,
+ p_dm: 37,
+ p_density: 20,
+ p_om: 20,
+ p_a: 30,
+ p_hc: 40,
+ p_eom: 50,
+ p_eoc: 60,
+ p_c_rt: 70,
+ p_c_of: 80,
+ p_c_if: 90,
+ p_c_fr: 100,
+ p_cn_of: 110,
+ p_n_rt: 120,
+ p_n_if: 130,
+ p_n_of: 140,
+ p_n_wc: 150,
+ p_p_rt: 160,
+ p_k_rt: 170,
+ p_mg_rt: 180,
+ p_ca_rt: 190,
+ p_ne: 200,
+ p_s_rt: 210,
+ p_s_wc: 220,
+ p_cu_rt: 230,
+ p_zn_rt: 240,
+ p_na_rt: 250,
+ p_si_rt: 260,
+ p_b_rt: 270,
+ p_mn_rt: 280,
+ p_ni_rt: 290,
+ p_fe_rt: 300,
+ p_mo_rt: 310,
+ p_co_rt: 320,
+ p_as_rt: 330,
+ p_cd_rt: 340,
+ pr_cr_rt: 350,
+ p_cr_vi: 360,
+ p_pb_rt: 370,
+ p_hg_rt: 380,
+ p_cl_rt: 390,
+ p_type_manure: true,
+ p_type_mineral: false,
+ p_type_compost: false,
+ },
+ )
const p_acquiring_amount = 1000
const p_acquiring_date = new Date()
@@ -222,56 +225,59 @@ describe("Fertilizer Data Model", () => {
const p_name_nl = "Test Fertilizer"
const p_name_en = "Test Fertilizer (EN)"
const p_description = "This is a test fertilizer"
- await addFertilizerToCatalogue(fdm, {
- p_id_catalogue,
- p_source,
- p_name_nl,
- p_name_en,
- p_description,
- p_dm: 37,
- p_density: 20,
- p_om: 20,
- p_a: 30,
- p_hc: 40,
- p_eom: 50,
- p_eoc: 60,
- p_c_rt: 70,
- p_c_of: 80,
- p_c_if: 90,
- p_c_fr: 100,
- p_cn_of: 110,
- p_n_rt: 120,
- p_n_if: 130,
- p_n_of: 140,
- p_n_wc: 150,
- p_p_rt: 160,
- p_k_rt: 170,
- p_mg_rt: 180,
- p_ca_rt: 190,
- p_ne: 200,
- p_s_rt: 210,
- p_s_wc: 220,
- p_cu_rt: 230,
- p_zn_rt: 240,
- p_na_rt: 250,
- p_si_rt: 260,
- p_b_rt: 270,
- p_mn_rt: 280,
- p_ni_rt: 290,
- p_fe_rt: 300,
- p_mo_rt: 310,
- p_co_rt: 320,
- p_as_rt: 330,
- p_cd_rt: 340,
- pr_cr_rt: 350,
- p_cr_vi: 360,
- p_pb_rt: 370,
- p_hg_rt: 380,
- p_cl_rt: 390,
- p_type_manure: true,
- p_type_mineral: false,
- p_type_compost: false,
- })
+ const p_id_catalogue = await addFertilizerToCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm,
+ {
+ p_name_nl,
+ p_name_en,
+ p_description,
+ p_dm: 37,
+ p_density: 20,
+ p_om: 20,
+ p_a: 30,
+ p_hc: 40,
+ p_eom: 50,
+ p_eoc: 60,
+ p_c_rt: 70,
+ p_c_of: 80,
+ p_c_if: 90,
+ p_c_fr: 100,
+ p_cn_of: 110,
+ p_n_rt: 120,
+ p_n_if: 130,
+ p_n_of: 140,
+ p_n_wc: 150,
+ p_p_rt: 160,
+ p_k_rt: 170,
+ p_mg_rt: 180,
+ p_ca_rt: 190,
+ p_ne: 200,
+ p_s_rt: 210,
+ p_s_wc: 220,
+ p_cu_rt: 230,
+ p_zn_rt: 240,
+ p_na_rt: 250,
+ p_si_rt: 260,
+ p_b_rt: 270,
+ p_mn_rt: 280,
+ p_ni_rt: 290,
+ p_fe_rt: 300,
+ p_mo_rt: 310,
+ p_co_rt: 320,
+ p_as_rt: 330,
+ p_cd_rt: 340,
+ pr_cr_rt: 350,
+ p_cr_vi: 360,
+ p_pb_rt: 370,
+ p_hg_rt: 380,
+ p_cl_rt: 390,
+ p_type_manure: true,
+ p_type_mineral: false,
+ p_type_compost: false,
+ },
+ )
const p_acquiring_amount = 1000
const p_acquiring_date = new Date()
@@ -307,56 +313,59 @@ describe("Fertilizer Data Model", () => {
const p_name_nl = "Test Fertilizer"
const p_name_en = "Test Fertilizer (EN)"
const p_description = "This is a test fertilizer"
- await addFertilizerToCatalogue(fdm, {
- p_id_catalogue,
- p_source,
- p_name_nl,
- p_name_en,
- p_description,
- p_dm: 37,
- p_density: 20,
- p_om: 20,
- p_a: 30,
- p_hc: 40,
- p_eom: 50,
- p_eoc: 60,
- p_c_rt: 70,
- p_c_of: 80,
- p_c_if: 90,
- p_c_fr: 100,
- p_cn_of: 110,
- p_n_rt: 120,
- p_n_if: 130,
- p_n_of: 140,
- p_n_wc: 150,
- p_p_rt: 160,
- p_k_rt: 170,
- p_mg_rt: 180,
- p_ca_rt: 190,
- p_ne: 200,
- p_s_rt: 210,
- p_s_wc: 220,
- p_cu_rt: 230,
- p_zn_rt: 240,
- p_na_rt: 250,
- p_si_rt: 260,
- p_b_rt: 270,
- p_mn_rt: 280,
- p_ni_rt: 290,
- p_fe_rt: 300,
- p_mo_rt: 310,
- p_co_rt: 320,
- p_as_rt: 330,
- p_cd_rt: 340,
- pr_cr_rt: 350,
- p_cr_vi: 360,
- p_pb_rt: 370,
- p_hg_rt: 380,
- p_cl_rt: 390,
- p_type_manure: true,
- p_type_mineral: false,
- p_type_compost: false,
- })
+ const p_id_catalogue = await addFertilizerToCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm,
+ {
+ p_name_nl,
+ p_name_en,
+ p_description,
+ p_dm: 37,
+ p_density: 20,
+ p_om: 20,
+ p_a: 30,
+ p_hc: 40,
+ p_eom: 50,
+ p_eoc: 60,
+ p_c_rt: 70,
+ p_c_of: 80,
+ p_c_if: 90,
+ p_c_fr: 100,
+ p_cn_of: 110,
+ p_n_rt: 120,
+ p_n_if: 130,
+ p_n_of: 140,
+ p_n_wc: 150,
+ p_p_rt: 160,
+ p_k_rt: 170,
+ p_mg_rt: 180,
+ p_ca_rt: 190,
+ p_ne: 200,
+ p_s_rt: 210,
+ p_s_wc: 220,
+ p_cu_rt: 230,
+ p_zn_rt: 240,
+ p_na_rt: 250,
+ p_si_rt: 260,
+ p_b_rt: 270,
+ p_mn_rt: 280,
+ p_ni_rt: 290,
+ p_fe_rt: 300,
+ p_mo_rt: 310,
+ p_co_rt: 320,
+ p_as_rt: 330,
+ p_cd_rt: 340,
+ pr_cr_rt: 350,
+ p_cr_vi: 360,
+ p_pb_rt: 370,
+ p_hg_rt: 380,
+ p_cl_rt: 390,
+ p_type_manure: true,
+ p_type_mineral: false,
+ p_type_compost: false,
+ },
+ )
const p_acquiring_amount = 1000
const p_acquiring_date = new Date()
@@ -385,7 +394,7 @@ describe("Fertilizer Data Model", () => {
fdm,
principal_id,
b_id_farm,
- p_source,
+ b_id_farm
)
const fertilizersWithNoCatalogue =
@@ -438,60 +447,62 @@ describe("Fertilizer Data Model", () => {
)
// Add fertilizer to catalogue
- p_id_catalogue = createId()
const p_name_nl = "Test Fertilizer"
const p_name_en = "Test Fertilizer (EN)"
const p_description = "This is a test fertilizer"
- await addFertilizerToCatalogue(fdm, {
- p_id_catalogue,
- p_source,
- p_name_nl,
- p_name_en,
- p_description,
- p_dm: 37,
- p_density: 20,
- p_om: 20,
- p_a: 30,
- p_hc: 40,
- p_eom: 50,
- p_eoc: 60,
- p_c_rt: 70,
- p_c_of: 80,
- p_c_if: 90,
- p_c_fr: 100,
- p_cn_of: 110,
- p_n_rt: 120,
- p_n_if: 130,
- p_n_of: 140,
- p_n_wc: 150,
- p_p_rt: 160,
- p_k_rt: 170,
- p_mg_rt: 180,
- p_ca_rt: 190,
- p_ne: 200,
- p_s_rt: 210,
- p_s_wc: 220,
- p_cu_rt: 230,
- p_zn_rt: 240,
- p_na_rt: 250,
- p_si_rt: 260,
- p_b_rt: 270,
- p_mn_rt: 280,
- p_ni_rt: 290,
- p_fe_rt: 300,
- p_mo_rt: 310,
- p_co_rt: 320,
- p_as_rt: 330,
- p_cd_rt: 340,
- pr_cr_rt: 350,
- p_cr_vi: 360,
- p_pb_rt: 370,
- p_hg_rt: 380,
- p_cl_rt: 390,
- p_type_manure: true,
- p_type_mineral: false,
- p_type_compost: false,
- })
+ const p_id_catalogue = await addFertilizerToCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm,
+ {
+ p_name_nl,
+ p_name_en,
+ p_description,
+ p_dm: 37,
+ p_density: 20,
+ p_om: 20,
+ p_a: 30,
+ p_hc: 40,
+ p_eom: 50,
+ p_eoc: 60,
+ p_c_rt: 70,
+ p_c_of: 80,
+ p_c_if: 90,
+ p_c_fr: 100,
+ p_cn_of: 110,
+ p_n_rt: 120,
+ p_n_if: 130,
+ p_n_of: 140,
+ p_n_wc: 150,
+ p_p_rt: 160,
+ p_k_rt: 170,
+ p_mg_rt: 180,
+ p_ca_rt: 190,
+ p_ne: 200,
+ p_s_rt: 210,
+ p_s_wc: 220,
+ p_cu_rt: 230,
+ p_zn_rt: 240,
+ p_na_rt: 250,
+ p_si_rt: 260,
+ p_b_rt: 270,
+ p_mn_rt: 280,
+ p_ni_rt: 290,
+ p_fe_rt: 300,
+ p_mo_rt: 310,
+ p_co_rt: 320,
+ p_as_rt: 330,
+ p_cd_rt: 340,
+ pr_cr_rt: 350,
+ p_cr_vi: 360,
+ p_pb_rt: 370,
+ p_hg_rt: 380,
+ p_cl_rt: 390,
+ p_type_manure: true,
+ p_type_mineral: false,
+ p_type_compost: false,
+ },
+ )
const p_acquiring_amount = 1000
const p_acquiring_date = new Date()
diff --git a/fdm-core/src/fertilizer.ts b/fdm-core/src/fertilizer.ts
index 259698197..a29e16feb 100644
--- a/fdm-core/src/fertilizer.ts
+++ b/fdm-core/src/fertilizer.ts
@@ -10,6 +10,7 @@ import type {
getFertilizerApplicationType,
getFertilizerType,
} from "./fertilizer.d"
+import { hashFertilizer } from "@svenvw/fdm-data"
/**
* Retrieves all fertilizers from the enabled catalogues for a farm.
@@ -72,9 +73,11 @@ export async function getFertilizersFromCatalogue(
}
/**
- * Adds a new fertilizer to the catalogue.
+ * Adds a new custom fertilizer to the catalogue of a farm.
*
* @param fdm The FDM instance providing the connection to the database. The instance can be created with {@link createFdmServer}.
+ * @param principal_id The ID of the principal making the request.
+ * @param b_id_farm The ID of the farm.
* @param properties The properties of the fertilizer to add.
* @returns A Promise that resolves when the fertilizer has been added.
* @throws If adding the fertilizer fails.
@@ -82,9 +85,9 @@ export async function getFertilizersFromCatalogue(
*/
export async function addFertilizerToCatalogue(
fdm: FdmType,
+ principal_id: PrincipalId,
+ b_id_farm: schema.farmsTypeInsert["b_id_farm"],
properties: {
- p_id_catalogue: schema.fertilizersCatalogueTypeInsert["p_id_catalogue"]
- p_source: schema.fertilizersCatalogueTypeInsert["p_source"]
p_name_nl: schema.fertilizersCatalogueTypeInsert["p_name_nl"]
p_name_en: schema.fertilizersCatalogueTypeInsert["p_name_en"]
p_description: schema.fertilizersCatalogueTypeInsert["p_description"]
@@ -132,10 +135,30 @@ export async function addFertilizerToCatalogue(
p_type_mineral: schema.fertilizersCatalogueTypeInsert["p_type_mineral"]
p_type_compost: schema.fertilizersCatalogueTypeInsert["p_type_compost"]
},
-): Promise {
+): Promise {
try {
+ await checkPermission(
+ fdm,
+ "farm",
+ "write",
+ b_id_farm,
+ principal_id,
+ "addFertilizerToCatalogue",
+ )
+
+ const p_id_catalogue = createId()
+ const input: schema.fertilizersCatalogueTypeInsert = {
+ ...properties,
+ p_id_catalogue: p_id_catalogue,
+ p_source: b_id_farm,
+ hash: null,
+ }
+ input.hash = hashFertilizer(input)
+
// Insert the farm in the db
- await fdm.insert(schema.fertilizersCatalogue).values(properties)
+ await fdm.insert(schema.fertilizersCatalogue).values(input)
+
+ return p_id_catalogue
} catch (err) {
throw handleError(err, "Exception for addFertilizerToCatalogue", {
properties,
From a259ff6e5c61c5e29cfcdace19f061625be876f8 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Thu, 27 Mar 2025 12:03:33 +0100
Subject: [PATCH 09/55] Add to the output of `getFertilizer` the values for
`p_type_*`
---
.changeset/red-oranges-drop.md | 5 +++++
fdm-core/src/fertilizer.ts | 3 +++
2 files changed, 8 insertions(+)
create mode 100644 .changeset/red-oranges-drop.md
diff --git a/.changeset/red-oranges-drop.md b/.changeset/red-oranges-drop.md
new file mode 100644
index 000000000..bda6e7e72
--- /dev/null
+++ b/.changeset/red-oranges-drop.md
@@ -0,0 +1,5 @@
+---
+"@svenvw/fdm-core": minor
+---
+
+Add to the output of `getFertilizer` the values for `p_type_*`
diff --git a/fdm-core/src/fertilizer.ts b/fdm-core/src/fertilizer.ts
index a29e16feb..74491a31d 100644
--- a/fdm-core/src/fertilizer.ts
+++ b/fdm-core/src/fertilizer.ts
@@ -296,6 +296,9 @@ export async function getFertilizer(
p_pb_rt: schema.fertilizersCatalogue.p_pb_rt,
p_hg_rt: schema.fertilizersCatalogue.p_hg_rt,
p_cl_cr: schema.fertilizersCatalogue.p_cl_cr,
+ p_type_manure: schema.fertilizersCatalogue.p_type_manure,
+ p_type_mineral: schema.fertilizersCatalogue.p_type_mineral,
+ p_type_compost: schema.fertilizersCatalogue.p_type_compost,
})
.from(schema.fertilizers)
.leftJoin(
From a52796a5121429dc6c41de2a4f2518fa9c1a9e30 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Thu, 27 Mar 2025 12:28:45 +0100
Subject: [PATCH 10/55] Add function `updateFertilizerFromCatalogue` to alter
properties of custom fertilizer
---
.changeset/funny-dancers-rush.md | 5 +
fdm-core/src/fertilizer.test.ts | 291 ++++++++++++++++++++++++++++++-
fdm-core/src/fertilizer.ts | 114 +++++++++++-
3 files changed, 408 insertions(+), 2 deletions(-)
create mode 100644 .changeset/funny-dancers-rush.md
diff --git a/.changeset/funny-dancers-rush.md b/.changeset/funny-dancers-rush.md
new file mode 100644
index 000000000..726342b7e
--- /dev/null
+++ b/.changeset/funny-dancers-rush.md
@@ -0,0 +1,5 @@
+---
+"@svenvw/fdm-core": minor
+---
+
+Add function `updateFertilizerFromCatalogue` to alter properties of custom fertilizer
diff --git a/fdm-core/src/fertilizer.test.ts b/fdm-core/src/fertilizer.test.ts
index 0c451a859..2f050bdbb 100644
--- a/fdm-core/src/fertilizer.test.ts
+++ b/fdm-core/src/fertilizer.test.ts
@@ -22,12 +22,14 @@ import {
removeFertilizer,
removeFertilizerApplication,
updateFertilizerApplication,
+ updateFertilizerFromCatalogue,
} from "./fertilizer"
import { addField } from "./field"
import {
disableFertilizerCatalogue,
enableFertilizerCatalogue,
} from "./catalogues"
+import { createId } from "./id"
describe("Fertilizer Data Model", () => {
let fdm: FdmServerType
@@ -394,7 +396,7 @@ describe("Fertilizer Data Model", () => {
fdm,
principal_id,
b_id_farm,
- b_id_farm
+ b_id_farm,
)
const fertilizersWithNoCatalogue =
@@ -404,6 +406,293 @@ describe("Fertilizer Data Model", () => {
})
})
+ describe("updateFertilizerFromCatalogue", () => {
+ let p_id_catalogue: string
+
+ beforeEach(async () => {
+ // Add a fertilizer to the catalogue
+ p_id_catalogue = await addFertilizerToCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm,
+ {
+ p_name_nl: "Test Fertilizer",
+ p_name_en: "Test Fertilizer (EN)",
+ p_description: "This is a test fertilizer",
+ p_dm: 37,
+ p_density: 20,
+ p_om: 20,
+ p_a: 30,
+ p_hc: 40,
+ p_eom: 50,
+ p_eoc: 60,
+ p_c_rt: 70,
+ p_c_of: 80,
+ p_c_if: 90,
+ p_c_fr: 100,
+ p_cn_of: 110,
+ p_n_rt: 120,
+ p_n_if: 130,
+ p_n_of: 140,
+ p_n_wc: 150,
+ p_p_rt: 160,
+ p_k_rt: 170,
+ p_mg_rt: 180,
+ p_ca_rt: 190,
+ p_ne: 200,
+ p_s_rt: 210,
+ p_s_wc: 220,
+ p_cu_rt: 230,
+ p_zn_rt: 240,
+ p_na_rt: 250,
+ p_si_rt: 260,
+ p_b_rt: 270,
+ p_mn_rt: 280,
+ p_ni_rt: 290,
+ p_fe_rt: 300,
+ p_mo_rt: 310,
+ p_co_rt: 320,
+ p_as_rt: 330,
+ p_cd_rt: 340,
+ pr_cr_rt: 350,
+ p_cr_vi: 360,
+ p_pb_rt: 370,
+ p_hg_rt: 380,
+ p_cl_rt: 390,
+ p_type_manure: true,
+ p_type_mineral: false,
+ p_type_compost: false,
+ },
+ )
+ })
+
+ it("should update an existing fertilizer in the catalogue", async () => {
+ const updatedProperties = {
+ p_name_nl: "Updated Test Fertilizer",
+ p_description: "This is an updated test fertilizer",
+ p_dm: 50,
+ }
+
+ await updateFertilizerFromCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm,
+ p_id_catalogue,
+ updatedProperties,
+ )
+
+ const fertilizers = await getFertilizersFromCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm,
+ )
+ const updatedFertilizer = fertilizers.find(
+ (f) => f.p_id_catalogue === p_id_catalogue,
+ )
+ expect(updatedFertilizer).toBeDefined()
+ expect(updatedFertilizer?.p_name_nl).toBe(
+ updatedProperties.p_name_nl,
+ )
+ expect(updatedFertilizer?.p_description).toBe(
+ updatedProperties.p_description,
+ )
+ expect(updatedFertilizer?.p_dm).toBe(updatedProperties.p_dm)
+ })
+
+ it("should throw an error if fertilizer does not exist in catalogue", async () => {
+ const nonExistingCatalogueId = createId()
+ const updatedProperties = {
+ p_name_nl: "Updated Test Fertilizer",
+ }
+
+ await expect(
+ updateFertilizerFromCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm,
+ nonExistingCatalogueId,
+ updatedProperties,
+ ),
+ ).rejects.toThrow("Exception for updateFertilizerFromCatalogue")
+ })
+
+ it("should update a fertilizer with a subset of properties", async () => {
+ const updatedProperties = {
+ p_name_nl: "Updated Name Only",
+ }
+
+ await updateFertilizerFromCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm,
+ p_id_catalogue,
+ updatedProperties,
+ )
+
+ const fertilizers = await getFertilizersFromCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm,
+ )
+ const updatedFertilizer = fertilizers.find(
+ (f) => f.p_id_catalogue === p_id_catalogue,
+ )
+ expect(updatedFertilizer).toBeDefined()
+ expect(updatedFertilizer?.p_name_nl).toBe(
+ updatedProperties.p_name_nl,
+ )
+ // Check that other properties remain unchanged
+ expect(updatedFertilizer?.p_description).toBe(
+ "This is a test fertilizer",
+ )
+ expect(updatedFertilizer?.p_dm).toBe(37)
+ })
+
+ it("should throw an error when updating with invalid principal ID", async () => {
+ const updatedProperties = {
+ p_name_nl: "Updated Test Fertilizer",
+ }
+ const invalidPrincipalId = "invalid-principal-id"
+
+ await expect(
+ updateFertilizerFromCatalogue(
+ fdm,
+ invalidPrincipalId,
+ b_id_farm,
+ p_id_catalogue,
+ updatedProperties,
+ ),
+ ).rejects.toThrow(
+ "Principal does not have permission to perform this action",
+ )
+ })
+ it("should update hash after updating a fertilizer", async () => {
+ const updatedProperties = {
+ p_name_nl: "Updated Test Fertilizer",
+ p_description: "This is an updated test fertilizer",
+ p_dm: 50,
+ }
+ const fertilizersBefore = await getFertilizersFromCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm,
+ )
+ const fertilizerBefore = fertilizersBefore.find(
+ (f) => f.p_id_catalogue === p_id_catalogue,
+ )
+ expect(fertilizerBefore).toBeDefined()
+ const hashBefore = fertilizerBefore?.hash
+ expect(hashBefore).toBeDefined()
+ await updateFertilizerFromCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm,
+ p_id_catalogue,
+ updatedProperties,
+ )
+ const fertilizersAfter = await getFertilizersFromCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm,
+ )
+ const fertilizerAfter = fertilizersAfter.find(
+ (f) => f.p_id_catalogue === p_id_catalogue,
+ )
+ expect(fertilizerAfter).toBeDefined()
+ const hashAfter = fertilizerAfter?.hash
+ expect(hashAfter).toBeDefined()
+
+ expect(hashBefore).not.toBe(hashAfter)
+ })
+ it("should throw an error if updating a fertilizer of another farm", async () => {
+ const farmName = "Test Farm 2"
+ const farmBusinessId = "98765"
+ const farmAddress = "456 Farm Lane"
+ const farmPostalCode = "54321"
+ const b_id_farm2 = await addFarm(
+ fdm,
+ principal_id,
+ farmName,
+ farmBusinessId,
+ farmAddress,
+ farmPostalCode,
+ )
+ await enableFertilizerCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm2,
+ b_id_farm2,
+ )
+
+ // Add a fertilizer to the catalogue
+ const p_id_catalogue2 = await addFertilizerToCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm2,
+ {
+ p_name_nl: "Test Fertilizer 2",
+ p_name_en: "Test Fertilizer (EN) 2",
+ p_description: "This is a test fertilizer 2",
+ p_dm: 37,
+ p_density: 20,
+ p_om: 20,
+ p_a: 30,
+ p_hc: 40,
+ p_eom: 50,
+ p_eoc: 60,
+ p_c_rt: 70,
+ p_c_of: 80,
+ p_c_if: 90,
+ p_c_fr: 100,
+ p_cn_of: 110,
+ p_n_rt: 120,
+ p_n_if: 130,
+ p_n_of: 140,
+ p_n_wc: 150,
+ p_p_rt: 160,
+ p_k_rt: 170,
+ p_mg_rt: 180,
+ p_ca_rt: 190,
+ p_ne: 200,
+ p_s_rt: 210,
+ p_s_wc: 220,
+ p_cu_rt: 230,
+ p_zn_rt: 240,
+ p_na_rt: 250,
+ p_si_rt: 260,
+ p_b_rt: 270,
+ p_mn_rt: 280,
+ p_ni_rt: 290,
+ p_fe_rt: 300,
+ p_mo_rt: 310,
+ p_co_rt: 320,
+ p_as_rt: 330,
+ p_cd_rt: 340,
+ pr_cr_rt: 350,
+ p_cr_vi: 360,
+ p_pb_rt: 370,
+ p_hg_rt: 380,
+ p_cl_rt: 390,
+ p_type_manure: true,
+ p_type_mineral: false,
+ p_type_compost: false,
+ },
+ )
+ const updatedProperties = {
+ p_name_nl: "Updated Test Fertilizer",
+ }
+ await expect(
+ updateFertilizerFromCatalogue(
+ fdm,
+ principal_id,
+ b_id_farm,
+ p_id_catalogue2,
+ updatedProperties,
+ ),
+ ).rejects.toThrow("Exception for updateFertilizerFromCatalogue")
+ })
+ })
+
describe("Fertilizer Application", () => {
let b_id: string
let p_id: string
diff --git a/fdm-core/src/fertilizer.ts b/fdm-core/src/fertilizer.ts
index 74491a31d..745e4ef91 100644
--- a/fdm-core/src/fertilizer.ts
+++ b/fdm-core/src/fertilizer.ts
@@ -1,4 +1,4 @@
-import { asc, desc, eq, inArray } from "drizzle-orm"
+import { and, asc, desc, eq, inArray } from "drizzle-orm"
import { createId } from "./id"
import { checkPermission } from "./authorization"
@@ -327,6 +327,118 @@ export async function getFertilizer(
}
}
+/**
+ * Updates an existing fertilizer in the catalogue of a farm.
+ *
+ * @param fdm The FDM instance providing the connection to the database. The instance can be created with {@link createFdmServer}.
+ * @param principal_id The ID of the principal making the request.
+ * @param b_id_farm The ID of the farm.
+ * @param p_id_catalogue The ID of the fertilizer in the catalogue to update
+ * @param properties The properties of the fertilizer to update.
+ * @returns A Promise that resolves when the fertilizer has been updated.
+ * @throws If updating the fertilizer fails.
+ * @alpha
+ */
+export async function updateFertilizerFromCatalogue(
+ fdm: FdmType,
+ principal_id: PrincipalId,
+ b_id_farm: schema.farmsTypeInsert["b_id_farm"],
+ p_id_catalogue: schema.fertilizersCatalogueTypeInsert["p_id_catalogue"],
+ properties: Partial<{
+ p_name_nl: schema.fertilizersCatalogueTypeInsert["p_name_nl"]
+ p_name_en: schema.fertilizersCatalogueTypeInsert["p_name_en"]
+ p_description: schema.fertilizersCatalogueTypeInsert["p_description"]
+ p_dm: schema.fertilizersCatalogueTypeInsert["p_dm"]
+ p_density: schema.fertilizersCatalogueTypeInsert["p_density"]
+ p_om: schema.fertilizersCatalogueTypeInsert["p_om"]
+ p_a: schema.fertilizersCatalogueTypeInsert["p_a"]
+ p_hc: schema.fertilizersCatalogueTypeInsert["p_hc"]
+ p_eom: schema.fertilizersCatalogueTypeInsert["p_eom"]
+ p_eoc: schema.fertilizersCatalogueTypeInsert["p_eoc"]
+ p_c_rt: schema.fertilizersCatalogueTypeInsert["p_c_rt"]
+ p_c_of: schema.fertilizersCatalogueTypeInsert["p_c_of"]
+ p_c_if: schema.fertilizersCatalogueTypeInsert["p_c_if"]
+ p_c_fr: schema.fertilizersCatalogueTypeInsert["p_c_fr"]
+ p_cn_of: schema.fertilizersCatalogueTypeInsert["p_cn_of"]
+ p_n_rt: schema.fertilizersCatalogueTypeInsert["p_n_rt"]
+ p_n_if: schema.fertilizersCatalogueTypeInsert["p_n_if"]
+ p_n_of: schema.fertilizersCatalogueTypeInsert["p_n_of"]
+ p_n_wc: schema.fertilizersCatalogueTypeInsert["p_n_wc"]
+ p_p_rt: schema.fertilizersCatalogueTypeInsert["p_p_rt"]
+ p_k_rt: schema.fertilizersCatalogueTypeInsert["p_k_rt"]
+ p_mg_rt: schema.fertilizersCatalogueTypeInsert["p_mg_rt"]
+ p_ca_rt: schema.fertilizersCatalogueTypeInsert["p_ca_rt"]
+ p_ne: schema.fertilizersCatalogueTypeInsert["p_ne"]
+ p_s_rt: schema.fertilizersCatalogueTypeInsert["p_s_rt"]
+ p_s_wc: schema.fertilizersCatalogueTypeInsert["p_s_wc"]
+ p_cu_rt: schema.fertilizersCatalogueTypeInsert["p_cu_rt"]
+ p_zn_rt: schema.fertilizersCatalogueTypeInsert["p_zn_rt"]
+ p_na_rt: schema.fertilizersCatalogueTypeInsert["p_na_rt"]
+ p_si_rt: schema.fertilizersCatalogueTypeInsert["p_si_rt"]
+ p_b_rt: schema.fertilizersCatalogueTypeInsert["p_b_rt"]
+ p_mn_rt: schema.fertilizersCatalogueTypeInsert["p_mn_rt"]
+ p_ni_rt: schema.fertilizersCatalogueTypeInsert["p_ni_rt"]
+ p_fe_rt: schema.fertilizersCatalogueTypeInsert["p_fe_rt"]
+ p_mo_rt: schema.fertilizersCatalogueTypeInsert["p_mo_rt"]
+ p_co_rt: schema.fertilizersCatalogueTypeInsert["p_co_rt"]
+ p_as_rt: schema.fertilizersCatalogueTypeInsert["p_as_rt"]
+ p_cd_rt: schema.fertilizersCatalogueTypeInsert["p_cd_rt"]
+ pr_cr_rt: schema.fertilizersCatalogueTypeInsert["p_cr_rt"]
+ p_cr_vi: schema.fertilizersCatalogueTypeInsert["p_cr_vi"]
+ p_pb_rt: schema.fertilizersCatalogueTypeInsert["p_pb_rt"]
+ p_hg_rt: schema.fertilizersCatalogueTypeInsert["p_hg_rt"]
+ p_cl_rt: schema.fertilizersCatalogueTypeInsert["p_cl_cr"]
+ p_type_manure: schema.fertilizersCatalogueTypeInsert["p_type_manure"]
+ p_type_mineral: schema.fertilizersCatalogueTypeInsert["p_type_mineral"]
+ p_type_compost: schema.fertilizersCatalogueTypeInsert["p_type_compost"]
+ }>,
+): Promise {
+ try {
+ await checkPermission(
+ fdm,
+ "farm",
+ "write",
+ b_id_farm,
+ principal_id,
+ "updateFertilizerFromCatalogue",
+ )
+
+ const existingFertilizer = await fdm
+ .select()
+ .from(schema.fertilizersCatalogue)
+ .where(
+ and(
+ eq(
+ schema.fertilizersCatalogue.p_id_catalogue,
+ p_id_catalogue,
+ ),
+ eq(schema.fertilizersCatalogue.p_source, b_id_farm),
+ ),
+ )
+ if (existingFertilizer.length === 0) {
+ throw new Error("Fertilizer does not exist in catalogue")
+ }
+ const updatedProperties = {
+ ...existingFertilizer[0],
+ ...properties,
+ hash: null,
+ }
+ updatedProperties.hash = hashFertilizer(updatedProperties)
+
+ await fdm
+ .update(schema.fertilizersCatalogue)
+ .set(updatedProperties)
+ .where(
+ eq(schema.fertilizersCatalogue.p_id_catalogue, p_id_catalogue),
+ )
+ } catch (err) {
+ throw handleError(err, "Exception for updateFertilizerFromCatalogue", {
+ p_id_catalogue,
+ properties,
+ })
+ }
+}
+
/**
* Retrieves fertilizer details for a specified farm.
*
From d8ae3d0487cacc77aed9b43939e3baa081aece83 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Thu, 27 Mar 2025 13:16:01 +0100
Subject: [PATCH 11/55] Fix
---
fdm-calculator/src/doses/get-dose-field.test.ts | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/fdm-calculator/src/doses/get-dose-field.test.ts b/fdm-calculator/src/doses/get-dose-field.test.ts
index 66ebae170..edd976190 100644
--- a/fdm-calculator/src/doses/get-dose-field.test.ts
+++ b/fdm-calculator/src/doses/get-dose-field.test.ts
@@ -57,10 +57,7 @@ describe("getDoseForField", () => {
new Date(),
"lease",
)
- p_id_catalogue = `p_test_fertilizer_${Math.round(Math.random() * 1000)}`
- await addFertilizerToCatalogue(fdm, {
- p_id_catalogue: p_id_catalogue,
- p_source: "",
+ p_id_catalogue = await addFertilizerToCatalogue(fdm, principal_id, b_id_farm, {
p_name_nl: "",
p_name_en: "",
p_description: "",
From 1218ab79ed9b85cecb6ef2022feff692d9a48532 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Thu, 27 Mar 2025 13:27:45 +0100
Subject: [PATCH 12/55] Add `hashCultivation` to get the hash of a cultivation
item
---
.changeset/eleven-dancers-brush.md | 5 +++++
fdm-data/src/cultivations/catalogues/brp.ts | 3 ++-
fdm-data/src/cultivations/hash.ts | 9 +++++++++
fdm-data/src/index.ts | 5 +++--
4 files changed, 19 insertions(+), 3 deletions(-)
create mode 100644 .changeset/eleven-dancers-brush.md
create mode 100644 fdm-data/src/cultivations/hash.ts
diff --git a/.changeset/eleven-dancers-brush.md b/.changeset/eleven-dancers-brush.md
new file mode 100644
index 000000000..227dbafe9
--- /dev/null
+++ b/.changeset/eleven-dancers-brush.md
@@ -0,0 +1,5 @@
+---
+"@svenvw/fdm-data": minor
+---
+
+Add `hashCultivation` to get the hash of a cultivation item
diff --git a/fdm-data/src/cultivations/catalogues/brp.ts b/fdm-data/src/cultivations/catalogues/brp.ts
index 0de3d2c36..617fc8eaa 100644
--- a/fdm-data/src/cultivations/catalogues/brp.ts
+++ b/fdm-data/src/cultivations/catalogues/brp.ts
@@ -1,4 +1,5 @@
import type { CatalogueCultivation, CatalogueCultivationItem } from "../d"
+import { hashCultivation } from "../hash"
import brp from "./brp.json"
import xxhash from "xxhash-wasm"
@@ -40,7 +41,7 @@ export function getCatalogueBrp(): CatalogueCultivation {
}
// Hash the item
- item.hash = h32ToString(JSON.stringify(item))
+ item.hash = hashCultivation(item)
return item
})
diff --git a/fdm-data/src/cultivations/hash.ts b/fdm-data/src/cultivations/hash.ts
new file mode 100644
index 000000000..072864fd5
--- /dev/null
+++ b/fdm-data/src/cultivations/hash.ts
@@ -0,0 +1,9 @@
+import type { CatalogueCultivationItem } from "./d"
+import xxhash from "xxhash-wasm"
+
+const { h32ToString } = await xxhash()
+
+export function hashCultivation(cultivation: CatalogueCultivationItem) {
+ const hash = h32ToString(JSON.stringify(cultivation))
+ return hash
+}
diff --git a/fdm-data/src/index.ts b/fdm-data/src/index.ts
index ccc27fa66..3addf3e03 100644
--- a/fdm-data/src/index.ts
+++ b/fdm-data/src/index.ts
@@ -11,6 +11,7 @@
* @packageDocumentation
*/
-export { getFertilizersCatalogue} from "./fertilizers"
+export { getFertilizersCatalogue } from "./fertilizers"
export { getCultivationCatalogue } from "./cultivations"
-export { hashFertilizer} from "./fertilizers/hash"
+export { hashFertilizer } from "./fertilizers/hash"
+export { hashCultivation } from "./cultivations/hash"
From 2ef3870361f1b6d3bb34e260c500cf299acc0288 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Thu, 27 Mar 2025 13:33:28 +0100
Subject: [PATCH 13/55] Improve syncing
---
fdm-core/src/catalogues.test.ts | 1 -
fdm-core/src/catalogues.ts | 100 ++++++++++++++++++--------------
2 files changed, 56 insertions(+), 45 deletions(-)
diff --git a/fdm-core/src/catalogues.test.ts b/fdm-core/src/catalogues.test.ts
index a65e89365..673ca896c 100644
--- a/fdm-core/src/catalogues.test.ts
+++ b/fdm-core/src/catalogues.test.ts
@@ -658,7 +658,6 @@ describe("Catalogues syncing", () => {
)
expect(itemSynced[0].p_id_catalogue).toBeDefined()
- expect(itemSynced[0].hash).toBe(item[0].hash)
})
it("should update cultivation catalogue", async () => {
diff --git a/fdm-core/src/catalogues.ts b/fdm-core/src/catalogues.ts
index eeb99e322..a31c7354c 100644
--- a/fdm-core/src/catalogues.ts
+++ b/fdm-core/src/catalogues.ts
@@ -7,6 +7,8 @@ import { checkPermission } from "./authorization"
import {
getCultivationCatalogue,
getFertilizersCatalogue,
+ hashCultivation,
+ hashFertilizer,
} from "@svenvw/fdm-data"
/**
@@ -368,83 +370,93 @@ export async function isCultivationCatalogueEnabled(
* @returns A promise that resolves when the synchronization is complete.
*/
export async function syncCatalogues(fdm: FdmType): Promise {
- try {
- // Sync fertilizers catalogue (SRM)
- const srmCatalogue = getFertilizersCatalogue("srm")
- for (const srmItem of srmCatalogue) {
- const existingItem = await fdm
- .select()
+ await syncFertilizerCatalogue(fdm)
+ await syncCultivationCatalogue(fdm)
+}
+
+async function syncFertilizerCatalogue(fdm: FdmType) {
+ const srmCatalogue = getFertilizersCatalogue("srm")
+ await fdm.transaction(async (tx) => {
+ for (const item of srmCatalogue) {
+ const hash = hashFertilizer(item)
+ const existing = await tx
+ .select({ hash: schema.fertilizersCatalogue.hash })
.from(schema.fertilizersCatalogue)
.where(
eq(
schema.fertilizersCatalogue.p_id_catalogue,
- srmItem.p_id_catalogue,
+ item.p_id_catalogue,
),
)
.limit(1)
-
- if (existingItem.length === 0) {
- await fdm.insert(schema.fertilizersCatalogue).values(srmItem)
- console.log(
- `Inserted fertilizer catalogue item: ${srmItem.p_id_catalogue}`,
- )
+ if (existing.length === 0) {
+ //add the item if does not exist
+ await tx.insert(schema.fertilizersCatalogue).values({
+ ...item,
+ hash: hash,
+ })
} else {
- // Update item if different
- if (srmItem.hash && srmItem.hash !== existingItem[0].hash) {
- await fdm
+ // update the hash if it is undefined, null or different
+ if (
+ existing[0].hash === null ||
+ existing[0].hash === undefined ||
+ existing[0].hash !== hash
+ ) {
+ await tx
.update(schema.fertilizersCatalogue)
- .set(srmItem)
+ .set({ hash: hash })
.where(
eq(
schema.fertilizersCatalogue.p_id_catalogue,
- srmItem.p_id_catalogue,
+ item.p_id_catalogue,
),
)
- console.log(
- `Updated fertilizer catalogue item: ${srmItem.p_id_catalogue}`,
- )
}
}
}
+ })
+}
- // Sync cultivation catalogue (BRP)
- const brpCatalogue = getCultivationCatalogue("brp")
- for (const brpItem of brpCatalogue) {
- const existingItem = await fdm
- .select()
+async function syncCultivationCatalogue(fdm: FdmType) {
+ const brpCatalogue = getCultivationCatalogue("brp")
+
+ await fdm.transaction(async (tx) => {
+ for (const item of brpCatalogue) {
+ const hash = hashCultivation(item)
+ const existing = await tx
+ .select({ hash: schema.cultivationsCatalogue.hash })
.from(schema.cultivationsCatalogue)
.where(
eq(
schema.cultivationsCatalogue.b_lu_catalogue,
- brpItem.b_lu_catalogue,
+ item.b_lu_catalogue,
),
)
.limit(1)
-
- if (existingItem.length === 0) {
- await fdm.insert(schema.cultivationsCatalogue).values(brpItem)
- console.log(
- `Inserted cultivation catalogue item: ${brpItem.b_lu_catalogue}`,
- )
+ if (existing.length === 0) {
+ //add the item if does not exist
+ await tx.insert(schema.cultivationsCatalogue).values({
+ ...item,
+ hash: hash,
+ })
} else {
- // Update item if different
- if (brpItem.hash && brpItem.hash !== existingItem[0].hash) {
- await fdm
+ // update the hash if it is undefined, null or different
+ if (
+ existing[0].hash === null ||
+ existing[0].hash === undefined ||
+ existing[0].hash !== hash
+ ) {
+ await tx
.update(schema.cultivationsCatalogue)
- .set(brpItem)
+ .set({ hash: hash })
.where(
eq(
schema.cultivationsCatalogue.b_lu_catalogue,
- brpItem.b_lu_catalogue,
+ item.b_lu_catalogue,
),
)
- console.log(
- `Updated cultivation catalogue item: ${brpItem.b_lu_catalogue}`,
- )
}
}
}
- } catch (err) {
- throw handleError(err, "Exception for syncCatalogues")
- }
+ })
}
From 226a3cc2145e89f4487f376c7cf6586a590371f3 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Fri, 28 Mar 2025 09:40:36 +0100
Subject: [PATCH 14/55] Extend the output
---
.changeset/red-oranges-drop.md | 2 +-
fdm-core/src/fertilizer.ts | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/.changeset/red-oranges-drop.md b/.changeset/red-oranges-drop.md
index bda6e7e72..6489b1202 100644
--- a/.changeset/red-oranges-drop.md
+++ b/.changeset/red-oranges-drop.md
@@ -2,4 +2,4 @@
"@svenvw/fdm-core": minor
---
-Add to the output of `getFertilizer` the values for `p_type_*`
+Add to the output of `getFertilizer` and `getFertilizers` the values for `p_type_*` and `p_source`
diff --git a/fdm-core/src/fertilizer.ts b/fdm-core/src/fertilizer.ts
index 745e4ef91..9cbf3fb9a 100644
--- a/fdm-core/src/fertilizer.ts
+++ b/fdm-core/src/fertilizer.ts
@@ -261,6 +261,7 @@ export async function getFertilizer(
const fertilizer = await fdm
.select({
p_id: schema.fertilizers.p_id,
+ p_source: schema.fertilizersCatalogue.p_source,
p_name_nl: schema.fertilizersCatalogue.p_name_nl,
p_name_en: schema.fertilizersCatalogue.p_name_en,
p_description: schema.fertilizersCatalogue.p_description,
@@ -471,6 +472,7 @@ export async function getFertilizers(
const fertilizers = await fdm
.select({
p_id: schema.fertilizers.p_id,
+ p_source: schema.fertilizersCatalogue.p_source,
p_name_nl: schema.fertilizersCatalogue.p_name_nl,
p_name_en: schema.fertilizersCatalogue.p_name_en,
p_description: schema.fertilizersCatalogue.p_description,
@@ -506,6 +508,9 @@ export async function getFertilizers(
p_pb_rt: schema.fertilizersCatalogue.p_pb_rt,
p_hg_rt: schema.fertilizersCatalogue.p_hg_rt,
p_cl_cr: schema.fertilizersCatalogue.p_cl_cr,
+ p_type_manure: schema.fertilizersCatalogue.p_type_manure,
+ p_type_mineral: schema.fertilizersCatalogue.p_type_mineral,
+ p_type_compost: schema.fertilizersCatalogue.p_type_compost,
})
.from(schema.fertilizers)
.leftJoin(
From 17acee31e3f9e1acb9296079b71b31ef6d97fc1c Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Fri, 28 Mar 2025 10:32:11 +0100
Subject: [PATCH 15/55] Improve layout of cards
---
.../custom/fertilizer/formschema.tsx | 8 +
.../farm.$b_id_farm.fertilizers.$p_id.tsx | 821 ++++++++++--------
2 files changed, 466 insertions(+), 363 deletions(-)
diff --git a/fdm-app/app/components/custom/fertilizer/formschema.tsx b/fdm-app/app/components/custom/fertilizer/formschema.tsx
index bd0d56f6f..c080c724b 100644
--- a/fdm-app/app/components/custom/fertilizer/formschema.tsx
+++ b/fdm-app/app/components/custom/fertilizer/formschema.tsx
@@ -1,6 +1,14 @@
import { z } from "zod"
export const FormSchema = z.object({
+ p_name_nl: z.string({
+ required_error: "Naam is verplicht",
+ invalid_type_error: "Ongeldige waarde",
+ }),
+ p_type: z.string({
+ required_error: "Type is verplicht",
+ invalid_type_error: "Ongeldige waarde",
+ }),
p_n_rt: z.coerce.number({
invalid_type_error: "Ongeldige waarde",
}),
diff --git a/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx b/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
index 614aeebdb..531187230 100644
--- a/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
+++ b/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
@@ -18,6 +18,13 @@ import {
FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select"
import { SidebarInset } from "@/components/ui/sidebar"
import { getSession } from "@/lib/auth.server"
import { handleLoaderError } from "@/lib/error"
@@ -85,13 +92,20 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
// Get the available fertilizers
const fertilizer = await getFertilizer(fdm, p_id)
+ // Set editable status
+ let editable = true
+ console.log(fertilizer.p_source)
+ if (fertilizer.p_source === b_id_farm) {
+ editable = true
+ }
+
// Return user information from loader
return {
farm: farm,
b_id_farm: b_id_farm,
farmOptions: farmOptions,
fertilizer: fertilizer,
- editable: true,
+ editable: editable,
}
} catch (error) {
throw handleLoaderError(error)
@@ -108,15 +122,27 @@ export default function FarmFertilizerBlock() {
const loaderData = useLoaderData()
const fertilizer = loaderData.fertilizer
+ fertilizer.p_type = ""
+ if (fertilizer.p_type_manure) {
+ fertilizer.p_type = "manure"
+ } else if (fertilizer.p_type_compost) {
+ fertilizer.p_type = "compost"
+ } else if (fertilizer.p_type_mineral) {
+ fertilizer.p_type = "mineral"
+ }
+
const form = useRemixForm>({
mode: "onTouched",
resolver: zodResolver(FormSchema),
defaultValues: {
+ p_name_nl: fertilizer.p_name_nl,
+ p_type: fertilizer.p_type,
p_n_rt: fertilizer.p_n_rt,
+ p_n_wc: fertilizer.p_n_wc,
p_p_rt: fertilizer.p_p_rt,
p_k_rt: fertilizer.p_k_rt,
p_om: fertilizer.p_om,
- p_c_rt: fertilizer.p_c_rt,
+ p_eoc: fertilizer.p_eoc,
p_s_rt: fertilizer.p_s_rt,
p_ca_rt: fertilizer.p_ca_rt,
p_mg_rt: fertilizer.p_mg_rt,
@@ -125,11 +151,14 @@ export default function FarmFertilizerBlock() {
useEffect(() => {
form.reset({
+ p_name_nl: fertilizer.p_name_nl,
+ p_type: fertilizer.p_type,
p_n_rt: fertilizer.p_n_rt,
+ p_n_wc: fertilizer.p_n_wc,
p_p_rt: fertilizer.p_p_rt,
p_k_rt: fertilizer.p_k_rt,
p_om: fertilizer.p_om,
- p_c_rt: fertilizer.p_c_rt,
+ p_eoc: fertilizer.p_eoc,
p_s_rt: fertilizer.p_s_rt,
p_ca_rt: fertilizer.p_ca_rt,
p_mg_rt: fertilizer.p_mg_rt,
@@ -170,64 +199,132 @@ export default function FarmFertilizerBlock() {
-
+
Naam
-
- {fertilizer.p_name_nl}
-
+
+ {loaderData.editable ? (
+ (
+
+
+
+
+
+
+
+ )}
+ />
+ ) : (
+
+ {
+ fertilizer.p_name_nl
+ }
+
+ )}
+
-
+
- Bron
+ Catalogus
-
- {fertilizer.p_source}
+
+ {fertilizer.p_source !==
+ loaderData.b_id_farm ? (
+
+ {
+ loaderData.farm
+ .b_name_farm
+ }
+
+ ) : (
+
+ {
+ fertilizer.p_source
+ }
+
+ )}
- {fertilizer.p_description && (
-
-
- Omschrijving
-
-
- {
- fertilizer.p_description
- }
-
-
- )}
- {fertilizer.p_type_manure && (
-
-
- Type
-
-
- Mest
-
-
- )}
- {fertilizer.p_type_mineral && (
-
-
- Type
-
-
- Mineraal
-
-
- )}
- {fertilizer.p_type_compost && (
-
-
- Type
+
+
+ Type
+
+ {loaderData.editable ? (
+ (
+
+
+
+
+
+ )}
+ />
+ ) : (
+
+ {fertilizer.p_type_manure ? (
+
+ Mest
+
+ ) : null}
+ {fertilizer.p_type_compost ? (
+
+ Compost
+
+ ) : null}
+ {fertilizer.p_type_mineral ? (
+
+ Kunstmest
+
+ ) : null}
-
- Compost
-
-
- )}
+ )}
+
@@ -238,333 +335,331 @@ export default function FarmFertilizerBlock() {
- {fertilizer.p_n_rt !== null && (
-
-
- Stikstof (N)
-
-
- {loaderData.editable ? (
- (
-
-
-
-
-
-
-
- )}
- />
- ) : (
-
- {
- fertilizer.p_n_rt
- }
-
- )}
-
- g N / kg
+
+ {/* Stikstof Row */}
+
+ Stikstof
+
+
+ {loaderData.editable ? (
+ (
+
+
+
+
+
+
+
+ )}
+ />
+ ) : (
+
+ {fertilizer.p_n_rt}
-
+ )}
- )}
- {fertilizer.p_p_rt !== null && (
-
-
- Fosfor (P)
-
-
- )}
- {fertilizer.p_k_rt !== null && (
-
-
- Kalium (K)
-
-
- )}
- {fertilizer.p_om !== null && (
-
-
- Organische stof (OS)
-
-
- )}
- {fertilizer.p_c_rt !== null && (
-
-
- Koolstof (C)
-
-
- )}
- {fertilizer.p_s_rt !== null && (
-
-
- Zwavel (S)
-
-
- )}
- {fertilizer.p_ca_rt !== null && (
-
-
- Calcium (Ca)
-
-
- )}
- {fertilizer.p_mg_rt !== null && (
-
-
- Magnesium (Mg)
-
-
- )}
+
+ g MgO / kg
+
+
From 47b4c8072d44d2c4a08d099c0222d74444c18fa2 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Fri, 28 Mar 2025 10:47:05 +0100
Subject: [PATCH 16/55] Add submit buttons
---
.../farm.$b_id_farm.fertilizers.$p_id.tsx | 37 +++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx b/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
index 531187230..15938b728 100644
--- a/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
+++ b/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
@@ -1,11 +1,14 @@
import { FarmHeader } from "@/components/custom/farm/farm-header"
import { FarmTitle } from "@/components/custom/farm/farm-title"
import { FormSchema } from "@/components/custom/fertilizer/formschema"
+import { LoadingSpinner } from "@/components/custom/loadingspinner"
import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
import {
Card,
CardContent,
CardDescription,
+ CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
@@ -326,6 +329,23 @@ export default function FarmFertilizerBlock() {
)}
+ {loaderData.editable && (
+
+
+
+ )}
@@ -661,6 +681,23 @@ export default function FarmFertilizerBlock() {
+ {loaderData.editable && (
+
+
+
+ )}
From 4e1e38f3c8e35d93df44b6265695715244e0e5b8 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Fri, 28 Mar 2025 11:11:09 +0100
Subject: [PATCH 17/55] Fix missing output
---
fdm-core/src/fertilizer.ts | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/fdm-core/src/fertilizer.ts b/fdm-core/src/fertilizer.ts
index 9cbf3fb9a..6407b2229 100644
--- a/fdm-core/src/fertilizer.ts
+++ b/fdm-core/src/fertilizer.ts
@@ -269,6 +269,18 @@ export async function getFertilizer(
schema.fertilizerAcquiring.p_acquiring_amount,
p_acquiring_date: schema.fertilizerAcquiring.p_acquiring_date,
p_picking_date: schema.fertilizerPicking.p_picking_date,
+ p_dm: schema.fertilizersCatalogue.p_dm,
+ p_density: schema.fertilizersCatalogue.p_density,
+ p_om: schema.fertilizersCatalogue.p_om,
+ p_a: schema.fertilizersCatalogue.p_a,
+ p_hc: schema.fertilizersCatalogue.p_hc,
+ p_eom: schema.fertilizersCatalogue.p_eom,
+ p_eoc: schema.fertilizersCatalogue.p_eoc,
+ p_c_rt: schema.fertilizersCatalogue.p_c_rt,
+ p_c_of: schema.fertilizersCatalogue.p_c_of,
+ p_c_if: schema.fertilizersCatalogue.p_c_if,
+ p_c_fr: schema.fertilizersCatalogue.p_c_fr,
+ p_cn_of: schema.fertilizersCatalogue.p_cn_of,
p_n_rt: schema.fertilizersCatalogue.p_n_rt,
p_n_if: schema.fertilizersCatalogue.p_n_if,
p_n_of: schema.fertilizersCatalogue.p_n_of,
@@ -480,6 +492,18 @@ export async function getFertilizers(
schema.fertilizerAcquiring.p_acquiring_amount,
p_acquiring_date: schema.fertilizerAcquiring.p_acquiring_date,
p_picking_date: schema.fertilizerPicking.p_picking_date,
+ p_dm: schema.fertilizersCatalogue.p_dm,
+ p_density: schema.fertilizersCatalogue.p_density,
+ p_om: schema.fertilizersCatalogue.p_om,
+ p_a: schema.fertilizersCatalogue.p_a,
+ p_hc: schema.fertilizersCatalogue.p_hc,
+ p_eom: schema.fertilizersCatalogue.p_eom,
+ p_eoc: schema.fertilizersCatalogue.p_eoc,
+ p_c_rt: schema.fertilizersCatalogue.p_c_rt,
+ p_c_of: schema.fertilizersCatalogue.p_c_of,
+ p_c_if: schema.fertilizersCatalogue.p_c_if,
+ p_c_fr: schema.fertilizersCatalogue.p_c_fr,
+ p_cn_of: schema.fertilizersCatalogue.p_cn_of,
p_n_rt: schema.fertilizersCatalogue.p_n_rt,
p_n_if: schema.fertilizersCatalogue.p_n_if,
p_n_of: schema.fertilizersCatalogue.p_n_of,
From 5c97d58c06c9188411b7d868b7cddee506a4e33f Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Fri, 28 Mar 2025 11:13:24 +0100
Subject: [PATCH 18/55] Extend schema with min and max values
---
.../custom/fertilizer/formschema.tsx | 114 ++++++++++++++----
1 file changed, 90 insertions(+), 24 deletions(-)
diff --git a/fdm-app/app/components/custom/fertilizer/formschema.tsx b/fdm-app/app/components/custom/fertilizer/formschema.tsx
index c080c724b..7e5c3bf42 100644
--- a/fdm-app/app/components/custom/fertilizer/formschema.tsx
+++ b/fdm-app/app/components/custom/fertilizer/formschema.tsx
@@ -9,28 +9,94 @@ export const FormSchema = z.object({
required_error: "Type is verplicht",
invalid_type_error: "Ongeldige waarde",
}),
- p_n_rt: z.coerce.number({
- invalid_type_error: "Ongeldige waarde",
- }),
- p_p_rt: z.coerce.number({
- invalid_type_error: "Ongeldige waarde",
- }),
- p_k_rt: z.coerce.number({
- invalid_type_error: "Ongeldige waarde",
- }),
- p_om: z.coerce.number({
- invalid_type_error: "Ongeldige waarde",
- }),
- p_c_rt: z.coerce.number({
- invalid_type_error: "Ongeldige waarde",
- }),
- p_s_rt: z.coerce.number({
- invalid_type_error: "Ongeldige waarde",
- }),
- p_ca_rt: z.coerce.number({
- invalid_type_error: "Ongeldige waarde",
- }),
- p_mg_rt: z.coerce.number({
- invalid_type_error: "Ongeldige waarde",
- }),
+ p_n_rt: z.coerce
+ .number({
+ invalid_type_error: "Ongeldige waarde",
+ })
+ .min(0, {
+ message: "Waarde mag niet negatief zijn",
+ })
+ .max(1000, {
+ message: "Waarde mag niet groter zijn dan 1000",
+ }),
+ p_n_wc: z.coerce
+ .number({
+ invalid_type_error: "Ongeldige waarde",
+ })
+ .min(0, {
+ message: "Waarde mag niet negatief zijn",
+ })
+ .max(1, {
+ message: "Waarde mag niet groter zijn dan 1",
+ }),
+ p_p_rt: z.coerce
+ .number({
+ invalid_type_error: "Ongeldige waarde",
+ })
+ .min(0, {
+ message: "Waarde mag niet negatief zijn",
+ })
+ .max(4583, {
+ message: "Waarde mag niet groter zijn dan 4583",
+ }),
+ p_k_rt: z.coerce
+ .number({
+ invalid_type_error: "Ongeldige waarde",
+ })
+ .min(0, {
+ message: "Waarde mag niet negatief zijn",
+ })
+ .max(2409.2, {
+ message: "Waarde mag niet groter zijn dan 2409.2",
+ }),
+ p_om: z.coerce
+ .number({
+ invalid_type_error: "Ongeldige waarde",
+ })
+ .min(0, {
+ message: "Waarde mag niet negatief zijn",
+ })
+ .max(1000, {
+ message: "Waarde mag niet groter zijn dan 1000",
+ }),
+ p_eoc: z.coerce
+ .number({
+ invalid_type_error: "Ongeldige waarde",
+ })
+ .min(0, {
+ message: "Waarde mag niet negatief zijn",
+ })
+ .max(1000, {
+ message: "Waarde mag niet groter zijn dan 1000",
+ }),
+ p_s_rt: z.coerce
+ .number({
+ invalid_type_error: "Ongeldige waarde",
+ })
+ .min(0, {
+ message: "Waarde mag niet negatief zijn",
+ })
+ .max(2497.2, {
+ message: "Waarde mag niet groter zijn dan 2497.2",
+ }),
+ p_ca_rt: z.coerce
+ .number({
+ invalid_type_error: "Ongeldige waarde",
+ })
+ .min(0, {
+ message: "Waarde mag niet negatief zijn",
+ })
+ .max(1399.2, {
+ message: "Waarde mag niet groter zijn dan 1399.2",
+ }),
+ p_mg_rt: z.coerce
+ .number({
+ invalid_type_error: "Ongeldige waarde",
+ })
+ .min(0, {
+ message: "Waarde mag niet negatief zijn",
+ })
+ .max(1659, {
+ message: "Waarde mag niet groter zijn dan 1659",
+ }),
})
From b5f2693c1d18fa0bb2a025364ebeb1d4cc88a74b Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Fri, 28 Mar 2025 11:14:34 +0100
Subject: [PATCH 19/55] Typo
---
fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx b/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
index 15938b728..743361825 100644
--- a/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
+++ b/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
@@ -96,8 +96,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
const fertilizer = await getFertilizer(fdm, p_id)
// Set editable status
- let editable = true
- console.log(fertilizer.p_source)
+ let editable = false
if (fertilizer.p_source === b_id_farm) {
editable = true
}
@@ -242,7 +241,7 @@ export default function FarmFertilizerBlock() {
Catalogus
- {fertilizer.p_source !==
+ {fertilizer.p_source ===
loaderData.b_id_farm ? (
{
From 6bd5f8781243b5cbc401780ae035457d2c9ca598 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Fri, 28 Mar 2025 12:01:49 +0100
Subject: [PATCH 20/55] Include p_id_catalogue
---
fdm-core/src/fertilizer.ts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/fdm-core/src/fertilizer.ts b/fdm-core/src/fertilizer.ts
index 6407b2229..1c9934f02 100644
--- a/fdm-core/src/fertilizer.ts
+++ b/fdm-core/src/fertilizer.ts
@@ -261,6 +261,7 @@ export async function getFertilizer(
const fertilizer = await fdm
.select({
p_id: schema.fertilizers.p_id,
+ p_id_catalogue: schema.fertilizersCatalogue.p_id_catalogue,
p_source: schema.fertilizersCatalogue.p_source,
p_name_nl: schema.fertilizersCatalogue.p_name_nl,
p_name_en: schema.fertilizersCatalogue.p_name_en,
@@ -484,6 +485,7 @@ export async function getFertilizers(
const fertilizers = await fdm
.select({
p_id: schema.fertilizers.p_id,
+ p_id_catalogue: schema.fertilizersCatalogue.p_id_catalogue,
p_source: schema.fertilizersCatalogue.p_source,
p_name_nl: schema.fertilizersCatalogue.p_name_nl,
p_name_en: schema.fertilizersCatalogue.p_name_en,
From cbef8d4ab741c1f5d90ff00c427be6f9afc06b61 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Fri, 28 Mar 2025 12:02:09 +0100
Subject: [PATCH 21/55] Export updateFertilizerFromCatalogue
---
fdm-core/src/index.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/fdm-core/src/index.ts b/fdm-core/src/index.ts
index 509efdacb..000512498 100644
--- a/fdm-core/src/index.ts
+++ b/fdm-core/src/index.ts
@@ -25,6 +25,7 @@ export { addFarm, getFarm, getFarms, updateFarm } from "./farm"
export { addField, getField, getFields, updateField } from "./field"
export {
addFertilizerToCatalogue,
+ updateFertilizerFromCatalogue,
getFertilizersFromCatalogue,
addFertilizer,
removeFertilizer,
From e0a09548dbee6a9cdd338374acb39c961c2a1614 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Fri, 28 Mar 2025 12:02:55 +0100
Subject: [PATCH 22/55] Add header for fertilizers
---
.../components/custom/farm/farm-header.tsx | 57 +++++++++++++++++++
fdm-app/app/components/custom/farm/farm.d.ts | 5 ++
.../farm.$b_id_farm.fertilizers.$p_id.tsx | 20 ++++++-
3 files changed, 80 insertions(+), 2 deletions(-)
diff --git a/fdm-app/app/components/custom/farm/farm-header.tsx b/fdm-app/app/components/custom/farm/farm-header.tsx
index 9fdc249af..f289ed5c0 100644
--- a/fdm-app/app/components/custom/farm/farm-header.tsx
+++ b/fdm-app/app/components/custom/farm/farm-header.tsx
@@ -20,6 +20,7 @@ import { ChevronDown } from "lucide-react"
import { NavLink } from "react-router"
import type {
FarmOptions,
+ FertilizerOption,
FieldOptions,
HeaderAction,
LayerKey,
@@ -33,6 +34,8 @@ interface FarmHeaderProps {
b_id: string | undefined
layerOptions: LayerOptions[]
layerSelected: LayerKey | undefined
+ fertilizerOptions: FertilizerOption[] | undefined
+ p_id: string | undefined
action: HeaderAction
}
@@ -43,6 +46,8 @@ export function FarmHeader({
b_id,
layerOptions,
layerSelected,
+ fertilizerOptions,
+ p_id,
action,
}: FarmHeaderProps) {
return (
@@ -178,6 +183,58 @@ export function FarmHeader({
>
) : null}
+ {fertilizerOptions &&
+ fertilizerOptions.length > 0 ? (
+ <>
+
+
+
+ Meststof
+
+
+
+
+
+
+ {p_id && fertilizerOptions
+ ? (fertilizerOptions.find(
+ (option) =>
+ option.p_id ===
+ p_id,
+ )?.p_name_nl ??
+ "Unknown fertilizer")
+ : "Kies een meststof"}
+
+
+
+ {fertilizerOptions.map(
+ (option) => (
+
+
+ {
+ option.p_name_nl
+ }
+
+
+ ),
+ )}
+
+
+
+ >
+ ) : null}
>
) : null}
diff --git a/fdm-app/app/components/custom/farm/farm.d.ts b/fdm-app/app/components/custom/farm/farm.d.ts
index 4609f5e04..2462249eb 100644
--- a/fdm-app/app/components/custom/farm/farm.d.ts
+++ b/fdm-app/app/components/custom/farm/farm.d.ts
@@ -22,6 +22,11 @@ export interface LayerOption {
export type LayerOptions = LayerOption[]
+export interface FertilizerOption {
+ p_id: string
+ p_name_nl: string
+}
+
export interface HeaderAction {
label: string
to: string
diff --git a/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx b/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
index 743361825..983ff5c04 100644
--- a/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
+++ b/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
@@ -92,11 +92,24 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
}
})
- // Get the available fertilizers
+ // Get selected fertilizer
const fertilizer = await getFertilizer(fdm, p_id)
+ // Get the available fertilizers
+ const fertilizers = await getFertilizers(
+ fdm,
+ session.principal_id,
+ b_id_farm,
+ )
+ const fertilizerOptions = fertilizers.map((fertilizer) => {
+ return {
+ p_id: fertilizer.p_id,
+ p_name_nl: fertilizer.p_name_nl,
+ }
+ })
+
// Set editable status
- let editable = false
+ let editable = true
if (fertilizer.p_source === b_id_farm) {
editable = true
}
@@ -106,6 +119,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
farm: farm,
b_id_farm: b_id_farm,
farmOptions: farmOptions,
+ fertilizerOptions: fertilizerOptions,
fertilizer: fertilizer,
editable: editable,
}
@@ -176,6 +190,8 @@ export default function FarmFertilizerBlock() {
to: "../fertilizers",
label: "Terug naar overzicht",
}}
+ fertilizerOptions={loaderData.fertilizerOptions}
+ p_id={loaderData.fertilizer.p_id}
/>
Date: Fri, 28 Mar 2025 13:17:47 +0100
Subject: [PATCH 23/55] Move form into component
---
.../app/components/custom/fertilizer/form.tsx | 436 ++++++++++++
.../farm.$b_id_farm.fertilizers.$p_id.tsx | 640 +++---------------
2 files changed, 530 insertions(+), 546 deletions(-)
create mode 100644 fdm-app/app/components/custom/fertilizer/form.tsx
diff --git a/fdm-app/app/components/custom/fertilizer/form.tsx b/fdm-app/app/components/custom/fertilizer/form.tsx
new file mode 100644
index 000000000..d9cf05922
--- /dev/null
+++ b/fdm-app/app/components/custom/fertilizer/form.tsx
@@ -0,0 +1,436 @@
+import { type Farm, type Fertilizer } from "@svenvw/fdm-core";
+import { type z, type ZodType } from "zod";
+import { type UseFormReturn } from "react-hook-form";
+import { Badge } from "@/components/ui/badge";
+import { Button } from "@/components/ui/button";
+import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
+import { FormControl, FormDescription, FormField, FormItem, FormMessage } from "@/components/ui/form";
+import { Input } from "@/components/ui/input";
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
+import { Form } from "react-router";
+import { RemixFormProvider } from "remix-hook-form";
+import { LoadingSpinner } from "../loadingspinner";
+
+export function FertilizerForm({
+ fertilizer,
+ form,
+ editable,
+ farm, }: { fertilizer: Fertilizer; form: UseFormReturn, ZodType, undefined>; editable: boolean; farm: Farm }) {
+
+ return (
+
+
+
+ )
+}
diff --git a/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx b/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
index 983ff5c04..d5675c02e 100644
--- a/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
+++ b/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
@@ -1,47 +1,29 @@
import { FarmHeader } from "@/components/custom/farm/farm-header"
import { FarmTitle } from "@/components/custom/farm/farm-title"
+import { FertilizerForm } from "@/components/custom/fertilizer/form"
import { FormSchema } from "@/components/custom/fertilizer/formschema"
-import { LoadingSpinner } from "@/components/custom/loadingspinner"
-import { Badge } from "@/components/ui/badge"
-import { Button } from "@/components/ui/button"
-import {
- Card,
- CardContent,
- CardDescription,
- CardFooter,
- CardHeader,
- CardTitle,
-} from "@/components/ui/card"
-import {
- FormControl,
- FormDescription,
- FormField,
- FormItem,
- FormLabel,
- FormMessage,
-} from "@/components/ui/form"
-import { Input } from "@/components/ui/input"
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from "@/components/ui/select"
import { SidebarInset } from "@/components/ui/sidebar"
import { getSession } from "@/lib/auth.server"
-import { handleLoaderError } from "@/lib/error"
+import { handleActionError, handleLoaderError } from "@/lib/error"
import { fdm } from "@/lib/fdm.server"
+import { extractFormValuesFromRequest } from "@/lib/form"
import { zodResolver } from "@hookform/resolvers/zod"
-import { getFarm, getFarms, getFertilizer } from "@svenvw/fdm-core"
+import {
+ getFarm,
+ getFarms,
+ getFertilizer,
+ getFertilizers,
+} from "@svenvw/fdm-core"
+import { updateFertilizerFromCatalogue } from "@svenvw/fdm-core"
import { useEffect } from "react"
import {
- Form,
+ type ActionFunctionArgs,
type LoaderFunctionArgs,
data,
useLoaderData,
} from "react-router"
-import { RemixFormProvider, useRemixForm } from "remix-hook-form"
+import { useRemixForm } from "remix-hook-form"
+import { dataWithSuccess } from "remix-toast"
import type { z } from "zod"
export async function loader({ request, params }: LoaderFunctionArgs) {
@@ -199,527 +181,93 @@ export default function FarmFertilizerBlock() {
description={"Bekijk de eigenschappen van dit product"}
/>
-
-
-
-
-
-
- )
+ return dataWithSuccess(
+ { result: "Data saved successfully" },
+ { message: "Meststof is bijgewerkt! 🎉" },
+ )
+ } catch (error) {
+ throw handleActionError(error)
+ }
}
From 8fa1afaeeb4a4e0467f78a3b5a3375806227ffca Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Fri, 28 Mar 2025 13:25:06 +0100
Subject: [PATCH 24/55] Move button
---
fdm-app/app/components/custom/fertilizer/table.tsx | 11 +++++++++++
.../routes/farm.$b_id_farm.fertilizers._index.tsx | 14 ++------------
2 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/fdm-app/app/components/custom/fertilizer/table.tsx b/fdm-app/app/components/custom/fertilizer/table.tsx
index 02d3a61d9..7801e4175 100644
--- a/fdm-app/app/components/custom/fertilizer/table.tsx
+++ b/fdm-app/app/components/custom/fertilizer/table.tsx
@@ -18,6 +18,9 @@ import {
} from "@/components/ui/table"
import { useState } from "react"
import { Input } from "@/components/ui/input"
+import { Button } from "@/components/ui/button"
+import { NavLink } from "react-router"
+import { Plus } from "lucide-react"
interface DataTableProps {
columns: ColumnDef[]
@@ -62,6 +65,14 @@ export function DataTable({
}
className="max-w-sm"
/>
+
+
+
+
+
diff --git a/fdm-app/app/routes/farm.$b_id_farm.fertilizers._index.tsx b/fdm-app/app/routes/farm.$b_id_farm.fertilizers._index.tsx
index 1313f32b3..cc27a759c 100644
--- a/fdm-app/app/routes/farm.$b_id_farm.fertilizers._index.tsx
+++ b/fdm-app/app/routes/farm.$b_id_farm.fertilizers._index.tsx
@@ -10,12 +10,7 @@ import { getSession } from "@/lib/auth.server"
import { handleLoaderError } from "@/lib/error"
import { fdm } from "@/lib/fdm.server"
import { getFarm, getFarms, getFertilizers } from "@svenvw/fdm-core"
-import {
- type LoaderFunctionArgs,
- Outlet,
- data,
- useLoaderData,
-} from "react-router"
+import { type LoaderFunctionArgs, data, useLoaderData } from "react-router"
export async function loader({ request, params }: LoaderFunctionArgs) {
try {
@@ -62,7 +57,6 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
session.principal_id,
b_id_farm,
)
- // console.log(fertilizers)
// Return user information from loader
return {
@@ -89,11 +83,7 @@ export default function FarmFertilizersBlock() {
Date: Fri, 28 Mar 2025 13:37:16 +0100
Subject: [PATCH 25/55] Fix
---
fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx b/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
index d5675c02e..0bf7b0928 100644
--- a/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
+++ b/fdm-app/app/routes/farm.$b_id_farm.fertilizers.$p_id.tsx
@@ -91,7 +91,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
})
// Set editable status
- let editable = true
+ let editable = false
if (fertilizer.p_source === b_id_farm) {
editable = true
}
From f6920b8bda2b53e2b56f05e81db8be1d991a3ae9 Mon Sep 17 00:00:00 2001
From: Sven Verweij <37927107+SvenVw@users.noreply.github.com>
Date: Fri, 28 Mar 2025 13:37:39 +0100
Subject: [PATCH 26/55] Improve table with fertilizers
---
.../components/custom/fertilizer/columns.tsx | 51 +++++++++---
.../app/components/custom/fertilizer/form.tsx | 83 ++++++++++++++-----
2 files changed, 104 insertions(+), 30 deletions(-)
diff --git a/fdm-app/app/components/custom/fertilizer/columns.tsx b/fdm-app/app/components/custom/fertilizer/columns.tsx
index c9ebcd712..2d9dcb201 100644
--- a/fdm-app/app/components/custom/fertilizer/columns.tsx
+++ b/fdm-app/app/components/custom/fertilizer/columns.tsx
@@ -1,7 +1,5 @@
import type { ColumnDef } from "@tanstack/react-table"
-import {
- SquareArrowOutUpRight,
-} from "lucide-react"
+import { ArrowRight, Pencil, SquareArrowOutUpRight } from "lucide-react"
import { DataTableColumnHeader } from "./column-header"
import {
Tooltip,
@@ -10,6 +8,7 @@ import {
TooltipTrigger,
} from "@/components/ui/tooltip"
import { NavLink } from "react-router"
+import { Badge } from "@/components/ui/badge"
export type Fertilizer = {
p_id: string
@@ -20,10 +19,10 @@ export type Fertilizer = {
}
export const columns: ColumnDef[] = [
- {
- accessorKey: "p_id",
- header: "ID",
- },
+ // {
+ // accessorKey: "p_id",
+ // header: "ID",
+ // },
{
accessorKey: "p_name_nl",
header: "Naam",
@@ -37,11 +36,43 @@ export const columns: ColumnDef[] = [
{
accessorKey: "p_p_rt",
header: ({ column }) => {
- return
+ return
+ },
+ },
+ {
+ accessorKey: "p_k_rt",
+ header: ({ column }) => {
+ return
+ },
+ },
+ {
+ accessorKey: "p_eoc",
+ header: ({ column }) => {
+ return
+ },
+ },
+ {
+ accessorKey: "Type",
+ cell: ({ row }) => {
+ const fertilizer = row.original
+
+ return (
+
+ {fertilizer.p_type_manure ? (
+ Mest
+ ) : null}
+ {fertilizer.p_type_compost ? (
+ Compost
+ ) : null}
+ {fertilizer.p_type_mineral ? (
+ Kunstmest
+ ) : null}
+
+ )
},
},
{
- accessorKey: "Opties",
+ accessorKey: "Details",
cell: ({ row }) => {
const fertilizer = row.original
@@ -50,7 +81,7 @@ export const columns: ColumnDef[] = [
-
+
{`Bekijk details over ${fertilizer.p_name_nl}`}
diff --git a/fdm-app/app/components/custom/fertilizer/form.tsx b/fdm-app/app/components/custom/fertilizer/form.tsx
index d9cf05922..776843ef6 100644
--- a/fdm-app/app/components/custom/fertilizer/form.tsx
+++ b/fdm-app/app/components/custom/fertilizer/form.tsx
@@ -1,25 +1,57 @@
-import { type Farm, type Fertilizer } from "@svenvw/fdm-core";
-import { type z, type ZodType } from "zod";
-import { type UseFormReturn } from "react-hook-form";
-import { Badge } from "@/components/ui/badge";
-import { Button } from "@/components/ui/button";
-import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
-import { FormControl, FormDescription, FormField, FormItem, FormMessage } from "@/components/ui/form";
-import { Input } from "@/components/ui/input";
-import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
-import { Form } from "react-router";
-import { RemixFormProvider } from "remix-hook-form";
-import { LoadingSpinner } from "../loadingspinner";
+import { type Farm, type Fertilizer } from "@svenvw/fdm-core"
+import { type z, type ZodType } from "zod"
+import { type UseFormReturn } from "react-hook-form"
+import { Badge } from "@/components/ui/badge"
+import { Button } from "@/components/ui/button"
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardFooter,
+ CardHeader,
+ CardTitle,
+} from "@/components/ui/card"
+import {
+ FormControl,
+ FormDescription,
+ FormField,
+ FormItem,
+ FormMessage,
+} from "@/components/ui/form"
+import { Input } from "@/components/ui/input"
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select"
+import { Form } from "react-router"
+import { RemixFormProvider } from "remix-hook-form"
+import { LoadingSpinner } from "../loadingspinner"
export function FertilizerForm({
fertilizer,
form,
editable,
- farm, }: { fertilizer: Fertilizer; form: UseFormReturn, ZodType, undefined>; editable: boolean; farm: Farm }) {
-
+ farm,
+}: {
+ fertilizer: Fertilizer
+ form: UseFormReturn<
+ z.infer,
+ ZodType,
+ undefined
+ >
+ editable: boolean
+ farm: Farm
+}) {
return (
- |