diff --git a/app/login/LoginClient.tsx b/app/login/LoginClient.tsx index 1a4a354..a2774f6 100644 --- a/app/login/LoginClient.tsx +++ b/app/login/LoginClient.tsx @@ -42,6 +42,9 @@ export default function LoginPage() { sessionStorage.setItem('USERID', data.userid); localStorage.setItem('vgproducts_uid', data.userid); localStorage.setItem('d4a_email', data.email); + + // Dispatch event to update navbar state immediately + window.dispatchEvent(new Event('storage')); } catch { console.log('Error setting storage'); } diff --git a/app/products/ProductsClient.tsx b/app/products/ProductsClient.tsx index c8b7c8c..3f4548e 100644 --- a/app/products/ProductsClient.tsx +++ b/app/products/ProductsClient.tsx @@ -3,6 +3,7 @@ import { useState } from 'react'; import Link from 'next/link'; import Image from 'next/image'; import { products } from '@/data/products'; +import PriceDisplay from '@/components/PriceDisplay'; export default function ProductsPage() { const [currentPage, setCurrentPage] = useState(1); @@ -57,9 +58,7 @@ export default function ProductsPage() { {product.description}
-
- {product.price} -
+ View Product → diff --git a/app/products/[slug]/page.tsx b/app/products/[slug]/page.tsx index 8310ed1..2ee80ae 100644 --- a/app/products/[slug]/page.tsx +++ b/app/products/[slug]/page.tsx @@ -2,6 +2,7 @@ import Image from 'next/image'; import Link from 'next/link'; import { products } from '@/data/products'; import { notFound } from 'next/navigation'; +import PriceDisplay from '@/components/PriceDisplay'; import type { Metadata } from "next"; @@ -83,9 +84,7 @@ export default async function ProductDetailPage({
{product!.category}

{product!.name}

-
- {product!.price} -
+

Description

diff --git a/components/Navbar.tsx b/components/Navbar.tsx index c1ca23c..8bf606a 100644 --- a/components/Navbar.tsx +++ b/components/Navbar.tsx @@ -1,10 +1,41 @@ "use client"; -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import Link from 'next/link'; +import { useRouter } from 'next/navigation'; export default function Navbar() { const [isOpen, setIsOpen] = useState(false); + const [isLogged, setIsLogged] = useState(false); + const [showLogoutConfirm, setShowLogoutConfirm] = useState(false); + const router = useRouter(); + + useEffect(() => { + const checkAuth = () => { + const uid = localStorage.getItem('vgproducts_uid') || sessionStorage.getItem('USERID'); + setIsLogged(!!uid); + }; + checkAuth(); + // Check periodically or handle logout event + window.addEventListener('storage', checkAuth); + return () => window.removeEventListener('storage', checkAuth); + }, []); + + const handleLogoutClick = () => { + setShowLogoutConfirm(true); + }; + + const performLogout = () => { + localStorage.removeItem('vgproducts_uid'); + localStorage.removeItem('d4a_email'); + sessionStorage.removeItem('USERID'); + setIsLogged(false); + setIsOpen(false); + setShowLogoutConfirm(false); + router.push('/'); + // trigger state update for other components + window.dispatchEvent(new Event('storage')); + }; const toggleMenu = () => setIsOpen(!isOpen); @@ -32,16 +63,74 @@ export default function Navbar() {
  • setIsOpen(false)}>Blog
  • setIsOpen(false)}>Contact
  • - setIsOpen(false)} style={{ width: '100%', justifyContent: 'center' }}> - Login - + {isLogged ? ( + + ) : ( + setIsOpen(false)} style={{ width: '100%', justifyContent: 'center' }}> + Login + + )}
  • - - - Login - + {isLogged ? ( + + ) : ( + + + Login + + )} + + {/* Logout Confirmation Modal */} + {showLogoutConfirm && ( +
    +
    +

    Confirm Logout

    +

    + Are you sure you want to log out of your account? +

    +
    + + +
    +
    +
    + )} ); } diff --git a/components/PriceDisplay.tsx b/components/PriceDisplay.tsx new file mode 100644 index 0000000..8cad9f7 --- /dev/null +++ b/components/PriceDisplay.tsx @@ -0,0 +1,38 @@ +"use client"; +import { useState, useEffect } from 'react'; + +export default function PriceDisplay({ price, isDetail = false }: { price: string, isDetail?: boolean }) { + const [isLogged, setIsLogged] = useState(false); + const [mounted, setMounted] = useState(false); + + useEffect(() => { + // eslint-disable-next-line react-hooks/set-state-in-effect + setMounted(true); + const uid = localStorage.getItem('vgproducts_uid') || sessionStorage.getItem('USERID'); + if (uid) { + setIsLogged(true); + } + }, []); + + if (!mounted) { + return
    ; + } + + if (!isLogged) { + return null; + } + + if (isDetail) { + return ( +
    + {price} +
    + ); + } + + return ( +
    + {price} +
    + ); +} diff --git a/package-lock.json b/package-lock.json index 1fbe97b..1fa420b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "vgfence-website", "version": "0.1.0", "dependencies": { - "axios": "^1.15.0", + "axios": "^1.15.1", "next": "16.2.4", "react": "19.2.4", "react-dom": "19.2.4", @@ -2151,9 +2151,9 @@ } }, "node_modules/axios": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", - "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.1.tgz", + "integrity": "sha512-WOG+Jj8ZOvR0a3rAn+Tuf1UQJRxw5venr6DgdbJzngJE3qG7X0kL83CZGpdHMxEm+ZK3seAbvFsw4FfOfP9vxg==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.11", diff --git a/package.json b/package.json index 359d283..a21e8f0 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "lint": "eslint" }, "dependencies": { - "axios": "^1.15.0", + "axios": "^1.15.1", "next": "16.2.4", "react": "19.2.4", "react-dom": "19.2.4",