1 import { useState } from "react";
2 import { useLocation } from "wouter";
3 import { useQuery } from "@tanstack/react-query";
4 import { Input } from "@/components/ui/input";
5 import { Button } from "@/components/ui/button";
6 import { MobileMenu } from "@/components/layout/mobile-menu";
7 import {
8 DropdownMenu,
9 DropdownMenuContent,
10 DropdownMenuItem,
11 DropdownMenuSeparator,
12 DropdownMenuTrigger,
13 DropdownMenuLabel,
14 } from "@/components/ui/dropdown-menu";
15 import { useAuth } from "@/hooks/useAuth";
16 import { useTheme } from "@/contexts/theme-context";
17 import { ChevronDown, Search, Heart, User as UserIcon, LayoutGrid, Wrench, HelpCircle, Monitor, Download, CloudOff, Mail, Settings } from "lucide-react";
18 import type { RepairGuide, User } from "@shared/schema";
19
20 export default function Header() {
21 const [, setLocation] = useLocation();
22 const [searchQuery, setSearchQuery] = useState("");
23 const [showResults, setShowResults] = useState(false);
24 const { user, isAuthenticated } = useAuth();
25 const { setTheme } = useTheme();
26
27 const { data: searchResults = [] } = useQuery<RepairGuide[]>({
28 queryKey: ["/api/repair-guides/search", searchQuery],
29 queryFn: () => fetch(`/api/repair-guides/search?q=${encodeURIComponent(searchQuery)}`).then(res => res.json()),
30 enabled: searchQuery.length > 2,
31 });
32
33 const handleSearch = (e: React.FormEvent) => {
34 e.preventDefault();
35 if (searchQuery.trim()) {
36 setShowResults(false);
37 setLocation(`/?search=${encodeURIComponent(searchQuery)}`);
38 }
39 };
40
41 return (
42 <header className="sticky top-0 z-50 w-full border-b bg-background/80 backdrop-blur-xl supports-[backdrop-filter]:bg-background/60 border-border/40">
43 <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
44 <div className="flex items-center justify-between h-16 gap-4">
45
46 {/* Brand */}
47 <div className="flex items-center space-x-2 shrink-0">
48 <MobileMenu />
49 <button
50 onClick={() => setLocation("/")}
51 className="flex items-center gap-2 group transition-all"
52 >
53 <div className="p-1.5 rounded-lg bg-primary/10 text-primary group-hover:bg-primary group-hover:text-primary-foreground transition-all duration-300">
54 <Wrench className="h-5 w-5" />
55 </div>
56 <h1 className="text-lg font-bold tracking-tight bg-gradient-to-r from-primary to-indigo-400 bg-clip-text text-transparent hidden sm:block">
57 JCRguru
58 </h1>
59 </button>
60 </div>
61
62 {/* Elegant Search Bar */}
63 <div className="flex-1 max-w-2xl relative group">
64 <form onSubmit={handleSearch} className="relative">
65 <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground group-focus-within:text-primary transition-colors" />
66 <Input
67 type="text"
68 value={searchQuery}
69 onChange={(e) => {
70 setSearchQuery(e.target.value);
71 setShowResults(e.target.value.length > 2);
72 }}
73 onBlur={() => setTimeout(() => setShowResults(false), 200)}
74 onFocus={() => setShowResults(searchQuery.length > 2)}
75 className="w-full pl-10 h-10 bg-muted/50 border-none rounded-full focus-visible:ring-2 focus-visible:ring-primary/20 transition-all text-sm"
76 placeholder="Search tech guides..."
77 />
78 </form>
79
80 {/* Glass Search Results */}
81 {showResults && searchResults.length > 0 && (
82 <div className="absolute top-full left-0 right-0 mt-2 bg-popover/90 backdrop-blur-2xl border border-border/50 rounded-2xl shadow-glass overflow-hidden z-50">
83 <div className="p-2 space-y-1">
84 {searchResults.slice(0, 5).map((guide) => (
85 <button
86 key={guide.id}
87 onClick={() => {
88 setLocation(`/guide/${guide.id}`);
89 setShowResults(false);
90 }}
91 className="w-full p-3 flex flex-col items-start hover:bg-primary/10 rounded-xl transition-colors text-left"
92 >
93 <span className="text-sm font-semibold">{guide.title}</span>
94 <span className="text-xs text-muted-foreground">{guide.category}</span>
95 </button>
96 ))}
97 </div>
98 </div>
99 )}
100 </div>
101
102 {/* Actions */}
103 <div className="flex items-center gap-1 sm:gap-2 shrink-0">
104
105 <nav className="hidden lg:flex items-center gap-1 mr-2">
106 <Button variant="ghost" size="sm" onClick={() => setLocation("/")} className="rounded-full h-9 gap-2">
107 <LayoutGrid className="h-4 w-4" />
108 Guides
109 </Button>
110
111 <DropdownMenu>
112 <DropdownMenuTrigger asChild>
113 <Button variant="ghost" size="sm" className="rounded-full h-9 gap-2">
114 <Settings className="h-4 w-4" />
115 Tools
116 <ChevronDown className="h-3 w-3" />
117 </Button>
118 </DropdownMenuTrigger>
119 <DropdownMenuContent align="end" className="w-56 mt-2 rounded-2xl p-2 shadow-glass border-border/50">
120 <DropdownMenuLabel className="px-3 py-2 text-xs font-bold uppercase tracking-wider text-muted-foreground">Repair Hub</DropdownMenuLabel>
121 <DropdownMenuItem onClick={() => setLocation("/troubleshooting")} className="rounded-xl gap-3 p-2.5">
122 <HelpCircle className="h-4 w-4" /> Troubleshooting
123 </DropdownMenuItem>
124 <DropdownMenuItem onClick={() => setLocation("/device-finder")} className="rounded-xl gap-3 p-2.5">
125 <Monitor className="h-4 w-4" /> Device Finder
126 </DropdownMenuItem>
127
128 <DropdownMenuSeparator className="my-1 opacity-50" />
129
130 <DropdownMenuLabel className="px-3 py-2 text-xs font-bold uppercase tracking-wider text-muted-foreground">Manager</DropdownMenuLabel>
131 <DropdownMenuItem onClick={() => setLocation("/downloads")} className="rounded-xl gap-3 p-2.5">
132 <Download className="h-4 w-4" /> Downloads
133 </DropdownMenuItem>
134 <DropdownMenuItem onClick={() => setLocation("/offline-settings")} className="rounded-xl gap-3 p-2.5">
135 <CloudOff className="h-4 w-4" /> Offline Mode
136 </DropdownMenuItem>
137 </DropdownMenuContent>
138 </DropdownMenu>
139 </nav>
140
141 {isAuthenticated && (
142 <Button
143 variant="ghost"
144 size="icon"
145 onClick={() => setLocation("/favorites")}
146 className="rounded-full hover:bg-primary/10 hover:text-primary transition-colors h-9 w-9"
147 >
148 <Heart className="h-5 w-5" />
149 </Button>
150 )}
151
152 {/* Profile & Theme */}
153 <DropdownMenu>
154 <DropdownMenuTrigger asChild>
155 <Button variant="ghost" className="rounded-full p-0.5 h-9 w-9 border border-border/50 overflow-hidden hover:ring-2 hover:ring-primary/20 transition-all">
156 {user?.profileImageUrl ? (
157 <img src={user.profileImageUrl} className="h-full w-full object-cover" alt="Me" />
158 ) : (
159 <div className="h-full w-full bg-primary/10 flex items-center justify-center text-primary">
160 <UserIcon className="h-5 w-5" />
161 </div>
162 )}
163 </Button>
164 </DropdownMenuTrigger>
165 <DropdownMenuContent align="end" className="w-64 mt-2 rounded-2xl p-2 shadow-glass border-border/50">
166 <div className="px-3 py-3 mb-2 flex items-center gap-3 bg-muted/30 rounded-xl">
167 <div className="h-10 w-10 rounded-full bg-primary/20 flex items-center justify-center font-bold text-primary">
168 {user?.firstName?.charAt(0) || 'U'}
169 </div>
170 <div className="flex flex-col">
171 <span className="text-sm font-bold truncate max-w-[140px]">{user?.firstName || 'Tech Expert'}</span>
172 <span className="text-[10px] text-muted-foreground truncate max-w-[140px]">{user?.email}</span>
173 </div>
174 </div>
175 <DropdownMenuSeparator className="opacity-50" />
176 <DropdownMenuLabel className="px-3 py-2 text-[10px] font-bold uppercase tracking-widest text-muted-foreground">Appearance</DropdownMenuLabel>
177 <div className="grid grid-cols-2 gap-1 p-1">
178 <Button variant="ghost" size="sm" onClick={() => setTheme("light")} className="h-8 text-[11px] rounded-lg justify-start px-2">☀️ Light</Button>
179 <Button variant="ghost" size="sm" onClick={() => setTheme("dark")} className="h-8 text-[11px] rounded-lg justify-start px-2">🌙 Dark</Button>
180 </div>
181 </DropdownMenuContent>
182 </DropdownMenu>
183
184 </div>
185 </div>
186 </div>
187 </header>
188 );
189 }