feat: Erweiterte Filtermöglichkeiten für Buchungsverwaltung
- Neue Filter-Modi: Zukünftige (default), Alle, Datum - Filter-Buttons mit visueller Hervorhebung des aktiven Filters - Datumsauswahl nur sichtbar wenn Datum-Filter aktiv - Default-Filter zeigt alle zukünftigen (nicht stornierten) Buchungen - Angepasste Leermeldungen je nach aktivem Filter
This commit is contained in:
@@ -3,6 +3,7 @@ import { useMutation, useQuery } from "@tanstack/react-query";
|
|||||||
import { queryClient } from "@/client/rpc-client";
|
import { queryClient } from "@/client/rpc-client";
|
||||||
|
|
||||||
export function AdminBookings() {
|
export function AdminBookings() {
|
||||||
|
const [filterMode, setFilterMode] = useState<"upcoming" | "all" | "date">("upcoming");
|
||||||
const [selectedDate, setSelectedDate] = useState(new Date().toISOString().split('T')[0]);
|
const [selectedDate, setSelectedDate] = useState(new Date().toISOString().split('T')[0]);
|
||||||
const [selectedPhoto, setSelectedPhoto] = useState<string>("");
|
const [selectedPhoto, setSelectedPhoto] = useState<string>("");
|
||||||
const [showPhotoModal, setShowPhotoModal] = useState(false);
|
const [showPhotoModal, setShowPhotoModal] = useState(false);
|
||||||
@@ -139,9 +140,23 @@ export function AdminBookings() {
|
|||||||
return appointmentDate >= today;
|
return appointmentDate >= today;
|
||||||
};
|
};
|
||||||
|
|
||||||
const filteredBookings = bookings?.filter(booking =>
|
// Filter bookings based on selected filter mode
|
||||||
selectedDate ? booking.appointmentDate === selectedDate : true
|
const filteredBookings = bookings?.filter(booking => {
|
||||||
).sort((a, b) => {
|
if (filterMode === "upcoming") {
|
||||||
|
// Show all future bookings (not cancelled)
|
||||||
|
const bookingDate = new Date(booking.appointmentDate);
|
||||||
|
const today = new Date();
|
||||||
|
today.setHours(0, 0, 0, 0);
|
||||||
|
bookingDate.setHours(0, 0, 0, 0);
|
||||||
|
return bookingDate >= today && booking.status !== "cancelled";
|
||||||
|
} else if (filterMode === "date") {
|
||||||
|
// Show bookings for specific date
|
||||||
|
return booking.appointmentDate === selectedDate;
|
||||||
|
} else {
|
||||||
|
// Show all bookings
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}).sort((a, b) => {
|
||||||
if (a.appointmentDate === b.appointmentDate) {
|
if (a.appointmentDate === b.appointmentDate) {
|
||||||
return a.appointmentTime.localeCompare(b.appointmentTime);
|
return a.appointmentTime.localeCompare(b.appointmentTime);
|
||||||
}
|
}
|
||||||
@@ -218,22 +233,54 @@ export function AdminBookings() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Date Filter */}
|
{/* Filter Section */}
|
||||||
<div className="bg-white rounded-lg shadow p-4 mb-6">
|
<div className="bg-white rounded-lg shadow p-4 mb-6">
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex flex-col space-y-4">
|
||||||
<label className="text-sm font-medium text-gray-700">Filter by date:</label>
|
<div className="flex items-center space-x-2">
|
||||||
<input
|
<label className="text-sm font-medium text-gray-700">Filter:</label>
|
||||||
type="date"
|
<button
|
||||||
value={selectedDate}
|
onClick={() => setFilterMode("upcoming")}
|
||||||
onChange={(e) => setSelectedDate(e.target.value)}
|
className={`px-4 py-2 rounded-md text-sm font-medium transition-colors ${
|
||||||
className="p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-pink-500 focus:border-pink-500"
|
filterMode === "upcoming"
|
||||||
/>
|
? "bg-pink-600 text-white"
|
||||||
<button
|
: "bg-gray-100 text-gray-700 hover:bg-gray-200"
|
||||||
onClick={() => setSelectedDate("")}
|
}`}
|
||||||
className="text-sm text-pink-600 hover:text-pink-800"
|
>
|
||||||
>
|
Zukünftige
|
||||||
Show All
|
</button>
|
||||||
</button>
|
<button
|
||||||
|
onClick={() => setFilterMode("all")}
|
||||||
|
className={`px-4 py-2 rounded-md text-sm font-medium transition-colors ${
|
||||||
|
filterMode === "all"
|
||||||
|
? "bg-pink-600 text-white"
|
||||||
|
: "bg-gray-100 text-gray-700 hover:bg-gray-200"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Alle
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setFilterMode("date")}
|
||||||
|
className={`px-4 py-2 rounded-md text-sm font-medium transition-colors ${
|
||||||
|
filterMode === "date"
|
||||||
|
? "bg-pink-600 text-white"
|
||||||
|
: "bg-gray-100 text-gray-700 hover:bg-gray-200"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Datum
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{filterMode === "date" && (
|
||||||
|
<div className="flex items-center space-x-4 pl-16">
|
||||||
|
<label className="text-sm font-medium text-gray-700">Wähle Datum:</label>
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
value={selectedDate}
|
||||||
|
onChange={(e) => setSelectedDate(e.target.value)}
|
||||||
|
className="p-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-pink-500 focus:border-pink-500"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -369,8 +416,10 @@ export function AdminBookings() {
|
|||||||
|
|
||||||
{!filteredBookings?.length && (
|
{!filteredBookings?.length && (
|
||||||
<div className="text-center py-8 text-gray-500">
|
<div className="text-center py-8 text-gray-500">
|
||||||
{selectedDate
|
{filterMode === "date"
|
||||||
? `Keine Buchungen für ${new Date(selectedDate).toLocaleDateString()} gefunden`
|
? `Keine Buchungen für ${new Date(selectedDate).toLocaleDateString()} gefunden`
|
||||||
|
: filterMode === "upcoming"
|
||||||
|
? "Keine zukünftigen Buchungen verfügbar."
|
||||||
: "Keine Buchungen verfügbar."
|
: "Keine Buchungen verfügbar."
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user