diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index dd837dd..2e756b8 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -4,6 +4,8 @@ import Dashboard from './pages/Dashboard'
import MealDetail from './pages/MealDetail'
import Pantry from './pages/Pantry'
import ShoppingList from './pages/ShoppingList'
+import Login from './pages/Login'
+import { mealPlannerApi } from './api'
const queryClient = new QueryClient()
@@ -26,6 +28,17 @@ function App() {
Shopping List
+
+
+
@@ -35,6 +48,7 @@ function App() {
} />
} />
} />
+ } />
diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts
index 2735924..78a30f2 100644
--- a/frontend/src/api/index.ts
+++ b/frontend/src/api/index.ts
@@ -10,6 +10,16 @@ const api = axios.create({
withCredentials: true,
})
+api.interceptors.response.use(
+ response => response,
+ error => {
+ if (error.response?.status === 401 && window.location.pathname !== '/login') {
+ window.location.href = '/login'
+ }
+ return Promise.reject(error)
+ }
+)
+
export const mealPlannerApi = {
auth: {
login: (password: string) => api.post('/auth/login', { password }),
diff --git a/frontend/src/pages/Login.tsx b/frontend/src/pages/Login.tsx
new file mode 100644
index 0000000..bce4d66
--- /dev/null
+++ b/frontend/src/pages/Login.tsx
@@ -0,0 +1,54 @@
+import { useState } from 'react'
+import { mealPlannerApi } from '../api'
+
+export default function Login() {
+ const [password, setPassword] = useState('')
+ const [error, setError] = useState('')
+ const [loading, setLoading] = useState(false)
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault()
+ setError('')
+ setLoading(true)
+ try {
+ await mealPlannerApi.auth.login(password)
+ window.location.href = '/'
+ } catch {
+ setError('Incorrect password. Try again.')
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ return (
+
+
+
MealPlanner
+
Family login
+
+
+
+ )
+}