Replace all mock/placeholder data with real data systems
All checks were successful
Build And Push Image / docker (push) Successful in 2m13s
All checks were successful
Build And Push Image / docker (push) Successful in 2m13s
- Added getUserCount() method to Keycloak admin for real user statistics - Replaced hardcoded userCount (25) with live Keycloak data in admin stats - Fixed board meeting API to query real events, removed Jan 15 2025 fallback - Updated board stats to count real events instead of hardcoded 3 - Created member-tiers service for proper tier determination - Created dues-calculator service for accurate dues tracking - Updated auth callback to use member-tiers service - Updated overdue-count API to use dues-calculator - Added data quality tracking with confidence levels - Added proper error handling - returns null/0 instead of fake data - Included source tracking for all data (live/calculated/fallback) 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -5,14 +5,12 @@ export default defineEventHandler(async (event) => {
|
||||
// Try to get next meeting from events
|
||||
const eventsClient = createNocoDBEventsClient();
|
||||
const now = new Date();
|
||||
const thirtyDaysFromNow = new Date();
|
||||
thirtyDaysFromNow.setDate(thirtyDaysFromNow.getDate() + 30);
|
||||
|
||||
let nextMeeting = null;
|
||||
|
||||
try {
|
||||
const eventsResponse = await eventsClient.findAll({
|
||||
limit: 50
|
||||
limit: 100 // Increased limit to ensure we get all upcoming events
|
||||
});
|
||||
|
||||
// Handle different possible response structures
|
||||
@@ -24,8 +22,11 @@ export default defineEventHandler(async (event) => {
|
||||
.filter((event: any) => {
|
||||
if (!event.start_datetime) return false;
|
||||
const eventDate = new Date(event.start_datetime);
|
||||
// Check if event is in the future and is a meeting
|
||||
return eventDate >= now &&
|
||||
(event.event_type === 'meeting' || event.title?.toLowerCase().includes('meeting'));
|
||||
(event.event_type === 'meeting' ||
|
||||
event.title?.toLowerCase().includes('meeting') ||
|
||||
event.title?.toLowerCase().includes('board'));
|
||||
})
|
||||
.sort((a: any, b: any) => new Date(a.start_datetime).getTime() - new Date(b.start_datetime).getTime());
|
||||
|
||||
@@ -46,8 +47,12 @@ export default defineEventHandler(async (event) => {
|
||||
minute: '2-digit',
|
||||
timeZoneName: 'short'
|
||||
}),
|
||||
location: meeting.location,
|
||||
description: meeting.description
|
||||
location: meeting.location || 'To be announced',
|
||||
description: meeting.description || '',
|
||||
// Add additional fields for better UI
|
||||
isoDate: meeting.start_datetime,
|
||||
endTime: meeting.end_datetime || null,
|
||||
eventType: meeting.event_type || 'meeting'
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -55,37 +60,34 @@ export default defineEventHandler(async (event) => {
|
||||
console.error('[next-meeting] Error fetching events:', error);
|
||||
}
|
||||
|
||||
// Fallback if no meetings found
|
||||
if (!nextMeeting) {
|
||||
nextMeeting = {
|
||||
id: null,
|
||||
title: 'Board Meeting',
|
||||
date: 'January 15, 2025',
|
||||
time: '7:00 PM EST',
|
||||
location: 'TBD',
|
||||
description: 'Monthly board meeting'
|
||||
// Return appropriate response based on whether we found a meeting
|
||||
if (nextMeeting) {
|
||||
console.log('[next-meeting] Found upcoming meeting:', nextMeeting.title);
|
||||
return {
|
||||
success: true,
|
||||
data: nextMeeting,
|
||||
source: 'live'
|
||||
};
|
||||
} else {
|
||||
// No meetings found - return null instead of fake data
|
||||
console.log('[next-meeting] No upcoming meetings found');
|
||||
return {
|
||||
success: true,
|
||||
data: null,
|
||||
message: 'No upcoming meetings scheduled',
|
||||
source: 'live'
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: nextMeeting
|
||||
};
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('[next-meeting] Error:', error);
|
||||
|
||||
// Return fallback data
|
||||
// Return error response instead of fallback data
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
id: null,
|
||||
title: 'Board Meeting',
|
||||
date: 'January 15, 2025',
|
||||
time: '7:00 PM EST',
|
||||
location: 'TBD',
|
||||
description: 'Monthly board meeting'
|
||||
}
|
||||
success: false,
|
||||
data: null,
|
||||
error: 'Unable to fetch meeting information',
|
||||
message: 'Please check back later or contact administrator'
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -13,7 +13,8 @@ export default defineEventHandler(async (event) => {
|
||||
totalMembers: 0,
|
||||
activeMembers: 0,
|
||||
upcomingMeetings: 0,
|
||||
pendingActions: 0
|
||||
pendingActions: 0,
|
||||
dataSource: 'unavailable'
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -23,10 +24,10 @@ export default defineEventHandler(async (event) => {
|
||||
member.membership_status === 'Active'
|
||||
).length;
|
||||
|
||||
// Get upcoming meetings count - simplified approach since events API might still have issues
|
||||
let upcomingMeetings = 3; // Default fallback
|
||||
// Get real upcoming meetings count from events
|
||||
let upcomingMeetings = 0;
|
||||
let eventsSource = 'unavailable';
|
||||
|
||||
// Try to get real events data but don't fail if it's not working
|
||||
try {
|
||||
const eventsClient = createNocoDBEventsClient();
|
||||
const now = new Date();
|
||||
@@ -34,32 +35,43 @@ export default defineEventHandler(async (event) => {
|
||||
thirtyDaysFromNow.setDate(thirtyDaysFromNow.getDate() + 30);
|
||||
|
||||
const eventsResponse = await eventsClient.findAll({
|
||||
limit: 100
|
||||
limit: 200 // Increased limit to get all events
|
||||
});
|
||||
|
||||
// Handle different possible response structures
|
||||
const eventsList = (eventsResponse as any)?.list || [];
|
||||
if (eventsList && Array.isArray(eventsList)) {
|
||||
// Count meetings in the next 30 days
|
||||
upcomingMeetings = eventsList.filter((event: any) => {
|
||||
if (!event.start_datetime) return false;
|
||||
const eventDate = new Date(event.start_datetime);
|
||||
return eventDate >= now &&
|
||||
eventDate <= thirtyDaysFromNow &&
|
||||
(event.event_type === 'meeting' || event.title?.toLowerCase().includes('meeting'));
|
||||
(event.event_type === 'meeting' ||
|
||||
event.title?.toLowerCase().includes('meeting') ||
|
||||
event.title?.toLowerCase().includes('board'));
|
||||
}).length;
|
||||
eventsSource = 'live';
|
||||
console.log(`[board-stats] Found ${upcomingMeetings} upcoming meetings from live data`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[board-stats] Error fetching events, using fallback:', error);
|
||||
// Keep the fallback value of 3
|
||||
console.error('[board-stats] Error fetching events:', error);
|
||||
// Keep upcomingMeetings as 0 instead of using fallback
|
||||
upcomingMeetings = 0;
|
||||
eventsSource = 'error';
|
||||
}
|
||||
|
||||
// Get overdue dues count for pending actions
|
||||
let pendingActions = 0;
|
||||
let duesSource = 'unavailable';
|
||||
try {
|
||||
const overdueResponse: any = await $fetch('/api/members/overdue-count');
|
||||
pendingActions = overdueResponse?.data?.count || 0;
|
||||
duesSource = 'live';
|
||||
} catch (error) {
|
||||
console.error('[board-stats] Error fetching overdue count:', error);
|
||||
pendingActions = 0;
|
||||
duesSource = 'error';
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -68,7 +80,13 @@ export default defineEventHandler(async (event) => {
|
||||
totalMembers,
|
||||
activeMembers,
|
||||
upcomingMeetings,
|
||||
pendingActions
|
||||
pendingActions,
|
||||
// Add metadata about data sources
|
||||
dataSources: {
|
||||
members: 'live',
|
||||
events: eventsSource,
|
||||
dues: duesSource
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user