'use client'; import { useState, useEffect } from 'react'; import { useSearchParams } from 'next/navigation'; import { Listbox, Transition } from '@headlessui/react'; import { ChevronUpDownIcon, CheckIcon, XMarkIcon } from '@heroicons/react/20/solid'; import SearchInput from '@/components/SearchInput'; import ProductCard from '@/components/ProductCard'; import RestrictionAlert from '@/components/RestrictionAlert'; import Tooltip from '@/components/Tooltip'; import Link from 'next/link'; import { mockProducts } from '@/mock/product'; import type { Product } from '@/mock/product'; // Extract unique values for dropdowns const categories = ['All', ...Array.from(new Set(mockProducts.map(part => part.category.name)))]; const brands = ['All', ...Array.from(new Set(mockProducts.map(part => part.brand.name)))]; const vendors = ['All', ...Array.from(new Set(mockProducts.flatMap(part => part.offers.map(offer => offer.vendor.name))))]; // Restrictions for filter dropdown const restrictionOptions = [ '', 'NFA', 'SBR', 'SUPPRESSOR', 'STATE_RESTRICTIONS', ]; type SortField = 'name' | 'category' | 'price'; type SortDirection = 'asc' | 'desc'; // Restriction indicator component const RestrictionBadge = ({ restriction }: { restriction: string }) => { const restrictionConfig = { NFA: { label: 'NFA', color: 'bg-red-600 text-white', icon: '🔒', tooltip: 'National Firearms Act - Requires special registration' }, SBR: { label: 'SBR', color: 'bg-orange-600 text-white', icon: '📏', tooltip: 'Short Barrel Rifle - Requires NFA registration' }, SUPPRESSOR: { label: 'Suppressor', color: 'bg-purple-600 text-white', icon: '🔇', tooltip: 'Sound Suppressor - Requires NFA registration' }, FFL_REQUIRED: { label: 'FFL', color: 'bg-blue-600 text-white', icon: '🏪', tooltip: 'Federal Firearms License required for purchase' }, STATE_RESTRICTIONS: { label: 'State', color: 'bg-yellow-600 text-black', icon: '🗺️', tooltip: 'State-specific restrictions may apply' }, HIGH_CAPACITY: { label: 'High Cap', color: 'bg-pink-600 text-white', icon: '🥁', tooltip: 'High capacity magazine - check local laws' }, SILENCERSHOP_PARTNER: { label: 'SilencerShop', color: 'bg-green-600 text-white', icon: '🤝', tooltip: 'Available through SilencerShop partnership' } }; const config = restrictionConfig[restriction as keyof typeof restrictionConfig]; if (!config) return null; return (
{config.icon} {config.label}
); }; // Tailwind UI Dropdown Component const Dropdown = ({ label, value, onChange, options, placeholder = "Select option" }: { label: string; value: string; onChange: (value: string) => void; options: string[]; placeholder?: string; }) => { return (
{label} {value || placeholder} {options.map((option, optionIdx) => ( `relative cursor-default select-none py-2 pl-10 pr-4 ${ active ? 'bg-primary-100 dark:bg-primary-900 text-primary-900 dark:text-primary-100' : 'text-neutral-900 dark:text-white' }` } value={option} > {({ selected }) => ( <> {option} {selected ? ( ) : null} )} ))}
); }; export default function Home() { const searchParams = useSearchParams(); const [selectedCategory, setSelectedCategory] = useState('All'); const [selectedBrand, setSelectedBrand] = useState('All'); const [selectedVendor, setSelectedVendor] = useState('All'); const [priceRange, setPriceRange] = useState(''); const [searchTerm, setSearchTerm] = useState(''); const [selectedRestriction, setSelectedRestriction] = useState(''); const [sortField, setSortField] = useState('name'); const [sortDirection, setSortDirection] = useState('asc'); const [viewMode, setViewMode] = useState<'table' | 'cards'>('table'); // Read category from URL parameter on page load useEffect(() => { const categoryParam = searchParams.get('category'); if (categoryParam && categories.includes(categoryParam)) { setSelectedCategory(categoryParam); } }, [searchParams]); // Filter parts based on selected criteria const filteredParts = mockProducts.filter(part => { const matchesCategory = selectedCategory === 'All' || part.category.name === selectedCategory; const matchesBrand = selectedBrand === 'All' || part.brand.name === selectedBrand; const matchesVendor = selectedVendor === 'All' || part.offers.some(offer => offer.vendor.name === selectedVendor); const matchesSearch = !searchTerm || part.name.toLowerCase().includes(searchTerm.toLowerCase()) || part.description.toLowerCase().includes(searchTerm.toLowerCase()) || part.brand.name.toLowerCase().includes(searchTerm.toLowerCase()); // Restriction filter logic let matchesRestriction = true; if (selectedRestriction) { if (selectedRestriction === 'NFA') matchesRestriction = !!part.restrictions?.nfa; else if (selectedRestriction === 'SBR') matchesRestriction = !!part.restrictions?.sbr; else if (selectedRestriction === 'SUPPRESSOR') matchesRestriction = !!part.restrictions?.suppressor; else if (selectedRestriction === 'STATE_RESTRICTIONS') matchesRestriction = !!(part.restrictions?.stateRestrictions && part.restrictions.stateRestrictions.length > 0); else matchesRestriction = false; } // Price range filtering let matchesPrice = true; if (priceRange) { const lowestPrice = Math.min(...part.offers.map(offer => offer.price)); switch (priceRange) { case 'under-100': matchesPrice = lowestPrice < 100; break; case '100-300': matchesPrice = lowestPrice >= 100 && lowestPrice <= 300; break; case '300-500': matchesPrice = lowestPrice > 300 && lowestPrice <= 500; break; case 'over-500': matchesPrice = lowestPrice > 500; break; } } return matchesCategory && matchesBrand && matchesVendor && matchesSearch && matchesPrice && matchesRestriction; }); // Sort parts const sortedParts = [...filteredParts].sort((a, b) => { let aValue: any, bValue: any; if (sortField === 'price') { aValue = Math.min(...a.offers.map(offer => offer.price)); bValue = Math.min(...b.offers.map(offer => offer.price)); } else if (sortField === 'category') { aValue = a.category.name.toLowerCase(); bValue = b.category.name.toLowerCase(); } else { aValue = a.name.toLowerCase(); bValue = b.name.toLowerCase(); } if (sortDirection === 'asc') { return aValue > bValue ? 1 : -1; } else { return aValue < bValue ? 1 : -1; } }); const handleSort = (field: SortField) => { if (sortField === field) { setSortDirection(sortDirection === 'asc' ? 'desc' : 'asc'); } else { setSortField(field); setSortDirection('asc'); } }; const getSortIcon = (field: SortField) => { if (sortField !== field) { return '↕️'; } return sortDirection === 'asc' ? '↑' : '↓'; }; const clearFilters = () => { setSelectedCategory('All'); setSelectedBrand('All'); setSelectedVendor('All'); setSearchTerm(''); setPriceRange(''); setSelectedRestriction(''); }; const hasActiveFilters = selectedCategory !== 'All' || selectedBrand !== 'All' || selectedVendor !== 'All' || searchTerm || priceRange || selectedRestriction; // RestrictionBadge for table view (show NFA/SBR/Suppressor/State) const getRestrictionFlags = (restrictions?: Product['restrictions']) => { const flags: string[] = []; if (restrictions?.nfa) flags.push('NFA'); if (restrictions?.sbr) flags.push('SBR'); if (restrictions?.suppressor) flags.push('SUPPRESSOR'); if (restrictions?.stateRestrictions && restrictions.stateRestrictions.length > 0) flags.push('STATE_RESTRICTIONS'); return flags; }; return (
{/* Page Title */}

Parts Catalog {selectedCategory !== 'All' && ( - {selectedCategory} )}

{selectedCategory !== 'All' ? `Showing ${selectedCategory} parts for your build` : 'Browse and filter firearm parts for your build' }

{/* Search and Filters */}
{/* Search Row */}
{/* Filters Row */}
{/* Category Dropdown */} {/* Brand Dropdown */} {/* Vendor Dropdown */} {/* Price Range */}
Price Range {priceRange === '' ? 'Select price range' : priceRange === 'under-100' ? 'Under $100' : priceRange === '100-300' ? '$100 - $300' : priceRange === '300-500' ? '$300 - $500' : priceRange === 'over-500' ? '$500+' : priceRange} {[ { value: '', label: 'Select price range' }, { value: 'under-100', label: 'Under $100' }, { value: '100-300', label: '$100 - $300' }, { value: '300-500', label: '$300 - $500' }, { value: 'over-500', label: '$500+' } ].map((option, optionIdx) => ( `relative cursor-default select-none py-2 pl-10 pr-4 ${ active ? 'bg-primary-100 dark:bg-primary-900 text-primary-900 dark:text-primary-100' : 'text-neutral-900 dark:text-white' }` } value={option.value} > {({ selected }) => ( <> {option.label} {selected ? ( ) : null} )} ))}
{/* Restriction Filter */} {/* Clear Filters */}
{/* Parts Display */}
{/* View Toggle and Results Count */}
Showing {sortedParts.length} of {mockProducts.length} parts {hasActiveFilters && ( (filtered) )}
{/* View Toggle */}
View:
{/* Restriction Alert Example */} {sortedParts.some(part => part.restrictions?.nfa) && (
)} {/* Table View */} {viewMode === 'table' && (
{sortedParts.map((part) => ( ))}
Category handleSort('name')} >
Name {getSortIcon('name')}
Brand Description handleSort('price')} >
Price {getSortIcon('price')}
Actions
{part.category.name}
{part.name}
{part.brand.name}
{part.brand.name}
{part.description}
${Math.min(...part.offers.map(offer => offer.price)).toFixed(2)}
View Details
{/* Table Footer */}
Showing {sortedParts.length} of {mockProducts.length} parts {hasActiveFilters && ( (filtered) )}
Total Value: ${sortedParts.reduce((sum, part) => sum + Math.min(...part.offers.map(offer => offer.price)), 0).toFixed(2)}
)} {/* Card View */} {viewMode === 'cards' && (
{sortedParts.map((part) => ( ))}
)}
{/* Compact Restriction Legend */}
Restrictions:
🔒NFA
National Firearms Act
📏SBR
Short Barrel Rifle
🔇Suppressor
Sound Suppressor
🏪FFL
FFL Required
🗺️State
State Restrictions
🥁High Cap
High Capacity
🤝SilencerShop
SilencerShop Partner
); }