fix shift generation for day, ranking, family, etc...
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -18,7 +18,6 @@ lerna-debug.log*
|
|||||||
**/public/workbox-*.js.map
|
**/public/workbox-*.js.map
|
||||||
**/public/worker-*.js.map
|
**/public/worker-*.js.map
|
||||||
|
|
||||||
|
|
||||||
.eslintcache
|
.eslintcache
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
next-env.d.ts
|
next-env.d.ts
|
||||||
@ -37,3 +36,4 @@ public/content/output/*
|
|||||||
public/content/output/shifts 2024.1.json
|
public/content/output/shifts 2024.1.json
|
||||||
!public/content/uploads/*
|
!public/content/uploads/*
|
||||||
.aider*
|
.aider*
|
||||||
|
/shift_generate_log_*.txt
|
||||||
|
@ -143,7 +143,7 @@ function flattenRegistry(dayKey) {
|
|||||||
return Object.values(weekEntries).flat();
|
return Object.values(weekEntries).flat();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, autoFill = false, forDay, algType = 0) {
|
async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, autoFill = false, forDay, algType = 0, until) {
|
||||||
|
|
||||||
let missingPublishers = [];
|
let missingPublishers = [];
|
||||||
let publishersWithChangedPref = [];
|
let publishersWithChangedPref = [];
|
||||||
@ -176,7 +176,14 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
|
|||||||
|
|
||||||
if (forDay) {
|
if (forDay) {
|
||||||
day = monthInfo.date;
|
day = monthInfo.date;
|
||||||
endDate.setDate(monthInfo.date.getDate() + 1);
|
if (until === undefined) {
|
||||||
|
const oneDayInMs = 24 * 60 * 60 * 1000;
|
||||||
|
endDate = new Date(monthInfo.date.getTime() + oneDayInMs);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
endDate = new Date(until);
|
||||||
|
}
|
||||||
|
|
||||||
dayNr = monthInfo.date.getDate();
|
dayNr = monthInfo.date.getDate();
|
||||||
weekNr = common.getWeekNumber(monthInfo.date);
|
weekNr = common.getWeekNumber(monthInfo.date);
|
||||||
}
|
}
|
||||||
@ -184,7 +191,7 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
|
|||||||
let publishersThisWeek = [];
|
let publishersThisWeek = [];
|
||||||
|
|
||||||
|
|
||||||
|
// # # # # # # # # # # #
|
||||||
// 0. generate shifts and assign publishers from the previous month if still available
|
// 0. generate shifts and assign publishers from the previous month if still available
|
||||||
while (day < endDate) {
|
while (day < endDate) {
|
||||||
let availablePubsForTheDay = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth,lastLogin,type', day, false, false, false, true, false);
|
let availablePubsForTheDay = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth,lastLogin,type', day, false, false, false, true, false);
|
||||||
@ -262,7 +269,7 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
|
|||||||
//ToDo: check if getAvailablePublishersForShift is working correctly. It seems not to!
|
//ToDo: check if getAvailablePublishersForShift is working correctly. It seems not to!
|
||||||
let availablePublishers = await getAvailablePublishersForShiftNew(shiftStart, shiftEnd, availablePubsForTheDay, publishersThisWeek);
|
let availablePublishers = await getAvailablePublishersForShiftNew(shiftStart, shiftEnd, availablePubsForTheDay, publishersThisWeek);
|
||||||
|
|
||||||
console.log("shift " + __shiftName + " needs " + publishersNeeded + " publishers, available: " + availablePublishers.length + " for the day: " + availablePubsForTheDay.length);
|
console.log("shift " + __shiftName + " needs " + publishersNeeded + " publishers, available: " + availablePublishers.length + ", for the day: " + availablePubsForTheDay.length);
|
||||||
|
|
||||||
const createdShift = await prisma.shift.create({
|
const createdShift = await prisma.shift.create({
|
||||||
data: {
|
data: {
|
||||||
@ -294,21 +301,31 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
|
|||||||
shiftEnd.setMinutes(shiftStart.getMinutes() + event.shiftDuration);
|
shiftEnd.setMinutes(shiftStart.getMinutes() + event.shiftDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
day.setDate(day.getDate() + 1);
|
|
||||||
dayNr++;
|
if (forDay) { break; }
|
||||||
if (common.DaysOfWeekArray[day.getDayEuropean()] === DayOfWeek.Sunday) {
|
else {
|
||||||
weekNr++;
|
day.setDate(day.getDate() + 1);
|
||||||
publishersThisWeek = [];
|
dayNr++;
|
||||||
publishers.forEach(p => p.currentWeekAssignments = 0);
|
if (common.DaysOfWeekArray[day.getDayEuropean()] === DayOfWeek.Sunday) {
|
||||||
|
weekNr++;
|
||||||
|
publishersThisWeek = [];
|
||||||
|
publishers.forEach(p => p.currentWeekAssignments = 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (forDay) break;
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let from = monthInfo.firstMonday, to = monthInfo.lastSunday;
|
||||||
|
if (forDay) {
|
||||||
|
from = day;
|
||||||
|
to = endDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
let allShifts = await prisma.shift.findMany({
|
let allShifts = await prisma.shift.findMany({
|
||||||
where: {
|
where: {
|
||||||
startTime: {
|
startTime: {
|
||||||
gte: monthInfo.firstMonday,
|
gte: from,
|
||||||
lt: monthInfo.lastSunday,
|
lt: to,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
@ -320,17 +337,23 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
let publishersToday = [];
|
let publishersToday = [];
|
||||||
let rankedPublishers = [];
|
let rankedPublishers = [];
|
||||||
|
|
||||||
|
// # # # # # # # # # # #
|
||||||
// Second pass - prioritize shifts with transport where it is needed
|
// Second pass - prioritize shifts with transport where it is needed
|
||||||
|
if (forDay) { }
|
||||||
|
else {
|
||||||
|
day = new Date(monthInfo.firstMonday);
|
||||||
|
dayNr = 1;
|
||||||
|
weekNr = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
console.log("\r\n\r\n\r\n" + "# ".repeat(50));
|
console.log("\r\n\r\n\r\n" + "# ".repeat(50));
|
||||||
console.log("Second pass - fix transports " + monthInfo.monthName + " " + monthInfo.year);
|
console.log("Second pass - fix transports " + day.toLocaleDateString());
|
||||||
|
|
||||||
day = new Date(monthInfo.firstMonday);
|
|
||||||
dayNr = 1;
|
|
||||||
weekNr = 1;
|
|
||||||
while (day < endDate) {
|
while (day < endDate) {
|
||||||
let dayOfWeekEnum = common.getDayOfWeekNameEnEnumForDate(day);
|
let dayOfWeekEnum = common.getDayOfWeekNameEnEnumForDate(day);
|
||||||
let event = events.find((event) => event.dayofweek == common.DaysOfWeekArray[day.getDayEuropean()]);
|
let event = events.find((event) => event.dayofweek == common.DaysOfWeekArray[day.getDayEuropean()]);
|
||||||
@ -371,7 +394,7 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
|
|||||||
else if (publishersNeeded > 0) {
|
else if (publishersNeeded > 0) {
|
||||||
console.log("shift " + shift.name + " requires transport (" + transportCapable.length + " transport capable)");
|
console.log("shift " + shift.name + " requires transport (" + transportCapable.length + " transport capable)");
|
||||||
|
|
||||||
let availablePubsForTheShift = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth,lastLogin,type', shift.startTime, true, false, false, true, false);
|
let availablePubsForTheShift = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth,lastLogin,type,familyHeadId', shift.startTime, true, false, false, true, false);
|
||||||
|
|
||||||
let availablePublishers = availablePubsForTheShift.filter(p => {
|
let availablePublishers = availablePubsForTheShift.filter(p => {
|
||||||
const hasTransportInAvailability = shift.transportIn && p.availabilities.some(avail => avail.isWithTransportIn);
|
const hasTransportInAvailability = shift.transportIn && p.availabilities.some(avail => avail.isWithTransportIn);
|
||||||
@ -386,45 +409,35 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
|
|||||||
} else if (algType == 1) {
|
} else if (algType == 1) {
|
||||||
rankedPublishers = await RankPublishersForShiftWeighted([...availablePublishers], scheduledPubsPerDayAndWeek, day, weekNr);
|
rankedPublishers = await RankPublishersForShiftWeighted([...availablePublishers], scheduledPubsPerDayAndWeek, day, weekNr);
|
||||||
}
|
}
|
||||||
// if (rankedPublishers.length > 0) {
|
|
||||||
// const newAssignment = await prisma.assignment.create({
|
|
||||||
// data: {
|
|
||||||
// shift: {
|
|
||||||
// connect: {
|
|
||||||
// id: shift.id,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// publisher: {
|
|
||||||
// connect: {
|
|
||||||
// id: rankedPublishers[0].id,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// isWithTransport: true,
|
|
||||||
// isConfirmed: true,
|
|
||||||
// isBySystem: false,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// shift.assignments.push(newAssignment);
|
|
||||||
// publishersToday.push(rankedPublishers[0].id);
|
|
||||||
// updateRegistry(rankedPublishers[0].id, day, weekNr);
|
|
||||||
// }
|
|
||||||
AddPublisherAssignment(prisma, event, shift, availablePublishers, rankedPublishers, publishersToday, day, weekNr);
|
AddPublisherAssignment(prisma, event, shift, availablePublishers, rankedPublishers, publishersToday, day, weekNr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
day.setDate(day.getDate() + 1);
|
if (forDay) { break; }
|
||||||
|
else {
|
||||||
|
day.setDate(day.getDate() + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill the rest of the shifts
|
|
||||||
|
// # # # # # # # # # # #
|
||||||
|
// 3. Fill the rest of the shifts
|
||||||
let goal = 1;
|
let goal = 1;
|
||||||
while (goal <= 4) {
|
while (goal <= 4) {
|
||||||
console.log("\r\n\r\n\r\n" + "# ".repeat(50));
|
|
||||||
console.log("Filling shifts with " + goal + " publishers " + monthInfo.monthName + " " + monthInfo.year);
|
if (forDay) {
|
||||||
day = new Date(monthInfo.firstMonday);
|
}
|
||||||
dayNr = 1;
|
else {
|
||||||
weekNr = 1;
|
day = new Date(monthInfo.firstMonday);
|
||||||
|
dayNr = 1;
|
||||||
|
weekNr = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("\r\n\r\n" + "# ".repeat(50));
|
||||||
|
console.log("Filling shifts with " + goal + " publishers | " + day.toLocaleDateString());
|
||||||
|
|
||||||
while (day < endDate) {
|
while (day < endDate) {
|
||||||
let dayOfWeekEnum = common.getDayOfWeekNameEnEnumForDate(day);
|
let dayOfWeekEnum = common.getDayOfWeekNameEnEnumForDate(day);
|
||||||
let event = events.find((event) => event.dayofweek == common.DaysOfWeekArray[day.getDayEuropean()]);
|
let event = events.find((event) => event.dayofweek == common.DaysOfWeekArray[day.getDayEuropean()]);
|
||||||
@ -452,7 +465,7 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
|
|||||||
console.log("Filling shift " + shift.name + " with " + goal + " publishers");
|
console.log("Filling shift " + shift.name + " with " + goal + " publishers");
|
||||||
let publishersNeeded = event.numberOfPublishers - shift.assignments.length;
|
let publishersNeeded = event.numberOfPublishers - shift.assignments.length;
|
||||||
if (publishersNeeded > 0 && shift.assignments.length < goal) {
|
if (publishersNeeded > 0 && shift.assignments.length < goal) {
|
||||||
let availablePubsForTheShift = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth,lastLogin,type', shift.startTime, true, false, false, true, false);
|
let availablePubsForTheShift = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth,lastLogin,type,familyHeadId', shift.startTime, true, false, false, true, false);
|
||||||
|
|
||||||
let availablePublishers = await FilterInappropriatePublishers([...availablePubsForTheShift], publishersToday, shift);
|
let availablePublishers = await FilterInappropriatePublishers([...availablePubsForTheShift], publishersToday, shift);
|
||||||
if (algType == 0) {
|
if (algType == 0) {
|
||||||
@ -461,12 +474,17 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
|
|||||||
rankedPublishers = await RankPublishersForShiftWeighted([...availablePublishers], scheduledPubsPerDayAndWeek, day, weekNr);
|
rankedPublishers = await RankPublishersForShiftWeighted([...availablePublishers], scheduledPubsPerDayAndWeek, day, weekNr);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddPublisherAssignment(prisma, event, shift, availablePublishers, rankedPublishers, publishersToday, day, weekNr);
|
await AddPublisherAssignment(prisma, event, shift, availablePublishers, rankedPublishers, publishersToday, day, weekNr);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
day.setDate(day.getDate() + 1);
|
if (forDay) { break; }
|
||||||
|
else {
|
||||||
|
day.setDate(day.getDate() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
goal += 1;
|
goal += 1;
|
||||||
}
|
}
|
||||||
@ -486,14 +504,18 @@ async function GenerateSchedule(axios, date, copyFromPreviousMonth = false, auto
|
|||||||
|
|
||||||
async function AddPublisherAssignment(prisma, event, shift, availablePubsForTheShift, rankedPublishers, publishersToday, day, weekNr) {
|
async function AddPublisherAssignment(prisma, event, shift, availablePubsForTheShift, rankedPublishers, publishersToday, day, weekNr) {
|
||||||
if (rankedPublishers.length == 0) {
|
if (rankedPublishers.length == 0) {
|
||||||
console.log("No available publishers for shift " + shift.name);
|
console.log("! ! ! No available publishers for shift " + shift.name + " ! ! !");
|
||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < rankedPublishers.length; i++) {
|
for (let i = 0; i < rankedPublishers.length; i++) {
|
||||||
let mainPublisher = rankedPublishers[i];
|
let mainPublisher = rankedPublishers[i];
|
||||||
let familyMembers = availablePubsForTheShift.filter(p => (p.familyHeadId && p.familyHeadId === mainPublisher.familyHeadId) || (p.familyHeadId === mainPublisher.id));
|
let familyMembers = availablePubsForTheShift.filter(p => (p.id !== mainPublisher.id && (p.id === mainPublisher.familyHeadId) || (p.familyHeadId === mainPublisher.id)));
|
||||||
|
|
||||||
if (familyMembers.length > 0 && (shift.assignments.length + familyMembers.length + 1) <= event.numberOfPublishers) {
|
if (familyMembers.length > 0 && (shift.assignments.length + familyMembers.length + 1) <= event.numberOfPublishers) {
|
||||||
console.log("Assigning " + mainPublisher.firstName + " " + mainPublisher.lastName + " and family members to " + new Date(shift.startTime).getDate() + " " + shift.name);
|
console.log("Assigning " + mainPublisher.firstName + " " + mainPublisher.lastName + " and " + familyMembers.length + " available family members to " + new Date(shift.startTime).getDate() + " " + shift.name);
|
||||||
|
|
||||||
|
const hasTransportInAvailability = shift.transportIn && mainPublisher.availabilities.some(avail => avail.isWithTransportIn);
|
||||||
|
const hasTransportOutAvailability = shift.transportOut && mainPublisher.availabilities.some(avail => avail.isWithTransportOut);
|
||||||
|
|
||||||
const newAssignment = await prisma.assignment.create({
|
const newAssignment = await prisma.assignment.create({
|
||||||
data: {
|
data: {
|
||||||
shift: {
|
shift: {
|
||||||
@ -508,7 +530,7 @@ async function AddPublisherAssignment(prisma, event, shift, availablePubsForTheS
|
|||||||
},
|
},
|
||||||
isConfirmed: false,
|
isConfirmed: false,
|
||||||
isBySystem: false,
|
isBySystem: false,
|
||||||
isWithTransport: shift.requiresTransport,
|
isWithTransport: (hasTransportInAvailability || hasTransportOutAvailability),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
shift.assignments.push(newAssignment);
|
shift.assignments.push(newAssignment);
|
||||||
@ -540,6 +562,10 @@ async function AddPublisherAssignment(prisma, event, shift, availablePubsForTheS
|
|||||||
break;
|
break;
|
||||||
} else if (familyMembers.length == 0) {
|
} else if (familyMembers.length == 0) {
|
||||||
console.log("Assigning " + mainPublisher.firstName + " " + mainPublisher.lastName + " to " + new Date(shift.startTime).getDate() + " " + shift.name);
|
console.log("Assigning " + mainPublisher.firstName + " " + mainPublisher.lastName + " to " + new Date(shift.startTime).getDate() + " " + shift.name);
|
||||||
|
|
||||||
|
const hasTransportInAvailability = shift.transportIn && mainPublisher.availabilities.some(avail => avail.isWithTransportIn);
|
||||||
|
const hasTransportOutAvailability = shift.transportOut && mainPublisher.availabilities.some(avail => avail.isWithTransportOut);
|
||||||
|
|
||||||
const newAssignment = await prisma.assignment.create({
|
const newAssignment = await prisma.assignment.create({
|
||||||
data: {
|
data: {
|
||||||
shift: {
|
shift: {
|
||||||
@ -554,7 +580,7 @@ async function AddPublisherAssignment(prisma, event, shift, availablePubsForTheS
|
|||||||
},
|
},
|
||||||
isConfirmed: false,
|
isConfirmed: false,
|
||||||
isBySystem: false,
|
isBySystem: false,
|
||||||
isWithTransport: shift.requiresTransport,
|
isWithTransport: (hasTransportInAvailability || hasTransportOutAvailability),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
shift.assignments.push(newAssignment);
|
shift.assignments.push(newAssignment);
|
||||||
@ -564,17 +590,16 @@ async function AddPublisherAssignment(prisma, event, shift, availablePubsForTheS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function FilterInappropriatePublishers(availablePublishers, pubsToExclude, shift) {
|
async function FilterInappropriatePublishers(availablePublishers, pubsToExclude, shift, maxShifts = 0) {
|
||||||
//ToDo: Optimization: store number of publishers, so we process the shifts from least to most available publishers later.
|
//ToDo: Optimization: store number of publishers, so we process the shifts from least to most available publishers later.
|
||||||
let goodPublishers = availablePublishers.filter(p => {
|
let goodPublishers = availablePublishers.filter(p => {
|
||||||
const isNotAssigned = !shift.assignments.some(a => a.publisher?.id === p.id);
|
const isNotAssigned = !shift.assignments.some(a => a.publisher?.id === p.id);
|
||||||
const isNotAssignedToday = !pubsToExclude.includes(p.id);
|
const isNotAssignedToday = !pubsToExclude.includes(p.id);
|
||||||
const isAssignedEnough = p.currentMonthAssignments >= p.desiredShiftsPerMonth
|
const isAssignedEnough = p.currentMonthAssignments >= p.desiredShiftsPerMonth
|
||||||
|| p.currentMonthAssignments >= 6; // overwrite the desiredShiftsPerMonth to max 6 shifts per month
|
|| p.currentMonthAssignments >= maxShifts; // overwrite the desiredShiftsPerMonth to max 10 shifts per month
|
||||||
return isNotAssigned && isNotAssignedToday && !isAssignedEnough;
|
return isNotAssigned && isNotAssignedToday && (!isAssignedEnough || maxShifts == 0);
|
||||||
});
|
});
|
||||||
return goodPublishers;
|
return goodPublishers;
|
||||||
}
|
}
|
||||||
@ -696,10 +721,17 @@ async function RankPublishersForShiftWeighted(publishers, scheduledPubsPerDayAnd
|
|||||||
const result = calculateScoreAndPenalties(p);
|
const result = calculateScoreAndPenalties(p);
|
||||||
p.score = result.score;
|
p.score = result.score;
|
||||||
p.penalties = result.penalties;
|
p.penalties = result.penalties;
|
||||||
|
|
||||||
|
p.finalScore = p.score;
|
||||||
|
if (p.finalScore > 0) {
|
||||||
|
p.penalties.forEach(penalty => {
|
||||||
|
p.finalScore *= penalty.penalty;
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sort publishers based on score
|
// Sort publishers based on score
|
||||||
let ranked = publishers.sort((a, b) => b.score - a.score);
|
let ranked = publishers.sort((a, b) => b.finalScore - a.finalScore);
|
||||||
|
|
||||||
// Log the scores and penalties of the top publisher
|
// Log the scores and penalties of the top publisher
|
||||||
if (ranked.length > 0) {
|
if (ranked.length > 0) {
|
||||||
|
@ -703,9 +703,11 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
|
|||||||
<button className="block w-full px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center" onClick={() => generateShifts("genEmptyDay", false, false, true)}>
|
<button className="block w-full px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center" onClick={() => generateShifts("genEmptyDay", false, false, true)}>
|
||||||
{isLoading('genEmptyDay') ? (<i className="fas fa-sync-alt fa-spin mr-2"></i>) : (<i className="fas fa-plus mr-2"></i>)}
|
{isLoading('genEmptyDay') ? (<i className="fas fa-sync-alt fa-spin mr-2"></i>) : (<i className="fas fa-plus mr-2"></i>)}
|
||||||
създай празни ({value.getDate()}-ти) </button>
|
създай празни ({value.getDate()}-ти) </button>
|
||||||
<button className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" onClick={() => generateShifts("genDay", false, true, true)}>
|
|
||||||
|
<button className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" onClick={() => generateShifts("genDay", false, true, true, 1)}>
|
||||||
{isLoading('genDay') ? (<i className="fas fa-sync-alt fa-spin mr-2"></i>) : (<i className="fas fa-cogs mr-2"></i>)}
|
{isLoading('genDay') ? (<i className="fas fa-sync-alt fa-spin mr-2"></i>) : (<i className="fas fa-cogs mr-2"></i>)}
|
||||||
Генерирай смени ({value.getDate()}-ти) </button>
|
Генерирай смени ({value.getDate()}-ти) </button>
|
||||||
|
|
||||||
<button className="block px-4 py-2 text-sm text-red-500 hover:bg-gray-100"
|
<button className="block px-4 py-2 text-sm text-red-500 hover:bg-gray-100"
|
||||||
onClick={() => openConfirmModal(
|
onClick={() => openConfirmModal(
|
||||||
'Сигурни ли сте че искате да изтриете смените и назначения на този ден?',
|
'Сигурни ли сте че искате да изтриете смените и назначения на този ден?',
|
||||||
|
Reference in New Issue
Block a user