diff --git a/inventory/src/App.tsx b/inventory/src/App.tsx
index 6d9189b..dc72e67 100644
--- a/inventory/src/App.tsx
+++ b/inventory/src/App.tsx
@@ -11,11 +11,11 @@ import PurchaseOrders from './pages/PurchaseOrders';
import { Login } from './pages/Login';
import { useEffect } from 'react';
import config from './config';
+import { RequireAuth } from './components/auth/RequireAuth';
const queryClient = new QueryClient();
function App() {
- const isLoggedIn = sessionStorage.getItem('isLoggedIn') === 'true';
const navigate = useNavigate();
useEffect(() => {
@@ -50,19 +50,19 @@ function App() {
} />
- {isLoggedIn ? (
- }>
- } />
- } />
- } />
- } />
- } />
- } />
- } />
-
- ) : (
- } />
- )}
+
+
+
+ }>
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
);
diff --git a/inventory/src/components/auth/RequireAuth.tsx b/inventory/src/components/auth/RequireAuth.tsx
new file mode 100644
index 0000000..a2aeac4
--- /dev/null
+++ b/inventory/src/components/auth/RequireAuth.tsx
@@ -0,0 +1,16 @@
+import { Navigate, useLocation } from "react-router-dom"
+
+export function RequireAuth({ children }: { children: React.ReactNode }) {
+ const isLoggedIn = sessionStorage.getItem("isLoggedIn") === "true"
+ const location = useLocation()
+
+ if (!isLoggedIn) {
+ // Redirect to login with the current path in the redirect parameter
+ return
+ }
+
+ return <>{children}>
+}
\ No newline at end of file
diff --git a/inventory/src/components/dashboard/InventoryHealthSummary.tsx b/inventory/src/components/dashboard/InventoryHealthSummary.tsx
index 9012b1d..78f34c3 100644
--- a/inventory/src/components/dashboard/InventoryHealthSummary.tsx
+++ b/inventory/src/components/dashboard/InventoryHealthSummary.tsx
@@ -2,6 +2,8 @@ import { useQuery } from "@tanstack/react-query"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { AlertCircle, AlertTriangle, CheckCircle2, PackageSearch } from "lucide-react"
import config from "@/config"
+import { useNavigate } from "react-router-dom"
+import { cn } from "@/lib/utils"
interface InventoryHealth {
critical: number
@@ -12,6 +14,7 @@ interface InventoryHealth {
}
export function InventoryHealthSummary() {
+ const navigate = useNavigate();
const { data: summary } = useQuery({
queryKey: ["inventory-health"],
queryFn: async () => {
@@ -31,6 +34,7 @@ export function InventoryHealthSummary() {
icon: AlertCircle,
className: "bg-destructive/10",
iconClassName: "text-destructive",
+ view: "critical"
},
{
title: "Reorder Soon",
@@ -39,6 +43,7 @@ export function InventoryHealthSummary() {
icon: AlertTriangle,
className: "bg-warning/10",
iconClassName: "text-warning",
+ view: "reorder"
},
{
title: "Healthy Stock",
@@ -47,6 +52,7 @@ export function InventoryHealthSummary() {
icon: CheckCircle2,
className: "bg-success/10",
iconClassName: "text-success",
+ view: "healthy"
},
{
title: "Overstock",
@@ -55,13 +61,18 @@ export function InventoryHealthSummary() {
icon: PackageSearch,
className: "bg-muted",
iconClassName: "text-muted-foreground",
+ view: "overstocked"
},
]
return (
<>
{stats.map((stat) => (
-
+ navigate(`/products?view=${stat.view}`)}
+ >
{stat.title}
diff --git a/inventory/src/pages/Login.tsx b/inventory/src/pages/Login.tsx
index 74f18ff..024d33a 100644
--- a/inventory/src/pages/Login.tsx
+++ b/inventory/src/pages/Login.tsx
@@ -1,5 +1,5 @@
import { useState } from "react";
-import { useNavigate } from "react-router-dom";
+import { useNavigate, useSearchParams } from "react-router-dom";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
@@ -15,6 +15,7 @@ export function Login() {
const [password, setPassword] = useState("");
const [isLoading, setIsLoading] = useState(false);
const navigate = useNavigate();
+ const [searchParams] = useSearchParams();
const handleLogin = async (e: React.FormEvent) => {
e.preventDefault();
@@ -57,7 +58,12 @@ export function Login() {
sessionStorage.setItem("token", data.token);
sessionStorage.setItem("isLoggedIn", "true");
toast.success("Successfully logged in");
- navigate("/", { replace: true });
+
+ // Get the redirect URL from the URL parameters, defaulting to "/"
+ const redirectTo = searchParams.get("redirect") || "/"
+
+ // Navigate to the redirect URL after successful login
+ navigate(redirectTo)
} catch (error) {
console.error("Login error:", error);
toast.error(
diff --git a/inventory/src/pages/Products.tsx b/inventory/src/pages/Products.tsx
index 72def4d..660712a 100644
--- a/inventory/src/pages/Products.tsx
+++ b/inventory/src/pages/Products.tsx
@@ -1,5 +1,6 @@
import { useState, useEffect, useMemo } from 'react';
import { useQuery, keepPreviousData } from '@tanstack/react-query';
+import { useSearchParams } from 'react-router-dom';
import { ProductFilters } from '@/components/products/ProductFilters';
import { ProductTable } from '@/components/products/ProductTable';
import { ProductTableSkeleton } from '@/components/products/ProductTableSkeleton';
@@ -151,11 +152,12 @@ const VIEW_COLUMNS: Record = {
};
export function Products() {
+ const [searchParams, setSearchParams] = useSearchParams();
const [filters, setFilters] = useState>({});
const [sortColumn, setSortColumn] = useState('title');
const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc');
const [currentPage, setCurrentPage] = useState(1);
- const [activeView, setActiveView] = useState("all");
+ const [activeView, setActiveView] = useState(searchParams.get('view') || "all");
const [pageSize] = useState(50);
const [showNonReplenishable, setShowNonReplenishable] = useState(false);
const [selectedProductId, setSelectedProductId] = useState(null);
@@ -369,6 +371,25 @@ export function Products() {
: [currentPage - 2, currentPage - 1, currentPage, currentPage + 1, currentPage + 2]
: Array.from({ length: totalPages }, (_, i) => i + 1);
+ // Update URL when view changes
+ const handleViewChange = (view: string) => {
+ setActiveView(view);
+ setCurrentPage(1);
+ setSearchParams(prev => {
+ const newParams = new URLSearchParams(prev);
+ newParams.set('view', view);
+ return newParams;
+ });
+ };
+
+ // Sync with URL params when they change
+ useEffect(() => {
+ const viewParam = searchParams.get('view');
+ if (viewParam && viewParam !== activeView) {
+ setActiveView(viewParam);
+ }
+ }, [searchParams]);
+
return (
Products
- {
- setActiveView(view);
- setCurrentPage(1);
- }} />
+