Fix duplicate calendar edits and prevent double-save submissions

This commit is contained in:
Linus Rath
2026-03-19 14:40:16 +01:00
parent 77514bd054
commit 41f91244d9
2 changed files with 12 additions and 23 deletions
+12 -6
View File
@@ -25,7 +25,7 @@ interface EventModalProps {
calendars: Calendar[];
defaultDate?: Date;
defaultEndDate?: Date;
onSave: (data: Partial<CalendarEvent>, sendSchedulingMessages?: boolean) => void;
onSave: (data: Partial<CalendarEvent>, sendSchedulingMessages?: boolean) => void | Promise<void>;
onDelete?: (id: string, sendSchedulingMessages?: boolean) => void;
onDuplicate?: (data: Partial<CalendarEvent>) => void;
onRsvp?: (eventId: string, participantId: string, status: CalendarParticipant['participationStatus']) => void;
@@ -209,6 +209,7 @@ export function EventModal({
return "none";
});
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
const [isSaving, setIsSaving] = useState(false);
const [attendees, setAttendees] = useState<{ name: string; email: string }[]>(() => {
if (!event?.participants) return [];
@@ -231,9 +232,9 @@ export function EventModal({
setAttendees(prev => prev.filter(a => a.email.toLowerCase() !== email.toLowerCase()));
}, []);
const handleSave = useCallback(() => {
const handleSave = useCallback(async () => {
const trimmedTitle = title.trim();
if (!trimmedTitle) return;
if (!trimmedTitle || isSaving) return;
if (trimmedTitle.length > 500 || description.trim().length > 10000 || location.trim().length > 500) return;
const startStr = allDay
@@ -343,8 +344,13 @@ export function EventModal({
}
const shouldSendScheduling = attendees.length > 0 && sendInvitations;
onSave(data, shouldSendScheduling);
}, [title, description, location, startDate, startTime, endDate, endTime, allDay, calendarId, recurrence, alert, attendees, sendInvitations, currentUserEmails, existingParticipants, event, onSave]);
setIsSaving(true);
try {
await onSave(data, shouldSendScheduling);
} finally {
setIsSaving(false);
}
}, [title, description, location, startDate, startTime, endDate, endTime, allDay, calendarId, recurrence, alert, attendees, sendInvitations, currentUserEmails, existingParticipants, event, onSave, isSaving]);
const handleRsvp = useCallback((status: CalendarParticipant['participationStatus']) => {
if (!event || !userParticipantId || !onRsvp) return;
@@ -945,7 +951,7 @@ export function EventModal({
<Button variant="outline" onClick={isEdit ? () => setMode("view") : onClose}>
{t("form.cancel")}
</Button>
<Button onClick={handleSave} disabled={!title.trim()}>
<Button onClick={handleSave} disabled={!title.trim() || isSaving}>
{t("form.save")}
</Button>
</div>
-17
View File
@@ -142,13 +142,6 @@ export const useCalendarStore = create<CalendarStore>()(
}
const created = await client.createCalendarEvent(cleanEvent, sendSchedulingMessages, targetAccountId);
set((state) => ({ events: [...state.events, created] }));
if (sendSchedulingMessages && created.participants) {
try {
await client.sendImipInvitation(created);
} catch (e) {
debug.error('Failed to send invitation emails:', e);
}
}
return created;
} catch (error) {
debug.error('Failed to create event:', error);
@@ -178,16 +171,6 @@ export const useCalendarStore = create<CalendarStore>()(
set((state) => ({
events: state.events.map(e => e.id === id ? { ...e, ...updates } : e),
}));
if (sendSchedulingMessages) {
try {
const updatedEvent = await client.getCalendarEvent(realId, targetAccountId);
if (updatedEvent?.participants) {
await client.sendImipInvitation(updatedEvent);
}
} catch (e) {
debug.error('Failed to send update notification emails:', e);
}
}
} catch (error) {
debug.error('Failed to update event:', error);
set({ error: 'Failed to update event' });