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.
-
- Přidat první jízdu
-
-
- ) : (
-
-
-
-
- | Datum |
- Vozidlo |
- Řidič |
- Trasa |
- Vzdálenost |
- Typ |
- Akce |
-
-
-
- {trips.slice(0, 10).map((trip) => (
-
- |
- {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á"}
-
- |
-
-
- openEditModal(trip)}
- className="admin-btn-icon"
- title="Upravit"
- aria-label="Upravit"
- >
-
-
-
- setDeleteConfirm({ show: true, tripId: trip.id })
- }
- className="admin-btn-icon danger"
- title="Smazat"
- aria-label="Smazat"
- >
-
-
-
- |
-
- ))}
-
-
-
- )}
-
+ Poslední jízdy
+
+ Zobrazit historii
+
+
+
+ columns={columns}
+ rows={recentTrips}
+ rowKey={(trip) => trip.id}
+ empty={
+
+
+ Zatím nemáte žádné záznamy jízd.
+
+
+ Přidat první jízdu
+
+
+ }
+ />
+
{/* 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"
- />
-
-
-
-
-
-
-
-
-
-
-
+
-
+ {
+ setForm({ ...form, trip_date: val });
+ setErrors((prev) => ({ ...prev, trip_date: "" }));
+ }}
+ />
+
+
+
+
+
+ {
+ setForm({ ...form, start_km: e.target.value });
+ setErrors((prev) => ({ ...prev, start_km: "" }));
+ }}
+ slotProps={{ htmlInput: { min: 0 } }}
+ />
+
+
+
+ {
+ setForm({ ...form, end_km: e.target.value });
+ setErrors((prev) => ({ ...prev, end_km: "" }));
+ }}
+ slotProps={{ htmlInput: { min: 0 } }}
+ />
+
+
+
+
+
+
+
+
+
+ {
+ setForm({ ...form, route_from: e.target.value });
+ setErrors((prev) => ({ ...prev, route_from: "" }));
+ }}
+ placeholder="Např. Praha"
+ />
+
+
+
+ {
+ setForm({ ...form, route_to: e.target.value });
+ setErrors((prev) => ({ ...prev, route_to: "" }));
+ }}
+ placeholder="Např. Brno"
+ />
+
+
+
+
+
+
+
+ setForm({ ...form, notes: e.target.value })}
+ placeholder="Volitelné poznámky..."
+ />
+
+
+
+ setDeleteConfirm({ show: false, tripId: null })}
onConfirm={() => handleDelete(deleteConfirm.tripId!)}
@@ -657,9 +693,9 @@ export default function Trips() {
message="Opravdu chcete smazat tento záznam?"
confirmText="Smazat"
cancelText="Zrušit"
- type="danger"
+ confirmVariant="danger"
loading={deleteMutation.isPending}
/>
-
+
);
}