207 lines
11 KiB
TypeScript
207 lines
11 KiB
TypeScript
import { useEffect, useState } from "react";
|
||
import axiosInstance from "../../../src/axiosSecure";
|
||
import { useSession } from "next-auth/react";
|
||
import Layout from "../../../components/layout";
|
||
import ProtectedRoute from "../../../components/protectedRoute";
|
||
import { UserRole, EventLogType } from "@prisma/client";
|
||
|
||
const timeFilters = [
|
||
{ label: "1 седмица", value: 7 },
|
||
{ label: "1 месец", value: 30 },
|
||
{ label: "3 месеца", value: 90 },
|
||
{ label: "Всички", value: null },
|
||
];
|
||
|
||
const eventTypes = [
|
||
{ label: "Заявки", value: EventLogType.AssignmentReplacementRequested },
|
||
{ label: "Приети замествания", value: EventLogType.AssignmentReplacementAccepted },
|
||
{ label: "Ръчно въведени замествания", value: EventLogType.AssignmentReplacementManual },
|
||
];
|
||
|
||
export default function EventLogList() {
|
||
const [eventLogs, setEventLog] = useState([]);
|
||
const [requestedAssignments, setRequestedAssignments] = useState([]);
|
||
const [showOpenRequests, setShowOpenRequests] = useState(false);
|
||
const [selectedTimeFilter, setSelectedTimeFilter] = useState(null); // Time filter state
|
||
const [selectedEventTypes, setSelectedEventTypes] = useState(eventTypes.map((et) => et.value)); // Default: all types
|
||
const { data: session } = useSession();
|
||
|
||
useEffect(() => {
|
||
const fetchEventLogs = async () => {
|
||
try {
|
||
const where = encodeURIComponent(
|
||
JSON.stringify({
|
||
OR: selectedEventTypes.map((type) => ({ type })),
|
||
})
|
||
);
|
||
|
||
const { data: eventLogsData } = await axiosInstance.get(
|
||
`/api/data/prisma/eventLog?where=${where}&include={"publisher":{"select":{"firstName":true,"lastName":true}},"shift":{"include":{"assignments":{"include":{"publisher":{"select":{"firstName":true,"lastName":true}}}}}}}`
|
||
);
|
||
|
||
setEventLog(eventLogsData);
|
||
|
||
const { data: shiftsData } = await axiosInstance.get(
|
||
`/api/data/prisma/assignment?where={"publicGuid":{"not":"null"}}&include={"shift":{"include":{"assignments":{"include":{"publisher":{"select":{"firstName":true,"lastName":true}}}}}},"publisher":{"select":{"firstName":true,"lastName":true}}}`
|
||
);
|
||
setRequestedAssignments(shiftsData);
|
||
} catch (error) {
|
||
console.error(error);
|
||
}
|
||
};
|
||
|
||
fetchEventLogs();
|
||
}, [selectedEventTypes]);
|
||
|
||
// Filter events based on the selected time range
|
||
const filteredEventLogs = eventLogs.filter((event) => {
|
||
if (!selectedTimeFilter) return true;
|
||
const eventDate = new Date(event.date);
|
||
const cutoffDate = new Date();
|
||
cutoffDate.setDate(cutoffDate.getDate() - selectedTimeFilter);
|
||
return eventDate >= cutoffDate;
|
||
});
|
||
|
||
// Toggle event type selection
|
||
const toggleEventType = (eventType) => {
|
||
setSelectedEventTypes((prev) =>
|
||
prev.includes(eventType)
|
||
? prev.filter((type) => type !== eventType)
|
||
: [...prev, eventType]
|
||
);
|
||
};
|
||
|
||
return (
|
||
<Layout>
|
||
<ProtectedRoute allowedRoles={[UserRole.POWERUSER, UserRole.ADMIN]}>
|
||
<div className="h-5/6 grid place-items-start px-4 pt-8">
|
||
<div className="flex flex-col w-full px-4">
|
||
<h1 className="text-2xl font-bold text-center">Заявки за заместване</h1>
|
||
|
||
<div className="flex gap-2 mb-4">
|
||
<label
|
||
className={`cursor-pointer px-4 py-2 rounded-full ${!showOpenRequests ? "bg-blue-500 text-white" : "bg-gray-200 text-gray-800"
|
||
}`}
|
||
>
|
||
<input
|
||
type="radio"
|
||
name="reportType"
|
||
value="ServiceReport"
|
||
onChange={() => setShowOpenRequests(false)}
|
||
checked={!showOpenRequests}
|
||
className="sr-only"
|
||
/>
|
||
Приети/затворени заявки
|
||
</label>
|
||
<label
|
||
className={`cursor-pointer px-4 py-2 rounded-full ${showOpenRequests ? "bg-yellow-500 text-white" : "bg-yellow-100 text-gray-800"
|
||
}`}
|
||
>
|
||
<input
|
||
type="radio"
|
||
name="reportType"
|
||
value="Experience"
|
||
onChange={() => setShowOpenRequests(true)}
|
||
checked={showOpenRequests}
|
||
className="sr-only"
|
||
/>
|
||
Отворени заявки (Без отговор/Още се търси)
|
||
</label>
|
||
</div>
|
||
|
||
|
||
|
||
{/* Event Type Filter Pills */}
|
||
<div className="flex gap-2 mb-4">
|
||
{eventTypes.map((type) => (
|
||
<button
|
||
key={type.value}
|
||
onClick={() => toggleEventType(type.value)}
|
||
className={`px-4 py-2 rounded-full ${selectedEventTypes.includes(type.value)
|
||
? "bg-blue-500 text-white"
|
||
: "bg-gray-200 text-gray-800"
|
||
}`}
|
||
>
|
||
{type.label}
|
||
</button>
|
||
))}
|
||
</div>
|
||
{/* Time Filter Pills */}
|
||
<div className="flex gap-2 mb-4">
|
||
{timeFilters.map((filter) => (
|
||
<button
|
||
key={filter.value}
|
||
onClick={() => setSelectedTimeFilter(filter.value)}
|
||
className={`px-4 py-2 rounded-full ${selectedTimeFilter === filter.value
|
||
? "bg-blue-500 text-white"
|
||
: "bg-gray-200 text-gray-800"
|
||
}`}
|
||
>
|
||
{filter.label}
|
||
</button>
|
||
))}
|
||
</div>
|
||
<div className="mt-4 w-full overflow-x-auto">
|
||
<table className="w-full table-auto border-collapse">
|
||
<thead className="bg-gray-100">
|
||
<tr>
|
||
<th className="px-4 py-2 text-left sticky top-0 z-10 bg-gray-100 border">На</th>
|
||
<th className="px-4 py-2 text-left sticky top-0 z-10 bg-gray-100 border">От</th>
|
||
<th className="px-4 py-2 text-left sticky top-0 z-10 bg-gray-100 border">Дата</th>
|
||
<th className="px-4 py-2 text-left sticky top-0 z-10 bg-gray-100 border">Смяна</th>
|
||
<th className="px-4 py-2 text-left sticky top-0 z-10 bg-gray-100 border">Събитие</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{!showOpenRequests &&
|
||
filteredEventLogs.map((event) => (
|
||
<tr key={event.id}>
|
||
<td className="border px-2 py-2">{new Date(event.date).toLocaleString("bg")}</td>
|
||
<td className="border px-2 py-2">
|
||
{event.publisher?.firstName && event.publisher?.lastName
|
||
? `${event.publisher.firstName} ${event.publisher.lastName}`
|
||
: "???"}
|
||
</td>
|
||
<td className="border px-2 py-2">{new Date(event.shift?.startTime).toLocaleString("bg")}</td>
|
||
<td className="border px-2 py-2">
|
||
{event.shift?.assignments.map((ass) => (
|
||
<div key={ass.id}>
|
||
{ass.publisher.firstName + " " + ass.publisher.lastName}
|
||
</div>
|
||
))}
|
||
</td>
|
||
<td className="border px-2 py-2">{event.content}</td>
|
||
</tr>
|
||
))}
|
||
|
||
{showOpenRequests &&
|
||
requestedAssignments.map((assignment) => (
|
||
<tr key={assignment.id}>
|
||
<td className="border px-2 py-2">
|
||
{new Date(assignment.date).toLocaleString("bg")}
|
||
</td>
|
||
<td className="border px-2 py-2">
|
||
{assignment.publisher.firstName + " " + assignment.publisher.lastName}
|
||
</td>
|
||
<td className="border px-2 py-2">
|
||
{new Date(assignment.shift.startTime).toLocaleString("bg")}
|
||
</td>
|
||
<td className="border px-2 py-2">
|
||
{assignment.shift.assignments.map((ass) => (
|
||
<div key={ass.id}>
|
||
{ass.publisher.firstName + " " + ass.publisher.lastName}
|
||
</div>
|
||
))}
|
||
</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</ProtectedRoute>
|
||
</Layout>
|
||
);
|
||
}
|