diff --git a/frontend/components/core/command/vessel-finder.tsx b/frontend/components/core/command/vessel-finder.tsx index 7232bf7a..9fa65b52 100644 --- a/frontend/components/core/command/vessel-finder.tsx +++ b/frontend/components/core/command/vessel-finder.tsx @@ -1,13 +1,16 @@ "use client" -import { useShallow } from "zustand/react/shallow" -import { useState } from "react" +import { useEffect, useMemo, useRef, useState } from "react" import { getVesselFirstExcursionSegments } from "@/services/backend-rest-client" import { FlyToInterpolator } from "deck.gl" +import { useShallow } from "zustand/react/shallow" -import { Vessel, VesselPosition } from "@/types/vessel" +import { VesselPosition } from "@/types/vessel" +import { useMapStore } from "@/libs/stores/map-store" +import { useTrackModeOptionsStore } from "@/libs/stores/track-mode-options-store" +import { useVesselsStore } from "@/libs/stores/vessels-store" import { - CommandDialog, + Command, CommandEmpty, CommandGroup, CommandInput, @@ -15,19 +18,18 @@ import { CommandList, CommandSeparator, } from "@/components/ui/command" -import { useMapStore } from "@/libs/stores/map-store" -import { useTrackModeOptionsStore } from "@/libs/stores/track-mode-options-store" -import { useVesselsStore } from "@/libs/stores/vessels-store" type Props = { wideMode: boolean + setWideMode: (wideMode: boolean) => void } const SEPARATOR = "___" -export function VesselFinderDemo({ wideMode }: Props) { +export function VesselFinderDemo({ wideMode, setWideMode }: Props) { const [open, setOpen] = useState(false) const [search, setSearch] = useState("") + const inputRef = useRef(null) const { addTrackedVessel, trackedVesselIDs } = useTrackModeOptionsStore( useShallow((state) => ({ @@ -36,19 +38,15 @@ export function VesselFinderDemo({ wideMode }: Props) { })) ) - const { - setActivePosition, - viewState, - latestPositions, - setViewState, - } = useMapStore( - useShallow((state) => ({ - viewState: state.viewState, - latestPositions: state.latestPositions, - setActivePosition: state.setActivePosition, - setViewState: state.setViewState, - })) - ) + const { setActivePosition, viewState, latestPositions, setViewState } = + useMapStore( + useShallow((state) => ({ + viewState: state.viewState, + latestPositions: state.latestPositions, + setActivePosition: state.setActivePosition, + setViewState: state.setViewState, + })) + ) const { vessels: allVessels } = useVesselsStore( useShallow((state) => ({ @@ -56,8 +54,37 @@ export function VesselFinderDemo({ wideMode }: Props) { })) ) + const simpleVessels = useMemo(() => { + return allVessels.map((vessel) => ({ + id: vessel.id, + title: vessel.ship_name, + subtitle: `MMSI ${vessel.mmsi} | IMO ${vessel.imo}`, + value: `${vessel.ship_name}${SEPARATOR}${vessel.mmsi}${SEPARATOR}${vessel.imo}${SEPARATOR}${vessel.id}`, + })) + }, [allVessels]) + + const filteredItems = useMemo( + () => + simpleVessels.filter( + (vessel) => + vessel.value.toLowerCase().includes(search.toLowerCase()) && + !trackedVesselIDs.includes(vessel.id) + ), + [simpleVessels, search, trackedVesselIDs] + ) + + useEffect(() => { + if (!wideMode && open) { + setOpen(false) + } + }, [wideMode]) + + const displayedItems = filteredItems.slice(0, 50) + const onSelectVessel = async (vesselIdentifier: string) => { + setOpen(false) const vesselId = parseInt(vesselIdentifier.split(SEPARATOR)[3]) + const response = await getVesselFirstExcursionSegments(vesselId) if (vesselId && !trackedVesselIDs.includes(vesselId)) { addTrackedVessel(vesselId) @@ -83,67 +110,53 @@ export function VesselFinderDemo({ wideMode }: Props) { } return ( - <> - - - - - - No results found. - - {allVessels.map((vessel: Vessel) => { - return ( - onSelectVessel(value)} - value={`${vessel.ship_name}${SEPARATOR}${vessel.mmsi}${SEPARATOR}${vessel.imo}${SEPARATOR}${vessel.id}`} // so we can search by name, mmsi, imo - > - {vessel.ship_name} - - {" "} - MMSI {vessel.mmsi} | IMO {vessel.imo} + No results found. + + {displayedItems.map((vessel) => { + return ( + onSelectVessel(value)} + value={vessel.value} + > +
+ {vessel.title} + - + + {vessel.subtitle} - - ) - })} - - - - - +
+
+ ) + })} +
+ +
+ ) } diff --git a/frontend/components/core/left-panel.tsx b/frontend/components/core/left-panel.tsx index a3dc0a5b..1b9b2cc3 100644 --- a/frontend/components/core/left-panel.tsx +++ b/frontend/components/core/left-panel.tsx @@ -1,6 +1,6 @@ "use client" -import { useEffect, useState } from "react" +import { useEffect } from "react" import Image from "next/image" import TrawlWatchLogo from "@/public/trawlwatch.svg" import { ChartBarIcon } from "@heroicons/react/24/outline" @@ -114,7 +114,7 @@ export default function LeftPanel() { name="Dashboard" wide={leftPanelOpened} > - +
@@ -123,7 +123,10 @@ export default function LeftPanel() {
) : ( - + )} diff --git a/frontend/components/core/map/filter-button.tsx b/frontend/components/core/map/filter-button.tsx index 364db138..f12fe959 100644 --- a/frontend/components/core/map/filter-button.tsx +++ b/frontend/components/core/map/filter-button.tsx @@ -17,9 +17,9 @@ export function FilterButton({ @@ -107,9 +128,7 @@ export default function TrackedVesselItem({
- +
diff --git a/frontend/components/core/tracked-vessel/tracked-vessels-panel.tsx b/frontend/components/core/tracked-vessel/tracked-vessels-panel.tsx index 35a8249d..27154f6a 100644 --- a/frontend/components/core/tracked-vessel/tracked-vessels-panel.tsx +++ b/frontend/components/core/tracked-vessel/tracked-vessels-panel.tsx @@ -309,28 +309,26 @@ export default function TrackedVesselsPanel({ return ( <> -
-
- {!wideMode && ( -
- - {vesselsSelectedCount > 0 && ( - - {vesselsSelectedCount} - - )} -
- )} - {mapMode === "position" && wideMode && ( - {`Selected vessel (${trackedVesselIDs.length})`} - )} -
+
+ {!wideMode && ( +
+ + {vesselsSelectedCount > 0 && ( + + {vesselsSelectedCount} + + )} +
+ )} + {mapMode === "position" && wideMode && ( + {`Selected vessel (${trackedVesselIDs.length})`} + )}
{wideMode && } diff --git a/frontend/components/dashboard/kpi-card.tsx b/frontend/components/dashboard/kpi-card.tsx index c565f31e..e8581360 100644 --- a/frontend/components/dashboard/kpi-card.tsx +++ b/frontend/components/dashboard/kpi-card.tsx @@ -21,7 +21,7 @@ export default function KPICard({ loading, }: Props) { return ( -
+
{title}
diff --git a/frontend/components/ui/command.tsx b/frontend/components/ui/command.tsx index 80567b4b..9e1aa58d 100644 --- a/frontend/components/ui/command.tsx +++ b/frontend/components/ui/command.tsx @@ -21,9 +21,7 @@ const Command = React.forwardRef< )) Command.displayName = CommandPrimitive.displayName -interface CommandDialogProps extends DialogProps {} - -const CommandDialog = ({ children, ...props }: CommandDialogProps) => { +const CommandDialog = ({ children, ...props }: DialogProps) => { return ( @@ -115,7 +113,7 @@ const CommandItem = React.forwardRef< {children} - + Close diff --git a/frontend/components/ui/icon-button.tsx b/frontend/components/ui/icon-button.tsx index 172490f7..b33989d0 100644 --- a/frontend/components/ui/icon-button.tsx +++ b/frontend/components/ui/icon-button.tsx @@ -1,6 +1,7 @@ -import { cn } from "@/libs/utils" import * as React from "react" +import { cn } from "@/libs/utils" + type Props = { description: string onClick?: () => void @@ -9,25 +10,26 @@ type Props = { className?: string } -export default function IconButton({ - onClick, - children, - description, - disabled, - className, -}: Props) { - return ( - - ) -} +const IconButton = React.forwardRef( + ({ onClick, children, description, disabled, className }, ref) => { + return ( + + ) + } +) + +IconButton.displayName = "IconButton" + +export default IconButton diff --git a/frontend/components/ui/navigation-link.tsx b/frontend/components/ui/navigation-link.tsx index 1bb5c44d..2fe25eb0 100644 --- a/frontend/components/ui/navigation-link.tsx +++ b/frontend/components/ui/navigation-link.tsx @@ -7,6 +7,7 @@ interface Props { name: string wide: boolean href: string + onClick?: () => void } const NavigationLink = ({ @@ -14,15 +15,17 @@ const NavigationLink = ({ name, href = "#", wide = false, + onClick, }: Props) => { return ( {children} {wide && ( -

+

{name}

)} diff --git a/frontend/components/ui/select.tsx b/frontend/components/ui/select.tsx index c94fa86d..5cc7cb3c 100644 --- a/frontend/components/ui/select.tsx +++ b/frontend/components/ui/select.tsx @@ -116,7 +116,7 @@ const SelectItem = React.forwardRef<