@@ -347,7 +347,7 @@ export const getFirstAPI = async (events: string[], team: number, season: Suppor
347347 team_2 : createTeam ( redTeams [ 1 ] ) ,
348348 date : match . actualStartTime ?? match . postResultTime ,
349349 alliance : 'red' ,
350- matchType : match . tournamentLevel === 'Playoff' ? 'PLAYOFF' : match . tournamentLevel === 'Practice' ? 'PRACTICE ' : 'QUALIFICATION' ,
350+ matchType : isPlayoff ? 'PLAYOFF' : isQualification ? 'QUALIFICATION ' : 'PRACTICE'
351351 } ,
352352 blueAlliance : {
353353 totalPoints : blueScore ,
@@ -358,7 +358,7 @@ export const getFirstAPI = async (events: string[], team: number, season: Suppor
358358 team_2 : createTeam ( blueTeams [ 1 ] ) ,
359359 date : match . actualStartTime ?? match . postResultTime ,
360360 alliance : 'blue' ,
361- matchType : match . tournamentLevel === 'Playoff' ? 'PLAYOFF' : match . tournamentLevel === 'Practice' ? 'PRACTICE ' : 'QUALIFICATION' ,
361+ matchType : isPlayoff ? 'PLAYOFF' : isQualification ? 'QUALIFICATION ' : 'PRACTICE'
362362 } ,
363363 } ;
364364 } ) ;
@@ -720,8 +720,77 @@ export async function getCachedMatchScoreDetails(
720720 return scores ;
721721}
722722
723+ // ------------------- BASIC EVENTS (FAST LOADING) -------------------
724+ export interface BasicEventInfo {
725+ name : string ;
726+ eventCode : string ;
727+ location : string ;
728+ date : string ;
729+ rawDate : string ; // ISO date string for reliable parsing
730+ type ?: string ;
731+ }
732+
733+ export const getEventsBasic = async ( season : SupportedYear , includeCompleted = false ) : Promise < BasicEventInfo [ ] > => {
734+ const supabaseAnonKey = process . env . EXPO_PUBLIC_SUPABASE_ANON_KEY ! ;
735+ const headers = { apikey : supabaseAnonKey } ;
736+
737+ try {
738+ const eventsRes = await fetchWithRetry ( `https://api.ares-bot.com/functions/v1/first/${ season } /events` , headers ) ;
739+
740+ if ( ! eventsRes . events || eventsRes . events . length === 0 ) {
741+ console . log ( 'No events found for season' ) ;
742+ return [ ] ;
743+ }
744+
745+ let filteredEvents = eventsRes . events ;
746+
747+ // Filter for future and in-progress events based on end date unless includeCompleted is true
748+ if ( ! includeCompleted ) {
749+ const today = new Date ( ) ;
750+ today . setHours ( 0 , 0 , 0 , 0 ) ;
751+
752+ filteredEvents = eventsRes . events . filter ( ( event : any ) => {
753+ if ( ! event . dateEnd && ! event . dateStart ) return false ;
754+
755+ // Use end date if available, otherwise use start date
756+ const eventDate = new Date ( event . dateEnd || event . dateStart ) ;
757+ eventDate . setHours ( 23 , 59 , 59 , 999 ) ;
758+
759+ // Include events that haven't ended yet (upcoming and ongoing)
760+ return eventDate >= today ;
761+ } ) ;
762+ }
763+
764+ // Convert to basic format immediately without additional API calls
765+ const basicEvents : BasicEventInfo [ ] = filteredEvents . map ( ( event : any ) => ( {
766+ name : event . name || 'Unknown Event' ,
767+ eventCode : event . code || 'UNKNOWN' ,
768+ location : event . venue || event . city || 'TBD' ,
769+ date : event . dateStart
770+ ? new Date ( event . dateStart ) . toLocaleDateString ( 'en-US' , { month : 'long' , day : 'numeric' , year : 'numeric' } )
771+ : 'TBD' ,
772+ rawDate : event . dateStart || event . dateEnd || '' ,
773+ type : event . type || undefined ,
774+ } ) ) ;
775+
776+ // Sort by date (most recent first)
777+ basicEvents . sort ( ( b , a ) => {
778+ const dateA = new Date ( a . date || '' ) ;
779+ const dateB = new Date ( b . date || '' ) ;
780+ return dateA . getTime ( ) - dateB . getTime ( ) ;
781+ } ) ;
782+
783+ console . log ( `Returning ${ basicEvents . length } basic events for fast loading` ) ;
784+ return basicEvents ;
785+
786+ } catch ( error ) {
787+ console . error ( 'Error fetching basic events:' , error ) ;
788+ return [ ] ;
789+ }
790+ } ;
791+
723792// ------------------- UPCOMING EVENTS -------------------
724- export const getUpcomingEvents = async ( season : SupportedYear , team ?: number ) : Promise < EventInfo [ ] > => {
793+ export const getUpcomingEvents = async ( season : SupportedYear , team ?: number , includeTeamCounts = true , includeCompleted = false ) : Promise < EventInfo [ ] > => {
725794 const supabaseAnonKey = process . env . EXPO_PUBLIC_SUPABASE_ANON_KEY ! ;
726795 const headers = { apikey : supabaseAnonKey } ;
727796
@@ -733,29 +802,51 @@ export const getUpcomingEvents = async (season: SupportedYear, team?: number): P
733802 return [ ] ;
734803 }
735804
736- // Return ALL events for the season, not just upcoming ones
737- let teamEvents = eventsRes . events ;
805+ let filteredEvents = eventsRes . events ;
738806
739- // Convert to EventInfo format - only fetch team count from FIRST API
807+ // Filter for future and in-progress events based on end date unless includeCompleted is true
808+ if ( ! includeCompleted ) {
809+ const today = new Date ( ) ;
810+ today . setHours ( 0 , 0 , 0 , 0 ) ;
811+
812+ filteredEvents = eventsRes . events . filter ( ( event : any ) => {
813+ if ( ! event . dateEnd && ! event . dateStart ) return false ;
814+
815+ // Use end date if available, otherwise use start date
816+ const eventDate = new Date ( event . dateEnd || event . dateStart ) ;
817+ eventDate . setHours ( 23 , 59 , 59 , 999 ) ;
818+
819+ // Include events that haven't ended yet (upcoming and ongoing)
820+ return eventDate >= today ;
821+ } ) ;
822+ }
823+
824+ // If a team is specified, filter for events where the team is participating
825+ let teamEvents = filteredEvents ;
826+
827+ // Convert to EventInfo format
740828 const eventPromises = teamEvents . map ( async ( event : any ) => {
741829 let teamCount = 0 ;
742830
743- // Fetch team count from FIRST API
744- try {
745- const teamsUrl = `https://ftc-api.firstinspires.org/v2.0/${ season } /teams?eventCode=${ event . code } ` ;
746- const teamsRes = await fetch ( teamsUrl , {
747- headers : {
748- 'Authorization' : 'Basic ' + Buffer . from ( process . env . EXPO_PUBLIC_FTC_USERNAME + ':' + process . env . EXPO_PUBLIC_FTC_API_KEY ) . toString ( 'base64' ) ,
749- 'Accept' : 'application/json'
831+ // Only fetch team count if requested (slower but more complete data)
832+ if ( includeTeamCounts ) {
833+ // Fetch team count from FIRST API
834+ try {
835+ const teamsUrl = `https://ftc-api.firstinspires.org/v2.0/${ season } /teams?eventCode=${ event . code } ` ;
836+ const teamsRes = await fetch ( teamsUrl , {
837+ headers : {
838+ 'Authorization' : 'Basic ' + btoa ( process . env . EXPO_PUBLIC_FTC_USERNAME + ':' + process . env . EXPO_PUBLIC_FTC_API_KEY ) ,
839+ 'Accept' : 'application/json'
840+ }
841+ } ) ;
842+
843+ if ( teamsRes . ok ) {
844+ const teamsData = await teamsRes . json ( ) ;
845+ teamCount = teamsData . teamCountTotal || teamsData . teams ?. length || 0 ;
750846 }
751- } ) ;
752-
753- if ( teamsRes . ok ) {
754- const teamsData = await teamsRes . json ( ) ;
755- teamCount = teamsData . teamCountTotal || teamsData . teams ?. length || 0 ;
847+ } catch ( error ) {
848+ console . error ( `Error fetching team count for event ${ event . code } :` , error ) ;
756849 }
757- } catch ( error ) {
758- console . error ( `Error fetching team count for event ${ event . code } :` , error ) ;
759850 }
760851
761852 const eventInfo : EventInfo = {
@@ -794,4 +885,19 @@ export const getUpcomingEvents = async (season: SupportedYear, team?: number): P
794885 console . error ( 'Error fetching upcoming events:' , error ) ;
795886 return [ ] ;
796887 }
888+ } ;
889+
890+ // Get only upcoming and ongoing events (not completed ones)
891+ export const getUpcomingEventsOnly = async ( season : SupportedYear , team ?: number ) : Promise < EventInfo [ ] > => {
892+ const allEvents = await getUpcomingEvents ( season , team , true ) ;
893+
894+ const today = new Date ( ) ;
895+ today . setHours ( 0 , 0 , 0 , 0 ) ;
896+
897+ return allEvents . filter ( event => {
898+ if ( ! event . date || event . date === 'TBD' ) return true ; // Include events with unknown dates
899+ const eventDate = new Date ( event . date ) ;
900+ // Include events that haven't ended yet (upcoming and ongoing)
901+ return eventDate >= today ;
902+ } ) ;
797903} ;
0 commit comments