@@ -11,17 +11,22 @@ import {DayId} from "@/models/VoxxrinDay";
1111import { VoxxrinConferenceDescriptor } from "@/models/VoxxrinConferenceDescriptor" ;
1212import { DocumentReference , doc , collection , getDoc } from "firebase/firestore" ;
1313import { db } from "@/state/firebase" ;
14- import { prepareEventTalks } from "@/state/useEventTalk" ;
14+ import { prepareEventTalk } from "@/state/useEventTalk" ;
1515import { prepareTalkStats } from "@/state/useEventTalkStats" ;
1616import { prepareUserTalkNotes } from "@/state/useUserTalkNotes" ;
17- import { TalkId , VoxxrinTalk } from "@/models/VoxxrinTalk" ;
17+ import {
18+ createVoxxrinTalkFromFirestore ,
19+ removeTalkOverflowsAndDuplicates ,
20+ VoxxrinTalk
21+ } from "@/models/VoxxrinTalk" ;
1822import { VoxxrinTimeslotFeedback } from "@/models/VoxxrinFeedback" ;
1923import { UserDailyFeedbacks } from "../../../shared/feedbacks.firestore" ;
20- import { Logger , PERF_LOGGER } from "@/services/Logger" ;
24+ import { PERF_LOGGER } from "@/services/Logger" ;
2125import { User } from 'firebase/auth' ;
2226import { CompletablePromiseQueue } from "@/models/utils" ;
23- import { match } from "ts-pattern" ;
24- import { preloadPicture } from "@/services/Cachings" ;
27+ import { match , P } from "ts-pattern" ;
28+ import { checkCache } from "@/services/Cachings" ;
29+ import { Temporal } from "temporal-polyfill" ;
2530
2631export function useSchedule (
2732 conferenceDescriptorRef : Ref < VoxxrinConferenceDescriptor | undefined > ,
@@ -61,33 +66,12 @@ export function dailyScheduleDocument(eventDescriptor: VoxxrinConferenceDescript
6166 return doc ( collection ( doc ( collection ( db , 'events' ) , eventDescriptor . id . value ) , 'days' ) , dayId . value ) as DocumentReference < DailySchedule > ;
6267}
6368
64- const IN_MEMORY_SPEAKER_URL_PRELOADINGS = new Set < string > ( ) ;
65- async function loadTalkSpeakerUrls (
66- talk : { speakers : Array < { photoUrl ?: VoxxrinTalk [ 'speakers' ] [ number ] [ 'photoUrl' ] } > } ,
67- promisesQueue : CompletablePromiseQueue
68- ) {
69- const LOGGER = Logger . named ( "loadTalkSpeakerUrls" ) ;
70-
71- promisesQueue . addAll ( talk . speakers . map ( speaker => {
72- return async ( ) => new Promise ( async resolve => {
73- if ( speaker . photoUrl ) {
74- if ( IN_MEMORY_SPEAKER_URL_PRELOADINGS . has ( speaker . photoUrl ) ) {
75- LOGGER . debug ( `Speaker url already preloaded, skipping: ${ speaker . photoUrl } ` )
76- resolve ( null ) ;
77- } else {
78- IN_MEMORY_SPEAKER_URL_PRELOADINGS . add ( speaker . photoUrl ) ;
79-
80- // TODO: handle picture loading error here maybe ??
81- await preloadPicture ( speaker . photoUrl )
82- resolve ( null ) ;
83- }
84- } else {
85- resolve ( null ) ;
86- }
87- } ) ;
88- } ) , { priority : 1 } ) ; // Low priority because if we're not getting speaker image, that's not dramatic
89- }
69+ export async function prepareDailySchedule ( conferenceDescriptor : VoxxrinConferenceDescriptor , day : DayId , dailyTalks : VoxxrinTalk [ ] , promisesQueue : CompletablePromiseQueue , queuePriority : number ) {
70+ // Removing talk duplicates (for instance, overflows)
71+ const dedupedDailyTalks = removeTalkOverflowsAndDuplicates ( dailyTalks ) ;
9072
73+ promisesQueue . addAll ( dedupedDailyTalks . map ( talk => ( ) => prepareEventTalk ( conferenceDescriptor , day , talk , promisesQueue , queuePriority ) ) )
74+ }
9175
9276export async function
9377prepareSchedules (
@@ -98,55 +82,52 @@ prepareSchedules(
9882 otherDayIds : Array < DayId > ,
9983 promisesQueue : CompletablePromiseQueue
10084) {
101- PERF_LOGGER . debug ( ( ) => `prepareSchedules(userId=${ user . uid } , eventId=${ conferenceDescriptor . id . value } , currentDayId=${ currentDayId . value } , currentTalkIds=${ JSON . stringify ( currentTalks . map ( talk => talk . id . value ) ) } , otherDayIds=${ JSON . stringify ( otherDayIds . map ( id => id . value ) ) } )` ) ;
102-
103- promisesQueue . addAll ( [ currentDayId , ...otherDayIds ] . map ( ( dayId ) => {
104- return async ( ) => {
105- const talkIds : TalkId [ ] | undefined = await match ( dayId === currentDayId )
106- . with ( true , async ( ) => {
107- currentTalks . forEach ( talk => {
108- loadTalkSpeakerUrls ( talk , promisesQueue ) ;
109- } )
110-
111- return currentTalks . map ( talk => talk . id ) ;
112- } ) . otherwise ( async ( ) => {
113- const dailyScheduleDoc = dailyScheduleDocument ( conferenceDescriptor , dayId )
114-
115- if ( navigator . onLine && dailyScheduleDoc ) {
116- const dailyScheduleSnapshot = await getDoc ( dailyScheduleDoc ) ;
117- PERF_LOGGER . debug ( `getDoc(${ dailyScheduleDoc . path } )` )
118-
119- return dailyScheduleSnapshot . data ( ) ?. timeSlots . reduce ( ( talkIds , timeslot ) => {
120- if ( timeslot . type === 'talks' ) {
121- timeslot . talks . forEach ( talk => {
122- loadTalkSpeakerUrls ( talk , promisesQueue ) ;
123-
124- talkIds . push ( new TalkId ( talk . id ) )
125- } )
126- }
127-
128- return talkIds ;
129- } , [ ] as Array < TalkId > ) || [ ] ;
130- } else {
131- return undefined ;
132- }
133- } )
134-
135- if ( navigator . onLine && talkIds ) {
136- // Removing talk ids duplicates (for instance, on overflows)
137- const uniqueTalkIds = Array . from (
138- new Set ( talkIds . map ( t => t . value ) )
139- ) . map ( rawTalkId => new TalkId ( rawTalkId ) ) ;
140-
141- if ( dayId !== currentDayId ) {
142- promisesQueue . add ( ( ) => prepareTalkStats ( conferenceDescriptor . id , dayId , uniqueTalkIds , promisesQueue ) , { priority : 100 } )
143- promisesQueue . add ( ( ) => prepareUserTalkNotes ( user , conferenceDescriptor . id , dayId , uniqueTalkIds , promisesQueue ) , { priority : 100 } ) ;
144- }
145-
146- promisesQueue . add ( ( ) => prepareEventTalks ( conferenceDescriptor , dayId , uniqueTalkIds , promisesQueue ) , { priority : 100 } ) ;
147- }
148- }
149- } ) , { priority : 1000 } ) ;
85+ promisesQueue . add ( ( ) =>
86+ checkCache ( `offlineSchedulePrep(eventId=${ conferenceDescriptor . id . value } )(currentDay (${ currentDayId . value } ))` ,
87+ Temporal . Duration . from ( { hours : 6 } ) , // Cache should be lower for current day than for other days
88+ async ( ) => {
89+ PERF_LOGGER . debug ( ( ) => `offlineSchedulePrep(eventId=${ conferenceDescriptor . id . value } )(currentDay (${ currentDayId . value } ))` )
90+ await prepareDailySchedule ( conferenceDescriptor , currentDayId , currentTalks , promisesQueue , 1000 ) ;
91+ } ) ,
92+ { priority : 1000 }
93+ ) ;
94+
95+ promisesQueue . addAll ( otherDayIds . map ( otherDayId => ( ) =>
96+ checkCache ( `offlineSchedulePrep(eventId=${ conferenceDescriptor . id . value } )(otherDay=${ currentDayId . value } )` ,
97+ Temporal . Duration . from ( { hours : 24 } ) , // Cache should be higher for other days than for current day
98+ async ( ) => {
99+ PERF_LOGGER . debug ( ( ) => `offlineSchedulePrep(eventId=${ conferenceDescriptor . id . value } )(otherDay=${ currentDayId . value } )` )
100+
101+ const maybeDailyScheduleDoc = dailyScheduleDocument ( conferenceDescriptor , otherDayId )
102+
103+ const otherDayTalks = await match ( [ navigator . onLine , maybeDailyScheduleDoc ] )
104+ . with ( [ true , P . nonNullable ] , async ( [ _ , dailyScheduleDoc ] ) => {
105+ const dailyScheduleSnapshot = await getDoc ( dailyScheduleDoc ) ;
106+ PERF_LOGGER . debug ( `getDoc(${ dailyScheduleDoc . path } )` )
107+
108+ return dailyScheduleSnapshot . data ( ) ?. timeSlots . reduce ( ( talks , timeslot ) => {
109+ if ( timeslot . type === 'talks' ) {
110+ timeslot . talks . forEach ( talk => {
111+ const voxxrinTalk = createVoxxrinTalkFromFirestore ( conferenceDescriptor , talk )
112+ talks . push ( voxxrinTalk ) ;
113+ } )
114+ }
115+
116+ return talks ;
117+ } , [ ] as Array < VoxxrinTalk > ) || [ ] ;
118+ } ) . otherwise ( async ( ) => [ ] as VoxxrinTalk [ ] ) ;
119+
120+ const dedupedOtherDayTalks = removeTalkOverflowsAndDuplicates ( otherDayTalks )
121+
122+ // For other days, we also need to prepare talks stats & notes given that it won't have been de-facto
123+ // pre-loaded by user navigation
124+ promisesQueue . add ( ( ) => prepareTalkStats ( conferenceDescriptor . id , otherDayId , dedupedOtherDayTalks , promisesQueue ) , { priority : 100 } )
125+ promisesQueue . add ( ( ) => prepareUserTalkNotes ( user , conferenceDescriptor . id , otherDayId , dedupedOtherDayTalks , promisesQueue ) , { priority : 100 } ) ;
126+
127+ await prepareDailySchedule ( conferenceDescriptor , otherDayId , otherDayTalks , promisesQueue , 100 ) ;
128+ } ) ) ,
129+ { priority : 100 }
130+ ) ;
150131}
151132
152133export type LabelledTimeslotWithFeedback = VoxxrinScheduleTimeSlot & {
0 commit comments