Merge branch 'main' into production
This commit is contained in:
@ -214,9 +214,15 @@ fix published schedule to cover end of the week
|
|||||||
|
|
||||||
имейлите - ОК
|
имейлите - ОК
|
||||||
графика - синк - ОК
|
графика - синк - ОК
|
||||||
вестителите от Фабио -
|
вестителите от Фабио - OK
|
||||||
потребителите с двойни имейли -
|
потребителите с двойни имейли -
|
||||||
|
|
||||||
|
|
||||||
админс can send *urgent* email to everybody to ask for shift
|
админс can send *urgent* email to everybody to ask for shift
|
||||||
in schedule admin - if a publisher is always pair & family is not in the shift - add + button to add them
|
in schedule admin - if a publisher is always pair & family is not in the shift - add + button to add them
|
||||||
|
|
||||||
|
|
||||||
|
last login. pubs.
|
||||||
|
otchet - za denq
|
||||||
|
делете цонфирм
|
||||||
|
статистика - фкс (янка) + posledno vlizane
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
|
import zIndex from "@mui/material/styles/zIndex";
|
||||||
|
|
||||||
export default function ConfirmationModal({ isOpen, onClose, onConfirm, message }) {
|
export default function ConfirmationModal({ isOpen, onClose, onConfirm, message }) {
|
||||||
//export default function ConfirmationModal({ isOpen, onClose, onConfirm, message })
|
//export default function ConfirmationModal({ isOpen, onClose, onConfirm, message })
|
||||||
if (!isOpen) return null;
|
if (!isOpen) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 flex items-center justify-center z-50">
|
<div className="opacity-100 fixed inset-0 flex items-center justify-center z-1002" >
|
||||||
<div className="bg-white p-4 rounded-md shadow-lg modal-content">
|
<div className="bg-white p-4 rounded-md shadow-lg modal-content" style={{ zIndex: 1002 }}>
|
||||||
<p className="mb-4">{message}</p>
|
<p className="mb-4">{message}</p>
|
||||||
<button
|
<button
|
||||||
className="bg-red-500 text-white px-4 py-2 rounded mr-2"
|
className="bg-red-500 text-white px-4 py-2 rounded mr-2"
|
||||||
|
@ -193,7 +193,7 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={index}
|
<div key={index}
|
||||||
className={`flow space-x-2 rounded-md px-2 py-1 my-1 ${ass.isConfirmed ? 'bg-green-100' : 'bg-gray-100'} ${borderStyles}`}
|
className={`flow rounded-md px-2 py-1 sm:py-0.5 my-1 ${ass.isConfirmed ? 'bg-green-100' : 'bg-gray-100'} ${borderStyles}`}
|
||||||
>
|
>
|
||||||
<div className="flex justify-between items-center" onClick={() => handlePublisherClick(ass.publisher)}>
|
<div className="flex justify-between items-center" onClick={() => handlePublisherClick(ass.publisher)}>
|
||||||
<span className="text-gray-700">{publisherInfo.firstName} {publisherInfo.lastName}</span>
|
<span className="text-gray-700">{publisherInfo.firstName} {publisherInfo.lastName}</span>
|
||||||
@ -202,12 +202,12 @@ function ShiftComponent({ shift, onShiftSelect, isSelected, onPublisherSelect, a
|
|||||||
{shift.requiresTransport && (
|
{shift.requiresTransport && (
|
||||||
<span
|
<span
|
||||||
onClick={ass.canTransport || true ? () => toggleTransport(ass) : undefined}
|
onClick={ass.canTransport || true ? () => toggleTransport(ass) : undefined}
|
||||||
className={`material-icons ${ass.isWithTransport ? 'text-green-500 font-bold' : (transportProvided ? 'text-gray-400 ' : 'text-orange-400 font-bold')} ${ass.canTransport || ass.isWithTransport || true ? ' cursor-pointer' : 'cursor-not-allowed'} px-3 py-1 ml-2 rounded-md`}
|
className={`material-icons ${ass.isWithTransport ? 'text-green-500 font-bold' : (transportProvided ? 'text-gray-400 ' : 'text-orange-400 font-bold')} ${ass.canTransport || ass.isWithTransport || true ? ' cursor-pointer' : 'cursor-not-allowed'} px-3 py-0 ml-2 rounded-md`}
|
||||||
>
|
>
|
||||||
{ass.isWithTransport ? "транспорт" : ass.canTransport ? "може транспорт" : "без транспорт"} <LocalShippingIcon />
|
{ass.isWithTransport ? "транспорт" : ass.canTransport ? "може транспорт" : "без транспорт"} <LocalShippingIcon />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<button onClick={() => removeAssignment(ass.id)} className="text-white bg-red-500 hover:bg-red-600 px-3 py-1 ml-2 rounded-md" >
|
<button onClick={() => removeAssignment(ass.id)} className="items-center leading-snug text-white text-center bg-red-500 hover:bg-red-600 px-3 py-1 md:py-0.5 ml-2 rounded-md" >
|
||||||
махни
|
махни
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
@ -55,12 +55,12 @@ export default function Layout({ children }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="">
|
<div className="">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col ">
|
||||||
<div className="flex flex-row min-h-screen w-screen">
|
<div className="flex flex-row min-h-screen w-screen pr-8">
|
||||||
<ToastContainer position="top-center" style={{ zIndex: 9999 }} />
|
<ToastContainer position="top-center" style={{ zIndex: 9999 }} />
|
||||||
<Sidebar isSidebarOpen={isSidebarOpen} toggleSidebar={toggleSidebar} />
|
<Sidebar isSidebarOpen={isSidebarOpen} toggleSidebar={toggleSidebar} />
|
||||||
<main className={`flex-1 transition-all duration-300 ${marginLeftClass}`}>
|
<main className={`flex-1 transition-all duration-300 ${marginLeftClass}`}>
|
||||||
<div className="p-4 mx-auto pr-8 pl-0">
|
<div className="">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
@ -6,6 +6,7 @@ import toast from "react-hot-toast";
|
|||||||
|
|
||||||
import axiosInstance from '../../src/axiosSecure';
|
import axiosInstance from '../../src/axiosSecure';
|
||||||
import ProtectedRoute, { serverSideAuth } from "../../components/protectedRoute";
|
import ProtectedRoute, { serverSideAuth } from "../../components/protectedRoute";
|
||||||
|
import ConfirmationModal from "../../components/ConfirmationModal";
|
||||||
|
|
||||||
//add months to date. works with negative numbers and numbers > 12
|
//add months to date. works with negative numbers and numbers > 12
|
||||||
export function addMonths(numOfMonths, date) {
|
export function addMonths(numOfMonths, date) {
|
||||||
@ -41,6 +42,7 @@ export function IsDateInXMonths(date, monthsFrom, monthsTo) {
|
|||||||
export default function PublisherCard({ publisher }) {
|
export default function PublisherCard({ publisher }) {
|
||||||
|
|
||||||
const [isCardVisible, setIsCardVisible] = useState(true);
|
const [isCardVisible, setIsCardVisible] = useState(true);
|
||||||
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
|
||||||
const handleDelete = async (id) => {
|
const handleDelete = async (id) => {
|
||||||
try {
|
try {
|
||||||
@ -74,7 +76,7 @@ export default function PublisherCard({ publisher }) {
|
|||||||
|
|
||||||
return isCardVisible ? (
|
return isCardVisible ? (
|
||||||
// className="block p-6 max-w-sm bg-white rounded-lg border border-gray-200 shadow-md hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700 mb-3"
|
// className="block p-6 max-w-sm bg-white rounded-lg border border-gray-200 shadow-md hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700 mb-3"
|
||||||
<div id={`publisher-card-${publisher.id}`} className={`relative block p-6 max-w-sm rounded-lg border border-gray-200 shadow-md hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700 mb-3
|
<div id={`publisher-card-${publisher.id}`} className={`relative block p-6 max-w-sm rounded-lg border border-gray-200 shadow-md z-50 hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700 mb-3
|
||||||
${!publisher.isActive ? "opacity-50 bg-gray-200 border-gray-300 text-gray-400" : (publisher.isImported ? "bg-orange-50" : (publisher.isTrained ? "bg-white" : "bg-red-50"))}`}
|
${!publisher.isActive ? "opacity-50 bg-gray-200 border-gray-300 text-gray-400" : (publisher.isImported ? "bg-orange-50" : (publisher.isTrained ? "bg-white" : "bg-red-50"))}`}
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
@ -95,7 +97,7 @@ export default function PublisherCard({ publisher }) {
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div className="absolute bottom-2 right-2">
|
<div className="absolute bottom-2 right-2">
|
||||||
<button onClick={() => handleDelete(publisher.id)} aria-label="Изтрий Publisher">
|
<button onClick={() => { setIsModalOpen(true) }} aria-label="Изтрий Publisher">
|
||||||
<svg className="w-5 h-6 text-red-500 hover:text-red-700" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
<svg className="w-5 h-6 text-red-500 hover:text-red-700" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||||
<path d="M10 11V17" stroke="#000000" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
<path d="M10 11V17" stroke="#000000" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
<path d="M14 11V17" stroke="#000000" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
<path d="M14 11V17" stroke="#000000" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
@ -107,6 +109,12 @@ export default function PublisherCard({ publisher }) {
|
|||||||
<path fillRule="evenodd" d="M4.293 4.293A1 1 0 015.707 3.707L10 8l4.293-4.293a1 1 0 111.414 1.414L11.414 9l4.293 4.293a1 1 0 01-1.414 1.414L10 10.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 9 4.293 4.707a1 1 0 010-1.414z" clipRule="evenodd" /> */}
|
<path fillRule="evenodd" d="M4.293 4.293A1 1 0 015.707 3.707L10 8l4.293-4.293a1 1 0 111.414 1.414L11.414 9l4.293 4.293a1 1 0 01-1.414 1.414L10 10.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 9 4.293 4.707a1 1 0 010-1.414z" clipRule="evenodd" /> */}
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
<ConfirmationModal
|
||||||
|
isOpen={isModalOpen}
|
||||||
|
onClose={() => setIsModalOpen(false)}
|
||||||
|
onConfirm={() => handleDelete(publisher.id)}
|
||||||
|
message="Сигурни ли сте, че искате да изтриете този профил? Това действие не може да бъде отменено."
|
||||||
|
/>
|
||||||
<ProtectedRoute>
|
<ProtectedRoute>
|
||||||
|
|
||||||
<button onClick={() => handleLoginAs(publisher.id)}>Login as</button>
|
<button onClick={() => handleLoginAs(publisher.id)}>Login as</button>
|
||||||
|
@ -7,13 +7,13 @@ import axiosInstance from '../../src/axiosSecure';
|
|||||||
//import { getDate } from "date-fns";
|
//import { getDate } from "date-fns";
|
||||||
|
|
||||||
import PwaManager from "../PwaManager";
|
import PwaManager from "../PwaManager";
|
||||||
|
import common from "../../src/helpers/common";
|
||||||
|
import ProtectedRoute from '../../components/protectedRoute';
|
||||||
import { monthNamesBG, GetTimeFormat, GetDateFormat } from "../../src/helpers/const"
|
import { monthNamesBG, GetTimeFormat, GetDateFormat } from "../../src/helpers/const"
|
||||||
import PublisherSearchBox from './PublisherSearchBox';
|
import PublisherSearchBox from './PublisherSearchBox';
|
||||||
import AvailabilityList from "../availability/AvailabilityList";
|
import AvailabilityList from "../availability/AvailabilityList";
|
||||||
import ShiftsList from "../publisher/ShiftsList.tsx";
|
import ShiftsList from "../publisher/ShiftsList.tsx";
|
||||||
import common from "../../src/helpers/common";
|
import ConfirmationModal from "../ConfirmationModal";
|
||||||
|
|
||||||
import ProtectedRoute from '../../components/protectedRoute';
|
|
||||||
import { UserRole } from "@prisma/client";
|
import { UserRole } from "@prisma/client";
|
||||||
|
|
||||||
// import { Tabs, List } from 'tw-elements'
|
// import { Tabs, List } from 'tw-elements'
|
||||||
@ -66,6 +66,8 @@ export default function PublisherForm({ item, me }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [helpers, setHelper] = useState(null);
|
const [helpers, setHelper] = useState(null);
|
||||||
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
|
||||||
const fetchModules = async () => {
|
const fetchModules = async () => {
|
||||||
const h = (await import("../../src/helpers/const.js")).default;
|
const h = (await import("../../src/helpers/const.js")).default;
|
||||||
//console.log("fetchModules: " + JSON.stringify(h));
|
//console.log("fetchModules: " + JSON.stringify(h));
|
||||||
@ -312,9 +314,17 @@ export default function PublisherForm({ item, me }) {
|
|||||||
<div className="panel-actions">
|
<div className="panel-actions">
|
||||||
<Link href={urls.indexUrl} className="action-button"> Отмени </Link>
|
<Link href={urls.indexUrl} className="action-button"> Отмени </Link>
|
||||||
{/* delete */}
|
{/* delete */}
|
||||||
<button className="button bg-red-500 hover:bg-red-700 focus:outline-none focus:shadow-outline" type="button" onClick={handleDelete}>
|
<button className="button bg-red-500 hover:bg-red-700 focus:outline-none focus:shadow-outline" type="button" onClick={() => setIsModalOpen(true)}>
|
||||||
Изтрий
|
Изтрий
|
||||||
</button>
|
</button>
|
||||||
|
<ConfirmationModal
|
||||||
|
isOpen={isModalOpen}
|
||||||
|
onClose={() => setIsModalOpen(false)}
|
||||||
|
onConfirm={handleDelete}
|
||||||
|
message="Сигурни ли сте, че искате да изтриете този профил? Това действие не може да бъде отменено."
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* save */}
|
||||||
<button className="button bg-blue-500 hover:bg-blue-700 focus:outline-none focus:shadow-outline" type="submit">
|
<button className="button bg-blue-500 hover:bg-blue-700 focus:outline-none focus:shadow-outline" type="submit">
|
||||||
{router.query?.id ? "Update" : "Create"}
|
{router.query?.id ? "Update" : "Create"}
|
||||||
</button>
|
</button>
|
||||||
|
@ -46,6 +46,7 @@ export default function ReportForm({ shiftId, existingItem, onDone }) {
|
|||||||
const initialDate = getFormattedDate(new Date());
|
const initialDate = getFormattedDate(new Date());
|
||||||
const { data: session, status } = useSession()
|
const { data: session, status } = useSession()
|
||||||
const [publisherId, setPublisher] = useState(null);
|
const [publisherId, setPublisher] = useState(null);
|
||||||
|
const [allDay, setAllDay] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (session) {
|
if (session) {
|
||||||
setPublisher(session.user.id);
|
setPublisher(session.user.id);
|
||||||
@ -88,7 +89,11 @@ export default function ReportForm({ shiftId, existingItem, onDone }) {
|
|||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
item.publisher = { connect: { id: publisherId } };
|
item.publisher = { connect: { id: publisherId } };
|
||||||
item.shift = { connect: { id: parseInt(item.shiftId) } };
|
if (allDay) {
|
||||||
|
delete item.shift;
|
||||||
|
} else {
|
||||||
|
item.shift = { connect: { id: parseInt(item.shiftId) } };
|
||||||
|
}
|
||||||
item.date = new Date(item.date);
|
item.date = new Date(item.date);
|
||||||
item.type = ReportType.Report;
|
item.type = ReportType.Report;
|
||||||
delete item.publisherId;
|
delete item.publisherId;
|
||||||
@ -117,6 +122,15 @@ export default function ReportForm({ shiftId, existingItem, onDone }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleCheckboxChange = (event) => {
|
||||||
|
setAllDay(event.target.checked);
|
||||||
|
|
||||||
|
// Set shiftId to null if the checkbox is checked
|
||||||
|
if (event.target.checked) {
|
||||||
|
handleChange({ target: { name: 'shiftId', value: null } });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full max-w-md mx-auto">
|
<div className="w-full max-w-md mx-auto">
|
||||||
{/* <iframe src="https://docs.google.com/forms/d/e/1FAIpQLSdjbqgQEGY5-fA4A0B4cXjKRQVRWk5_-uoHVIAwdMcZ5bB7Zg/viewform?embedded=true" width="640" height="717" frameborder="0" marginheight="0" marginwidth="0">Loading…</iframe> */}
|
{/* <iframe src="https://docs.google.com/forms/d/e/1FAIpQLSdjbqgQEGY5-fA4A0B4cXjKRQVRWk5_-uoHVIAwdMcZ5bB7Zg/viewform?embedded=true" width="640" height="717" frameborder="0" marginheight="0" marginwidth="0">Loading…</iframe> */}
|
||||||
@ -134,7 +148,8 @@ export default function ReportForm({ shiftId, existingItem, onDone }) {
|
|||||||
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="shiftId">
|
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="shiftId">
|
||||||
Смяна
|
Смяна
|
||||||
</label>
|
</label>
|
||||||
<select className="textbox form-select px-4 py-2 rounded"
|
<select className={`textbox form-select px-4 py-2 rounded ${allDay ? 'bg-gray-200' : 'bg-white'}`}
|
||||||
|
disabled={allDay}
|
||||||
id="shiftId" name="shiftId" onChange={handleChange} value={item.shiftId} autoComplete="off" >
|
id="shiftId" name="shiftId" onChange={handleChange} value={item.shiftId} autoComplete="off" >
|
||||||
{shifts.map((shift) => (
|
{shifts.map((shift) => (
|
||||||
<option key={shift.id} value={shift.id}>
|
<option key={shift.id} value={shift.id}>
|
||||||
@ -142,6 +157,17 @@ export default function ReportForm({ shiftId, existingItem, onDone }) {
|
|||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
<div className="mb-4">
|
||||||
|
<label className="block text-gray-700 text-sm font-bold mb-2">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={allDay}
|
||||||
|
onChange={handleCheckboxChange}
|
||||||
|
className="mr-2 leading-tight"
|
||||||
|
/>
|
||||||
|
за целия ден
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
|
112
package-lock.json
generated
112
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "pwwa",
|
"name": "pwwa",
|
||||||
"version": "1.1.2",
|
"version": "1.2.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "pwwa",
|
"name": "pwwa",
|
||||||
"version": "1.1.2",
|
"version": "1.2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@auth/prisma-adapter": "^1.4.0",
|
"@auth/prisma-adapter": "^1.4.0",
|
||||||
"@emotion/react": "^11.11.3",
|
"@emotion/react": "^11.11.3",
|
||||||
@ -16,7 +16,7 @@
|
|||||||
"@mui/material": "^5.15.10",
|
"@mui/material": "^5.15.10",
|
||||||
"@mui/x-date-pickers": "^6.19.4",
|
"@mui/x-date-pickers": "^6.19.4",
|
||||||
"@premieroctet/next-crud": "^3.0.0",
|
"@premieroctet/next-crud": "^3.0.0",
|
||||||
"@prisma/client": "^5.12.1",
|
"@prisma/client": "^5.13.0",
|
||||||
"@react-pdf/renderer": "^3.3.8",
|
"@react-pdf/renderer": "^3.3.8",
|
||||||
"@tailwindcss/forms": "^0.5.7",
|
"@tailwindcss/forms": "^0.5.7",
|
||||||
"@types/multer": "^1.4.11",
|
"@types/multer": "^1.4.11",
|
||||||
@ -85,7 +85,8 @@
|
|||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"web-push": "^3.6.7",
|
"web-push": "^3.6.7",
|
||||||
"webpack-bundle-analyzer": "^4.10.1",
|
"webpack-bundle-analyzer": "^4.10.1",
|
||||||
"winston": "^3.11.0",
|
"winston": "^3.13.0",
|
||||||
|
"winston-daily-rotate-file": "^5.0.0",
|
||||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.1/xlsx-0.19.1.tgz",
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.1/xlsx-0.19.1.tgz",
|
||||||
"xlsx-style": "^0.8.13",
|
"xlsx-style": "^0.8.13",
|
||||||
"xml-js": "^1.6.11",
|
"xml-js": "^1.6.11",
|
||||||
@ -94,7 +95,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"depcheck": "^1.4.7",
|
"depcheck": "^1.4.7",
|
||||||
"prisma": "^5.12.1"
|
"prisma": "^5.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@alloc/quick-lru": {
|
"node_modules/@alloc/quick-lru": {
|
||||||
@ -3760,9 +3761,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/client": {
|
"node_modules/@prisma/client": {
|
||||||
"version": "5.12.1",
|
"version": "5.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.13.0.tgz",
|
||||||
"integrity": "sha512-6/JnizEdlSBxDIdiLbrBdMW5NqDxOmhXAJaNXiPpgzAPr/nLZResT6MMpbOHLo5yAbQ1Vv5UU8PTPRzb0WIxdA==",
|
"integrity": "sha512-uYdfpPncbZ/syJyiYBwGZS8Gt1PTNoErNYMuqHDa2r30rNSFtgTA/LXsSk55R7pdRTMi5pHkeP9B14K6nHmwkg==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.13"
|
"node": ">=16.13"
|
||||||
@ -3777,39 +3778,39 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/debug": {
|
"node_modules/@prisma/debug": {
|
||||||
"version": "5.12.1",
|
"version": "5.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.13.0.tgz",
|
||||||
"integrity": "sha512-kd/wNsR0klrv79o1ITsbWxYyh4QWuBidvxsXSParPsYSu0ircUmNk3q4ojsgNc3/81b0ozg76iastOG43tbf8A==",
|
"integrity": "sha512-699iqlEvzyCj9ETrXhs8o8wQc/eVW+FigSsHpiskSFydhjVuwTJEfj/nIYqTaWFYuxiWQRfm3r01meuW97SZaQ==",
|
||||||
"devOptional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/engines": {
|
"node_modules/@prisma/engines": {
|
||||||
"version": "5.12.1",
|
"version": "5.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.13.0.tgz",
|
||||||
"integrity": "sha512-HQDdglLw2bZR/TXD2Y+YfDMvi5Q8H+acbswqOsWyq9pPjBLYJ6gzM+ptlTU/AV6tl0XSZLU1/7F4qaWa8bqpJA==",
|
"integrity": "sha512-hIFLm4H1boj6CBZx55P4xKby9jgDTeDG0Jj3iXtwaaHmlD5JmiDkZhh8+DYWkTGchu+rRF36AVROLnk0oaqhHw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/debug": "5.12.1",
|
"@prisma/debug": "5.13.0",
|
||||||
"@prisma/engines-version": "5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab",
|
"@prisma/engines-version": "5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b",
|
||||||
"@prisma/fetch-engine": "5.12.1",
|
"@prisma/fetch-engine": "5.13.0",
|
||||||
"@prisma/get-platform": "5.12.1"
|
"@prisma/get-platform": "5.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/engines-version": {
|
"node_modules/@prisma/engines-version": {
|
||||||
"version": "5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab",
|
"version": "5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b.tgz",
|
||||||
"integrity": "sha512-6yvO8s80Tym61aB4QNtYZfWVmE3pwqe807jEtzm8C5VDe7nw8O1FGX3TXUaXmWV0fQTIAfRbeL2Gwrndabp/0g==",
|
"integrity": "sha512-AyUuhahTINGn8auyqYdmxsN+qn0mw3eg+uhkp8zwknXYIqoT3bChG4RqNY/nfDkPvzWAPBa9mrDyBeOnWSgO6A==",
|
||||||
"devOptional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/fetch-engine": {
|
"node_modules/@prisma/fetch-engine": {
|
||||||
"version": "5.12.1",
|
"version": "5.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.13.0.tgz",
|
||||||
"integrity": "sha512-qSs3KcX1HKcea1A+hlJVK/ljj0PNIUHDxAayGMvgJBqmaN32P9tCidlKz1EGv6WoRFICYnk3Dd/YFLBwnFIozA==",
|
"integrity": "sha512-Yh4W+t6YKyqgcSEB3odBXt7QyVSm0OQlBSldQF2SNXtmOgMX8D7PF/fvH6E6qBCpjB/yeJLy/FfwfFijoHI6sA==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/debug": "5.12.1",
|
"@prisma/debug": "5.13.0",
|
||||||
"@prisma/engines-version": "5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab",
|
"@prisma/engines-version": "5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b",
|
||||||
"@prisma/get-platform": "5.12.1"
|
"@prisma/get-platform": "5.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/generator-helper": {
|
"node_modules/@prisma/generator-helper": {
|
||||||
@ -3826,12 +3827,12 @@
|
|||||||
"integrity": "sha512-tZ+MOjWlVvz1kOEhNYMa4QUGURY+kgOUBqLHYIV8jmCsMuvA1tWcn7qtIMLzYWCbDcQT4ZS8xDgK0R2gl6/0wA=="
|
"integrity": "sha512-tZ+MOjWlVvz1kOEhNYMa4QUGURY+kgOUBqLHYIV8jmCsMuvA1tWcn7qtIMLzYWCbDcQT4ZS8xDgK0R2gl6/0wA=="
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/get-platform": {
|
"node_modules/@prisma/get-platform": {
|
||||||
"version": "5.12.1",
|
"version": "5.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.13.0.tgz",
|
||||||
"integrity": "sha512-pgIR+pSvhYHiUcqXVEZS31NrFOTENC9yFUdEAcx7cdQBoZPmHVjtjN4Ss6NzVDMYPrKJJ51U14EhEoeuBlMioQ==",
|
"integrity": "sha512-B/WrQwYTzwr7qCLifQzYOmQhZcFmIFhR81xC45gweInSUn2hTEbfKUPd2keAog+y5WI5xLAFNJ3wkXplvSVkSw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/debug": "5.12.1"
|
"@prisma/debug": "5.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/internals": {
|
"node_modules/@prisma/internals": {
|
||||||
@ -7624,6 +7625,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
|
||||||
"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="
|
"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/file-stream-rotator": {
|
||||||
|
"version": "0.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.6.1.tgz",
|
||||||
|
"integrity": "sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"moment": "^2.29.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/file-type": {
|
"node_modules/file-type": {
|
||||||
"version": "3.9.0",
|
"version": "3.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
|
||||||
@ -14352,13 +14361,13 @@
|
|||||||
"integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew=="
|
"integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew=="
|
||||||
},
|
},
|
||||||
"node_modules/prisma": {
|
"node_modules/prisma": {
|
||||||
"version": "5.12.1",
|
"version": "5.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-5.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/prisma/-/prisma-5.13.0.tgz",
|
||||||
"integrity": "sha512-SkMnb6wyIxTv9ACqiHBI2u9gD6y98qXRoCoLEnZsF6yee5Qg828G+ARrESN+lQHdw4maSZFFSBPPDpvSiVTo0Q==",
|
"integrity": "sha512-kGtcJaElNRAdAGsCNykFSZ7dBKpL14Cbs+VaQ8cECxQlRPDjBlMHNFYeYt0SKovAVy2Y65JXQwB3A5+zIQwnTg==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/engines": "5.12.1"
|
"@prisma/engines": "5.13.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"prisma": "build/index.js"
|
"prisma": "build/index.js"
|
||||||
@ -17763,9 +17772,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/winston": {
|
"node_modules/winston": {
|
||||||
"version": "3.11.0",
|
"version": "3.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz",
|
||||||
"integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==",
|
"integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@colors/colors": "^1.6.0",
|
"@colors/colors": "^1.6.0",
|
||||||
"@dabh/diagnostics": "^2.0.2",
|
"@dabh/diagnostics": "^2.0.2",
|
||||||
@ -17777,12 +17786,37 @@
|
|||||||
"safe-stable-stringify": "^2.3.1",
|
"safe-stable-stringify": "^2.3.1",
|
||||||
"stack-trace": "0.0.x",
|
"stack-trace": "0.0.x",
|
||||||
"triple-beam": "^1.3.0",
|
"triple-beam": "^1.3.0",
|
||||||
"winston-transport": "^4.5.0"
|
"winston-transport": "^4.7.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/winston-daily-rotate-file": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-JDjiXXkM5qvwY06733vf09I2wnMXpZEhxEVOSPenZMii+g7pcDcTBt2MRugnoi8BwVSuCT2jfRXBUy+n1Zz/Yw==",
|
||||||
|
"dependencies": {
|
||||||
|
"file-stream-rotator": "^0.6.1",
|
||||||
|
"object-hash": "^3.0.0",
|
||||||
|
"triple-beam": "^1.4.1",
|
||||||
|
"winston-transport": "^4.7.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"winston": "^3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/winston-daily-rotate-file/node_modules/object-hash": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/winston-transport": {
|
"node_modules/winston-transport": {
|
||||||
"version": "4.7.0",
|
"version": "4.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz",
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
"@mui/material": "^5.15.10",
|
"@mui/material": "^5.15.10",
|
||||||
"@mui/x-date-pickers": "^6.19.4",
|
"@mui/x-date-pickers": "^6.19.4",
|
||||||
"@premieroctet/next-crud": "^3.0.0",
|
"@premieroctet/next-crud": "^3.0.0",
|
||||||
"@prisma/client": "^5.12.1",
|
"@prisma/client": "^5.13.0",
|
||||||
"@react-pdf/renderer": "^3.3.8",
|
"@react-pdf/renderer": "^3.3.8",
|
||||||
"@tailwindcss/forms": "^0.5.7",
|
"@tailwindcss/forms": "^0.5.7",
|
||||||
"@types/multer": "^1.4.11",
|
"@types/multer": "^1.4.11",
|
||||||
@ -102,7 +102,8 @@
|
|||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"web-push": "^3.6.7",
|
"web-push": "^3.6.7",
|
||||||
"webpack-bundle-analyzer": "^4.10.1",
|
"webpack-bundle-analyzer": "^4.10.1",
|
||||||
"winston": "^3.11.0",
|
"winston": "^3.13.0",
|
||||||
|
"winston-daily-rotate-file": "^5.0.0",
|
||||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.1/xlsx-0.19.1.tgz",
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.1/xlsx-0.19.1.tgz",
|
||||||
"xlsx-style": "^0.8.13",
|
"xlsx-style": "^0.8.13",
|
||||||
"xml-js": "^1.6.11",
|
"xml-js": "^1.6.11",
|
||||||
@ -111,6 +112,6 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"depcheck": "^1.4.7",
|
"depcheck": "^1.4.7",
|
||||||
"prisma": "^5.12.1"
|
"prisma": "^5.13.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,11 +145,17 @@ export const authOptions: NextAuthOptions = {
|
|||||||
user.id = dbUser.id;
|
user.id = dbUser.id;
|
||||||
//user.permissions = dbUser.permissions;
|
//user.permissions = dbUser.permissions;
|
||||||
const session = { ...user };
|
const session = { ...user };
|
||||||
|
|
||||||
|
await prisma.publisher.update({
|
||||||
|
where: { id: dbUser.id },
|
||||||
|
data: { lastLogin: new Date() }
|
||||||
|
});
|
||||||
return true; // Sign-in successful
|
return true; // Sign-in successful
|
||||||
} else {
|
} else {
|
||||||
// Optionally create a new user in your DB
|
// Optionally create a new user in your DB
|
||||||
// Or return false to deny access
|
// Or return false to deny access
|
||||||
return false;
|
//Let's customize the error message to give a better user experience
|
||||||
|
throw new Error(`Твоят имейл '${user.email}' не е регистриран в системата. Моля свържи се с нас за да те регистрираме ако искаш да ползваш този имейл.`);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
|
@ -8,6 +8,8 @@ import { authOptions } from "../auth/[...nextauth]";
|
|||||||
const common = require("../../../src/helpers/common");
|
const common = require("../../../src/helpers/common");
|
||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
import { decode } from 'next-auth/jwt';
|
import { decode } from 'next-auth/jwt';
|
||||||
|
const logger = require('../../../src/logger');
|
||||||
|
|
||||||
// import { getToken } from "next-auth/jwt";
|
// import { getToken } from "next-auth/jwt";
|
||||||
|
|
||||||
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
@ -25,6 +27,14 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
const authHeader = req.headers.authorization || '';
|
const authHeader = req.headers.authorization || '';
|
||||||
//console.log('authHeader', authHeader);
|
//console.log('authHeader', authHeader);
|
||||||
if (session) {
|
if (session) {
|
||||||
|
//get target table
|
||||||
|
const targetTable = req.query.nextcrud[0];
|
||||||
|
//get target action
|
||||||
|
if (req.method === 'DELETE') {
|
||||||
|
|
||||||
|
const targetId = req.query.nextcrud[1];
|
||||||
|
logger.info('[nextCrud] ' + targetTable + ': ' + targetId + 'DELETED by ' + session.user.email);
|
||||||
|
}
|
||||||
return nextCrudHandler(req, res);
|
return nextCrudHandler(req, res);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -677,7 +677,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
|
|||||||
list of publishers for the selected date with availabilities
|
list of publishers for the selected date with availabilities
|
||||||
|
|
||||||
------------------AVAILABLE PUBLISHERS LIST FOR THE SELECTED DATE0 ------------------ */}
|
------------------AVAILABLE PUBLISHERS LIST FOR THE SELECTED DATE0 ------------------ */}
|
||||||
<div className="flex flex-col items-center my-8 sticky top-0">
|
<div className="flex flex-col items-center my-4 sticky top-0">
|
||||||
|
|
||||||
<h2 className="text-lg font-semibold mb-4">Достъпни за този ден: <span className="text-blue-600">{availablePubs.length}</span></h2>
|
<h2 className="text-lg font-semibold mb-4">Достъпни за този ден: <span className="text-blue-600">{availablePubs.length}</span></h2>
|
||||||
<label className="toggle pb-3">
|
<label className="toggle pb-3">
|
||||||
@ -719,7 +719,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<li key={index}
|
<li key={index}
|
||||||
className={`flex justify-between items-center p-4 rounded-lg shadow-sm mb-2
|
className={`flex justify-between items-center p-4 sm:py-2 rounded-lg shadow-sm mb-2
|
||||||
${bgAndBorderColorClass} ${selectedBorderClass} ${activeOpacityClass}`}
|
${bgAndBorderColorClass} ${selectedBorderClass} ${activeOpacityClass}`}
|
||||||
onDoubleClick={(handlePublisherModalOpen.bind(this, pub))}
|
onDoubleClick={(handlePublisherModalOpen.bind(this, pub))}
|
||||||
>
|
>
|
||||||
|
@ -39,6 +39,7 @@ function ContactsPage({ publishers, allPublishers }) {
|
|||||||
<th className="border-b font-medium p-4 pl-8 pt-0 pb-3">Име</th>
|
<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>
|
||||||
<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>
|
||||||
|
<th className="border-b font-medium p-4 pt-0 pb-3">Последно влизане</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -67,6 +68,7 @@ function ContactsPage({ publishers, allPublishers }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
<td className="border-b p-4">{pub.lastLogin ? new Date(pub.lastLogin).toLocaleString("bg") : ""}</td>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
@ -125,7 +127,7 @@ export const getServerSideProps = async (context) => {
|
|||||||
const prisma = common.getPrismaClient();
|
const prisma = common.getPrismaClient();
|
||||||
const dateStr = new Date().toISOString().split('T')[0];
|
const dateStr = new Date().toISOString().split('T')[0];
|
||||||
|
|
||||||
let publishers = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth', dateStr, false, true, true);
|
let publishers = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth,lastLogin', dateStr, false, true, true, true);
|
||||||
|
|
||||||
// const axios = await axiosServer(context);
|
// 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`);
|
// const { data: publishers } = await axios.get(`api/?action=filterPublishers&assignments=true&availabilities=true&date=${dateStr}&select=id,firstName,lastName,isActive,desiredShiftsPerMonth`);
|
||||||
@ -158,6 +160,7 @@ export const getServerSideProps = async (context) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
publisher.lastLogin = publisher.lastLogin ? publisher.lastLogin.toISOString() : null;
|
||||||
//remove availabilities that isFromPreviousAssignment
|
//remove availabilities that isFromPreviousAssignment
|
||||||
publisher.availabilities = publisher.availabilities.filter(availability => !availability.isFromPreviousAssignment);
|
publisher.availabilities = publisher.availabilities.filter(availability => !availability.isFromPreviousAssignment);
|
||||||
|
|
||||||
@ -175,6 +178,7 @@ export const getServerSideProps = async (context) => {
|
|||||||
phone: true,
|
phone: true,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
desiredShiftsPerMonth: true,
|
desiredShiftsPerMonth: true,
|
||||||
|
lastLogin: true,
|
||||||
assignments: {
|
assignments: {
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
@ -211,6 +215,7 @@ export const getServerSideProps = async (context) => {
|
|||||||
publisher.currentMonthAssignments = countAssignments(publisher.assignments, currentMonthStart, currentMonthEnd);
|
publisher.currentMonthAssignments = countAssignments(publisher.assignments, currentMonthStart, currentMonthEnd);
|
||||||
publisher.previousMonthAssignments = countAssignments(publisher.assignments, previousMonthStart, previousMonthEnd);
|
publisher.previousMonthAssignments = countAssignments(publisher.assignments, previousMonthStart, previousMonthEnd);
|
||||||
|
|
||||||
|
publisher.lastLogin = publisher.lastLogin ? publisher.lastLogin.toISOString() : null;
|
||||||
// Convert date formats within the same iteration
|
// Convert date formats within the same iteration
|
||||||
convertShiftDates(publisher.assignments);
|
convertShiftDates(publisher.assignments);
|
||||||
});
|
});
|
||||||
|
@ -63,9 +63,9 @@ export default function IndexPage({ initialItems, initialUserId }: IProps) {
|
|||||||
<ProtectedRoute allowedRoles={[UserRole.ADMIN]} deniedMessage="">
|
<ProtectedRoute allowedRoles={[UserRole.ADMIN]} deniedMessage="">
|
||||||
<PublisherSearchBox selectedId={userId} infoText="" onChange={handleUserSelection} />
|
<PublisherSearchBox selectedId={userId} infoText="" onChange={handleUserSelection} />
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
<div className="flex flex-row md:flex-row mt-4 space-y-4 md:space-y-0 md:space-x-4 h-[calc(100vh-10rem)]">
|
<div className="flex flex-row md:flex-row mt-4 xs:mt-1 space-y-4 md:space-y-0 md:space-x-4 h-[calc(100vh-10rem)]">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="text-center font-bold pb-3">
|
<div className="text-center font-bold pb-3 xs:pb-1">
|
||||||
<PublisherInlineForm publisherId={userId} />
|
<PublisherInlineForm publisherId={userId} />
|
||||||
</div>
|
</div>
|
||||||
<AvCalendar publisherId={userId} events={events} selectedDate={new Date()} />
|
<AvCalendar publisherId={userId} events={events} selectedDate={new Date()} />
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE `publisher` ADD COLUMN `lastLogin` DATETIME(3) NULL;
|
@ -122,6 +122,7 @@ model Publisher {
|
|||||||
reports Report[]
|
reports Report[]
|
||||||
Message Message[]
|
Message Message[]
|
||||||
EventLog EventLog[]
|
EventLog EventLog[]
|
||||||
|
lastLogin DateTime?
|
||||||
}
|
}
|
||||||
|
|
||||||
model Availability {
|
model Availability {
|
||||||
|
@ -228,7 +228,7 @@ async function getAvailabilities(userId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function filterPublishersNew(selectFields, filterDate, isExactTime = false, isForTheMonth = false, isWithStats = true, includeOldAvailabilities = false) {
|
async function filterPublishersNew(selectFields, filterDate, isExactTime = false, isForTheMonth = false, isNoEndDateFilter = false, isWithStats = true, includeOldAvailabilities = false) {
|
||||||
|
|
||||||
filterDate = new Date(filterDate); // Convert to date object if not already
|
filterDate = new Date(filterDate); // Convert to date object if not already
|
||||||
|
|
||||||
@ -341,7 +341,7 @@ async function filterPublishersNew(selectFields, filterDate, isExactTime = false
|
|||||||
{
|
{
|
||||||
dayOfMonth: { not: null },
|
dayOfMonth: { not: null },
|
||||||
startTime: { gte: monthInfo.firstMonday },
|
startTime: { gte: monthInfo.firstMonday },
|
||||||
endTime: { lte: monthInfo.lastSunday }
|
// endTime: { lte: monthInfo.lastSunday }
|
||||||
},
|
},
|
||||||
// Check if dayOfMonth is null and match by day of week using the enum (Assigments every week)
|
// Check if dayOfMonth is null and match by day of week using the enum (Assigments every week)
|
||||||
{
|
{
|
||||||
@ -358,6 +358,10 @@ async function filterPublishersNew(selectFields, filterDate, isExactTime = false
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!isNoEndDateFilter) { // Check if we need to apply the endTime filter
|
||||||
|
whereClause["availabilities"].some.OR[0].endTime = { lte: monthInfo.lastSunday };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`getting publishers for date: ${filterDate}, isExactTime: ${isExactTime}, isForTheMonth: ${isForTheMonth}`);
|
console.log(`getting publishers for date: ${filterDate}, isExactTime: ${isExactTime}, isForTheMonth: ${isForTheMonth}`);
|
||||||
|
25
src/logger.js
Normal file
25
src/logger.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
const winston = require('winston');
|
||||||
|
require('winston-daily-rotate-file');
|
||||||
|
|
||||||
|
const logConfiguration = {
|
||||||
|
'transports': [
|
||||||
|
new winston.transports.DailyRotateFile({
|
||||||
|
filename: './logs/application-%DATE%.log',
|
||||||
|
datePattern: 'YYYY-MM-DD-HH',
|
||||||
|
zippedArchive: true,
|
||||||
|
maxSize: '20m',
|
||||||
|
maxFiles: '90d',
|
||||||
|
level: 'info'
|
||||||
|
})
|
||||||
|
],
|
||||||
|
format: winston.format.combine(
|
||||||
|
winston.format.timestamp({
|
||||||
|
format: 'YYYY-MM-DD HH:mm:ss'
|
||||||
|
}),
|
||||||
|
winston.format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const logger = winston.createLogger(logConfiguration);
|
||||||
|
|
||||||
|
module.exports = logger;
|
Reference in New Issue
Block a user