Display empty courses in new class table

This commit is contained in:
Tanner Collin 2022-04-26 03:06:51 +00:00
parent b400d010e0
commit 667887c06c
4 changed files with 58 additions and 9 deletions

View File

@ -234,6 +234,8 @@ class CardViewSet(Base, Create, Retrieve, Update, Destroy):
utils_stats.changed_card() 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): class CourseViewSet(Base, List, Retrieve, Create, Update):
permission_classes = [AllowMetadata | IsAuthenticatedOrReadOnly, IsAdminOrReadOnly | IsInstructorOrReadOnly] permission_classes = [AllowMetadata | IsAuthenticatedOrReadOnly, IsAdminOrReadOnly | IsInstructorOrReadOnly]
queryset = models.Course.objects.annotate(date=Max('sessions__datetime')).order_by('-date') queryset = models.Course.objects.annotate(date=Max('sessions__datetime')).order_by('-date')

View File

@ -6,6 +6,7 @@ import moment from 'moment-timezone';
import { apiUrl, isAdmin, isInstructor, getInstructor, BasicTable, requester } from './utils.js'; import { apiUrl, isAdmin, isInstructor, getInstructor, BasicTable, requester } from './utils.js';
import { NotFound, PleaseLogin } from './Misc.js'; import { NotFound, PleaseLogin } from './Misc.js';
import { InstructorClassDetail, InstructorClassAttendance } from './InstructorClasses.js'; import { InstructorClassDetail, InstructorClassAttendance } from './InstructorClasses.js';
import { courseCache } from './Courses.js';
import { PayPalPayNow } from './PayPal.js'; import { PayPalPayNow } from './PayPal.js';
import { tags } from './Courses.js'; import { tags } from './Courses.js';
@ -61,9 +62,10 @@ function ClassTable(props) {
}; };
function NewClassTable(props) { function NewClassTable(props) {
const { classes } = props; const { classes, courses } = props;
let sortedClasses = []; let sortedClasses = [];
let seenCourseIds = [];
if (classes.length) { if (classes.length) {
for (const clazz of classes) { for (const clazz of classes) {
const course_data = clazz.course_data; const course_data = clazz.course_data;
@ -76,6 +78,9 @@ function NewClassTable(props) {
course: course_data, course: course_data,
classes: [clazz], classes: [clazz],
}); });
seenCourseIds.push(
course_data.id
);
} }
} }
} }
@ -84,17 +89,17 @@ function NewClassTable(props) {
return ( return (
<> <>
<div style={{ margin: '0 -1.5rem 0 -0.5rem', display: 'flex', flexWrap: 'wrap' }}> <div className='newclasstable'>
{sortedClasses.map(x => {sortedClasses.map(x =>
<Segment style={{ margin: '1rem 1rem 0 0', width: '22rem' }}> <Segment style={{ margin: '1rem 1rem 0 0', width: '22rem' }}>
<Header size='medium'> <Header size='small'>
<Link to={'/courses/'+x.course.id}> <Link to={'/courses/'+x.course.id}>
{x.course.name} {x.course.name}
</Link> </Link>
</Header> </Header>
{!!x.course.tags && x.course.tags.split(',').map(name => {!!x.course.tags && x.course.tags.split(',').map(name =>
<Label color={tags[name]} tag> <Label color={tags[name]} tag size='small'>
{name} {name}
</Label> </Label>
)} )}
@ -136,6 +141,22 @@ function NewClassTable(props) {
</Table> </Table>
</Segment> </Segment>
)} )}
{courses.filter(x => !seenCourseIds.includes(x.id)).map(x =>
<Segment style={{ margin: '1rem 1rem 0 0', width: '22rem' }}>
<Header size='small'>
<Link to={'/courses/'+x.id}>
{x.name}
</Link>
</Header>
{!!x.tags && x.tags.split(',').map(name =>
<Label color={tags[name]} tag>
{name}
</Label>
)}
</Segment>
)}
</div> </div>
</> </>
); );
@ -184,10 +205,22 @@ export function ClassFeed(props) {
export function Classes(props) { export function Classes(props) {
const [classes, setClasses] = useState(classesCache); const [classes, setClasses] = useState(classesCache);
const [courses, setCourses] = useState(courseCache);
const [sortByCourse, setSortByCourse] = useState(sortCache); const [sortByCourse, setSortByCourse] = useState(sortCache);
const [tagFilter, setTagFilter] = useState(tagFilterCache); const [tagFilter, setTagFilter] = useState(tagFilterCache);
const { token, user } = props; const { token, user } = props;
useEffect(() => {
requester('/courses/', 'GET', token)
.then(res => {
setCourses(res.results);
courseCache = res.results;
})
.catch(err => {
console.log(err);
});
}, []);
useEffect(() => { useEffect(() => {
requester('/sessions/', 'GET', token) requester('/sessions/', 'GET', token)
.then(res => { .then(res => {
@ -201,7 +234,8 @@ export function Classes(props) {
const byTeaching = (x) => x.instructor_id === user.member.id; const byTeaching = (x) => x.instructor_id === user.member.id;
const byDate = (a, b) => a.datetime > b.datetime ? 1 : -1; 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 ( return (
<Container> <Container>
@ -268,11 +302,14 @@ export function Classes(props) {
</p> </p>
{classes.length ? {classes.length && courses.length ?
sortByCourse ? sortByCourse ?
<NewClassTable classes={classes.filter(byTag)} /> <NewClassTable
classes={classes.filter(classesByTag)}
courses={courses.filter(coursesByTag)}
/>
: :
<ClassTable classes={classes.slice().filter(byTag).sort(byDate)} /> <ClassTable classes={classes.slice().filter(classesByTag).sort(byDate)} />
: :
<p>Loading...</p> <p>Loading...</p>
} }

View File

@ -24,7 +24,7 @@ export const tags = {
Misc: 'grey', Misc: 'grey',
}; };
let courseCache = false; export let courseCache = false;
let tagFilterCache = false; let tagFilterCache = false;
export function Courses(props) { export function Courses(props) {

View File

@ -132,6 +132,16 @@ body {
.coursetags .ui.tag.label { .coursetags .ui.tag.label {
margin-top: 1rem; 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 { .usage {
height: 100vh; height: 100vh;