diff --git a/.gitignore b/.gitignore
index e3f27ab..95cb8ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,4 +24,7 @@ frontend/*.sln
frontend/*.sw?
# Do not commit _pycache_ directories
-backend/__pycache__/
\ No newline at end of file
+backend/__pycache__/
+backend/endpoints/__pycache__/
+backend/models/schemas/__pycache__/
+backend/models/sql/__pycache__/
\ No newline at end of file
diff --git a/backend/.env b/backend/.env
index d646ae9..0822967 100644
--- a/backend/.env
+++ b/backend/.env
@@ -1 +1,4 @@
+# esto esta aqui porque es un entorno local
+# y además un usuario y contraseña bastante
+# genéricos
DB_URL = "mysql+aiomysql://root:root@localhost:3306/DAD"
\ No newline at end of file
diff --git a/backend/requirements.txt b/backend/requirements.txt
index 5c55989..d318c19 100644
--- a/backend/requirements.txt
+++ b/backend/requirements.txt
@@ -4,4 +4,5 @@ contextlib2
dotenv
pydantic
sqlalchemy
-db
\ No newline at end of file
+databases
+aiomysql
diff --git a/frontend/public/config/settings.json b/frontend/public/config/settings.json
index cb18d28..86ae650 100644
--- a/frontend/public/config/settings.json
+++ b/frontend/public/config/settings.json
@@ -6,6 +6,11 @@
]
},
"appConfig": {
+ "endpoints": {
+ "baseUrl": "http://localhost:8080/api/v1",
+ "sensors": "sensors",
+ "sensor": "sensors/sensor"
+ },
"historyChartConfig": {
"timeLabels": [
"08:00",
diff --git a/frontend/src/components/App.jsx b/frontend/src/components/App.jsx
index 6acf5b8..4a63281 100644
--- a/frontend/src/components/App.jsx
+++ b/frontend/src/components/App.jsx
@@ -3,16 +3,13 @@ import 'leaflet/dist/leaflet.css'
import 'bootstrap/dist/css/bootstrap.min.css'
import 'bootstrap/dist/js/bootstrap.bundle.min.js'
-import { ThemeProvider } from '../contexts/ThemeContext.jsx'
-
import Home from '../pages/Home.jsx'
const App = () => {
return (
<>
-
-
-
+ {/* Planeo añadir un React Router */}
+
>
);
}
diff --git a/frontend/src/components/HistoryCharts.jsx b/frontend/src/components/HistoryCharts.jsx
index eea2fb6..26c0015 100644
--- a/frontend/src/components/HistoryCharts.jsx
+++ b/frontend/src/components/HistoryCharts.jsx
@@ -6,16 +6,28 @@ import PropTypes from "prop-types";
import { useTheme } from "../contexts/ThemeContext.jsx";
import { DataProvider, useData } from "../contexts/DataContext.jsx";
-import { ConfigProvider, useConfig } from "../contexts/ConfigContext.jsx";
+import { useConfig } from "../contexts/ConfigContext.jsx";
ChartJS.register(LineElement, PointElement, LinearScale, CategoryScale, Filler);
const HistoryCharts = () => {
+ const { config, configLoading, configError } = useConfig();
+
+ if (configLoading) return
Cargando configuración...
;
+ if (configError) return Error al cargar configuración: {configError}
;
+ if (!config) return Configuración no disponible.
;
+
+ const BASE = config.appConfig.endpoints.baseUrl;
+ const ENDPOINT = config.appConfig.endpoints.sensors;
+
+ const reqConfig = {
+ baseUrl: `${BASE}/${ENDPOINT}`,
+ params: {}
+ }
+
return (
-
-
-
-
+
+
);
};
diff --git a/frontend/src/components/PollutionMap.jsx b/frontend/src/components/PollutionMap.jsx
index 514ae00..2dd8a31 100644
--- a/frontend/src/components/PollutionMap.jsx
+++ b/frontend/src/components/PollutionMap.jsx
@@ -1,7 +1,5 @@
import { MapContainer, TileLayer, Circle, Popup } from 'react-leaflet';
-
-import { ConfigProvider } from '../contexts/ConfigContext.jsx';
import { useConfig } from '../contexts/ConfigContext.jsx';
import { DataProvider } from '../contexts/DataContext.jsx';
@@ -41,23 +39,41 @@ const PollutionCircles = ({ data }) => {
};
const PollutionMap = () => {
+ const { config, configLoading, configError } = useConfig();
+
+ if (configLoading) return Cargando configuración...
;
+ if (configError) return Error al cargar configuración: {configError}
;
+ if (!config) return Configuración no disponible.
;
+
+ const BASE = config.appConfig.endpoints.baseUrl;
+ const ENDPOINT = config.appConfig.endpoints.sensors;
+
+ const reqConfig = {
+ baseUrl: `${BASE}/${ENDPOINT}`,
+ params: {}
+ }
+
return (
-
-
-
-
+
+
);
};
const PollutionMapContent = () => {
- const { config } = useConfig();
+ const { config, configLoading, configError } = useConfig();
+ const { data, dataLoading, dataError } = useData();
+
+ if (configLoading) return Cargando configuración...
;
+ if (configError) return Error al cargar configuración: {configError}
;
+ if (!config) return Configuración no disponible.
;
+
+ if (dataLoading) return Cargando datos...
;
+ if (dataError) return Error al cargar datos: {configError}
;
+ if (!data) return Datos no disponibles.
;
+
const SEVILLA = config?.userConfig.city;
- const { data, loading } = useData();
-
- if (loading) return Cargando datos...
;
-
const pollutionData = data.map((sensor) => ({
lat: sensor.lat,
lng: sensor.lon,
diff --git a/frontend/src/components/SummaryCards.jsx b/frontend/src/components/SummaryCards.jsx
index 5a14788..68ef1df 100644
--- a/frontend/src/components/SummaryCards.jsx
+++ b/frontend/src/components/SummaryCards.jsx
@@ -4,9 +4,28 @@ import CardContainer from './CardContainer';
import { DataProvider } from '../contexts/DataContext';
import { useData } from '../contexts/DataContext';
+import { useConfig } from '../contexts/ConfigContext';
+
const SummaryCards = () => {
+ const { config, configLoading, configError } = useConfig();
+
+ if (configLoading) return Cargando configuración...
;
+ if (configError) return Error al cargar configuración: {configError}
;
+ if (!config) return Configuración no disponible.
;
+
+ const BASE = config.appConfig.endpoints.baseUrl;
+ const ENDPOINT = config.appConfig.endpoints.sensors;
+
+ const reqConfig = {
+ baseUrl: `${BASE}/${ENDPOINT}`,
+ params: {
+ _sort: 'timestamp',
+ _order: 'desc'
+ }
+ }
+
return (
-
+
);
diff --git a/frontend/src/contexts/ConfigContext.jsx b/frontend/src/contexts/ConfigContext.jsx
index 94ab968..5cccf8b 100644
--- a/frontend/src/contexts/ConfigContext.jsx
+++ b/frontend/src/contexts/ConfigContext.jsx
@@ -5,8 +5,8 @@ const ConfigContext = createContext();
export const ConfigProvider = ({ children }) => {
const [config, setConfig] = useState(null);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
+ const [configLoading, setLoading] = useState(true);
+ const [configError, setError] = useState(null);
useEffect(() => {
const fetchConfig = async () => {
@@ -26,7 +26,7 @@ export const ConfigProvider = ({ children }) => {
}, []);
return (
-
+
{children}
);
diff --git a/frontend/src/contexts/DataContext.jsx b/frontend/src/contexts/DataContext.jsx
index 6f8526a..7ff3153 100644
--- a/frontend/src/contexts/DataContext.jsx
+++ b/frontend/src/contexts/DataContext.jsx
@@ -3,15 +3,17 @@ import PropTypes from "prop-types";
const DataContext = createContext();
-export const DataProvider = ({ children, apiUrl }) => {
+export const DataProvider = ({ children, config }) => {
const [data, setData] = useState(null);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState(null);
+ const [dataLoading, setLoading] = useState(true);
+ const [dataError, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
- const response = await fetch(apiUrl);
+ const queryParams = new URLSearchParams(config.params).toString();
+ const url = `${config.baseUrl}?${queryParams}`;
+ const response = await fetch(url);
if (!response.ok) throw new Error("Error al obtener datos");
const result = await response.json();
setData(result);
@@ -23,10 +25,10 @@ export const DataProvider = ({ children, apiUrl }) => {
};
fetchData();
- }, [apiUrl]);
+ }, [config]);
return (
-
+
{children}
);
@@ -34,7 +36,10 @@ export const DataProvider = ({ children, apiUrl }) => {
DataProvider.propTypes = {
children: PropTypes.node.isRequired,
- apiUrl: PropTypes.string.isRequired,
+ config: PropTypes.shape({
+ baseUrl: PropTypes.string.isRequired,
+ params: PropTypes.object,
+ }).isRequired,
};
export const useData = () => useContext(DataContext);
\ No newline at end of file
diff --git a/frontend/src/css/Card.css b/frontend/src/css/Card.css
index a722456..975e0ca 100644
--- a/frontend/src/css/Card.css
+++ b/frontend/src/css/Card.css
@@ -39,6 +39,7 @@
color: var(--primary-color);
text-transform: uppercase;
letter-spacing: 1px;
+ font-weight: 600;
}
p.card-text {
diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx
index 20dbf24..f5c9d96 100644
--- a/frontend/src/main.jsx
+++ b/frontend/src/main.jsx
@@ -3,8 +3,15 @@ import { createRoot } from 'react-dom/client'
import './css/index.css'
import App from './components/App.jsx'
+import { ThemeProvider } from './contexts/ThemeContext.jsx'
+import { ConfigProvider } from './contexts/ConfigContext.jsx'
+
createRoot(document.getElementById('root')).render(
-
+
+
+
+
+
,
)
diff --git a/frontend/src/pages/Home.jsx b/frontend/src/pages/Home.jsx
index 3717f10..b0e2172 100644
--- a/frontend/src/pages/Home.jsx
+++ b/frontend/src/pages/Home.jsx
@@ -12,7 +12,6 @@ const Home = () => {
- {/* */}