Skip to content

Instantly share code, notes, and snippets.

@shashwat-idm
Created August 23, 2024 13:06
Show Gist options
  • Save shashwat-idm/e4932540d297561514f592f00957d239 to your computer and use it in GitHub Desktop.
Save shashwat-idm/e4932540d297561514f592f00957d239 to your computer and use it in GitHub Desktop.
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