diff --git a/apiserver/apiserver/api/views.py b/apiserver/apiserver/api/views.py index 91ae185..6396ffd 100644 --- a/apiserver/apiserver/api/views.py +++ b/apiserver/apiserver/api/views.py @@ -234,6 +234,8 @@ class CardViewSet(Base, Create, Retrieve, Update, Destroy): utils_stats.changed_card() +# TODO: return nested list of sessions, limited with Prefetch: +# https://stackoverflow.com/a/58689019 class CourseViewSet(Base, List, Retrieve, Create, Update): permission_classes = [AllowMetadata | IsAuthenticatedOrReadOnly, IsAdminOrReadOnly | IsInstructorOrReadOnly] queryset = models.Course.objects.annotate(date=Max('sessions__datetime')).order_by('-date') diff --git a/webclient/src/Classes.js b/webclient/src/Classes.js index 13aff8c..7d38f44 100644 --- a/webclient/src/Classes.js +++ b/webclient/src/Classes.js @@ -6,6 +6,7 @@ import moment from 'moment-timezone'; import { apiUrl, isAdmin, isInstructor, getInstructor, BasicTable, requester } from './utils.js'; import { NotFound, PleaseLogin } from './Misc.js'; import { InstructorClassDetail, InstructorClassAttendance } from './InstructorClasses.js'; +import { courseCache } from './Courses.js'; import { PayPalPayNow } from './PayPal.js'; import { tags } from './Courses.js'; @@ -61,9 +62,10 @@ function ClassTable(props) { }; function NewClassTable(props) { - const { classes } = props; + const { classes, courses } = props; let sortedClasses = []; + let seenCourseIds = []; if (classes.length) { for (const clazz of classes) { const course_data = clazz.course_data; @@ -76,6 +78,9 @@ function NewClassTable(props) { course: course_data, classes: [clazz], }); + seenCourseIds.push( + course_data.id + ); } } } @@ -84,17 +89,17 @@ function NewClassTable(props) { return ( <> -
+
{sortedClasses.map(x => -
+
{x.course.name}
{!!x.course.tags && x.course.tags.split(',').map(name => -
); @@ -184,10 +205,22 @@ export function ClassFeed(props) { export function Classes(props) { const [classes, setClasses] = useState(classesCache); + const [courses, setCourses] = useState(courseCache); const [sortByCourse, setSortByCourse] = useState(sortCache); const [tagFilter, setTagFilter] = useState(tagFilterCache); const { token, user } = props; + useEffect(() => { + requester('/courses/', 'GET', token) + .then(res => { + setCourses(res.results); + courseCache = res.results; + }) + .catch(err => { + console.log(err); + }); + }, []); + useEffect(() => { requester('/sessions/', 'GET', token) .then(res => { @@ -201,7 +234,8 @@ export function Classes(props) { const byTeaching = (x) => x.instructor_id === user.member.id; const byDate = (a, b) => a.datetime > b.datetime ? 1 : -1; - const byTag = (x) => tagFilter ? x.course_data.tags.includes(tagFilter) : true; + const classesByTag = (x) => tagFilter ? x.course_data.tags.includes(tagFilter) : true; + const coursesByTag = (x) => tagFilter ? x.tags.includes(tagFilter) : true; return ( @@ -268,11 +302,14 @@ export function Classes(props) {

- {classes.length ? + {classes.length && courses.length ? sortByCourse ? - + : - + :

Loading...

} diff --git a/webclient/src/Courses.js b/webclient/src/Courses.js index fd226c2..e664abd 100644 --- a/webclient/src/Courses.js +++ b/webclient/src/Courses.js @@ -24,7 +24,7 @@ export const tags = { Misc: 'grey', }; -let courseCache = false; +export let courseCache = false; let tagFilterCache = false; export function Courses(props) { diff --git a/webclient/src/light.css b/webclient/src/light.css index 695a4b9..1761e1f 100644 --- a/webclient/src/light.css +++ b/webclient/src/light.css @@ -132,6 +132,16 @@ body { .coursetags .ui.tag.label { margin-top: 1rem; } +.newclasstable { + margin: 0 -1.5rem 0 -0.5rem; + display: flex; + flex-wrap: wrap; +} + +.newclasstable .ui.tag.label { + padding-left: 1rem; + padding-right: 0.5rem; +} .usage { height: 100vh;