From ff1629a68f55859a0c229fcaa96cbf88629d99b7 Mon Sep 17 00:00:00 2001
From: SiemensHalske <140380689+SiemensHalske@users.noreply.github.com>
Date: Mon, 17 Jun 2024 20:35:31 +0200
Subject: [PATCH 1/3] chore: Update CSS styles for responsive design on mobile
devices
---
.../src/app/dashboard/radar/Radar.module.css | 34 +++++
frontend/src/app/dashboard/radar/WMSLayer.tsx | 8 +-
frontend/src/app/dashboard/radar/page.tsx | 61 ++++++++-
.../account-settings.module.css | 16 +++
.../src/app/profile/account-settings/page.tsx | 84 +++++++++++++
.../edit-profile/edit-profile.module.css | 16 +++
.../src/app/profile/edit-profile/page.tsx | 101 +++++++++++++++
.../notification-settings.module.css | 14 +++
.../profile/notification-settings/page.tsx | 104 ++++++++++++++++
frontend/src/app/profile/page.tsx | 117 ++++++++++++++++++
frontend/src/app/profile/profile.module.css | 13 ++
.../app/profile/security-settings/page.tsx | 102 +++++++++++++++
.../security-settings.module.css | 18 +++
frontend/src/components/Navbar/Navbar.tsx | 16 +++
14 files changed, 698 insertions(+), 6 deletions(-)
create mode 100644 frontend/src/app/profile/account-settings/account-settings.module.css
create mode 100644 frontend/src/app/profile/account-settings/page.tsx
create mode 100644 frontend/src/app/profile/edit-profile/edit-profile.module.css
create mode 100644 frontend/src/app/profile/edit-profile/page.tsx
create mode 100644 frontend/src/app/profile/notification-settings/notification-settings.module.css
create mode 100644 frontend/src/app/profile/notification-settings/page.tsx
create mode 100644 frontend/src/app/profile/page.tsx
create mode 100644 frontend/src/app/profile/profile.module.css
create mode 100644 frontend/src/app/profile/security-settings/page.tsx
create mode 100644 frontend/src/app/profile/security-settings/security-settings.module.css
diff --git a/frontend/src/app/dashboard/radar/Radar.module.css b/frontend/src/app/dashboard/radar/Radar.module.css
index fb85339..f6138ab 100644
--- a/frontend/src/app/dashboard/radar/Radar.module.css
+++ b/frontend/src/app/dashboard/radar/Radar.module.css
@@ -65,3 +65,37 @@
height: 600px;
background: transparent; /* Ensure the background is transparent */
}
+
+.legendBox {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width: 90%;
+ max-width: 1200px;
+ margin: auto;
+ margin-top: 20px;
+ padding: 1rem;
+ border: 1px solid #ddd;
+ border-radius: 8px;
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+ background-color: 0 4px 8px rgba(0, 0, 0, 0.8);
+ color: black;
+ font-size: 1rem;
+ line-height: 1.5;
+ text-align: center;
+ box-sizing: border-box;
+ overflow: hidden;
+ transition: max-height 0.5s;
+}
+
+.legendTitle {
+ font-size: 1.5rem;
+ font-weight: bold;
+ margin-bottom: 0.5rem;
+}
+
+.legendContent {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+}
diff --git a/frontend/src/app/dashboard/radar/WMSLayer.tsx b/frontend/src/app/dashboard/radar/WMSLayer.tsx
index 2a04654..805b262 100644
--- a/frontend/src/app/dashboard/radar/WMSLayer.tsx
+++ b/frontend/src/app/dashboard/radar/WMSLayer.tsx
@@ -2,12 +2,12 @@ import { useEffect } from "react";
import { useMap } from "react-leaflet";
import L from "leaflet";
-const WMSTileLayer = ({ url, layers }: { url: string; layers: string }) => {
+const WMSLayer = ({ url, layerName }: { url: string; layerName: string }) => {
const map = useMap();
useEffect(() => {
const wmsLayer = L.tileLayer.wms(url, {
- layers,
+ layers: layerName,
format: "image/png",
transparent: true,
attribution: "© DWD",
@@ -18,9 +18,9 @@ const WMSTileLayer = ({ url, layers }: { url: string; layers: string }) => {
return () => {
map.removeLayer(wmsLayer);
};
- }, [url, layers, map]);
+ }, [url, layerName, map]);
return null;
};
-export default WMSTileLayer;
+export default WMSLayer;
diff --git a/frontend/src/app/dashboard/radar/page.tsx b/frontend/src/app/dashboard/radar/page.tsx
index d6e5813..e17c0af 100644
--- a/frontend/src/app/dashboard/radar/page.tsx
+++ b/frontend/src/app/dashboard/radar/page.tsx
@@ -4,7 +4,14 @@ import React, { useEffect, useState } from "react";
import { MapContainer, TileLayer, useMap } from "react-leaflet";
import L from "leaflet";
import "leaflet/dist/leaflet.css";
-import { FormControl, InputLabel, Select, MenuItem } from "@mui/material";
+import {
+ FormControl,
+ InputLabel,
+ Select,
+ MenuItem,
+ Typography,
+} from "@mui/material";
+import Image from "next/image";
import styles from "./Radar.module.css";
// Custom component to add the WMS layer
@@ -32,13 +39,53 @@ const WMSLayer = ({ url, layerName }: { url: string; layerName: string }) => {
const RadarPage = () => {
const [layerName, setLayerName] = useState("dwd:Niederschlagsradar");
+ const legendContent = () => {
+ switch (layerName) {
+ case "dwd:Niederschlagsradar":
+ return (
+
+
+ Farbskala:
+ Blau: Leichter Niederschlag
+ Grün: Mäßiger Niederschlag
+ Gelb: Starker Niederschlag
+ Rot: Sehr starker Niederschlag
+ Violett: Extrem starker Niederschlag{" "}
+
D_k}`F zDC`NP`#PmR>ffBGYvWoxjU=skI1X+Rk=>gt>Hb*h=K0_ymeEncF4>4?jr-nn^ z-I39bPQOc{2(tmpA=NY>(!#4n)bMso)y*ZlosM{k>_teiE&^bO%D2ngWlui2FQ4zp z=e^R2{nEK!>7188ep}jx9u4E6^{>Pai4O=bro^CKXDj1wPdHNx)f fsAapvUbrGuG8dO$_D zIP%N$Qo(vGfZQTekQggiZ1OrWImQE%&x##nYINN^Up$^E$N{9p5kxqF2#_te*b`Gy zic*VNFAKB*KY Z#Kq{x*b&qp(HZfD0mS|yHQ7Mf6ac}vZtVa7 diff --git a/backend/app/blueprints/__pycache__/api.cpython-312.pyc b/backend/app/blueprints/__pycache__/api.cpython-312.pyc index 0ef3be8380df1dac2aed6e337e5b9f8023a7a98d..d329227c595ddb7217aaa5dd63d6c53e0705df6e 100644 GIT binary patch literal 3144 zcmai0Uu+b|8K2$z|IcUN;h11!tuab{Qn+h^94FKzfnqxl2Pig9d%`-cZ|06Y_I9r` zd$I3yj+_c9q>6;|(BepuVzqf7f~r)i)IRpHRbTcvTBH?KRfS6B%|N6!JoTI1+w<8C zVWgdz-S6*w-#5Q+{}PLZ5sb5+R|;PS5&Dw9xFgWsJnj(?x`r^yA}nB070O~(EPJvZ zfxmlHZ`qgimHk P$nle6)s$V7I@M7v~qpCS{(LEKXmyDY_tNJ7K|PhUZN9&EZZ?!D~o z_>ider4sT*2uk?a*^|<7wMr^f(Twn+?h&59s4!{CB}(v8WduuxE@4toG$I)niNqC9 zy=o996?AHUk}DNe$;*bKYiUs8@a)h-Nl{@2p`cCCTp6h#=MA0Kx;|xcIYm>9TrORy zNd-kE>2UZ5RZ59wNat*$N5Y4sj9gK|5)9b7EBIrCZR2g{WJ=m@V@c+|s;a)sc8SkS z%^#7@5u-{qX1m1 +d+BP$`5y$XTCFjAB1K|fe{VCD%o!1~LmT$gVQAx^U zg*vgf0wtzvN}*;2DEUbhq*8(vJV#hX*BF7le~xHOr LrplSZ4ms zGv_i(a{dz0FoeF6=_p`46Oby)r*K;|0g^-TFn$r&(3T%X2Wc pnYn&-7X1(fc-+ zEidP={d6X-o%X?Gd3kndKWq=c)8#_KaUqytc0ifsJ$q(u-ttpB?>l_*futSBQ*h<4 zAp>5WQEEeg`_5M^Tp9!8(*_T^JxYFex4o7^+k1ECUd$8dD$0vRcordatEhoW5tnCs zb-6zlKicC(tHLTWVlK5I+<;rn2NnzB+_OCP*dBl0b*>&qx_f55+xoE=0|b65cB}-r zl_J8yUka DtmS8LK zLX_Iq9{@ xbeGaC2 VmHnv|C{O*f<^B9U^%sBwfNlmbct zEHNe*iLws$nDSd8$E}=#tr#Ozk=2}5EiVyjMcNciE)y%LLfbH^m{=iI*NV 7+u)3IFAu}|_zjreLIT{+23iD1SA~YqRTJNEQ{P3u5UvRV`e?5g)zGg!%R)*x zof0XBDa*@o7!D$)ziasl3Q;lRDkRB ioAk1v?X3ug4fBd;)c zMz|8cA5TC&Zs~Ut(|6+2ZRRu0!LzO856!s+Gr3?!7w$*;u1 hv6$KCG%qg~0}yPOm6uilq#uJgFu($3d=3CIrZc24q%h_% Y%)F9Y z%!vh=leaOebNk(52}vz3S; ^S CPqe~&&&)=;$RloNB|%WKD__{ diff --git a/backend/app/blueprints/api.py b/backend/app/blueprints/api.py index 8d400de..387a742 100755 --- a/backend/app/blueprints/api.py +++ b/backend/app/blueprints/api.py @@ -1,8 +1,71 @@ -from flask import Blueprint +""" +API Blueprint +------------- +This blueprint is used to define the API routes for the application. +The API blueprint is registered in the app factory in the app/__init__.py file. + +Current Routes: +- /api + - / + - /test + +The routes are defined as follows: +- /api + - GET: Returns the string "API Blueprint" +- /api/test + - GET: Returns the string "Test" +""" + +from typing import Union, Tuple +from flask import Blueprint, jsonify, request +from werkzeug.wrappers import Response + +from app.models import Sensor api_bp = Blueprint('api', __name__) -@api_bp.route('/test') +@api_bp.route('/', methods=['GET']) +def index(): + """Index route for the API blueprint""" + return "API Blueprint" + + +@api_bp.route('/test', methods=['GET']) def test(): + """Test route for the API blueprint""" return "Test" + + +@api_bp.route('/sensors', methods=['GET', 'POST']) +def sensors() -> Union[Response, Tuple[Response, int]]: + """ + Handles GET and POST requests to the /sensors route. + GET: Returns a list of all sensors in the database. + POST: Adds a new sensor to the database. + """ + if request.method == 'GET': + sensors_list = [sensor.to_dict() for sensor in Sensor.query.all()] + return jsonify(sensors_list), 200 + + elif request.method == 'POST': + if not request.json: + return jsonify({"error": "Bad Request", "message": "Body cannot be empty"}), 400 + + required_fields = ['sensor_id', 'serial_number', + 'sensor_name', 'latitude', 'longitude', 'owner_id'] + if not all(field in request.json for field in required_fields): + return jsonify({"error": "Bad Request", "message": "Missing values"}), 400 + + if Sensor.query.filter_by(sensor_id=request.json['sensor_id']).first(): + return jsonify({"error": "Bad Request", "message": "Sensor already exists"}), 400 + + # Hier die Logik zum Hinzufügen des Sensors zur Datenbank einfügen. + # Beispiel: new_sensor = Sensor(...) + # db.session.add(new_sensor) + # db.session.commit() + + return jsonify({"message": "Sensor successfully added"}), 201 + + # Fügt einen expliziten Rückgabewert für den Fall hinzu, dass keine der Bedingungen erfüllt ist + return jsonify({"error": "Method Not Allowed"}), 405 diff --git a/backend/app/models.py b/backend/app/models.py index 76362b6..12d7bf3 100755 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -69,6 +69,42 @@ class Sensor(db.Model): owner = db.relationship('User', backref=db.backref('sensors', lazy=True)) + def __init__(self, sensor_id, serial_number, sensor_name, latitude, longitude, owner_id): + """Initializes the Sensor model.""" + self.sensor_id = sensor_id + self.serial_number = serial_number + self.sensor_name = sensor_name + self.latitude = latitude + self.longitude = longitude + self.owner_id = owner_id + + def set_sensor(self, sensor_id, serial_number, sensor_name, latitude, longitude, owner_id): + """Sets a sensor in the database.""" + + sensor = Sensor( + sensor_id=sensor_id, + serial_number=serial_number, + sensor_name=sensor_name, + latitude=latitude, + longitude=longitude, + owner_id=owner_id + ) + + db.session.add(sensor) + db.session.commit() + + return sensor + + def to_dict(self): + return { + 'sensor_id': self.sensor_id, + 'serial_number': self.serial_number, + 'sensor_name': self.sensor_name, + 'latitude': self.latitude, + 'longitude': self.longitude, + 'owner_id': self.owner_id + } + class LocalizationData(db.Model): __tablename__ = 'localizationdata' From 81de34cc6ab486bf269d717914c7592700e01ff4 Mon Sep 17 00:00:00 2001 From: SiemensHalske <140380689+SiemensHalske@users.noreply.github.com> Date: Tue, 18 Jun 2024 10:14:41 +0200 Subject: [PATCH 3/3] chore: Update npm dependencies and add OpenMeteo SDK library --- .cache.sqlite | Bin 0 -> 24576 bytes backend/Scripts/rain_test.py | 52 ++++++++++++ backend/Scripts/test.py | 15 ++++ backend/app/blueprints/api.py | 4 +- frontend/package-lock.json | 29 +++++++ frontend/package.json | 1 + frontend/src/app/rain/RadarPage.module.css | 39 +++++++++ frontend/src/app/rain/page.tsx | 87 +++++++++++++++++++++ 8 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 .cache.sqlite create mode 100644 backend/Scripts/rain_test.py create mode 100644 backend/Scripts/test.py create mode 100644 frontend/src/app/rain/RadarPage.module.css create mode 100644 frontend/src/app/rain/page.tsx diff --git a/.cache.sqlite b/.cache.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..11fedafc4d9bae3353ff52efc0ee2fc02b49d8c8 GIT binary patch literal 24576 zcmeI&Jx{_w7{Ku>ZyFO`HbyRSfy9^)2UkHahKQiGAuu&4XHrE#S`3bUI5!7Bj+^#K zY1Bj)C!7BzEzk9?cYS`n ltW4CJ0D3Cj`(QVJo`;gJiEbusnKx)T0c zpW>gwwAj6Q%@^N9w$KyBZt=PBUg#BGe(KJ31Q0*~0R#|0009ILKmdXNB@kpb%9V=s zv>yyF$9k?u-dtY=ejH>EZPjp;bQ;aJlJR9(m0`KnkJ3?nN1oZO(}q2eCu*=`8Xkt@ zg_g~Bx4EiHy_|*P`m)t=)UmQ_^=z)JDwgmjBfa$R$Kl4-9WH|Ds_w?Kxb-;9b<(-= zcE$2mU83<^Z?p`DolPgc_A}9wwmL_uzn; #G_eE;!$Y!@|$K&<;|&NP80+XKmY**5I_I{1Q0*~0R#|8s=$^>jQxL7UoUwf zfB*srAb Union[Response, Tuple[Response, int]]: GET: Returns a list of all sensors in the database. POST: Adds a new sensor to the database. """ + + print(f"Request method: {request.method}") + if request.method == 'GET': sensors_list = [sensor.to_dict() for sensor in Sensor.query.all()] return jsonify(sensors_list), 200 @@ -67,5 +70,4 @@ def sensors() -> Union[Response, Tuple[Response, int]]: return jsonify({"message": "Sensor successfully added"}), 201 - # Fügt einen expliziten Rückgabewert für den Fall hinzu, dass keine der Bedingungen erfüllt ist return jsonify({"error": "Method Not Allowed"}), 405 diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 40d5f69..eb6e91e 100755 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -30,6 +30,7 @@ "next-redux-wrapper": "^8.1.0", "next-transpile-modules": "^10.0.1", "ol": "^9.2.4", + "openmeteo": "^1.1.4", "react": "^18.3.1", "react-chartjs-2": "^5.2.0", "react-dnd": "^16.0.1", @@ -1922,6 +1923,17 @@ "node": ">= 8" } }, + "node_modules/@openmeteo/sdk": { + "version": "1.11.7", + "resolved": "https://registry.npmjs.org/@openmeteo/sdk/-/sdk-1.11.7.tgz", + "integrity": "sha512-qV790gksvJ+l/umb1iKt+ZRUKE5RzgmPkwTeUSmtUcnoRaAQZX9/BQLDpmEZrkcuv4g1trzcsNRwxBrBLWUnWA==", + "dependencies": { + "flatbuffers": "^24.3.25" + }, + "engines": { + "node": ">=12.0" + } + }, "node_modules/@petamoriken/float16": { "version": "3.8.7", "resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.8.7.tgz", @@ -6323,6 +6335,11 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/flatbuffers": { + "version": "24.3.25", + "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-24.3.25.tgz", + "integrity": "sha512-3HDgPbgiwWMI9zVB7VYBHaMrbOO7Gm0v+yD2FV/sCKj+9NDeVL7BOBYUuhWAQGKWOzBo8S9WdMvV0eixO233XQ==" + }, "node_modules/flatted": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", @@ -8842,6 +8859,18 @@ "node": ">=12.20.0" } }, + "node_modules/openmeteo": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/openmeteo/-/openmeteo-1.1.4.tgz", + "integrity": "sha512-TalTDl0M7JJoeRTf+rWiFZ9SLvoxm7KkFLOQqcSjCiYs+bVMhax1qtryJqeZ1RF4W4Xfsgcl9x+VC1z39ULCxA==", + "dependencies": { + "@openmeteo/sdk": "^1.11.4", + "flatbuffers": "^24.3.25" + }, + "engines": { + "node": ">=12.0" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index 493a165..1655f4b 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -33,6 +33,7 @@ "next-redux-wrapper": "^8.1.0", "next-transpile-modules": "^10.0.1", "ol": "^9.2.4", + "openmeteo": "^1.1.4", "react": "^18.3.1", "react-chartjs-2": "^5.2.0", "react-dnd": "^16.0.1", diff --git a/frontend/src/app/rain/RadarPage.module.css b/frontend/src/app/rain/RadarPage.module.css new file mode 100644 index 0000000..42acbcc --- /dev/null +++ b/frontend/src/app/rain/RadarPage.module.css @@ -0,0 +1,39 @@ +/* RadarPage.module.css */ +.container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 2rem; +} + +.title { + font-size: 2.5rem; + margin-bottom: 2rem; + text-align: center; +} + +.radarGrid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 1rem; + width: 100%; + max-width: 1200px; +} + +.radarFrame { + border: 1px solid #ddd; + background-color: #f9f9f9; + color: #333; + padding: 1rem; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + display: flex; + flex-direction: column; + align-items: center; +} + +.loading, +.error { + font-size: 1.5rem; + color: #888; +} diff --git a/frontend/src/app/rain/page.tsx b/frontend/src/app/rain/page.tsx new file mode 100644 index 0000000..b852134 --- /dev/null +++ b/frontend/src/app/rain/page.tsx @@ -0,0 +1,87 @@ +// pages/RadarPage.tsx +"use client"; + +import React, { useState, useEffect } from "react"; +import styles from "./RadarPage.module.css"; + +const fetchWeatherApi = async (url: string, params: any) => { + const response = await fetch(`${url}?${new URLSearchParams(params)}`); + return response.json(); +}; + +const RadarPage: React.FC = () => { + const [weatherData, setWeatherData] = useState (null); + const [error, setError] = useState (null); + + useEffect(() => { + const fetchRadarData = async () => { + try { + const params = { + latitude: 51.73929, + longitude: 8.2509, + hourly: ["rain", "windspeed_10m", "winddirection_10m"], + }; + const url = "https://api.open-meteo.com/v1/forecast"; + const response = await fetchWeatherApi(url, params); + + console.log("API Response:", response); // Log the API response + + if (!response || !response.hourly) { + throw new Error("Ungültige API-Antwort"); + } + + const hourly = response.hourly; + + const weatherData = { + hourly: { + time: hourly.time.map((t: string) => new Date(t)), + rain: hourly.rain, + windSpeed10m: hourly.windspeed_10m, + windDirection10m: hourly.winddirection_10m, + }, + }; + + console.log("Processed Weather Data:", weatherData); // Log the processed weather data + + setWeatherData(weatherData); + } catch (error: any) { + setError(error.message); + } + }; + + fetchRadarData(); + }, []); + + return ( + ++ ); +}; + +export default RadarPage;Niederschlagsradar
+ {error ? ( +{error}
+ ) : weatherData ? ( ++ {weatherData.hourly.time.map( + (time: Date, index: number) => ( ++ ) : ( +++ ) + )} +{time.toLocaleString()}
+Regen: {weatherData.hourly.rain[index]}
++ Windgeschwindigkeit:{" "} + {weatherData.hourly.windSpeed10m[index]} +
++ Windrichtung:{" "} + {weatherData.hourly.windDirection10m[index]} +
+ {/* Hier könnten Sie das Radarbild für den jeweiligen Zeitpunkt einfügen */} +Daten werden geladen...
+ )} +