181 lines
6.5 KiB
TypeScript
181 lines
6.5 KiB
TypeScript
"use client"
|
|
|
|
import Link from "next/link"
|
|
import { useEffect, useState } from "react"
|
|
import { Menu, X, Search } from "lucide-react"
|
|
import { ensureHttpsImageUrl } from "@/lib/utils"
|
|
|
|
const navItems = [
|
|
{ label: "Home", href: "#", isActive: true },
|
|
{ label: "About", href: "#" },
|
|
{ label: "ERP", href: "#" },
|
|
{ label: "Tech Lab Setup", href: "#" },
|
|
{ label: "Resources", href: "#" },
|
|
{ label: "Contact", href: "#" },
|
|
]
|
|
|
|
export default function Navbar() {
|
|
const [isOpen, setIsOpen] = useState(false)
|
|
const [logoUrl, setLogoUrl] = useState("")
|
|
|
|
useEffect(() => {
|
|
const loadLogo = async () => {
|
|
try {
|
|
// Use Next.js API route instead of direct Strapi call
|
|
const res = await fetch("/api/logo", {
|
|
headers: { Accept: "application/json" },
|
|
})
|
|
if (!res.ok) {
|
|
throw new Error(`logo status ${res.status}: ${res.statusText}`)
|
|
}
|
|
const json = await res.json()
|
|
|
|
// Handle both Strapi v4 formats: data.logo (direct) or data.attributes.logo.data (nested)
|
|
const logoData = json?.data?.logo || json?.data?.attributes?.logo?.data || json?.data?.attributes?.logo
|
|
|
|
if (!logoData) {
|
|
console.warn("No logo data found in response. Full response:", json)
|
|
return
|
|
}
|
|
|
|
const logo = Array.isArray(logoData) ? logoData[0] : logoData
|
|
|
|
// Logo object may have attributes or be direct
|
|
const logoObj = logo?.attributes || logo
|
|
const url =
|
|
logoObj?.url ||
|
|
logoObj?.formats?.small?.url ||
|
|
logoObj?.formats?.thumbnail?.url ||
|
|
logoObj?.formats?.medium?.url ||
|
|
logoObj?.formats?.large?.url ||
|
|
""
|
|
|
|
if (url) {
|
|
// Get base URL for constructing absolute URLs if needed
|
|
const baseUrl = process.env.NEXT_PUBLIC_STRAPI_BASE_URL || "http://160.187.167.213"
|
|
// Ensure HTTPS to prevent Mixed Content errors
|
|
const absolute = ensureHttpsImageUrl(url, baseUrl)
|
|
console.log("✅ Logo URL from API:", absolute)
|
|
console.log("🔍 Original URL:", url)
|
|
console.log("🔍 Base URL:", baseUrl)
|
|
if (absolute) {
|
|
setLogoUrl(absolute)
|
|
} else {
|
|
console.error("❌ ensureHttpsImageUrl returned empty string")
|
|
}
|
|
} else {
|
|
console.warn("⚠️ No logo URL found in logo object. Logo object:", logoObj)
|
|
}
|
|
} catch (err) {
|
|
console.error("❌ Failed to load navbar logo:", err)
|
|
// Don't set fallback - user wants only Strapi logo
|
|
}
|
|
}
|
|
loadLogo()
|
|
}, [])
|
|
|
|
return (
|
|
<nav className="fixed top-0 left-0 right-0 z-50 w-full bg-white border-b border-gray-200">
|
|
<div className="w-full pl-6 sm:pl-8 lg:pl-12 pr-4 sm:pr-6 lg:pr-8">
|
|
<div className="flex justify-between items-center h-20">
|
|
{/* Logo */}
|
|
{logoUrl ? (
|
|
<div className="shrink-0 flex items-center">
|
|
{/* Use regular img tag for external URLs to avoid Next.js Image restrictions */}
|
|
<img
|
|
src={logoUrl}
|
|
alt="School for Schools"
|
|
className="h-7 md:h-10 w-auto object-contain"
|
|
style={{ maxWidth: "200px" }}
|
|
onError={(e) => {
|
|
console.error("❌ Image failed to load:", logoUrl)
|
|
console.error("Error event:", e)
|
|
// Try to reload after a delay
|
|
setTimeout(() => {
|
|
const img = e.currentTarget as HTMLImageElement
|
|
if (img.src !== logoUrl) {
|
|
img.src = logoUrl
|
|
}
|
|
}, 1000)
|
|
}}
|
|
onLoad={() => {
|
|
console.log("✅ Image loaded successfully:", logoUrl)
|
|
}}
|
|
/>
|
|
</div>
|
|
) : (
|
|
<div className="shrink-0 flex items-center">
|
|
<div className="h-7 md:h-10 w-32 bg-gray-200 animate-pulse rounded" />
|
|
</div>
|
|
)}
|
|
|
|
{/* Desktop Navigation */}
|
|
<div className="hidden md:flex items-center space-x-8">
|
|
{navItems.map((item) => (
|
|
<Link
|
|
key={item.label}
|
|
href={item.href}
|
|
className={`text-sm font-medium transition-colors whitespace-nowrap ${item.isActive ? "text-[#F48120]" : "text-[#353535] hover:text-[#F48120]"
|
|
}`}
|
|
>
|
|
{item.label}
|
|
</Link>
|
|
))}
|
|
{/* Desktop Search Icon */}
|
|
<button
|
|
onClick={() => {
|
|
// Add search functionality here
|
|
console.log("Search clicked")
|
|
}}
|
|
aria-label="Search"
|
|
className="inline-flex items-center justify-center p-2 rounded-md text-[#353535] hover:text-[#F48120] hover:bg-gray-100 transition-colors"
|
|
>
|
|
<Search className="h-5 w-5" />
|
|
</button>
|
|
</div>
|
|
|
|
{/* Mobile: Search icon and menu button */}
|
|
<div className="md:hidden flex items-center gap-2">
|
|
{/* Mobile Search Icon */}
|
|
<button
|
|
onClick={() => {
|
|
// Add search functionality here
|
|
console.log("Search clicked")
|
|
}}
|
|
aria-label="Search"
|
|
className="inline-flex items-center justify-center p-2 rounded-md text-[#353535] hover:text-[#F48120] hover:bg-gray-100 transition-colors"
|
|
>
|
|
<Search className="h-6 w-6" />
|
|
</button>
|
|
{/* Mobile menu button */}
|
|
<button
|
|
onClick={() => setIsOpen(!isOpen)}
|
|
className="inline-flex items-center justify-center p-2 rounded-md text-[#353535] hover:bg-gray-100"
|
|
>
|
|
{isOpen ? <X className="h-6 w-6" /> : <Menu className="h-6 w-6" />}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Mobile Navigation */}
|
|
{isOpen && (
|
|
<div className="md:hidden bg-white border-t border-gray-200">
|
|
<div className="px-2 pt-2 pb-3 space-y-1">
|
|
{navItems.map((item) => (
|
|
<Link
|
|
key={item.label}
|
|
href={item.href}
|
|
className={`block px-3 py-2 rounded-md text-base font-medium transition-colors ${item.isActive ? "bg-orange-50 text-[#F48120]" : "text-[#353535] hover:bg-gray-50"
|
|
}`}
|
|
>
|
|
{item.label}
|
|
</Link>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</nav>
|
|
)
|
|
}
|