119 lines
7.1 KiB
TypeScript
119 lines
7.1 KiB
TypeScript
import { useState } from 'react';
|
||
import Layout from "../../../components/layout";
|
||
import ProtectedRoute from '../../../components/protectedRoute';
|
||
import { UserRole } from '@prisma/client';
|
||
import axiosServer from '../../../src/axiosServer';
|
||
import common from '../../../src/helpers/common';
|
||
import { filterPublishers, /* other functions */ } from '../../api/index';
|
||
|
||
function ContactsPage({ publishers }) {
|
||
const [searchQuery, setSearchQuery] = useState('');
|
||
|
||
const filteredPublishers = publishers.filter((publisher) =>
|
||
publisher.firstName.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||
publisher.lastName.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||
publisher.email.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||
publisher.phone?.toLowerCase().includes(searchQuery.toLowerCase())
|
||
);
|
||
|
||
return (
|
||
<Layout>
|
||
<ProtectedRoute allowedRoles={[UserRole.ADMIN, UserRole.POWERUSER, UserRole.USER]}>
|
||
<div className="container mx-auto p-4">
|
||
<h1 className="text-xl font-semibold mb-4">Статистика </h1>
|
||
<h5 className="text-lg font-semibold mb-4">{publishers.length} участника с предпочитания</h5>
|
||
<input
|
||
type="text"
|
||
placeholder="Търси по име, имейл или телефон..."
|
||
value={searchQuery}
|
||
onChange={(e) => setSearchQuery(e.target.value)}
|
||
className="border border-gray-300 rounded-md px-2 py-2 mb-4 w-full text-base md:text-sm"
|
||
/>
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full text-left border-collapse">
|
||
<thead>
|
||
<tr>
|
||
<th className="border-b font-medium p-4 pl-8 pt-0 pb-3">Име</th>
|
||
<th className="border-b font-medium p-4 pt-0 pb-3">Възможности</th>
|
||
<th className="border-b font-medium p-4 pt-0 pb-3">Участия</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{filteredPublishers.map((pub) => (
|
||
<tr key={pub.id}>
|
||
<td className="border-b p-4 pl-8" title={pub.lastUpdate}>{pub.firstName} {pub.lastName}</td>
|
||
<td className="border-b p-4">
|
||
<span title="Възможност: часове | дни" className={`badge py-1 px-2 rounded-md text-xs ${pub.currentMonthAvailabilityHoursCount || pub.currentMonthAvailabilityDaysCount ? 'bg-teal-500 text-white' : 'bg-teal-200 text-gray-300'} hover:underline`} >
|
||
{pub.currentMonthAvailabilityDaysCount || 0} | {pub.currentMonthAvailabilityHoursCount || 0}
|
||
</span>
|
||
</td>
|
||
<td className="border-b p-4">
|
||
<div className="flex items-center justify-between">
|
||
<div className="flex items-center">
|
||
<span title="участия тази седмица" className={`badge py-1 px-2 rounded-full text-xs ${pub.currentWeekAssignments ? 'bg-yellow-500 text-white' : 'bg-yellow-200 text-gray-400'}`}>{pub.currentWeekAssignments || 0}</span>
|
||
<span title="участия този месец" className={`badge py-1 px-2 rounded-full text-xs ${pub.currentMonthAssignments ? 'bg-green-500 text-white' : 'bg-green-200 text-gray-400'}`}>{pub.currentMonthAssignments || 0}</span>
|
||
<span tooltip="участия миналия месец" title="участия миналия месец" className={`badge py-1 px-2 rounded-full text-xs ${pub.previousMonthAssignments ? 'bg-blue-500 text-white' : 'bg-blue-200 text-gray-400'}`}>{pub.previousMonthAssignments || 0}</span>
|
||
<button tooltip="желани участия този месец" title="желани участия" className={`badge py-1 px-2 rounded-md text-xs ${pub.desiredShiftsPerMonth ? 'bg-purple-500 text-white' : 'bg-purple-200 text-gray-400'}`}>{pub.desiredShiftsPerMonth || 0}</button>
|
||
</div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</ProtectedRoute>
|
||
</Layout>
|
||
);
|
||
}
|
||
|
||
|
||
export default ContactsPage;
|
||
|
||
export const getServerSideProps = async (context) => {
|
||
const dateStr = new Date().toISOString().split('T')[0];
|
||
|
||
let publishers = await filterPublishers('id,firstName,lastName,email,isActive,desiredShiftsPerMonth', "", new Date(), true, true, false);
|
||
|
||
// const axios = await axiosServer(context);
|
||
// const { data: publishers } = await axios.get(`api/?action=filterPublishers&assignments=true&availabilities=true&date=${dateStr}&select=id,firstName,lastName,isActive,desiredShiftsPerMonth`);
|
||
|
||
// api/index?action=filterPublishers&assignments=true&availabilities=true&date=2024-03-14&select=id%2CfirstName%2ClastName%2CisActive%2CdesiredShiftsPerMonth
|
||
publishers.forEach(publisher => {
|
||
publisher.desiredShiftsPerMonth = publisher.desiredShiftsPerMonth || 0;
|
||
publisher.assignments = publisher.assignments || [];
|
||
publisher.availabilities = publisher.availabilities || [];
|
||
publisher.lastUpdate = publisher.availabilities.reduce((acc, curr) => curr.dateOfEntry > acc ? curr.dateOfEntry : acc, null);
|
||
if (publisher.lastUpdate) {
|
||
publisher.lastUpdate = common.getDateFormated(publisher.lastUpdate);
|
||
}
|
||
else {
|
||
publisher.lastUpdate = "Няма данни";
|
||
}
|
||
//serialize dates in publisher.assignments and publisher.availabilities
|
||
publisher.assignments.forEach(assignment => {
|
||
if (assignment.shift && assignment.shift.startTime) {
|
||
assignment.shift.startTime = assignment.shift.startTime.toISOString();
|
||
assignment.shift.endTime = assignment.shift.endTime.toISOString();
|
||
}
|
||
});
|
||
publisher.availabilities.forEach(availability => {
|
||
if (availability.startTime) {
|
||
availability.startTime = availability.startTime.toISOString();
|
||
availability.endTime = availability.endTime.toISOString();
|
||
if (availability.dateOfEntry) {
|
||
availability.dateOfEntry = availability.dateOfEntry.toISOString();
|
||
}
|
||
}
|
||
});
|
||
|
||
});
|
||
|
||
return {
|
||
props: {
|
||
publishers,
|
||
},
|
||
};
|
||
};
|