import { useState, useEffect, useCallback, useRef } from 'react' import DOMPurify from 'dompurify' import { useAlert } from '../context/AlertContext' import { useAuth } from '../context/AuthContext' import { Link } from 'react-router-dom' import Forbidden from '../components/Forbidden' import { motion, AnimatePresence } from 'framer-motion' import ConfirmModal from '../components/ConfirmModal' import AdminDatePicker from '../components/AdminDatePicker' import FormField from '../components/FormField' import useModalLock from '../hooks/useModalLock' import { formatDate } from '../utils/attendanceHelpers' import { formatKm } from '../utils/formatters' import apiFetch from '../utils/api' const API_BASE = '/api/admin' export default function TripsAdmin() { const alert = useAlert() const { hasPermission } = useAuth() const [loading, setLoading] = useState(true) const [dateFrom, setDateFrom] = useState(() => { const now = new Date() return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-01` }) const [dateTo, setDateTo] = useState(() => { const now = new Date() const lastDay = new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate() return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(lastDay).padStart(2, '0')}` }) const [filterVehicleId, setFilterVehicleId] = useState('') const [filterUserId, setFilterUserId] = useState('') const [data, setData] = useState({ trips: [], vehicles: [], users: [], totals: { total: 0, business: 0, count: 0 } }) const [printData, setPrintData] = useState(null) const printRef = useRef(null) const [showEditModal, setShowEditModal] = useState(false) const [editingTrip, setEditingTrip] = useState(null) const [editForm, setEditForm] = useState({ vehicle_id: '', trip_date: '', start_km: '', end_km: '', route_from: '', route_to: '', is_business: 1, notes: '' }) const [deleteConfirm, setDeleteConfirm] = useState({ show: false, trip: null }) const fetchData = useCallback(async (showLoading = true) => { if (showLoading) setLoading(true) try { let url = `${API_BASE}/trips.php?action=admin&date_from=${dateFrom}&date_to=${dateTo}` if (filterVehicleId) url += `&vehicle_id=${filterVehicleId}` if (filterUserId) url += `&user_id=${filterUserId}` const response = await apiFetch(url) const result = await response.json() if (result.success) { setData(result.data) } } catch { alert.error('Nepodařilo se načíst data') } finally { if (showLoading) setLoading(false) } }, [dateFrom, dateTo, filterVehicleId, filterUserId, alert]) useEffect(() => { fetchData() }, [fetchData]) useModalLock(showEditModal) if (!hasPermission('trips.admin')) return const openEditModal = (trip) => { setEditingTrip(trip) setEditForm({ vehicle_id: trip.vehicle_id, trip_date: trip.trip_date, start_km: trip.start_km, end_km: trip.end_km, route_from: trip.route_from, route_to: trip.route_to, is_business: trip.is_business, notes: trip.notes || '' }) setShowEditModal(true) } const handleEditSubmit = async () => { if (parseInt(editForm.end_km) <= parseInt(editForm.start_km)) { alert.error('Konečný stav km musí být větší než počáteční') return } try { const response = await apiFetch(`${API_BASE}/trips.php?id=${editingTrip.id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(editForm) }) const result = await response.json() if (result.success) { setShowEditModal(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.trip) return try { const response = await apiFetch(`${API_BASE}/trips.php?id=${deleteConfirm.trip.id}`, { method: 'DELETE', }) const result = await response.json() if (result.success) { setDeleteConfirm({ show: false, trip: null }) await fetchData(false) alert.success(result.message) } else { alert.error(result.error) } } catch { alert.error('Chyba připojení') } } const handlePrint = async () => { try { let url = `${API_BASE}/trips.php?action=print&date_from=${dateFrom}&date_to=${dateTo}` if (filterVehicleId) url += `&vehicle_id=${filterVehicleId}` if (filterUserId) url += `&user_id=${filterUserId}` const response = await apiFetch(url) const result = await response.json() if (result.success) { setPrintData(result.data) setTimeout(() => { if (printRef.current) { const printWindow = window.open('', '_blank') printWindow.document.write(` Kniha jízd - ${result.data.period_name} ${DOMPurify.sanitize(printRef.current.innerHTML)} `) printWindow.document.close() printWindow.onload = () => { printWindow.print() } } }, 100) } } catch { alert.error('Nepodařilo se připravit tisk') } } const calculateDistance = () => { const start = parseInt(editForm.start_km) || 0 const end = parseInt(editForm.end_km) || 0 return end > start ? end - start : 0 } const { trips, vehicles, users, totals } = data return (

Správa knihy jízd

{trips.length > 0 && ( )} Vozidla
{/* Filters */}
setDateFrom(val)} /> setDateTo(val)} />
{totals.count} Počet jízd
{formatKm(totals.total)} km Celkem naježděno
{formatKm(totals.business)} km Služební km
{/* Trips Table */}
{loading && (
{[0, 1, 2, 3, 4].map(i => (
))}
)} {!loading && trips.length === 0 && (

Žádné záznamy jízd pro vybrané období.

)} {!loading && trips.length > 0 && (
{trips.map((trip) => ( ))}
Datum Řidič Vozidlo Trasa Stav km Vzdálenost Typ Akce
{formatDate(trip.trip_date)} {trip.driver_name} {trip.spz} {trip.route_from} → {trip.route_to} {formatKm(trip.start_km)} - {formatKm(trip.end_km)} {formatKm(trip.distance)} km {trip.is_business ? 'Služební' : 'Soukromá'}
)}
{/* Edit Modal */} {showEditModal && editingTrip && (
setShowEditModal(false)} />

Upravit jízdu

{editingTrip.driver_name}

setEditForm({ ...editForm, trip_date: val })} />
setEditForm({ ...editForm, start_km: e.target.value })} className="admin-form-input" min="0" /> setEditForm({ ...editForm, end_km: e.target.value })} className="admin-form-input" min="0" />
setEditForm({ ...editForm, route_from: e.target.value })} className="admin-form-input" /> setEditForm({ ...editForm, route_to: e.target.value })} className="admin-form-input" />