Replace all mock data in admin and board pages with real data
All checks were successful
Build And Push Image / docker (push) Successful in 1m56s
All checks were successful
Build And Push Image / docker (push) Successful in 1m56s
- Admin members page now loads real member data from NocoDB API - Admin users page fetches actual users from Keycloak with tier determination - Board members page uses real member data with proper transformations - Admin payments page generates payment records from dues tracking data - Created new /api/admin/users endpoint for Keycloak user management - All stats cards now calculate from real data instead of hardcoded values - Removed all mock/placeholder data arrays from production pages 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -38,7 +38,7 @@
|
||||
<v-card-text>
|
||||
<div class="d-flex align-center justify-space-between">
|
||||
<div>
|
||||
<div class="text-h4 font-weight-bold">${{ stats.pending.toLocaleString() }}</div>
|
||||
<div class="text-h4 font-weight-bold">${{ stats.pendingPayments.toLocaleString() }}</div>
|
||||
<div class="text-body-2 text-medium-emphasis">Pending</div>
|
||||
</div>
|
||||
<v-icon size="32" color="warning">mdi-clock-outline</v-icon>
|
||||
@@ -51,8 +51,8 @@
|
||||
<v-card-text>
|
||||
<div class="d-flex align-center justify-space-between">
|
||||
<div>
|
||||
<div class="text-h4 font-weight-bold">${{ stats.overdue.toLocaleString() }}</div>
|
||||
<div class="text-body-2 text-medium-emphasis">Overdue</div>
|
||||
<div class="text-h4 font-weight-bold">{{ stats.failedTransactions }}</div>
|
||||
<div class="text-body-2 text-medium-emphasis">Failed</div>
|
||||
</div>
|
||||
<v-icon size="32" color="error">mdi-alert-circle-outline</v-icon>
|
||||
</div>
|
||||
@@ -64,8 +64,8 @@
|
||||
<v-card-text>
|
||||
<div class="d-flex align-center justify-space-between">
|
||||
<div>
|
||||
<div class="text-h4 font-weight-bold">{{ stats.transactions }}</div>
|
||||
<div class="text-body-2 text-medium-emphasis">Transactions</div>
|
||||
<div class="text-h4 font-weight-bold">{{ stats.successfulTransactions }}</div>
|
||||
<div class="text-body-2 text-medium-emphasis">Successful</div>
|
||||
</div>
|
||||
<v-icon size="32" color="info">mdi-swap-horizontal</v-icon>
|
||||
</div>
|
||||
@@ -349,10 +349,10 @@ const dateTo = ref('');
|
||||
|
||||
// Stats
|
||||
const stats = ref({
|
||||
totalRevenue: 45820,
|
||||
pending: 3250,
|
||||
overdue: 1800,
|
||||
transactions: 342
|
||||
totalRevenue: 0,
|
||||
pendingPayments: 0,
|
||||
successfulTransactions: 0,
|
||||
failedTransactions: 0
|
||||
});
|
||||
|
||||
// Form data
|
||||
@@ -387,53 +387,8 @@ const headers = [
|
||||
{ title: 'Actions', key: 'actions', sortable: false, align: 'end' }
|
||||
];
|
||||
|
||||
// Mock data
|
||||
const payments = ref([
|
||||
{
|
||||
id: 1,
|
||||
transaction_id: 'TXN-2024-001',
|
||||
member_name: 'John Smith',
|
||||
member_email: 'john.smith@example.com',
|
||||
amount: 500,
|
||||
type: 'Membership',
|
||||
status: 'Completed',
|
||||
date: new Date('2024-01-15'),
|
||||
method: 'Credit Card'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
transaction_id: 'TXN-2024-002',
|
||||
member_name: 'Sarah Johnson',
|
||||
member_email: 'sarah.j@example.com',
|
||||
amount: 250,
|
||||
type: 'Event',
|
||||
status: 'Pending',
|
||||
date: new Date('2024-01-14'),
|
||||
method: 'Bank Transfer'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
transaction_id: 'TXN-2024-003',
|
||||
member_name: 'Michael Williams',
|
||||
member_email: 'michael.w@example.com',
|
||||
amount: 1000,
|
||||
type: 'Donation',
|
||||
status: 'Completed',
|
||||
date: new Date('2024-01-13'),
|
||||
method: 'Check'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
transaction_id: 'TXN-2024-004',
|
||||
member_name: 'Emma Davis',
|
||||
member_email: 'emma.d@example.com',
|
||||
amount: 75,
|
||||
type: 'Event',
|
||||
status: 'Failed',
|
||||
date: new Date('2024-01-12'),
|
||||
method: 'Credit Card'
|
||||
}
|
||||
]);
|
||||
// Real dues payment data
|
||||
const payments = ref([]);
|
||||
|
||||
// Computed
|
||||
const filteredPayments = computed(() => {
|
||||
@@ -521,4 +476,79 @@ const savePayment = () => {
|
||||
console.log('Save payment:', paymentForm.value);
|
||||
showRecordPaymentDialog.value = false;
|
||||
};
|
||||
|
||||
// Load dues payment data from members
|
||||
const loadPayments = async () => {
|
||||
try {
|
||||
// Fetch members from API
|
||||
const { data } = await $fetch('/api/members');
|
||||
|
||||
if (data?.members) {
|
||||
const paymentRecords = [];
|
||||
let transactionCounter = 1;
|
||||
|
||||
// Generate payment records from member dues data
|
||||
for (const member of data.members) {
|
||||
// If member has last_dues_paid, create a payment record
|
||||
if (member.last_dues_paid) {
|
||||
paymentRecords.push({
|
||||
id: transactionCounter++,
|
||||
transaction_id: `TXN-${new Date(member.last_dues_paid).getFullYear()}-${String(transactionCounter).padStart(3, '0')}`,
|
||||
member_name: `${member.first_name} ${member.last_name}`,
|
||||
member_email: member.email,
|
||||
amount: member.dues_amount || 50, // Default annual dues
|
||||
type: 'Membership Dues',
|
||||
status: 'Completed',
|
||||
date: new Date(member.last_dues_paid),
|
||||
method: member.last_payment_method || 'Unknown'
|
||||
});
|
||||
}
|
||||
|
||||
// If member has dues due/overdue, create a pending payment record
|
||||
if (member.dues_status === 'Due' || member.dues_status === 'Overdue') {
|
||||
const dueDate = member.dues_paid_until ? new Date(member.dues_paid_until) : null;
|
||||
if (dueDate) {
|
||||
paymentRecords.push({
|
||||
id: transactionCounter++,
|
||||
transaction_id: `TXN-PENDING-${String(transactionCounter).padStart(3, '0')}`,
|
||||
member_name: `${member.first_name} ${member.last_name}`,
|
||||
member_email: member.email,
|
||||
amount: member.dues_amount || 50,
|
||||
type: 'Membership Dues',
|
||||
status: member.dues_status === 'Overdue' ? 'Overdue' : 'Pending',
|
||||
date: dueDate,
|
||||
method: 'Awaiting Payment'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by date descending (most recent first)
|
||||
paymentRecords.sort((a, b) => b.date.getTime() - a.date.getTime());
|
||||
|
||||
payments.value = paymentRecords;
|
||||
|
||||
// Calculate stats
|
||||
const completed = paymentRecords.filter(p => p.status === 'Completed');
|
||||
const pending = paymentRecords.filter(p => p.status === 'Pending' || p.status === 'Overdue');
|
||||
|
||||
stats.value = {
|
||||
totalRevenue: completed.reduce((sum, p) => sum + p.amount, 0),
|
||||
pendingPayments: pending.reduce((sum, p) => sum + p.amount, 0),
|
||||
successfulTransactions: completed.length,
|
||||
failedTransactions: paymentRecords.filter(p => p.status === 'Failed').length
|
||||
};
|
||||
|
||||
console.log(`[admin-payments] Generated ${paymentRecords.length} payment records from member dues data`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading payments:', error);
|
||||
// Keep empty array if load fails
|
||||
}
|
||||
};
|
||||
|
||||
// Load data on mount
|
||||
onMounted(async () => {
|
||||
await loadPayments();
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user