changemaker.lite/api/dist/modules/map/shifts/shift-series.service.js

180 lines
6.7 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ShiftSeriesService = void 0;
const database_1 = require("../../../config/database");
const client_1 = require("@prisma/client");
const MAX_OCCURRENCES = 100;
const MAX_DAYS = 365;
class ShiftSeriesService {
/**
* Generate occurrence dates based on recurrence rules
*/
static generateOccurrences(input) {
const dates = [];
const startDate = new Date(input.startDate);
const endDate = input.endDate ? new Date(input.endDate) : null;
let currentDate = new Date(startDate);
let count = 0;
while (count < MAX_OCCURRENCES) {
// Check end date
if (endDate && currentDate > endDate)
break;
// Check max days
const daysDiff = Math.floor((currentDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24));
if (daysDiff > MAX_DAYS)
break;
// Check if date matches recurrence pattern
let shouldInclude = false;
if (input.frequency === client_1.RecurrenceFrequency.DAILY) {
shouldInclude = true;
}
else if (input.frequency === client_1.RecurrenceFrequency.WEEKLY) {
const dayOfWeek = currentDate.getDay(); // 0=Sun, 6=Sat
shouldInclude = input.daysOfWeek?.includes(dayOfWeek) ?? false;
}
else if (input.frequency === client_1.RecurrenceFrequency.MONTHLY) {
shouldInclude = currentDate.getDate() === startDate.getDate();
}
if (shouldInclude) {
dates.push(new Date(currentDate));
count++;
}
// Increment date
if (input.frequency === client_1.RecurrenceFrequency.DAILY) {
currentDate.setDate(currentDate.getDate() + 1);
}
else if (input.frequency === client_1.RecurrenceFrequency.WEEKLY) {
currentDate.setDate(currentDate.getDate() + 1); // Check each day
}
else if (input.frequency === client_1.RecurrenceFrequency.MONTHLY) {
currentDate.setMonth(currentDate.getMonth() + 1);
}
}
return dates;
}
/**
* Create a shift series and generate all individual shifts
*/
static async createSeries(input, createdBy) {
// Generate occurrence dates
const dates = this.generateOccurrences(input);
if (dates.length === 0) {
throw new Error('No valid dates generated from recurrence rules');
}
// Create series and shifts in transaction
const result = await database_1.prisma.$transaction(async (tx) => {
// Create series
const series = await tx.shiftSeries.create({
data: {
title: input.title,
description: input.description,
startTime: input.startTime,
endTime: input.endTime,
location: input.location,
maxVolunteers: input.maxVolunteers,
isPublic: input.isPublic ?? false,
cutId: input.cutId,
frequency: input.frequency,
daysOfWeek: input.daysOfWeek,
startDate: new Date(input.startDate),
endDate: input.endDate ? new Date(input.endDate) : null,
createdBy,
},
});
// Create individual shifts
const shifts = await Promise.all(dates.map((date) => tx.shift.create({
data: {
title: input.title,
description: input.description,
date,
startTime: input.startTime,
endTime: input.endTime,
location: input.location,
maxVolunteers: input.maxVolunteers,
isPublic: input.isPublic ?? false,
cutId: input.cutId,
seriesId: series.id,
createdBy,
},
})));
return { series, shifts };
});
return {
series: result.series,
generatedShiftsCount: result.shifts.length,
};
}
/**
* Get series with all its shifts
*/
static async getSeries(seriesId) {
const series = await database_1.prisma.shiftSeries.findUnique({
where: { id: seriesId },
include: {
cut: true,
shifts: {
orderBy: { date: 'asc' },
include: { signups: true },
},
},
});
if (!series) {
throw new Error('Shift series not found');
}
return series;
}
/**
* Update series shifts based on edit mode
*/
static async updateSeries(seriesId, input) {
const series = await database_1.prisma.shiftSeries.findUnique({
where: { id: seriesId },
include: { shifts: true },
});
if (!series) {
throw new Error('Shift series not found');
}
const { editMode, fromDate, ...updates } = input;
if (editMode === 'ALL') {
// Update series + all shifts
await database_1.prisma.$transaction(async (tx) => {
await tx.shiftSeries.update({
where: { id: seriesId },
data: updates,
});
await tx.shift.updateMany({
where: { seriesId, isException: false },
data: updates,
});
});
}
else if (editMode === 'FUTURE' && fromDate) {
// Update shifts from date onwards
await database_1.prisma.shift.updateMany({
where: {
seriesId,
date: { gte: new Date(fromDate) },
isException: false,
},
data: updates,
});
}
// Note: THIS mode is handled by regular shift update with isException flag
return this.getSeries(seriesId);
}
/**
* Delete series (cascades to shifts via onDelete: SetNull)
*/
static async deleteSeries(seriesId) {
// Delete all shifts in series first
await database_1.prisma.shift.deleteMany({
where: { seriesId },
});
// Then delete series
await database_1.prisma.shiftSeries.delete({
where: { id: seriesId },
});
}
}
exports.ShiftSeriesService = ShiftSeriesService;
//# sourceMappingURL=shift-series.service.js.map