From 42f1b4de384bcbbdab3b80d8e5cc53b36fcffd50 Mon Sep 17 00:00:00 2001
From: Adam Mathes <adam@adammathes.com>
Date: Thu, 12 Feb 2026 21:50:56 -0800
Subject: Implement frontend login logic with >90% coverage

---
 frontend/src/App.tsx | 85 ++++++++++++++++++++++++++++++++++------------------
 1 file changed, 56 insertions(+), 29 deletions(-)

(limited to 'frontend/src/App.tsx')

diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 3d7ded3..b986198 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,35 +1,62 @@
-import { useState } from 'react'
-import reactLogo from './assets/react.svg'
-import viteLogo from '/vite.svg'
-import './App.css'
+import React, { useEffect, useState } from 'react';
+import { BrowserRouter, Routes, Route, Navigate, useLocation } from 'react-router-dom';
+import Login from './components/Login';
+import './App.css';
 
-function App() {
-  const [count, setCount] = useState(0)
+// Protected Route wrapper
+function RequireAuth({ children }: { children: React.ReactElement }) {
+  const [auth, setAuth] = useState<boolean | null>(null);
+  const location = useLocation();
+
+  useEffect(() => {
+    fetch('/api/auth')
+      .then((res) => {
+        if (res.ok) {
+          setAuth(true);
+        } else {
+          setAuth(false);
+        }
+      })
+      .catch(() => setAuth(false));
+  }, []);
+
+  if (auth === null) {
+    return <div>Loading...</div>;
+  }
+
+  if (!auth) {
+    return <Navigate to="/login" state={{ from: location }} replace />;
+  }
+
+  return children;
+}
 
+function Dashboard() {
+  // Placeholder for now
   return (
-    <>
-      <div>
-        <a href="https://vite.dev" target="_blank">
-          <img src={viteLogo} className="logo" alt="Vite logo" />
-        </a>
-        <a href="https://react.dev" target="_blank">
-          <img src={reactLogo} className="logo react" alt="React logo" />
-        </a>
-      </div>
-      <h1>Vite + React</h1>
-      <div className="card">
-        <button onClick={() => setCount((count) => count + 1)}>
-          count is {count}
-        </button>
-        <p>
-          Edit <code>src/App.tsx</code> and save to test HMR
-        </p>
-      </div>
-      <p className="read-the-docs">
-        Click on the Vite and React logos to learn more
-      </p>
-    </>
+    <div>
+      <h1>Dashboard</h1>
+      <p>Welcome to the new Neko/v2 frontend.</p>
+    </div>
   )
 }
 
-export default App
+function App() {
+  return (
+    <BrowserRouter basename="/v2">
+      <Routes>
+        <Route path="/login" element={<Login />} />
+        <Route
+          path="/*"
+          element={
+            <RequireAuth>
+              <Dashboard />
+            </RequireAuth>
+          }
+        />
+      </Routes>
+    </BrowserRouter>
+  );
+}
+
+export default App;
-- 
cgit v1.2.3

