'use client' import { useState, useMemo } from 'react' import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card' import { Input } from '@/components/ui/input' import { Button } from '@/components/ui/button' import { Download, Search, Filter, X, Coffee, Utensils, Package, Droplet, Eye } from 'lucide-react' import type { Manual, ManualGroup } from '@/lib/manuals-types' import { getManualUrl } from '@/lib/manuals-types' import { getMachineTypeInfo, getAllMachineTypeNames } from '@/lib/manuals-config' import { ManualViewer } from '@/components/manual-viewer' interface ManualsPageClientProps { manuals: Manual[] groupedManuals: ManualGroup[] manufacturers: string[] categories: string[] } export function ManualsPageClient({ manuals, groupedManuals, manufacturers, categories, }: ManualsPageClientProps) { const [searchTerm, setSearchTerm] = useState('') const [selectedManufacturer, setSelectedManufacturer] = useState('') const [selectedCategory, setSelectedCategory] = useState('') const [viewMode, setViewMode] = useState<'grouped' | 'list'>('grouped') const [viewingManual, setViewingManual] = useState<{ url: string; filename: string } | null>(null) // Filter manuals based on search and filters const filteredManuals = useMemo(() => { let filtered = manuals if (selectedManufacturer) { filtered = filtered.filter((m) => m.manufacturer === selectedManufacturer) } if (selectedCategory) { filtered = filtered.filter((m) => m.category === selectedCategory) } if (searchTerm) { const search = searchTerm.toLowerCase() filtered = filtered.filter( (m) => m.filename.toLowerCase().includes(search) || m.manufacturer.toLowerCase().includes(search) || m.category.toLowerCase().includes(search) ) } return filtered }, [manuals, searchTerm, selectedManufacturer, selectedCategory]) // Filter grouped manuals const filteredGroupedManuals = useMemo(() => { if (!selectedManufacturer && !selectedCategory && !searchTerm) { return groupedManuals } return groupedManuals .filter((group) => { if (selectedManufacturer && group.manufacturer !== selectedManufacturer) { return false } return true }) .map((group) => { const filteredCategories: { [key: string]: Manual[] } = {} for (const [category, categoryManuals] of Object.entries(group.categories)) { if (selectedCategory && category !== selectedCategory) { continue } const filtered = categoryManuals.filter((manual) => { if (searchTerm) { const search = searchTerm.toLowerCase() return ( manual.filename.toLowerCase().includes(search) || manual.manufacturer.toLowerCase().includes(search) || manual.category.toLowerCase().includes(search) ) } return true }) if (filtered.length > 0) { filteredCategories[category] = filtered } } return { ...group, categories: filteredCategories, } }) .filter((group) => Object.keys(group.categories).length > 0) }, [groupedManuals, selectedManufacturer, selectedCategory, searchTerm]) const hasActiveFilters = selectedManufacturer || selectedCategory || searchTerm const clearFilters = () => { setSearchTerm('') setSelectedManufacturer('') setSelectedCategory('') } const formatFileSize = (bytes?: number): string => { if (!bytes) return 'Unknown size' if (bytes < 1024) return `${bytes} B` if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB` return `${(bytes / (1024 * 1024)).toFixed(1)} MB` } // Organize categories by machine type first, then others const organizeCategories = (categories: { [key: string]: Manual[] }) => { const machineTypes = getAllMachineTypeNames() const machineTypeCategories: { [key: string]: Manual[] } = {} const otherCategories: { [key: string]: Manual[] } = {} for (const [category, manuals] of Object.entries(categories)) { if (machineTypes.includes(category)) { machineTypeCategories[category] = manuals } else { otherCategories[category] = manuals } } // Sort machine types by priority order const sortedMachineTypes = machineTypes .filter((type) => machineTypeCategories[type]) .map((type) => [type, machineTypeCategories[type]] as [string, Manual[]]) // Sort other categories alphabetically const sortedOthers = Object.entries(otherCategories).sort(([a], [b]) => a.localeCompare(b) ) return { machineTypes: sortedMachineTypes, others: sortedOthers } } // Get icon for machine type const getCategoryIcon = (category: string) => { const machineType = getMachineTypeInfo(category) if (!machineType) return null switch (category) { case 'Coffee': return case 'Food': return case 'Beverage': return case 'Snack': return default: return null } } // Get badge color for category const getCategoryBadgeClass = (category: string): string => { const machineType = getMachineTypeInfo(category) const categoryLower = category.toLowerCase() // Check for common category patterns if (categoryLower.includes('snack')) { return 'bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200' } if (categoryLower.includes('beverage') || categoryLower.includes('drink')) { return 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200' } if (categoryLower.includes('frozen')) { return 'bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-200' } if (categoryLower.includes('combo')) { return 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200' } if (categoryLower.includes('coffee') || categoryLower.includes('hot')) { return 'bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-200' } if (categoryLower.includes('food')) { return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200' } if (categoryLower.includes('bulk')) { return 'bg-pink-100 text-pink-800 dark:bg-pink-900 dark:text-pink-200' } if (categoryLower.includes('ice') || categoryLower.includes('cream')) { return 'bg-cyan-100 text-cyan-800 dark:bg-cyan-900 dark:text-cyan-200' } if (categoryLower.includes('service') || categoryLower.includes('repair')) { return 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200' } if (categoryLower.includes('parts')) { return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200' } if (categoryLower.includes('operator') || categoryLower.includes('user')) { return 'bg-teal-100 text-teal-800 dark:bg-teal-900 dark:text-teal-200' } if (categoryLower.includes('installation') || categoryLower.includes('setup')) { return 'bg-lime-100 text-lime-800 dark:bg-lime-900 dark:text-lime-200' } // Fallback for machine types if (machineType) { switch (category) { case 'Snack': return 'bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200' case 'Beverage': return 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200' case 'Combo': return 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-200' case 'Coffee': return 'bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-200' case 'Food': return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200' case 'Bulk': return 'bg-pink-100 text-pink-800 dark:bg-pink-900 dark:text-pink-200' case 'Ice Cream': return 'bg-cyan-100 text-cyan-800 dark:bg-cyan-900 dark:text-cyan-200' default: return 'bg-muted text-muted-foreground' } } return 'bg-muted text-muted-foreground' } return (
{/* Search and Filter Controls */}
{/* Search Bar */}
setSearchTerm(e.target.value)} className="pl-10" />
{/* Filters */}
Filters:
{hasActiveFilters && ( )}
{/* View Mode Toggle */}
View:
{/* Results Count */}
Showing {filteredManuals.length} of {manuals.length}{' '} manuals
{/* Manuals Display */} {filteredManuals.length === 0 ? (

No manuals found matching your criteria. Try adjusting your filters.

) : viewMode === 'grouped' ? ( /* Grouped View */
{filteredGroupedManuals.map((group) => { const organized = organizeCategories(group.categories) return (

{group.manufacturer}

{/* Machine Type Categories First */} {organized.machineTypes.length > 0 && (
{organized.machineTypes.map(([category, categoryManuals]) => { const machineTypeInfo = getMachineTypeInfo(category) const icon = getCategoryIcon(category) return (
{icon && {icon}}

{category}

{categoryManuals.length} {categoryManuals.length === 1 ? 'manual' : 'manuals'} {machineTypeInfo && ( {machineTypeInfo.description} )}
{categoryManuals.map((manual) => ( {manual.filename.replace(/\.pdf$/i, '')}
{manual.category}
{manual.size && (

Size: {formatFileSize(manual.size)}

)}
))}
) })}
)} {/* Other Categories (Model Numbers, Document Types, etc.) */} {organized.others.length > 0 && (
{organized.machineTypes.length > 0 && (

Models & Other Documents

)} {organized.others.map(([category, categoryManuals]) => (

{category}

({categoryManuals.length} {categoryManuals.length === 1 ? 'manual' : 'manuals'})
{categoryManuals.map((manual) => ( {manual.filename.replace(/\.pdf$/i, '')}
{manual.category}
{manual.size && (

Size: {formatFileSize(manual.size)}

)}
))}
))}
)}
) })}
) : ( /* List View */
{filteredManuals.map((manual) => ( {manual.filename.replace(/\.pdf$/i, '')}
{manual.category}

Manufacturer: {manual.manufacturer}

{manual.size && (

Size: {formatFileSize(manual.size)}

)}
))}
)} {/* PDF Viewer Modal */} {viewingManual && ( setViewingManual(null)} /> )}
) }