client vs server render issues

This commit is contained in:
2024-09-17 09:19:52 -06:00
parent c6c9b299d9
commit c7f968bb8f
13 changed files with 175 additions and 58 deletions

View File

@@ -44,7 +44,7 @@ const proxyResponseHeaders = (response: any) => {
};
export async function GET(
req: NextRequest,
_req: NextRequest,
{ params }: { params: { rest: string[] } }
) {
return withErrorHandling(async () => {
@@ -58,7 +58,12 @@ export async function GET(
url.toString()
);
var returnData = firstData ? [firstData] : [];
if(!Array.isArray(firstData))
{
return NextResponse.json(firstData)
}
var returnData = firstData;
var nextUrl = getNextUrl(firstHeaders);
while (nextUrl) {
@@ -77,6 +82,7 @@ export async function GET(
}
return NextResponse.json(returnData);
} catch (error: any) {
return new NextResponse(
JSON.stringify({ error: error.message || "Canvas GET request failed" }),

View File

@@ -1,3 +1,4 @@
"use client";
import {
useAssignmentNamesQuery,
useAssignmentsQueries,
@@ -12,9 +13,15 @@ import {
} from "@/hooks/localCourse/quizHooks";
import { IModuleItem } from "@/models/local/IModuleItem";
import { getDateFromStringOrThrow } from "@/models/local/timeUtils";
import { useState } from "react";
import { Suspense, useEffect, useState } from "react";
import Modal from "../../../../components/Modal";
import NewItemForm from "./NewItemForm";
import { useCanvasModulesQuery } from "@/hooks/canvas/canvasModuleHooks";
import { Spinner } from "@/components/Spinner";
import { SuspenseAndErrorHandling } from "@/components/SuspenseAndErrorHandling";
import { isServer } from "@tanstack/react-query";
import { ModuleCanvasStatus } from "./ModuleCanvasStatus";
import ClientOnly from "@/components/ClientOnly";
export default function ExpandableModule({
moduleName,
@@ -66,11 +73,14 @@ export default function ExpandableModule({
return (
<div className="bg-slate-800 rounded-lg p-3 border border-slate-600 mb-3">
<div
className="font-bold "
className="font-bold flex flex-row justify-between "
role="button"
onClick={() => setExpanded((e) => !e)}
>
{moduleName}
<div>{moduleName}</div>
<ClientOnly>
<ModuleCanvasStatus moduleName={moduleName} />
</ClientOnly>
</div>
<div
className={

View File

@@ -0,0 +1,29 @@
"use client";
import { Spinner } from "@/components/Spinner";
import {
useAddCanvasModuleMutation,
useCanvasModulesQuery,
} from "@/hooks/canvas/canvasModuleHooks";
export function ModuleCanvasStatus({ moduleName }: { moduleName: string }) {
const { data: canvasModules } = useCanvasModulesQuery();
const addToCanvas = useAddCanvasModuleMutation();
const canvasModule = canvasModules.find((c) => c.name === moduleName);
return (
<div className="text-slate-400 text-end">
{!canvasModule && <div>Not in Canvas</div>}
{!canvasModule && (
<button
disabled={addToCanvas.isPending}
onClick={() => addToCanvas.mutate(moduleName)}
>
{addToCanvas.isPending ? <Spinner /> : <div>Add</div>}
</button>
)}
{canvasModule && !canvasModule.published && <div>Not Published</div>}
{canvasModule && canvasModule.published && <div>Published</div>}
</div>
);
}

View File

@@ -2,6 +2,7 @@
import React, { useState } from "react";
import { SuspenseAndErrorHandling } from "@/components/SuspenseAndErrorHandling";
import NewCourseForm from "./NewCourseForm";
import ClientOnly from "@/components/ClientOnly";
export default function AddNewCourse() {
const [showForm, setShowForm] = useState(false);
@@ -13,7 +14,7 @@ export default function AddNewCourse() {
<div className={" collapsible " + (showForm && "expand")}>
<div className="border rounded-md p-3 m-3">
<SuspenseAndErrorHandling>
{showForm && <NewCourseForm />}
<ClientOnly>{showForm && <NewCourseForm />}</ClientOnly>
</SuspenseAndErrorHandling>
</div>
</div>

View File

@@ -8,8 +8,7 @@ export default async function Home() {
<CourseList />
<br />
<br />
<AddNewCourse />
<AddNewCourse />
</div>
</main>
);

View File

@@ -0,0 +1,13 @@
"use client"
import React, { ReactNode, useEffect, useState } from "react";
export default function ClientOnly({ children }: { children: ReactNode }) {
const [isClient, setIsClient] = useState(false);
useEffect(() => {
setIsClient(true);
}, []);
if (!isClient) return <></>;
return <>{children}</>;
}

View File

@@ -1,5 +1,6 @@
import { canvasService } from "@/services/canvas/canvasService";
import { useSuspenseQuery } from "@tanstack/react-query";
import { QueryClient, useSuspenseQuery } from "@tanstack/react-query";
import { canvasCourseModuleKeys } from "./canvasModuleHooks";
export const canvasKeys = {
allTerms: ["all canvas terms"] as const,
@@ -34,4 +35,4 @@ export const useCanvasTermsQuery = (queryDate: Date) => {
return currentTerms;
},
});
};
};

View File

@@ -0,0 +1,34 @@
import { canvasModuleService } from "@/services/canvas/canvasModuleService";
import {
useMutation,
useQueryClient,
useSuspenseQuery,
} from "@tanstack/react-query";
import { useLocalCourseSettingsQuery } from "../localCourse/localCoursesHooks";
export const canvasCourseModuleKeys = {
modules: (canvasId: number) => ["canvas", canvasId, "module list"] as const,
};
export const useCanvasModulesQuery = () => {
const { data: settings } = useLocalCourseSettingsQuery();
return useSuspenseQuery({
queryKey: canvasCourseModuleKeys.modules(settings.canvasId),
queryFn: async () =>
await canvasModuleService.getCourseModules(settings.canvasId),
});
};
export const useAddCanvasModuleMutation = () => {
const { data: settings } = useLocalCourseSettingsQuery();
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (moduleName: string) =>
await canvasModuleService.createModule(settings.canvasId, moduleName),
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: canvasCourseModuleKeys.modules(settings.canvasId),
});
},
});
};

View File

@@ -1,10 +1,9 @@
import { canvasServiceUtils } from "./canvasServiceUtils";
import { baseCanvasUrl, canvasServiceUtils } from "./canvasServiceUtils";
import { axiosClient } from "../axiosUtils";
import { CanvasAssignmentGroup } from "@/models/canvas/assignments/canvasAssignmentGroup";
import { LocalAssignmentGroup } from "@/models/local/assignment/localAssignmentGroup";
import { rateLimitAwareDelete } from "./canvasWebRequestor";
const baseCanvasUrl = "https://snow.instructure.com/api/v1";
export const canvasAssignmentGroupService = {
async getAll(courseId: number): Promise<CanvasAssignmentGroup[]> {

View File

@@ -0,0 +1,65 @@
import { CanvasModuleItem } from "@/models/canvas/modules/canvasModuleItems";
import { CanvasPage } from "@/models/canvas/pages/canvasPageModel";
import { axiosClient } from "../axiosUtils";
import { baseCanvasUrl } from "./canvasServiceUtils";
import { CanvasModule } from "@/models/canvas/modules/canvasModule";
export const canvasModuleService = {
async updateModuleItem(
canvasCourseId: number,
canvasModuleId: number,
item: CanvasModuleItem
) {
console.log(`Updating module item ${item.title}`);
const url = `${baseCanvasUrl}/courses/${canvasCourseId}/modules/${canvasModuleId}/items/${item.id}`;
const body = {
module_item: { title: item.title, position: item.position },
};
const { data } = await axiosClient.put<CanvasModuleItem>(url, body);
if (!data) throw new Error("Something went wrong updating module item");
},
async createModuleItem(
canvasCourseId: number,
canvasModuleId: number,
title: string,
type: string,
contentId: number | string
): Promise<void> {
console.log(`Creating new module item ${title}`);
const url = `${baseCanvasUrl}/courses/${canvasCourseId}/modules/${canvasModuleId}/items`;
const body = { module_item: { title, type, content_id: contentId } };
await axiosClient.post(url, body);
},
async createPageModuleItem(
canvasCourseId: number,
canvasModuleId: number,
title: string,
canvasPage: CanvasPage
): Promise<void> {
console.log(`Creating new module item ${title}`);
const url = `${baseCanvasUrl}/courses/${canvasCourseId}/modules/${canvasModuleId}/items`;
const body = {
module_item: { title, type: "Page", page_url: canvasPage.url },
};
await axiosClient.post<CanvasModuleItem>(url, body);
},
async getCourseModules(canvasCourseId: number) {
const url = `${baseCanvasUrl}/courses/${canvasCourseId}/modules`;
const response = await axiosClient.get<CanvasModule[]>(url);
return response.data;
},
async createModule(canvasCourseId: number, moduleName: string) {
const url = `${baseCanvasUrl}/courses/${canvasCourseId}/modules`;
const body = {
module: {
name: moduleName,
},
};
await axiosClient.post(url, body);
},
};

View File

@@ -1,11 +1,10 @@
import { CanvasPage } from "@/models/canvas/pages/canvasPageModel";
import { LocalCoursePage } from "@/models/local/page/localCoursePage";
import { canvasServiceUtils } from "./canvasServiceUtils";
import { baseCanvasUrl, canvasServiceUtils } from "./canvasServiceUtils";
import { markdownToHTMLSafe } from "../htmlMarkdownUtils";
import { axiosClient } from "../axiosUtils";
import { rateLimitAwareDelete } from "./canvasWebRequestor";
const baseCanvasUrl = "https://snow.instructure.com/api/v1";
export const canvasPageService = {
async getAll(courseId: number): Promise<CanvasPage[]> {

View File

@@ -1,12 +1,11 @@
import { CanvasEnrollmentTermModel } from "@/models/canvas/enrollmentTerms/canvasEnrollmentTermModel";
import { canvasServiceUtils } from "./canvasServiceUtils";
import { baseCanvasUrl, canvasServiceUtils } from "./canvasServiceUtils";
import { CanvasCourseModel } from "@/models/canvas/courses/canvasCourseModel";
import { CanvasModuleItem } from "@/models/canvas/modules/canvasModuleItems";
import { CanvasPage } from "@/models/canvas/pages/canvasPageModel";
import { CanvasEnrollmentModel } from "@/models/canvas/enrollments/canvasEnrollmentModel";
import { axiosClient } from "../axiosUtils";
const baseCanvasUrl = "https://snow.instructure.com/api/v1";
const getAllTerms = async () => {
const url = `${baseCanvasUrl}/accounts/10/terms`;
@@ -23,7 +22,7 @@ export const canvasService = {
getAllTerms,
async getCourses(termId: number) {
const url = `${baseCanvasUrl}/courses`;
const response = await axiosClient.get<CanvasCourseModel[][]>(url);
const response = await axiosClient.get<CanvasCourseModel[]>(url);
const allCourses = response.data;
const coursesInTerm = allCourses
.flatMap((l) => l)
@@ -57,47 +56,6 @@ export const canvasService = {
return currentTerms;
},
async updateModuleItem(
canvasCourseId: number,
canvasModuleId: number,
item: CanvasModuleItem
) {
console.log(`Updating module item ${item.title}`);
const url = `${baseCanvasUrl}/courses/${canvasCourseId}/modules/${canvasModuleId}/items/${item.id}`;
const body = {
module_item: { title: item.title, position: item.position },
};
const { data } = await axiosClient.put<CanvasModuleItem>(url, body);
if (!data) throw new Error("Something went wrong updating module item");
},
async createModuleItem(
canvasCourseId: number,
canvasModuleId: number,
title: string,
type: string,
contentId: number | string
): Promise<void> {
console.log(`Creating new module item ${title}`);
const url = `${baseCanvasUrl}/courses/${canvasCourseId}/modules/${canvasModuleId}/items`;
const body = { module_item: { title, type, content_id: contentId } };
const response = await axiosClient.post(url, body);
},
async createPageModuleItem(
canvasCourseId: number,
canvasModuleId: number,
title: string,
canvasPage: CanvasPage
): Promise<void> {
console.log(`Creating new module item ${title}`);
const url = `${baseCanvasUrl}/courses/${canvasCourseId}/modules/${canvasModuleId}/items`;
const body = {
module_item: { title, type: "Page", page_url: canvasPage.url },
};
await axiosClient.post<CanvasModuleItem>(url, body);
},
async getEnrolledStudents(canvasCourseId: number) {
console.log(`Getting students for course ${canvasCourseId}`);

View File

@@ -3,6 +3,9 @@
import { AxiosResponseHeaders, RawAxiosResponseHeaders } from "axios";
import { axiosClient } from "../axiosUtils";
export const baseCanvasUrl = "https://snow.instructure.com/api/v1";
const getNextUrl = (
headers: AxiosResponseHeaders | RawAxiosResponseHeaders
): string | undefined => {