From e91ac886c73d3093fc168a549841e5928d5e8c05 Mon Sep 17 00:00:00 2001
From: Hannah <hz018@hdm-stuttgart.de>
Date: Tue, 16 Jan 2024 21:38:24 +0100
Subject: [PATCH] #51 show growingTip, plantsReadyToGrow,plantsReadyToWater and
 plantsReadyToHarvest + fix bug in schemas.ts (imageUrl can now be null) +
 merged main into my branch

---
 CHANGELOG.md                                  |  32 ++--
 growbros-frontend/package-lock.json           |  28 +++
 growbros-frontend/package.json                |   5 +
 .../src/components/DropDownFilter.tsx         |  55 +++---
 .../src/components/FilterPage.tsx             |  95 +++++++--
 growbros-frontend/src/components/Grandma.tsx  |  49 +++--
 .../src/components/PlantDetails.tsx           |  87 ++++-----
 .../src/components/StatusMessage.tsx          |  30 +++
 growbros-frontend/src/index.css               |  12 +-
 growbros-frontend/src/pages/Garten.tsx        | 101 +++++++---
 growbros-frontend/src/pages/Suche.tsx         | 181 +++++++++++++-----
 growbros-frontend/src/pages/Wunschliste.tsx   | 110 ++++++-----
 growbros-frontend/src/stylesheets/Home.css    |   8 +-
 growbros-frontend/src/stylesheets/Navbar.css  |   2 +-
 .../src/stylesheets/RegisterAndLogin.css      |   2 -
 .../src/stylesheets/StatusMessage.css         |  22 +++
 .../src/utils/BackendConnectorImpl.ts         |  23 ++-
 .../src/utils/IBackendConnector.ts            |   4 +-
 growbros-frontend/src/utils/commonTypes.d.ts  |  12 +-
 growbros-frontend/src/utils/schemas.ts        |  77 ++++++--
 .../controllers/GardenController.java         |   6 +-
 .../controllers/WishListController.java       |   6 +-
 .../hdm/mi/growbros/models/WishListEntry.java |  14 +-
 .../repositories/GardenRepository.java        |   7 +
 .../repositories/WishListRepository.java      |  14 ++
 .../mi/growbros/service/GardenService.java    |   3 +-
 .../mi/growbros/service/GrandmaService.java   |   4 +-
 .../mi/growbros/service/WishListService.java  |   4 +-
 28 files changed, 692 insertions(+), 301 deletions(-)
 create mode 100644 growbros-frontend/src/components/StatusMessage.tsx
 create mode 100644 growbros-frontend/src/stylesheets/StatusMessage.css

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2ada303..df898cc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,12 +15,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - This Changelog
 - Tags and Semantic Versioning
 
-### Fixed
-
-### Changed
-
-### Removed
-
 ## [0.1.0] - 31.12.2023
 
 ### Added
@@ -29,11 +23,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - JWT token is persisted as cookie 
 - Wishlist 
 - Plant details
-- Plants overview 
-- Random plants 
+- Plants overview
+- Random plants
 
-### Fixed
+## [0.2.0] - 13.01.2024
+
+### Added
+
+- Buttons to remove & add plants to wishlist and garden. Includes status message popup
 
-### Changed
+## [Released]
+
+## [1.0.0]
+
+### Added
+
+- Search functionality
+- Fully functional release
+- Garden, wishlist all working
+
+## [1.0.1]
+
+### Fixed
 
-### Removed
+- Re-add empty option to dropdown on search / filter page
diff --git a/growbros-frontend/package-lock.json b/growbros-frontend/package-lock.json
index 277b0d4..28e79d6 100644
--- a/growbros-frontend/package-lock.json
+++ b/growbros-frontend/package-lock.json
@@ -14,11 +14,14 @@
         "@mui/material": "^5.15.4",
         "font-awesome": "^4.7.0",
         "jwt-decode": "^4.0.0",
+        "mui": "^0.0.1",
         "rc-slider": "^10.5.0",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
+        "react-icons": "^4.12.0",
         "react-modal": "^3.16.1",
         "react-router-dom": "^6.18.0",
+        "reactjs-popup": "^2.0.6",
         "zod": "^3.22.4"
       },
       "devDependencies": {
@@ -2662,6 +2665,11 @@
       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
       "dev": true
     },
+    "node_modules/mui": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/mui/-/mui-0.0.1.tgz",
+      "integrity": "sha512-iB9zfxsJBcMkZ/SY6X+HGSPr4fftCZIQ76ZMH8iSMfVkidVzRtZlLW2gbWXUe+IMcj8JLv1p+dGKvPVlgtiocA=="
+    },
     "node_modules/nanoid": {
       "version": "3.3.6",
       "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
@@ -2970,6 +2978,14 @@
         "react": "^18.2.0"
       }
     },
+    "node_modules/react-icons": {
+      "version": "4.12.0",
+      "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz",
+      "integrity": "sha512-IBaDuHiShdZqmfc/TwHu6+d6k2ltNCf3AszxNmjJc1KUfXdEeRJOKyNvLmAHaarhzGmTSVygNdyu8/opXv2gaw==",
+      "peerDependencies": {
+        "react": "*"
+      }
+    },
     "node_modules/react-is": {
       "version": "18.2.0",
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
@@ -3043,6 +3059,18 @@
         "react-dom": ">=16.6.0"
       }
     },
+    "node_modules/reactjs-popup": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/reactjs-popup/-/reactjs-popup-2.0.6.tgz",
+      "integrity": "sha512-A+tt+x9wdgZiZjv0e2WzYLD3IfFwJALaRaqwrCSXGjo0iQdsry/EtBEbQXRSmQs7cHmOi5eytCiSlOm8k4C+dg==",
+      "engines": {
+        "node": ">=10"
+      },
+      "peerDependencies": {
+        "react": ">=16",
+        "react-dom": ">=16"
+      }
+    },
     "node_modules/regenerator-runtime": {
       "version": "0.14.1",
       "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
diff --git a/growbros-frontend/package.json b/growbros-frontend/package.json
index 76963cb..d83e50f 100644
--- a/growbros-frontend/package.json
+++ b/growbros-frontend/package.json
@@ -10,8 +10,13 @@
     "preview": "vite preview"
   },
   "dependencies": {
+    "@emotion/react": "^11.11.3",
+    "@emotion/styled": "^11.11.0",
+    "@mui/icons-material": "^5.15.4",
+    "@mui/material": "^5.15.4",
     "font-awesome": "^4.7.0",
     "jwt-decode": "^4.0.0",
+    "mui": "^0.0.1",
     "rc-slider": "^10.5.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
diff --git a/growbros-frontend/src/components/DropDownFilter.tsx b/growbros-frontend/src/components/DropDownFilter.tsx
index 655574c..41bb750 100644
--- a/growbros-frontend/src/components/DropDownFilter.tsx
+++ b/growbros-frontend/src/components/DropDownFilter.tsx
@@ -1,37 +1,32 @@
-import { useState } from "react";
-import { propsDropDownFilter } from "../utils/commonTypes";
+import {useState} from "react";
+import {DropdownOption, PropsDropDownFilter} from "../utils/commonTypes";
 import "../stylesheets/DropDownFilter.css";
+import "../pages/Wunschliste.tsx";
 
-function DropDownFilter(props: PropsDropDownFilter) {
-  const options = props.options;
-  const topic = props.topic;
-  const [selectedOption, setSelectedOption] = useState("");
+function DropDownFilter<T extends DropdownOption>(props: PropsDropDownFilter<T>) {
+    const options = props.options;
+    const topic = props.topic;
+    const hasEmptyOption = props.hasEmptyOption;
+    const [selectedOption, setSelectedOption] = useState("");
 
-  const handleOptionChange = (event: any) => {
-    setSelectedOption(event.target.value);
-    props.filterOnChange!(event.target.value);
-  };
+    const handleOptionChange = (event: any) => {
+        setSelectedOption(event.target.value);
+        props.filterOnChange(event.target.value);
+    };
 
-  return (
-    <div className="dropdown-filter">
-      <label>{topic}</label>
-      <select value={selectedOption} onChange={handleOptionChange}>
-        <option value=""></option>
-        {options.map((option, index) => (
-          <option key={index} value={option}>
-            {option}
-          </option>
-        ))}
-      </select>
-    </div>
-  );
+    return (
+        <div className="dropdown-filter">
+            <label>{topic}</label>
+            <select value={selectedOption} onChange={handleOptionChange}>
+                {hasEmptyOption && <option value=""/>}
+                {options.map((option, index) => (
+                    <option key={index} value={option}>
+                        {option}
+                    </option>
+                ))}
+            </select>
+        </div>
+    );
 }
 
-//TODO filteronchange ? weg wenn lara Garten fertig
-type PropsDropDownFilter = {
-  options: Array<string>;
-  topic: string;
-  filterOnChange?: (selectedOption: string) => void;
-};
-
 export default DropDownFilter;
diff --git a/growbros-frontend/src/components/FilterPage.tsx b/growbros-frontend/src/components/FilterPage.tsx
index ebee59d..81657c8 100644
--- a/growbros-frontend/src/components/FilterPage.tsx
+++ b/growbros-frontend/src/components/FilterPage.tsx
@@ -1,11 +1,53 @@
-import { useState } from "react";
+import {useState} from "react";
 import Slider from "rc-slider";
 import "rc-slider/assets/index.css";
 import "../stylesheets/FilterPage.css";
 import DropDownFilter from "./DropDownFilter";
-import { propsSliderFilter } from "../utils/commonTypes";
+import {PropsSliderFilter} from "../utils/commonTypes";
+import {
+  GroundType,
+  GroundTypeTranslated,
+  LightingDemand,
+  LightingDemandTranslated,
+  NutrientDemand,
+  NutrientDemandTranslated,
+  translateGroundTypeReverse,
+  translateLightingDemandReverse,
+  translateNutrientDemandReverse,
+  translateWaterDemandReverse,
+  WaterDemand,
+  WaterDemandTranslated,
+} from "../utils/schemas";
 
-function FilterPage() {
+type FilterPageProps = {
+  setWaterDemand: (value: WaterDemand) => void;
+  setNutrientDemand: (value: NutrientDemand) => void;
+  setLightingDemand: (value: LightingDemand) => void;
+  setGroundType: (value: GroundType) => void;
+  setPlantDuration: (value: [number, number]) => void;
+  setGrowthDuration: (value: [number, number]) => void;
+};
+
+function FilterPage({
+  setGroundType,
+  setGrowthDuration,
+  setLightingDemand,
+  setNutrientDemand,
+  setPlantDuration,
+  setWaterDemand,
+}: FilterPageProps) {
+  const handleGroundType = (groundType: GroundTypeTranslated) => {
+    setGroundType(translateGroundTypeReverse(groundType));
+  };
+  const handleWaterDemand = (waterDemand: WaterDemandTranslated) => {
+    setWaterDemand(translateWaterDemandReverse(waterDemand));
+  };
+  const handleNutrientDemand = (nutrientDemand: NutrientDemandTranslated) => {
+    setNutrientDemand(translateNutrientDemandReverse(nutrientDemand));
+  };
+  const handleLightingDemand = (lightingDemand: LightingDemandTranslated) => {
+    setLightingDemand(translateLightingDemandReverse(lightingDemand));
+  };
   return (
     <>
       <div className="filterPage">
@@ -13,37 +55,52 @@ function FilterPage() {
       </div>
       <div>
         <DropDownFilter
-          topic={"Wasserbedarf "}
-          options={["Trocken", "Feucht", "Sehr Feucht"]}
+            topic={"Wasserbedarf "}
+            options={["Trocken", "Feucht", "Sehr feucht"]}
+            filterOnChange={handleWaterDemand}
+            hasEmptyOption
         />
         <DropDownFilter
-          topic={"Nährstoffbedarf "}
-          options={["Niedrig", "Mittel", "Hoch"]}
+            topic={"Nährstoffbedarf "}
+            options={["Niedrig", "Mittel", "Hoch"]}
+            filterOnChange={handleNutrientDemand}
+            hasEmptyOption
         />
         <DropDownFilter
-          topic={"Lichtbedarf "}
-          options={["Niedrig", "Mittel", "Hoch"]}
+            topic={"Lichtbedarf "}
+            options={["Niedrig", "Mittel", "Hoch"]}
+            filterOnChange={handleLightingDemand}
+            hasEmptyOption
         />
         <DropDownFilter
-          topic={"Bodentyp"}
-          options={["Leicht", "Mittel", "Schwer"]}
+            topic={"Bodentyp"}
+            options={["Leicht", "Mittel", "Schwer"]}
+            filterOnChange={handleGroundType}
+            hasEmptyOption
         />
       </div>
-      <SliderFilter topic={"Anbauphase"} min={1} max={52} />
-      <SliderFilter topic={"Erntezeitraum"} min={1} max={52} />
-      <SliderFilter topic={"Wachstumsdauer"} min={1} max={52} />{" "}
+      <SliderFilter
+        topic={"Anbauphase"}
+        min={1}
+        max={52}
+        filterOnChange={setPlantDuration}
+      />
+      <SliderFilter
+        topic={"Wachstumsdauer"}
+        min={1}
+        max={52}
+        filterOnChange={setGrowthDuration}
+      />{" "}
     </>
   );
 }
 
-
-
-
-function SliderFilter({ topic, min, max }: propsSliderFilter) {
+function SliderFilter({ topic, min, max, filterOnChange }: PropsSliderFilter) {
   const [range, setRange] = useState([min, max]);
 
   const handleRangeChange = (newRange: any) => {
     setRange(newRange);
+    filterOnChange!(newRange);
   };
 
   return (
@@ -62,6 +119,4 @@ function SliderFilter({ topic, min, max }: propsSliderFilter) {
   );
 }
 
-
 export default FilterPage;
-
diff --git a/growbros-frontend/src/components/Grandma.tsx b/growbros-frontend/src/components/Grandma.tsx
index 87f4a4f..1267a8c 100644
--- a/growbros-frontend/src/components/Grandma.tsx
+++ b/growbros-frontend/src/components/Grandma.tsx
@@ -1,5 +1,5 @@
 import 'reactjs-popup/dist/index.css';
-import {useEffect, useState} from "react";
+import React, {useEffect, useState} from "react";
 import {checkJwtStatus} from "../jwt/Cookies.ts";
 import "../stylesheets/GrandmaPopup.css"
 import {Link} from "react-router-dom";
@@ -12,12 +12,12 @@ function Grandma() {
     const [showText, setShowText] = useState<boolean>(false);
 
     const [growingTip, setGrowingTip] = useState<string>('');
-    const [plantsReadyToGrow, setPlantsReadyToGrow] = useState<string>('');
-    const [plantsReadyToWater, setPlantsReadyToWater] = useState<string>('');
-    const [plantsReadyToHarvest, setPlantsReadyToHarvest] = useState<string>('');
+    const [plantsReadyToGrow, setPlantsReadyToGrow] = useState<React.ReactNode>();
+    const [plantsReadyToWater, setPlantsReadyToWater] = useState<React.ReactNode>();
+    const [plantsReadyToHarvest, setPlantsReadyToHarvest] = useState<React.ReactNode>();
 
     const [error, setError] = useState<object>();
-    const [currentDisplay, setCurrentDisplay] = useState<string>(growingTip);
+    const [currentDisplay, setCurrentDisplay] = useState<string | React.ReactNode>(growingTip);
     const [displayIndex, setDisplayIndex] = useState<number>(0);
 
     const bc: IBackendConnector = useGrowbrosFetcher();
@@ -92,10 +92,20 @@ function Grandma() {
             const plants: Plant[] = response.value ?? [];
             if (plants.length === 0) {
                 console.log("no plants ready to grow");
-                setPlantsReadyToGrow("Füge Pflanzen die du gerne in der Zukunft einpflanzen möchtest deiner Wunschliste hinzu.")
+                setPlantsReadyToGrow(
+                    <>
+                        Im Moment sind keine deiner Pflanzen auf deiner Wunschliste bereit eingepflanzt zu werden.
+                        Falls du Pflanzen deiner Wunschliste hinzufügen möchtest, kannst du das <Link to="/suchen">hier</Link>.
+                    </>
+                );
             } else {
                 const plantNames = plants.map(plant => plant.name).join(', ');
-                setPlantsReadyToGrow("Folgende Pflanzen aus deiner Wunschliste wären bereit eingepflanzt zu werden:" + plantNames);
+                setPlantsReadyToGrow(
+                    <>
+                        Folgende Pflanzen aus deiner <Link to="/wunschlist">Wunschliste</Link> wären bereit eingepflanzt zu werden: <br /> <span>{plantNames}</span>
+                    </>
+               );
+
             }
         }
     }
@@ -108,10 +118,19 @@ function Grandma() {
             const plants: Plant[] = response.value ?? [];
             if(plants.length === 0) {
                 console.log("no plants ready to water");
-                setPlantsReadyToWater("Du hast noch keine Pflanzen in deinem Garten. Füge Pflanzen die du bereits eingepflanzt hast hinzu.")
+                setPlantsReadyToWater(
+                    <>
+                        Im Moment muss keine deiner Pflanzen im Garten gegossen werden.
+                        Schau doch mal <Link to="/suchen">hier</Link> welche Pflanzen du deinem Garten hinzufügen möchtest.
+                    </>
+                )
             } else {
                 const plantNames = plants.map(plant => plant.name).join(', ');
-                setPlantsReadyToWater("Folgende Pflanzen in deinem Garten müssen gegossen werden:" + plantNames);
+                setPlantsReadyToWater(
+                    <>
+                        Folgende Pflanzen in deinem <Link to="/garten">Garten</Link> müssen gegossen werden: <br /> <span>{plantNames}</span>
+                    </>
+                )
             }
         }
     }
@@ -124,10 +143,18 @@ function Grandma() {
             const plants: Plant[] = response.value ?? [];
             if(plants.length === 0) {
                 console.log("no plants ready to harvest");
-                setPlantsReadyToHarvest("Du hast noch keine Pflanzen in deinem Garten. Füge Pflanzen die du bereits eingepflanzt hast hinzu.")
+                setPlantsReadyToHarvest(
+                    <>
+                        Im Moment ist noch keine deiner Pflanzen bereit geerntet zu werden. Habe noch etwas Geduld.
+                    </>
+                )
             } else {
                 const plantNames = plants.map(plant => plant.name).join(', ');
-                setPlantsReadyToHarvest("Folgende Pflanzen in deinem Garten können geerntet werden:" + plantNames);
+                setPlantsReadyToHarvest(
+                    <>
+                        Schau doch mal in deinem <Link to="/garten">Garten</Link> nach. Folgende Pflanzen in deinem Garten sind eventuell bereit geerntet zu werden: <br /> <span>{plantNames}</span>
+                    </>
+                );
             }
         }
     }
diff --git a/growbros-frontend/src/components/PlantDetails.tsx b/growbros-frontend/src/components/PlantDetails.tsx
index cb56451..894ae27 100644
--- a/growbros-frontend/src/components/PlantDetails.tsx
+++ b/growbros-frontend/src/components/PlantDetails.tsx
@@ -1,10 +1,14 @@
 import "../stylesheets/PlantDetails.css";
 import "font-awesome/css/font-awesome.min.css";
-import {useEffect, useState} from "react";
+import AgricultureIcon from '@mui/icons-material/Agriculture';
+import HeartBrokenIcon from '@mui/icons-material/HeartBroken';
+import {ReactNode, useEffect, useState} from "react";
 import {Plant} from "../utils/schemas";
 import {useParams} from "react-router";
 import {IBackendConnector} from "../utils/IBackendConnector";
 import useGrowbrosFetcher from "../utils/useGrowbrosFetcher";
+import {FetchResult} from "../utils/FetchResult.ts";
+import StatusMessage from "./StatusMessage.tsx";
 
 function PlantDetails() {
     const {plantId} = useParams();
@@ -73,8 +77,18 @@ function PlantDetails() {
                                     margin: "0 0 40px 0",
                                 }}
                             >
-                                <ButtonAddToGarden plantId={plant.id}></ButtonAddToGarden>
-                                <ButtonAddToWishlist plantId={plant.id}></ButtonAddToWishlist>
+                                <ActionButton buttonTitle={"Add to garden"}
+                                              buttonContent={<i className="fa fa-leaf"></i>}
+                                              buttonAction={() => bc.addToGarden(plant.id)}/>
+                                <ActionButton buttonTitle={"Remove from garden"}
+                                              buttonContent={<AgricultureIcon/>}
+                                              buttonAction={() => bc.removeFromGarden(plant.id)}/>
+                                <ActionButton buttonTitle={"Add to wishlist"}
+                                              buttonContent={<i className="fa fa-heart"></i>}
+                                              buttonAction={() => bc.addToWishlist(plant.id)}/>
+                                <ActionButton buttonTitle={"Remove from wishlist"}
+                                              buttonContent={<HeartBrokenIcon sx={{fontSize: 19}}/>}
+                                              buttonAction={() => bc.removeFromWishlist(plant.id)}/>
                             </div>
                         </div>
                 }
@@ -83,59 +97,40 @@ function PlantDetails() {
     }
 }
 
-function ButtonAddToGarden({plantId}: any) {
-    const [status, setStatus] = useState<null | String>(null);
-
-    const bc: IBackendConnector = useGrowbrosFetcher();
-
-    const handleButtonClick = async () => {
-        await bc.addToGarden(plantId);
-    };
-
-    return (
-        <>
-            {status && (
-                <div
-                    className={`status-message ${
-                        status.includes("erfolgreich") ? "success-message" : "error-message"
-                    }`}
-                >
-                    {status}
-                </div>
-            )}
-            <button title="Zum Garten hinzufügen" onClick={handleButtonClick}>
-                <i className="fa fa-leaf"></i>
-            </button>
-        </>
-    );
+type ActionButtonProps = {
+    buttonTitle: string,
+    buttonContent: ReactNode,
+    buttonAction: () => Promise<FetchResult<unknown>>;
 }
 
-//TODO status+error handling
-//TODO css für status message
-function ButtonAddToWishlist({plantId}: any) {
-    const [status, setStatus] = useState<null | String>(null);
+function ActionButton({buttonContent, buttonTitle, buttonAction}: ActionButtonProps) {
+    const [status, setStatus] = useState<"error" | "success">();
+    const message = () => {
+        if (status === "error") {
+            return "Something went wrong..."
+        } else {
+            return "Success!"
+        }
+    };
 
-    const bc: IBackendConnector = useGrowbrosFetcher();
+    const statusVisibleFor = 3000;
 
     const handleButtonClick = async () => {
-        await bc.addToWishlist(plantId);
+        const result = await buttonAction();
+        if (result.err) {
+            setStatus("error");
+        } else {
+            setStatus("success")
+        }
+        setTimeout(() => setStatus(undefined), statusVisibleFor);
     };
 
     return (
         <>
-            {status && (
-                <div
-                    className={`status-message ${
-                        status.includes("erfolgreich") ? "success-message" : "error-message"
-                    }`}
-                >
-                    {" "}
-                    {status}
-                </div>
-            )}
-            <button title="Zur Wunschliste hinzufügen" onClick={handleButtonClick}>
-                <i className="fa fa-heart"></i>
+            <button title={buttonTitle} onClick={handleButtonClick}>
+                {buttonContent}
             </button>
+            {status && <StatusMessage message={message()} status={status} visibleFor={3000}/>}
         </>
     );
 }
diff --git a/growbros-frontend/src/components/StatusMessage.tsx b/growbros-frontend/src/components/StatusMessage.tsx
new file mode 100644
index 0000000..13b79e0
--- /dev/null
+++ b/growbros-frontend/src/components/StatusMessage.tsx
@@ -0,0 +1,30 @@
+import {useEffect, useState} from "react";
+import "../stylesheets/StatusMessage.css"
+
+type StatusMessageProps = {
+    status: "success" | "error",
+    visibleFor: number,
+    message: string
+}
+
+function StatusMessage({message, status, visibleFor}: StatusMessageProps) {
+    const [visible, setVisible] = useState(true);
+
+    useEffect(() => {
+        const timer = setTimeout(() => {
+            setVisible(false);
+        }, visibleFor);
+
+        return () => {
+            clearTimeout(timer);
+        };
+    }, [visibleFor]);
+
+    return visible ? (
+        <div className={`status-message ${status === "success" ? "success-message" : "error-message"}`}>
+            {message}
+        </div>
+    ) : null;
+}
+
+export default StatusMessage;
diff --git a/growbros-frontend/src/index.css b/growbros-frontend/src/index.css
index 37f5c1d..5d55461 100644
--- a/growbros-frontend/src/index.css
+++ b/growbros-frontend/src/index.css
@@ -3,7 +3,6 @@
     line-height: 1.5;
     font-weight: 400;
 
-    color-scheme: light dark;
     color: rgba(255, 255, 255, 0.87);
     background-color: #242424;
 
@@ -66,3 +65,14 @@ button:focus-visible {
         background-color: #f9f9f9;
     }
 }
+
+@media (prefers-color-scheme: dark) {
+    :root {
+        color: #213547;
+        background-color: #ffffff;
+    }
+
+    button, input {
+        background-color: #f9f9f9;
+    }
+}
diff --git a/growbros-frontend/src/pages/Garten.tsx b/growbros-frontend/src/pages/Garten.tsx
index 3c083a1..492d0be 100644
--- a/growbros-frontend/src/pages/Garten.tsx
+++ b/growbros-frontend/src/pages/Garten.tsx
@@ -6,37 +6,76 @@ import {IBackendConnector} from "../utils/IBackendConnector";
 import PlantsOverview from "../components/PlantsOverview";
 
 function Garten() {
-  const [plants, setPlantsInGarden] = useState<Plant[]>([]);
-  const [error, setError] = useState({});
-  const bc: IBackendConnector = useGrowbrosFetcher();
-
-  useEffect(() => {
-    (async () => {
-      const result = await bc.getGardenEntries();
-      if (result.err) {
-        setError(result.err);
-      } else {
-        setPlantsInGarden(result.value!);
-      }
-    })();
-  }, []);
-
-  return (
-      <>
-          <div style={{padding: "20px"}}>
-              <h2>Dein Garten</h2>
-              <DropDownFilter
-                  topic={"Sortierung der Pflanzen im Garten"}
-                  options={[
-                      "neueste zuerst",
-                      "als nächstes anpflanzbar",
-                      "als nächstes erntbar",
-                  ]}
-              />
-          </div>
-      <PlantsOverview plants={plants} />
-      </>
-  );
+    const [plants, setPlantsInGarden] = useState<Plant[]>([]);
+    const [error, setError] = useState<object>();
+    const [currentSort, setCurrentSort] = useState<string>("")
+
+    const bc: IBackendConnector = useGrowbrosFetcher();
+
+    useEffect(() => {
+        (async () => {
+            const result = await bc.getGardenEntries(currentSort);
+            if (result.err) {
+                setError(result.err);
+            } else {
+                setPlantsInGarden(result.value!);
+            }
+        })();
+    }, [currentSort]);
+
+
+    const handleClearGarden = async () => {
+        if (confirm("Möchtest du wirklich alle Pflanzen aus deinem Garten entfernen?" + "\n" +
+            "Diese Aktion kann nicht rückgängig gemacht werden.")) {
+            const result = await bc.clearGarden();
+            if (result.err) {
+                setError(result.err);
+            } else {
+                setError(undefined);
+                setPlantsInGarden([]);
+            }
+        }
+    }
+
+    const handleSortOptions = async (selectedOption: string) => {
+        switch (selectedOption) {
+            case "neueste zuerst":
+                setCurrentSort("createdAt");
+                break;
+            case "als nächstes anpflanzbar":
+                setCurrentSort("plantDate");
+                break;
+            case "als nächstes erntbar":
+                setCurrentSort("harvestDate");
+                break;
+            case "alphabetisch sortiert":
+            default:
+                setCurrentSort("");
+        }
+    }
+
+    return (
+        <>
+            <div style={{padding: "20px"}}>
+                <h2>Dein Garten</h2>
+                <DropDownFilter
+                    filterOnChange={handleSortOptions}
+                    topic={"Sortierung der Pflanzen im Garten"}
+                    options={[
+                        "alphabetisch sortiert",
+                        "neueste zuerst",
+                        "als nächstes anpflanzbar",
+                        "als nächstes erntbar",
+                    ]}
+                />
+                <button onClick={handleClearGarden}>Garten leeren</button>
+            </div>
+            {error && (
+                <div style={{padding: "20px"}}>Es ist ein Fehler aufgetreten...</div>
+            )}
+            <PlantsOverview plants={plants}/>
+        </>
+    );
 }
 
 export default Garten;
diff --git a/growbros-frontend/src/pages/Suche.tsx b/growbros-frontend/src/pages/Suche.tsx
index 99c843a..292261c 100644
--- a/growbros-frontend/src/pages/Suche.tsx
+++ b/growbros-frontend/src/pages/Suche.tsx
@@ -1,68 +1,147 @@
 import "font-awesome/css/font-awesome.min.css";
 import "../stylesheets/Suche.css";
 import PlantsOverview from "../components/PlantsOverview";
-import { useState, useEffect } from "react";
+import {useEffect, useState} from "react";
 import FilterPage from "../components/FilterPage";
-import { Plant } from "../utils/schemas";
-import { IBackendConnector } from "../utils/IBackendConnector";
+import {GroundType, LightingDemand, NutrientDemand, Plant, WaterDemand,} from "../utils/schemas";
+import {IBackendConnector} from "../utils/IBackendConnector";
 import useGrowbrosFetcher from "../utils/useGrowbrosFetcher";
 
+type SearchBarProps = {
+    setError: (value: any) => void;
+    setPlants: (value: Plant[]) => void;
+};
+
 function Suche() {
-  const [randomPlants, setRandomPlants] = useState<Plant[]>([]);
-  const [error, setError] = useState({});
-  const randomPlantsCount: number = 100;
+    const [plants, setPlants] = useState<Plant[]>([]);
+    const [error, setError] = useState({});
+    const randomPlantsCount: number = 100;
 
-  const bc: IBackendConnector = useGrowbrosFetcher();
+    const bc: IBackendConnector = useGrowbrosFetcher();
 
-  useEffect(() => {
-    (async () => {
-      const result = await bc.getRandomPlants(randomPlantsCount);
-      if (result.err) {
-        setError(result.err);
-      } else {
-        setRandomPlants(result.value!);
-      }
-    })();
-  }, []);
+    useEffect(() => {
+        (async () => {
+            const result = await bc.getRandomPlants(randomPlantsCount);
+            if (result.err) {
+                setError(result.err);
+            } else {
+                setPlants(result.value!);
+            }
+        })();
+    }, []);
 
-  //TODO error handling
-  return (
-    <>
-      <SearchBar />
-      <div>
-        <PlantsOverview plants={randomPlants} />
-      </div>
-    </>
-  );
+    return (
+        <>
+            <SearchBar setError={setError} setPlants={setPlants}/>
+            <div>
+                {plants.length === 0 && (
+                    <div>
+                        Es wurden keine Pflanzen passend zu deiner Suchanfrage gefunden
+                    </div>
+                )}
+                {
+                    error && (
+                        <div>
+                            Es ist ein Fehler aufgetreten.
+                        </div>
+                    )
+                }
+                <PlantsOverview plants={plants}/>
+            </div>
+        </>
+    );
 }
 
-function SearchBar() {
-  const [isComponentVisible, setComponentVisible] = useState(false);
+function SearchBar({setPlants, setError}: SearchBarProps) {
+    const [isComponentVisible, setComponentVisible] = useState(false);
+    const [searchTerm, setSearchTerm] = useState<string>("");
+    const [waterDemand, setWaterDemand] = useState<WaterDemand>();
+    const [nutrientDemand, setNutrientDemand] = useState<NutrientDemand>();
+    const [lightingDemand, setLightingDemand] = useState<LightingDemand>();
+    const [groundType, setGroundType] = useState<GroundType>();
+    const [plantDuration, setPlantDuration] = useState<[number, number]>();
+    const [growthDuration, setGrowthDuration] = useState<[number, number]>();
+    const bc: IBackendConnector = useGrowbrosFetcher();
+
+    const handleSearchChange = (event: any) => {
+        setSearchTerm(event.target.value);
+    };
+    const loadComponent = () => {
+        setComponentVisible(!isComponentVisible);
+    };
+
+    const handleSearchRequestSubmit = async () => {
+        let result;
+
+        if (isSearchSetToDefault()) {
+            result = await bc.getRandomPlants(100);
+        } else {
+            result = await bc.searchPlants({
+                searchTerm,
+                waterDemand,
+                nutrientDemand,
+                lightingDemand,
+                groundType,
+                growthDurationMin: growthDuration && growthDuration[0],
+                growthDurationMax: growthDuration && growthDuration[1],
+                plantWeekStart: plantDuration && plantDuration[0],
+                plantWeekEnd: plantDuration && plantDuration[1],
+            });
+        }
+
+        if (result.err) {
+            setError(result.err);
+            console.log(result.err);
+        } else {
+            console.log(result.value);
+            setPlants(result.value!);
+        }
+    };
 
-  const loadComponent = () => {
-    setComponentVisible(!isComponentVisible);
-  };
+    const isSearchSetToDefault = () => {
+        return (!searchTerm || searchTerm.trim() === "") && !waterDemand && !lightingDemand && !nutrientDemand && !groundType
+            && (!plantDuration || plantDuration[0] === 1 && plantDuration[1] === 52)
+            && (!growthDuration || growthDuration[0] === 1 && growthDuration[1] === 52)
+    }
 
-  return (
-    <>
-      <div className="searchBar">
-        <h2>Suche nach einer Pflanze</h2>
-        <p>
-          und füge diese dann zu deinem Garten oder zu deiner Wunschliste hinzu
-        </p>
-        <div className="searchFilter">
-          <input type="text" placeholder="Pflanze suchen..." />
-          <button>
-            <i className="fa fa-search"></i>
-          </button>
-          <button onClick={loadComponent} className="filter">
-            <i className="fa fa-filter" />
-          </button>
-        </div>
-        {isComponentVisible && <FilterPage />}
-      </div>
-    </>
-  );
+    return (
+        <>
+            <div className="searchBar">
+                <h2>Suche nach einer Pflanze</h2>
+                <p>
+                    und füge diese dann zu deinem Garten oder zu deiner Wunschliste hinzu
+                </p>
+                <div className="searchFilter">
+                    <input
+                        onChange={handleSearchChange}
+                        value={searchTerm}
+                        type="text"
+                        placeholder="Pflanze suchen..."
+                    />
+                    <button onClick={loadComponent} className="filter">
+                        <i className="fa fa-filter"/>
+                    </button>
+                    <button onClick={handleSearchRequestSubmit}>
+                        <i className="fa fa-search"></i>
+                    </button>
+                </div>
+                <div
+                    style={
+                        isComponentVisible ? {display: "block"} : {display: "none"}
+                    }
+                >
+                    <FilterPage
+                        setGroundType={setGroundType}
+                        setGrowthDuration={setGrowthDuration}
+                        setLightingDemand={setLightingDemand}
+                        setNutrientDemand={setNutrientDemand}
+                        setPlantDuration={setPlantDuration}
+                        setWaterDemand={setWaterDemand}
+                    />
+                </div>
+            </div>
+        </>
+    );
 }
 
 export default Suche;
diff --git a/growbros-frontend/src/pages/Wunschliste.tsx b/growbros-frontend/src/pages/Wunschliste.tsx
index 2a69cac..21fb741 100644
--- a/growbros-frontend/src/pages/Wunschliste.tsx
+++ b/growbros-frontend/src/pages/Wunschliste.tsx
@@ -6,57 +6,71 @@ import PlantsOverview from "../components/PlantsOverview";
 import DropDownFilter from "../components/DropDownFilter";
 
 function Wunschliste() {
-  const [plants, setPlantsInWishlist] = useState<Plant[]>([]);
-  console.log(plants);
-  const [error, setError] = useState({});
-  const [currentSort, setCurrentSort] = useState<string>("");
+    const [plants, setPlantsInWishlist] = useState<Plant[]>([]);
+    console.log(plants);
+    const [error, setError] = useState({});
+    const [currentSort, setCurrentSort] = useState<string>("")
 
-  const bc: IBackendConnector = useGrowbrosFetcher();
+    const bc: IBackendConnector = useGrowbrosFetcher();
 
-  useEffect(() => {
-    (async () => {
-      const result = await bc.getWishlistEntries(currentSort);
-      if (result.err) {
-        setError(result.err);
-      } else {
-        setPlantsInWishlist(result.value!);
-      }
-    })();
-  }, [currentSort]);
+    useEffect(() => {
+        (async () => {
+            const result = await bc.getWishlistEntries(currentSort);
+            if (result.err) {
+                setError(result.err);
+            } else {
+                setPlantsInWishlist(result.value!);
+            }
+        })();
+    }, [currentSort]);
 
-  const handleSortOptions = async (selectedOption: string) => {
-    switch (selectedOption) {
-      case "neueste zuerst":
-        setCurrentSort("createdAt");
-        break;
-      case "als nächstes anpflanzbar":
-        setCurrentSort("plantDate");
-        break;
-      case "als nächstes erntbar":
-        setCurrentSort("currentPlantable");
-        break;
-      default:
-        setCurrentSort("");
+    const handleClearWishList = async () => {
+        if (confirm("Möchtest du wirklich alle Pflanzen aus deiner Wunschliste entfernen?" + "\n" +
+            "Diese Aktion kann nicht rückgängig gemacht werden.")) {
+                const result = await bc.clearWishlist();
+                if (result.err) {
+                    setError(result.err);
+                } else {
+                    setPlantsInWishlist([]);
+                }
+            }
     }
-  };
 
-  return (
-    <>
-      <div style={{padding: "20px"}}>
-        <h2>Deine Wunschliste</h2>
-        <DropDownFilter
-            filterOnChange={handleSortOptions}
-            options={[
-              "neueste zuerst",
-              "als nächstes anpflanzbar",
-              "gerade anpflanzbar",
-            ]}
-            topic={"Sortierung der Pflanzen in der Wunschliste"}
-        />
-      </div>
-      <PlantsOverview plants={plants} />
-    </>
-  );
-}
+    const handleSortOptions = async (selectedOption: string) => {
+        switch (selectedOption) {
+            case "neueste zuerst":
+                setCurrentSort("createdAt");
+                break;
+            case "als nächstes anpflanzbar":
+                setCurrentSort("plantDate");
+                break;
+            case "gerade anpflanzbar":
+                setCurrentSort("currentPlantable");
+                break;
+            case "alphabetisch sortiert":
+            default:
+                setCurrentSort("");
+        }
+    };
 
-export default Wunschliste;
+    return (
+        <>
+            <div style={{padding: "20px"}}>
+                <h2>Deine Wunschliste</h2>
+                <DropDownFilter
+                    filterOnChange={handleSortOptions}
+                    topic={"Sortierung der Pflanzen in der Wunschliste"}
+                    options={[
+                        "alphabetisch sortiert",
+                        "neueste zuerst",
+                        "als nächstes anpflanzbar",
+                        "gerade anpflanzbar",
+                    ]}
+                />
+                <button onClick={handleClearWishList}>Wunschliste leeren</button>
+            </div>
+            <PlantsOverview plants={plants}/>
+        </>
+    );
+}
+export default Wunschliste;
\ No newline at end of file
diff --git a/growbros-frontend/src/stylesheets/Home.css b/growbros-frontend/src/stylesheets/Home.css
index c7b6e9d..78cea5d 100644
--- a/growbros-frontend/src/stylesheets/Home.css
+++ b/growbros-frontend/src/stylesheets/Home.css
@@ -15,7 +15,7 @@
     color: #4d5927;
 }
 .descriptionAside h1{
-    font-family: Garamond;
+    font-family: Garamond, sans-serif;
 }
 .descriptionAside h2 {
     padding-top: 5px;
@@ -23,7 +23,7 @@
 
 .descriptionAside p {
     padding-top: 20px;
-    font-family: Century Gothic;
+    font-family: Century Gothic, sans-serif;
 }
 
 
@@ -36,7 +36,7 @@
     padding: 10%;
     font-size: 1.5rem;
     font-weight: 500;
-    font-family: Century Gothic;
+    font-family: Century Gothic, sans-serif;
 }
 
 .smallDiv {
@@ -46,7 +46,7 @@
 
 .smallDiv p {
     padding-top: 10px;
-    font-family: Century Gothic;
+    font-family: Century Gothic, sans-serif;
     font-size: 1.25rem;
 }
 
diff --git a/growbros-frontend/src/stylesheets/Navbar.css b/growbros-frontend/src/stylesheets/Navbar.css
index c38cb58..f2c831f 100644
--- a/growbros-frontend/src/stylesheets/Navbar.css
+++ b/growbros-frontend/src/stylesheets/Navbar.css
@@ -20,7 +20,7 @@ ul {
 }
 
 nav .title {
-    font-family: Garamond;
+    font-family: Garamond, sans-serif;
     color: rgb(0, 0, 0);
     font-size: 3rem;
     font-weight: bold;
diff --git a/growbros-frontend/src/stylesheets/RegisterAndLogin.css b/growbros-frontend/src/stylesheets/RegisterAndLogin.css
index 95ddc19..7c632cd 100644
--- a/growbros-frontend/src/stylesheets/RegisterAndLogin.css
+++ b/growbros-frontend/src/stylesheets/RegisterAndLogin.css
@@ -22,7 +22,6 @@ form {
     width: 60%;
     background-color: #f9f9f9;
     border-radius: 5px;
-    color: #333;
 }
 
 .input:hover{
@@ -35,7 +34,6 @@ form {
     background-color: #f9f9f9;
     font-size: 1em;
     font-weight: bold;
-
 }
 
 .submitButton:hover {
diff --git a/growbros-frontend/src/stylesheets/StatusMessage.css b/growbros-frontend/src/stylesheets/StatusMessage.css
new file mode 100644
index 0000000..5798c65
--- /dev/null
+++ b/growbros-frontend/src/stylesheets/StatusMessage.css
@@ -0,0 +1,22 @@
+.status-message {
+    text-align: center;
+    position: fixed;
+    bottom: 100px;
+    left: 50%;
+    transform: translateX(-50%);
+    z-index: 9999;
+    padding: 10px 20px;
+    border-radius: 0.5rem;
+}
+
+.success-message {
+    background: #6a945c;
+    color: #e5ffca;
+    border: 2px solid #406240;
+}
+
+.error-message {
+    background: #622424;
+    color: #ffabab;
+    border: 2px solid #460808;
+}
diff --git a/growbros-frontend/src/utils/BackendConnectorImpl.ts b/growbros-frontend/src/utils/BackendConnectorImpl.ts
index 7748367..74a3d04 100644
--- a/growbros-frontend/src/utils/BackendConnectorImpl.ts
+++ b/growbros-frontend/src/utils/BackendConnectorImpl.ts
@@ -36,9 +36,13 @@ export class BackendConnectorImpl implements IBackendConnector {
     async searchPlants(search: SearchRequest): Promise<FetchResult<Plant[]>> {
         let result: FetchResult<Plant[]>;
         try {
-            const searchParams = new URLSearchParams(
-                Object.entries(search)
-                    .map(([key, value]) => [key, value as string]));
+            const searchParams = new URLSearchParams()
+            Object.entries(search)
+            .forEach(([key, value]) => {
+              if (value !== undefined && value !== "") {
+                searchParams.append(key, String(value));
+              }
+            }); 
             const response = await this.makeFetchWithAuth("/plants/search?" + searchParams);
             const json = await response.json();
             result = this.parsePlants(json);
@@ -135,12 +139,12 @@ export class BackendConnectorImpl implements IBackendConnector {
         return result;
     }
 
-    async removeEntryFromGarden(entryId: number): Promise<FetchResult<void>> {
+    async removeFromGarden(plantId: number): Promise<FetchResult<void>> {
         let result: FetchResult<void> = {value: undefined};
         try {
-            await this.makeFetchWithAuthAndOptions("/garden/remove/" + entryId, {method: "DELETE"});
+            await this.makeFetchWithAuthAndOptions("/garden/remove/" + plantId, {method: "DELETE"});
         } catch (e) {
-            console.error("An error occurred while removing garden entry with ID", entryId);
+            console.error("An error occurred while removing garden entry with plantID", plantId);
             console.error(e);
             result = {err: e};
         }
@@ -261,12 +265,12 @@ export class BackendConnectorImpl implements IBackendConnector {
         return result;
     }
 
-    async removeFromWishlist(entryId: number): Promise<FetchResult<void>> {
+    async removeFromWishlist(plantId: number): Promise<FetchResult<void>> {
         let result: FetchResult<void> = {value: undefined};
         try {
-            await this.makeFetchWithAuthAndOptions("/wishlist/remove/" + entryId, {method: "DELETE"});
+            await this.makeFetchWithAuthAndOptions("/wishlist/remove/" + plantId, {method: "DELETE"});
         } catch (e) {
-            console.error("An error occurred while removing entry from wishlist with id", entryId)
+            console.error("An error occurred while removing entry from wishlist with plantID", plantId)
             console.error(e);
             result = {err: e};
         }
@@ -318,6 +322,7 @@ export class BackendConnectorImpl implements IBackendConnector {
                 plants.push(PlantSchema.parse(p))
             } catch (e) {
                 if (e instanceof ZodError) {
+                    console.log(result.err)
                     result = {...result, err: "One or more plants could not be parsed correctly."}
                 }
             }
diff --git a/growbros-frontend/src/utils/IBackendConnector.ts b/growbros-frontend/src/utils/IBackendConnector.ts
index e8d8176..91cf9bc 100644
--- a/growbros-frontend/src/utils/IBackendConnector.ts
+++ b/growbros-frontend/src/utils/IBackendConnector.ts
@@ -16,7 +16,7 @@ export interface IBackendConnector {
 
     getGardenSize(): Promise<FetchResult<number>>;
 
-    removeEntryFromGarden(entryId: number): Promise<FetchResult<void>>;
+    removeFromGarden(plantId: number): Promise<FetchResult<void>>;
 
     clearGarden(): Promise<FetchResult<number>>;
 
@@ -26,7 +26,7 @@ export interface IBackendConnector {
 
     getWishlistSize(): Promise<FetchResult<number>>;
 
-    removeFromWishlist(entryId: number): Promise<FetchResult<void>>
+    removeFromWishlist(plantId: number): Promise<FetchResult<void>>
 
     clearWishlist(): Promise<FetchResult<number>>;
 
diff --git a/growbros-frontend/src/utils/commonTypes.d.ts b/growbros-frontend/src/utils/commonTypes.d.ts
index db20786..02091e4 100644
--- a/growbros-frontend/src/utils/commonTypes.d.ts
+++ b/growbros-frontend/src/utils/commonTypes.d.ts
@@ -1,13 +1,17 @@
-export type propsDropDownFilter = {
-    options: Array<string>;
+export type PropsDropDownFilter<T> = {
+    options: T[];
     topic: string;
+    filterOnChange: (selectedOption: T) => void;
+    hasEmptyOption?: boolean
 };
 
-
-export type propsSliderFilter = {
+export type PropsSliderFilter = {
     topic: string;
     min: number;
     max: number;
+    filterOnChange: (selectedRange: [number,number])=> void
 };
 
+export type DropdownOption = string | number | readonly string[]
+
 export type HttpMethod = "GET" | "POST" | "DELETE" | "PUT" | "PATCH";
diff --git a/growbros-frontend/src/utils/schemas.ts b/growbros-frontend/src/utils/schemas.ts
index 48fec4a..73f7cf2 100644
--- a/growbros-frontend/src/utils/schemas.ts
+++ b/growbros-frontend/src/utils/schemas.ts
@@ -6,6 +6,16 @@ const lightingDemand=z.enum(["LOW","MEDIUM","HIGH"])
 const nutrientDemand=z.enum(["LOW","MEDIUM","HIGH"])
 const weekNumber= z.number().int().min(0).max(51)
 
+export type WaterDemand = z.infer<typeof waterDemand>;
+export type GroundType= z.infer<typeof groundType>
+export type LightingDemand= z.infer<typeof lightingDemand>
+export type NutrientDemand= z.infer<typeof nutrientDemand>
+
+export type NutrientDemandTranslated = "Niedrig" | "Mittel" | "Hoch";
+export type WaterDemandTranslated = "Trocken" | "Feucht" | "Sehr feucht";
+export type LightingDemandTranslated = "Niedrig" | "Mittel" | "Hoch";
+export type GroundTypeTranslated = "Leicht" | "Mittel" | "Schwer";
+
 export const PlantSchema = z.object({
     id: z.number(),
     name: z.string(),
@@ -21,47 +31,88 @@ export const PlantSchema = z.object({
     waterDemand: waterDemand.transform(s=>translateWaterDemand(s)).nullable(),
     lightingDemand: lightingDemand.transform(s=>translateLightingDemand(s)).nullable(),
     nutrientDemand: nutrientDemand.transform(s=>translateNutrientDemand(s)).nullable(),
-    imageUrl: z.string().optional()
+    imageUrl: z.string().optional().nullable()
   });
   
   export type Plant = z.infer<typeof PlantSchema>;
 
-  function translateLightingDemand(key: "LOW"|"MEDIUM"|"HIGH"){
+  
+  
+function translateGroundType(key: GroundType) { 
     const map = {
-        LOW: "Niedrig",
+        HEAVY: "Schwer",
         MEDIUM: "Mittel",
-        HIGH: "Hoch"
-    } 
+        LIGHT: "Leicht"
+    } satisfies Record<GroundType, GroundTypeTranslated>
     return map[key];
   }
 
-  function translateGroundType(key: "HEAVY" | "MEDIUM" | "LIGHT") {
+export function translateGroundTypeReverse(key: GroundTypeTranslated){
     const map = {
-        HEAVY: "Schwer",
+        Schwer: "HEAVY",
+        Mittel: "MEDIUM",
+        Leicht: "LIGHT"
+    } satisfies Record<GroundTypeTranslated, GroundType>
+    return map[key]
+}
+
+function translateLightingDemand(key: LightingDemand){
+    const map = {
+        LOW: "Niedrig",
         MEDIUM: "Mittel",
-        LIGHT: "Leicht"
-    } 
+        HIGH: "Hoch"
+    } satisfies Record<LightingDemand, LightingDemandTranslated>
     return map[key];
   }
 
-  function translateWaterDemand(key: "DRY"|"WET"|"VERY_WET"){
+ export function translateLightingDemandReverse(key: LightingDemandTranslated){
+    const map = {
+        Niedrig :"LOW",
+        Mittel : "MEDIUM",
+        Hoch: "HIGH"
+    }satisfies Record<LightingDemandTranslated,LightingDemand>
+    return map[key]
+  }
+  
+
+  function translateWaterDemand(key: WaterDemand){
     const map = {
         DRY: "Trocken",
         WET: "Feucht",
         VERY_WET: "Sehr feucht"
-    } 
+    } satisfies Record<WaterDemand, WaterDemandTranslated> 
+    return map[key];
+  }
+
+  export function translateWaterDemandReverse(key: WaterDemandTranslated){
+    const map = {
+        Trocken: "DRY",
+        Feucht: "WET",
+        "Sehr feucht" :"VERY_WET"
+    } satisfies Record<WaterDemandTranslated, WaterDemand> 
     return map[key];
   }
 
-  function translateNutrientDemand(key: "LOW"|"MEDIUM"|"HIGH"){
+
+
+function translateNutrientDemand(key: NutrientDemand){
     const map = {
         LOW: "Niedrig",
         MEDIUM: "Mittel",
         HIGH: "Hoch"
-    } 
+    } satisfies Record<NutrientDemand, NutrientDemandTranslated>
     return map[key];
   }
 
+  export function translateNutrientDemandReverse(key: "Niedrig" | "Mittel" |"Hoch"){
+    const map = {
+        Niedrig :"LOW",
+        Mittel : "MEDIUM",
+        Hoch: "HIGH"
+    }satisfies Record<NutrientDemandTranslated, NutrientDemand>
+    return map[key]
+  }
+
 export const SearchRequestSchema = z.object({
     searchTerm: z.string().optional(),
     waterDemand: waterDemand.optional(),
diff --git a/src/main/java/hdm/mi/growbros/controllers/GardenController.java b/src/main/java/hdm/mi/growbros/controllers/GardenController.java
index db636f8..3feeca0 100644
--- a/src/main/java/hdm/mi/growbros/controllers/GardenController.java
+++ b/src/main/java/hdm/mi/growbros/controllers/GardenController.java
@@ -45,12 +45,12 @@ public class GardenController {
         return ResponseEntity.status(201).body(plantAdded);
     }
 
-    @DeleteMapping("/remove/{entryId}")
+    @DeleteMapping("/remove/{plantId}")
     public ResponseEntity<Void> removePlantFromGarden(
-            @PathVariable Long entryId,
+            @PathVariable Long plantId,
             @AuthenticationPrincipal User user
     ) {
-        gardenService.removeFromGarden(entryId, user);
+        gardenService.removeFromGarden(plantId, user);
         return ResponseEntity.status(204).build();
     }
 
diff --git a/src/main/java/hdm/mi/growbros/controllers/WishListController.java b/src/main/java/hdm/mi/growbros/controllers/WishListController.java
index 54f4066..54b9c78 100644
--- a/src/main/java/hdm/mi/growbros/controllers/WishListController.java
+++ b/src/main/java/hdm/mi/growbros/controllers/WishListController.java
@@ -39,11 +39,11 @@ public class WishListController {
         return ResponseEntity.status(201).build();
     }
 
-    @DeleteMapping("/remove/{entryId}")
+    @DeleteMapping("/remove/{plantId}")
     @ResponseStatus(HttpStatus.NO_CONTENT)
-    public void removePlantFromWishlist(@PathVariable Long entryId,
+    public void removePlantFromWishlist(@PathVariable Long plantId,
                                         @AuthenticationPrincipal User user) {
-        wishListService.removeFromWishList(entryId, user);
+        wishListService.removeFromWishList(plantId, user);
     }
 
     @DeleteMapping("/remove/all")
diff --git a/src/main/java/hdm/mi/growbros/models/WishListEntry.java b/src/main/java/hdm/mi/growbros/models/WishListEntry.java
index b7f04c2..a8254b6 100644
--- a/src/main/java/hdm/mi/growbros/models/WishListEntry.java
+++ b/src/main/java/hdm/mi/growbros/models/WishListEntry.java
@@ -18,17 +18,17 @@ import java.util.Date;
 @NoArgsConstructor
 public class WishListEntry {
 
-    @ManyToOne(optional = false)
-    @CreatedBy
-    private User user;
+    @Id
+    @GeneratedValue
+    private Long id;
 
     @ManyToOne(optional = false)
     private Plant plant;
 
+    @ManyToOne(optional = false)
+    @CreatedBy
+    private User user;
+
     @CreatedDate
     private Date createdAt;
-
-    @Id
-    @GeneratedValue
-    private Long id;
 }
\ No newline at end of file
diff --git a/src/main/java/hdm/mi/growbros/repositories/GardenRepository.java b/src/main/java/hdm/mi/growbros/repositories/GardenRepository.java
index 9395c7e..8e6dee7 100644
--- a/src/main/java/hdm/mi/growbros/repositories/GardenRepository.java
+++ b/src/main/java/hdm/mi/growbros/repositories/GardenRepository.java
@@ -51,4 +51,11 @@ public interface GardenRepository extends JpaRepository<GardenEntry, Long> {
                 ASC
             """)
     List<GardenEntry> findAllByNearestPlantingWeek(@Param("user") User user, @Param("week") int currentWeek);
+
+    @Query("""
+                SELECT ge.id FROM GardenEntry ge
+                WHERE ge.user = :user
+                AND ge.plant.id = :plantId
+            """)
+    Long findEntryIdByUserAndPlantId(@Param("user") User user, @Param("plantId") Long plantId);
 }
diff --git a/src/main/java/hdm/mi/growbros/repositories/WishListRepository.java b/src/main/java/hdm/mi/growbros/repositories/WishListRepository.java
index 683844f..206b4fa 100644
--- a/src/main/java/hdm/mi/growbros/repositories/WishListRepository.java
+++ b/src/main/java/hdm/mi/growbros/repositories/WishListRepository.java
@@ -47,6 +47,20 @@ public interface WishListRepository extends JpaRepository<WishListEntry, Long> {
             """)
     List<WishListEntry> findByCurrentPlantingWeek(@Param("user") User user, @Param("week") int currentWeek);
 
+    @Query("""
+                SELECT ge.plant FROM WishListEntry ge
+                WHERE ge.user = :user
+                AND ge.plant.id = :plantId
+            """)
+    Plant findPlantByUserAndPlantId(@Param("user") User user, @Param("plantId") Long plantId);
+
+    @Query("""
+                SELECT ge.id FROM WishListEntry ge
+                WHERE ge.user = :user
+                AND ge.plant.id = :plantId
+            """)
+    Long findEntryIdByUserAndPlantId(@Param("user") User user, @Param("plantId") Long plantId);
+
     boolean existsByUserAndPlant(User user, Plant plant);
 
     int deleteAllByPlant_Id(long id);
diff --git a/src/main/java/hdm/mi/growbros/service/GardenService.java b/src/main/java/hdm/mi/growbros/service/GardenService.java
index b851da7..e04e5ec 100644
--- a/src/main/java/hdm/mi/growbros/service/GardenService.java
+++ b/src/main/java/hdm/mi/growbros/service/GardenService.java
@@ -44,7 +44,8 @@ public class GardenService {
     }
 
     @Transactional
-    public void removeFromGarden(Long entryId, User authenticatedUser) {
+    public void removeFromGarden(Long plantId, User authenticatedUser) {
+        Long entryId = gardenRepository.findEntryIdByUserAndPlantId(authenticatedUser, plantId);
         gardenRepository.deleteByIdAndUser(entryId, authenticatedUser);
     }
 
diff --git a/src/main/java/hdm/mi/growbros/service/GrandmaService.java b/src/main/java/hdm/mi/growbros/service/GrandmaService.java
index 5b7fc89..adc0183 100644
--- a/src/main/java/hdm/mi/growbros/service/GrandmaService.java
+++ b/src/main/java/hdm/mi/growbros/service/GrandmaService.java
@@ -29,10 +29,10 @@ public class GrandmaService {
         String tipDesTages;
         Random random = new Random();
         if(usersPlants.isEmpty()) {
-            return "Du hast noch keine Pflanzen in deinem Garten. Füge Pflanzen die du bereits eingepflanzt hast hinzu.";
+            return "Hallo ich bin Grandma! Schön, dass du GrowBros nutzt um deinen Garten zu planen.";
         } else {
             int randomNumber = random.nextInt(usersPlants.size());
-            tipDesTages = "Tip des Tages für deinen Garten: " + usersPlants.get(randomNumber).getGrowingTips();
+            tipDesTages = "Tip des Tages für deinen Garten: \n " + usersPlants.get(randomNumber).getGrowingTips();
         }
         return tipDesTages;
     }
diff --git a/src/main/java/hdm/mi/growbros/service/WishListService.java b/src/main/java/hdm/mi/growbros/service/WishListService.java
index a8a59b4..eaa82bf 100644
--- a/src/main/java/hdm/mi/growbros/service/WishListService.java
+++ b/src/main/java/hdm/mi/growbros/service/WishListService.java
@@ -47,10 +47,12 @@ public class WishListService {
     }
 
     @Transactional
-    public void removeFromWishList(Long entryId, User user) {
+    public void removeFromWishList(Long plantId, User user) {
+        Long entryId = wishListRepository.findEntryIdByUserAndPlantId(user, plantId);
         wishListRepository.deleteByIdAndUser(entryId, user);
     }
 
+
     @Transactional
     public int clearWishList(User user) {
         return wishListRepository.deleteAllByUser(user);
-- 
GitLab