Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Monitor Decals pod #735

Draft
wants to merge 5 commits into
base: gql
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions apps/backend/src/modules/class/controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ClassModel, SectionModel } from "@repo/common";
import { ClassModel, DecalModel, SectionModel } from "@repo/common";

import { formatClass, formatSection } from "./formatter";
import { formatClass, formatDecalInfo, formatSection } from "./formatter";

export const getClass = async (
year: number,
Expand Down Expand Up @@ -75,3 +75,21 @@ export const getSection = async (

return formatSection(section);
};

export const isDecal = async (ccn: number) => {
const decal = await DecalModel.findOne({
"sections.ccn": ccn,
}).lean();

return !!decal;
};

export const getDecalInfo = async (ccn: number) => {
const decal = await DecalModel.findOne({
"sections.ccn": ccn,
}).lean();

if (!decal) return null;

return formatDecalInfo(decal);
};
109 changes: 72 additions & 37 deletions apps/backend/src/modules/class/formatter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ClassType, SectionType } from "@repo/common";
import { ClassType, DecalType, SectionType } from "@repo/common";

import {
ClassFinalExam,
Expand Down Expand Up @@ -51,6 +51,8 @@ export const formatClass = (_class: ClassType) => {
gradingBasis: _class.gradingBasis?.description as ClassGradingBasis,
finalExam: _class.finalExam?.code as ClassFinalExam,
title: _class.classTitle,
decal: false,
decalInfo: null,
unitsMax: _class.allowedUnits?.maximum as number,
unitsMin: _class.allowedUnits?.minimum as number,
} as IntermediateClass;
Expand Down Expand Up @@ -92,42 +94,47 @@ export const formatSection = (section: SectionType) => {
endDate: formatDate(section?.endDate),
startDate: formatDate(section?.startDate),

meetings: section.meetings?.map((m) => ({
days: [
m.meetsSunday,
m.meetsMonday,
m.meetsTuesday,
m.meetsWednesday,
m.meetsThursday,
m.meetsFriday,
m.meetsSaturday,
],

endDate: formatDate(m.endDate),
endTime: m.endTime,
location: m.location?.description,
startDate: formatDate(m.startDate),
startTime: m.startTime,

instructors: m?.assignedInstructors
?.filter(
(i) => i.printInScheduleOfClasses && i.instructor?.names != undefined
)
.map((i) => {
// Primary name has precedence over preferred name
let nameInfo = i.instructor?.names?.find(
(n) => n.type?.code === "PRI"
);
if (nameInfo == undefined) {
nameInfo = i.instructor?.names?.find((n) => n.type?.code === "PRF");
}

return {
givenName: nameInfo?.givenName as string,
familyName: nameInfo?.familyName as string,
};
}),
})),
meetings:
section.meetings?.map((m) => ({
days: [
m.meetsSunday,
m.meetsMonday,
m.meetsTuesday,
m.meetsWednesday,
m.meetsThursday,
m.meetsFriday,
m.meetsSaturday,
],

endDate: formatDate(m.endDate),
endTime: m.endTime,
location: m.location?.description,
startDate: formatDate(m.startDate),
startTime: m.startTime,

instructors:
m?.assignedInstructors
?.filter(
(i) =>
i.printInScheduleOfClasses && i.instructor?.names != undefined
)
.map((i) => {
// Primary name has precedence over preferred name
let nameInfo = i.instructor?.names?.find(
(n) => n.type?.code === "PRI"
);
if (nameInfo == undefined) {
nameInfo = i.instructor?.names?.find(
(n) => n.type?.code === "PRF"
);
}

return {
givenName: nameInfo?.givenName as string,
familyName: nameInfo?.familyName as string,
};
}) || [],
})) || [],

exams: section.exams?.map((e) => ({
date: formatDate(e.date),
Expand Down Expand Up @@ -157,3 +164,31 @@ export const formatSection = (section: SectionType) => {
})),
} as IntermediateSection;
};

export const formatDecalInfo = (decal: DecalType) => {
if (!decal) return null;

return {
id: String(decal.id) || "",
semester: decal.semester || "",
title: decal.title || "",
description: decal.description || "",
category: decal.category || "",
website: decal.website || "",
application: decal.application || "",
enroll: decal.enroll || "",
contact: decal.contact || "",
units: String(decal.units) || "",
sections:
decal.sections?.map((section) => ({
title: section.title || "",
size: section.size || 0,
facilitators: section.faciliators || "",
location: section.location || "",
time: section.time || "",
starts: section.starts || "",
status: section.status || "",
ccn: section.ccn || 0,
})) || [],
};
};
32 changes: 32 additions & 0 deletions apps/backend/src/modules/class/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import { getTerm } from "../term/controller";
import { TermModule } from "../term/generated-types/module-types";
import {
getClass,
getDecalInfo,
getPrimarySection,
getSecondarySections,
getSection,
isDecal,
} from "./controller";
import { IntermediateClass, IntermediateSection } from "./formatter";
import { ClassModule } from "./generated-types/module-types";
Expand Down Expand Up @@ -146,6 +148,36 @@ const resolvers: ClassModule.Resolvers = {

return gradeDistribution;
},

decal: async (parent: IntermediateClass | ClassModule.Class) => {
const primarySection = await getPrimarySection(
parent.year,
parent.semester,
parent.subject,
parent.courseNumber,
parent.number
);

if (!primarySection) return false;

return await isDecal(primarySection.ccn);
},

decalInfo: async (parent: IntermediateClass | ClassModule.Class) => {
const primarySection = await getPrimarySection(
parent.year,
parent.semester,
parent.subject,
parent.courseNumber,
parent.number
);

if (!primarySection || !(await isDecal(primarySection.ccn))) {
return null as any;
}

return await getDecalInfo(primarySection.ccn);
},
},

Section: {
Expand Down
26 changes: 26 additions & 0 deletions apps/backend/src/modules/class/typedefs/class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,30 @@ export default gql`
): Section
}

type DecalSection {
title: String
size: Int
location: String
time: String
starts: String
status: String
ccn: Int
}

type DecalInfo {
id: Int
semester: String
title: String
description: String
category: String
website: String
application: String
enroll: String
contact: String
units: String
sections: [DecalSection]
}

type Class {
"Identifiers"
subject: String!
Expand All @@ -44,6 +68,8 @@ export default gql`
title: String
unitsMax: Float!
unitsMin: Float!
decal: Boolean!
decalInfo: DecalInfo
}

enum ClassFinalExam {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,20 @@
.heading {
font-weight: 660;
font-feature-settings: "cv05" on, "cv13" on, "ss07" on, "cv12" on, "cv06" on;

.decalTag {
display: inline-flex;
align-items: center;
padding: 4px 12px;
margin-left: 8px;
border-radius: 100px;
background-color: var(--blue-50, #E6F3FF); // Using system color if available
color: var(--blue-500, #2196F3); // Using system color if available
font-size: 14px;
font-weight: 500;
font-feature-settings: normal; // Reset inherited feature settings
line-height: 1;
}
}

.title {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const Course = forwardRef<HTMLDivElement, ClassProps & IClass>(
primarySection: { enrollCount, enrollMax, waitlistCount, waitlistMax },
unitsMax,
unitsMin,
decal,
index,
onClick,
},
Expand All @@ -43,6 +44,7 @@ const Course = forwardRef<HTMLDivElement, ClassProps & IClass>(
<div className={styles.text}>
<p className={styles.heading}>
{subject} {courseNumber} #{number}
{decal && <span className={styles.decalTag}>Decal</span>}
</p>
<p className={styles.description}>{title ?? courseTitle}</p>
<div className={styles.row}>
Expand Down
27 changes: 27 additions & 0 deletions apps/frontend/src/lib/api/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,30 @@ export interface IMeeting {
instructors: IInstructor[];
}

export interface IClassDecalSection {
title: string;
size: number;
location: string;
time: string;
starts: string;
status: string;
ccn: number;
}

export interface IClassDecalInfo {
id: number;
semester: string;
title: string;
description: string;
category: string;
website: string;
application: string;
enroll: string;
contact: string;
units: string;
sections: IClassDecalSection[];
}

export interface IClass {
// Identifiers
year: number;
Expand All @@ -204,6 +228,8 @@ export interface IClass {
title: string | null;
unitsMax: number;
unitsMin: number;
decal: boolean;
decalInfo: IClassDecalInfo | null;
}

export interface ReadClassResponse {
Expand Down Expand Up @@ -334,6 +360,7 @@ export const GET_CATALOG = gql`
unitsMin
finalExam
gradingBasis
decal
primarySection {
component
online
Expand Down
40 changes: 40 additions & 0 deletions apps/frontend/src/lib/api/courses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,43 @@ export const GET_COURSES = gql`
}
}
`;

export interface GetClassesResponse {
catalog: ICourse[];
}

export const GET_CLASSES = gql`
query GetClasses($year: Int!, $semester: Semester!) {
catalog(year: $year, semester: $semester) {
subject
number
title
gradeDistribution {
average
}
academicCareer
classes {
subject
courseNumber
number
title
unitsMax
unitsMin
finalExam
gradingBasis
primarySection {
component
online
open
enrollCount
enrollMax
waitlistCount
waitlistMax
meetings {
days
}
}
}
}
}
`;
Loading