Skip to content

feat: added courses loading skeleton#1608

Open
dsnsgithub wants to merge 8 commits intomainfrom
fix/distinguish-loading-state
Open

feat: added courses loading skeleton#1608
dsnsgithub wants to merge 8 commits intomainfrom
fix/distinguish-loading-state

Conversation

@dsnsgithub
Copy link
Copy Markdown
Member

@dsnsgithub dsnsgithub commented Apr 13, 2026

Summary

Distinguish loading state from empty state through a loading skeleton.

Screen.Recording.2026-04-13.at.1.39.15.AM.mov

Test Plan

  1. Load a schedule
  2. Check added pane

If there is no data, it assumes 3 courses.
If the user has loaded a schedule in the past, it remembers how many courses/sections the user has to reconstruct a more accurate skeleton.

Issues

Fixes inability to distinguish loading state from empty state.
chrome-capture-2026-4-12
(from Kevin)

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 4 files

@KevinWu098
Copy link
Copy Markdown
Member

How's progress here?

@dsnsgithub
Copy link
Copy Markdown
Member Author

dsnsgithub commented Apr 19, 2026

How's progress here?

I modified the colors of the calendar and course loading skeleton to be slightly lighter, so it should be ready for review.

@dsnsgithub dsnsgithub requested a review from KevinWu098 April 19, 2026 22:52
Copy link
Copy Markdown
Member

@KevinWu098 KevinWu098 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A handful of comments — feature looks good, but just hoping to flesh out the implementation a bit more


return {
color: '#6d6d6d',
color: '#8d8d8d',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: sorry to nit again. is there any chance this could come from the MUI theme? is the default skeleton style not valid here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would likely have to modify the existing calendar skeleton loading animation to match MUI skeleton, as the existing calendar skeleton doesn't actually use the MUI skeleton component. Instead, it uses the existing calendar system with some special CSS.

I could attempt to replicate the MUI skeleton component, but if neither the calender skeleton nor the added course skeleton use it, it would mean trying to compare and replicate it with vanilla CSS and rewriting both of these skeletons (added scope).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought: man this file sucks and i wrote this file


export default function SectionTableLazyWrapper(props: SectionTableProps) {
return (
<Suspense fallback={<div></div>}>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: when does this codepath get hit? trying to understand where SectionTableSkeleton and AddedCoursesLoadingSkeleton differ

Copy link
Copy Markdown
Member Author

@dsnsgithub dsnsgithub Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is hit right when initial section table data is loaded. I believe the section table is lazy loaded because some data takes extra time to load (haven't really dug into if that is necessary or the true reason). I know that before I made this change, the loading skeleton would have some flicker as it initially uses my skeleton, then switches over to the section table lazy loading fallback, then finally renders the full table.

I modified the fallback so that I could use the section table lazy loading as part of my skeleton.

};
}, []);

useEffect(() => {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: do we need a useEffect here? can't updating localStorage be handled in the callback to setCourses?

}

// shade is #9d9d9d instead of #8d8d8d to account for gray overlay on calendar
const shimmerSx: SxProps = {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: I... assume that this mirrors code from the calendar, but I just want to confirm that it is?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to mirror the loading animation as close as I could to the calendar skeleton.

Since the calendar skeleton piggybacks off of the existing calendar system instead of using the MUI skeleton component it makes it harder.

.rbc-event.calendar-loading-event {
background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.1) 50%, transparent 100%);
background-size: 200% 100%;
animation: calendar-loading-shimmer 2s ease-in-out infinite;
}
.rbc-event.calendar-loading-event::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: inherit;
background-size: 200% 100%;
animation: calendar-loading-shimmer 3s ease-in-out infinite;
pointer-events: none;
mix-blend-mode: overlay;
}

return null;
}

export function AddedCoursesLoadingSkeleton() {
Copy link
Copy Markdown
Member

@KevinWu098 KevinWu098 Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue + question (repeat): still trying to figure out when each is rendered, but I'm seeing layout shift where it looks like the non-blueprint skeleton loads, then the blueprint skeleton loads... but if we have a copy in localStorage... why do we ever hit the non-blueprint?

similarly, if we have this in localStorage, why is there a separate default skeleton? if we have no blueprint, wouldn't we just render nothing / the empty state, like the calendar?

chrome-capture-2026-4-20

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since my skeleton doesn't store the full names of the classes, there will still be some layout shift as I assume the length of the course.

I will try to see if I can use localStorage with the entire schedule similar to the calendar skeleton loader.

similarly, if we have this in localStorage, why is there a separate default skeleton? if we have no blueprint, wouldn't we just render nothing / the empty state, like the calendar?

I think that in attempting to "distinguish loading state from empty state" we need to signify that there might be a schedule that is not in localStorage (because it is being pulled from AntAlmanac), so a default skeleton would still make sense here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants