diff --git a/app/api/study-plan/route.ts b/app/api/study-plan/route.ts
index f65f4f3..bbcd8f3 100644
--- a/app/api/study-plan/route.ts
+++ b/app/api/study-plan/route.ts
@@ -65,3 +65,25 @@ export async function GET(req: NextRequest) {
});
return res;
}
+
+export async function DELETE(req: NextRequest) {
+ const user = await getUser(req);
+
+ if (!user) {
+ return NextResponse.json({}, { status: 401 });
+ }
+
+ const semesterRepository = AppDataSource.getRepository(Semester);
+
+ const deleteRes = await semesterRepository.delete({
+ studyPlan: {
+ user: {
+ id: user.id,
+ },
+ },
+ });
+ if (deleteRes.affected === 0) {
+ return NextResponse.json({}, { status: 404 });
+ }
+ return NextResponse.json({}, { status: 200 });
+}
diff --git a/components/Header/index.tsx b/components/Header/index.tsx
index f965976..c211107 100644
--- a/components/Header/index.tsx
+++ b/components/Header/index.tsx
@@ -3,6 +3,7 @@
import {
AuditOutlined,
BugOutlined,
+ DeleteOutlined,
ExperimentOutlined,
InfoCircleOutlined,
PoweroffOutlined,
@@ -32,11 +33,13 @@ export interface HeaderProps {
avatarUrl: string;
} | null;
isMobile?: boolean;
+ onResetStudyPlan?: () => void;
}
export default function Header({
isLoading = false,
user,
isMobile = false,
+ onResetStudyPlan,
}: HeaderProps) {
return (
,
},
+ {
+ key: "4",
+ label: (
+
+ ),
+ icon: ,
+ },
],
}}
>
diff --git a/components/Header/useHeader.ts b/components/Header/useHeader.ts
index c512338..af8d604 100644
--- a/components/Header/useHeader.ts
+++ b/components/Header/useHeader.ts
@@ -1,8 +1,10 @@
+import useSession from "@/services/apiClient/useSession";
import { useLearningPlatformCurrentUser } from "@/services/learningPlatform/hooks/useLearningPlatformCurrentUser";
import { HeaderProps } from ".";
export default function useHeader(): HeaderProps {
+ const { api } = useSession();
const currentUserQuery = useLearningPlatformCurrentUser();
const avatarUrl = currentUserQuery.data?.me.avatarUrl;
@@ -21,8 +23,20 @@ export default function useHeader(): HeaderProps {
}
: null;
+ async function onResetStudyPlan() {
+ try {
+ await api?.resetStudyPlan();
+
+ location.reload();
+ } catch (err) {
+ alert((err as Error).message || "Unknown error");
+ }
+ }
+
return {
isLoading: currentUserQuery.isLoading,
user,
+
+ onResetStudyPlan,
};
}
diff --git a/components/ModulesListSection.tsx b/components/ModulesListSection.tsx
index 498944e..7084770 100644
--- a/components/ModulesListSection.tsx
+++ b/components/ModulesListSection.tsx
@@ -16,6 +16,7 @@ export interface ModulesListSectionProps extends Omit {
showAddItemButton?: boolean;
isHovered?: boolean;
isDragInProgress?: boolean;
+ isLoading?: boolean;
onAddItem?: () => void;
}
@@ -27,6 +28,7 @@ function ModulesListSection({
showAddItemButton = true,
isHovered = false,
isDragInProgress = false,
+ isLoading = false,
onAddItem,
...rest
@@ -116,16 +118,18 @@ function ModulesListSection({
}}
>
{provided.placeholder}
- {modules.map((module, index) => (
-
- ))}
+ {modules
+ .filter((i) => (isLoading ? true : i.module != null))
+ .map((module, index) => (
+
+ ))}
)}
diff --git a/components/Semester.tsx b/components/Semester.tsx
index d2a3e95..76b3cd8 100644
--- a/components/Semester.tsx
+++ b/components/Semester.tsx
@@ -20,6 +20,8 @@ export interface SemesterProps {
setMouseUpInboxId: (inboxId: string | null) => void;
setHoveredInboxId: (inboxId: string | null) => void;
+
+ isLoading?: boolean;
}
function SemesterCard({
semester,
@@ -28,6 +30,7 @@ function SemesterCard({
draggedModules,
setMouseUpInboxId,
setHoveredInboxId,
+ isLoading = false,
}: SemesterProps) {
const [isHovered, setIsHovered] = useState(false);
@@ -157,6 +160,7 @@ function SemesterCard({
}}
{}}
/>
setMouseUpInboxId(
@@ -204,6 +209,7 @@ function SemesterCard({
disabled={isPastSemester || isstandardDisabled}
/>
{}}
/>
setMouseUpInboxId(`droppable:semester:${semester.id}:reassessments`)
diff --git a/components/SemestersList/index.tsx b/components/SemestersList/index.tsx
index 5ebb6cc..ff7a9e4 100644
--- a/components/SemestersList/index.tsx
+++ b/components/SemestersList/index.tsx
@@ -128,6 +128,7 @@ export default function SemestersList({
draggedModules={draggedModules}
setMouseUpInboxId={setMouseUpInboxId}
setHoveredInboxId={setHoveredInboxId}
+ isLoading={isLoading}
/>
))}
diff --git a/services/apiClient/index.ts b/services/apiClient/index.ts
index 7f5096e..717c506 100644
--- a/services/apiClient/index.ts
+++ b/services/apiClient/index.ts
@@ -74,6 +74,22 @@ export class StudyPlannerApiClient {
return data;
}
+
+ public async resetStudyPlan(): Promise<{}> {
+ const res = await fetch(this.url + "/study-plan", {
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: this.accessToken,
+ },
+ method: "DELETE",
+ });
+ if (!res.ok) {
+ throw new Error(`Failed to reset study plan (code ${res.status})`);
+ }
+ const data: {} = await res.json();
+
+ return data;
+ }
}
export type UpdateSemesterModuleInput = Record;