|
1 |
| -import { type Component, Show, createMemo } from "solid-js"; |
| 1 | +import { type Component, For, createMemo } from "solid-js"; |
2 | 2 |
|
3 | 3 | import { ChevronDownIcon } from "lucide-solid";
|
| 4 | +import { HStack } from "styled-system/jsx"; |
| 5 | +import Class from "~/components/Class"; |
4 | 6 | import { Accordion } from "~/components/ui/accordion";
|
| 7 | +import { Text } from "~/components/ui/text"; |
5 | 8 |
|
6 | 9 | import { useCourseDataContext } from "~/context/create";
|
7 | 10 | import type {
|
8 | 11 | SelectedSubjects,
|
9 | 12 | SimplifiedSelectedSubjects,
|
| 13 | + Subject, |
| 14 | + SubjectFull, |
10 | 15 | } from "~/context/types";
|
11 | 16 |
|
12 | 17 | const Semester: Component<{
|
13 | 18 | selectedSubjects: SimplifiedSelectedSubjects;
|
14 |
| - semesterSubjects: Array<SelectedSubjects>; |
| 19 | + semesterSubjects: SelectedSubjects[]; |
15 | 20 | index: number;
|
16 | 21 | roadID: string;
|
17 | 22 | isOpen: boolean;
|
@@ -54,19 +59,110 @@ const Semester: Component<{
|
54 | 59 | : "";
|
55 | 60 | });
|
56 | 61 |
|
| 62 | + // TODO: copied from courseroad 2, see what's actually needed |
| 63 | + const semesterInformation = createMemo(() => { |
| 64 | + const classesInfo = props.semesterSubjects |
| 65 | + .map((subj) => { |
| 66 | + if (subj.public === false) { |
| 67 | + return Object.assign({}, subj, { |
| 68 | + total_units: subj.units, |
| 69 | + }); |
| 70 | + } |
| 71 | + if (subj.subject_id in store.subjectsIndex) { |
| 72 | + return store.subjectsInfo[store.subjectsIndex[subj.subject_id]]; |
| 73 | + } |
| 74 | + if (subj.subject_id in store.genericIndex) { |
| 75 | + return store.genericCourses[store.genericIndex[subj.subject_id]]; |
| 76 | + } |
| 77 | + return undefined; |
| 78 | + }) |
| 79 | + .filter((subj) => subj !== undefined); |
| 80 | + const totalUnits = classesInfo.reduce((units, subj) => { |
| 81 | + let tu = subj.total_units; |
| 82 | + tu = Number.isNaN(tu) ? 0 : tu; |
| 83 | + return units + tu; |
| 84 | + }, 0); |
| 85 | + const expectedHours = (subj: SubjectFull) => { |
| 86 | + let hours = |
| 87 | + (subj.in_class_hours ?? Number.NaN) + |
| 88 | + (subj.out_of_class_hours ?? Number.NaN); |
| 89 | + hours = Number.isNaN(hours) ? subj.total_units : hours; |
| 90 | + hours = Number.isNaN(hours) ? 0 : hours; |
| 91 | + return { |
| 92 | + hours, |
| 93 | + subject_id: subj.subject_id, |
| 94 | + }; |
| 95 | + }; |
| 96 | + const sumExpectedHours = (hours: number, subj: { hours: number }) => |
| 97 | + hours + subj.hours; |
| 98 | + const isInQuarter = (subj: Subject, quarter: number) => |
| 99 | + subj.quarter_information === undefined || |
| 100 | + Number.parseInt(subj.quarter_information.split(",")[0]) === quarter; |
| 101 | + const expectedHoursQuarter1 = classesInfo |
| 102 | + .filter((s) => isInQuarter(s, 0)) |
| 103 | + .map(expectedHours); |
| 104 | + const totalExpectedHoursQuarter1 = expectedHoursQuarter1.reduce( |
| 105 | + sumExpectedHours, |
| 106 | + 0, |
| 107 | + ); |
| 108 | + const expectedHoursQuarter2 = classesInfo |
| 109 | + .filter((s) => isInQuarter(s, 1)) |
| 110 | + .map(expectedHours); |
| 111 | + const totalExpectedHoursQuarter2 = expectedHoursQuarter2.reduce( |
| 112 | + sumExpectedHours, |
| 113 | + 0, |
| 114 | + ); |
| 115 | + const totalExpectedHours = Math.max( |
| 116 | + totalExpectedHoursQuarter1, |
| 117 | + totalExpectedHoursQuarter2, |
| 118 | + ); |
| 119 | + const anyClassInSingleQuarter = classesInfo.some( |
| 120 | + (s) => s.quarter_information !== undefined, |
| 121 | + ); |
| 122 | + |
| 123 | + return { |
| 124 | + totalUnits, |
| 125 | + totalExpectedHours, |
| 126 | + anyClassInSingleQuarter, |
| 127 | + expectedHoursQuarter1, |
| 128 | + expectedHoursQuarter2, |
| 129 | + totalExpectedHoursQuarter1, |
| 130 | + totalExpectedHoursQuarter2, |
| 131 | + }; |
| 132 | + }); |
| 133 | + |
57 | 134 | return (
|
58 | 135 | <Accordion.Item
|
59 | 136 | value={props.index.toString()}
|
60 | 137 | hidden={store.hideIAP && semesterType() === "IAP"}
|
61 | 138 | >
|
62 | 139 | <Accordion.ItemTrigger>
|
63 |
| - {semesterYearName()} {semesterType()} {semesterYearRendered()} |
| 140 | + <HStack gap={6}> |
| 141 | + <Text width="12em"> |
| 142 | + {semesterYearName()} {semesterType()} {semesterYearRendered()} |
| 143 | + </Text> |
| 144 | + <Text minWidth="4.5em" fontSize="sm"> |
| 145 | + Units: {semesterInformation().totalUnits} |
| 146 | + </Text> |
| 147 | + <Text fontSize="sm"> |
| 148 | + Hours: {semesterInformation().totalExpectedHours.toFixed(1)} |
| 149 | + </Text> |
| 150 | + </HStack> |
64 | 151 | <Accordion.ItemIndicator>
|
65 | 152 | <ChevronDownIcon />
|
66 | 153 | </Accordion.ItemIndicator>
|
67 | 154 | </Accordion.ItemTrigger>
|
68 |
| - <Accordion.ItemContent> |
69 |
| - Showing semester {props.index} for {props.roadID} |
| 155 | + <Accordion.ItemContent justifyContent="center" display="flex"> |
| 156 | + <For each={props.semesterSubjects}> |
| 157 | + {(subj, index) => ( |
| 158 | + <Class |
| 159 | + classInfo={subj} |
| 160 | + semesterIndex={props.index} |
| 161 | + // warnings={warnings()[props.index]} |
| 162 | + classIndex={index()} |
| 163 | + /> |
| 164 | + )} |
| 165 | + </For> |
70 | 166 | </Accordion.ItemContent>
|
71 | 167 | </Accordion.Item>
|
72 | 168 | );
|
|
0 commit comments