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:
@@ -1,14 +1,34 @@
|
||||
import { View, Text, Pressable } from "react-native";
|
||||
import { ProposedEventChange } from "@calchat/shared";
|
||||
import { ProposedEventChange, RecurringDeleteMode } from "@calchat/shared";
|
||||
import { useThemeStore } from "../stores/ThemeStore";
|
||||
import { EventCardBase } from "./EventCardBase";
|
||||
|
||||
const DELETE_MODE_LABELS: Record<RecurringDeleteMode, string> = {
|
||||
single: "Nur dieses Vorkommen",
|
||||
future: "Dieses & zukuenftige",
|
||||
all: "Alle Vorkommen",
|
||||
};
|
||||
|
||||
type ProposedEventCardProps = {
|
||||
proposedChange: ProposedEventChange;
|
||||
onConfirm: () => void;
|
||||
onReject: () => void;
|
||||
};
|
||||
|
||||
const DeleteModeBadge = ({ mode }: { mode: RecurringDeleteMode }) => {
|
||||
const { theme } = useThemeStore();
|
||||
return (
|
||||
<View
|
||||
className="self-start px-2 py-1 rounded-md mb-2"
|
||||
style={{ backgroundColor: theme.rejectButton }}
|
||||
>
|
||||
<Text style={{ color: theme.buttonText }} className="text-xs font-medium">
|
||||
{DELETE_MODE_LABELS[mode]}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const ConfirmRejectButtons = ({
|
||||
isDisabled,
|
||||
respondedAction,
|
||||
@@ -68,6 +88,12 @@ export const ProposedEventCard = ({
|
||||
// respondedAction is now part of the proposedChange
|
||||
const isDisabled = !!proposedChange.respondedAction;
|
||||
|
||||
// Show delete mode badge for delete actions on recurring events
|
||||
const showDeleteModeBadge =
|
||||
proposedChange.action === "delete" &&
|
||||
event?.isRecurring &&
|
||||
proposedChange.deleteMode;
|
||||
|
||||
if (!event) {
|
||||
return null;
|
||||
}
|
||||
@@ -82,6 +108,9 @@ export const ProposedEventCard = ({
|
||||
description={event.description}
|
||||
isRecurring={event.isRecurring}
|
||||
>
|
||||
{showDeleteModeBadge && (
|
||||
<DeleteModeBadge mode={proposedChange.deleteMode!} />
|
||||
)}
|
||||
<ConfirmRejectButtons
|
||||
isDisabled={isDisabled}
|
||||
respondedAction={proposedChange.respondedAction}
|
||||
|
||||
Reference in New Issue
Block a user