Skip to content
5 changes: 5 additions & 0 deletions .changeset/easy-boxes-sort.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@svenvw/fdm-app": patch
---

The code for fertilizer management is made more maintainable by using only one route for all fertilizer application routes.
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,7 @@ export function FertilizerApplicationForm({
)
}
navigate(
searchParams.has("fieldIds")
? `./manage/new?fieldIds=${searchParams.get("fieldIds")}`
: "./manage/new",
`/farm/${b_id_farm}/fertilizers/new?returnUrl=${encodeURIComponent(`${location.pathname}${location.search}`)}`,
)
}

Expand Down
9 changes: 5 additions & 4 deletions fdm-app/app/components/blocks/fertilizer/new-fertilizer.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { modifySearchParams } from "@/app/lib/url-utils"
import type { Fertilizer } from "@svenvw/fdm-core"
import { Link, NavLink, useSearchParams } from "react-router"
import { Card, CardContent } from "~/components/ui/card"
Expand All @@ -7,8 +8,8 @@ export function CustomFertilizerButton() {
return (
<Link
to={
searchParams.has("fieldIds")
? `custom?fieldIds=${searchParams.get("fieldIds")}`
searchParams.has("returnUrl")
? `custom?returnUrl=${encodeURIComponent(searchParams.get("returnUrl") ?? "")}`
: "custom"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
className="block"
Expand Down Expand Up @@ -36,8 +37,8 @@ export function BasedOffFertilizerButton({
return (
<NavLink
to={
searchParams.has("fieldIds")
? `${fertilizer.p_id}?fieldIds=${searchParams.get("fieldIds")}`
searchParams.has("returnUrl")
? `${fertilizer.p_id}?returnUrl=${encodeURIComponent(searchParams.get("returnUrl") ?? "")}`
: `${fertilizer.p_id}`
}
className="block"
Expand Down
9 changes: 6 additions & 3 deletions fdm-app/app/components/blocks/header/create-farm.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useLocation } from "react-router"
import { useLocation, useSearchParams } from "react-router"
import {
BreadcrumbItem,
BreadcrumbLink,
Expand All @@ -11,6 +11,7 @@ export function HeaderFarmCreate({
b_name_farm: string | undefined | null
}) {
const location = useLocation()
const [searchParams] = useSearchParams()
const currentPath = String(location.pathname)

return (
Expand Down Expand Up @@ -65,10 +66,12 @@ export function HeaderFarmCreate({
<BreadcrumbLink>Bouwplan</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
{currentPath.match(/manage/) ? (
{currentPath.match(/new/) ? (
<>
<BreadcrumbItem className="hidden md:block">
<BreadcrumbLink href="..">
<BreadcrumbLink
href={searchParams.get("returnUrl") ?? "#"}
>
Bemesting
</BreadcrumbLink>
</BreadcrumbItem>
Expand Down
9 changes: 6 additions & 3 deletions fdm-app/app/components/blocks/sidebar/apps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
MapIcon,
Scale,
} from "lucide-react"
import { NavLink, useLocation } from "react-router"
import { NavLink, useLocation, useSearchParams } from "react-router"
import { useCalendarStore } from "@/app/store/calendar"
import { useFarmStore } from "@/app/store/farm"
import { Badge } from "~/components/ui/badge"
Expand All @@ -24,9 +24,12 @@ export function SidebarApps() {
const farmId = useFarmStore((state) => state.farmId)
const selectedCalendar = useCalendarStore((state) => state.calendar)

// Check if page contains `farm/create` in url
// Check if the page or its return page contains `farm/create` in url
const location = useLocation()
const isCreateFarmWizard = location.pathname.includes("farm/create")
const [searchParams] = useSearchParams()
const isCreateFarmWizard =
location.pathname.includes("farm/create") ||
searchParams.get("returnUrl")?.includes("farm/create")

let atlasLink: string | undefined
if (isCreateFarmWizard) {
Expand Down
9 changes: 6 additions & 3 deletions fdm-app/app/components/blocks/sidebar/farm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
Square,
} from "lucide-react"
import { useState } from "react"
import { NavLink, useLocation } from "react-router"
import { NavLink, useLocation, useSearchParams } from "react-router"
import { getCalendarSelection } from "@/app/lib/calendar"
import { useCalendarStore } from "@/app/store/calendar"
import { useFarmStore } from "@/app/store/farm"
Expand Down Expand Up @@ -37,9 +37,12 @@ export function SidebarFarm() {
const [isCalendarOpen, setIsCalendarOpen] = useState(false)
const calendarSelection = getCalendarSelection()

// Check if page contains `farm/create` in url
// Check if the page or its return page contains `farm/create` in url
const location = useLocation()
const isCreateFarmWizard = location.pathname.includes("farm/create")
const [searchParams] = useSearchParams()
const isCreateFarmWizard =
location.pathname.includes("farm/create") ||
searchParams.get("returnUrl")?.includes("farm/create")

// Set the farm link
let farmLink: string
Expand Down
71 changes: 71 additions & 0 deletions fdm-app/app/lib/url-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* Applies a function on the search params from a relative or absolute path,
* or a full URL, then returns the modified value.
*
* Note that it will treat input like `example.com/about` as
* `/example.com/about` since it looks for a http:// or https:// at the
* beginning to determine full URLs
*
* @param href relative or absolute path, or a full URL
* @param modifier function to be applied on the search params
* @returns a relative or absolute path, or a full URL, whichever format was
* provided
*/
export function modifySearchParams(
href: string,
modifier: (searchParams: URLSearchParams) => void,
): string {
const hasProtocol =
href.startsWith("http://") || href.startsWith("https://")
const hasSlash = href.startsWith("/")
const url = new URL(
hasProtocol
? href
: hasSlash
? `http://localhost${href}`
: `http://localhost/${href}`,
)
modifier(url.searchParams)
const relativeToOrigin = `${url.pathname}${url.search}${url.hash}`
return hasProtocol
? url.href
: hasSlash
? relativeToOrigin
: relativeToOrigin.substring(1)
}

/**
* Gets the search params from a relative or absolute path, or a full URL.
*
* Note that it will treat input like `example.com/about` as
* `/example.com/about` since it looks for a http:// or https:// at the
* beginning to determine full URLs
*
* @param href relative or absolute path, or a full URL
* @returns the search parameters, or empty search parameters if none was found
*/
export function getSearchParams(href: string) {
let searchParams: URLSearchParams | undefined
if (href.length > 0) {
modifySearchParams(href, (p) => {
searchParams = p
})
}
return searchParams ?? new URLSearchParams()
}

/**
* Checks if the given URL-like might be a full URL, and if so, if it is of the
* origin given. No checks are performed if no protocol in the URL is detected.
*
* @param href URL-like
* @param origin origin, like `example.com` to check if full URL is detected
* @returns the validation result for full URLs, true if no full URL is found
*/
export function isOfOrigin(href: string, origin: string) {
try {
return !href.includes("://") || new URL(href).origin === origin
} catch {
return false
}
}
Loading