diff --git a/app/routes/add.schedule.tsx b/app/routes/add.schedule.tsx index 99800e1..13813d7 100644 --- a/app/routes/add.schedule.tsx +++ b/app/routes/add.schedule.tsx @@ -155,8 +155,8 @@ export async function action({ request }: ActionFunctionArgs) { const locationId = data.locationId const scheduleDates = oneDay - ? getMonthlyScheduleDates(oneDay, isRepetiveMonth) - : getWeeklyScheduleDates(weeklyDays, isRepetiveWeek) + ? getMonthlyScheduleDates(oneDay, isRepetiveMonth ?? false) + : getWeeklyScheduleDates(weeklyDays, isRepetiveWeek ?? false) const existingSchedules = await prisma.schedule.findMany({ where: { diff --git a/app/services/schedule.server.test.ts b/app/services/schedule.server.test.ts index 6d0a7ba..23f4581 100644 --- a/app/services/schedule.server.test.ts +++ b/app/services/schedule.server.test.ts @@ -58,9 +58,9 @@ describe('getWeeklyScheduleDates', () => { false, ) expect(result).toHaveLength(3) - expect(result[0].toISOString()).toBe('2024-09-08T00:00:00.000Z') // Next Sunday - expect(result[1].toISOString()).toBe('2024-09-04T00:00:00.000Z') // Same Wednesday - expect(result[2].toISOString()).toBe('2024-09-06T00:00:00.000Z') // Next Friday + expect(result[0].toISOString()).toBe('2024-09-04T00:00:00.000Z') // Same Wednesday + expect(result[1].toISOString()).toBe('2024-09-06T00:00:00.000Z') // Next Friday + expect(result[2].toISOString()).toBe('2024-09-08T00:00:00.000Z') // Next Sunday }) it(`should return the next ${REPEAT_WEEKS} occurrences for a single day (repetitive)`, () => { diff --git a/app/services/schedule.server.ts b/app/services/schedule.server.ts index 5cb9ef4..19ef63e 100644 --- a/app/services/schedule.server.ts +++ b/app/services/schedule.server.ts @@ -1,5 +1,5 @@ import { Schedule } from '@prisma/client' -import { add, getDay, addMonths, addWeeks } from 'date-fns' +import { addMonths, addDays } from 'date-fns' import { DAYS } from '~/routes/add.schedule' import { getHoursAndMinutes } from '~/utils/schedule' @@ -27,57 +27,60 @@ export function getMonthlyScheduleDates( ) } -function getDayByNumber(day: (typeof DAYS)[number]) { - const daysOfWeek = { - sunday: 0, - monday: 1, - tuesday: 2, - wednesday: 3, - thursday: 4, - friday: 5, - saturday: 6, - } - return daysOfWeek[day] -} - -export function getWeeklyScheduleDates( - days?: TDay[], - isRepetitiveWeek?: boolean, -) { - if (!days) return [] +export function getWeeklyScheduleDates(daysArray?: TDay[], isRepetive = false) { + if (!daysArray?.length) return [] const today = new Date() - const currentDayIndex = getDay(today) - - // Calculate the next occurrence for each day - const nextOccurrences = days.map(day => { - const targetDayIndex = getDayByNumber(day) - let daysUntilNextOccurrence = (targetDayIndex - currentDayIndex + 7) % 7 - if (daysUntilNextOccurrence === 0 && today.getDay() !== targetDayIndex) { - daysUntilNextOccurrence = 7 + const dayNames = [ + 'sunday', + 'monday', + 'tuesday', + 'wednesday', + 'thursday', + 'friday', + 'saturday', + ] + + // Function to find the next occurrences for a given weekday name + const getOccurrences = (dayName: string) => { + const dayIndex = dayNames.indexOf(dayName.toLocaleLowerCase()) + const occurrences = [] + let currentDate = today + + // Check if today matches the target day + if (currentDate.getDay() === dayIndex) { + occurrences.push(currentDate) } - const nextDate = add(today, { days: daysUntilNextOccurrence }) - nextDate.setUTCHours(0, 0, 0, 0) - return nextDate - }) - if (!isRepetitiveWeek) return nextOccurrences - - // Generate the next 52 occurrences for each selected day - const occurrences = days.flatMap(day => { - const targetDayIndex = getDayByNumber(day) - return Array.from({ length: REPEAT_WEEKS }, (_, week) => { - const baseDate = nextOccurrences.find( - occurrence => getDay(occurrence) === targetDayIndex, - )! - // Calculate the occurrence date for this week + week offset - return addWeeks(baseDate, week) - }) - }) + // Generate future occurrences + const targetOccurrences = isRepetive ? REPEAT_WEEKS : 1 + while (occurrences.length < targetOccurrences) { + currentDate = addDays(currentDate, 1) - // Sort occurrences by date to ensure they're in the correct order - occurrences.sort((a, b) => a.getTime() - b.getTime()) + if (currentDate.getDay() === dayIndex) { + occurrences.push(new Date(currentDate)) // Add occurrence + } + + // Safety check to avoid infinite loop + if (occurrences.length > 366) { + console.error('Infinite loop detected') + break + } + } + + return occurrences + } + + // Generate all occurrences for the input days + const allOccurrences = daysArray.flatMap(dayName => getOccurrences(dayName)) + + // Remove duplicates, sort, and format the dates + const uniqueDates = Array.from( + new Set(allOccurrences.map(date => date.getTime())), + ) + .sort((a, b) => a - b) + .map(date => new Date(date)) - return occurrences + return uniqueDates } export function checkOverlapSchedule( diff --git a/prisma/dev.db b/prisma/dev.db index 604c08d..df6116b 100644 Binary files a/prisma/dev.db and b/prisma/dev.db differ