import React, { useState, useEffect } from 'react'; import { PlusIcon, MagnifyingGlassIcon, FunnelIcon, WrenchScrewdriverIcon, TrashIcon, PencilIcon, EyeIcon } from '@heroicons/react/24/outline'; import { equipmentAPI, nozzlesAPI } from '../../services/api'; import LoadingSpinner from '../../components/UI/LoadingSpinner'; import toast from 'react-hot-toast'; const Equipment = () => { const [equipment, setEquipment] = useState([]); const [categories, setCategories] = useState([]); const [equipmentTypes, setEquipmentTypes] = useState([]); const [loading, setLoading] = useState(true); const [showCreateForm, setShowCreateForm] = useState(false); const [showEditForm, setShowEditForm] = useState(false); const [editingEquipment, setEditingEquipment] = useState(null); const [selectedCategory, setSelectedCategory] = useState(''); const [searchTerm, setSearchTerm] = useState(''); const [showInactive, setShowInactive] = useState(false); const [activeTab, setActiveTab] = useState('all'); const [showPumpAssignments, setShowPumpAssignments] = useState(false); const [showNozzleConfigs, setShowNozzleConfigs] = useState(false); const [selectedSprayerForPump, setSelectedSprayerForPump] = useState(null); const [selectedSprayerForNozzles, setSelectedSprayerForNozzles] = useState(null); useEffect(() => { fetchData(); }, []); const fetchData = async () => { try { setLoading(true); const [equipmentResponse, categoriesResponse, typesResponse] = await Promise.all([ equipmentAPI.getAll({ category_id: selectedCategory, is_active: !showInactive }), equipmentAPI.getCategories(), equipmentAPI.getTypes() ]); setEquipment(equipmentResponse.data.data.equipment || []); setCategories(categoriesResponse.data.data.categories || []); setEquipmentTypes(typesResponse.data.data.equipmentTypes || []); } catch (error) { console.error('Failed to fetch equipment:', error); toast.error('Failed to load equipment'); setEquipment([]); setCategories([]); setEquipmentTypes([]); } finally { setLoading(false); } }; const handleSearch = (e) => { setSearchTerm(e.target.value); }; const handleFilterChange = () => { fetchData(); }; const handleCreateEquipment = async (equipmentData) => { try { await equipmentAPI.create(equipmentData); toast.success('Equipment created successfully!'); setShowCreateForm(false); fetchData(); } catch (error) { console.error('Failed to create equipment:', error); toast.error('Failed to create equipment'); } }; const handleEditEquipment = (equipment) => { setEditingEquipment(equipment); setShowEditForm(true); }; const handleUpdateEquipment = async (equipmentData) => { try { await equipmentAPI.update(editingEquipment.id, equipmentData); toast.success('Equipment updated successfully!'); setShowEditForm(false); setEditingEquipment(null); fetchData(); } catch (error) { console.error('Failed to update equipment:', error); toast.error('Failed to update equipment'); } }; const handleDeleteEquipment = async (equipmentId) => { if (window.confirm('Are you sure you want to delete this equipment?')) { try { await equipmentAPI.delete(equipmentId); toast.success('Equipment deleted successfully'); fetchData(); } catch (error) { console.error('Failed to delete equipment:', error); toast.error('Failed to delete equipment'); } } }; const handleManagePumpAssignments = (sprayer) => { setSelectedSprayerForPump(sprayer); setShowPumpAssignments(true); }; const handleManageNozzleConfigs = (sprayer) => { setSelectedSprayerForNozzles(sprayer); setShowNozzleConfigs(true); }; // Filter equipment based on search term and active tab const filteredEquipment = equipment.filter(item => { const matchesSearch = searchTerm === '' || item.customName?.toLowerCase().includes(searchTerm.toLowerCase()) || item.typeName?.toLowerCase().includes(searchTerm.toLowerCase()) || item.manufacturer?.toLowerCase().includes(searchTerm.toLowerCase()) || item.model?.toLowerCase().includes(searchTerm.toLowerCase()); if (activeTab === 'all') return matchesSearch; return matchesSearch && item.categoryName?.toLowerCase() === activeTab.toLowerCase(); }); // Get unique category names for tabs const categoryTabs = ['all', ...new Set(equipment.map(item => item.categoryName).filter(Boolean))]; const EquipmentCard = ({ item }) => (

{item.customName || item.typeName}

{item.manufacturer && item.model && (

{item.manufacturer} {item.model}

)} {item.categoryName} {!item.isActive && ( Inactive )}
{item.categoryName === 'Sprayer' && ( <> )}
{/* Equipment-specific details */}
{renderEquipmentDetails(item)}
{item.notes && (

Notes: {item.notes}

)} {item.purchaseDate && (

Purchased: {new Date(item.purchaseDate).toLocaleDateString()}

)}
); const renderEquipmentDetails = (item) => { switch (item.categoryName?.toLowerCase()) { case 'mower': return ( <> {item.mowerStyle &&

Style: {item.mowerStyle.replace('_', ' ')}

} {item.cuttingWidthInches &&

Cutting Width: {item.cuttingWidthInches}"

} {item.engineHp &&

Engine: {item.engineHp} HP

} {item.fuelType &&

Fuel: {item.fuelType}

} ); case 'spreader': return ( <> {item.spreaderType &&

Type: {item.spreaderType.replace('_', ' ')}

} {item.capacityLbs &&

Capacity: {item.capacityLbs} lbs

} {item.spreadWidth &&

Spread Width: {item.spreadWidth} ft

} ); case 'sprayer': return ( <> {item.sprayerType &&

Type: {item.sprayerType.replace('_', ' ')}

} {item.tankSizeGallons &&

Tank Size: {item.tankSizeGallons} gal

} {item.sprayWidthFeet &&

Spray Width: {item.sprayWidthFeet} ft

} {item.pumpGpm &&

Pump: {item.pumpGpm} GPM

} {item.boomSections &&

Boom Sections: {item.boomSections}

} ); case 'pump': return ( <> {item.pumpType &&

Type: {item.pumpType}

} {item.maxGpm &&

Max Flow: {item.maxGpm} GPM

} {item.maxPsi &&

Max Pressure: {item.maxPsi} PSI

} {item.powerSource &&

Power: {item.powerSource}

} ); case 'nozzle': return ( <> {item.orificeSize &&

Orifice: {item.orificeSize}

} {item.sprayAngle &&

Spray Angle: {item.sprayAngle}°

} {item.flowRateGpm &&

Flow Rate: {item.flowRateGpm} GPM

} {item.dropletSize &&

Droplet Size: {item.dropletSize}

} {item.sprayPattern &&

Pattern: {item.sprayPattern.replace('_', ' ')}

} {item.quantityOwned &&

Quantity: {item.quantityOwned}

} ); default: return ( <> {item.toolType &&

Type: {item.toolType.replace('_', ' ')}

} {item.workingWidthInches &&

Working Width: {item.workingWidthInches}"

} ); } }; const getCategoryColor = (categoryName) => { const colors = { 'Mower': 'bg-green-100 text-green-800', 'Spreader': 'bg-orange-100 text-orange-800', 'Sprayer': 'bg-blue-100 text-blue-800', 'Nozzle': 'bg-teal-100 text-teal-800', 'Pump': 'bg-purple-100 text-purple-800', 'Aerator': 'bg-yellow-100 text-yellow-800', 'Dethatcher': 'bg-red-100 text-red-800', 'Scarifier': 'bg-pink-100 text-pink-800', 'Trimmer': 'bg-indigo-100 text-indigo-800', }; return colors[categoryName] || 'bg-gray-100 text-gray-800'; }; if (loading) { return (
); } return (

Equipment

Manage your lawn care equipment inventory

{/* Search and Filters */}
{/* Search */}
{/* Category Filter */}
{/* Show Inactive Toggle */}
{/* Category Tabs */}
{/* Equipment Grid */} {filteredEquipment.length === 0 ? (

No Equipment Found

{searchTerm || selectedCategory ? 'Try adjusting your search or filters' : 'Start building your equipment inventory' }

{!searchTerm && !selectedCategory && ( )}
) : (
{filteredEquipment.map((item) => ( ))}
)} {/* Create Equipment Form Modal */} {showCreateForm && ( setShowCreateForm(false)} /> )} {/* Edit Equipment Form Modal */} {showEditForm && editingEquipment && ( { setShowEditForm(false); setEditingEquipment(null); }} /> )} {/* Pump Assignment Modal */} {showPumpAssignments && selectedSprayerForPump && ( e.categoryName === 'Pump')} onClose={() => { setShowPumpAssignments(false); setSelectedSprayerForPump(null); fetchData(); }} /> )} {/* Nozzle Configuration Modal */} {showNozzleConfigs && selectedSprayerForNozzles && ( { setShowNozzleConfigs(false); setSelectedSprayerForNozzles(null); fetchData(); }} /> )}
); }; // Equipment Form Modal Component (Create/Edit) const EquipmentFormModal = ({ isEdit, equipment, categories, equipmentTypes, onSubmit, onCancel }) => { const [formData, setFormData] = useState({ equipmentTypeId: equipment?.equipmentTypeId || '', categoryId: equipment?.categoryId || '', customName: equipment?.customName || '', manufacturer: equipment?.manufacturer || '', model: equipment?.model || '', // Spreader fields capacityLbs: equipment?.capacityLbs || '', spreaderType: equipment?.spreaderType || 'walk_behind', spreadWidth: equipment?.spreadWidth || '', // Sprayer fields tankSizeGallons: equipment?.tankSizeGallons || '', sprayerType: equipment?.sprayerType || 'walk_behind', sprayWidthFeet: equipment?.sprayWidthFeet || '', pumpGpm: equipment?.pumpGpm || '', pumpPsi: equipment?.pumpPsi || '', boomSections: equipment?.boomSections || '', // Mower fields mowerStyle: equipment?.mowerStyle || 'push', cuttingWidthInches: equipment?.cuttingWidthInches || '', engineHp: equipment?.engineHp || '', fuelType: equipment?.fuelType || '', // Tool fields toolType: equipment?.toolType || 'walk_behind', workingWidthInches: equipment?.workingWidthInches || '', // Pump fields pumpType: equipment?.pumpType || '', maxGpm: equipment?.maxGpm || '', maxPsi: equipment?.maxPsi || '', powerSource: equipment?.powerSource || '', // Nozzle fields orificeSize: equipment?.orificeSize || '', sprayAngle: equipment?.sprayAngle || '', flowRateGpm: equipment?.flowRateGpm || '', dropletSize: equipment?.dropletSize || '', sprayPattern: equipment?.sprayPattern || '', pressureRangePsi: equipment?.pressureRangePsi || '', threadSize: equipment?.threadSize || '', material: equipment?.material || '', colorCode: equipment?.colorCode || '', quantityOwned: equipment?.quantityOwned || 1, // General fields purchaseDate: equipment?.purchaseDate || '', purchasePrice: equipment?.purchasePrice || '', notes: equipment?.notes || '', isActive: equipment?.isActive !== undefined ? equipment.isActive : true }); const selectedCategory = categories.find(cat => cat.id === parseInt(formData.categoryId)); const handleSubmit = (e) => { e.preventDefault(); if (!formData.categoryId && !formData.equipmentTypeId) { toast.error('Please select a category or equipment type'); return; } if (!formData.customName && !formData.equipmentTypeId) { toast.error('Please enter a name or select an equipment type'); return; } const submitData = { equipmentTypeId: formData.equipmentTypeId ? parseInt(formData.equipmentTypeId) : null, categoryId: formData.categoryId ? parseInt(formData.categoryId) : null, customName: formData.customName || null, manufacturer: formData.manufacturer || null, model: formData.model || null, capacityLbs: formData.capacityLbs ? parseFloat(formData.capacityLbs) : null, spreaderType: formData.spreaderType || null, spreadWidth: formData.spreadWidth ? parseFloat(formData.spreadWidth) : null, tankSizeGallons: formData.tankSizeGallons ? parseFloat(formData.tankSizeGallons) : null, sprayerType: formData.sprayerType || null, sprayWidthFeet: formData.sprayWidthFeet ? parseFloat(formData.sprayWidthFeet) : null, pumpGpm: formData.pumpGpm ? parseFloat(formData.pumpGpm) : null, pumpPsi: formData.pumpPsi ? parseFloat(formData.pumpPsi) : null, boomSections: formData.boomSections ? parseInt(formData.boomSections) : null, mowerStyle: formData.mowerStyle || null, cuttingWidthInches: formData.cuttingWidthInches ? parseFloat(formData.cuttingWidthInches) : null, engineHp: formData.engineHp ? parseFloat(formData.engineHp) : null, fuelType: formData.fuelType || null, toolType: formData.toolType || null, workingWidthInches: formData.workingWidthInches ? parseFloat(formData.workingWidthInches) : null, pumpType: formData.pumpType || null, maxGpm: formData.maxGpm ? parseFloat(formData.maxGpm) : null, maxPsi: formData.maxPsi ? parseFloat(formData.maxPsi) : null, powerSource: formData.powerSource || null, // Nozzle fields orificeSize: formData.orificeSize || null, sprayAngle: formData.sprayAngle ? parseInt(formData.sprayAngle) : null, flowRateGpm: formData.flowRateGpm ? parseFloat(formData.flowRateGpm) : null, dropletSize: formData.dropletSize || null, sprayPattern: formData.sprayPattern || null, pressureRangePsi: formData.pressureRangePsi || null, threadSize: formData.threadSize || null, material: formData.material || null, colorCode: formData.colorCode || null, quantityOwned: formData.quantityOwned ? parseInt(formData.quantityOwned) : null, purchaseDate: formData.purchaseDate || null, purchasePrice: formData.purchasePrice ? parseFloat(formData.purchasePrice) : null, notes: formData.notes || null, isActive: formData.isActive }; onSubmit(submitData); }; const renderCategorySpecificFields = () => { const categoryName = selectedCategory?.name?.toLowerCase(); switch (categoryName) { case 'mower': return ( <>
setFormData({ ...formData, cuttingWidthInches: e.target.value })} placeholder="21" />
setFormData({ ...formData, engineHp: e.target.value })} placeholder="6.5" />
); case 'spreader': return ( <>
setFormData({ ...formData, capacityLbs: e.target.value })} placeholder="50" />
setFormData({ ...formData, spreadWidth: e.target.value })} placeholder="8" />
); case 'sprayer': return ( <>
setFormData({ ...formData, tankSizeGallons: e.target.value })} placeholder="25" />
setFormData({ ...formData, sprayWidthFeet: e.target.value })} placeholder="10" />
setFormData({ ...formData, pumpGpm: e.target.value })} placeholder="2.5" />
setFormData({ ...formData, pumpPsi: e.target.value })} placeholder="60" />
setFormData({ ...formData, boomSections: e.target.value })} placeholder="3" />
); case 'pump': return ( <>
setFormData({ ...formData, pumpType: e.target.value })} placeholder="Centrifugal, Diaphragm, etc." />
setFormData({ ...formData, maxGpm: e.target.value })} placeholder="10" />
setFormData({ ...formData, maxPsi: e.target.value })} placeholder="100" />
); case 'nozzle': return ( <>
setFormData({ ...formData, orificeSize: e.target.value })} placeholder="02, 03, 04..." required />
setFormData({ ...formData, sprayAngle: e.target.value })} placeholder="80, 110..." required />
setFormData({ ...formData, flowRateGpm: e.target.value })} placeholder="0.20, 0.30..." required />
setFormData({ ...formData, pressureRangePsi: e.target.value })} placeholder="15-60" />
setFormData({ ...formData, threadSize: e.target.value })} placeholder="1/4", 3/8"..." />
setFormData({ ...formData, colorCode: e.target.value })} placeholder="Yellow, Blue, Red..." />
setFormData({ ...formData, quantityOwned: e.target.value })} placeholder="1" />
); default: return ( <>
setFormData({ ...formData, workingWidthInches: e.target.value })} placeholder="18" />
); } }; return (

{isEdit ? 'Edit Equipment' : 'Add New Equipment'}

{/* Basic Information */}
setFormData({ ...formData, customName: e.target.value })} placeholder="My Lawn Mower, Office Spreader, etc." required={!formData.equipmentTypeId} />
setFormData({ ...formData, manufacturer: e.target.value })} placeholder="Toro, John Deere, etc." />
setFormData({ ...formData, model: e.target.value })} placeholder="Model number" />
{/* Category-specific fields */} {formData.categoryId && renderCategorySpecificFields()} {/* Purchase Information */}
setFormData({ ...formData, purchaseDate: e.target.value })} />
setFormData({ ...formData, purchasePrice: e.target.value })} placeholder="0.00" />
{/* Notes and Status */}