more stuff

This commit is contained in:
2025-06-29 09:20:25 -04:00
parent 5cd7db4339
commit 6aa87ea11d
7 changed files with 1614 additions and 752 deletions
+45 -641
View File
@@ -8,640 +8,23 @@ import SearchInput from '@/components/SearchInput';
import ProductCard from '@/components/ProductCard';
import RestrictionAlert from '@/components/RestrictionAlert';
import Tooltip from '@/components/Tooltip';
// Sample firearm parts data
const parts = [
{
id: '1',
name: 'Faxon 16" Gunner Barrel - 5.56 NATO',
description: 'Lightweight, high-performance AR-15 barrel with 1:8 twist rate',
image_url: 'https://placehold.co/300x200/1f2937/ffffff?text=Barrel',
brand: {
id: 'b1',
name: 'Faxon Firearms',
},
category: {
id: 'c1',
name: 'Barrel',
},
restrictions: [],
offers: [
{
price: 189.99,
url: 'https://primaryarms.com/faxon-16-gunner-barrel',
vendor: {
name: 'Primary Arms',
},
},
],
},
{
id: '2',
name: 'BCM M4 Upper Receiver',
description: 'Forged upper receiver with M4 feed ramps and T-markings',
image_url: 'https://placehold.co/300x200/374151/ffffff?text=Upper+Receiver',
brand: {
id: 'b2',
name: 'BCM',
},
category: {
id: 'c2',
name: 'Upper Receiver',
},
restrictions: [],
offers: [
{
price: 129.99,
url: 'https://rainierarms.com/bcm-m4-upper',
vendor: {
name: 'Rainier Arms',
},
},
],
},
{
id: '3',
name: 'Aero Precision Lower Receiver',
description: 'Mil-spec forged lower receiver with trigger guard and threaded bolt catch',
image_url: 'https://placehold.co/300x200/4b5563/ffffff?text=Lower+Receiver',
brand: {
id: 'b3',
name: 'Aero Precision',
},
category: {
id: 'c3',
name: 'Lower Receiver',
},
restrictions: ['FFL_REQUIRED'],
offers: [
{
price: 89.99,
url: 'https://aeroprecisionusa.com/lower',
vendor: {
name: 'Aero Precision',
},
},
],
},
{
id: '4',
name: 'Toolcraft BCG - Nitride',
description: 'Mil-spec bolt carrier group with Carpenter 158 bolt and nitride finish',
image_url: 'https://placehold.co/300x200/6b7280/ffffff?text=BCG',
brand: {
id: 'b4',
name: 'Toolcraft',
},
category: {
id: 'c4',
name: 'BCG',
},
restrictions: [],
offers: [
{
price: 149.99,
url: 'https://wctoolcraft.com/bcg-nitride',
vendor: {
name: 'WC Toolcraft',
},
},
],
},
{
id: '5',
name: 'Geissele SSA-E Trigger',
description: 'Two-stage trigger with 3.5lb total pull weight and enhanced reliability',
image_url: 'https://placehold.co/300x200/1e40af/ffffff?text=Trigger',
brand: {
id: 'b5',
name: 'Geissele',
},
category: {
id: 'c5',
name: 'Trigger',
},
restrictions: [],
offers: [
{
price: 249.99,
url: 'https://geissele.com/ssa-e',
vendor: {
name: 'Geissele',
},
},
],
},
{
id: '6',
name: 'Magpul CTR Stock',
description: 'Collapsible stock with friction lock system and QD sling mount',
image_url: 'https://placehold.co/300x200/059669/ffffff?text=Stock',
brand: {
id: 'b6',
name: 'Magpul',
},
category: {
id: 'c6',
name: 'Stock',
},
restrictions: [],
offers: [
{
price: 69.99,
url: 'https://magpul.com/ctr-stock',
vendor: {
name: 'Magpul',
},
},
],
},
{
id: '7',
name: 'Radian Raptor Charging Handle',
description: 'Ambidextrous charging handle with oversized latches and smooth operation',
image_url: 'https://placehold.co/300x200/7c3aed/ffffff?text=Charging+Handle',
brand: {
id: 'b7',
name: 'Radian Weapons',
},
category: {
id: 'c7',
name: 'Charging Handle',
},
restrictions: [],
offers: [
{
price: 89.99,
url: 'https://radianweapons.com/raptor',
vendor: {
name: 'Radian Weapons',
},
},
],
},
{
id: '8',
name: 'BCM Gunfighter Handguard - 15" M-LOK',
description: 'Free-float handguard with M-LOK slots and integrated QD mounts',
image_url: 'https://placehold.co/300x200/dc2626/ffffff?text=Handguard',
brand: {
id: 'b2',
name: 'BCM',
},
category: {
id: 'c8',
name: 'Handguard',
},
restrictions: [],
offers: [
{
price: 199.99,
url: 'https://bravocompanyusa.com/handguard',
vendor: {
name: 'BCM',
},
},
],
},
{
id: '9',
name: 'SureFire WarComp Flash Hider',
description: 'Compensator/flash hider hybrid with suppressor mount capability',
image_url: 'https://placehold.co/300x200/ea580c/ffffff?text=Muzzle+Device',
brand: {
id: 'b8',
name: 'SureFire',
},
category: {
id: 'c9',
name: 'Muzzle Device',
},
restrictions: [],
offers: [
{
price: 159.99,
url: 'https://surefire.com/warcomp',
vendor: {
name: 'SureFire',
},
},
],
},
{
id: '10',
name: 'Aero Precision Gas Block - Low Profile',
description: 'Low-profile adjustable gas block for free-float handguards',
image_url: 'https://placehold.co/300x200/be185d/ffffff?text=Gas+Block',
brand: {
id: 'b3',
name: 'Aero Precision',
},
category: {
id: 'c10',
name: 'Gas Block',
},
restrictions: [],
offers: [
{
price: 49.99,
url: 'https://aeroprecisionusa.com/gas-block',
vendor: {
name: 'Aero Precision',
},
},
],
},
{
id: '11',
name: 'BCM Gas Tube - Mid Length',
description: 'Stainless steel gas tube for mid-length gas systems',
image_url: 'https://placehold.co/300x200/0891b2/ffffff?text=Gas+Tube',
brand: {
id: 'b2',
name: 'BCM',
},
category: {
id: 'c11',
name: 'Gas Tube',
},
restrictions: [],
offers: [
{
price: 19.99,
url: 'https://bravocompanyusa.com/gas-tube',
vendor: {
name: 'BCM',
},
},
],
},
{
id: '12',
name: 'Magpul MOE Pistol Grip',
description: 'Ergonomic pistol grip with storage compartment and enhanced texture',
image_url: 'https://placehold.co/300x200/166534/ffffff?text=Pistol+Grip',
brand: {
id: 'b6',
name: 'Magpul',
},
category: {
id: 'c12',
name: 'Pistol Grip',
},
restrictions: [],
offers: [
{
price: 24.99,
url: 'https://magpul.com/moe-grip',
vendor: {
name: 'Magpul',
},
},
],
},
{
id: '13',
name: 'BCM Buffer Tube - Mil-Spec',
description: 'Mil-spec buffer tube with proper castle nut and end plate',
image_url: 'https://placehold.co/300x200/92400e/ffffff?text=Buffer+Tube',
brand: {
id: 'b2',
name: 'BCM',
},
category: {
id: 'c13',
name: 'Buffer Tube',
},
restrictions: [],
offers: [
{
price: 44.99,
url: 'https://bravocompanyusa.com/buffer-tube',
vendor: {
name: 'BCM',
},
},
],
},
{
id: '14',
name: 'H2 Buffer Weight',
description: 'Heavy buffer weight for improved recoil management',
image_url: 'https://placehold.co/300x200/7c2d12/ffffff?text=Buffer',
brand: {
id: 'b9',
name: 'Spikes Tactical',
},
category: {
id: 'c14',
name: 'Buffer',
},
restrictions: [],
offers: [
{
price: 29.99,
url: 'https://spikestactical.com/h2-buffer',
vendor: {
name: 'Spikes Tactical',
},
},
],
},
{
id: '15',
name: 'Sprinco Blue Buffer Spring',
description: 'Enhanced buffer spring for improved reliability and reduced wear',
image_url: 'https://placehold.co/300x200/1e3a8a/ffffff?text=Buffer+Spring',
brand: {
id: 'b10',
name: 'Sprinco',
},
category: {
id: 'c15',
name: 'Buffer Spring',
},
restrictions: [],
offers: [
{
price: 19.99,
url: 'https://sprinco.com/blue-spring',
vendor: {
name: 'Sprinco',
},
},
],
},
{
id: '16',
name: 'Magpul PMAG 30-Round Magazine',
description: '30-round polymer magazine with anti-tilt follower and dust cover',
image_url: 'https://placehold.co/300x200/065f46/ffffff?text=Magazine',
brand: {
id: 'b6',
name: 'Magpul',
},
category: {
id: 'c16',
name: 'Magazine',
},
restrictions: ['STATE_RESTRICTIONS'],
offers: [
{
price: 14.99,
url: 'https://magpul.com/pmag',
vendor: {
name: 'Magpul',
},
},
],
},
{
id: '17',
name: 'Troy Industries BUIS - Folding',
description: 'Folding backup iron sights with micro-adjustable elevation',
image_url: 'https://placehold.co/300x200/581c87/ffffff?text=Sights',
brand: {
id: 'b11',
name: 'Troy Industries',
},
category: {
id: 'c17',
name: 'Sights',
},
restrictions: [],
offers: [
{
price: 129.99,
url: 'https://troyind.com/buis',
vendor: {
name: 'Troy Industries',
},
},
],
},
{
id: '18',
name: 'Aero Precision Trigger Guard',
description: 'Enhanced trigger guard with oversized opening for gloved hands',
image_url: 'https://placehold.co/300x200/991b1b/ffffff?text=Trigger+Guard',
brand: {
id: 'b3',
name: 'Aero Precision',
},
category: {
id: 'c18',
name: 'Trigger Guard',
},
restrictions: [],
offers: [
{
price: 12.99,
url: 'https://aeroprecisionusa.com/trigger-guard',
vendor: {
name: 'Aero Precision',
},
},
],
},
{
id: '19',
name: 'Larue MBT-2S Trigger',
description: 'Two-stage trigger with 4.5lb total pull weight and excellent value',
image_url: 'https://placehold.co/300x200/0c4a6e/ffffff?text=Trigger',
brand: {
id: 'b12',
name: 'LaRue Tactical',
},
category: {
id: 'c5',
name: 'Trigger',
},
restrictions: [],
offers: [
{
price: 89.99,
url: 'https://laruetactical.com/mbt-2s',
vendor: {
name: 'LaRue Tactical',
},
},
],
},
{
id: '20',
name: 'Daniel Defense 18" Barrel - 5.56 NATO',
description: 'Cold hammer forged barrel with 1:7 twist rate for precision shooting',
image_url: 'https://placehold.co/300x200/1f2937/ffffff?text=Barrel',
brand: {
id: 'b13',
name: 'Daniel Defense',
},
category: {
id: 'c1',
name: 'Barrel',
},
restrictions: [],
offers: [
{
price: 399.99,
url: 'https://danieldefense.com/18-barrel',
vendor: {
name: 'Daniel Defense',
},
},
],
},
{
id: '21',
name: 'BCM Complete Lower Receiver',
description: 'Complete lower receiver with BCM trigger, grip, and stock',
image_url: 'https://placehold.co/300x200/374151/ffffff?text=Lower+Receiver',
brand: {
id: 'b2',
name: 'BCM',
},
category: {
id: 'c3',
name: 'Lower Receiver',
},
restrictions: ['FFL_REQUIRED'],
offers: [
{
price: 449.99,
url: 'https://bravocompanyusa.com/complete-lower',
vendor: {
name: 'BCM',
},
},
],
},
{
id: '22',
name: 'Aimpoint PRO Red Dot Sight',
description: '2 MOA red dot sight with 2x magnification and 40mm objective',
image_url: 'https://placehold.co/300x200/4b5563/ffffff?text=Red+Dot+Sight',
brand: {
id: 'b14',
name: 'Aimpoint',
},
category: {
id: 'c17',
name: 'Sights',
},
restrictions: [],
offers: [
{
price: 449.99,
url: 'https://aimpoint.com/pro',
vendor: {
name: 'Aimpoint',
},
},
],
},
{
id: '23',
name: 'SilencerCo Omega 300 Suppressor',
description: 'Multi-caliber suppressor with quick-detach mount system',
image_url: 'https://placehold.co/300x200/7f1d1d/ffffff?text=Suppressor',
brand: {
id: 'b15',
name: 'SilencerCo',
},
category: {
id: 'c19',
name: 'Suppressor',
},
restrictions: ['NFA', 'SUPPRESSOR', 'SILENCERSHOP_PARTNER'],
offers: [
{
price: 899.99,
url: 'https://silencershop.com/omega-300',
vendor: {
name: 'SilencerShop',
},
},
],
},
{
id: '24',
name: 'Daniel Defense 10.3" SBR Barrel',
description: 'Short barrel rifle barrel with 1:7 twist rate for SBR builds',
image_url: 'https://placehold.co/300x200/1e293b/ffffff?text=SBR+Barrel',
brand: {
id: 'b13',
name: 'Daniel Defense',
},
category: {
id: 'c1',
name: 'Barrel',
},
restrictions: ['NFA', 'SBR', 'FFL_REQUIRED'],
offers: [
{
price: 299.99,
url: 'https://danieldefense.com/10-3-sbr-barrel',
vendor: {
name: 'Daniel Defense',
},
},
],
},
{
id: '25',
name: 'Dead Air Sandman-S Suppressor',
description: 'Rugged 30-caliber suppressor with E-Brake technology',
image_url: 'https://placehold.co/300x200/374151/ffffff?text=Suppressor',
brand: {
id: 'b16',
name: 'Dead Air',
},
category: {
id: 'c19',
name: 'Suppressor',
},
restrictions: ['NFA', 'SUPPRESSOR', 'SILENCERSHOP_PARTNER'],
offers: [
{
price: 799.99,
url: 'https://silencershop.com/sandman-s',
vendor: {
name: 'SilencerShop',
},
},
],
},
{
id: '26',
name: 'Magpul 60-Round Drum Magazine',
description: 'High-capacity drum magazine for AR-15 platform',
image_url: 'https://placehold.co/300x200/065f46/ffffff?text=Drum+Mag',
brand: {
id: 'b6',
name: 'Magpul',
},
category: {
id: 'c16',
name: 'Magazine',
},
restrictions: ['STATE_RESTRICTIONS', 'HIGH_CAPACITY'],
offers: [
{
price: 129.99,
url: 'https://magpul.com/drum-mag',
vendor: {
name: 'Magpul',
},
},
],
}
];
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(parts.map(part => part.category.name)))];
const brands = ['All', ...Array.from(new Set(parts.map(part => part.brand.name)))];
const vendors = ['All', ...Array.from(new Set(parts.flatMap(part => part.offers.map(offer => offer.vendor.name))))];
const restrictions = [...new Set(parts.flatMap(part => part.restrictions))];
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';
@@ -800,7 +183,7 @@ export default function Home() {
}, [searchParams]);
// Filter parts based on selected criteria
const filteredParts = parts.filter(part => {
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);
@@ -808,7 +191,16 @@ export default function Home() {
part.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
part.description.toLowerCase().includes(searchTerm.toLowerCase()) ||
part.brand.name.toLowerCase().includes(searchTerm.toLowerCase());
const matchesRestriction = !selectedRestriction || part.restrictions.includes(selectedRestriction);
// 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;
@@ -882,6 +274,16 @@ export default function Home() {
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 (
<main className="min-h-screen bg-neutral-50 dark:bg-neutral-900">
{/* Page Title */}
@@ -1019,7 +421,7 @@ export default function Home() {
label="Restriction"
value={selectedRestriction}
onChange={setSelectedRestriction}
options={['', ...restrictions]}
options={restrictionOptions}
placeholder="All restrictions"
/>
@@ -1047,7 +449,7 @@ export default function Home() {
{/* View Toggle and Results Count */}
<div className="flex justify-between items-center mb-6">
<div className="text-sm text-neutral-700 dark:text-neutral-300">
Showing {sortedParts.length} of {parts.length} parts
Showing {sortedParts.length} of {mockProducts.length} parts
{hasActiveFilters && (
<span className="ml-2 text-primary-600 dark:text-primary-400">
(filtered)
@@ -1076,7 +478,7 @@ export default function Home() {
</div>
{/* Restriction Alert Example */}
{sortedParts.some(part => part.restrictions.includes('NFA')) && (
{sortedParts.some(part => part.restrictions?.nfa) && (
<div className="mb-6">
<RestrictionAlert
type="warning"
@@ -1158,9 +560,11 @@ export default function Home() {
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button className="btn-primary text-xs">
View Details
</button>
<Link href={`/products/${part.id}`} legacyBehavior>
<a className="btn btn-primary btn-sm">
View Details
</a>
</Link>
</td>
</tr>
))}
@@ -1172,7 +576,7 @@ export default function Home() {
<div className="bg-neutral-50 dark:bg-neutral-700 px-6 py-3 border-t border-neutral-200 dark:border-neutral-600">
<div className="flex items-center justify-between">
<div className="text-sm text-neutral-700 dark:text-neutral-300">
Showing {sortedParts.length} of {parts.length} parts
Showing {sortedParts.length} of {mockProducts.length} parts
{hasActiveFilters && (
<span className="ml-2 text-primary-600 dark:text-primary-400">
(filtered)