comprehensive diagnostic and fix system for the "undefined" member display issue
All checks were successful
Build And Push Image / docker (push) Successful in 2m49s
All checks were successful
Build And Push Image / docker (push) Successful in 2m49s
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { getMembers, handleNocoDbError } from '~/server/utils/nocodb';
|
||||
import { getMembers, handleNocoDbError, normalizeFieldsFromNocoDB } from '~/server/utils/nocodb';
|
||||
import type { Member } from '~/utils/types';
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
@@ -28,6 +28,27 @@ export default defineEventHandler(async (event) => {
|
||||
|
||||
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) {
|
||||
@@ -56,11 +77,23 @@ export default defineEventHandler(async (event) => {
|
||||
}
|
||||
|
||||
// Add computed fields
|
||||
const processedMembers = members.map(member => ({
|
||||
...member,
|
||||
FullName: `${member.first_name || ''} ${member.last_name || ''}`.trim(),
|
||||
FormattedPhone: formatPhoneNumber(member.phone)
|
||||
}));
|
||||
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');
|
||||
|
||||
|
||||
@@ -98,6 +98,102 @@ export const formatNationalitiesAsString = (nationalities: string[]): string =>
|
||||
return nationalities.filter(n => n && n.trim()).join(',');
|
||||
};
|
||||
|
||||
// Field normalization functions
|
||||
export const normalizeFieldsFromNocoDB = (data: any): Member => {
|
||||
console.log('[normalizeFieldsFromNocoDB] Input data keys:', Object.keys(data));
|
||||
|
||||
const normalized: any = { ...data };
|
||||
|
||||
// Field mapping for display names to snake_case (READ operations)
|
||||
const readFieldMap: Record<string, string> = {
|
||||
'First Name': 'first_name',
|
||||
'Last Name': 'last_name',
|
||||
'Email': 'email',
|
||||
'Email Address': 'email',
|
||||
'Phone': 'phone',
|
||||
'Phone Number': 'phone',
|
||||
'Date of Birth': 'date_of_birth',
|
||||
'Nationality': 'nationality',
|
||||
'Address': 'address',
|
||||
'Membership Status': 'membership_status',
|
||||
'Member Since': 'member_since',
|
||||
'Current Year Dues Paid': 'current_year_dues_paid',
|
||||
'Membership Date Paid': 'membership_date_paid',
|
||||
'Payment Due Date': 'payment_due_date',
|
||||
// Also handle reverse mapping in case data comes in snake_case already
|
||||
'first_name': 'first_name',
|
||||
'last_name': 'last_name',
|
||||
'email': 'email',
|
||||
'phone': 'phone',
|
||||
'date_of_birth': 'date_of_birth',
|
||||
'nationality': 'nationality',
|
||||
'address': 'address',
|
||||
'membership_status': 'membership_status',
|
||||
'member_since': 'member_since',
|
||||
'current_year_dues_paid': 'current_year_dues_paid',
|
||||
'membership_date_paid': 'membership_date_paid',
|
||||
'payment_due_date': 'payment_due_date'
|
||||
};
|
||||
|
||||
// Apply field mapping
|
||||
for (const [sourceKey, targetKey] of Object.entries(readFieldMap)) {
|
||||
if (sourceKey in data && data[sourceKey] !== undefined && data[sourceKey] !== null) {
|
||||
normalized[targetKey] = data[sourceKey];
|
||||
console.log(`[normalizeFieldsFromNocoDB] Mapped "${sourceKey}" -> "${targetKey}":`, data[sourceKey]);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure required fields exist with fallbacks
|
||||
normalized.first_name = normalized.first_name || normalized['First Name'] || '';
|
||||
normalized.last_name = normalized.last_name || normalized['Last Name'] || '';
|
||||
normalized.email = normalized.email || normalized['Email'] || normalized['Email Address'] || '';
|
||||
|
||||
console.log('[normalizeFieldsFromNocoDB] Normalized member fields:', Object.keys(normalized));
|
||||
console.log('[normalizeFieldsFromNocoDB] Final first_name:', normalized.first_name);
|
||||
console.log('[normalizeFieldsFromNocoDB] Final last_name:', normalized.last_name);
|
||||
|
||||
return normalized as Member;
|
||||
};
|
||||
|
||||
export const normalizeFieldsForNocoDB = (data: any): Record<string, any> => {
|
||||
console.log('[normalizeFieldsForNocoDB] Input data keys:', Object.keys(data));
|
||||
|
||||
// Field mapping for snake_case to display names (WRITE operations)
|
||||
const writeFieldMap: Record<string, string> = {
|
||||
'first_name': 'First Name',
|
||||
'last_name': 'Last Name',
|
||||
'email': 'Email',
|
||||
'phone': 'Phone',
|
||||
'date_of_birth': 'Date of Birth',
|
||||
'nationality': 'Nationality',
|
||||
'address': 'Address',
|
||||
'membership_status': 'Membership Status',
|
||||
'member_since': 'Member Since',
|
||||
'current_year_dues_paid': 'Current Year Dues Paid',
|
||||
'membership_date_paid': 'Membership Date Paid',
|
||||
'payment_due_date': 'Payment Due Date'
|
||||
};
|
||||
|
||||
const normalized: any = {};
|
||||
|
||||
// First, try direct mapping using write field map
|
||||
for (const [sourceKey, targetKey] of Object.entries(writeFieldMap)) {
|
||||
if (sourceKey in data && data[sourceKey] !== undefined) {
|
||||
normalized[targetKey] = data[sourceKey];
|
||||
console.log(`[normalizeFieldsForNocoDB] Mapped "${sourceKey}" -> "${targetKey}":`, data[sourceKey]);
|
||||
}
|
||||
}
|
||||
|
||||
// If no mappings worked, try to use the data as-is (fallback)
|
||||
if (Object.keys(normalized).length === 0) {
|
||||
console.log('[normalizeFieldsForNocoDB] No field mappings applied, using original data');
|
||||
return { ...data };
|
||||
}
|
||||
|
||||
console.log('[normalizeFieldsForNocoDB] Final normalized keys:', Object.keys(normalized));
|
||||
return normalized;
|
||||
};
|
||||
|
||||
// Global variable to store effective configuration
|
||||
let globalNocoDBConfig: any = null;
|
||||
|
||||
@@ -161,6 +257,17 @@ export const getMembers = async (): Promise<EntityResponse<Member>> => {
|
||||
console.log('[nocodb.getMembers] Successfully fetched members, count:', result.list?.length || 0);
|
||||
console.log('[nocodb.getMembers] Request duration:', Date.now() - startTime, 'ms');
|
||||
|
||||
// DIAGNOSTIC: Log raw member data structure to identify schema issues
|
||||
if (result.list && result.list.length > 0) {
|
||||
const sampleMember = result.list[0];
|
||||
console.log('[nocodb.getMembers] DIAGNOSTIC - Raw member fields from NocoDB:', Object.keys(sampleMember));
|
||||
console.log('[nocodb.getMembers] DIAGNOSTIC - Sample member data:', JSON.stringify(sampleMember, null, 2));
|
||||
console.log('[nocodb.getMembers] DIAGNOSTIC - first_name value:', sampleMember.first_name);
|
||||
console.log('[nocodb.getMembers] DIAGNOSTIC - last_name value:', sampleMember.last_name);
|
||||
console.log('[nocodb.getMembers] DIAGNOSTIC - First Name value:', (sampleMember as any)['First Name']);
|
||||
console.log('[nocodb.getMembers] DIAGNOSTIC - Last Name value:', (sampleMember as any)['Last Name']);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error: any) {
|
||||
console.error('[nocodb.getMembers] Error fetching members:', error);
|
||||
|
||||
Reference in New Issue
Block a user