diff --git a/server/utils/nocodb-events.ts b/server/utils/nocodb-events.ts index b81b468..8b71bfa 100644 --- a/server/utils/nocodb-events.ts +++ b/server/utils/nocodb-events.ts @@ -62,48 +62,63 @@ export function createNocoDBEventsClient() { if (filters?.limit) queryParams.set('limit', filters.limit.toString()); if (filters?.offset) queryParams.set('offset', filters.offset.toString()); + // Build where clause for filtering using correct field names from NocoDB + const whereConditions: string[] = []; + + if (filters?.start_date && filters?.end_date) { + // Date range filtering using gte and lte (btw didn't work) + whereConditions.push(`(start_datetime,gte,${filters.start_date})`); + whereConditions.push(`(start_datetime,lte,${filters.end_date})`); + } + + if (filters?.event_type) { + whereConditions.push(`(event_type,eq,${filters.event_type})`); + } + + if (filters?.visibility) { + whereConditions.push(`(visibility,eq,${filters.visibility})`); + } else if (filters?.user_role) { + // Role-based visibility filtering + if (filters.user_role === 'user') { + whereConditions.push(`(visibility,eq,public)`); + } else if (filters.user_role === 'board') { + // Board members can see public and board-only events + whereConditions.push(`~or((visibility,eq,public),(visibility,eq,board-only))`); + } + // Admin sees all events (no filter) + } + + if (filters?.status) { + whereConditions.push(`(status,eq,${filters.status})`); + } else { + // Default to active events only + whereConditions.push(`(status,eq,active)`); + } + + if (filters?.search) { + // Search in title or description + whereConditions.push(`~or((title,like,%${filters.search}%),(description,like,%${filters.search}%))`); + } + + // Combine conditions with ~and if multiple conditions exist + if (whereConditions.length > 0) { + const whereClause = whereConditions.length === 1 + ? whereConditions[0] + : `~and(${whereConditions.join(',')})`; + queryParams.set('where', whereClause); + } + + // Sort by start date + queryParams.set('sort', 'start_datetime'); + const url = `${baseUrl}/api/v2/tables/${eventsTableId}/records?${queryParams.toString()}`; - console.log('[nocodb-events] 🔍 DEBUG: Attempting to fetch events...'); - console.log('[nocodb-events] 📋 Table ID:', eventsTableId); - console.log('[nocodb-events] 🌐 Full URL:', url); - console.log('[nocodb-events] 🔑 Token (first 10 chars):', token?.substring(0, 10) + '...'); + const response = await $fetch(url, { + method: 'GET', + headers + }); - try { - const response = await $fetch(url, { - method: 'GET', - headers - }); - - console.log('[nocodb-events] ✅ SUCCESS! Got response'); - console.log('[nocodb-events] 📊 Response type:', typeof response); - console.log('[nocodb-events] 📝 Response keys:', Object.keys(response || {})); - - if (response && typeof response === 'object') { - const responseObj = response as any; - if (responseObj.list && Array.isArray(responseObj.list)) { - console.log('[nocodb-events] 📈 Records found:', responseObj.list.length); - if (responseObj.list.length > 0) { - console.log('[nocodb-events] 🔍 First record keys (FIELD NAMES):', Object.keys(responseObj.list[0])); - console.log('[nocodb-events] 📄 Sample record:', JSON.stringify(responseObj.list[0], null, 2)); - } - } - } - - return response; - } catch (error: any) { - console.error('[nocodb-events] ❌ FAILED with error:', error); - console.error('[nocodb-events] 🔍 Error details:', { - message: error?.message, - status: error?.status, - statusCode: error?.statusCode, - statusMessage: error?.statusMessage, - data: error?.data - }); - - // Re-throw the error so the calling code can handle it - throw error; - } + return response; }, /** @@ -272,7 +287,15 @@ export function createNocoDBEventsClient() { } // Get user's RSVPs for these events - const eventIds = events.list.map((e: Event) => e.id); + // Fix: Use 'Id' (capital I) as that's the actual field name from NocoDB + const eventIds = events.list.map((e: any) => e.Id); + + // Skip RSVP lookup if no valid event IDs + if (!eventIds.length || eventIds.some(id => !id)) { + console.log('[nocodb-events] ⚠️ No valid event IDs found, skipping RSVP lookup'); + return { list: events.list, PageInfo: events.PageInfo }; + } + const rsvpQueryParams = new URLSearchParams(); const eventIdConditions = eventIds.map(id => `(event_id,eq,${id})`).join(','); rsvpQueryParams.set('where', `~and((member_id,eq,${memberId}),~or(${eventIdConditions}))`); @@ -293,9 +316,10 @@ export function createNocoDBEventsClient() { } // Add RSVP information to events - const eventsWithRSVP = events.list.map((event: Event) => ({ + // Fix: Use 'Id' (capital I) as that's the actual field name from NocoDB + const eventsWithRSVP = events.list.map((event: any) => ({ ...event, - user_rsvp: rsvpMap.get(event.id) || null + user_rsvp: rsvpMap.get(event.Id) || null })); return { @@ -333,8 +357,9 @@ export function createNocoDBEventsClient() { /** * Utility function to transform Event data for FullCalendar + * Updated to use correct field names from NocoDB (Id instead of id) */ -export function transformEventForCalendar(event: Event): any { +export function transformEventForCalendar(event: any): any { const eventTypeColors = { 'meeting': { bg: '#2196f3', border: '#1976d2' }, 'social': { bg: '#4caf50', border: '#388e3c' }, @@ -347,8 +372,8 @@ export function transformEventForCalendar(event: Event): any { { bg: '#757575', border: '#424242' }; return { - id: event.id, - title: event.title, + id: event.Id, // Fix: Use 'Id' (capital I) from NocoDB + title: event.title || 'Untitled Event', start: event.start_datetime, end: event.end_datetime, backgroundColor: colors.bg,