From 733f3dc9317159d3191d4943947e2a1294688b13 Mon Sep 17 00:00:00 2001 From: chark1es Date: Wed, 2 Apr 2025 17:00:37 -0700 Subject: [PATCH] fix database fetching --- .../dashboard/EventsSection/EventCheckIn.tsx | 44 ++++-- .../LeaderboardSection/LeaderboardStats.tsx | 46 +++++-- .../LeaderboardSection/LeaderboardTable.tsx | 66 ++++++--- .../Officer_EventManagement/EventEditor.tsx | 125 ++++++++++++++++-- .../dashboard/ProfileSection/Stats.tsx | 60 ++++----- src/schemas/pocketbase/schema.ts | 17 ++- 6 files changed, 274 insertions(+), 84 deletions(-) diff --git a/src/components/dashboard/EventsSection/EventCheckIn.tsx b/src/components/dashboard/EventsSection/EventCheckIn.tsx index 69ef38e..253272f 100644 --- a/src/components/dashboard/EventsSection/EventCheckIn.tsx +++ b/src/components/dashboard/EventsSection/EventCheckIn.tsx @@ -7,7 +7,7 @@ import { DataSyncService } from "../../../scripts/database/DataSyncService"; import { Collections } from "../../../schemas/pocketbase/schema"; import { Icon } from "@iconify/react"; import toast from "react-hot-toast"; -import type { Event, EventAttendee } from "../../../schemas/pocketbase"; +import type { Event, EventAttendee, LimitedUser } from "../../../schemas/pocketbase"; // Extended Event interface with additional properties needed for this component interface ExtendedEvent extends Event { @@ -264,20 +264,48 @@ const EventCheckIn = () => { totalPoints += attendee.points_earned || 0; }); - // Log the points update - // console.log(`Updating user points to: ${totalPoints}`); + // Update the LimitedUser record with the new points total + try { + // Try to get the LimitedUser record to check if it exists + let limitedUserExists = false; + try { + const limitedUser = await get.getOne(Collections.LIMITED_USERS, userId); + limitedUserExists = !!limitedUser; + } catch (e) { + // Record doesn't exist + limitedUserExists = false; + } - // Update the user record with the new total points - await update.updateFields(Collections.USERS, userId, { - points: totalPoints - }); + // Create or update the LimitedUser record + if (limitedUserExists) { + await update.updateFields(Collections.LIMITED_USERS, userId, { + points: JSON.stringify(totalPoints), + total_events_attended: JSON.stringify(userAttendance.totalItems) + }); + } else { + // Get user data to create LimitedUser record + const userData = await get.getOne(Collections.USERS, userId); + if (userData) { + await update.create(Collections.LIMITED_USERS, { + id: userId, // Use same ID as user record + name: userData.name || 'Anonymous User', + major: userData.major || '', + points: JSON.stringify(totalPoints), + total_events_attended: JSON.stringify(userAttendance.totalItems) + }); + } + } + } catch (error) { + console.error('Failed to update LimitedUser record:', error); + } // Ensure local data is in sync with backend // First sync the new attendance record await dataSync.syncCollection(Collections.EVENT_ATTENDEES); - // Then sync the updated user data to ensure points are correctly reflected locally + // Then sync the updated user and LimitedUser data await dataSync.syncCollection(Collections.USERS); + await dataSync.syncCollection(Collections.LIMITED_USERS); // Clear event code from local storage await dataSync.clearEventCode(); diff --git a/src/components/dashboard/LeaderboardSection/LeaderboardStats.tsx b/src/components/dashboard/LeaderboardSection/LeaderboardStats.tsx index 9291492..5b18653 100644 --- a/src/components/dashboard/LeaderboardSection/LeaderboardStats.tsx +++ b/src/components/dashboard/LeaderboardSection/LeaderboardStats.tsx @@ -1,6 +1,8 @@ import { useState, useEffect } from 'react'; import { Get } from '../../../scripts/pocketbase/Get'; import { Authentication } from '../../../scripts/pocketbase/Authentication'; +import { Collections } from '../../../schemas/pocketbase/schema'; +import type { LimitedUser } from '../../../schemas/pocketbase/schema'; interface LeaderboardStats { totalUsers: number; @@ -54,34 +56,50 @@ export default function LeaderboardStats() { setLoading(true); // Get all users without sorting - we'll sort on client side - const response = await get.getList('limitedUser', 1, 500, '', '', { + const response = await get.getList(Collections.LIMITED_USERS, 1, 500, '', '', { fields: ['id', 'name', 'points'] }); + // Parse points from JSON string and convert to number + const processedUsers = response.items.map((user: Partial) => { + let pointsValue = 0; + try { + if (user.points) { + // Parse the JSON string to get the points value + const pointsData = JSON.parse(user.points); + pointsValue = typeof pointsData === 'number' ? pointsData : 0; + } + } catch (e) { + console.error('Error parsing points data:', e); + } + + return { + id: user.id, + name: user.name, + parsedPoints: pointsValue + }; + }); + // Filter out users with no points for the leaderboard stats - const leaderboardUsers = response.items - .filter((user: any) => - user.points !== undefined && - user.points !== null && - user.points > 0 - ) + const leaderboardUsers = processedUsers + .filter(user => user.parsedPoints > 0) // Sort by points descending - .sort((a: any, b: any) => b.points - a.points); + .sort((a, b) => b.parsedPoints - a.parsedPoints); const totalUsers = leaderboardUsers.length; - const totalPoints = leaderboardUsers.reduce((sum: number, user: any) => sum + (user.points || 0), 0); - const topScore = leaderboardUsers.length > 0 ? leaderboardUsers[0].points : 0; + const totalPoints = leaderboardUsers.reduce((sum: number, user) => sum + user.parsedPoints, 0); + const topScore = leaderboardUsers.length > 0 ? leaderboardUsers[0].parsedPoints : 0; // Find current user's points and rank - BUT don't filter by points > 0 for the current user let yourPoints = 0; let yourRank = null; if (isAuthenticated && currentUserId) { - // Look for the current user in ALL users, not just those with points > 0 - const currentUser = response.items.find((user: any) => user.id === currentUserId); + // Look for the current user in ALL processed users, not just those with points > 0 + const currentUser = processedUsers.find(user => user.id === currentUserId); if (currentUser) { - yourPoints = currentUser.points || 0; + yourPoints = currentUser.parsedPoints || 0; // Only calculate rank if user has points if (yourPoints > 0) { @@ -119,7 +137,7 @@ export default function LeaderboardStats() { }; fetchStats(); - }, [isAuthenticated, currentUserId]); + }, [get, isAuthenticated, currentUserId]); if (loading) { return ( diff --git a/src/components/dashboard/LeaderboardSection/LeaderboardTable.tsx b/src/components/dashboard/LeaderboardSection/LeaderboardTable.tsx index d505c01..2fb71d1 100644 --- a/src/components/dashboard/LeaderboardSection/LeaderboardTable.tsx +++ b/src/components/dashboard/LeaderboardSection/LeaderboardTable.tsx @@ -1,7 +1,8 @@ import { useState, useEffect } from 'react'; import { Get } from '../../../scripts/pocketbase/Get'; import { Authentication } from '../../../scripts/pocketbase/Authentication'; -import type { User } from '../../../schemas/pocketbase/schema'; +import type { User, LimitedUser } from '../../../schemas/pocketbase/schema'; +import { Collections } from '../../../schemas/pocketbase/schema'; interface LeaderboardUser { id: string; @@ -63,21 +64,44 @@ export default function LeaderboardTable() { setLoading(true); // Fetch users without sorting - we'll sort on client side - const response = await get.getList('limitedUser', 1, 100, '', '', { + const response = await get.getList(Collections.LIMITED_USERS, 1, 100, '', '', { fields: ['id', 'name', 'points', 'avatar', 'major'] }); // First get the current user separately so we can include them even if they have 0 points let currentUserData = null; if (isAuthenticated && currentUserId) { - currentUserData = response.items.find((user: Partial) => user.id === currentUserId); + currentUserData = response.items.find((user: Partial) => user.id === currentUserId); } + // Parse points from JSON string and convert to number + const processedUsers = response.items.map((user: any) => { + let pointsValue = 0; + try { + if (user.points) { + // Parse the JSON string to get the points value + const pointsData = JSON.parse(user.points); + pointsValue = typeof pointsData === 'number' ? pointsData : 0; + } + } catch (e) { + console.error('Error parsing points data:', e); + } + + return { + id: user.id, + name: user.name, + major: user.major, + avatar: user.avatar, // Include avatar if it exists + points: user.points, + parsedPoints: pointsValue + }; + }); + // Filter and map to our leaderboard user format, and sort client-side - let leaderboardUsers = response.items - .filter((user: Partial) => user.points !== undefined && user.points !== null && user.points > 0) - .sort((a: Partial, b: Partial) => (b.points || 0) - (a.points || 0)) - .map((user: Partial, index: number) => { + let leaderboardUsers = processedUsers + .filter(user => user.parsedPoints > 0) + .sort((a, b) => (b.parsedPoints || 0) - (a.parsedPoints || 0)) + .map((user, index: number) => { // Check if this is the current user if (isAuthenticated && user.id === currentUserId) { setCurrentUserRank(index + 1); @@ -86,7 +110,7 @@ export default function LeaderboardTable() { return { id: user.id || '', name: user.name || 'Anonymous User', - points: user.points || 0, + points: user.parsedPoints, avatar: user.avatar, major: user.major }; @@ -94,16 +118,20 @@ export default function LeaderboardTable() { // Include current user even if they have 0 points, // but don't include in ranking if they have no points - if (isAuthenticated && currentUserData && - !leaderboardUsers.some(user => user.id === currentUserId)) { - // User isn't already in the list (has 0 points) - leaderboardUsers.push({ - id: currentUserData.id || '', - name: currentUserData.name || 'Anonymous User', - points: currentUserData.points || 0, - avatar: currentUserData.avatar, - major: currentUserData.major - }); + if (isAuthenticated && currentUserId) { + // Find current user in processed users + const currentUserProcessed = processedUsers.find(user => user.id === currentUserId); + + // If current user exists and isn't already in the leaderboard (has 0 points) + if (currentUserProcessed && !leaderboardUsers.some(user => user.id === currentUserId)) { + leaderboardUsers.push({ + id: currentUserProcessed.id || '', + name: currentUserProcessed.name || 'Anonymous User', + points: currentUserProcessed.parsedPoints || 0, + avatar: currentUserProcessed.avatar, + major: currentUserProcessed.major + }); + } } setUsers(leaderboardUsers); @@ -117,7 +145,7 @@ export default function LeaderboardTable() { }; fetchLeaderboard(); - }, [isAuthenticated, currentUserId]); + }, [get, isAuthenticated, currentUserId]); useEffect(() => { if (searchQuery.trim() === '') { diff --git a/src/components/dashboard/Officer_EventManagement/EventEditor.tsx b/src/components/dashboard/Officer_EventManagement/EventEditor.tsx index 268de86..24a1ee1 100644 --- a/src/components/dashboard/Officer_EventManagement/EventEditor.tsx +++ b/src/components/dashboard/Officer_EventManagement/EventEditor.tsx @@ -5,6 +5,7 @@ import { Authentication } from "../../../scripts/pocketbase/Authentication"; import { Update } from "../../../scripts/pocketbase/Update"; import { FileManager } from "../../../scripts/pocketbase/FileManager"; import { SendLog } from "../../../scripts/pocketbase/SendLog"; +import { Realtime } from "../../../scripts/pocketbase/Realtime"; import FilePreview from "../universal/FilePreview"; import type { Event as SchemaEvent, AttendeeEntry } from "../../../schemas/pocketbase"; import { DataSyncService } from '../../../scripts/database/DataSyncService'; @@ -240,7 +241,15 @@ const EventForm = memo(({ // Show error for rejected files if (rejectedFiles.length > 0) { const errorMessage = `The following files were not added:\n${rejectedFiles.map(f => `${f.name}: ${f.reason}`).join('\n')}`; - toast.error(errorMessage); + // Use toast with custom styling to ensure visibility above modal + toast.error(errorMessage, { + duration: 5000, + style: { + zIndex: 9999, // Ensure it's above the modal + maxWidth: '500px', + whiteSpace: 'pre-line' // Preserve line breaks + } + }); } setSelectedFiles(newFiles); @@ -293,6 +302,31 @@ const EventForm = memo(({ > +
{filesToDelete.has(filename) ? (