diff --git a/src/admin/pages/Trips.tsx b/src/admin/pages/Trips.tsx index 791cb7f..59a33b0 100644 --- a/src/admin/pages/Trips.tsx +++ b/src/admin/pages/Trips.tsx @@ -1,14 +1,12 @@ import { useState } 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 { motion } from "framer-motion"; - -import AdminDatePicker from "../components/AdminDatePicker"; -import ConfirmModal from "../components/ConfirmModal"; -import FormModal from "../components/FormModal"; -import FormField from "../components/FormField"; import Forbidden from "../components/Forbidden"; import { formatDate } from "../utils/attendanceHelpers"; import { formatKm, todayLocalStr } from "../utils/formatters"; @@ -17,9 +15,24 @@ import { tripListOptions, tripVehiclesOptions, type BackendTrip, - type TripVehicle, } from "../lib/queries/trips"; import { useApiMutation } from "../lib/queries/mutations"; +import { + Button, + Card, + DataTable, + Modal, + ConfirmDialog, + Field, + TextField, + Select, + DateField, + StatusChip, + LoadingState, + StatCard, + type DataColumn, +} from "../ui"; + const API_BASE = "/api/admin"; interface TripForm { @@ -33,6 +46,114 @@ interface TripForm { notes: string; } +const PlusIcon = ( + + + + +); +const EditIcon = ( + + + + +); +const DeleteIcon = ( + + + + +); + +const TripsIcon = ( + + + + + +); +const TotalIcon = ( + + + +); +const BusinessIcon = ( + + + + + + + +); +const PrivateIcon = ( + + + + +); + export default function Trips() { const alert = useAlert(); const { hasPermission } = useAuth(); @@ -197,11 +318,7 @@ export default function Trips() { }; if (tripsLoading) { - return ( -
-
-
- ); + return ; } const totals = trips.reduce( @@ -216,440 +333,359 @@ export default function Trips() { { total: 0, business: 0, private: 0, count: 0 }, ); + const recentTrips = trips.slice(0, 10); + + const columns: DataColumn[] = [ + { + key: "trip_date", + header: "Datum", + width: "12%", + mono: true, + render: (trip) => formatDate(trip.trip_date), + }, + { + key: "vehicle", + header: "Vozidlo", + width: "12%", + render: (trip) => ( + + ), + }, + { + key: "driver", + header: "Řidič", + width: "16%", + render: (trip) => + trip.users ? `${trip.users.first_name} ${trip.users.last_name}` : "", + }, + { + key: "route", + header: "Trasa", + width: "22%", + render: (trip) => ( + + {trip.route_from} → {trip.route_to} + + ), + }, + { + key: "distance", + header: "Vzdálenost", + width: "12%", + mono: true, + bold: true, + render: (trip) => + `${formatKm(trip.distance ?? trip.end_km - trip.start_km)} km`, + }, + { + key: "type", + header: "Typ", + width: "12%", + render: (trip) => ( + + ), + }, + { + key: "actions", + header: "Akce", + width: "10%", + align: "right", + render: (trip) => ( + + openEditModal(trip)} + aria-label="Upravit" + title="Upravit" + > + {EditIcon} + + setDeleteConfirm({ show: true, tripId: trip.id })} + aria-label="Smazat" + title="Smazat" + > + {DeleteIcon} + + + ), + }, + ]; + return ( -
+ -
-

Kniha jízd

-

- {new Date().toLocaleDateString("cs-CZ", { - month: "long", - year: "numeric", - })} -

-
-
- -
+ +
{/* Stats Cards */} -
-
- - - - - -
-
- {totals.count} - Počet jízd -
-
- -
-
- - - -
-
- - {formatKm(totals.total)} km - - Celkem naježděno -
-
- -
-
- - - - - - - -
-
- - {formatKm(totals.business)} km - - Služební -
-
- -
-
- - - - -
-
- - {formatKm(totals.private)} km - - Soukromé -
-
+ + + + + +
{/* Recent Trips */} -
-

Poslední jízdy

- + - Zobrazit historii - -
-
- {trips.length === 0 ? ( -
-
- - - - - - -
-

Zatím nemáte žádné záznamy jízd.

- -
- ) : ( -
- - - - - - - - - - - - - - {trips.slice(0, 10).map((trip) => ( - - - - - - - - - - ))} - -
DatumVozidloŘidičTrasaVzdálenostTypAkce
- {formatDate(trip.trip_date)} - - - {trip.vehicles?.spz ?? ""} - - - {trip.users - ? `${trip.users.first_name} ${trip.users.last_name}` - : ""} - - - {trip.route_from} → {trip.route_to} - - - - {formatKm( - trip.distance ?? trip.end_km - trip.start_km, - )}{" "} - km - - - - {trip.is_business ? "Služební" : "Soukromá"} - - -
- - -
-
-
- )} -
+ Poslední jízdy + + + + columns={columns} + rows={recentTrips} + rowKey={(trip) => trip.id} + empty={ + + + Zatím nemáte žádné záznamy jízd. + + + + } + /> +
{/* Add/Edit Modal */} - setShowModal(false)} onSubmit={handleSubmit} title={editingTrip ? "Upravit jízdu" : "Přidat jízdu"} loading={submitMutation.isPending} - size="lg" + maxWidth="md" > -
-
- - - - - - { - setForm({ ...form, trip_date: val }); - setErrors((prev) => ({ ...prev, trip_date: "" })); - }} - /> - -
- -
- - { - setForm({ ...form, start_km: e.target.value }); - setErrors((prev) => ({ ...prev, start_km: "" })); - }} - className="admin-form-input" - min="0" - /> - - - - { - setForm({ ...form, end_km: e.target.value }); - setErrors((prev) => ({ ...prev, end_km: "" })); - }} - className="admin-form-input" - min="0" - /> - - - - - -
- -
- - { - setForm({ ...form, route_from: e.target.value }); - setErrors((prev) => ({ ...prev, route_from: "" })); - }} - className="admin-form-input" - placeholder="Např. Praha" - /> - - - - { - setForm({ ...form, route_to: e.target.value }); - setErrors((prev) => ({ ...prev, route_to: "" })); - }} - className="admin-form-input" - placeholder="Např. Brno" - /> - -
- - - - - - -