feat(board): Add real data integration for board dashboard
All checks were successful
Build And Push Image / docker (push) Successful in 3m22s

- Create /api/board/stats endpoint for member statistics and overview data
- Create /api/board/next-meeting endpoint for upcoming meeting information
- Update board.vue to fetch real data instead of using mock data
- Add loading states and error handling with graceful fallbacks
- Board Overview now shows actual member counts and pending actions
- Next Meeting section displays real event data when available

The board dashboard now displays live data from the database while maintaining
fallback functionality if any data sources are unavailable.
This commit is contained in:
2025-08-12 14:18:55 +02:00
parent 1d5ecfddcd
commit 287af29f6c
3 changed files with 239 additions and 8 deletions

View File

@@ -278,21 +278,78 @@ const duesRefreshTrigger = ref(0);
// Member dialog state
const showViewDialog = ref(false);
const showEditDialog = ref(false);
const selectedMember = ref(null);
const selectedMember = ref<Member | null>(null);
// Mock data for board dashboard
// Real data for board dashboard
const stats = ref({
totalMembers: 156,
activeMembers: 142,
upcomingMeetings: 3,
pendingActions: 7
totalMembers: 0,
activeMembers: 0,
upcomingMeetings: 0,
pendingActions: 0
});
const nextMeeting = ref({
date: 'January 15, 2025',
time: '7:00 PM EST'
id: null,
title: 'Board Meeting',
date: 'Loading...',
time: 'Loading...',
location: 'TBD',
description: 'Monthly board meeting'
});
const isLoading = ref(true);
// Load real data on component mount
onMounted(async () => {
await loadBoardData();
});
const loadBoardData = async () => {
try {
isLoading.value = true;
// Load board statistics
const [statsResponse, meetingResponse] = await Promise.allSettled([
$fetch('/api/board/stats'),
$fetch('/api/board/next-meeting')
]);
// Handle stats response
if (statsResponse.status === 'fulfilled') {
const statsData = statsResponse.value as any;
if (statsData?.success) {
stats.value = {
totalMembers: statsData.data.totalMembers || 0,
activeMembers: statsData.data.activeMembers || 0,
upcomingMeetings: statsData.data.upcomingMeetings || 0,
pendingActions: statsData.data.pendingActions || 0
};
}
}
// Handle next meeting response
if (meetingResponse.status === 'fulfilled') {
const meetingData = meetingResponse.value as any;
if (meetingData?.success) {
nextMeeting.value = {
id: meetingData.data.id,
title: meetingData.data.title || 'Board Meeting',
date: meetingData.data.date || 'TBD',
time: meetingData.data.time || 'TBD',
location: meetingData.data.location || 'TBD',
description: meetingData.data.description || 'Monthly board meeting'
};
}
}
} catch (error) {
console.error('Error loading board data:', error);
// Keep fallback values
} finally {
isLoading.value = false;
}
};
const recentActivity = ref([
{
id: 1,