diff --git a/frontend/src/components/general/Tabs.tsx b/frontend/src/components/general/Tabs.tsx
new file mode 100644
index 00000000..160f7612
--- /dev/null
+++ b/frontend/src/components/general/Tabs.tsx
@@ -0,0 +1,46 @@
+import { ReactNode } from '@tanstack/react-router';
+import React, { useState } from 'react';
+
+interface Tabs {
+ tabs: { label: string; icon: ReactNode; view: ReactNode; }[]
+}
+
+const Tabs: React.FC = ({ tabs }) => {
+ const [showTabIndex, setShowTabIndex] = useState(0);
+
+ return (
+ <>
+
+ {tabs.map((tab, key) => (
+ setShowTabIndex(key)}
+ key={key}
+ id={`tab-${key}`}
+ role="tab"
+ aria-selected={showTabIndex === key}
+ aria-controls={`tabpanel-${key}`}
+ className={`flex items-center gap-x-2 pb-2 group border-b transition-all ease-in-out duration-300 hover:text-dark-800 ${showTabIndex === key ? 'text-dark border-b-dark' : 'text-dark-600 border-b-transparent'}`}
+ >
+ {tab.icon}
+ {tab.label}
+
+ ))}
+
+
+ {tabs.map((tab, key) => (
+
+ {tab.view}
+
+ ))}
+ >
+ );
+}
+
+export default Tabs;
diff --git a/frontend/src/components/general/cards/EntitiesStatusCard.tsx b/frontend/src/components/general/cards/EntitiesStatusCard.tsx
new file mode 100644
index 00000000..1fc76cbb
--- /dev/null
+++ b/frontend/src/components/general/cards/EntitiesStatusCard.tsx
@@ -0,0 +1,20 @@
+import React from 'react';
+
+interface EntitiesStatusCard {
+ statusDetails: {label: string, color: string, description: string};
+ label: string;
+}
+
+const EntitiesStatusCard: React.FC = ({ statusDetails, label }) => {
+ return (
+
+
{label}
+
+ {statusDetails.label}
+
+
{statusDetails.description}
+
+ );
+}
+
+export default EntitiesStatusCard;
diff --git a/frontend/src/components/general/cards/GeneralStatusCard.tsx b/frontend/src/components/general/cards/GeneralStatusCard.tsx
index 93e95ca1..aeec3088 100644
--- a/frontend/src/components/general/cards/GeneralStatusCard.tsx
+++ b/frontend/src/components/general/cards/GeneralStatusCard.tsx
@@ -4,13 +4,14 @@ interface GeneralStatusCard {
overline: string;
value: string;
description?: string;
+ isLarge?: boolean;
}
-const GeneralStatusCard: React.FC = ({ overline, value, description = '' }) => {
+const GeneralStatusCard: React.FC = ({ overline, value, description = '', isLarge = false }) => {
return (
{overline}
-
{value}
+
{value}
{description &&
{description}
}
);
diff --git a/frontend/src/components/general/cards/TreeCard.tsx b/frontend/src/components/general/cards/TreeCard.tsx
index 8bcbc02f..2f11e418 100644
--- a/frontend/src/components/general/cards/TreeCard.tsx
+++ b/frontend/src/components/general/cards/TreeCard.tsx
@@ -1,70 +1,37 @@
import { getWateringStatusDetails } from '@/hooks/useDetailsForWateringStatus';
-import { EntitiesTreeClusterWateringStatus } from '@green-ecolution/backend-client';
+import { EntitiesTreeClusterWateringStatus, Tree } from '@green-ecolution/backend-client';
import { Link } from '@tanstack/react-router';
import { MoveRight } from 'lucide-react';
import React from 'react';
-
-interface Tree {
- id: number;
- species: string;
- number: string;
- hasSensor: boolean;
- status: EntitiesTreeClusterWateringStatus;
-}
-
-interface TreeCardContentProps {
- tree: Tree;
- statusDetails: {
- color: string;
- label: string;
- description: string;
- };
-}
-
-const TreeCardContent: React.FC = ({ tree, statusDetails }) => (
- <>
-
- {statusDetails.label}
-
- {tree.species}
- {tree.number &&
-
- Baumnummer: {tree.number}
-
- }
-
- {tree.hasSensor &&
-
- Zur Detailansicht
-
-
- }
- >
-);
-
interface TreeCardProps {
tree: Tree;
}
const TreeCard: React.FC = ({ tree }) => {
- const statusDetails = getWateringStatusDetails(tree.status);
+ // TODO: Add real status
+ const statusDetails = getWateringStatusDetails(EntitiesTreeClusterWateringStatus.TreeClusterWateringStatusGood);
const wrapperClasses = 'bg-white group border border-dark-50 p-6 rounded-xl shadow-cards flex flex-col gap-y-4 lg:grid lg:grid-cols-[1fr,2fr,1fr,1fr] lg:items-center lg:gap-5 lg:py-5 xl:px-10';
- if (!tree.hasSensor) {
- return (
-
-
-
- );
- }
-
return (
-
+
+ {statusDetails.label}
+
+ {tree.species}
+ {tree.number &&
+
+ Baumnummer: {tree.number}
+
+ }
+
+
+ Zur Detailansicht
+
+
);
}
diff --git a/frontend/src/components/general/cards/WateringStatusCard.tsx b/frontend/src/components/general/cards/WateringStatusCard.tsx
deleted file mode 100644
index 5cc00881..00000000
--- a/frontend/src/components/general/cards/WateringStatusCard.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import { getWateringStatusDetails } from '@/hooks/useDetailsForWateringStatus';
-import { EntitiesTreeClusterWateringStatus } from '@green-ecolution/backend-client';
-import React from 'react';
-
-interface WateringStatusCard {
- wateringStatus: EntitiesTreeClusterWateringStatus;
-}
-
-const WateringStatusCard: React.FC = ({ wateringStatus }) => {
- const statusDetails = getWateringStatusDetails(wateringStatus);
-
- return (
-
-
Bewässerungszustand (ø)
-
- {statusDetails.label}
-
-
{statusDetails.description}
-
- );
-}
-
-export default WateringStatusCard;
diff --git a/frontend/src/components/general/error/LoadingInfo.tsx b/frontend/src/components/general/error/LoadingInfo.tsx
new file mode 100644
index 00000000..52008b3f
--- /dev/null
+++ b/frontend/src/components/general/error/LoadingInfo.tsx
@@ -0,0 +1,19 @@
+import React from 'react';
+
+interface LoadingInfo {
+ label: string;
+}
+
+const LoadingInfo: React.FC = ({ label }) => {
+ return (
+
+ );
+}
+
+export default LoadingInfo;
diff --git a/frontend/src/components/general/filter/Dialog.tsx b/frontend/src/components/general/filter/Dialog.tsx
index 0a129bc1..44da2973 100644
--- a/frontend/src/components/general/filter/Dialog.tsx
+++ b/frontend/src/components/general/filter/Dialog.tsx
@@ -117,7 +117,7 @@ const Dialog: React.FC = ({ initStatusTags, initRegionTags, headlin
diff --git a/frontend/src/components/general/buttons/GeneralLink.tsx b/frontend/src/components/general/links/ButtonLink.tsx
similarity index 73%
rename from frontend/src/components/general/buttons/GeneralLink.tsx
rename to frontend/src/components/general/links/ButtonLink.tsx
index ff8632b3..5f7841d2 100644
--- a/frontend/src/components/general/buttons/GeneralLink.tsx
+++ b/frontend/src/components/general/links/ButtonLink.tsx
@@ -2,13 +2,14 @@ import { Link } from '@tanstack/react-router';
import { MoveRight } from 'lucide-react';
import React from 'react';
-interface GeneralLinkProps {
+interface ButtonLink {
label: string;
url: string;
+ asButton?: boolean;
icon: React.ComponentType>;
}
-const GeneralLink: React.FC = ({ label, icon: Icon = MoveRight, url }) => (
+const ButtonLink: React.FC = ({ label, icon: Icon = MoveRight, url }) => (
= ({ label, icon: Icon = MoveRight
);
-export default GeneralLink;
+export default ButtonLink;
diff --git a/frontend/src/components/general/links/GeneralLink.tsx b/frontend/src/components/general/links/GeneralLink.tsx
new file mode 100644
index 00000000..026b79d2
--- /dev/null
+++ b/frontend/src/components/general/links/GeneralLink.tsx
@@ -0,0 +1,17 @@
+import { Link } from '@tanstack/react-router';
+import { MoveRight } from 'lucide-react';
+import React from 'react';
+
+interface GeneralLink {
+ label: string;
+ url: string;
+}
+
+const GeneralLink: React.FC = ({ label, url }) => (
+
+ {label}
+
+
+);
+
+export default GeneralLink;
diff --git a/frontend/src/components/icons/Sensor.tsx b/frontend/src/components/icons/Sensor.tsx
new file mode 100644
index 00000000..55fd2339
--- /dev/null
+++ b/frontend/src/components/icons/Sensor.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+
+const Sensor: React.FC> = (props) => (
+
+
+
+);
+
+export default Sensor;
diff --git a/frontend/src/components/tree/TreeGeneralData.tsx b/frontend/src/components/tree/TreeGeneralData.tsx
new file mode 100644
index 00000000..23621d95
--- /dev/null
+++ b/frontend/src/components/tree/TreeGeneralData.tsx
@@ -0,0 +1,80 @@
+import { format } from "date-fns";
+
+
+interface TreeGeneralData {
+ tree?: {
+ id: number;
+ species: string;
+ number: number;
+ heightAboveSeaLevel: number;
+ plantingYear: number;
+ age: number;
+ updatedAt: string;
+ latitude: number;
+ longitude: number;
+ }
+}
+
+const TreeGeneralData: React.FC = ({ tree }) => {
+ const updatedDate = tree?.updatedAt
+ ? format(new Date(tree?.updatedAt), 'dd.MM.yyyy')
+ : 'Keine Angabe';
+
+ const treeData = [
+ {
+ label: 'Baumart',
+ value: tree?.species ?? 'Keine Angabe',
+ },
+ {
+ label: 'Höhe über NHN',
+ value: tree?.heightAboveSeaLevel ?? 'Keine Angabe',
+ },
+ {
+ label: 'Standalter',
+ value: tree?.age ?? 'Keine Angabe',
+ },
+ {
+ label: 'Pflanzjahr',
+ value: tree?.plantingYear ?? 'Keine Angabe',
+ },
+ {
+ label: 'Bewässerungsgruppe',
+ value: '@TODO: Implement'
+ },
+ {
+ label: 'Latitude',
+ value: tree?.latitude ?? 'Keine Angabe',
+ },
+ {
+ label: 'Longitude',
+ value: tree?.longitude ?? 'Keine Angabe',
+ },
+ {
+ label: 'Letztes Update',
+ value: updatedDate,
+ },
+ ];
+
+ return (
+ <>
+
+ {treeData.map((data, index) => (
+
+
{data.label}:
+ {data.value}
+
+ ))}
+
+
+
+ @TODO: Add image slider
+
+ >
+ );
+}
+
+export default TreeGeneralData;
diff --git a/frontend/src/components/tree/TreeSensorData.tsx b/frontend/src/components/tree/TreeSensorData.tsx
new file mode 100644
index 00000000..b284917e
--- /dev/null
+++ b/frontend/src/components/tree/TreeSensorData.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import GeneralStatusCard from '../general/cards/GeneralStatusCard';
+import EntitiesStatusCard from '../general/cards/EntitiesStatusCard';
+import { getSensorStatusDetails } from '@/hooks/useDetailsForSensorStatus';
+import { EntitiesSensorStatus, Tree } from '@green-ecolution/backend-client';
+import { format } from 'date-fns';
+
+interface TreeSensorData {
+ tree?: Tree,
+}
+
+const TreeSensorData: React.FC = ({ tree }) => {
+ const updatedDate = tree?.updatedAt
+ ? format(new Date(tree?.updatedAt), 'dd.MM.yyyy')
+ : 'Keine Angabe';
+ const updatedTime = tree?.updatedAt
+ ? format(new Date(tree?.updatedAt), 'HH:mm')
+ : 'Keine Angabe';
+
+ const statusCards = [
+ {
+ overline: "Letzte Messung",
+ value: `${updatedTime} Uhr`,
+ description: `am ${updatedDate}`,
+ },
+ ]
+
+ const sensorStatus = tree?.sensor?.status ?? EntitiesSensorStatus.SensorStatusUnknown;
+
+ return (
+ <>
+
+
+
+
+ {statusCards.map((card, key) => (
+
+
+
+ ))}
+
+ >
+ );
+}
+
+export default TreeSensorData;
diff --git a/frontend/src/components/tree/TreeWateringStatus.tsx b/frontend/src/components/tree/TreeWateringStatus.tsx
new file mode 100644
index 00000000..529c3e96
--- /dev/null
+++ b/frontend/src/components/tree/TreeWateringStatus.tsx
@@ -0,0 +1,124 @@
+import { EntitiesTreeClusterWateringStatus, Tree } from '@green-ecolution/backend-client';
+import React from 'react';
+import { TreeDeciduous } from 'lucide-react';
+import { getWateringStatusDetails } from '@/hooks/useDetailsForWateringStatus';
+import GeneralStatusCard from '../general/cards/GeneralStatusCard';
+import EntitiesStatusCard from '../general/cards/EntitiesStatusCard';
+
+interface TreeWateringStatus {
+ tree?: Tree,
+}
+
+const TreeWateringStatus: React.FC = ({ tree }) => {
+ // TODO: Switch to real content
+ const statusProDepth = [
+ {
+ status: EntitiesTreeClusterWateringStatus.TreeClusterWateringStatusGood,
+ sensorCount: 1,
+ value: "42,46 kΩ",
+ },
+ {
+ status: EntitiesTreeClusterWateringStatus.TreeClusterWateringStatusGood,
+ sensorCount: 1,
+ value: "35,46 kΩ",
+ },
+ {
+ status: EntitiesTreeClusterWateringStatus.TreeClusterWateringStatusModerate,
+ sensorCount: 1,
+ value: "28,12 kΩ",
+ },
+ ];
+
+ // TODO: Switch to real content
+ const statusCards = [
+ {
+ overline: "Bewässerungszustand (ø)",
+ value: "35,02 kΩ",
+ description: "+0.5% zu der letzten Messung.",
+ },
+ {
+ overline: "Bodenfeuchte",
+ value: "78 %",
+ description: "-0.5% zu der letzten Messung.",
+ },
+ {
+ overline: "Bodentemperatur",
+ value: "12 °C",
+ description: "- 0.5 °C zur letzten Messung",
+ },
+ ]
+
+ return (
+ <>
+
+
+
+
+ {statusCards.map((card, key) => (
+
+
+
+ ))}
+
+
+
+
+ Bewässerungszustand pro Bodentiefe
+
+
+
+
+
+
+
+ Status
+ Eingesetzte Tiefe
+ Anzahl der Sensoren
+
+
+
+
+
+
+ >
+ );
+}
+
+export default TreeWateringStatus;
diff --git a/frontend/src/data/trees.tsx b/frontend/src/data/trees.tsx
deleted file mode 100644
index 028469fc..00000000
--- a/frontend/src/data/trees.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import { EntitiesTreeClusterWateringStatus } from "@green-ecolution/backend-client";
-
-export function treeDemoData() {
- return [
- {
- id: 0,
- species: 'Quercus robur',
- number: '100123',
- hasSensor: true,
- status: EntitiesTreeClusterWateringStatus.TreeClusterWateringStatusGood,
- },
- {
- id: 1,
- species: 'Crataegus monogyna',
- number: '100123',
- hasSensor: true,
- status: EntitiesTreeClusterWateringStatus.TreeClusterWateringStatusModerate,
- },
- {
- id: 2,
- species: 'Crataegus monogyna',
- number: '100123',
- hasSensor: true,
- status: EntitiesTreeClusterWateringStatus.TreeClusterWateringStatusGood,
- },
- {
- id: 3,
- species: 'Quercus robur',
- number: '100123',
- hasSensor: false,
- status: EntitiesTreeClusterWateringStatus.TreeClusterWateringStatusUnknown,
- },
- {
- id: 4,
- species: 'Quercus robur',
- number: '100123',
- hasSensor: false,
- status: EntitiesTreeClusterWateringStatus.TreeClusterWateringStatusUnknown,
- },
- ];
-}
diff --git a/frontend/src/hooks/useDetailsForSensorStatus.ts b/frontend/src/hooks/useDetailsForSensorStatus.ts
new file mode 100644
index 00000000..334a1339
--- /dev/null
+++ b/frontend/src/hooks/useDetailsForSensorStatus.ts
@@ -0,0 +1,25 @@
+import { EntitiesSensorStatus } from "@green-ecolution/backend-client";
+
+const SensorStatusProperties = {
+ [EntitiesSensorStatus.SensorStatusUnknown]: {
+ color: 'dark-400',
+ label: 'Unbekannt',
+ description: 'Der Status ist unbekannt.',
+ },
+ [EntitiesSensorStatus.SensorStatusOffline]: {
+ color: 'red',
+ label: 'Offline',
+ description: 'Einige Sensoren haben Probleme und benötigen eine Wartung.',
+ },
+ [EntitiesSensorStatus.SensorStatusOnline]: {
+ color: 'green-light',
+ label: 'In Ordnung',
+ description: 'Alle Sensoren sind online und können Daten senden.',
+ },
+} as const;
+
+type SensorStatusDetails = typeof SensorStatusProperties[EntitiesSensorStatus];
+
+export const getSensorStatusDetails = (status: EntitiesSensorStatus): SensorStatusDetails => {
+ return SensorStatusProperties[status];
+};
diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts
index b043b1a9..24b6bf14 100644
--- a/frontend/src/routeTree.gen.ts
+++ b/frontend/src/routeTree.gen.ts
@@ -28,10 +28,10 @@ import { Route as ProtectedWaypointsIndexImport } from './routes/_protected/wayp
import { Route as ProtectedTreeclusterIndexImport } from './routes/_protected/treecluster/index'
import { Route as ProtectedMapIndexImport } from './routes/_protected/map/index'
import { Route as ProtectedWaypointsNewImport } from './routes/_protected/waypoints/new'
+import { Route as ProtectedTreesTreeIdImport } from './routes/_protected/trees/$treeId'
import { Route as ProtectedTreeclusterNewImport } from './routes/_protected/treecluster/new'
import { Route as ProtectedTreeclusterTreeclusterIdImport } from './routes/_protected/treecluster/$treeclusterId'
import { Route as ProtectedTreeNewImport } from './routes/_protected/tree/new'
-import { Route as ProtectedTreeTreeIdImport } from './routes/_protected/tree/$treeId'
import { Route as ProtectedMapTreeNewImport } from './routes/_protected/map/tree/new'
import { Route as ProtectedMapTreeclusterSelectTreeImport } from './routes/_protected/map/treecluster/select.tree'
@@ -122,6 +122,11 @@ const ProtectedWaypointsNewRoute = ProtectedWaypointsNewImport.update({
getParentRoute: () => ProtectedRoute,
} as any)
+const ProtectedTreesTreeIdRoute = ProtectedTreesTreeIdImport.update({
+ path: '/trees/$treeId',
+ getParentRoute: () => ProtectedRoute,
+} as any)
+
const ProtectedTreeclusterNewRoute = ProtectedTreeclusterNewImport.update({
path: '/treecluster/new',
getParentRoute: () => ProtectedRoute,
@@ -138,11 +143,6 @@ const ProtectedTreeNewRoute = ProtectedTreeNewImport.update({
getParentRoute: () => ProtectedRoute,
} as any)
-const ProtectedTreeTreeIdRoute = ProtectedTreeTreeIdImport.update({
- path: '/tree/$treeId',
- getParentRoute: () => ProtectedRoute,
-} as any)
-
const ProtectedMapTreeNewRoute = ProtectedMapTreeNewImport.update({
path: '/tree/new',
getParentRoute: () => ProtectedMapRoute,
@@ -249,13 +249,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof ProtectedIndexImport
parentRoute: typeof ProtectedImport
}
- '/_protected/tree/$treeId': {
- id: '/_protected/tree/$treeId'
- path: '/tree/$treeId'
- fullPath: '/tree/$treeId'
- preLoaderRoute: typeof ProtectedTreeTreeIdImport
- parentRoute: typeof ProtectedImport
- }
'/_protected/tree/new': {
id: '/_protected/tree/new'
path: '/tree/new'
@@ -277,6 +270,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof ProtectedTreeclusterNewImport
parentRoute: typeof ProtectedImport
}
+ '/_protected/trees/$treeId': {
+ id: '/_protected/trees/$treeId'
+ path: '/trees/$treeId'
+ fullPath: '/trees/$treeId'
+ preLoaderRoute: typeof ProtectedTreesTreeIdImport
+ parentRoute: typeof ProtectedImport
+ }
'/_protected/waypoints/new': {
id: '/_protected/waypoints/new'
path: '/waypoints/new'
@@ -339,10 +339,10 @@ export const routeTree = rootRoute.addChildren({
ProtectedTeamRoute,
ProtectedVehiclesRoute,
ProtectedIndexRoute,
- ProtectedTreeTreeIdRoute,
ProtectedTreeNewRoute,
ProtectedTreeclusterTreeclusterIdRoute,
ProtectedTreeclusterNewRoute,
+ ProtectedTreesTreeIdRoute,
ProtectedWaypointsNewRoute,
ProtectedTreeclusterIndexRoute,
ProtectedWaypointsIndexRoute,
@@ -378,10 +378,10 @@ export const routeTree = rootRoute.addChildren({
"/_protected/team",
"/_protected/vehicles",
"/_protected/",
- "/_protected/tree/$treeId",
"/_protected/tree/new",
"/_protected/treecluster/$treeclusterId",
"/_protected/treecluster/new",
+ "/_protected/trees/$treeId",
"/_protected/waypoints/new",
"/_protected/treecluster/",
"/_protected/waypoints/"
@@ -437,10 +437,6 @@ export const routeTree = rootRoute.addChildren({
"filePath": "_protected/index.tsx",
"parent": "/_protected"
},
- "/_protected/tree/$treeId": {
- "filePath": "_protected/tree/$treeId.tsx",
- "parent": "/_protected"
- },
"/_protected/tree/new": {
"filePath": "_protected/tree/new.tsx",
"parent": "/_protected"
@@ -453,6 +449,10 @@ export const routeTree = rootRoute.addChildren({
"filePath": "_protected/treecluster/new.tsx",
"parent": "/_protected"
},
+ "/_protected/trees/$treeId": {
+ "filePath": "_protected/trees/$treeId.tsx",
+ "parent": "/_protected"
+ },
"/_protected/waypoints/new": {
"filePath": "_protected/waypoints/new.tsx",
"parent": "/_protected"
diff --git a/frontend/src/routes/_protected/map/index.tsx b/frontend/src/routes/_protected/map/index.tsx
index ec1121b7..7810ccce 100644
--- a/frontend/src/routes/_protected/map/index.tsx
+++ b/frontend/src/routes/_protected/map/index.tsx
@@ -1,16 +1,23 @@
-import { createFileRoute } from "@tanstack/react-router";
+import { createFileRoute, useNavigate } from "@tanstack/react-router";
import MapButtons from "@/components/map/MapButtons";
import { WithAllTrees } from "@/components/map/TreeMarker";
+import { Tree } from "@green-ecolution/backend-client";
export const Route = createFileRoute("/_protected/map/")({
component: MapView,
});
function MapView() {
+ const navigate = useNavigate({ from: '/map' });
+
+ const handleMarkerClick = (tree: Tree) => {
+ navigate({ to: `/trees/${tree.id}` });
+ };
+
return (
<>
-
+
>
);
}
diff --git a/frontend/src/routes/_protected/tree/$treeId.tsx b/frontend/src/routes/_protected/tree/$treeId.tsx
deleted file mode 100644
index 06fcddf0..00000000
--- a/frontend/src/routes/_protected/tree/$treeId.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import { createFileRoute } from '@tanstack/react-router'
-
-export const Route = createFileRoute('/_protected/tree/$treeId')({
- component: () => Hello /_protected/dashboard/tree/$treeId!
-})
-
-
diff --git a/frontend/src/routes/_protected/treecluster/$treeclusterId.tsx b/frontend/src/routes/_protected/treecluster/$treeclusterId.tsx
index 41e0d91f..b7154fee 100644
--- a/frontend/src/routes/_protected/treecluster/$treeclusterId.tsx
+++ b/frontend/src/routes/_protected/treecluster/$treeclusterId.tsx
@@ -1,9 +1,12 @@
+import { treeApi } from '@/api/backendApi';
+import EntitiesStatusCard from '@/components/general/cards/EntitiesStatusCard';
import GeneralStatusCard from '@/components/general/cards/GeneralStatusCard';
import TreeCard from '@/components/general/cards/TreeCard';
-import WateringStatusCard from '@/components/general/cards/WateringStatusCard';
import BackLink from '@/components/general/links/BackLink';
import { treeclusterDemoData } from '@/data/treecluser';
-import { treeDemoData } from '@/data/trees';
+import { useAuthHeader } from '@/hooks/useAuthHeader';
+import { getWateringStatusDetails } from '@/hooks/useDetailsForWateringStatus';
+import { useQuery } from '@tanstack/react-query';
import { createFileRoute, useLoaderData } from '@tanstack/react-router'
export const Route = createFileRoute('/_protected/treecluster/$treeclusterId')({
@@ -16,13 +19,14 @@ export const Route = createFileRoute('/_protected/treecluster/$treeclusterId')({
})
function SingleTreecluster() {
-
- const trees = treeDemoData();
-
const treecluster = useLoaderData({ from: '/_protected/treecluster/$treeclusterId'});
- if (!treecluster) {
- return Tree cluster not found
;
- }
+ const authorization = useAuthHeader();
+
+ // TODO: delete if real tree cluster data is used
+ const { data: treeRes } = useQuery({
+ queryKey: ["trees"],
+ queryFn: () => treeApi.getAllTrees({ authorization }),
+ });
const location = `${treecluster.address}, ${treecluster.region}`;
const treeCount = `${treecluster.treeCount} Bäume | ${treecluster.sensorCount} mit Sensoren`;
@@ -43,10 +47,11 @@ function SingleTreecluster() {
-
diff --git a/frontend/src/routes/_protected/trees/$treeId.tsx b/frontend/src/routes/_protected/trees/$treeId.tsx
new file mode 100644
index 00000000..a2e9032f
--- /dev/null
+++ b/frontend/src/routes/_protected/trees/$treeId.tsx
@@ -0,0 +1,94 @@
+import { treeApi } from '@/api/backendApi';
+import LoadingInfo from '@/components/general/error/LoadingInfo';
+import BackLink from '@/components/general/links/BackLink';
+import GeneralLink from '@/components/general/links/GeneralLink';
+import Tabs from '@/components/general/Tabs';
+import Sensor from '@/components/icons/Sensor';
+import Tree from '@/components/icons/Tree';
+import TreeGeneralData from '@/components/tree/TreeGeneralData';
+import TreeSensorData from '@/components/tree/TreeSensorData';
+import TreeWateringStatus from '@/components/tree/TreeWateringStatus';
+import { useAuthHeader } from '@/hooks/useAuthHeader';
+import { useSuspenseQuery } from '@tanstack/react-query';
+import { createFileRoute, useLoaderData } from '@tanstack/react-router'
+import { File, Info } from 'lucide-react';
+
+export const Route = createFileRoute('/_protected/trees/$treeId')({
+ component: SingleTree,
+
+ loader: async ({ params }) => {
+ return params.treeId;
+ },
+})
+
+function SingleTree() {
+ const treeId = useLoaderData({ from: '/_protected/trees/$treeId'});
+ const authorization = useAuthHeader();
+
+ const { data: tree, isLoading, isError } = useSuspenseQuery({
+ queryKey: ["tree", treeId],
+ queryFn: () => treeApi.getTrees({ treeId, authorization }),
+ });
+
+ const tabs = [
+ {
+ label: 'Bewässerungsdaten',
+ icon: ,
+ view:
+ },
+ {
+ label: 'Allgemeine Daten',
+ icon: ,
+ view:
+ },
+ {
+ label: 'Sensordaten',
+ icon: ,
+ view:
+ },
+ ];
+
+ return (
+
+ {isLoading ? (
+
+ ) : isError || !tree ? (
+
Einen Baum mit der Baumnummer {treeId} gibt es nicht oder die Baumdaten konnten nicht geladen werden.
+ ) : (
+
+
+
+
+ Baum: {tree.number}
+
+
+ @TODO: Bewässerungsgruppe hinzufügen,
+ @TODO: Adresse der Bewässerungsgruppe
+
+
+
+ {tree?.sensor ? (
+
+ ) : (
+
+
+
+
+ Info: Dieser Baum ist nicht mit einem Sensor ausgestattet.
+
+
+ Dieser Baum wurde bisher nicht mit einem Sensor ausgestattet, sodass keine Informationen über den aktuellen Bewässerungszustand angezeigt
+ werden können.
+
+
+
+
+ )}
+
+ )}
+
+ )
+}