Created
August 23, 2024 13:06
-
-
Save shashwat-idm/e4932540d297561514f592f00957d239 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Task } from '../../models/task.model.js' | |
import TaskException from '../../models/taskException.model.js' | |
import { DateTime } from 'luxon' | |
import pkg from 'rrule' | |
const { RRule } = pkg | |
import mongoose from 'mongoose' | |
// const getTasksByDueDate = async (baseDate, userId) => { | |
// try { | |
// // Convert baseDate to Luxon DateTime object | |
// const baseDateTime = DateTime.fromISO(baseDate) | |
// // Calculate today, tomorrow, and day after tomorrow dates based on baseDate | |
// const today = baseDateTime.toISODate() | |
// const tomorrow = baseDateTime.plus({ days: 1 }).toISODate() | |
// const dayAfterTomorrow = baseDateTime.plus({ days: 2 }).toISODate() | |
// // Fetch tasks from database for the given userId and due dates | |
// const tasks = await Task.find({ | |
// userId: userId, | |
// dueDate: { $in: [today, tomorrow, dayAfterTomorrow] }, | |
// }).sort({ dueDate: 1 }) | |
// // Group tasks by due date | |
// const groupedTasks = { | |
// today: [], | |
// tomorrow: [], | |
// dayAfterTomorrow: [], | |
// } | |
// tasks.forEach((task) => { | |
// if (task.dueDate === today) { | |
// groupedTasks.today.push(task) | |
// } else if (task.dueDate === tomorrow) { | |
// groupedTasks.tomorrow.push(task) | |
// } else if (task.dueDate === dayAfterTomorrow) { | |
// groupedTasks.dayAfterTomorrow.push(task) | |
// } | |
// }) | |
// return groupedTasks | |
// } catch (err) { | |
// console.error(err) | |
// throw new Error('Error fetching tasks') | |
// } | |
// } | |
const expandRecurringTasks = (task, startDateStr, endDateStr, timeZone) => { | |
if (!task.isRecurring || !task.recurrence) { | |
return [task] // Return the task as is if it's not recurring | |
} | |
// console.log(task.dueDate) | |
const clientTimeZone = timeZone | |
const hasBYDAY = task.recurrence.includes('BYDAY') | |
// Parse the task's dueDate | |
// const taskDueDate = DateTime.fromFormat(task.dueDate, 'yyyy-MM-dd').toJSDate() | |
// const taskDueDate = DateTime.fromFormat(task.dueDate, 'yyyy-MM-dd', { | |
// zone: 'UTC', | |
// }).toJSDate() | |
console.log('due due :', task.dueDate) | |
if (hasBYDAY) { | |
console.log('Recurrence with BYDAY:', task.recurrence) | |
} | |
// Create the recurrence rule from the string | |
const rule = new RRule({ | |
...RRule.parseString(task.recurrence), | |
dtstart: task.dueDate, | |
}) | |
// Parse the provided date range | |
// const startDate = DateTime.fromFormat(startDateStr, 'yyyy-MM-dd').toJSDate() | |
// const endDate = DateTime.fromFormat(endDateStr, 'yyyy-MM-dd').toJSDate() | |
const startDate = DateTime.fromFormat(startDateStr, 'yyyy-MM-dd', { | |
zone: clientTimeZone, | |
}).toJSDate() | |
const endDate = DateTime.fromFormat(endDateStr, 'yyyy-MM-dd', { | |
zone: clientTimeZone, | |
}).toJSDate() | |
// Get occurrences of the rule within the date range | |
const occurrences = rule.between(startDate, endDate, true) | |
// console.log(occurrences) | |
const convertedOccurrences = occurrences.map((date) => | |
DateTime.fromJSDate(date, { zone: 'UTC' }) | |
.setZone(clientTimeZone) | |
.toJSDate() | |
) | |
// console.log(convertedOccurrences) | |
// console.log(occurrences) | |
// Map occurrences to expanded tasks | |
// const modifiedDates = occurrences.map((date) => { | |
// // Convert each Date object to a Luxon DateTime object in UTC | |
// const dt = DateTime.fromJSDate(date, { zone: 'utc' }) | |
// // Subtract 24 hours (1 day) from the date | |
// const modifiedDt = dt.minus({ days: 1 }) | |
// // Format the modified date back to ISO 8601 format | |
// return modifiedDt.toISO() | |
// }) | |
// const originalDates = modifiedDates.map((dateString) => new Date(dateString)) | |
// console.log('originalDates:', originalDates) | |
// if (hasBYDAY) { | |
// // occurrences = originalDates | |
// console.log('final :', originalDates) | |
// return originalDates.map((date) => ({ | |
// ...task.toObject(), // Convert Mongoose document to plain object | |
// dueDate: DateTime.fromJSDate(date).toFormat('yyyy-MM-dd'), // Convert date to yyyy-MM-dd string | |
// _id: new mongoose.Types.ObjectId(), // Generate new ObjectId for each instance | |
// originalTaskId: task._id, // Add the original task ID | |
// })) | |
// } else { | |
// console.log('normal :', occurrences) | |
// return occurrences.map((date) => ({ | |
// ...task.toObject(), // Convert Mongoose document to plain object | |
// dueDate: DateTime.fromJSDate(date).toFormat('yyyy-MM-dd'), // Convert date to yyyy-MM-dd string | |
// _id: new mongoose.Types.ObjectId(), // Generate new ObjectId for each instance | |
// originalTaskId: task._id, // Add the original task ID | |
// })) | |
// } | |
// console.log(latest) | |
return convertedOccurrences.map((date) => ({ | |
...task.toObject(), // Convert Mongoose document to plain object | |
// dueDate: DateTime.fromJSDate(date).toFormat('yyyy-MM-dd'), // Convert date to yyyy-MM-dd string | |
dueDate: date, | |
occurrenceDate: date, | |
_id: new mongoose.Types.ObjectId(), // Generate new ObjectId for each instance | |
originalTaskId: task._id, // Add the original task ID | |
})) | |
} | |
// const getTaskByDateRange = async (startDate, endDate, userId) => { | |
// try { | |
// // Fetch all tasks from the database | |
// const tasks = await Task.find({ | |
// $or: [ | |
// { dueDate: { $gte: startDate, $lte: endDate } }, // Non-recurring tasks | |
// { isRecurring: true }, // Recurring tasks | |
// ], | |
// userId: userId, | |
// }) | |
// // Expand recurring tasks dynamically including checking for exceptions | |
// const expandedTasks = [] | |
// for (let task of tasks) { | |
// const occurrences = expandRecurringTasks(task, startDate, endDate) | |
// for (let occurrence of occurrences) { | |
// // Check for an exception for the current occurrence | |
// const exception = await TaskException.findOne({ | |
// originalTaskId: task._id, | |
// occurrenceDate: occurrence.dueDate, | |
// }) | |
// if (exception) { | |
// const updatedOccurrence = { ...occurrence } | |
// if (exception.updatedName !== null) | |
// updatedOccurrence.name = exception.updatedName | |
// if (exception.updatedDescription !== null) | |
// updatedOccurrence.description = exception.updatedDescription | |
// if (exception.updatedPriority !== null) | |
// updatedOccurrence.priority = exception.updatedPriority | |
// if (exception.updatedLabels !== null) | |
// updatedOccurrence.labels = exception.updatedLabels | |
// if (exception.updatedComments !== null) | |
// updatedOccurrence.comments = exception.updatedComments | |
// if (exception.updatedExternalLink !== null) | |
// updatedOccurrence.externalLink = exception.updatedExternalLink | |
// if (exception.updatedDuration !== null) | |
// updatedOccurrence.duration = exception.updatedDuration | |
// if (exception.updatedDueDate !== null) | |
// updatedOccurrence.dueDate = exception.updatedDueDate | |
// if (exception.isCompleted !== null) | |
// updatedOccurrence.isCompleted = exception.isCompleted | |
// expandedTasks.push(updatedOccurrence) | |
// } else { | |
// // Otherwise, use the original task occurrence | |
// expandedTasks.push(occurrence) | |
// } | |
// } | |
// } | |
// return expandedTasks | |
// } catch (error) { | |
// throw new Error(error.message) | |
// } | |
// } | |
const getTaskByDateRange = async (baseDate, endDate, userId) => { | |
try { | |
// Fetch all tasks from the database | |
const tasks = await Task.find({ | |
$or: [ | |
{ dueDate: { $gte: baseDate, $lte: endDate } }, // Non-recurring tasks | |
{ isRecurring: true }, // Recurring tasks | |
], | |
userId: userId, | |
}) | |
// console.log(tasks) | |
// Expand recurring tasks dynamically including checking for exceptions | |
const expandedTasks = [] | |
for (let task of tasks) { | |
const occurrences = expandRecurringTasks(task, baseDate, endDate) | |
for (let occurrence of occurrences) { | |
// Check for an exception for the current occurrence | |
const exception = await TaskException.findOne({ | |
originalTaskId: task._id, | |
occurrenceDate: occurrence.occurrenceDate, | |
}) | |
// console.log('me :', exception) | |
if (exception) { | |
const updatedOccurrence = { ...occurrence } | |
if (exception.updatedSection === 'completed') { | |
// console.log(exception.updatedSection) | |
updatedOccurrence.isCompleted = true | |
// console.log(updatedOccurrence.isCompleted) | |
} | |
if (exception.updatedName !== undefined) | |
updatedOccurrence.name = exception.updatedName | |
if (exception.updatedDescription !== undefined) | |
updatedOccurrence.description = exception.updatedDescription | |
if (exception.updatedPriority !== undefined) | |
updatedOccurrence.priority = exception.updatedPriority | |
if (exception.updatedLabels !== undefined) | |
updatedOccurrence.labels = exception.updatedLabels | |
if (exception.updatedComments !== undefined) | |
updatedOccurrence.comments = exception.updatedComments | |
if (exception.updatedExternalLink !== undefined) | |
updatedOccurrence.externalLink = exception.updatedExternalLink | |
if (exception.updatedDuration !== undefined) | |
updatedOccurrence.duration = exception.updatedDuration | |
if (exception.updatedDueDate !== undefined) { | |
updatedOccurrence.dueDate = exception.updatedDueDate | |
} | |
//updated eventId -> even put it in schema | |
if (exception.updatedSection !== undefined) | |
updatedOccurrence.section = exception.updatedSection | |
// if (exception.isCompleted !== undefined) | |
// updatedOccurrence.isCompleted = exception.isCompleted | |
if (exception.updatedEventId !== undefined) { | |
updatedOccurrence.eventId = exception.updatedEventId | |
} | |
// also update _id, for exception tasks atleast the _id would be consistently same for exceptional tasks | |
updatedOccurrence._id = exception._id | |
expandedTasks.push(updatedOccurrence) | |
} else { | |
// Otherwise, use the original task occurrence | |
expandedTasks.push(occurrence) | |
} | |
} | |
} | |
// Group tasks by due date | |
const groupedTasks = { | |
today: [], | |
tomorrow: [], | |
dayAfterTomorrow: [], | |
} | |
// console.log(baseDate) | |
// const baseDatenew = DateTime.fromISO(baseDate, { zone: 'UTC' }) | |
// console.log(baseDatenew) | |
// console.log(expandedTasks) | |
const baseDateTime = DateTime.fromISO(baseDate) | |
const today = baseDateTime.toISODate() | |
const tomorrow = baseDateTime.plus({ days: 1 }).toISODate() | |
const dayAfterTomorrow = baseDateTime.plus({ days: 2 }).toISODate() | |
expandedTasks.forEach((task) => { | |
const dueDateTime = DateTime.fromJSDate(task.dueDate, { zone: 'UTC' }) | |
// Format the DateTime object to "yyyy-MM-dd" | |
const formattedDueDate = dueDateTime.toFormat('yyyy-MM-dd') | |
console.log('formattedDueDate :', formattedDueDate) | |
if (formattedDueDate === today) { | |
groupedTasks.today.push(task) | |
} else if (formattedDueDate === tomorrow) { | |
groupedTasks.tomorrow.push(task) | |
} else if (formattedDueDate === dayAfterTomorrow) { | |
groupedTasks.dayAfterTomorrow.push(task) | |
} | |
}) | |
return groupedTasks | |
} catch (error) { | |
throw new Error(error.message) | |
} | |
} | |
const updateOccurrence = async (taskId, occurrenceDate, changes) => { | |
console.log('here :', occurrenceDate) | |
try { | |
// Find or create the task exception | |
const exception = await TaskException.findOneAndUpdate( | |
{ | |
originalTaskId: taskId, | |
occurrenceDate: occurrenceDate, | |
}, | |
{ | |
$set: { | |
originalTaskId: taskId, | |
occurrenceDate: occurrenceDate, | |
...changes, | |
}, | |
}, | |
{ upsert: true, new: true, runValidators: true } | |
) | |
return exception | |
} catch (error) { | |
console.error('Error updating occurrence:', error) | |
throw new Error(error.message) | |
} | |
} | |
export default { | |
// getTasksByDueDate, | |
getTaskByDateRange, | |
updateOccurrence, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment