From 316c51a64cb9657da7e7a64703691104fdb2a9a6 Mon Sep 17 00:00:00 2001 From: Manoj K Date: Thu, 6 Mar 2025 14:05:07 +0530 Subject: [PATCH] Feat: add CRUD Api for task occurrences --- .../migration.sql | 21 ++ .../migration.sql | 2 + apps/server/prisma/schema.prisma | 7 +- .../src/modules/pages/pages.controller.ts | 7 - .../server/src/modules/pages/pages.service.ts | 56 +--- .../replication/replication.interface.ts | 1 + .../task-occurence.controller.ts | 61 ++-- .../task-occurence/task-occurence.service.ts | 291 +++++++++++++----- .../modules/tasks-hook/tasks-hook.service.ts | 25 +- .../server/src/modules/tasks/tasks.service.ts | 4 +- .../src/triggers/page/task-occurence.ts | 67 ++-- .../src/sync-action/sync-action.entity.ts | 2 + .../create-task-occurence.dto.ts | 18 ++ packages/types/src/task-occurence/index.ts | 1 + .../update-task-occurence.dto.ts | 16 +- 15 files changed, 362 insertions(+), 217 deletions(-) create mode 100644 apps/server/prisma/migrations/20250306074350_add_unique_task_page_id_on_task_occurence/migration.sql create mode 100644 apps/server/prisma/migrations/20250306083417_add_task_occurrence_in_model_name/migration.sql create mode 100644 packages/types/src/task-occurence/create-task-occurence.dto.ts diff --git a/apps/server/prisma/migrations/20250306074350_add_unique_task_page_id_on_task_occurence/migration.sql b/apps/server/prisma/migrations/20250306074350_add_unique_task_page_id_on_task_occurence/migration.sql new file mode 100644 index 0000000..83a6f8e --- /dev/null +++ b/apps/server/prisma/migrations/20250306074350_add_unique_task_page_id_on_task_occurence/migration.sql @@ -0,0 +1,21 @@ +/* + Warnings: + + - A unique constraint covering the columns `[taskId,pageId]` on the table `TaskOccurrence` will be added. If there are existing duplicate values, this will fail. + - Made the column `pageId` on table `TaskOccurrence` required. This step will fail if there are existing NULL values in that column. + +*/ +-- DropForeignKey +ALTER TABLE "TaskOccurrence" DROP CONSTRAINT "TaskOccurrence_pageId_fkey"; + +-- DropIndex +DROP INDEX "TaskOccurrence_taskId_startTime_endTime_key"; + +-- AlterTable +ALTER TABLE "TaskOccurrence" ALTER COLUMN "pageId" SET NOT NULL; + +-- CreateIndex +CREATE UNIQUE INDEX "TaskOccurrence_taskId_pageId_key" ON "TaskOccurrence"("taskId", "pageId"); + +-- AddForeignKey +ALTER TABLE "TaskOccurrence" ADD CONSTRAINT "TaskOccurrence_pageId_fkey" FOREIGN KEY ("pageId") REFERENCES "Page"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20250306083417_add_task_occurrence_in_model_name/migration.sql b/apps/server/prisma/migrations/20250306083417_add_task_occurrence_in_model_name/migration.sql new file mode 100644 index 0000000..9461abf --- /dev/null +++ b/apps/server/prisma/migrations/20250306083417_add_task_occurrence_in_model_name/migration.sql @@ -0,0 +1,2 @@ +-- AlterEnum +ALTER TYPE "ModelName" ADD VALUE 'TaskOccurrence'; diff --git a/apps/server/prisma/schema.prisma b/apps/server/prisma/schema.prisma index cc324de..2d95b9e 100644 --- a/apps/server/prisma/schema.prisma +++ b/apps/server/prisma/schema.prisma @@ -372,13 +372,13 @@ model TaskOccurrence { task Task @relation(fields: [taskId], references: [id]) taskId String - page Page? @relation(fields: [pageId], references: [id]) - pageId String? + page Page @relation(fields: [pageId], references: [id]) + pageId String workspace Workspace @relation(fields: [workspaceId], references: [id]) workspaceId String - @@unique([taskId, startTime, endTime]) + @@unique([taskId, pageId]) } model Template { @@ -466,6 +466,7 @@ enum ModelName { Conversation ConversationHistory List + TaskOccurrence } enum ActionType { diff --git a/apps/server/src/modules/pages/pages.controller.ts b/apps/server/src/modules/pages/pages.controller.ts index 2718570..cf2c585 100644 --- a/apps/server/src/modules/pages/pages.controller.ts +++ b/apps/server/src/modules/pages/pages.controller.ts @@ -12,7 +12,6 @@ import { CreatePageDto, EnhancePageResponse, GetPageByTitleDto, - MoveTaskToPageDto, Page, PageRequestParamsDto, UpdatePageDto, @@ -56,12 +55,6 @@ export class PagesController { return await this.pagesService.createPage(pageData, workspaceId); } - @Post('move-task') - @UseGuards(AuthGuard) - async moveTaskToPage(@Body() moveTaskToPageData: MoveTaskToPageDto) { - return await this.pagesService.moveTaskToPage(moveTaskToPageData); - } - @Post(':pageId') @UseGuards(AuthGuard) async updateIssue( diff --git a/apps/server/src/modules/pages/pages.service.ts b/apps/server/src/modules/pages/pages.service.ts index a7ac480..ccef671 100644 --- a/apps/server/src/modules/pages/pages.service.ts +++ b/apps/server/src/modules/pages/pages.service.ts @@ -14,7 +14,6 @@ import { PageSelect, UpdatePageDto, enchancePrompt, - MoveTaskToPageDto, JsonObject, } from '@sigma/types'; import { parse } from 'date-fns'; @@ -257,15 +256,16 @@ export class PagesService { return tasks; } - async removeTaskFromPageByTitle(title: string, taskId: string) { + async removeTaskFromPageByTitle(title: string, taskIds: string[]) { const page = await this.prisma.page.findFirst({ where: { title, deleted: null }, }); let tasksExtensionContent = getTaskExtensionInPage(page); - tasksExtensionContent = removeTaskInExtension(tasksExtensionContent, [ - taskId, - ]); + tasksExtensionContent = removeTaskInExtension( + tasksExtensionContent, + taskIds, + ); const pageDescription = updateTaskExtensionInPage( page, @@ -373,6 +373,7 @@ export class PagesService { const removedTaskIds = currentTaskExtensionIds.filter( (taskId) => !taskExtensionTaskIds.has(taskId), ); + const addedTaskIds = Array.from(taskExtensionTaskIds).filter( (taskId) => !currentTaskExtensionIds.includes(taskId), ); @@ -381,6 +382,7 @@ export class PagesService { await this.prisma.taskOccurrence.updateMany({ where: { taskId: { in: removedTaskIds }, + pageId, }, data: { deleted: new Date().toISOString() }, }); @@ -416,48 +418,4 @@ export class PagesService { await this.storeOutlinks(payload.pageId); } } - - async moveTaskToPage(moveTaskToPageData: MoveTaskToPageDto) { - const fromPage = await this.prisma.page.findFirst({ - where: { title: moveTaskToPageData.fromDate }, - }); - const toPage = await this.prisma.page.findFirst({ - where: { title: moveTaskToPageData.toDate }, - }); - - if (fromPage) { - let fromTaskExtension = getTaskExtensionInPage(fromPage); - fromTaskExtension = removeTaskInExtension( - fromTaskExtension, - moveTaskToPageData.taskIds, - ); - - const pageDescription = updateTaskExtensionInPage( - fromPage, - fromTaskExtension, - ); - await this.contentService.updateContentForDocument( - fromPage.id, - JSON.parse(pageDescription), - ); - } - - if (toPage) { - let toTaskExtension = getTaskExtensionInPage(toPage); - const tasks = await this.prisma.task.findMany({ - where: { id: { in: moveTaskToPageData.taskIds } }, - include: { page: true }, - }); - toTaskExtension = upsertTaskInExtension(toTaskExtension, tasks); - const pageDescription = updateTaskExtensionInPage( - toPage, - toTaskExtension, - ); - await this.contentService.updateContentForDocument( - toPage.id, - JSON.parse(pageDescription), - ); - } - return { success: true }; - } } diff --git a/apps/server/src/modules/replication/replication.interface.ts b/apps/server/src/modules/replication/replication.interface.ts index 407bbc3..7d02f20 100644 --- a/apps/server/src/modules/replication/replication.interface.ts +++ b/apps/server/src/modules/replication/replication.interface.ts @@ -23,6 +23,7 @@ export const tablesToSendMessagesFor = new Map([ [ModelNameEnum.Conversation, true], [ModelNameEnum.ConversationHistory, true], [ModelNameEnum.List, true], + [ModelNameEnum.TaskOccurrence, true], ]); export const tableHooks = new Map([[ModelNameEnum.Page, true]]); diff --git a/apps/server/src/modules/task-occurence/task-occurence.controller.ts b/apps/server/src/modules/task-occurence/task-occurence.controller.ts index a419ed7..dbce6b1 100644 --- a/apps/server/src/modules/task-occurence/task-occurence.controller.ts +++ b/apps/server/src/modules/task-occurence/task-occurence.controller.ts @@ -7,8 +7,13 @@ import { Body, Get, Query, + Put, } from '@nestjs/common'; -import { GetTaskOccurenceDTO, UpdateTaskOccurenceDTO } from '@sigma/types'; +import { + CreateTaskOccurenceDTO, + GetTaskOccurenceDTO, + UpdateTaskOccurenceDTO, +} from '@sigma/types'; import { AuthGuard } from 'modules/auth/auth.guard'; import { Workspace } from 'modules/auth/session.decorator'; @@ -42,37 +47,55 @@ export class TaskOccurenceController { @Post() @UseGuards(AuthGuard) - async createTaskOccurence(@Body('taskId') taskId: string) { - return await this.taskOccurenceService.createTaskOccurance(taskId); - } - - @Post('task/:taskId') - @UseGuards(AuthGuard) - async updateTaskOccurenceByTask(@Param('taskId') taskId: string) { - return await this.taskOccurenceService.updateTaskOccuranceByTask(taskId); + async createTaskOccurence( + @Body() createTaskOccurencesData: CreateTaskOccurenceDTO, + @Workspace() workspaceId: string, + ) { + return await this.taskOccurenceService.createTaskOccurence( + createTaskOccurencesData, + workspaceId, + ); } - @Post(':taskOccurenceId') + @Put() @UseGuards(AuthGuard) async updateTaskOccurence( - @Param('taskOccurenceId') taskOccurenceId: string, @Body() updateTaskOccurenceDto: UpdateTaskOccurenceDTO, + @Workspace() workspaceId: string, ) { - return await this.taskOccurenceService.updateTaskOccurance( - taskOccurenceId, + return await this.taskOccurenceService.updateTaskOccurence( updateTaskOccurenceDto, + workspaceId, + true, ); } - @Delete('task/:taskId') + @Delete() @UseGuards(AuthGuard) - async deleteTaskOccurenceByTask(@Param('taskId') taskId: string) { - return await this.taskOccurenceService.deleteTaskOccuranceByTask(taskId); + async deleteTaskOccurence( + @Body('taskOccurenceIds') taskOccurenceIds: string[], + ) { + return await this.taskOccurenceService.deleteTaskOccurence( + taskOccurenceIds, + true, + ); } - @Delete(':taskOccurenceId') + @Post('task') + @UseGuards(AuthGuard) + async createTaskOccurenceByTask(@Body('taskId') taskId: string) { + return await this.taskOccurenceService.createTaskOccurenceByTask(taskId); + } + + @Post('task/:taskId') @UseGuards(AuthGuard) - async deleteTaskOccurence(@Param('taskOccurenceId') taskOccurenceId: string) { - return await this.taskOccurenceService.deleteTaskOccurence(taskOccurenceId); + async updateTaskOccurenceByTask(@Param('taskId') taskId: string) { + return await this.taskOccurenceService.updateTaskOccurenceByTask(taskId); + } + + @Delete('task/:taskId') + @UseGuards(AuthGuard) + async deleteTaskOccurenceByTask(@Param('taskId') taskId: string) { + return await this.taskOccurenceService.deleteTaskOccurenceByTask(taskId); } } diff --git a/apps/server/src/modules/task-occurence/task-occurence.service.ts b/apps/server/src/modules/task-occurence/task-occurence.service.ts index 52ac00b..75822ca 100644 --- a/apps/server/src/modules/task-occurence/task-occurence.service.ts +++ b/apps/server/src/modules/task-occurence/task-occurence.service.ts @@ -1,7 +1,9 @@ import { Injectable } from '@nestjs/common'; import { + CreateTaskOccurenceDTO, DateFilterEnum, GetTaskOccurenceDTO, + Page, PageTypeEnum, UpdateTaskOccurenceDTO, } from '@sigma/types'; @@ -10,7 +12,6 @@ import { PrismaService } from 'nestjs-prisma'; import { RRule } from 'rrule'; import { PagesService } from 'modules/pages/pages.service'; -import { TransactionClient } from 'modules/tasks/tasks.utils'; @Injectable() export class TaskOccurenceService { @@ -89,9 +90,119 @@ export class TaskOccurenceService { }); } - async createTaskOccurance(taskId: string, tx?: TransactionClient) { - const prismaClient = tx || this.prisma; - const task = await prismaClient.task.findUnique({ where: { id: taskId } }); + async createTaskOccurence( + createTaskOccurenceData: CreateTaskOccurenceDTO, + workspaceId: string, + modifyPage?: boolean, + ) { + const { taskIds, startTime, endTime } = createTaskOccurenceData; + let pageId = createTaskOccurenceData.pageId; + + let page: Page; + if (!pageId || modifyPage) { + const formattedDate = format(new Date(startTime), 'dd-MM-yyyy'); + page = await this.pagesService.getOrCreatePageByTitle(workspaceId, { + title: formattedDate, + type: PageTypeEnum.Daily, + taskIds, + }); + } + + if (!page || !pageId) { + return null; + } + + if (!pageId) { + pageId = page.id; + } + + // Create each task occurrence in parallel + return await Promise.all( + taskIds.map((taskId) => + this.prisma.taskOccurrence.upsert({ + where: { taskId_pageId: { taskId, pageId } }, + create: { + taskId, + startTime: startTime ? new Date(startTime) : null, + endTime: endTime ? new Date(endTime) : null, + pageId: pageId || page.id, + workspaceId, + }, + update: { + deleted: null, + }, + }), + ), + ); + } + + async updateTaskOccurence( + updateTaskOccurenceDto: UpdateTaskOccurenceDTO, + workspaceId: string, + modifyPage?: boolean, + ) { + const deletedTaskOccurences = await this.deleteTaskOccurence( + updateTaskOccurenceDto.taskOccurenceIds, + modifyPage, + ); + + // Extract taskIds from deleted occurrences and add them to updateTaskOccurenceDto + const deletedTaskIds = deletedTaskOccurences + .filter((occurrence) => occurrence.task?.id) + .map((occurrence) => occurrence.task.id); + + // Combine with existing taskIds, ensuring no duplicates + updateTaskOccurenceDto.taskIds = [ + ...new Set([...updateTaskOccurenceDto.taskIds, ...deletedTaskIds]), + ]; + + return await this.createTaskOccurence( + updateTaskOccurenceDto, + workspaceId, + modifyPage, + ); + } + + async deleteTaskOccurence(taskOccurenceIds: string[], modifyPage?: boolean) { + const taskOccurences = await this.prisma.taskOccurrence.findMany({ + where: { id: { in: taskOccurenceIds } }, + include: { page: true, task: true }, + }); + + // Mark all occurrences as deleted + await this.prisma.taskOccurrence.updateMany({ + where: { id: { in: taskOccurenceIds } }, + data: { deleted: new Date().toISOString() }, + }); + + // Remove tasks from their respective pages + const pageTaskMap = new Map(); + + // Group tasks by page title for efficient updates + taskOccurences.forEach((occurrence) => { + if (occurrence.pageId && occurrence.task?.id) { + const pageTitle = occurrence.page.title; + if (!pageTaskMap.has(pageTitle)) { + pageTaskMap.set(pageTitle, []); + } + pageTaskMap.get(pageTitle).push(occurrence.task.id); + } + }); + + if (modifyPage) { + // Remove tasks from each page + await Promise.all( + Array.from(pageTaskMap.entries()).map(async ([pageTitle, taskIds]) => { + await this.pagesService.removeTaskFromPageByTitle(pageTitle, taskIds); + }), + ); + } + + return taskOccurences; + } + + async createTaskOccurenceByTask(taskId: string) { + const task = await this.prisma.task.findUnique({ where: { id: taskId } }); if (!task.recurrence || task.recurrence.length === 0 || !task.startTime) { return null; } @@ -121,85 +232,108 @@ export class TaskOccurenceService { // Filter out any occurrences that have already passed const futureOccurrences = occurrences.filter((date) => date > now); + if (futureOccurrences.length === 0) { + return []; + } - const taskOccurences = await Promise.all( - futureOccurrences.map((date) => - prismaClient.taskOccurrence.upsert({ - where: { - taskId_startTime_endTime: { - taskId: task.id, - startTime: date, - endTime: task.endTime - ? new Date( - date.getTime() + - (task.endTime.getTime() - taskStartTime!.getTime()), - ) - : date, - }, - }, - create: { - taskId: task.id as string, - workspaceId: task.workspaceId, - startTime: date, - endTime: task.endTime - ? new Date( - date.getTime() + - (task.endTime.getTime() - taskStartTime!.getTime()), - ) - : date, - status: 'Todo', - }, - update: { - deleted: null, - }, - }), - ), - ); + // Step 1: Create a map of formatted dates to their occurrences + const dateOccurrenceMap = new Map(); + futureOccurrences.forEach((date) => { + const formattedDate = format(date, 'dd-MM-yyyy'); + if (!dateOccurrenceMap.has(formattedDate)) { + dateOccurrenceMap.set(formattedDate, []); + } + dateOccurrenceMap.get(formattedDate).push(date); + }); - if (!tx) { - await Promise.all( - futureOccurrences.map(async (date) => { - const formattedDate = format(date, 'dd-MM-yyyy'); - await this.pagesService.getOrCreatePageByTitle(task.workspaceId, { + // Step 2: Create or get all pages first + + const pageMap = new Map(); // Maps formatted date to {pageId, taskId} + + await Promise.all( + Array.from(dateOccurrenceMap.keys()).map(async (formattedDate) => { + const page = await this.pagesService.getOrCreatePageByTitle( + task.workspaceId, + { title: formattedDate, type: PageTypeEnum.Daily, taskIds: [taskId], - }); - }), - ); - } + }, + ); - return taskOccurences; - } + if (page && page.id) { + pageMap.set(formattedDate, page.id); + } + }), + ); - async updateTaskOccurance( - taskOccurenceId: string, - updateTaskOccurenceDto: UpdateTaskOccurenceDTO, - ) { - return await this.prisma.taskOccurrence.update({ - where: { id: taskOccurenceId }, - data: updateTaskOccurenceDto, - }); - } + // Step 3: Create task occurrences with the correct page IDs and task ID + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const taskOccurrenceData: any = []; - async updateTaskOccuranceByTask(taskId: string, tx?: TransactionClient) { - await this.deleteTaskOccuranceByTask(taskId, tx); + futureOccurrences.forEach((date) => { + const formattedDate = format(date, 'dd-MM-yyyy'); + const pageId = pageMap.get(formattedDate); - return await this.createTaskOccurance(taskId, tx); - } + if (pageId) { + const endTime = task.endTime + ? new Date( + date.getTime() + + (task.endTime.getTime() - taskStartTime!.getTime()), + ) + : date; - async deleteTaskOccurence(taskOccurenceId: string) { - return await this.prisma.taskOccurrence.update({ - where: { id: taskOccurenceId }, - data: { deleted: new Date().toISOString() }, + taskOccurrenceData.push({ + taskId, + pageId, + workspaceId: task.workspaceId, + startTime: date, + endTime, + status: 'Todo', + }); + } + }); + + // Step 4: Bulk upsert task occurrences + // Now we can use the enhanced map for more efficient operations + + // Create a list of unique taskId_pageId combinations for upsert + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const upsertOperations = taskOccurrenceData.map((data: any) => { + return this.prisma.taskOccurrence.upsert({ + where: { + taskId_pageId: { + taskId: data.taskId, + pageId: data.pageId, + }, + }, + create: { + taskId: data.taskId, + pageId: data.pageId, + workspaceId: data.workspaceId, + startTime: data.startTime, + endTime: data.endTime, + status: data.status, + }, + update: { + deleted: null, + }, + }); }); + + // Execute all upsert operations in parallel + return await Promise.all(upsertOperations); } - async deleteTaskOccuranceByTask(taskId: string, tx?: TransactionClient) { - const prismaClient = tx || this.prisma; + async updateTaskOccurenceByTask(taskId: string) { + await this.deleteTaskOccurenceByTask(taskId); + + return await this.createTaskOccurenceByTask(taskId); + } + async deleteTaskOccurenceByTask(taskId: string) { // First get all future occurrences to know which pages to update - const futureOccurrences = await prismaClient.taskOccurrence.findMany({ + const futureOccurrences = await this.prisma.taskOccurrence.findMany({ where: { taskId, startTime: { @@ -213,7 +347,7 @@ export class TaskOccurenceService { }); // Mark occurrences as deleted - await prismaClient.taskOccurrence.updateMany({ + await this.prisma.taskOccurrence.updateMany({ where: { taskId, startTime: { @@ -224,16 +358,13 @@ export class TaskOccurenceService { }); // Remove task from each daily page - if (!tx) { - await Promise.all( - futureOccurrences.map(async (occurrence) => { - const formattedDate = format(occurrence.startTime, 'dd-MM-yyyy'); - await this.pagesService.removeTaskFromPageByTitle( - formattedDate, - taskId, - ); - }), - ); - } + await Promise.all( + futureOccurrences.map(async (occurrence) => { + const formattedDate = format(occurrence.startTime, 'dd-MM-yyyy'); + await this.pagesService.removeTaskFromPageByTitle(formattedDate, [ + taskId, + ]); + }), + ); } } diff --git a/apps/server/src/modules/tasks-hook/tasks-hook.service.ts b/apps/server/src/modules/tasks-hook/tasks-hook.service.ts index f46e4a8..d3139df 100644 --- a/apps/server/src/modules/tasks-hook/tasks-hook.service.ts +++ b/apps/server/src/modules/tasks-hook/tasks-hook.service.ts @@ -36,7 +36,7 @@ export class TaskHooksService { await Promise.all([ this.handleTitleChange(task, context), this.handleDeleteTask(task, context), - this.handleScheduleTask(task, context, tx), + this.handleScheduleTask(task, context), // this.handleCalendarTask(task, context), // this.handleBeautifyTask(task, context), // this.handleGenerateSummary(task, context), @@ -63,10 +63,9 @@ export class TaskHooksService { if (referencingPages.length > 0) { await Promise.all( referencingPages.map(async (page) => { - await this.pagesService.removeTaskFromPageByTitle( - page.title, + await this.pagesService.removeTaskFromPageByTitle(page.title, [ task.id, - ); + ]); }), ); } @@ -130,15 +129,11 @@ export class TaskHooksService { } } - async handleScheduleTask( - task: Task, - context: TaskHookContext, - tx: TransactionClient, - ) { + async handleScheduleTask(task: Task, context: TaskHookContext) { switch (context.action) { case 'create': if (task.recurrence) { - await this.taskOccurenceService.createTaskOccurance(task.id, tx); + await this.taskOccurenceService.createTaskOccurenceByTask(task.id); } return { message: 'Handled schedule create' }; @@ -149,19 +144,13 @@ export class TaskHooksService { task.startTime !== context.previousTask?.startTime || task.endTime !== context.previousTask?.endTime ) { - await this.taskOccurenceService.updateTaskOccuranceByTask( - task.id, - tx, - ); + await this.taskOccurenceService.updateTaskOccurenceByTask(task.id); } return { message: 'Handled schedule update' }; case 'delete': if (task.recurrence || task.startTime || task.endTime) { - await this.taskOccurenceService.deleteTaskOccuranceByTask( - task.id, - tx, - ); + await this.taskOccurenceService.deleteTaskOccurenceByTask(task.id); } return { message: 'Handled schedule delete' }; } diff --git a/apps/server/src/modules/tasks/tasks.service.ts b/apps/server/src/modules/tasks/tasks.service.ts index 76bd6db..8db7676 100644 --- a/apps/server/src/modules/tasks/tasks.service.ts +++ b/apps/server/src/modules/tasks/tasks.service.ts @@ -354,7 +354,7 @@ export class TasksService { await Promise.all([ // Delete task occurrences if it's recurring task.recurrence && - this.taskOccurenceService.deleteTaskOccuranceByTask(task.id), + this.taskOccurenceService.deleteTaskOccurenceByTask(task.id), // Update calendar if task has dates (task.startTime || task.endTime) && @@ -403,7 +403,7 @@ export class TasksService { await Promise.all([ // Delete task occurrences if it's recurring task.recurrence && - this.taskOccurenceService.deleteTaskOccuranceByTask(task.id), + this.taskOccurenceService.deleteTaskOccurenceByTask(task.id), // Update calendar if task has dates (task.startTime || task.endTime) && diff --git a/apps/server/src/triggers/page/task-occurence.ts b/apps/server/src/triggers/page/task-occurence.ts index ba6e46a..b8430f8 100644 --- a/apps/server/src/triggers/page/task-occurence.ts +++ b/apps/server/src/triggers/page/task-occurence.ts @@ -47,39 +47,40 @@ export const processTaskOccurrences = task({ return null; } - const createdOccurrences = await Promise.all( - futureOccurrences.map((date) => - prisma.taskOccurrence.upsert({ - where: { - taskId_startTime_endTime: { - taskId: sigmaTask.id, - startTime: date, - endTime: sigmaTask.endTime - ? new Date( - date.getTime() + - (sigmaTask.endTime.getTime() - - sigmaTask.startTime!.getTime()), - ) - : date, - }, - }, - create: { - taskId: sigmaTask.id, - workspaceId: sigmaTask.workspaceId, - startTime: date, - endTime: sigmaTask.endTime - ? new Date( - date.getTime() + - (sigmaTask.endTime.getTime() - - sigmaTask.startTime!.getTime()), - ) - : date, - status: 'Todo', - }, - update: {}, - }), - ), - ); + const createdOccurrences = []; + // const createdOccurrences = await Promise.all( + // futureOccurrences.map((date) => + // prisma.taskOccurrence.upsert({ + // where: { + // taskId_startTime_endTime: { + // taskId: sigmaTask.id, + // startTime: date, + // endTime: sigmaTask.endTime + // ? new Date( + // date.getTime() + + // (sigmaTask.endTime.getTime() - + // sigmaTask.startTime!.getTime()), + // ) + // : date, + // }, + // }, + // create: { + // taskId: sigmaTask.id, + // workspaceId: sigmaTask.workspaceId, + // startTime: date, + // endTime: sigmaTask.endTime + // ? new Date( + // date.getTime() + + // (sigmaTask.endTime.getTime() - + // sigmaTask.startTime!.getTime()), + // ) + // : date, + // status: 'Todo', + // }, + // update: {}, + // }), + // ), + // ); return { taskId: sigmaTask.id, diff --git a/packages/types/src/sync-action/sync-action.entity.ts b/packages/types/src/sync-action/sync-action.entity.ts index b646fe6..88adbeb 100644 --- a/packages/types/src/sync-action/sync-action.entity.ts +++ b/packages/types/src/sync-action/sync-action.entity.ts @@ -11,6 +11,7 @@ export enum ModelNameEnum { Conversation = 'Conversation', ConversationHistory = 'ConversationHistory', List = 'List', + TaskOccurrence = 'TaskOccurrence', } export const ModelName = { @@ -25,6 +26,7 @@ export const ModelName = { Conversation: 'Conversation', ConversationHistory: 'ConversationHistory', List: 'List', + TaskOccurrence: 'TaskOccurrence', }; export type ModelName = (typeof ModelName)[keyof typeof ModelName]; diff --git a/packages/types/src/task-occurence/create-task-occurence.dto.ts b/packages/types/src/task-occurence/create-task-occurence.dto.ts new file mode 100644 index 0000000..eb63d77 --- /dev/null +++ b/packages/types/src/task-occurence/create-task-occurence.dto.ts @@ -0,0 +1,18 @@ +import { IsArray, IsDateString, IsOptional, IsString } from 'class-validator'; + +export class CreateTaskOccurenceDTO { + @IsArray() + taskIds: string[]; + + @IsOptional() + @IsDateString() + startTime?: string; + + @IsOptional() + @IsDateString() + endTime?: string; + + @IsString() + @IsOptional() + pageId?: string; +} diff --git a/packages/types/src/task-occurence/index.ts b/packages/types/src/task-occurence/index.ts index 5958326..ef59d62 100644 --- a/packages/types/src/task-occurence/index.ts +++ b/packages/types/src/task-occurence/index.ts @@ -2,3 +2,4 @@ export * from './task-occurence.entity'; export * from './update-task-occurence.dto'; export * from './get-task-occurence.dto'; export * from './task-occurence.dto'; +export * from './create-task-occurence.dto'; diff --git a/packages/types/src/task-occurence/update-task-occurence.dto.ts b/packages/types/src/task-occurence/update-task-occurence.dto.ts index a1098c1..f0670b3 100644 --- a/packages/types/src/task-occurence/update-task-occurence.dto.ts +++ b/packages/types/src/task-occurence/update-task-occurence.dto.ts @@ -1,4 +1,4 @@ -import { IsString, IsOptional, IsEnum } from 'class-validator'; +import { IsString, IsOptional, IsEnum, IsArray } from 'class-validator'; import { TaskOccurrenceStatusEnum, @@ -6,15 +6,19 @@ import { } from './task-occurence.entity'; export class UpdateTaskOccurenceDTO { - @IsString() - @IsOptional() - startTime?: string; + @IsArray() + taskIds: string[]; + + @IsArray() + taskOccurenceIds: string[]; @IsString() - @IsOptional() - endTime?: string; + startTime: string; @IsString() + endTime: string; + + @IsOptional() @IsEnum(TaskOccurrenceStatusEnum) status?: TaskOccurrenceStatusType; }