From 6ed5bc74a250623924e2aa1082fd4e7127605629 Mon Sep 17 00:00:00 2001 From: Mahin Bharathwaj Date: Fri, 7 Aug 2026 14:10:39 -0700 Subject: [PATCH 1/2] Handle disabled classes API --- src/routes/dashboard/classes.tsx | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/routes/dashboard/classes.tsx b/src/routes/dashboard/classes.tsx index 1274d5c..0728fde 100644 --- a/src/routes/dashboard/classes.tsx +++ b/src/routes/dashboard/classes.tsx @@ -10,6 +10,8 @@ function formatWeekends(weekends: string): string { } const ClassTile: Component<{ class: any }, {}> = function() { + const teachers = Array.isArray(this.class.teachers) ? this.class.teachers : []; + this.css = ` h2 { margin: 0; @@ -22,16 +24,17 @@ const ClassTile: Component<{ class: any }, {}> = function() {

{this.class.title}

{this.class.sourcedId}
Class size: {this.class.classSize}
- {this.class.teachers.map((x: any) => { return
Teacher: {x.givenName} {x.familyName} ({x.sourcedId})
; })} + {teachers.map((x: any) => { return
Teacher: {x.givenName} {x.familyName} ({x.sourcedId})
; })} ); } -export const Classes: Component<{ loaded: boolean, error: Error | undefined, }, { disabled: boolean, schoolyear: any, classes: any }> = function() { +export const Classes: Component<{ loaded: boolean, error: Error | undefined, }, { disabled: boolean, notice: string, schoolyear: any, classes: any[] }> = function() { this.loaded = false; this.error = undefined; this.disabled = false; + this.notice = ""; this.schoolyear = { startHour: 0, endHour: 0, weekend: "" }; this.classes = []; @@ -45,9 +48,18 @@ export const Classes: Component<{ loaded: boolean, error: Error | undefined, }, const backpack = await fetchBearer("https://nodeapi.classlink.com/tenant/customization/backpack").then(r => r.json()); this.disabled = backpack.enableStudentbackpack !== "1"; + if (this.disabled) this.notice = "Your admin has disabled viewing of classes data."; this.schoolyear = await fetchGws("https://analytics-data.classlink.io/teacherConsole/v1p0/schoolyear").then(r => r.json()); - this.classes = await fetchBearer("https://myclasses.apis.classlink.com/v1/classes").then(r => r.json()); + const classes = await fetchBearer("https://myclasses.apis.classlink.com/v1/classes").then(r => r.json()); + if (Array.isArray(classes)) { + this.classes = classes; + } else if (classes?.code === "MYCLASSES_DISABLED" || classes?.statusCode === 403) { + this.disabled = true; + this.notice = classes.message || "My Classes is disabled for this district."; + } else { + throw new Error(classes?.message || "ClassLink returned an invalid classes response."); + } this.loaded = true; } catch (error) { @@ -67,7 +79,7 @@ export const Classes: Component<{ loaded: boolean, error: Error | undefined, },
!x)} error={use(this.error)}>

Classes

- {$if(use(this.disabled),

Your admin has disabled viewing of classes data. The APIs are still accessible however.

)} + {$if(use(this.notice, x => !!x),

{use(this.notice)}

)}

School year: {use(this.schoolyear, x => x.Year)} ({use(this.schoolyear, x => x.startDate)} to {use(this.schoolyear, x => x.endDate)}) {use(this.schoolyear, x => x.startHour.toString().padStart(2, "0"))}:00-{use(this.schoolyear, x => x.endHour.toString().padStart(2, "0"))}:00, weekends on {use(this.schoolyear, x => formatWeekends(x.weekend))}

From 5c14bb1f40562ded5e2b60131af8b6d4f6d99a8c Mon Sep 17 00:00:00 2001 From: Mahin Bharathwaj Date: Fri, 7 Aug 2026 14:50:08 -0700 Subject: [PATCH 2/2] Stop disabled class requests and fix API test --- src/routes/dashboard/classes.tsx | 31 +++++++++++++++++++++++-------- src/routes/dashboard/settings.tsx | 2 +- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/routes/dashboard/classes.tsx b/src/routes/dashboard/classes.tsx index 0728fde..44c5f55 100644 --- a/src/routes/dashboard/classes.tsx +++ b/src/routes/dashboard/classes.tsx @@ -48,10 +48,23 @@ export const Classes: Component<{ loaded: boolean, error: Error | undefined, }, const backpack = await fetchBearer("https://nodeapi.classlink.com/tenant/customization/backpack").then(r => r.json()); this.disabled = backpack.enableStudentbackpack !== "1"; - if (this.disabled) this.notice = "Your admin has disabled viewing of classes data."; + if (this.disabled) { + this.notice = "Your admin has disabled viewing of classes data."; + this.loaded = true; + return; + } this.schoolyear = await fetchGws("https://analytics-data.classlink.io/teacherConsole/v1p0/schoolyear").then(r => r.json()); - const classes = await fetchBearer("https://myclasses.apis.classlink.com/v1/classes").then(r => r.json()); + const classesResponse = await fetchBearer("https://myclasses.apis.classlink.com/v1/classes"); + if (classesResponse.status === 403) { + this.disabled = true; + this.notice = "My Classes is disabled for this district."; + this.loaded = true; + return; + } + if (!classesResponse.ok) throw new Error(`ClassLink returned HTTP ${classesResponse.status}.`); + + const classes = await classesResponse.json(); if (Array.isArray(classes)) { this.classes = classes; } else if (classes?.code === "MYCLASSES_DISABLED" || classes?.statusCode === 403) { @@ -80,12 +93,14 @@ export const Classes: Component<{ loaded: boolean, error: Error | undefined, }, !x)} error={use(this.error)}>

Classes

{$if(use(this.notice, x => !!x),

{use(this.notice)}

)} -

- School year: {use(this.schoolyear, x => x.Year)} ({use(this.schoolyear, x => x.startDate)} to {use(this.schoolyear, x => x.endDate)}) {use(this.schoolyear, x => x.startHour.toString().padStart(2, "0"))}:00-{use(this.schoolyear, x => x.endHour.toString().padStart(2, "0"))}:00, weekends on {use(this.schoolyear, x => formatWeekends(x.weekend))} -

-
- {use(this.classes, x => x.map((x: any) => { return }))} -
+ {$if(use(this.disabled, x => !x),
+

+ School year: {use(this.schoolyear, x => x.Year)} ({use(this.schoolyear, x => x.startDate)} to {use(this.schoolyear, x => x.endDate)}) {use(this.schoolyear, x => x.startHour.toString().padStart(2, "0"))}:00-{use(this.schoolyear, x => x.endHour.toString().padStart(2, "0"))}:00, weekends on {use(this.schoolyear, x => formatWeekends(x.weekend))} +

+
+ {use(this.classes, x => x.map((x: any) => { return }))} +
+
)}
); diff --git a/src/routes/dashboard/settings.tsx b/src/routes/dashboard/settings.tsx index 66d2753..08e43d6 100644 --- a/src/routes/dashboard/settings.tsx +++ b/src/routes/dashboard/settings.tsx @@ -55,7 +55,7 @@ const WispTestCard: Component<{}, { res: Response | undefined, body: string | un this.body = undefined; this.error = undefined; try { - this.res = await fetch("http://applications.apis.classlink.com"); + this.res = await fetch("https://applications.apis.classlink.com"); this.body = await this.res?.text(); } catch (err) { this.error = "" + err;