From 9e21d593f141f9d77677febae84289ee75757b34 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 15 Jan 2025 15:07:42 -0500 Subject: [PATCH] Link homepage cards to products views, add url params for views and for login redirect --- inventory/src/App.tsx | 28 ++++++++--------- inventory/src/components/auth/RequireAuth.tsx | 16 ++++++++++ .../dashboard/InventoryHealthSummary.tsx | 13 +++++++- inventory/src/pages/Login.tsx | 10 ++++-- inventory/src/pages/Products.tsx | 31 ++++++++++++++++--- 5 files changed, 76 insertions(+), 22 deletions(-) create mode 100644 inventory/src/components/auth/RequireAuth.tsx 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); - }} /> +