189 lines
7.2 KiB
TypeScript
189 lines
7.2 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { Menu, Search, X, ChevronDown } from 'lucide-react';
|
|
import { Link, useLocation, useNavigate } from 'react-router-dom';
|
|
import { Category, City } from '../types';
|
|
|
|
const categories: Category[] = ['Film', 'Theater', 'Music', 'Sports', 'Art', 'Legends', 'Anniversaries', 'Memory'];
|
|
const cities: City[] = ['New York', 'London'];
|
|
|
|
export function Header() {
|
|
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
|
const [searchQuery, setSearchQuery] = useState('');
|
|
const location = useLocation();
|
|
const navigate = useNavigate();
|
|
const searchParams = new URLSearchParams(location.search);
|
|
const currentCategory = searchParams.get('category');
|
|
const currentCity = searchParams.get('city');
|
|
|
|
const handleCityChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
|
const city = event.target.value;
|
|
const params = new URLSearchParams(location.search);
|
|
|
|
if (city) {
|
|
params.set('city', city);
|
|
} else {
|
|
params.delete('city');
|
|
}
|
|
|
|
navigate(`/?${params.toString()}`);
|
|
};
|
|
|
|
const handleSearch = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
if (searchQuery.trim()) {
|
|
navigate(`/search?q=${encodeURIComponent(searchQuery.trim())}`);
|
|
}
|
|
};
|
|
|
|
const handleSearchKeyPress = (e: React.KeyboardEvent) => {
|
|
if (e.key === 'Enter') {
|
|
handleSearch(e);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<header className="sticky top-0 z-50 bg-white shadow-sm">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div className="flex justify-between items-center h-16">
|
|
<div className="flex items-center">
|
|
<button
|
|
className="p-2 rounded-md text-gray-500 lg:hidden hover:bg-gray-100"
|
|
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
|
>
|
|
{isMobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
|
|
</button>
|
|
<Link to="/" className="ml-2 flex items-center space-x-2">
|
|
<h1 className="text-2xl font-bold text-gray-900">CultureScope</h1>
|
|
</Link>
|
|
</div>
|
|
|
|
<nav className="hidden lg:flex items-center space-x-8">
|
|
<div className="flex items-center space-x-4">
|
|
<span className="text-sm font-medium text-gray-500"></span>
|
|
<div className="relative">
|
|
<select
|
|
value={currentCity || ''}
|
|
onChange={handleCityChange}
|
|
className="appearance-none bg-white pl-3 pr-8 py-2 text-sm font-medium rounded-md border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent cursor-pointer"
|
|
>
|
|
<option value="">All Cities</option>
|
|
{cities.map((city) => (
|
|
<option key={city} value={city}>
|
|
{city}
|
|
</option>
|
|
))}
|
|
</select>
|
|
<ChevronDown
|
|
size={16}
|
|
className="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-400 pointer-events-none"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="h-6 w-px bg-gray-200" />
|
|
|
|
<div className="flex items-center space-x-4 overflow-x-auto">
|
|
<span className="text-sm font-medium text-gray-500"></span>
|
|
<Link
|
|
to={currentCity ? `/?city=${currentCity}` : '/'}
|
|
className={`px-3 py-2 text-sm font-medium transition-colors whitespace-nowrap ${
|
|
!currentCategory
|
|
? 'text-blue-600 hover:text-blue-800'
|
|
: 'text-gray-600 hover:text-gray-900'
|
|
}`}
|
|
>
|
|
All Categories
|
|
</Link>
|
|
{categories.map((category) => (
|
|
<Link
|
|
key={category}
|
|
to={`/?category=${category}${currentCity ? `&city=${currentCity}` : ''}`}
|
|
className={`px-3 py-2 text-sm font-medium transition-colors whitespace-nowrap ${
|
|
currentCategory === category
|
|
? 'text-blue-600 hover:text-blue-800'
|
|
: 'text-gray-600 hover:text-gray-900'
|
|
}`}
|
|
>
|
|
{category}
|
|
</Link>
|
|
))}
|
|
</div>
|
|
</nav>
|
|
|
|
<div className="flex items-center space-x-4">
|
|
<form onSubmit={handleSearch} className="relative">
|
|
<input
|
|
type="text"
|
|
placeholder="Search..."
|
|
value={searchQuery}
|
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
onKeyPress={handleSearchKeyPress}
|
|
className="w-40 lg:w-60 pl-10 pr-4 py-2 text-sm border border-gray-300 rounded-full focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
/>
|
|
<button
|
|
type="submit"
|
|
className="absolute left-3 top-2.5 text-gray-400 hover:text-gray-600"
|
|
>
|
|
<Search size={18} />
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Mobile menu */}
|
|
<div
|
|
className={`lg:hidden ${
|
|
isMobileMenuOpen ? 'block' : 'hidden'
|
|
} border-b border-gray-200`}
|
|
>
|
|
<div className="px-2 pt-2 pb-3 space-y-1">
|
|
<div className="px-3 py-2">
|
|
<h3 className="text-sm font-medium text-gray-500 mb-2">City</h3>
|
|
<select
|
|
value={currentCity || ''}
|
|
onChange={handleCityChange}
|
|
className="w-full bg-white px-3 py-2 text-base font-medium rounded-md border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
>
|
|
<option value="">All Cities</option>
|
|
{cities.map((city) => (
|
|
<option key={city} value={city}>
|
|
{city}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
|
|
<div className="px-3 py-2">
|
|
<h3 className="text-sm font-medium text-gray-500 mb-2">Categories</h3>
|
|
<div className="space-y-1">
|
|
<Link
|
|
to={currentCity ? `/?city=${currentCity}` : '/'}
|
|
className={`block px-3 py-2 rounded-md text-base font-medium ${
|
|
!currentCategory
|
|
? 'bg-blue-50 text-blue-600'
|
|
: 'text-gray-600 hover:bg-gray-50'
|
|
}`}
|
|
>
|
|
All Categories
|
|
</Link>
|
|
{categories.map((category) => (
|
|
<Link
|
|
key={category}
|
|
to={`/?category=${category}${currentCity ? `&city=${currentCity}` : ''}`}
|
|
className={`block px-3 py-2 rounded-md text-base font-medium ${
|
|
currentCategory === category
|
|
? 'bg-blue-50 text-blue-600'
|
|
: 'text-gray-600 hover:bg-gray-50'
|
|
}`}
|
|
>
|
|
{category}
|
|
</Link>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
);
|
|
} |