From ca386c9d9835c5777fa54502d65e6f8a20888598 Mon Sep 17 00:00:00 2001 From: BOHA Date: Sat, 6 Jun 2026 23:51:52 +0200 Subject: [PATCH] =?UTF-8?q?feat(mui):=20migrate=20Trips=20Admin=20(Spr?= =?UTF-8?q?=C3=A1va=20kniha=20j=C3=ADzd)=20onto=20MUI=20kit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- src/admin/pages/TripsAdmin.tsx | 785 +++++++++++++++++---------------- 1 file changed, 416 insertions(+), 369 deletions(-) diff --git a/src/admin/pages/TripsAdmin.tsx b/src/admin/pages/TripsAdmin.tsx index 05e10bb..149ceed 100644 --- a/src/admin/pages/TripsAdmin.tsx +++ b/src/admin/pages/TripsAdmin.tsx @@ -1,30 +1,41 @@ import { useState, useRef } from "react"; import { useQuery } from "@tanstack/react-query"; +import { Link as RouterLink } from "react-router-dom"; +import { motion } from "framer-motion"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import IconButton from "@mui/material/IconButton"; import { useAlert } from "../context/AlertContext"; import { useAuth } from "../context/AuthContext"; -import { Link } from "react-router-dom"; import Forbidden from "../components/Forbidden"; -import { motion } from "framer-motion"; -import ConfirmModal from "../components/ConfirmModal"; -import FormModal from "../components/FormModal"; import { tripListOptions, tripVehiclesOptions, tripUsersOptions, type BackendTrip, - type TripVehicle, - type TripUser, } from "../lib/queries/trips"; -import { - companySettingsOptions, - type CompanySettingsData, -} from "../lib/queries/settings"; - -import AdminDatePicker from "../components/AdminDatePicker"; -import FormField from "../components/FormField"; +import { companySettingsOptions } from "../lib/queries/settings"; import { formatDate } from "../utils/attendanceHelpers"; import { formatKm } from "../utils/formatters"; import { useApiMutation } from "../lib/queries/mutations"; +import { + Button, + Card, + DataTable, + Modal, + ConfirmDialog, + Field, + TextField, + Select, + DateField, + StatusChip, + FilterBar, + LoadingState, + EmptyState, + StatCard, + type DataColumn, +} from "../ui"; + const API_BASE = "/api/admin"; interface Trip { @@ -71,6 +82,102 @@ function mapTrip(bt: BackendTrip): Trip { }; } +const PrintIcon = ( + + + + + +); + +const EditIcon = ( + + + + +); + +const DeleteIcon = ( + + + + +); + +const TripsIcon = ( + + + + + +); +const TotalIcon = ( + + + +); +const BusinessIcon = ( + + + + + + + +); + export default function TripsAdmin() { const alert = useAlert(); const { hasPermission } = useAuth(); @@ -331,463 +438,403 @@ export default function TripsAdmin() { .reduce((sum, t) => sum + t.distance, 0), }; + const columns: DataColumn[] = [ + { + key: "trip_date", + header: "Datum", + width: "11%", + mono: true, + render: (trip) => formatDate(trip.trip_date), + }, + { + key: "driver", + header: "Řidič", + width: "16%", + render: (trip) => trip.driver_name, + }, + { + key: "vehicle", + header: "Vozidlo", + width: "11%", + mono: true, + render: (trip) => , + }, + { + key: "route", + header: "Trasa", + width: "20%", + render: (trip) => ( + + {trip.route_from} → {trip.route_to} + + ), + }, + { + key: "km", + header: "Stav km", + width: "14%", + mono: true, + render: (trip) => ( + + {formatKm(trip.start_km)} - {formatKm(trip.end_km)} + + ), + }, + { + key: "distance", + header: "Vzdálenost", + width: "12%", + mono: true, + bold: true, + render: (trip) => `${formatKm(trip.distance)} km`, + }, + { + key: "type", + header: "Typ", + width: "10%", + render: (trip) => ( + + ), + }, + { + key: "actions", + header: "Akce", + width: "10%", + align: "right", + render: (trip) => ( + + openEditModal(trip)} + aria-label="Upravit" + title="Upravit" + > + {EditIcon} + + setDeleteConfirm({ show: true, trip })} + aria-label="Smazat" + title="Smazat" + > + {DeleteIcon} + + + ), + }, + ]; + return ( -
+ -
-

Správa knihy jízd

-
-
- {trips.length > 0 && ( - - )} - - Vozidla - -
+ Tisk + + )} + +
+ {/* Filters */} -
-
- - setFilterMonth(e.target.value)} - className="admin-form-select" - > - {Array.from({ length: 12 }, (_, i) => ( - - ))} - - - - setFilterYear(e.target.value)} - className="admin-form-select" - > - {Array.from({ length: 5 }, (_, i) => { + onChange={setFilterYear} + options={Array.from({ length: 5 }, (_, i) => { const y = new Date().getFullYear() - 2 + i; - return ( - - ); + return { value: String(y), label: String(y) }; })} - - - - setFilterVehicleId(e.target.value)} - className="admin-form-select" - > - - {vehicles.map((v) => ( - - ))} - - - - setFilterUserId(e.target.value)} - className="admin-form-select" - > - - {tripUsers.map((u) => ( - - ))} - - -
-
+ onChange={setFilterUserId} + options={[ + { value: "", label: "Všichni řidiči" }, + ...tripUsers.map((u) => ({ + value: String(u.id), + label: u.name, + })), + ]} + /> + + +
+ {/* Stats Cards */} -
-
- - - - - -
-
- {totals.count} - Počet jízd -
-
-
-
- - - -
-
- - {formatKm(totals.total)} km - - Celkem naježděno -
-
-
-
- - - - - - - -
-
- - {formatKm(totals.business)} km - - Služební km -
-
+ + + + +
{/* Trips Table */} -
+ {isPending ? ( -
-
-
+ ) : ( - <> - {trips.length === 0 && ( -
-

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

-
- )} - {trips.length > 0 && ( -
- - - - - - - - - - - - - - - {trips.map((trip) => ( - - - - - - - - - - - ))} - -
DatumŘidičVozidloTrasaStav kmVzdálenostTypAkce
- {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á"} - - -
- - -
-
-
- )} - + + columns={columns} + rows={trips} + rowKey={(trip) => trip.id} + empty={ + + } + /> )} -
+
{/* Edit Modal */} - setShowEditModal(false)} onSubmit={handleEditSubmit} title="Upravit jízdu" + subtitle={editingTrip?.driver_name} loading={editMutation.isPending} - size="lg" + maxWidth="lg" > {editingTrip && ( -
-

+ - {editingTrip.driver_name} -

-
- - - setEditForm({ - ...editForm, - vehicle_id: e.target.value, - }) + onChange={(value) => + setEditForm({ ...editForm, vehicle_id: value }) } - className="admin-form-select" - > - {vehicles.map((v) => ( - - ))} - - + options={vehicles.map((v) => ({ + value: String(v.id), + label: `${v.spz} - ${v.name}`, + }))} + /> + - - + + onChange={(val) => setEditForm({ ...editForm, trip_date: val }) } /> - -
+ + -
- - + + setEditForm({ ...editForm, start_km: e.target.value }) } - className="admin-form-input" - min="0" + slotProps={{ htmlInput: { min: 0 } }} /> - + - - + setEditForm({ ...editForm, end_km: e.target.value }) } - className="admin-form-input" - min="0" + slotProps={{ htmlInput: { min: 0 } }} /> - + - - + - -
+ + -
- - + + - setEditForm({ - ...editForm, - route_from: e.target.value, - }) + setEditForm({ ...editForm, route_from: e.target.value }) } - className="admin-form-input" /> - + - - + setEditForm({ ...editForm, route_to: e.target.value }) } - className="admin-form-input" /> - -
+ + - - + setEditForm({ ...editForm, is_business: parseInt(value) }) } - className="admin-form-select" - > - - - - + options={[ + { value: "1", label: "Služební" }, + { value: "0", label: "Soukromá" }, + ]} + /> + - -