From 83604f5eaabb65d39c5d6aeb9d7e7617da36f257 Mon Sep 17 00:00:00 2001 From: Adolfo Reyna Date: Fri, 20 Feb 2026 20:52:26 -0500 Subject: [PATCH] Debug and fix courses watching progress resolution --- Views/Courses.js | 107 +++++++++++++++++++++++++++++++++----- components/Media.js | 12 +++-- components/VideoPlayer.js | 6 ++- 3 files changed, 106 insertions(+), 19 deletions(-) diff --git a/Views/Courses.js b/Views/Courses.js index 74b49f9..a5e1b79 100644 --- a/Views/Courses.js +++ b/Views/Courses.js @@ -8,6 +8,11 @@ import GlobalState from '../contexts/GlobalState.js'; import i18n from "../i18nMessages.js"; import AsyncStorage from '@react-native-async-storage/async-storage'; +const COURSES_LOG_PREFIX = '[Courses]'; +const logCourses = (...args) => { + if (__DEV__) console.log(COURSES_LOG_PREFIX, ...args); +}; + const emptyCoursesData = { courses: [], popular: [], @@ -17,15 +22,42 @@ const emptyCoursesData = { const getCourses = async (profileObj = {}) => { let courses = []; let popular = []; + logCourses('getCourses:start', { + viewerId: profileObj?._id || null, + hasViewerData: !!profileObj?.data, + }); await API.getCourses().then((data) => { const groups = Array.isArray(data?.groups) ? data.groups : []; courses = groups; popular = [...groups].sort((a, b) => { return Object.keys(b.subscribed).length - Object.keys(a.subscribed).length; }); + logCourses('getCourses:groups', { + groups: groups.length, + popular: popular.length, + }); }); let watching = {}; let watchingProms = []; + let watchingStats = { + rawEntries: 0, + explicitProfileId: 0, + fallbackByPost: 0, + skippedNoProgress: 0, + skippedNoProfileId: 0, + courseProfilesResolved: 0, + }; + const pushWatchingProgress = (profile, progress, profileId) => { + if (!profile?.isCourse) return; + if (!watching[profileId]) { + watching[profileId] = { profile, progress: [], mostRecent: 0 }; + } + if (watching[profileId].mostRecent < (progress?.ts || 0)) { + watching[profileId].mostRecent = progress.ts || 0; + } + watching[profileId].progress.push(progress); + watchingStats.courseProfilesResolved += 1; + }; let viewerData = {}; try { // Detach potential proxy/non-extensible objects before iterating keys. @@ -33,20 +65,44 @@ const getCourses = async (profileObj = {}) => { } catch (error) { viewerData = {}; } + const viewerKeys = Object.keys(viewerData); + logCourses('watching:viewerData', { + entries: viewerKeys.length, + sampleKeys: viewerKeys.slice(0, 5), + }); Object.keys(viewerData).forEach((videoId) => { + watchingStats.rawEntries += 1; const progress = viewerData[videoId]; - if (progress?.profileId) { - let profileId = progress.profileId; - watchingProms.push(API.getUserProfile(profileId).then(profile => { - if (!profile.isCourse) - return 0; - if (!watching[profileId]) - watching[profileId] = { profile, progress: [], mostRecent: 0 }; - if (watching[profileId].mostRecent < progress.ts) - watching[profileId].mostRecent = progress.ts; - watching[profileId].progress.push(progress); - })); + if (!progress) { + watchingStats.skippedNoProgress += 1; + return; } + + const explicitProfileId = progress.profileId || progress.profileid; + if (explicitProfileId) { + watchingStats.explicitProfileId += 1; + watchingProms.push(API.getUserProfile(explicitProfileId).then((profile) => { + pushWatchingProgress(profile, progress, explicitProfileId); + })); + return; + } + + // Backward compatibility: old progress entries may not include profileId. + const postId = progress.postId || videoId; + if (!postId) { + watchingStats.skippedNoProfileId += 1; + return; + } + watchingStats.fallbackByPost += 1; + watchingProms.push( + API.getPost(postId).then((post) => { + const fallbackProfileId = post?.profileid; + if (!fallbackProfileId) return 0; + return API.getUserProfile(fallbackProfileId).then((profile) => { + pushWatchingProgress(profile, progress, fallbackProfileId); + }); + }) + ); }); let watchingArray = []; await Promise.all(watchingProms).then(() => { @@ -57,6 +113,10 @@ const getCourses = async (profileObj = {}) => { return b.mostRecent - a.mostRecent; }); }); + logCourses('watching:resolved', { + ...watchingStats, + uniqueCourses: watchingArray.length, + }); return { courses: courses.slice(0, 10), popular: popular.slice(0, 10), @@ -97,14 +157,22 @@ const Courses = () => { let subscribed = true; const getData = async () => { const cached = await getCoursesCache(); - console.log("Courses Cache"); + logCourses('cache:read', { + courses: Array.isArray(cached?.courses) ? cached.courses.length : 0, + popular: Array.isArray(cached?.popular) ? cached.popular.length : 0, + watching: Array.isArray(cached?.watching) ? cached.watching.length : 0, + }); if (subscribed) { setGroups(Array.isArray(cached?.courses) ? cached.courses : []); setPopular(Array.isArray(cached?.popular) ? cached.popular : []); setWatching(Array.isArray(cached?.watching) ? cached.watching : []); } let r = await getCourses(viewer); - console.log("Courses Live"); + logCourses('live:resolved', { + courses: Array.isArray(r?.courses) ? r.courses.length : 0, + popular: Array.isArray(r?.popular) ? r.popular.length : 0, + watching: Array.isArray(r?.watching) ? r.watching.length : 0, + }); if(subscribed){ setGroups(r.courses || []); setPopular(r.popular || []); @@ -116,7 +184,7 @@ const Courses = () => { return () => { subscribed = false; } - }, []) + }, [viewer]) const onChangeSearch = query => { setSearchQuery(query); @@ -151,6 +219,17 @@ const Courses = () => { /> )); }; + + useEffect(() => { + logCourses('render', { + searchQueryLength: searchQuery.length, + groups: groups.length, + popular: popular.length, + watching: watching.length, + showWatching: searchQuery.length === 0 && watching.length > 0, + }); + }, [searchQuery, groups.length, popular.length, watching.length]); + return ( { const renderVideo = () => { if (videosFiles.length && !props.skiptVideo) { return loaded ? ( - + ) : ( setLoaded(true)}> @@ -123,7 +129,7 @@ let Media = (props) => { const renderHlsVideo = () => { if (hlsUrl && !props.skiptVideo) { return loaded ? ( - + ) : ( { GlobalState.currentMedia = hlsUrl; @@ -289,4 +295,4 @@ const styles = StyleSheet.create({ width: "100%", minHeight: 300, } -}); \ No newline at end of file +}); diff --git a/components/VideoPlayer.js b/components/VideoPlayer.js index 03915c6..1a81b68 100644 --- a/components/VideoPlayer.js +++ b/components/VideoPlayer.js @@ -43,7 +43,9 @@ const VideoPlayer = ({ videosFiles, postId, profileId, poster, videoUrl, videoSt postId: postId, profileId: profileId, }; - //console.log(postId, newData); + if (!GlobalState.me.data) GlobalState.me.data = {}; + // Keep local viewer progress in sync so Courses can render immediately. + GlobalState.me.data[postId] = newData; API.setDataValue(postId, newData); } @@ -74,4 +76,4 @@ const styles = StyleSheet.create({ width: 320, height: 200, }, -}); \ No newline at end of file +});