Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions backend/requirements-render.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ firebase-admin
a2wsgi
scikit-learn
numpy
passlib[bcrypt]
python-jose[cryptography]
Comment on lines +19 to +20
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

passlib bcrypt latest stable version 2025 security advisories

💡 Result:

Latest stable versions (as of 2025)

  • passlib (PyPI): 1.7.4 — released Oct 8, 2020 (still the latest on PyPI in 2025). [1]
  • bcrypt (pyca/bcrypt on PyPI): 5.0.0 — released Sep 25, 2025. [2]

Security advisories / known issues relevant to 2025

  • passlib: No known direct vulnerabilities reported for the latest release 1.7.4 in Snyk’s DB, but older versions (<1.7.3) are flagged for a cryptographic weakness (unsalted SHA-256 “prehash” used with bcrypt, enabling breach-correlation). Upgrade guidance: use passlib ≥ 1.7.3 (1.7.4 satisfies this). [3][4]
  • bcrypt (Python package): Snyk and Safety DB report no known direct vulnerabilities affecting bcrypt 5.0.0. [5][6]

Practical 2025 concern (compatibility, not a CVE)

  • passlib + bcrypt compatibility: bcrypt releases have explicitly had compatibility friction with passlib (e.g., bcrypt 4.1.0 was yanked due to “incompatibility with assumptions made by passlib”). [2]
  • Community reports indicate bcrypt 5.0.0 can break passlib-based workflows (e.g., Ansible users reporting failures and proposing patches, noting passlib maintenance concerns). [7]

Sources: passlib on PyPI [1], bcrypt on PyPI [2], Snyk passlib advisory details [3][4], Snyk bcrypt status [5], Safety DB bcrypt status [6], Ansible community thread on bcrypt 5.0.0 breakage with passlib [7].


🌐 Web query:

python-jose cryptography latest stable version 2025 security advisories CVE

💡 Result:

Latest stable versions (as released in 2025)

  • python-jose: 3.5.0 (released May 28, 2025) [1]
  • cryptography (pyca/cryptography): 46.0.3 (released Oct 15, 2025) [2]
    (Note: cryptography 46.0.4 was released Jan 28, 2026, i.e., after 2025.) [2]

Security advisories / CVEs relevant to 2025 (published or updated in 2025)

python-jose

  • CVE-2025-61152 — “alg=none” JWT acceptance / signature-bypass risk (GitHub Advisory Database entry; unreviewed) [3]
  • CVE-2024-33664 — DoS via highly-compressed JWE (“JWT bomb”); affects python-jose < 3.4.0, patched in 3.4.0 (advisory updated Feb 18, 2025) [4]
  • CVE-2024-29370 — DoS via compressed JWE content; fixed in 3.4.0 (listed as a duplicate/withdrawn advisory, but points to the same underlying issue/fix) [5]

cryptography

  • CVE-2024-12797 — cryptography wheels bundled a vulnerable OpenSSL; affects cryptography >= 42.0.0, < 44.0.1, patched in 44.0.1 (published Feb 11, 2025) [6]

Sources: [1] python-jose PyPI release history; [2] cryptography PyPI release history; [3] GHSA entry for CVE-2025-61152; [4] GHSA entry for CVE-2024-33664; [5] GitLab advisory note for CVE-2024-29370 (duplicate); [6] GHSA entry for CVE-2024-12797.


🏁 Script executed:

#!/bin/bash
# Check requirements management in the project
echo "=== Requirements files in the repository ==="
find . -name "requirements*.txt" -o -name "Pipfile*" -o -name "poetry.lock" -o -name "pyproject.toml" | head -20

echo -e "\n=== Contents of backend/requirements-render.txt ==="
cat -n backend/requirements-render.txt

echo -e "\n=== Check for version pinning patterns ==="
rg -A 2 -B 2 "passlib|python-jose" --type txt

Repository: RohanExploit/VishwaGuru

Length of output: 1049


Pin crypto dependencies to secure, compatible versions; critical CVE exposure without pinning.

Unpinned passlib[bcrypt] and python-jose[cryptography] expose the project to critical vulnerabilities and compatibility breaks:

  • passlib[bcrypt]: Unpinned constraint will pull bcrypt 5.0.0 (latest), which is incompatible with passlib—causing runtime failures. Pin to passlib>=1.7.4 with bcrypt<5.0.0 (e.g., bcrypt==4.0.1).
  • python-jose[cryptography]: Unpinned constraint risks pulling python-jose < 3.4.0, which is vulnerable to CVE-2024-33664 (DoS via compressed JWE). Pin to python-jose>=3.4.0 (currently 3.5.0).
  • cryptography: Pin to >=44.0.1 to avoid CVE-2024-12797 (vulnerable OpenSSL bundled in wheels, patched Feb 2025).

Also consider adopting a lockfile (e.g., pip-compile, Poetry, or Pipenv) to lock all transitive dependencies.

🤖 Prompt for AI Agents
In `@backend/requirements-render.txt` around lines 19 - 20, Update
requirements-render.txt to pin the crypto-related packages: replace the unpinned
entries `passlib[bcrypt]` and `python-jose[cryptography]` with pinned versions
(e.g., `passlib>=1.7.4` and `bcrypt==4.0.1` to ensure bcrypt <5.0.0
compatibility, and `python-jose>=3.4.0` (preferably 3.5.0) plus
`cryptography>=44.0.1`) so that `passlib`, `bcrypt`, `python-jose`, and
`cryptography` are fixed to secure, compatible releases; also add a note or
start a follow-up to add a locked dependency file (pip-compile/Poetry/Pipenv) to
lock transitive dependencies.

174 changes: 174 additions & 0 deletions frontend/src/AbandonedVehicleDetector.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import React, { useRef, useState, useEffect } from 'react';
import { detectorsApi } from './api';

const AbandonedVehicleDetector = ({ onBack }) => {
const videoRef = useRef(null);
const canvasRef = useRef(null);
const [isDetecting, setIsDetecting] = useState(false);
const [error, setError] = useState(null);

useEffect(() => {
let interval;
if (isDetecting) {
startCamera();
interval = setInterval(detectFrame, 2000); // Check every 2 seconds
} else {
stopCamera();
if (interval) clearInterval(interval);
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This use of variable 'interval' always evaluates to false.

Suggested change
if (interval) clearInterval(interval);

Copilot uses AI. Check for mistakes.
if (canvasRef.current) {
const ctx = canvasRef.current.getContext('2d');
ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
}
}
return () => {
stopCamera();
if (interval) clearInterval(interval);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isDetecting]);
Comment on lines +10 to +28
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Dead clearInterval in the else branch and stale closure on isDetecting.

On Line 17, interval is always undefined in the else branch because it's only assigned inside if (isDetecting). This clearInterval call is dead code — the cleanup happens correctly in the return function (Line 25).

Additionally, detectFrame (Line 91) checks !isDetecting, but it's captured in a closure where isDetecting was true at the time the interval was created, so this guard never triggers. Consider using a ref to track detection state if you need a reliable guard.

💡 Suggested approach using a ref
+    const isDetectingRef = useRef(false);
+
     useEffect(() => {
         let interval;
         if (isDetecting) {
+            isDetectingRef.current = true;
             startCamera();
             interval = setInterval(detectFrame, 2000);
         } else {
+            isDetectingRef.current = false;
             stopCamera();
-            if (interval) clearInterval(interval);
             if (canvasRef.current) {
                 const ctx = canvasRef.current.getContext('2d');
                 ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
             }
         }

Then in detectFrame:

-        if (!videoRef.current || !canvasRef.current || !isDetecting) return;
+        if (!videoRef.current || !canvasRef.current || !isDetectingRef.current) return;
🤖 Prompt for AI Agents
In `@frontend/src/AbandonedVehicleDetector.jsx` around lines 10 - 28, The else
branch in the useEffect contains a dead clearInterval and the detectFrame
closure captures a stale isDetecting; change to store the interval id and
detection state in refs (e.g., detectionIntervalRef and isDetectingRef), update
useEffect to set isDetectingRef.current when isDetecting changes, assign the
interval id to detectionIntervalRef.current inside the if (isDetecting) block
and clear it only from the cleanup using
clearInterval(detectionIntervalRef.current), remove the redundant clearInterval
in the else branch, and modify detectFrame to read isDetectingRef.current
instead of the captured isDetecting; keep existing startCamera/stopCamera and
canvasRef clear logic but rely on the cleanup function to clear the interval.


const startCamera = async () => {
setError(null);
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: {
facingMode: 'environment',
width: { ideal: 640 },
height: { ideal: 480 }
}
});
if (videoRef.current) {
videoRef.current.srcObject = stream;
}
} catch (err) {
setError("Could not access camera: " + err.message);
setIsDetecting(false);
}
};

const stopCamera = () => {
if (videoRef.current && videoRef.current.srcObject) {
const tracks = videoRef.current.srcObject.getTracks();
tracks.forEach(track => track.stop());
videoRef.current.srcObject = null;
}
};

const drawDetections = (detections, context) => {
context.clearRect(0, 0, context.canvas.width, context.canvas.height);

context.lineWidth = 4;
context.font = 'bold 18px Arial';

if (!detections || detections.length === 0) return;

detections.forEach(det => {
const { label, confidence, box } = det;

// For Abandoned Vehicle (likely zero-shot, no box)
// But if we had box...
if (box && box.length === 4) {
const [x1, y1, x2, y2] = box;
context.strokeStyle = '#A9A9A9'; // DarkGray
context.strokeRect(x1, y1, x2 - x1, y2 - y1);

context.fillStyle = 'rgba(0,0,0,0.5)';
const text = `${label} ${(confidence * 100).toFixed(0)}%`;
const textWidth = context.measureText(text).width;
context.fillRect(x1, y1 > 20 ? y1 - 25 : y1, textWidth + 10, 25);

context.fillStyle = '#FFFFFF';
context.fillText(text, x1 + 5, y1 > 20 ? y1 - 7 : y1 + 18);
} else {
context.fillStyle = 'rgba(169, 169, 169, 0.8)'; // DarkGray
const text = `${label} ${(confidence * 100).toFixed(0)}%`;
context.fillText(text, 20, 40);
}
});
Comment on lines +65 to +87
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Multiple no-box detections render at the same fixed position, overlapping each other.

In the else branch (Line 85), all detections without a bounding box are drawn at coordinates (20, 40), stacking on top of each other. Offset each label vertically using the loop index.

🐛 Fix overlapping labels
-        detections.forEach(det => {
+        detections.forEach((det, index) => {
             const { label, confidence, box } = det;
             // ...
             } else {
                  context.fillStyle = 'rgba(169, 169, 169, 0.8)';
                  const text = `${label} ${(confidence * 100).toFixed(0)}%`;
-                 context.fillText(text, 20, 40);
+                 context.fillText(text, 20, 40 + index * 28);
             }
         });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
detections.forEach(det => {
const { label, confidence, box } = det;
// For Abandoned Vehicle (likely zero-shot, no box)
// But if we had box...
if (box && box.length === 4) {
const [x1, y1, x2, y2] = box;
context.strokeStyle = '#A9A9A9'; // DarkGray
context.strokeRect(x1, y1, x2 - x1, y2 - y1);
context.fillStyle = 'rgba(0,0,0,0.5)';
const text = `${label} ${(confidence * 100).toFixed(0)}%`;
const textWidth = context.measureText(text).width;
context.fillRect(x1, y1 > 20 ? y1 - 25 : y1, textWidth + 10, 25);
context.fillStyle = '#FFFFFF';
context.fillText(text, x1 + 5, y1 > 20 ? y1 - 7 : y1 + 18);
} else {
context.fillStyle = 'rgba(169, 169, 169, 0.8)'; // DarkGray
const text = `${label} ${(confidence * 100).toFixed(0)}%`;
context.fillText(text, 20, 40);
}
});
detections.forEach((det, index) => {
const { label, confidence, box } = det;
// For Abandoned Vehicle (likely zero-shot, no box)
// But if we had box...
if (box && box.length === 4) {
const [x1, y1, x2, y2] = box;
context.strokeStyle = '#A9A9A9'; // DarkGray
context.strokeRect(x1, y1, x2 - x1, y2 - y1);
context.fillStyle = 'rgba(0,0,0,0.5)';
const text = `${label} ${(confidence * 100).toFixed(0)}%`;
const textWidth = context.measureText(text).width;
context.fillRect(x1, y1 > 20 ? y1 - 25 : y1, textWidth + 10, 25);
context.fillStyle = '#FFFFFF';
context.fillText(text, x1 + 5, y1 > 20 ? y1 - 7 : y1 + 18);
} else {
context.fillStyle = 'rgba(169, 169, 169, 0.8)'; // DarkGray
const text = `${label} ${(confidence * 100).toFixed(0)}%`;
context.fillText(text, 20, 40 + index * 28);
}
});
🤖 Prompt for AI Agents
In `@frontend/src/AbandonedVehicleDetector.jsx` around lines 65 - 87, The else
branch inside detections.forEach currently draws all no-box labels at fixed
coordinates (20,40), causing overlap; modify the loop to accept the index (e.g.,
detections.forEach((det, i) => { ... })) and compute a vertical offset for each
label (for example labelY = 40 + i * <spacing>) and use that y coordinate
instead of the hardcoded 40 so each no-box detection (rendered in the else
branch) is drawn on its own line; ensure you update the fillText/fillRect
positions accordingly and keep spacing consistent with text height.

};

const detectFrame = async () => {
if (!videoRef.current || !canvasRef.current || !isDetecting) return;

const video = videoRef.current;
if (video.readyState !== 4) return;

const canvas = canvasRef.current;
const context = canvas.getContext('2d');

if (canvas.width !== video.videoWidth || canvas.height !== video.videoHeight) {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
}

context.drawImage(video, 0, 0, canvas.width, canvas.height);
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Drawing the video frame to the visible overlay canvas freezes the live video feed during the API call (which awaits the response). The user will see a stuttering or frozen image instead of a smooth video stream with overlay.

Use an off-screen canvas to capture the frame for detection.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/AbandonedVehicleDetector.jsx, line 104:

<comment>Drawing the video frame to the visible overlay canvas freezes the live video feed during the API call (which awaits the response). The user will see a stuttering or frozen image instead of a smooth video stream with overlay.

Use an off-screen canvas to capture the frame for detection.</comment>

<file context>
@@ -0,0 +1,174 @@
+            canvas.height = video.videoHeight;
+        }
+
+        context.drawImage(video, 0, 0, canvas.width, canvas.height);
+
+        canvas.toBlob(async (blob) => {
</file context>
Fix with Cubic


canvas.toBlob(async (blob) => {
if (!blob) return;

const formData = new FormData();
formData.append('image', blob, 'frame.jpg');

try {
const data = await detectorsApi.abandonedVehicle(formData);
if (data && data.detections) {
drawDetections(data.detections, context);
}
} catch (err) {
console.error("Detection error:", err);
}
}, 'image/jpeg', 0.8);
};
Comment on lines +90 to +121
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Drawing video frame onto the overlay canvas causes visual doubling and concurrent request pileup.

Two issues in detectFrame:

  1. Visual doubling (Line 104): context.drawImage(video, ...) paints the video frame onto canvasRef, which is the transparent overlay canvas positioned on top of the <video> element. This produces a doubled image. The video frame should be drawn to a separate offscreen canvas for blob capture, keeping canvasRef exclusively for detection annotations.

  2. No in-flight guard: If the API takes >2s, setInterval fires again and queues another request. Multiple overlapping calls can cause flickering detections and unnecessary load. Track whether a request is in-flight and skip if so.

🐛 Proposed fix — use offscreen canvas + in-flight guard
     const detectFrame = async () => {
-        if (!videoRef.current || !canvasRef.current || !isDetecting) return;
+        if (!videoRef.current || !canvasRef.current) return;
 
         const video = videoRef.current;
         if (video.readyState !== 4) return;
 
-        const canvas = canvasRef.current;
-        const context = canvas.getContext('2d');
+        const overlayCanvas = canvasRef.current;
+        const overlayCtx = overlayCanvas.getContext('2d');
 
-        if (canvas.width !== video.videoWidth || canvas.height !== video.videoHeight) {
-            canvas.width = video.videoWidth;
-            canvas.height = video.videoHeight;
+        if (overlayCanvas.width !== video.videoWidth || overlayCanvas.height !== video.videoHeight) {
+            overlayCanvas.width = video.videoWidth;
+            overlayCanvas.height = video.videoHeight;
         }
 
-        context.drawImage(video, 0, 0, canvas.width, canvas.height);
-
-        canvas.toBlob(async (blob) => {
+        // Use an offscreen canvas for frame capture
+        const offscreen = document.createElement('canvas');
+        offscreen.width = video.videoWidth;
+        offscreen.height = video.videoHeight;
+        offscreen.getContext('2d').drawImage(video, 0, 0, offscreen.width, offscreen.height);
+
+        offscreen.toBlob(async (blob) => {
             if (!blob) return;
 
             const formData = new FormData();
             formData.append('image', blob, 'frame.jpg');
 
             try {
                 const data = await detectorsApi.abandonedVehicle(formData);
                 if (data && data.detections) {
-                    drawDetections(data.detections, context);
+                    drawDetections(data.detections, overlayCtx);
                 }
             } catch (err) {
                 console.error("Detection error:", err);
             }
         }, 'image/jpeg', 0.8);
     };
🤖 Prompt for AI Agents
In `@frontend/src/AbandonedVehicleDetector.jsx` around lines 90 - 121, detectFrame
currently draws the video into the overlay canvasRef (causing doubled visuals)
and allows overlapping requests; change it to draw the video into a separate
offscreen canvas (create a local offscreenCanvas sized to
video.videoWidth/video.videoHeight and use its 2D context to call toBlob) so
canvasRef is used only for annotations via drawDetections, and add an in-flight
guard (e.g., a boolean or ref like inFlightRef/isRequestInFlight checked at the
start of detectFrame and set true before awaiting
detectorsApi.abandonedVehicle(formData) and false in finally) to skip starting a
new API call while one is pending; ensure you still resize offscreenCanvas to
the video dimensions and pass the blob from the offscreen canvas to
detectorsApi.abandonedVehicle, and only drawDetections onto canvasRef's context.


return (
<div className="mt-6 flex flex-col items-center w-full">
<h2 className="text-xl font-semibold mb-4 text-center">Abandoned Vehicle Detector</h2>

{error && <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">{error}</div>}

<div className="relative w-full max-w-md bg-black rounded-lg overflow-hidden shadow-lg mb-6">
<div className="relative">
<video
ref={videoRef}
autoPlay
playsInline
muted
className="w-full h-auto block"
style={{ opacity: isDetecting ? 1 : 0.5 }}
/>
<canvas
ref={canvasRef}
className="absolute top-0 left-0 w-full h-full pointer-events-none"
/>
{!isDetecting && (
<div className="absolute inset-0 flex items-center justify-center">
<p className="text-white font-medium bg-black bg-opacity-50 px-4 py-2 rounded">
Camera Paused
</p>
</div>
)}
</div>
</div>

<button
onClick={() => setIsDetecting(!isDetecting)}
className={`w-full max-w-md py-3 px-4 rounded-lg text-white font-medium shadow-md transition transform active:scale-95 ${isDetecting ? 'bg-red-600 hover:bg-red-700' : 'bg-blue-600 hover:bg-blue-700'}`}
>
{isDetecting ? 'Stop Detection' : 'Start Live Detection'}
</button>

<p className="text-sm text-gray-500 mt-2 text-center max-w-md">
Identifies abandoned, rusted, or wrecked vehicles.
</p>

<button
onClick={onBack}
className="mt-6 text-gray-600 hover:text-gray-900 underline"
>
Back to Home
</button>
</div>
);
};
Comment on lines +1 to +172
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

This component is nearly identical to TrafficSignDetector.jsx — extract a shared LiveDetector component.

AbandonedVehicleDetector and TrafficSignDetector share ~95% of their code (camera management, detection loop, canvas overlay, UI layout). The only differences are the API endpoint, title, description text, and overlay colors. This is a textbook case for a reusable component parameterized by those differences.

♻️ Sketch of a shared component
// LiveDetector.jsx
const LiveDetector = ({ title, description, detectApi, overlayColor, onBack }) => {
    // All the shared camera, detection, canvas, and UI logic here
    // Use detectApi, overlayColor, title, description as parameters
};

// AbandonedVehicleDetector.jsx
const AbandonedVehicleDetector = ({ onBack }) => (
    <LiveDetector
        title="Abandoned Vehicle Detector"
        description="Identifies abandoned, rusted, or wrecked vehicles."
        detectApi={detectorsApi.abandonedVehicle}
        overlayColor="#A9A9A9"
        onBack={onBack}
    />
);
🧰 Tools
🪛 Biome (2.3.13)

[error] 52-52: This callback passed to forEach() iterable method should not return a value.

Either remove this return or remove the returned value.

(lint/suspicious/useIterableCallbackReturn)

🤖 Prompt for AI Agents
In `@frontend/src/AbandonedVehicleDetector.jsx` around lines 1 - 172,
AbandonedVehicleDetector and TrafficSignDetector share camera, detection loop
and canvas overlay logic; extract a reusable LiveDetector component that
contains startCamera, stopCamera, detectFrame, drawDetections, videoRef and
canvasRef, and the useEffect hook, and parameterize it with props: title,
description, detectApi (e.g., detectorsApi.abandonedVehicle), overlayColor, and
onBack; then rewrite AbandonedVehicleDetector and TrafficSignDetector to be thin
wrappers that pass the specific detectApi, overlayColor and text into
LiveDetector, preserving behavior (blob upload, FormData, canvas sizing and
drawing) and ensuring hook dependencies and error handling remain intact.


export default AbandonedVehicleDetector;
23 changes: 19 additions & 4 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ const SmartScanner = React.lazy(() => import('./SmartScanner'));
const GrievanceAnalysis = React.lazy(() => import('./views/GrievanceAnalysis'));
const NoiseDetector = React.lazy(() => import('./NoiseDetector'));
const CivicEyeDetector = React.lazy(() => import('./CivicEyeDetector'));
const WasteDetector = React.lazy(() => import('./WasteDetector'));
const WaterLeakDetector = React.lazy(() => import('./WaterLeakDetector'));
const CrowdDetector = React.lazy(() => import('./CrowdDetector'));
const AccessibilityDetector = React.lazy(() => import('./AccessibilityDetector'));
const TrafficSignDetector = React.lazy(() => import('./TrafficSignDetector'));
const AbandonedVehicleDetector = React.lazy(() => import('./AbandonedVehicleDetector'));
const MyReportsView = React.lazy(() => import('./views/MyReportsView'));


Expand All @@ -42,6 +48,9 @@ import { AuthProvider } from './contexts/AuthContext';
import Login from './views/Login';
import ProtectedRoute from './components/ProtectedRoute';
import AdminDashboard from './views/AdminDashboard';
import AppHeader from './components/AppHeader';
import FloatingButtonsManager from './components/FloatingButtonsManager';
import LoadingSpinner from './components/LoadingSpinner';

// Create a wrapper component to handle state management
function AppContent() {
Expand All @@ -59,12 +68,12 @@ function AppContent() {

// Safe navigation helper
const navigateToView = useCallback((view) => {
const validViews = ['home', 'map', 'report', 'action', 'mh-rep', 'pothole', 'garbage', 'vandalism', 'flood', 'infrastructure', 'parking', 'streetlight', 'fire', 'animal', 'blocked', 'tree', 'pest', 'smart-scan', 'grievance-analysis', 'noise', 'safety-check', 'my-reports', 'login', 'signup'];
const validViews = ['home', 'map', 'report', 'action', 'mh-rep', 'pothole', 'garbage', 'vandalism', 'flood', 'infrastructure', 'parking', 'streetlight', 'fire', 'animal', 'blocked', 'tree', 'pest', 'smart-scan', 'grievance-analysis', 'noise', 'safety-check', 'my-reports', 'waste', 'water-leak', 'crowd', 'accessibility', 'traffic-sign', 'abandoned-vehicle', 'login', 'signup'];
if (validViews.includes(view)) {
navigate(view === 'home' ? '/' : `/${view}`);
navigate(view === 'home' ? '/home' : `/${view}`);
} else {
console.warn(`Attempted to navigate to invalid view: ${view}`);
navigate('/');
navigate('/home');
}
}, [navigate]);

Expand Down Expand Up @@ -191,7 +200,7 @@ function AppContent() {
/>

<Route
path="/"
path="/home"
element={
<Home
setView={navigateToView}
Expand Down Expand Up @@ -285,6 +294,12 @@ function AppContent() {
<Route path="/smart-scan" element={<SmartScanner onBack={() => navigate('/')} />} />
<Route path="/grievance-analysis" element={<GrievanceAnalysis onBack={() => navigate('/')} />} />
<Route path="/noise" element={<NoiseDetector onBack={() => navigate('/')} />} />
<Route path="/waste" element={<WasteDetector onBack={() => navigate('/')} />} />
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The new detector routes still navigate back to "/", but the app’s home route was moved to "/home". This sends users to the landing page instead of the main home screen after exiting these detectors. Update the onBack navigation to "/home" (and keep it consistent across all new detector routes).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At frontend/src/App.jsx, line 297:

<comment>The new detector routes still navigate back to "/", but the app’s home route was moved to "/home". This sends users to the landing page instead of the main home screen after exiting these detectors. Update the onBack navigation to "/home" (and keep it consistent across all new detector routes).</comment>

<file context>
@@ -285,6 +294,12 @@ function AppContent() {
             <Route path="/smart-scan" element={<SmartScanner onBack={() => navigate('/')} />} />
             <Route path="/grievance-analysis" element={<GrievanceAnalysis onBack={() => navigate('/')} />} />
             <Route path="/noise" element={<NoiseDetector onBack={() => navigate('/')} />} />
+            <Route path="/waste" element={<WasteDetector onBack={() => navigate('/')} />} />
+            <Route path="/water-leak" element={<WaterLeakDetector onBack={() => navigate('/')} />} />
+            <Route path="/crowd" element={<CrowdDetector onBack={() => navigate('/')} />} />
</file context>
Fix with Cubic

<Route path="/water-leak" element={<WaterLeakDetector onBack={() => navigate('/')} />} />
<Route path="/crowd" element={<CrowdDetector onBack={() => navigate('/')} />} />
<Route path="/accessibility" element={<AccessibilityDetector onBack={() => navigate('/')} />} />
<Route path="/traffic-sign" element={<TrafficSignDetector onBack={() => navigate('/')} />} />
<Route path="/abandoned-vehicle" element={<AbandonedVehicleDetector onBack={() => navigate('/')} />} />
Comment on lines +297 to +302
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The newly added detector routes pass onBack={() => navigate('/')}. Since / now renders the Landing page and Home is /home, these “Back to Home” actions will take users to the landing screen instead of the home dashboard. Update these callbacks to navigate to /home (or reuse navigateToView('home')).

Copilot uses AI. Check for mistakes.
Comment on lines +297 to +302
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

onBack navigates to / (Landing) instead of /home — broken "Back" button on all new detectors.

The Home route was moved to /home (Line 203), but onBack callbacks here still use navigate('/'), which resolves to the Landing page. Users pressing "Back" from any detector will land on the Landing page instead of Home.

Note: this same issue exists on Lines 259–296 for the pre-existing detectors, but at minimum the newly added routes should be correct.

🐛 Proposed fix for new routes
-            <Route path="/waste" element={<WasteDetector onBack={() => navigate('/')} />} />
-            <Route path="/water-leak" element={<WaterLeakDetector onBack={() => navigate('/')} />} />
-            <Route path="/crowd" element={<CrowdDetector onBack={() => navigate('/')} />} />
-            <Route path="/accessibility" element={<AccessibilityDetector onBack={() => navigate('/')} />} />
-            <Route path="/traffic-sign" element={<TrafficSignDetector onBack={() => navigate('/')} />} />
-            <Route path="/abandoned-vehicle" element={<AbandonedVehicleDetector onBack={() => navigate('/')} />} />
+            <Route path="/waste" element={<WasteDetector onBack={() => navigate('/home')} />} />
+            <Route path="/water-leak" element={<WaterLeakDetector onBack={() => navigate('/home')} />} />
+            <Route path="/crowd" element={<CrowdDetector onBack={() => navigate('/home')} />} />
+            <Route path="/accessibility" element={<AccessibilityDetector onBack={() => navigate('/home')} />} />
+            <Route path="/traffic-sign" element={<TrafficSignDetector onBack={() => navigate('/home')} />} />
+            <Route path="/abandoned-vehicle" element={<AbandonedVehicleDetector onBack={() => navigate('/home')} />} />

Consider also fixing Lines 259–296 for the existing detectors in the same pass.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Route path="/waste" element={<WasteDetector onBack={() => navigate('/')} />} />
<Route path="/water-leak" element={<WaterLeakDetector onBack={() => navigate('/')} />} />
<Route path="/crowd" element={<CrowdDetector onBack={() => navigate('/')} />} />
<Route path="/accessibility" element={<AccessibilityDetector onBack={() => navigate('/')} />} />
<Route path="/traffic-sign" element={<TrafficSignDetector onBack={() => navigate('/')} />} />
<Route path="/abandoned-vehicle" element={<AbandonedVehicleDetector onBack={() => navigate('/')} />} />
<Route path="/waste" element={<WasteDetector onBack={() => navigate('/home')} />} />
<Route path="/water-leak" element={<WaterLeakDetector onBack={() => navigate('/home')} />} />
<Route path="/crowd" element={<CrowdDetector onBack={() => navigate('/home')} />} />
<Route path="/accessibility" element={<AccessibilityDetector onBack={() => navigate('/home')} />} />
<Route path="/traffic-sign" element={<TrafficSignDetector onBack={() => navigate('/home')} />} />
<Route path="/abandoned-vehicle" element={<AbandonedVehicleDetector onBack={() => navigate('/home')} />} />
🤖 Prompt for AI Agents
In `@frontend/src/App.jsx` around lines 297 - 302, The onBack handlers for the
detector routes in App.jsx currently call navigate('/') which sends users to the
Landing page; update each detector route's onBack prop (e.g., WasteDetector,
WaterLeakDetector, CrowdDetector, AccessibilityDetector, TrafficSignDetector,
AbandonedVehicleDetector and also the earlier detectors at lines ~259–296) to
call navigate('/home') instead so the Back button returns to the Home route;
locate the Route elements that pass onBack={() => navigate('/')} and replace the
path string with '/home'.

<Route path="/safety-check" element={
<div className="flex flex-col h-full p-4">
<button onClick={() => navigate('/')} className="self-start text-blue-600 mb-2 font-bold">
Expand Down
Loading