From eb838a189c7f6e2940166986e1cd1d8006bd41a6 Mon Sep 17 00:00:00 2001 From: immersir <129412569+immerSIR@users.noreply.github.com> Date: Mon, 7 Apr 2025 14:32:59 +0000 Subject: [PATCH] Update page reload --- src/Fonctions/Incident_fonction.js | 834 +++++++++++++++-------------- src/views/Dashboard/analyze.jsx | 120 ++--- 2 files changed, 494 insertions(+), 460 deletions(-) diff --git a/src/Fonctions/Incident_fonction.js b/src/Fonctions/Incident_fonction.js index 110e7c2..e5a58f7 100644 --- a/src/Fonctions/Incident_fonction.js +++ b/src/Fonctions/Incident_fonction.js @@ -1,4 +1,3 @@ - import React, { useState, useEffect } from "react"; import { config } from "config"; import { useParams, useHistory, useLocation } from "react-router-dom"; @@ -7,289 +6,323 @@ import axios from "axios"; import Swal from "sweetalert2"; export const IncidentData = () => { - const { incidentId, userId } = useParams(); - const navigate = useHistory(); - const location = useLocation(); - const pictUrl = location.state ? location.state.pictUrl : ""; - - const [user, setUser] = useState({}); - const [incident, setIncident] = useState({}); - const [prediction, setPredictions] = useState([]); - const [videoIsLoading, setVideoIsLoading] = useState(false); - const [selectedMonth, setSelectedMonth] = useState(new Date().getMonth() + 1); - const [isChanged, setisChanged] = useState(false); - const [inProgress, setProgress] = useState(false); - const [changeState, setState] = useState(false); - const [EditIncident, setEditIncident] = useState({ - title: "", - zone: "", - description: "", - latitude: "", - longitude: "", - user_id: "", - etat: "", - indicateur_id: "", - category_ids: [], - }); + const { incidentId, userId } = useParams(); + const navigate = useHistory(); + const location = useLocation(); + const pictUrl = location.state ? location.state.pictUrl : ""; - const optionstype = [ - { label: "En attente", value: "declared" }, - { label: "Prendre en compte", value: "taken_into_account" }, - { label: "Résolu", value: "resolved" }, - ]; + const [user, setUser] = useState({}); + const [incident, setIncident] = useState({}); + const [prediction, setPredictions] = useState([]); + const [videoIsLoading, setVideoIsLoading] = useState(false); + const [selectedMonth, setSelectedMonth] = useState( + new Date().getMonth() + 1 + ); + const [isChanged, setisChanged] = useState(false); + const [inProgress, setProgress] = useState(false); + const [changeState, setState] = useState(false); + const [EditIncident, setEditIncident] = useState({ + title: "", + zone: "", + description: "", + latitude: "", + longitude: "", + user_id: "", + etat: "", + indicateur_id: "", + category_ids: [], + }); - const imgUrl = - incident && incident.photo ? config.url + incident.photo : ""; - const audioUrl = incident ? config.url + incident.audio : ""; - const videoUrl = incident ? config.url + incident.video : ""; + const optionstype = [ + { label: "En attente", value: "declared" }, + { label: "Prendre en compte", value: "taken_into_account" }, + { label: "Résolu", value: "resolved" }, + ]; - const latitude = incident?.lattitude || 0; - const longitude = incident?.longitude || 0; - const zone = incident?.zone || ""; - const description = incident ? incident.description : ""; - const position = [latitude, longitude]; - const dataTostring = incident ? incident.created_at : ""; - const dateObject = new Date(dataTostring); - const date = dateObject.toLocaleDateString(); - const heure = dateObject.toLocaleTimeString(); + const imgUrl = + incident && incident.photo && incident.photo !== "null" + ? `${config.url}${incident.photo}` + : ""; + const audioUrl = + incident && incident.audio && incident.audio !== "null" + ? `${config.url}${incident.audio}` + : ""; + const videoUrl = + incident && incident.video && incident.video !== "null" + ? `${config.url}${incident.video}` + : ""; - // Pour l'analyse des prédictions - const piste_solution = prediction ? prediction.piste_solution : ""; - const analysis = prediction ? prediction.analysis : ""; - const ndvi_heatmap = prediction ? prediction.ndvi_heatmap : ""; - const ndvi_ndwi_plot = prediction ? prediction.ndvi_ndwi_plot : ""; - const landcover_plot = prediction ? prediction.landcover_plot : ""; - const type_incident = prediction ? prediction.incident_type : ""; + const latitude = incident?.lattitude || 0; + const longitude = incident?.longitude || 0; + const zone = incident?.zone || ""; + const description = incident ? incident.description : ""; + const position = [latitude, longitude]; + const dataTostring = incident ? incident.created_at : ""; + const dateObject = new Date(dataTostring); + const date = dateObject.toLocaleDateString(); + const heure = dateObject.toLocaleTimeString(); - // Récupérer les données utilisateur - const fetchUserData = async () => { - try { - const response = await axios.get( - `${config.url}/MapApi/user_retrieve/`, - { - headers: { - Authorization: `Bearer ${sessionStorage.getItem("token")}`, - }, - } - ); - console.log("User information", response.data.data); - setUser(response.data.data); - } catch (error) { - console.error( - "Erreur lors de la récupération des informations utilisateur :", - error.message - ); - } - }; + // Pour l'analyse des prédictions + const piste_solution = prediction ? prediction.piste_solution : ""; + const analysis = prediction ? prediction.analysis : ""; + const ndvi_heatmap = prediction ? prediction.ndvi_heatmap : ""; + const ndvi_ndwi_plot = prediction ? prediction.ndvi_ndwi_plot : ""; + const landcover_plot = prediction ? prediction.landcover_plot : ""; + const type_incident = prediction ? prediction.incident_type : ""; - useEffect(() => { - fetchUserData(); - const fetchIncident = async () => { - try { - const response = await axios.get( - `${config.url}/MapApi/incident/${incidentId}` - ); - console.log("Incident response", response); - setIncident(response.data); - } catch (error) { - console.error( - "Erreur lors de la récupération des détails de l'incident :", - error - ); - } - }; - const fetchPredictionsEffect = async () => { - try { - const response = await axios.get( - `${config.url}/MapApi/Incidentprediction/${incidentId}` - ); - console.log("Prédictions response", response); - // Gérer les deux formats de réponse possibles : - if (response.data && Array.isArray(response.data) && response.data.length > 0) { - setPredictions(response.data[0]); - } else if ( - response.data && - response.data.data && - Array.isArray(response.data.data) && - response.data.data.length > 0 - ) { - setPredictions(response.data.data[0]); + // Récupérer les données utilisateur + const fetchUserData = async () => { + try { + const response = await axios.get( + `${config.url}/MapApi/user_retrieve/`, + { + headers: { + Authorization: `Bearer ${sessionStorage.getItem( + "token" + )}`, + }, + } + ); + console.log("User information", response.data.data); + setUser(response.data.data); + } catch (error) { + console.error( + "Erreur lors de la récupération des informations utilisateur :", + error.message + ); } - } catch (error) { - console.error( - "Erreur lors de la récupération des prédictions :", - error - ); - } }; - if (incidentId) { - fetchIncident(); - fetchPredictionsEffect(); - } - }, [incidentId]); - // Fonction exportable pour rafraîchir manuellement les prédictions - const fetchPredictions = async () => { - try { - const response = await axios.get( - `${config.url}/MapApi/Incidentprediction/${incidentId}` - ); - console.log("Prédictions (manuelles)", response.data); - if (response.data && Array.isArray(response.data) && response.data.length > 0) { - setPredictions(response.data[0]); - } else if ( - response.data && - response.data.data && - Array.isArray(response.data.data) && - response.data.data.length > 0 - ) { - setPredictions(response.data.data[0]); - } - } catch (error) { - console.error( - "Erreur lors de la récupération des prédictions :", - error - ); - } - }; + useEffect(() => { + fetchUserData(); + const fetchIncident = async () => { + try { + const response = await axios.get( + `${config.url}/MapApi/incident/${incidentId}` + ); + console.log("Incident response", response); + setIncident(response.data); + } catch (error) { + console.error( + "Erreur lors de la récupération des détails de l'incident :", + error + ); + } + }; + const fetchPredictionsEffect = async () => { + try { + const response = await axios.get( + `${config.url}/MapApi/Incidentprediction/${incidentId}` + ); + console.log("Prédictions response", response); + // Gérer les deux formats de réponse possibles : + if ( + response.data && + Array.isArray(response.data) && + response.data.length > 0 + ) { + setPredictions(response.data[0]); + } else if ( + response.data && + response.data.data && + Array.isArray(response.data.data) && + response.data.data.length > 0 + ) { + setPredictions(response.data.data[0]); + } + } catch (error) { + console.error( + "Erreur lors de la récupération des prédictions :", + error + ); + } + }; + if (incidentId) { + fetchIncident(); + fetchPredictionsEffect(); + } + }, [incidentId]); - // Changement du type d'incident (appelé lors du changement de sélection) - const handleSelectChange = async (selectedOption) => { - console.log("Nouveau type sélectionné :", selectedOption.value); - setEditIncident({ ...EditIncident, etat: selectedOption.value }); - try { - await axios.post( - `${config.url}/MapApi/changeIncidentType/${incidentId}`, - { etat: selectedOption.value }, - { - headers: { - Authorization: `Bearer ${sessionStorage.getItem("token")}`, - }, + // Fonction exportable pour rafraîchir manuellement les prédictions + const fetchPredictions = async () => { + try { + const response = await axios.get( + `${config.url}/MapApi/Incidentprediction/${incidentId}` + ); + console.log("Prédictions (manuelles)", response.data); + if ( + response.data && + Array.isArray(response.data) && + response.data.length > 0 + ) { + setPredictions(response.data[0]); + } else if ( + response.data && + response.data.data && + Array.isArray(response.data.data) && + response.data.data.length > 0 + ) { + setPredictions(response.data.data[0]); + } + } catch (error) { + console.error( + "Erreur lors de la récupération des prédictions :", + error + ); } - ); - } catch (error) { - console.error("Erreur lors du changement de type d'incident :", error); - } - }; + }; - // Changement de statut de l'incident - const handleChangeStatus = async (e) => { - e.preventDefault(); - setState(true); - setProgress(true); + // Changement du type d'incident (appelé lors du changement de sélection) + const handleSelectChange = async (selectedOption) => { + console.log("Nouveau type sélectionné :", selectedOption.value); + setEditIncident({ ...EditIncident, etat: selectedOption.value }); + try { + await axios.post( + `${config.url}/MapApi/changeIncidentType/${incidentId}`, + { etat: selectedOption.value }, + { + headers: { + Authorization: `Bearer ${sessionStorage.getItem( + "token" + )}`, + }, + } + ); + } catch (error) { + console.error( + "Erreur lors du changement de type d'incident :", + error + ); + } + }; - const action = EditIncident.etat; - const url = config.url + "/MapApi/hadleIncident/" + incidentId; - const token = sessionStorage.getItem("token"); + // Changement de statut de l'incident + const handleChangeStatus = async (e) => { + e.preventDefault(); + setState(true); + setProgress(true); - if (!token) { - Swal.fire("Token not found. Please log in."); - setState(false); - setisChanged(false); - setProgress(false); - return; - } + const action = EditIncident.etat; + const url = config.url + "/MapApi/hadleIncident/" + incidentId; + const token = sessionStorage.getItem("token"); - try { - const response = await axios.post( - url, - { action }, - { - headers: { - Authorization: `Bearer ${token}`, - }, + if (!token) { + Swal.fire("Token not found. Please log in."); + setState(false); + setisChanged(false); + setProgress(false); + return; } - ); - console.log("Réponse changement de statut", response); - setState(false); - setisChanged(false); - setEditIncident({ - title: "", - zone: "", - description: "", - latitude: "", - longitude: "", - user_id: "", - etat: "", - indicateur_id: "", - category_ids: [], - }); - Swal.fire("Changement de status effectué avec succès"); - } catch (error) { - if ( - error.response && - error.response.data.code === "token_not_valid" - ) { + try { - const refreshToken = localStorage.getItem("refresh_token"); - const refreshResponse = await axios.post( - config.url + "/api/token/refresh/", - { refresh: refreshToken } - ); - localStorage.setItem("token", refreshResponse.data.access); - const retryResponse = await axios.post( - url, - { action }, - { - headers: { - Authorization: `Bearer ${refreshResponse.data.access}`, - }, + const response = await axios.post( + url, + { action }, + { + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + console.log("Réponse changement de statut", response); + setState(false); + setisChanged(false); + setEditIncident({ + title: "", + zone: "", + description: "", + latitude: "", + longitude: "", + user_id: "", + etat: "", + indicateur_id: "", + category_ids: [], + }); + Swal.fire("Changement de status effectué avec succès"); + } catch (error) { + if ( + error.response && + error.response.data.code === "token_not_valid" + ) { + try { + const refreshToken = localStorage.getItem("refresh_token"); + const refreshResponse = await axios.post( + config.url + "/api/token/refresh/", + { refresh: refreshToken } + ); + localStorage.setItem("token", refreshResponse.data.access); + const retryResponse = await axios.post( + url, + { action }, + { + headers: { + Authorization: `Bearer ${refreshResponse.data.access}`, + }, + } + ); + console.log( + "Réponse après rafraîchissement", + retryResponse + ); + setState(false); + setisChanged(false); + setEditIncident({ + title: "", + zone: "", + description: "", + latitude: "", + longitude: "", + user_id: "", + etat: "", + indicateur_id: "", + category_ids: [], + }); + Swal.fire("Changement de status effectué avec succès"); + } catch (refreshError) { + console.log( + "Erreur lors du rafraîchissement du token", + refreshError + ); + // Ici, on renvoie le message attendu par le test pour un token expiré + Swal.fire("Session expired. Please log in again."); + sessionStorage.removeItem("token"); + } + } else { + setState(false); + setisChanged(false); + if (error.response) { + console.log(error.response.status); + console.log(error.response.data); + Swal.fire( + "Désolé", + "Cet incident est déjà pris en compte." + ); + } else if (error.request) { + console.log(error.request); + } else { + console.log(error.message); + } } - ); - console.log("Réponse après rafraîchissement", retryResponse); - setState(false); - setisChanged(false); - setEditIncident({ - title: "", - zone: "", - description: "", - latitude: "", - longitude: "", - user_id: "", - etat: "", - indicateur_id: "", - category_ids: [], - }); - Swal.fire("Changement de status effectué avec succès"); - } catch (refreshError) { - console.log("Erreur lors du rafraîchissement du token", refreshError); - // Ici, on renvoie le message attendu par le test pour un token expiré - Swal.fire("Session expired. Please log in again."); - sessionStorage.removeItem("token"); - } - } else { - setState(false); - setisChanged(false); - if (error.response) { - console.log(error.response.status); - console.log(error.response.data); - Swal.fire("Désolé", "Cet incident est déjà pris en compte."); - } else if (error.request) { - console.log(error.request); - } else { - console.log(error.message); + } finally { + setProgress(false); } - } - } finally { - setProgress(false); - } - }; + }; - // Navigation vers d'autres pages - const handleNavigate = async () => { - const userIdLocal = user.id; - navigate.push(`/admin/analyze/${incident.id}/${userIdLocal}`); - }; - const handleNavigateLLM = async () => { - navigate.push(`/admin/llm_chat/${incident.id}/${userId}`); - }; + // Navigation vers d'autres pages + const handleNavigate = async () => { + const userIdLocal = user.id; + navigate.push(`/admin/analyze/${incident.id}/${userIdLocal}`); + }; + const handleNavigateLLM = async () => { + navigate.push(`/admin/llm_chat/${incident.id}/${userId}`); + }; - // Récupérer les structures sensibles à proximité via Overpass - const fetchNearbySensitiveStructures = async (latitude, longitude) => { - try { - const radius = 250; - const overpassUrl = "https://overpass-api.de/api/interpreter"; - const overpassQuery = ` + // Récupérer les structures sensibles à proximité via Overpass + const fetchNearbySensitiveStructures = async (latitude, longitude) => { + try { + const radius = 250; + const overpassUrl = "https://overpass-api.de/api/interpreter"; + const overpassQuery = ` [out:json]; ( // Infrastructures urbaines et autres @@ -353,139 +386,148 @@ export const IncidentData = () => { ); out center; `; - - const response = await axios.post( - overpassUrl, - `data=${encodeURIComponent(overpassQuery)}` - ); - const nearbyElements = response.data.elements; - - // Traduction en français - const translatedElements = nearbyElements.map((element) => { - const tags = element.tags; - if (tags.highway) return "Route"; - if (tags.amenity === "hospital") return "Hôpital"; - if (tags.amenity === "school") return "École"; - if (tags.amenity === "public_building") return "Bâtiment public"; - if (tags.man_made === "sewer") return "Égout"; - if (tags.man_made === "drain") return "Drain"; - if (tags.waterway === "river") return "Rivière"; - if (tags.waterway === "stream") return "Ruisseau"; - if (tags.waterway === "canal") return "Canal"; - if (tags.waterway === "drain") return "Drain"; - if (tags.waterway === "ditch") return "Fossé"; - if (tags.natural === "water") return "Plan d'eau"; - if (tags.natural === "wetland") return "Zone humide"; - if (tags.waterway === "riverbank") return "Berge de rivière"; - if (tags.landuse === "reservoir") return "Réservoir"; - if (tags.landuse === "basin") return "Bassin"; - if (tags.man_made === "reservoir_covered") return "Réservoir couvert"; - if (tags.landuse === "forest") return "Forêt"; - if (tags.leisure === "park") return "Parc"; - if (tags.landuse === "residential") return "Zone résidentielle"; - if (tags.building === "residential") return "Bâtiment résidentiel"; - if (tags.amenity === "marketplace") return "Marché"; - if (tags.landuse === "farmland") return "Terre agricole"; - if (tags.landuse === "orchard") return "Verger"; - if (tags.boundary === "protected_area") return "Zone protégée"; - if (tags.landuse === "industrial") return "Zone industrielle"; - if (tags.landuse === "commercial") return "Zone commerciale"; - if (tags.amenity === "waste_disposal") return "Site de gestion des déchets"; - if (tags.amenity === "recycling") return "Site de recyclage"; - if (tags.amenity === "drinking_water") return "Point d'eau potable"; - if (tags.man_made === "water_well") return "Puits"; - if (tags.man_made === "wastewater_plant") return "Station d'épuration"; - if (tags.power === "plant") return "Centrale électrique"; - if (tags.power === "substation") return "Sous-station électrique"; - if (tags.power === "line") return "Ligne électrique"; - if (tags.highway === "bus_stop") return "Arrêt de bus"; - if (tags.railway === "station") return "Gare"; - if (tags.hazard === "flood") return "Zone inondable"; - return "Autre"; - }); - - return translatedElements; - } catch (error) { - console.error( - "Error fetching structures and natural resources from Overpass API:", - error - ); - return []; - } - }; - // Envoi des prédictions vers FastAPI - const sendPrediction = async () => { - try { - const fastapiUrl = config.url2; - if (!incident.photo) { - console.error("Incident photo is undefined, skipping prediction."); - return; - } - - // Récupération des structures sensibles - const sensitiveStructures = await fetchNearbySensitiveStructures( - latitude, - longitude - ); - - const payload = { - image_name: incident.photo, - sensitive_structures: sensitiveStructures, - incident_id: incidentId, - user_id: userId, - zone: incident.zone, - latitude: latitude, - longitude: longitude, - }; - console.log("Les sites voisins:", sensitiveStructures); - console.log("Payload being sent:", payload); - - // Envoi vers FastAPI - await axios.post(fastapiUrl, payload); - } catch (error) { - console.error( - "Error sending prediction (Axios error):", - error.response || error.message || error - ); - throw new Error( - error.response?.data?.detail || "Error during API call" - ); - } - }; + const response = await axios.post( + overpassUrl, + `data=${encodeURIComponent(overpassQuery)}` + ); + const nearbyElements = response.data.elements; + + // Traduction en français + const translatedElements = nearbyElements.map((element) => { + const tags = element.tags; + if (tags.highway) return "Route"; + if (tags.amenity === "hospital") return "Hôpital"; + if (tags.amenity === "school") return "École"; + if (tags.amenity === "public_building") + return "Bâtiment public"; + if (tags.man_made === "sewer") return "Égout"; + if (tags.man_made === "drain") return "Drain"; + if (tags.waterway === "river") return "Rivière"; + if (tags.waterway === "stream") return "Ruisseau"; + if (tags.waterway === "canal") return "Canal"; + if (tags.waterway === "drain") return "Drain"; + if (tags.waterway === "ditch") return "Fossé"; + if (tags.natural === "water") return "Plan d'eau"; + if (tags.natural === "wetland") return "Zone humide"; + if (tags.waterway === "riverbank") return "Berge de rivière"; + if (tags.landuse === "reservoir") return "Réservoir"; + if (tags.landuse === "basin") return "Bassin"; + if (tags.man_made === "reservoir_covered") + return "Réservoir couvert"; + if (tags.landuse === "forest") return "Forêt"; + if (tags.leisure === "park") return "Parc"; + if (tags.landuse === "residential") return "Zone résidentielle"; + if (tags.building === "residential") + return "Bâtiment résidentiel"; + if (tags.amenity === "marketplace") return "Marché"; + if (tags.landuse === "farmland") return "Terre agricole"; + if (tags.landuse === "orchard") return "Verger"; + if (tags.boundary === "protected_area") return "Zone protégée"; + if (tags.landuse === "industrial") return "Zone industrielle"; + if (tags.landuse === "commercial") return "Zone commerciale"; + if (tags.amenity === "waste_disposal") + return "Site de gestion des déchets"; + if (tags.amenity === "recycling") return "Site de recyclage"; + if (tags.amenity === "drinking_water") + return "Point d'eau potable"; + if (tags.man_made === "water_well") return "Puits"; + if (tags.man_made === "wastewater_plant") + return "Station d'épuration"; + if (tags.power === "plant") return "Centrale électrique"; + if (tags.power === "substation") + return "Sous-station électrique"; + if (tags.power === "line") return "Ligne électrique"; + if (tags.highway === "bus_stop") return "Arrêt de bus"; + if (tags.railway === "station") return "Gare"; + if (tags.hazard === "flood") return "Zone inondable"; + return "Autre"; + }); + + return translatedElements; + } catch (error) { + console.error( + "Error fetching structures and natural resources from Overpass API:", + error + ); + return []; + } + }; + + // Envoi des prédictions vers FastAPI + const sendPrediction = async () => { + try { + const fastapiUrl = config.url2; + if (!incident.photo) { + console.error( + "Incident photo is undefined, skipping prediction." + ); + return; + } - return { - handleChangeStatus, - latitude, - longitude, - videoUrl, - imgUrl, - audioUrl, - optionstype, - description, - position, - date, - heure, - videoIsLoading, - handleNavigate, - setVideoIsLoading, - incident, - analysis, - ndvi_heatmap, - ndvi_ndwi_plot, - landcover_plot, - piste_solution, - type_incident, - zone, - EditIncident, - handleSelectChange, - fetchPredictions, - handleNavigateLLM, - sendPrediction, - // Pour vérification dans les tests - selectedMonth, - isChanged, - inProgress, - changeState, - }; + // Récupération des structures sensibles + const sensitiveStructures = await fetchNearbySensitiveStructures( + latitude, + longitude + ); + + const payload = { + image_name: incident.photo, + sensitive_structures: sensitiveStructures, + incident_id: incidentId, + user_id: userId, + zone: incident.zone, + latitude: latitude, + longitude: longitude, + }; + console.log("Les sites voisins:", sensitiveStructures); + console.log("Payload being sent:", payload); + + // Envoi vers FastAPI + await axios.post(fastapiUrl, payload); + } catch (error) { + console.error( + "Error sending prediction (Axios error):", + error.response || error.message || error + ); + throw new Error( + error.response?.data?.detail || "Error during API call" + ); + } + }; + + return { + handleChangeStatus, + latitude, + longitude, + videoUrl, + imgUrl, + audioUrl, + optionstype, + description, + position, + date, + heure, + videoIsLoading, + handleNavigate, + setVideoIsLoading, + incident, + analysis, + ndvi_heatmap, + ndvi_ndwi_plot, + landcover_plot, + piste_solution, + type_incident, + zone, + EditIncident, + handleSelectChange, + fetchPredictions, + handleNavigateLLM, + sendPrediction, + // Pour vérification dans les tests + selectedMonth, + isChanged, + inProgress, + changeState, + }; }; diff --git a/src/views/Dashboard/analyze.jsx b/src/views/Dashboard/analyze.jsx index aaad956..43ed6dc 100644 --- a/src/views/Dashboard/analyze.jsx +++ b/src/views/Dashboard/analyze.jsx @@ -66,6 +66,7 @@ export default function Analyze() { const [isLoadingContext, setIsLoadingContext] = useState(true); // State to track context loading const [predictionError, setPredictionError] = useState(null); // State to track prediction errors const predictionSentRef = useRef(false); // Ref to track if prediction has been sent + const refreshTimerRef = useRef(null); // Ref to store the refresh timer const { isOpen, onOpen, onClose } = useDisclosure(); @@ -73,6 +74,12 @@ export default function Analyze() { setExpanded(!expanded); }; + // Function to handle page refresh + const refreshPage = () => { + console.log("Auto-refreshing page to check for prediction data..."); + window.location.reload(); + }; + // Function to fetch predictions by incident ID const fetchPredictionsByIncidentId = async (incidentId) => { try { @@ -129,6 +136,12 @@ export default function Analyze() { : existingPrediction; setPrediction(validPrediction); setPredictionError(null); // Clear any previous errors + + // Clear any pending refresh timer + if (refreshTimerRef.current) { + clearTimeout(refreshTimerRef.current); + refreshTimerRef.current = null; + } } else if ( imgUrl && !predictionSentRef.current && @@ -138,6 +151,12 @@ export default function Analyze() { try { await sendPrediction(); predictionSentRef.current = true; + + // Set a refresh timer to check for new prediction data after 30 seconds + refreshTimerRef.current = setTimeout( + refreshPage, + 30000 + ); } catch (error) { console.error("Failed to send prediction:", error); // Set error state with meaningful message @@ -147,6 +166,24 @@ export default function Analyze() { // Mark as sent even on error to prevent retries predictionSentRef.current = true; } + } else if ( + Array.isArray(existingPrediction) && + existingPrediction.length === 0 + ) { + // If the API returned an empty array and we're not in the process of sending a prediction, + // set a refresh timer to check again after 30 seconds + if ( + !refreshTimerRef.current && + !predictionSentRef.current + ) { + console.log( + "No predictions found, setting refresh timer..." + ); + refreshTimerRef.current = setTimeout( + refreshPage, + 30000 + ); + } } } setIsLoadingContext(false); @@ -165,74 +202,29 @@ export default function Analyze() { if (!predictionSentRef.current) { fetchData(); } + + // Cleanup function to clear timer on unmount + return () => { + if (refreshTimerRef.current) { + clearTimeout(refreshTimerRef.current); + } + }; }, [incident, incidentId, imgUrl]); - // Polling to check for context availability if it's loading and prediction is not yet available + // Modified console logging to avoid repetitive messages useEffect(() => { - let pollingCount = 0; - const maxPollingAttempts = 5; // Maximum number of polling attempts - - if (isLoadingContext && !prediction && incidentId) { - const interval = setInterval(async () => { - try { - // Stop polling after reaching max attempts - if (pollingCount >= maxPollingAttempts) { - console.log( - "Reached maximum polling attempts. Stopping." - ); - setIsLoadingContext(false); - clearInterval(interval); - return; - } - - pollingCount++; - console.log( - `Polling attempt ${pollingCount}/${maxPollingAttempts}` - ); - - const updatedPrediction = await fetchPredictionsByIncidentId( - incidentId - ); - - console.log( - "Polling fetch: Existing prediction:", - updatedPrediction - ); - - const predictionExists = - (Array.isArray(updatedPrediction) && - updatedPrediction.length > 0) || - (typeof updatedPrediction === "object" && - updatedPrediction !== null && - Object.keys(updatedPrediction).length > 0); - - if (predictionExists) { - console.log("Prediction now exists."); - - // If updatedPrediction is an array, take the first element - const validPrediction = Array.isArray(updatedPrediction) - ? updatedPrediction[0] - : updatedPrediction; - setPrediction(validPrediction); - setIsLoadingContext(false); - clearInterval(interval); // Stop polling once context is available - } - } catch (error) { - console.error("Error fetching updated prediction:", error); - } - }, 5000); // Poll every 5 seconds - - return () => clearInterval(interval); // Cleanup on unmount or dependencies change + if (prediction) { + if (prediction.ndvi_heatmap) { + console.log("NDVI Heatmap URL:", prediction.ndvi_heatmap); + } else { + // Log only once + console.log( + "Prediction found but ndvi_heatmap is not available." + ); + } } - }, [isLoadingContext, prediction, incidentId]); - - if (prediction) { - console.log(prediction.ndvi_heatmap); - } else { - console.log( - "Prediction data is not available or does not contain ndvi_heatmap." - ); - } + // No else case to avoid repetitive logs + }, [prediction]); // Create a custom marker icon based on the incident state const iconHTML = ReactDOMServer.renderToString(