style: run prettier on entire codebase
This commit is contained in:
@@ -1,192 +1,287 @@
|
||||
import { useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
import { useAuth } from '../../context/AuthContext'
|
||||
import { useAlert } from '../../context/AlertContext'
|
||||
import { formatKm } from '../../utils/formatters'
|
||||
import AdminDatePicker from '../AdminDatePicker'
|
||||
import apiFetch from '../../utils/api'
|
||||
import useModalLock from '../../hooks/useModalLock'
|
||||
import { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { useAuth } from "../../context/AuthContext";
|
||||
import { useAlert } from "../../context/AlertContext";
|
||||
import { formatKm } from "../../utils/formatters";
|
||||
import AdminDatePicker from "../AdminDatePicker";
|
||||
import apiFetch from "../../utils/api";
|
||||
import useModalLock from "../../hooks/useModalLock";
|
||||
|
||||
const API_BASE = '/api/admin'
|
||||
const API_BASE = "/api/admin";
|
||||
|
||||
interface Vehicle {
|
||||
id: number | string
|
||||
spz: string
|
||||
name: string
|
||||
id: number | string;
|
||||
spz: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface TripForm {
|
||||
vehicle_id: string
|
||||
trip_date: string
|
||||
start_km: string
|
||||
end_km: string
|
||||
route_from: string
|
||||
route_to: string
|
||||
is_business: number
|
||||
notes: string
|
||||
vehicle_id: string;
|
||||
trip_date: string;
|
||||
start_km: string;
|
||||
end_km: string;
|
||||
route_from: string;
|
||||
route_to: string;
|
||||
is_business: number;
|
||||
notes: string;
|
||||
}
|
||||
|
||||
interface TripErrors {
|
||||
vehicle_id?: string
|
||||
trip_date?: string
|
||||
start_km?: string
|
||||
end_km?: string
|
||||
route_from?: string
|
||||
route_to?: string
|
||||
vehicle_id?: string;
|
||||
trip_date?: string;
|
||||
start_km?: string;
|
||||
end_km?: string;
|
||||
route_from?: string;
|
||||
route_to?: string;
|
||||
}
|
||||
|
||||
interface DashQuickActionsProps {
|
||||
dashData: {
|
||||
my_shift?: {
|
||||
has_ongoing: boolean
|
||||
}
|
||||
} | null
|
||||
punching: boolean
|
||||
onPunch: () => void
|
||||
has_ongoing: boolean;
|
||||
};
|
||||
} | null;
|
||||
punching: boolean;
|
||||
onPunch: () => void;
|
||||
}
|
||||
|
||||
export default function DashQuickActions({ dashData, punching, onPunch }: DashQuickActionsProps) {
|
||||
const { hasPermission } = useAuth()
|
||||
const alert = useAlert()
|
||||
export default function DashQuickActions({
|
||||
dashData,
|
||||
punching,
|
||||
onPunch,
|
||||
}: DashQuickActionsProps) {
|
||||
const { hasPermission } = useAuth();
|
||||
const alert = useAlert();
|
||||
|
||||
const [showTripModal, setShowTripModal] = useState(false)
|
||||
const [tripSubmitting, setTripSubmitting] = useState(false)
|
||||
const [tripVehicles, setTripVehicles] = useState<Vehicle[]>([])
|
||||
const [showTripModal, setShowTripModal] = useState(false);
|
||||
const [tripSubmitting, setTripSubmitting] = useState(false);
|
||||
const [tripVehicles, setTripVehicles] = useState<Vehicle[]>([]);
|
||||
const [tripForm, setTripForm] = useState<TripForm>({
|
||||
vehicle_id: '', trip_date: '', start_km: '', end_km: '',
|
||||
route_from: '', route_to: '', is_business: 1, notes: ''
|
||||
})
|
||||
const [tripErrors, setTripErrors] = useState<TripErrors>({})
|
||||
vehicle_id: "",
|
||||
trip_date: "",
|
||||
start_km: "",
|
||||
end_km: "",
|
||||
route_from: "",
|
||||
route_to: "",
|
||||
is_business: 1,
|
||||
notes: "",
|
||||
});
|
||||
const [tripErrors, setTripErrors] = useState<TripErrors>({});
|
||||
|
||||
useModalLock(showTripModal)
|
||||
useModalLock(showTripModal);
|
||||
|
||||
const openTripModal = async () => {
|
||||
setTripForm({
|
||||
vehicle_id: '', trip_date: new Date().toISOString().split('T')[0],
|
||||
start_km: '', end_km: '', route_from: '', route_to: '',
|
||||
is_business: 1, notes: ''
|
||||
})
|
||||
setTripErrors({})
|
||||
setShowTripModal(true)
|
||||
vehicle_id: "",
|
||||
trip_date: new Date().toISOString().split("T")[0],
|
||||
start_km: "",
|
||||
end_km: "",
|
||||
route_from: "",
|
||||
route_to: "",
|
||||
is_business: 1,
|
||||
notes: "",
|
||||
});
|
||||
setTripErrors({});
|
||||
setShowTripModal(true);
|
||||
|
||||
try {
|
||||
const response = await apiFetch(`${API_BASE}/vehicles`)
|
||||
const result = await response.json()
|
||||
const response = await apiFetch(`${API_BASE}/vehicles`);
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
setTripVehicles(Array.isArray(result.data) ? result.data : result.data?.vehicles || [])
|
||||
setTripVehicles(
|
||||
Array.isArray(result.data)
|
||||
? result.data
|
||||
: result.data?.vehicles || [],
|
||||
);
|
||||
}
|
||||
} catch {
|
||||
// vozidla se nenacetla
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleTripVehicleChange = async (vehicleId: string) => {
|
||||
setTripForm(prev => ({ ...prev, vehicle_id: vehicleId }))
|
||||
setTripForm((prev) => ({ ...prev, vehicle_id: vehicleId }));
|
||||
if (!vehicleId) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const response = await apiFetch(`${API_BASE}/trips/last-km/${vehicleId}`)
|
||||
const result = await response.json()
|
||||
const response = await apiFetch(`${API_BASE}/trips/last-km/${vehicleId}`);
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
setTripForm(prev => ({ ...prev, start_km: result.data.last_km }))
|
||||
setTripForm((prev) => ({ ...prev, start_km: result.data.last_km }));
|
||||
}
|
||||
} catch {
|
||||
// last_km se nenacetlo
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleTripSubmit = async () => {
|
||||
const errs: TripErrors = {}
|
||||
const errs: TripErrors = {};
|
||||
if (!tripForm.vehicle_id) {
|
||||
errs.vehicle_id = 'Vyberte vozidlo'
|
||||
errs.vehicle_id = "Vyberte vozidlo";
|
||||
}
|
||||
if (!tripForm.trip_date) {
|
||||
errs.trip_date = 'Zadejte datum'
|
||||
errs.trip_date = "Zadejte datum";
|
||||
}
|
||||
if (!tripForm.start_km) {
|
||||
errs.start_km = 'Zadejte počáteční km'
|
||||
errs.start_km = "Zadejte počáteční km";
|
||||
}
|
||||
if (!tripForm.end_km) {
|
||||
errs.end_km = 'Zadejte konečný km'
|
||||
errs.end_km = "Zadejte konečný km";
|
||||
}
|
||||
if (tripForm.start_km && tripForm.end_km && parseInt(tripForm.end_km) <= parseInt(tripForm.start_km)) {
|
||||
errs.end_km = 'Musí být větší než počáteční'
|
||||
if (
|
||||
tripForm.start_km &&
|
||||
tripForm.end_km &&
|
||||
parseInt(tripForm.end_km) <= parseInt(tripForm.start_km)
|
||||
) {
|
||||
errs.end_km = "Musí být větší než počáteční";
|
||||
}
|
||||
if (!tripForm.route_from) {
|
||||
errs.route_from = 'Zadejte místo odjezdu'
|
||||
errs.route_from = "Zadejte místo odjezdu";
|
||||
}
|
||||
if (!tripForm.route_to) {
|
||||
errs.route_to = 'Zadejte místo příjezdu'
|
||||
errs.route_to = "Zadejte místo příjezdu";
|
||||
}
|
||||
setTripErrors(errs)
|
||||
setTripErrors(errs);
|
||||
if (Object.keys(errs).length > 0) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
setTripSubmitting(true)
|
||||
setTripSubmitting(true);
|
||||
try {
|
||||
const response = await apiFetch(`${API_BASE}/trips`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(tripForm)
|
||||
})
|
||||
const result = await response.json()
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(tripForm),
|
||||
});
|
||||
const result = await response.json();
|
||||
if (result.success) {
|
||||
setShowTripModal(false)
|
||||
alert.success(result.message)
|
||||
setShowTripModal(false);
|
||||
alert.success(result.message);
|
||||
} else {
|
||||
alert.error(result.error)
|
||||
alert.error(result.error);
|
||||
}
|
||||
} catch {
|
||||
alert.error('Chyba připojení')
|
||||
alert.error("Chyba připojení");
|
||||
} finally {
|
||||
setTripSubmitting(false)
|
||||
setTripSubmitting(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const tripDistance = (): number => {
|
||||
const s = parseInt(tripForm.start_km) || 0
|
||||
const e = parseInt(tripForm.end_km) || 0
|
||||
return e > s ? e - s : 0
|
||||
}
|
||||
const s = parseInt(tripForm.start_km) || 0;
|
||||
const e = parseInt(tripForm.end_km) || 0;
|
||||
return e > s ? e - s : 0;
|
||||
};
|
||||
|
||||
const hasOngoingShift = dashData?.my_shift?.has_ongoing
|
||||
const punchLabel = hasOngoingShift ? 'Zaznamenat odchod' : 'Zaznamenat příchod'
|
||||
const hasOngoingShift = dashData?.my_shift?.has_ongoing;
|
||||
const punchLabel = hasOngoingShift
|
||||
? "Zaznamenat odchod"
|
||||
: "Zaznamenat příchod";
|
||||
const quickActions: Array<{
|
||||
label: string
|
||||
color: string
|
||||
icon: React.ReactNode
|
||||
onClick?: () => void
|
||||
path?: string
|
||||
disabled?: boolean
|
||||
}> = []
|
||||
label: string;
|
||||
color: string;
|
||||
icon: React.ReactNode;
|
||||
onClick?: () => void;
|
||||
path?: string;
|
||||
disabled?: boolean;
|
||||
}> = [];
|
||||
|
||||
if (hasPermission('attendance.record')) {
|
||||
if (hasPermission("attendance.record")) {
|
||||
quickActions.push({
|
||||
label: punching ? 'Odesílám...' : punchLabel,
|
||||
color: hasOngoingShift ? 'danger' : 'success',
|
||||
icon: hasOngoingShift
|
||||
? <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" /><polyline points="16 17 21 12 16 7" /><line x1="21" y1="12" x2="9" y2="12" /></svg>
|
||||
: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M9 12l2 2 4-4" /><circle cx="12" cy="12" r="10" /></svg>,
|
||||
label: punching ? "Odesílám..." : punchLabel,
|
||||
color: hasOngoingShift ? "danger" : "success",
|
||||
icon: hasOngoingShift ? (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
|
||||
<polyline points="16 17 21 12 16 7" />
|
||||
<line x1="21" y1="12" x2="9" y2="12" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<path d="M9 12l2 2 4-4" />
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
</svg>
|
||||
),
|
||||
onClick: onPunch,
|
||||
disabled: punching,
|
||||
})
|
||||
});
|
||||
}
|
||||
if (hasPermission('offers.create')) {
|
||||
quickActions.push({ label: 'Nová nabídka', path: '/offers/new', color: 'info', icon: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" /><polyline points="14 2 14 8 20 8" /></svg> })
|
||||
}
|
||||
if (hasPermission('trips.record')) {
|
||||
if (hasPermission("offers.create")) {
|
||||
quickActions.push({
|
||||
label: 'Přidat jízdu',
|
||||
color: 'warning',
|
||||
icon: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="1" y="3" width="15" height="13" rx="2" /><circle cx="8.5" cy="16" r="2.5" /><circle cx="18.5" cy="16" r="2.5" /><path d="M16 8h4l3 5v3h-7" /></svg>,
|
||||
onClick: openTripModal,
|
||||
})
|
||||
label: "Nová nabídka",
|
||||
path: "/offers/new",
|
||||
color: "info",
|
||||
icon: (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
|
||||
<polyline points="14 2 14 8 20 8" />
|
||||
</svg>
|
||||
),
|
||||
});
|
||||
}
|
||||
if (hasPermission('invoices.create')) {
|
||||
quickActions.push({ label: 'Vystavit fakturu', path: '/invoices/new', color: 'danger', icon: <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M12 1v22M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" /></svg> })
|
||||
if (hasPermission("trips.record")) {
|
||||
quickActions.push({
|
||||
label: "Přidat jízdu",
|
||||
color: "warning",
|
||||
icon: (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<rect x="1" y="3" width="15" height="13" rx="2" />
|
||||
<circle cx="8.5" cy="16" r="2.5" />
|
||||
<circle cx="18.5" cy="16" r="2.5" />
|
||||
<path d="M16 8h4l3 5v3h-7" />
|
||||
</svg>
|
||||
),
|
||||
onClick: openTripModal,
|
||||
});
|
||||
}
|
||||
if (hasPermission("invoices.create")) {
|
||||
quickActions.push({
|
||||
label: "Vystavit fakturu",
|
||||
path: "/invoices/new",
|
||||
color: "danger",
|
||||
icon: (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
>
|
||||
<path d="M12 1v22M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" />
|
||||
</svg>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -197,22 +292,28 @@ export default function DashQuickActions({ dashData, punching, onPunch }: DashQu
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.25, delay: 0.08 }}
|
||||
>
|
||||
{quickActions.map((action) => action.onClick ? (
|
||||
<button
|
||||
key={action.label}
|
||||
onClick={action.onClick}
|
||||
disabled={action.disabled}
|
||||
className={`dash-quick-btn dash-quick-btn-${action.color}`}
|
||||
>
|
||||
{action.icon}
|
||||
<span>{action.label}</span>
|
||||
</button>
|
||||
) : (
|
||||
<Link key={action.label} to={action.path!} className={`dash-quick-btn dash-quick-btn-${action.color}`}>
|
||||
{action.icon}
|
||||
<span>{action.label}</span>
|
||||
</Link>
|
||||
))}
|
||||
{quickActions.map((action) =>
|
||||
action.onClick ? (
|
||||
<button
|
||||
key={action.label}
|
||||
onClick={action.onClick}
|
||||
disabled={action.disabled}
|
||||
className={`dash-quick-btn dash-quick-btn-${action.color}`}
|
||||
>
|
||||
{action.icon}
|
||||
<span>{action.label}</span>
|
||||
</button>
|
||||
) : (
|
||||
<Link
|
||||
key={action.label}
|
||||
to={action.path!}
|
||||
className={`dash-quick-btn dash-quick-btn-${action.color}`}
|
||||
>
|
||||
{action.icon}
|
||||
<span>{action.label}</span>
|
||||
</Link>
|
||||
),
|
||||
)}
|
||||
</motion.div>
|
||||
|
||||
<AnimatePresence>
|
||||
@@ -224,7 +325,10 @@ export default function DashQuickActions({ dashData, punching, onPunch }: DashQu
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
>
|
||||
<div className="admin-modal-backdrop" onClick={() => setShowTripModal(false)} />
|
||||
<div
|
||||
className="admin-modal-backdrop"
|
||||
onClick={() => setShowTripModal(false)}
|
||||
/>
|
||||
<motion.div
|
||||
className="admin-modal admin-modal-lg"
|
||||
initial={{ opacity: 0, scale: 0.95, y: 20 }}
|
||||
@@ -238,102 +342,188 @@ export default function DashQuickActions({ dashData, punching, onPunch }: DashQu
|
||||
<div className="admin-modal-body">
|
||||
<div className="admin-form">
|
||||
<div className="admin-form-row">
|
||||
<div className={`admin-form-group${tripErrors.vehicle_id ? ' has-error' : ''}`}>
|
||||
<label className="admin-form-label required">Vozidlo</label>
|
||||
<div
|
||||
className={`admin-form-group${tripErrors.vehicle_id ? " has-error" : ""}`}
|
||||
>
|
||||
<label className="admin-form-label required">
|
||||
Vozidlo
|
||||
</label>
|
||||
<select
|
||||
value={tripForm.vehicle_id}
|
||||
onChange={(e) => {
|
||||
handleTripVehicleChange(e.target.value)
|
||||
setTripErrors(prev => ({ ...prev, vehicle_id: undefined }))
|
||||
handleTripVehicleChange(e.target.value);
|
||||
setTripErrors((prev) => ({
|
||||
...prev,
|
||||
vehicle_id: undefined,
|
||||
}));
|
||||
}}
|
||||
className="admin-form-select"
|
||||
>
|
||||
<option value="">Vyberte vozidlo</option>
|
||||
{tripVehicles.map((v) => (
|
||||
<option key={v.id} value={v.id}>{v.spz} - {v.name}</option>
|
||||
<option key={v.id} value={v.id}>
|
||||
{v.spz} - {v.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{tripErrors.vehicle_id && <span className="admin-form-error">{tripErrors.vehicle_id}</span>}
|
||||
{tripErrors.vehicle_id && (
|
||||
<span className="admin-form-error">
|
||||
{tripErrors.vehicle_id}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className={`admin-form-group${tripErrors.trip_date ? ' has-error' : ''}`}>
|
||||
<label className="admin-form-label required">Datum jízdy</label>
|
||||
<div
|
||||
className={`admin-form-group${tripErrors.trip_date ? " has-error" : ""}`}
|
||||
>
|
||||
<label className="admin-form-label required">
|
||||
Datum jízdy
|
||||
</label>
|
||||
<AdminDatePicker
|
||||
mode="date"
|
||||
value={tripForm.trip_date}
|
||||
onChange={(val: string) => {
|
||||
setTripForm(prev => ({ ...prev, trip_date: val }))
|
||||
setTripErrors(prev => ({ ...prev, trip_date: undefined }))
|
||||
setTripForm((prev) => ({ ...prev, trip_date: val }));
|
||||
setTripErrors((prev) => ({
|
||||
...prev,
|
||||
trip_date: undefined,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
{tripErrors.trip_date && <span className="admin-form-error">{tripErrors.trip_date}</span>}
|
||||
{tripErrors.trip_date && (
|
||||
<span className="admin-form-error">
|
||||
{tripErrors.trip_date}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="admin-form-row admin-form-row-3">
|
||||
<div className={`admin-form-group${tripErrors.start_km ? ' has-error' : ''}`}>
|
||||
<label className="admin-form-label required">Počáteční stav km</label>
|
||||
<div
|
||||
className={`admin-form-group${tripErrors.start_km ? " has-error" : ""}`}
|
||||
>
|
||||
<label className="admin-form-label required">
|
||||
Počáteční stav km
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
inputMode="numeric"
|
||||
value={tripForm.start_km}
|
||||
onChange={(e) => {
|
||||
setTripForm(prev => ({ ...prev, start_km: e.target.value }))
|
||||
setTripErrors(prev => ({ ...prev, start_km: undefined }))
|
||||
setTripForm((prev) => ({
|
||||
...prev,
|
||||
start_km: e.target.value,
|
||||
}));
|
||||
setTripErrors((prev) => ({
|
||||
...prev,
|
||||
start_km: undefined,
|
||||
}));
|
||||
}}
|
||||
className="admin-form-input"
|
||||
min="0"
|
||||
/>
|
||||
{tripErrors.start_km && <span className="admin-form-error">{tripErrors.start_km}</span>}
|
||||
{tripErrors.start_km && (
|
||||
<span className="admin-form-error">
|
||||
{tripErrors.start_km}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className={`admin-form-group${tripErrors.end_km ? ' has-error' : ''}`}>
|
||||
<label className="admin-form-label required">Konečný stav km</label>
|
||||
<div
|
||||
className={`admin-form-group${tripErrors.end_km ? " has-error" : ""}`}
|
||||
>
|
||||
<label className="admin-form-label required">
|
||||
Konečný stav km
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
inputMode="numeric"
|
||||
value={tripForm.end_km}
|
||||
onChange={(e) => {
|
||||
setTripForm(prev => ({ ...prev, end_km: e.target.value }))
|
||||
setTripErrors(prev => ({ ...prev, end_km: undefined }))
|
||||
setTripForm((prev) => ({
|
||||
...prev,
|
||||
end_km: e.target.value,
|
||||
}));
|
||||
setTripErrors((prev) => ({
|
||||
...prev,
|
||||
end_km: undefined,
|
||||
}));
|
||||
}}
|
||||
className="admin-form-input"
|
||||
min="0"
|
||||
/>
|
||||
{tripErrors.end_km && <span className="admin-form-error">{tripErrors.end_km}</span>}
|
||||
{tripErrors.end_km && (
|
||||
<span className="admin-form-error">
|
||||
{tripErrors.end_km}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="admin-form-group">
|
||||
<label className="admin-form-label">Vzdálenost</label>
|
||||
<input type="text" value={`${formatKm(tripDistance())} km`} className="admin-form-input" readOnly disabled />
|
||||
<input
|
||||
type="text"
|
||||
value={`${formatKm(tripDistance())} km`}
|
||||
className="admin-form-input"
|
||||
readOnly
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="admin-form-row">
|
||||
<div className={`admin-form-group${tripErrors.route_from ? ' has-error' : ''}`}>
|
||||
<label className="admin-form-label required">Místo odjezdu</label>
|
||||
<div
|
||||
className={`admin-form-group${tripErrors.route_from ? " has-error" : ""}`}
|
||||
>
|
||||
<label className="admin-form-label required">
|
||||
Místo odjezdu
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={tripForm.route_from}
|
||||
onChange={(e) => {
|
||||
setTripForm(prev => ({ ...prev, route_from: e.target.value }))
|
||||
setTripErrors(prev => ({ ...prev, route_from: undefined }))
|
||||
setTripForm((prev) => ({
|
||||
...prev,
|
||||
route_from: e.target.value,
|
||||
}));
|
||||
setTripErrors((prev) => ({
|
||||
...prev,
|
||||
route_from: undefined,
|
||||
}));
|
||||
}}
|
||||
className="admin-form-input"
|
||||
placeholder="Např. Praha"
|
||||
/>
|
||||
{tripErrors.route_from && <span className="admin-form-error">{tripErrors.route_from}</span>}
|
||||
{tripErrors.route_from && (
|
||||
<span className="admin-form-error">
|
||||
{tripErrors.route_from}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className={`admin-form-group${tripErrors.route_to ? ' has-error' : ''}`}>
|
||||
<label className="admin-form-label required">Místo příjezdu</label>
|
||||
<div
|
||||
className={`admin-form-group${tripErrors.route_to ? " has-error" : ""}`}
|
||||
>
|
||||
<label className="admin-form-label required">
|
||||
Místo příjezdu
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={tripForm.route_to}
|
||||
onChange={(e) => {
|
||||
setTripForm(prev => ({ ...prev, route_to: e.target.value }))
|
||||
setTripErrors(prev => ({ ...prev, route_to: undefined }))
|
||||
setTripForm((prev) => ({
|
||||
...prev,
|
||||
route_to: e.target.value,
|
||||
}));
|
||||
setTripErrors((prev) => ({
|
||||
...prev,
|
||||
route_to: undefined,
|
||||
}));
|
||||
}}
|
||||
className="admin-form-input"
|
||||
placeholder="Např. Brno"
|
||||
/>
|
||||
{tripErrors.route_to && <span className="admin-form-error">{tripErrors.route_to}</span>}
|
||||
{tripErrors.route_to && (
|
||||
<span className="admin-form-error">
|
||||
{tripErrors.route_to}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -341,7 +531,12 @@ export default function DashQuickActions({ dashData, punching, onPunch }: DashQu
|
||||
<label className="admin-form-label">Typ jízdy</label>
|
||||
<select
|
||||
value={tripForm.is_business}
|
||||
onChange={(e) => setTripForm(prev => ({ ...prev, is_business: parseInt(e.target.value) }))}
|
||||
onChange={(e) =>
|
||||
setTripForm((prev) => ({
|
||||
...prev,
|
||||
is_business: parseInt(e.target.value),
|
||||
}))
|
||||
}
|
||||
className="admin-form-select"
|
||||
>
|
||||
<option value={1}>Služební</option>
|
||||
@@ -353,7 +548,12 @@ export default function DashQuickActions({ dashData, punching, onPunch }: DashQu
|
||||
<label className="admin-form-label">Poznámky</label>
|
||||
<textarea
|
||||
value={tripForm.notes}
|
||||
onChange={(e) => setTripForm(prev => ({ ...prev, notes: e.target.value }))}
|
||||
onChange={(e) =>
|
||||
setTripForm((prev) => ({
|
||||
...prev,
|
||||
notes: e.target.value,
|
||||
}))
|
||||
}
|
||||
className="admin-form-textarea"
|
||||
rows={2}
|
||||
placeholder="Volitelné poznámky..."
|
||||
@@ -362,11 +562,21 @@ export default function DashQuickActions({ dashData, punching, onPunch }: DashQu
|
||||
</div>
|
||||
</div>
|
||||
<div className="admin-modal-footer">
|
||||
<button type="button" onClick={() => setShowTripModal(false)} className="admin-btn admin-btn-secondary" disabled={tripSubmitting}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowTripModal(false)}
|
||||
className="admin-btn admin-btn-secondary"
|
||||
disabled={tripSubmitting}
|
||||
>
|
||||
Zrušit
|
||||
</button>
|
||||
<button type="button" onClick={handleTripSubmit} className="admin-btn admin-btn-primary" disabled={tripSubmitting}>
|
||||
{tripSubmitting ? 'Ukládám...' : 'Uložit'}
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleTripSubmit}
|
||||
className="admin-btn admin-btn-primary"
|
||||
disabled={tripSubmitting}
|
||||
>
|
||||
{tripSubmitting ? "Ukládám..." : "Uložit"}
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
@@ -374,5 +584,5 @@ export default function DashQuickActions({ dashData, punching, onPunch }: DashQu
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user