feat: add recurring event deletion with three modes
Implement three deletion modes for recurring events: - single: exclude specific occurrence via EXDATE mechanism - future: set RRULE UNTIL to stop future occurrences - all: delete entire event series Changes include: - Add exceptionDates field to CalendarEvent model - Add RecurringDeleteMode type and DeleteRecurringEventDTO - EventService.deleteRecurring() with mode-based logic using rrule library - EventController DELETE endpoint accepts mode/occurrenceDate query params - recurrenceExpander filters out exception dates during expansion - AI tools support deleteMode and occurrenceDate for proposed deletions - ChatService.confirmEvent() handles recurring delete modes - New DeleteEventModal component for unified delete confirmation UI - Calendar screen integrates modal for both recurring and non-recurring events
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
||||
UpdateEventDTO,
|
||||
EventAction,
|
||||
GetMessagesOptions,
|
||||
RecurringDeleteMode,
|
||||
} from "@calchat/shared";
|
||||
import { ChatService } from "../services";
|
||||
import { createLogger } from "../logging";
|
||||
@@ -22,7 +23,10 @@ export class ChatController {
|
||||
const response = await this.chatService.processMessage(userId, data);
|
||||
res.json(response);
|
||||
} catch (error) {
|
||||
log.error({ error, userId: req.user?.userId }, "Error processing message");
|
||||
log.error(
|
||||
{ error, userId: req.user?.userId },
|
||||
"Error processing message",
|
||||
);
|
||||
res.status(500).json({ error: "Failed to process message" });
|
||||
}
|
||||
}
|
||||
@@ -31,12 +35,22 @@ export class ChatController {
|
||||
try {
|
||||
const userId = req.user!.userId;
|
||||
const { conversationId, messageId } = req.params;
|
||||
const { proposalId, action, event, eventId, updates } = req.body as {
|
||||
const {
|
||||
proposalId,
|
||||
action,
|
||||
event,
|
||||
eventId,
|
||||
updates,
|
||||
deleteMode,
|
||||
occurrenceDate,
|
||||
} = req.body as {
|
||||
proposalId: string;
|
||||
action: EventAction;
|
||||
event?: CreateEventDTO;
|
||||
eventId?: string;
|
||||
updates?: UpdateEventDTO;
|
||||
deleteMode?: RecurringDeleteMode;
|
||||
occurrenceDate?: string;
|
||||
};
|
||||
const response = await this.chatService.confirmEvent(
|
||||
userId,
|
||||
@@ -47,10 +61,15 @@ export class ChatController {
|
||||
event,
|
||||
eventId,
|
||||
updates,
|
||||
deleteMode,
|
||||
occurrenceDate,
|
||||
);
|
||||
res.json(response);
|
||||
} catch (error) {
|
||||
log.error({ error, conversationId: req.params.conversationId }, "Error confirming event");
|
||||
log.error(
|
||||
{ error, conversationId: req.params.conversationId },
|
||||
"Error confirming event",
|
||||
);
|
||||
res.status(500).json({ error: "Failed to confirm event" });
|
||||
}
|
||||
}
|
||||
@@ -68,7 +87,10 @@ export class ChatController {
|
||||
);
|
||||
res.json(response);
|
||||
} catch (error) {
|
||||
log.error({ error, conversationId: req.params.conversationId }, "Error rejecting event");
|
||||
log.error(
|
||||
{ error, conversationId: req.params.conversationId },
|
||||
"Error rejecting event",
|
||||
);
|
||||
res.status(500).json({ error: "Failed to reject event" });
|
||||
}
|
||||
}
|
||||
@@ -82,7 +104,10 @@ export class ChatController {
|
||||
const conversations = await this.chatService.getConversations(userId);
|
||||
res.json(conversations);
|
||||
} catch (error) {
|
||||
log.error({ error, userId: req.user?.userId }, "Error getting conversations");
|
||||
log.error(
|
||||
{ error, userId: req.user?.userId },
|
||||
"Error getting conversations",
|
||||
);
|
||||
res.status(500).json({ error: "Failed to get conversations" });
|
||||
}
|
||||
}
|
||||
@@ -113,7 +138,10 @@ export class ChatController {
|
||||
if ((error as Error).message === "Conversation not found") {
|
||||
res.status(404).json({ error: "Conversation not found" });
|
||||
} else {
|
||||
log.error({ error, conversationId: req.params.id }, "Error getting conversation");
|
||||
log.error(
|
||||
{ error, conversationId: req.params.id },
|
||||
"Error getting conversation",
|
||||
);
|
||||
res.status(500).json({ error: "Failed to get conversation" });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user