import { useState, useEffect, useCallback } from 'react' import { useAlert } from '../context/AlertContext' import { useAuth } from '../context/AuthContext' import Forbidden from '../components/Forbidden' import { motion, AnimatePresence } from 'framer-motion' import ConfirmModal from '../components/ConfirmModal' import useModalLock from '../hooks/useModalLock' import { formatKm } from '../utils/formatters' import apiFetch from '../utils/api' import FormField from '../components/FormField' const API_BASE = '/api/admin' interface Vehicle { id: number spz: string name: string brand?: string model?: string initial_km: number current_km: number trip_count: number is_active: boolean | number } interface VehicleForm { spz: string name: string brand: string model: string initial_km: number is_active: boolean } export default function Vehicles() { const alert = useAlert() const { hasPermission } = useAuth() const [loading, setLoading] = useState(true) const [vehicles, setVehicles] = useState([]) const [showModal, setShowModal] = useState(false) const [editingVehicle, setEditingVehicle] = useState(null) const [form, setForm] = useState({ spz: '', name: '', brand: '', model: '', initial_km: 0, is_active: true }) const [errors, setErrors] = useState>({}) const [deleteConfirm, setDeleteConfirm] = useState<{ show: boolean; vehicle: Vehicle | null }>({ show: false, vehicle: null }) const fetchData = useCallback(async (showLoading = true) => { if (showLoading) setLoading(true) try { const response = await apiFetch(`${API_BASE}/vehicles`) const result = await response.json() if (result.success) { setVehicles(Array.isArray(result.data) ? result.data : []) } } catch { alert.error('Nepodařilo se načíst data') } finally { if (showLoading) setLoading(false) } }, [alert]) useEffect(() => { fetchData() }, [fetchData]) useModalLock(showModal) if (!hasPermission('trips.vehicles')) return const openCreateModal = () => { setEditingVehicle(null) setForm({ spz: '', name: '', brand: '', model: '', initial_km: 0, is_active: true }) setErrors({}) setShowModal(true) } const openEditModal = (vehicle: Vehicle) => { setEditingVehicle(vehicle) setForm({ spz: vehicle.spz, name: vehicle.name, brand: vehicle.brand || '', model: vehicle.model || '', initial_km: vehicle.initial_km, is_active: Boolean(vehicle.is_active) }) setErrors({}) setShowModal(true) } const handleSubmit = async () => { const newErrors: Record = {} if (!form.spz) newErrors.spz = 'Zadejte SPZ' if (!form.name) newErrors.name = 'Zadejte název' setErrors(newErrors) if (Object.keys(newErrors).length > 0) return try { const url = editingVehicle ? `${API_BASE}/vehicles/${editingVehicle.id}` : `${API_BASE}/vehicles` const method = editingVehicle ? 'PUT' : 'POST' const response = await apiFetch(url, { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(form) }) const result = await response.json() if (result.success) { setShowModal(false) await fetchData(false) await new Promise(resolve => setTimeout(resolve, 300)) alert.success(result.message) } else { alert.error(result.error) } } catch { alert.error('Chyba připojení') } } const handleDelete = async () => { if (!deleteConfirm.vehicle) return try { const response = await apiFetch(`${API_BASE}/vehicles/${deleteConfirm.vehicle.id}`, { method: 'DELETE', }) const result = await response.json() if (result.success) { setDeleteConfirm({ show: false, vehicle: null }) await fetchData(false) alert.success(result.message) } else { alert.error(result.error) } } catch { alert.error('Chyba připojení') } } const toggleActive = async (vehicle: Vehicle) => { try { const response = await apiFetch(`${API_BASE}/vehicles/${vehicle.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ spz: vehicle.spz, name: vehicle.name, brand: vehicle.brand || '', model: vehicle.model || '', initial_km: vehicle.initial_km, is_active: !vehicle.is_active }) }) const result = await response.json() if (result.success) { fetchData(false) alert.success(vehicle.is_active ? 'Vozidlo bylo deaktivováno' : 'Vozidlo bylo aktivováno') } else { alert.error(result.error) } } catch { alert.error('Chyba připojení') } } if (loading) { return (
{[0, 1, 2, 3, 4].map(i => (
))}
) } return (

Správa vozidel

{vehicles.length === 0 && (

Zatím nejsou žádná vozidla.

)} {vehicles.length > 0 && (
{vehicles.map((vehicle) => ( ))}
SPZ Název Značka / Model Počáteční km Aktuální km Počet jízd Stav Akce
{vehicle.spz} {vehicle.name} {vehicle.brand || vehicle.model ? `${vehicle.brand || ''} ${vehicle.model || ''}`.trim() : '—'} {formatKm(vehicle.initial_km)} km {formatKm(vehicle.current_km)} km {vehicle.trip_count}
)}
{/* Add/Edit Modal */} {showModal && (
setShowModal(false)} />

{editingVehicle ? 'Upravit vozidlo' : 'Přidat vozidlo'}

{ setForm({ ...form, spz: e.target.value.toUpperCase() }) setErrors(prev => ({ ...prev, spz: '' })) }} className="admin-form-input" placeholder="1AB 2345" aria-invalid={!!errors.spz} /> { setForm({ ...form, name: e.target.value }) setErrors(prev => ({ ...prev, name: '' })) }} className="admin-form-input" placeholder="Služební #1" aria-invalid={!!errors.name} />
setForm({ ...form, brand: e.target.value })} className="admin-form-input" placeholder="Škoda" /> setForm({ ...form, model: e.target.value })} className="admin-form-input" placeholder="Octavia Combi" />
setForm({ ...form, initial_km: parseInt(e.target.value) || 0 })} className="admin-form-input" min="0" /> Stav tachometru při přidání vozidla
)} {/* Delete Confirmation */} setDeleteConfirm({ show: false, vehicle: null })} onConfirm={handleDelete} title="Smazat vozidlo" message={deleteConfirm.vehicle ? `Opravdu chcete smazat vozidlo ${deleteConfirm.vehicle.spz} - ${deleteConfirm.vehicle.name}?` : ''} confirmText="Smazat" confirmVariant="danger" />
) }