Files
EMI-ExpoAPP/Views/Courses.js
2023-03-10 19:41:30 -06:00

208 lines
7.0 KiB
JavaScript

import React, { useEffect } from "react";
import { Searchbar, Title } from 'react-native-paper';
import { ScrollView, ActivityIndicator, StyleSheet, SafeAreaView, FlatList, View } from 'react-native';
import API from "../API";
import CourseCard from "../components/CourseCard";
import { useSnapshot } from 'valtio';
import GlobalState from '../contexts/GlobalState.js';
import i18n from "../i18nMessages.js";
const getCourses = async (profileObj) => {
let courses;
let popular;
await API.getCourses().then((data) => {
courses = data.groups;
popular = [...data.groups].sort((a, b) => {
return Object.keys(b.subscribed).length - Object.keys(a.subscribed).length;
});
});
let watching = {};
let watchingProms = [];
Object.keys(profileObj.data).forEach((videoId) => {
if (profileObj.data[videoId].profileId) {
let profileId = profileObj.data[videoId].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 < profileObj.data[videoId].ts)
watching[profileId].mostRecent = profileObj.data[videoId].ts;
watching[profileId].progress.push(profileObj.data[videoId]);
}));
}
});
let watchingArray = [];
await Promise.all(watchingProms).then(() => {
for (const courseId in watching) {
watchingArray.push(watching[courseId]);
}
watchingArray = watchingArray.sort((a, b) => {
return b.mostRecent - a.mostRecent;
});
});
return {
courses: courses.slice(0, 10),
popular: popular.slice(0, 10),
watching: watchingArray.slice(0, 10),
}
}
const storeCoursesCache = async (value) => {
try {
const jsonValue = JSON.stringify(value)
await AsyncStorage.setItem('courses', jsonValue)
} catch (e) {
}
}
const getCoursesCache = async () => {
try {
const value = await AsyncStorage.getItem('courses')
if (value !== null) {
return JSON.parse(value);
}
} catch (e) {
return []
}
}
const Courses = () => {
const gState = useSnapshot(GlobalState);
const viewer = gState.me;
const [searchQuery, setSearchQuery] = React.useState('');
const [groups, setGroups] = React.useState([]);
const [popular, setPopular] = React.useState([]);
const [watching, setWatching] = React.useState([]);
const [queryTimer, setQueryTimer] = React.useState(0);
useEffect(() => {
let subscribed = true;
const getData = async () => {
await getCoursesCache().then((r) => {
console.log("Courses Cache");
setGroups(r.courses || []);
setPopular(r.popular || []);
setWatching(r.watching || []);
});
let r = await getCourses(viewer);
console.log("Courses Live");
if(subscribed){
setGroups(r.courses || []);
setPopular(r.popular || []);
setWatching(r.watching || []);
}
storeCoursesCache(r);
};
getData();
return () => {
subscribed = false;
}
}, [])
const onChangeSearch = query => {
setSearchQuery(query);
if (queryTimer) clearTimeout(queryTimer);
let timerId = setTimeout(() => {
if (!query) {
return API.getCourses('').then((data) => {
setGroups(data.groups || []);
});
}
API.searchCourses(query).then((data) => {
setGroups(data.groups || []);
})
}, 300);
setQueryTimer(timerId);
};
const renderProfile = (({ item }) => {
return (<CourseCard profileObj={item} />);
});
const watchingCourse = (({ item }) => {
return (<CourseCard profileObj={item.profile} />);
});
const renderCoursesQuery = (({ item }) => {
return (<CourseCard profileObj={item} twoCols={true}/>);
});
return (
<SafeAreaView style={styles.container}>
<Searchbar
placeholder = {i18n.t("message.searchCourses")}
onChangeText={onChangeSearch}
value={searchQuery}
/>
{groups.length ? <></> : <ActivityIndicator />}
<ScrollView>
{
(searchQuery.length === 0 && watching.length) ?
<View>
<Title style={styles.title} >{i18n.t("message.continueWatching")}:</Title>
<FlatList
horizontal={true}
data={watching}
renderItem={watchingCourse}
keyExtractor={item => item.profile._id}
initialNumToRender={2}
/>
</View> : <></>
}
{
(searchQuery.length === 0 && groups.length) ?
<>
<Title style={styles.title} >{i18n.t("message.recentlyAdded")}:</Title>
<FlatList
horizontal={true}
data={groups}
renderItem={renderProfile}
keyExtractor={item => item._id}
initialNumToRender={2}
/>
</> : <></>
}
{
(searchQuery.length === 0 && popular.length) ?
<>
<Title style={styles.title} >{i18n.t("message.popularCourses")}:</Title>
<FlatList
horizontal={true}
data={popular}
renderItem={renderProfile}
keyExtractor={item => item._id}
initialNumToRender={2}
/>
</> : <></>
}
{
(searchQuery.length !== 0 && groups.length) ?
<>
<FlatList
//horizontal={true}
data={groups}
numColumns={2}
renderItem={renderCoursesQuery}
keyExtractor={item => item._id}
initialNumToRender={8}
/>
</> : <></>
}
</ScrollView>
</SafeAreaView>
)
}
export default Courses;
const styles = StyleSheet.create({
container: {
flex: 1
},
title: {
padding: 10,
fontSize: 30,
marginTop: 15,
fontWeight: "bold",
color: "#777"
}
});