Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <title>Past Analyzes - CTRL + ALT + HEAL</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="script.js"></script> | |
| <link rel="stylesheet" href="style.css" /> | |
| </head> | |
| <body class="bg-[#F7F8F9] min-h-screen"> | |
| <nav | |
| class="fixed top-0 left-0 w-full z-50 backdrop-blur-md bg-white/20 border-b border-white/30 shadow-md" | |
| > | |
| <div class="flex justify-between items-center w-full px-6 py-4"> | |
| <!-- Logo --> | |
| <a | |
| href="index.html" | |
| class="text-2xl font-bold text-black hover:text-[var(--tropical-indigo)] transition" | |
| > | |
| CTRL + ALT + HEAL | |
| </a> | |
| <ul class="hidden md:flex space-x-6 font-medium text-gray-800"> | |
| <li><a href="index.html" class="nav-link">Home</a></li> | |
| <li><a href="profile.html" class="nav-link">Profile</a></li> | |
| <li><a href="analyzer.html" class="nav-link">Analyzer</a></li> | |
| <li><a href="past_data.html" class="nav-link">Past Reports</a></li> | |
| <li id="authNavItem"> | |
| <a href="login.html" class="nav-link">Login</a> | |
| </li> | |
| </ul> | |
| <!-- Hamburger Menu --> | |
| <button | |
| id="hamburger" | |
| class="md:hidden text-[var(--latte-cream)] text-2xl" | |
| > | |
| ☰ | |
| </button> | |
| </div> | |
| <!-- Mobile Menu --> | |
| <ul | |
| id="mobile-menu" | |
| class="hidden flex-col space-y-4 bg-white/30 backdrop-blur-lg border border-white/20 rounded-xl shadow-lg mt-2 p-4 mx-6 md:hidden" | |
| > | |
| <li> | |
| <a | |
| href="index.html" | |
| class="block text-gray-800 hover:text-[var(--tropical-indigo)]" | |
| >Home</a | |
| > | |
| </li> | |
| <li> | |
| <a | |
| href="analyzer.html" | |
| class="block text-gray-800 hover:text-[var(--tropical-indigo)]" | |
| >Analyzer</a | |
| > | |
| </li> | |
| <li> | |
| <a | |
| href="past_data.html" | |
| class="block text-gray-800 hover:text-[var(--tropical-indigo)]" | |
| >Past Reports</a | |
| > | |
| </li> | |
| <li> | |
| <a | |
| href="profile.html" | |
| class="block text-gray-800 hover:text-[var(--tropical-indigo)]" | |
| >Profile</a | |
| > | |
| </li> | |
| <li> | |
| <a | |
| href="login.html" | |
| class="block text-gray-800 hover:text-[var(--tropical-indigo)]" | |
| >Login</a | |
| > | |
| </li> | |
| </ul> | |
| </nav> | |
| <main class="max-w-4xl mx-auto px-4 pt-24 text-gray-800"> | |
| <div class="bg-white border border-gray-200 rounded-lg p-6 shadow mb-6"> | |
| <h2 class="text-xl font-semibold mb-4"> | |
| Your Past Analyzes | |
| </h1> | |
| <p id="auth-status" class="text-sm text-gray-500 mb-6"> | |
| Checking sign-in status… | |
| </p> | |
| <div id="recs-container" class="space-y-4"> | |
| <p class="text-sm text-gray-500"> | |
| Sign in to view your saved analyzes. | |
| </p> | |
| </div> | |
| </div> | |
| </main> | |
| <!-- Floating Chat Button --> | |
| <button | |
| id="chat-toggle" | |
| class="fixed bottom-6 right-6 bg-[var(--tropical-indigo)] text-white px-5 py-3 rounded-full shadow-lg hover:scale-105 transition" | |
| > | |
| 💬 Chat | |
| </button> | |
| <!-- Chatbot Drawer --> | |
| <div | |
| id="chat-drawer" | |
| class="fixed top-16 right-0 w-96 max-w-full h-[calc(100%-4rem)] bg-white shadow-lg border-l border-gray-200 transform translate-x-full transition-transform duration-300 ease-in-out z-40 flex flex-col" | |
| > | |
| <div class="flex justify-between items-center p-4 border-b"> | |
| <h3 class="text-lg font-semibold">Ask Chatbot</h3> | |
| <button id="chat-close" class="text-gray-600 hover:text-black text-xl"> | |
| ✖ | |
| </button> | |
| </div> | |
| <div id="chat-output" class="flex-1 overflow-auto p-4 space-y-2 text-sm"> | |
| <p><strong>Chatbot:</strong> Ask me something about your report</p> | |
| </div> | |
| <div class="flex gap-2 p-4 border-t"> | |
| <input | |
| type="text" | |
| id="user-question" | |
| placeholder="Ask a question..." | |
| class="flex-1 rounded px-3 py-2 focus:outline-none border" | |
| /> | |
| <button id="ask-btn" class="btn-primary px-4 py-2 rounded">Ask</button> | |
| </div> | |
| </div> | |
| <script> | |
| const chatDrawer = document.getElementById("chat-drawer"); | |
| const chatToggle = document.getElementById("chat-toggle"); | |
| const chatClose = document.getElementById("chat-close"); | |
| chatToggle.addEventListener("click", () => | |
| chatDrawer.classList.toggle("translate-x-full") | |
| ); | |
| chatClose.addEventListener("click", () => | |
| chatDrawer.classList.add("translate-x-full") | |
| ); | |
| </script> | |
| <script type="module"> | |
| import { | |
| getFirestore, | |
| collection, | |
| query, | |
| orderBy, | |
| getDocs, | |
| } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js"; | |
| import { initializeApp } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-app.js"; | |
| import { | |
| getAuth, | |
| onAuthStateChanged, | |
| signOut, | |
| } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-auth.js"; | |
| const firebaseConfig = { | |
| apiKey: "AIzaSyAPhM_Ee7cLzyKHs5zyFy8g5ZOk9-pubRI", | |
| authDomain: "login-tutorial-7a9e1.firebaseapp.com", | |
| projectId: "login-tutorial-7a9e1", | |
| storageBucket: "login-tutorial-7a9e1.firebasestorage.app", | |
| messagingSenderId: "491093197824", | |
| appId: "1:491093197824:web:9f866...", | |
| }; | |
| const app = initializeApp(firebaseConfig); | |
| const auth = getAuth(app); | |
| const db = getFirestore(app); | |
| onAuthStateChanged(auth, async (user) => { | |
| const authNavItem = document.getElementById("authNavItem"); | |
| const homeNavDesktop = document.querySelector( | |
| 'ul.md\\:flex li a[href="index.html"]' | |
| )?.parentElement; // Desktop <li> | |
| const homeNavMobile = document.querySelector( | |
| '#mobile-menu a[href="index.html"]' | |
| )?.parentElement; // Mobile <li> | |
| if (user) { | |
| // Update login/logout button | |
| if (authNavItem) { | |
| authNavItem.innerHTML = | |
| '<button onclick="logout()" class="hover:text-[#6B9080] text-red-600">Logout</button>'; | |
| } | |
| // Hide Home button | |
| if (homeNavDesktop) homeNavDesktop.style.display = "none"; | |
| if (homeNavMobile) homeNavMobile.style.display = "none"; | |
| // Update auth status | |
| statusEl.textContent = `Signed in as ${user.email || user.uid}`; | |
| // Fetch past reports | |
| async function getPastReports() { | |
| try { | |
| const url = api("reports/", { user_id: user.email }); | |
| const response = await fetch(url, { | |
| method: "GET", | |
| headers: { "Content-Type": "application/json" }, | |
| }); | |
| if (!response.ok) | |
| throw new Error(`HTTP error! status: ${response.status}`); | |
| const data = await response.json(); | |
| recsEl.innerHTML = data | |
| .map((doc) => renderAnalysis(doc)) | |
| .join(""); | |
| } catch (error) { | |
| console.error("Error sending report to backend:", error); | |
| recsEl.innerHTML = | |
| '<p class="text-sm text-gray-500">No saved analyses yet.</p>'; | |
| } | |
| } | |
| getPastReports(); | |
| } else { | |
| // Update login/logout button | |
| if (authNavItem) { | |
| authNavItem.innerHTML = | |
| '<a href="login.html" class="hover:text-[#6B9080]">Login</a>'; | |
| } | |
| // Show Home button | |
| if (homeNavDesktop) homeNavDesktop.style.display = ""; | |
| if (homeNavMobile) homeNavMobile.style.display = ""; | |
| // Update auth status | |
| statusEl.textContent = "Not signed in."; | |
| recsEl.innerHTML = | |
| '<p class="text-sm text-gray-500">Please sign in to see your analyses.</p>'; | |
| } | |
| }); | |
| window.logout = async () => { | |
| try { | |
| await signOut(auth); | |
| localStorage.clear(); | |
| window.location.href = "login.html"; | |
| } catch (error) { | |
| console.error("Error signing out:", error); | |
| } | |
| }; | |
| const statusEl = document.getElementById("auth-status"); | |
| const recsEl = document.getElementById("recs-container"); | |
| async function sendReportToBackend(report, userId) { | |
| try { | |
| const response = await fetch("http://localhost:9000/save_report/", { | |
| method: "POST", | |
| headers: { | |
| "Content-Type": "application/json", | |
| }, | |
| body: JSON.stringify({ | |
| ...report, | |
| user_id: userId, | |
| sync_timestamp: new Date().toISOString(), | |
| }), | |
| }); | |
| if (!response.ok) { | |
| console.warn( | |
| `Failed to sync report to backend: ${response.status}` | |
| ); | |
| } else { | |
| console.log("Report successfully synced to backend"); | |
| } | |
| } catch (error) { | |
| console.warn( | |
| "Error syncing report to backend (continuing anyway):", | |
| error | |
| ); | |
| } | |
| } | |
| function renderAnalysis(item) { | |
| const d = | |
| item.createdAt && item.createdAt.toDate | |
| ? item.createdAt.toDate().toLocaleString() | |
| : ""; | |
| return ` | |
| <div class="bg-white border border-gray-200 rounded-lg p-4 shadow"> | |
| <div class="flex justify-between mb-2"> | |
| <div class="font-semibold text-green-700">Report: ${ | |
| item.reportDate || "N/A" | |
| }</div> | |
| <div class="text-xs text-gray-500">${d}</div> | |
| </div> | |
| <pre class="whitespace-pre-wrap text-sm text-gray-700 mb-2">${ | |
| item.ocr_text || "" | |
| }</pre> | |
| ${(Array.isArray(item.Detected_Anomolies) | |
| ? item.Detected_Anomolies | |
| : [] | |
| ) | |
| .map( | |
| (r, i) => ` | |
| <div class="border-t border-gray-200 pt-2 mt-2"> | |
| <div class="font-medium">Finding ${i + 1}: ${ | |
| r.findings || "" | |
| }</div> | |
| <div class="text-sm text-gray-600">Severity: ${ | |
| r.severity || "" | |
| }</div> | |
| <div class="text-sm text-gray-600">Recommendations: ${( | |
| r.recommendations || [] | |
| ).join(", ")}</div> | |
| </div> | |
| ` | |
| ) | |
| .join("")} | |
| </div> | |
| `; | |
| } | |
| onAuthStateChanged(auth, async (user) => { | |
| if (user) { | |
| statusEl.textContent = `Signed in as ${user.email || user.uid}`; | |
| async function getPastReports() { | |
| try { | |
| const url = api("reports/", { user_id: user.email }); | |
| const response = await fetch(url, { | |
| method: "GET", | |
| headers: { | |
| "Content-Type": "application/json", | |
| }, | |
| }); | |
| if (!response.ok) { | |
| throw new Error(`HTTP error! status: ${response.status}`); | |
| } | |
| const data = await response.json(); | |
| console.log("Report successfully sent to backend:", data); | |
| recsEl.innerHTML = data | |
| .map((doc) => renderAnalysis(doc)) | |
| .join(""); | |
| } catch (error) { | |
| console.error("Error sending report to backend:", error); | |
| recsEl.innerHTML = | |
| '<p class="text-sm text-gray-500">No saved analyses yet.</p>'; | |
| } | |
| } | |
| getPastReports(); | |
| /* try { | |
| const q = query( | |
| collection(db, "users", user.uid, "analyses"), | |
| orderBy("createdAt", "desc") | |
| ); | |
| const snap = await getDocs(q); | |
| if (snap.empty) { | |
| recsEl.innerHTML = '<p class="text-sm text-gray-500">No saved analyses yet.</p>'; | |
| } else { | |
| const analyses = []; | |
| snap.forEach(doc => { | |
| const data = { id: doc.id, ...doc.data() }; | |
| analyses.push(data); | |
| sendReportToBackend(data, user.uid); | |
| }); | |
| recsEl.innerHTML = analyses.map(doc => renderAnalysis(doc)).join(""); | |
| const syncStatus = document.createElement('p'); | |
| syncStatus.className = 'text-xs text-blue-500 mt-2'; | |
| syncStatus.textContent = `Syncing ${analyses.length} reports to backend...`; | |
| recsEl.appendChild(syncStatus); | |
| setTimeout(() => { | |
| if (syncStatus.parentNode) { | |
| syncStatus.remove(); | |
| } | |
| }, 3000); | |
| } | |
| } catch (error) { | |
| console.error('Error fetching analyses:', error); | |
| recsEl.innerHTML = '<p class="text-sm text-red-500">Error loading analyses.</p>'; | |
| }*/ | |
| } else { | |
| statusEl.textContent = "Not signed in."; | |
| recsEl.innerHTML = | |
| '<p class="text-sm text-gray-500">Please sign in to see your analyses.</p>'; | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> | |