Refactor event form to use separate date/time inputs with validation
All checks were successful
Build And Push Image / docker (push) Successful in 1m26s

- Split combined datetime pickers into separate date and time fields
- Add validation for past dates and time consistency
- Implement error message display with dismissible alerts
- Add watchers to combine date/time values into ISO strings
- Set minimum date constraints to prevent past date selection
- Add delete endpoint for events
This commit is contained in:
2025-08-13 22:23:06 +02:00
parent 9ee0b2f14e
commit 44aee8f2f9
4 changed files with 371 additions and 29 deletions

View File

@@ -0,0 +1,135 @@
// server/api/events/[id].delete.ts
import { createNocoDBEventsClient } from '~/server/utils/nocodb-events';
import { createSessionManager } from '~/server/utils/session';
export default defineEventHandler(async (event) => {
console.log('[api/events/[id].delete] =========================');
console.log('[api/events/[id].delete] DELETE /api/events/[id] - Delete event');
console.log('[api/events/[id].delete] Request from:', getClientIP(event));
try {
const eventId = getRouterParam(event, 'id');
if (!eventId) {
throw createError({
statusCode: 400,
statusMessage: 'Event ID is required'
});
}
console.log('[api/events/[id].delete] Deleting event:', eventId);
// Get user session using the working session manager
const sessionManager = createSessionManager();
const cookieHeader = getHeader(event, 'cookie');
const session = sessionManager.getSession(cookieHeader);
if (!session || !session.user) {
throw createError({
statusCode: 401,
statusMessage: 'Authentication required'
});
}
// Check if user has permission to delete events (board or admin only)
const userTier = session.user.tier;
if (userTier !== 'board' && userTier !== 'admin') {
throw createError({
statusCode: 403,
statusMessage: 'Only board members and admins can delete events'
});
}
console.log('[api/events/[id].delete] ✅ User authorized to delete events:', session.user.email, 'tier:', userTier);
const eventsClient = createNocoDBEventsClient();
// First, get the event to verify it exists and get the event_id for RSVP cleanup
let eventToDelete;
try {
eventToDelete = await eventsClient.findOne(eventId);
console.log('[api/events/[id].delete] Found event to delete:', eventToDelete.title, 'event_id:', eventToDelete.event_id);
} catch (error: any) {
if (error.statusCode === 404) {
throw createError({
statusCode: 404,
statusMessage: 'Event not found'
});
}
throw error;
}
// Get all RSVPs for this event to clean them up
const eventIdentifier = eventToDelete.event_id || eventToDelete.id || (eventToDelete as any).Id;
console.log('[api/events/[id].delete] Getting RSVPs for event identifier:', eventIdentifier);
const eventRSVPs = await eventsClient.getEventRSVPs(eventIdentifier.toString());
console.log('[api/events/[id].delete] Found', eventRSVPs.length, 'RSVPs to delete');
// Delete all RSVPs first
let deletedRSVPs = 0;
for (const rsvp of eventRSVPs) {
try {
// Delete RSVP using its database Id
const rsvpId = rsvp.Id || rsvp.id;
if (rsvpId) {
console.log('[api/events/[id].delete] Deleting RSVP:', rsvpId);
await $fetch(eventsClient.constructor.prototype.createEventTableUrl('EventRSVPs'), {
method: 'DELETE',
headers: {
'xc-token': eventsClient.constructor.prototype.getNocoDbConfiguration().token,
},
body: {
Id: parseInt(rsvpId.toString())
}
});
deletedRSVPs++;
}
} catch (rsvpError: any) {
console.log('[api/events/[id].delete] ⚠️ Error deleting RSVP:', rsvp.Id || rsvp.id, rsvpError);
// Continue with other RSVPs even if one fails
}
}
console.log('[api/events/[id].delete] Deleted', deletedRSVPs, 'RSVPs');
// Now delete the event itself using its database Id
const eventDatabaseId = (eventToDelete as any).Id || eventToDelete.id;
if (!eventDatabaseId) {
throw createError({
statusCode: 500,
statusMessage: 'Could not determine event database ID for deletion'
});
}
console.log('[api/events/[id].delete] Deleting event with database ID:', eventDatabaseId);
await eventsClient.delete(eventDatabaseId.toString());
console.log('[api/events/[id].delete] ✅ Successfully deleted event and all associated RSVPs');
return {
success: true,
message: `Event "${eventToDelete.title}" and ${deletedRSVPs} associated RSVPs deleted successfully`,
deleted: {
event: {
id: eventDatabaseId,
event_id: eventToDelete.event_id,
title: eventToDelete.title
},
rsvps_deleted: deletedRSVPs
}
};
} catch (error: any) {
console.error('[api/events/[id].delete] ❌ Error deleting event:', error);
if (error.statusCode) {
throw error;
}
throw createError({
statusCode: 500,
statusMessage: 'Failed to delete event'
});
}
});

View File

@@ -274,22 +274,52 @@ export function createNocoDBEventsClient() {
},
/**
* Find a single event by ID
* Find a single event by ID (supports both database Id and business event_id)
*/
async findOne(id: string) {
console.log('[nocodb-events] Fetching event ID:', id);
try {
const result = await $fetch<Event>(`${createEventTableUrl(EventTable.Events)}/${id}`, {
// First, try to fetch by database Id (numeric)
if (/^\d+$/.test(id)) {
console.log('[nocodb-events] Using database Id lookup for:', id);
const result = await $fetch<Event>(`${createEventTableUrl(EventTable.Events)}/${id}`, {
headers: {
"xc-token": getNocoDbConfiguration().token,
},
});
console.log('[nocodb-events] Successfully retrieved event by database Id:', result.id || (result as any).Id);
return normalizeEventFieldsFromNocoDB(result);
}
// Otherwise, search by business event_id
console.log('[nocodb-events] Using event_id lookup for:', id);
const results = await $fetch<{list: Event[]}>(`${createEventTableUrl(EventTable.Events)}`, {
headers: {
"xc-token": getNocoDbConfiguration().token,
},
params: {
where: `(event_id,eq,${id})`,
limit: 1
}
});
console.log('[nocodb-events] Successfully retrieved event:', result.id || (result as any).Id);
return normalizeEventFieldsFromNocoDB(result);
if (results.list && results.list.length > 0) {
console.log('[nocodb-events] Successfully found event by event_id:', results.list[0].id || (results.list[0] as any).Id);
return normalizeEventFieldsFromNocoDB(results.list[0]);
}
console.log('[nocodb-events] No event found with event_id:', id);
throw createError({
statusCode: 404,
statusMessage: 'Event not found'
});
} catch (error: any) {
console.error('[nocodb-events] Error fetching event:', error);
if (error.statusCode === 404) {
throw error; // Re-throw 404 errors as-is
}
handleNocoDbError(error, 'getEventById', 'Event');
throw error;
}