From 9d6a3d11997c6685cde2e530c8975385384f3ff4 Mon Sep 17 00:00:00 2001 From: Alex Mickelson Date: Thu, 29 Aug 2024 15:25:54 -0600 Subject: [PATCH] loading states --- .../Services/Files/LoadMarkdownCourse.cs | 45 ++++++++++++--- nextjs/src/app/CourseList.tsx | 4 +- .../src/app/course/[courseName]/loading.tsx | 10 ++++ nextjs/src/components/Spinner.tsx | 10 ++++ nextjs/src/components/spinner.css | 56 +++++++++++++++++++ 5 files changed, 114 insertions(+), 11 deletions(-) create mode 100644 nextjs/src/app/course/[courseName]/loading.tsx create mode 100644 nextjs/src/components/Spinner.tsx create mode 100644 nextjs/src/components/spinner.css diff --git a/Management/Services/Files/LoadMarkdownCourse.cs b/Management/Services/Files/LoadMarkdownCourse.cs index 4e00cc5..1250dae 100644 --- a/Management/Services/Files/LoadMarkdownCourse.cs +++ b/Management/Services/Files/LoadMarkdownCourse.cs @@ -1,4 +1,5 @@ using LocalModels; + using Management.Services; public class CourseMarkdownLoader @@ -38,14 +39,23 @@ public class CourseMarkdownLoader throw new LoadCourseFromFileException(errorMessage); } - LocalCourseSettings settings = await loadCourseSettings(courseDirectory); - var modules = await loadCourseModules(courseDirectory); - - return new() + try { - Settings = settings, - Modules = modules - }; + + LocalCourseSettings settings = await loadCourseSettings(courseDirectory); + var modules = await loadCourseModules(courseDirectory); + + return new() + { + Settings = settings, + Modules = modules + }; + } + catch (Exception) + { + Console.WriteLine($"failed to load course at path: ${courseDirectory}"); + throw; + } } private async Task loadCourseSettings(string courseDirectory) @@ -106,7 +116,15 @@ public class CourseMarkdownLoader .Select(async filePath => { var rawFile = (await File.ReadAllTextAsync(filePath)).Replace("\r\n", "\n"); - return LocalAssignment.ParseMarkdown(rawFile); + try + { + return LocalAssignment.ParseMarkdown(rawFile); + } + catch + { + Console.WriteLine($"error loading assignment at path {filePath}"); + throw; + } }) .ToArray(); return await Task.WhenAll(assignmentPromises); @@ -145,8 +163,17 @@ public class CourseMarkdownLoader var pagePromises = pageFiles .Select(async path => { + var rawPage = (await File.ReadAllTextAsync(path)).Replace("\r\n", "\n"); - return LocalCoursePage.ParseMarkdown(rawPage); + try + { + return LocalCoursePage.ParseMarkdown(rawPage); + } + catch + { + Console.WriteLine($"error loading page at path {path}"); + throw; + } }) .ToArray(); diff --git a/nextjs/src/app/CourseList.tsx b/nextjs/src/app/CourseList.tsx index 2e9bbf5..7fa6715 100644 --- a/nextjs/src/app/CourseList.tsx +++ b/nextjs/src/app/CourseList.tsx @@ -7,8 +7,8 @@ export default function CourseList() { return (
{courses.map((c) => ( - - {c.settings.name}{" "} + + {c}{" "} ))}
diff --git a/nextjs/src/app/course/[courseName]/loading.tsx b/nextjs/src/app/course/[courseName]/loading.tsx new file mode 100644 index 0000000..858e083 --- /dev/null +++ b/nextjs/src/app/course/[courseName]/loading.tsx @@ -0,0 +1,10 @@ +import { Spinner } from "@/components/Spinner"; +import React from "react"; + +export default function Loading() { + return ( +
+ +
+ ); +} diff --git a/nextjs/src/components/Spinner.tsx b/nextjs/src/components/Spinner.tsx new file mode 100644 index 0000000..b40fa5e --- /dev/null +++ b/nextjs/src/components/Spinner.tsx @@ -0,0 +1,10 @@ +import React from "react"; +import "./spinner.css" + +export const Spinner = () => { + return ( +
+ +
+ ); +}; diff --git a/nextjs/src/components/spinner.css b/nextjs/src/components/spinner.css new file mode 100644 index 0000000..c0d6049 --- /dev/null +++ b/nextjs/src/components/spinner.css @@ -0,0 +1,56 @@ +.loader { + width: 48px; + height: 48px; + border-radius: 50%; + display: inline-block; + position: relative; + border: 3px solid; + border-color: #6c757d #6c757d transparent transparent; + box-sizing: border-box; + animation: rotation 2s linear infinite; +} +.loader::after, +.loader::before { + content: ''; + box-sizing: border-box; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; + border: 3px solid; + border-color: transparent transparent #092565 #092565; + width: 40px; + height: 40px; + border-radius: 50%; + box-sizing: border-box; + animation: rotationBack 1s linear infinite; + transform-origin: center center; +} +/* #092565 */ +/* #3a0647 */ +.loader::before { + width: 32px; + height: 32px; + border-color: #6c757d #6c757d transparent transparent; + animation: rotation 3s linear infinite; +} + +@keyframes rotation { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} +@keyframes rotationBack { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(-360deg); + } +} + \ No newline at end of file