import { getMembers, handleNocoDbError, normalizeFieldsFromNocoDB } from '~/server/utils/nocodb'; import type { Member } from '~/utils/types'; export default defineEventHandler(async (event) => { console.log('[api/members.get] ========================='); console.log('[api/members.get] GET /api/members - List all members'); console.log('[api/members.get] Request from:', getClientIP(event)); try { // Get query parameters const query = getQuery(event); const limit = parseInt(query.limit as string) || 1000; const searchTerm = query.search as string; const nationality = query.nationality as string; const membershipStatus = query.status as string; const duesPaid = query.duesPaid as string; console.log('[api/members.get] Query parameters:', { limit, searchTerm, nationality, membershipStatus, duesPaid }); // Fetch members from NocoDB const result = await getMembers(); let members = result.list || []; console.log('[api/members.get] Fetched members count:', members.length); // DIAGNOSTIC: Log processing pipeline if (members.length > 0) { const sampleMember = members[0]; console.log('[api/members.get] DIAGNOSTIC - Raw member from getMembers:', JSON.stringify(sampleMember, null, 2)); console.log('[api/members.get] DIAGNOSTIC - Member field check:'); console.log(' - sampleMember.first_name:', sampleMember.first_name); console.log(' - sampleMember.last_name:', sampleMember.last_name); console.log(' - sampleMember["First Name"]:', (sampleMember as any)['First Name']); console.log(' - sampleMember["Last Name"]:', (sampleMember as any)['Last Name']); console.log(' - typeof sampleMember.first_name:', typeof sampleMember.first_name); console.log(' - typeof sampleMember.last_name:', typeof sampleMember.last_name); } // Apply field normalization to handle schema mismatches members = members.map(member => { const normalized = normalizeFieldsFromNocoDB(member); return normalized; }); console.log('[api/members.get] Applied field normalization to', members.length, 'members'); // Apply client-side filtering since NocoDB filtering can be complex if (searchTerm) { const search = searchTerm.toLowerCase(); members = members.filter(member => member.first_name?.toLowerCase().includes(search) || member.last_name?.toLowerCase().includes(search) || member.email?.toLowerCase().includes(search) ); console.log('[api/members.get] After search filter:', members.length); } if (nationality) { members = members.filter(member => member.nationality === nationality); console.log('[api/members.get] After nationality filter:', members.length); } if (membershipStatus) { members = members.filter(member => member.membership_status === membershipStatus); console.log('[api/members.get] After status filter:', members.length); } if (duesPaid === 'true' || duesPaid === 'false') { members = members.filter(member => member.current_year_dues_paid === duesPaid); console.log('[api/members.get] After dues filter:', members.length); } // Add computed fields const processedMembers = members.map(member => { const fullName = `${member.first_name || ''} ${member.last_name || ''}`.trim(); return { ...member, FullName: fullName, FormattedPhone: formatPhoneNumber(member.phone) }; }); // DIAGNOSTIC: Log processed member data if (processedMembers.length > 0) { const sampleProcessed = processedMembers[0]; console.log('[api/members.get] DIAGNOSTIC - Processed member FullName:', `"${sampleProcessed.FullName}"`); console.log('[api/members.get] DIAGNOSTIC - FullName calculation result:', `"${sampleProcessed.first_name || ''}" + " " + "${sampleProcessed.last_name || ''}" = "${sampleProcessed.FullName}"`); console.log('[api/members.get] DIAGNOSTIC - Processed member keys:', Object.keys(sampleProcessed)); } console.log('[api/members.get] ✅ Successfully processed', processedMembers.length, 'members'); return { success: true, data: { list: processedMembers, totalCount: processedMembers.length, filters: { searchTerm, nationality, membershipStatus, duesPaid: duesPaid ? duesPaid === 'true' : undefined } } }; } catch (error: any) { console.error('[api/members.get] ❌ Error fetching members:', error); handleNocoDbError(error, 'getMembers', 'Members'); } }); // Utility function to format phone numbers function formatPhoneNumber(phone: string): string { if (!phone) return ''; // Remove all non-digits const cleaned = phone.replace(/\D/g, ''); // Format based on length if (cleaned.length === 10) { return `(${cleaned.substring(0, 3)}) ${cleaned.substring(3, 6)}-${cleaned.substring(6)}`; } else if (cleaned.length === 11 && cleaned.startsWith('1')) { return `+1 (${cleaned.substring(1, 4)}) ${cleaned.substring(4, 7)}-${cleaned.substring(7)}`; } return phone; // Return original if we can't format it }