From 6ff7ca64691cd93ce7169ccf17b1c793aef81aad Mon Sep 17 00:00:00 2001 From: Alex Mickelson Date: Thu, 19 Sep 2024 22:00:07 -0600 Subject: [PATCH] more layout and cleanup --- nextjs/src/app/course/[courseName]/layout.tsx | 18 +- .../[assignmentName]/AssignmentPreview.tsx | 2 +- .../[assignmentName]/EditAssignment.tsx | 153 +++++++---- nextjs/src/app/globals.css | 4 + nextjs/src/app/layout.tsx | 1 - .../src/hooks/canvas/canvasAssignmentHooks.ts | 4 +- nextjs/src/hooks/canvas/canvasHooks.ts | 3 +- nextjs/src/hooks/hookHydration.ts | 252 ++++++++++-------- nextjs/src/models/local/timeUtils.ts | 8 +- .../canvas/canvasAssignmentGroupService.ts | 4 +- .../canvas/canvasAssignmentService.ts | 124 ++++----- .../src/services/canvas/canvasServiceUtils.ts | 29 +- 12 files changed, 347 insertions(+), 255 deletions(-) diff --git a/nextjs/src/app/course/[courseName]/layout.tsx b/nextjs/src/app/course/[courseName]/layout.tsx index a89c664..3919c4d 100644 --- a/nextjs/src/app/course/[courseName]/layout.tsx +++ b/nextjs/src/app/course/[courseName]/layout.tsx @@ -1,5 +1,9 @@ +import { fileStorageService } from "@/services/fileStorage/fileStorageService"; import CourseContextProvider from "./context/CourseContextProvider"; import { Suspense } from "react"; +import { getQueryClient } from "@/app/providersQueryClientUtils"; +import { dehydrate, HydrationBoundary } from "@tanstack/react-query"; +import { hydrateCanvasCourse } from "@/hooks/hookHydration"; export default async function CourseLayout({ children, @@ -13,11 +17,19 @@ export default async function CourseLayout({ console.log("cannot load course that is .js.map " + decodedCourseName); return
; } + const settings = await fileStorageService.settings.getCourseSettings( + decodedCourseName + ); + const queryClient = getQueryClient(); + await hydrateCanvasCourse(settings.canvasId, queryClient); + const dehydratedState = dehydrate(queryClient); return ( - - {children} - + + + {children} + + ); } diff --git a/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/AssignmentPreview.tsx b/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/AssignmentPreview.tsx index eea7fe5..8658a16 100644 --- a/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/AssignmentPreview.tsx +++ b/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/AssignmentPreview.tsx @@ -8,7 +8,7 @@ export default function AssignmentPreview({ assignment: LocalAssignment; }) { return ( -
+
Due Date
diff --git a/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/EditAssignment.tsx b/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/EditAssignment.tsx index ff461d2..6aeb039 100644 --- a/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/EditAssignment.tsx +++ b/nextjs/src/app/course/[courseName]/modules/[moduleName]/assignment/[assignmentName]/EditAssignment.tsx @@ -21,6 +21,8 @@ import { Spinner } from "@/components/Spinner"; import { baseCanvasUrl } from "@/services/canvas/canvasServiceUtils"; import ClientOnly from "@/components/ClientOnly"; import { SuspenseAndErrorHandling } from "@/components/SuspenseAndErrorHandling"; +import { AssignmentSubmissionType } from "@/models/local/assignment/assignmentSubmissionType"; +import { LocalCourseSettings } from "@/models/local/localCourse"; export default function EditAssignment({ moduleName, @@ -29,6 +31,7 @@ export default function EditAssignment({ assignmentName: string; moduleName: string; }) { + const { data: settings } = useLocalCourseSettingsQuery(); const { data: assignment } = useAssignmentQuery(moduleName, assignmentName); const updateAssignment = useUpdateAssignmentMutation(); @@ -36,6 +39,7 @@ export default function EditAssignment({ localAssignmentMarkdown.toMarkdown(assignment) ); const [error, setError] = useState(""); + const [showHelp, setShowHelp] = useState(false); useEffect(() => { const delay = 500; @@ -72,14 +76,23 @@ export default function EditAssignment({ ]); return ( -
-
+
+
+ {showHelp && ( +
+            {getHelpString(settings)}
+          
+ )}
-
+
{error && error}
+ +
+ +
@@ -87,6 +100,7 @@ export default function EditAssignment({ setShowHelp((h) => !h)} /> @@ -94,12 +108,30 @@ export default function EditAssignment({ ); } +function getHelpString(settings: LocalCourseSettings) { + const groupNames = settings.assignmentGroups.map((g) => g.name).join("\n- "); + const helpString = `SubmissionTypes: +- ${AssignmentSubmissionType.ONLINE_TEXT_ENTRY} +- ${AssignmentSubmissionType.ONLINE_UPLOAD} +- ${AssignmentSubmissionType.DISCUSSION_TOPIC} +AllowedFileUploadExtensions: +- pdf +- jpg +- jpeg +- png +Assignment Group Names: +- ${groupNames}`; + return helpString; +} + function AssignmentButtons({ moduleName, assignmentName, + toggleHelp, }: { assignmentName: string; moduleName: string; + toggleHelp: () => void; }) { const { courseName } = useCourseContext(); const { data: settings } = useLocalCourseSettingsQuery(); @@ -113,61 +145,66 @@ function AssignmentButtons({ (a) => a.name === assignmentName ); return ( -
- {(addToCanvas.isPending || - deleteFromCanvas.isPending || - updateAssignment.isPending) && } - {assignmentInCanvas && !assignmentInCanvas.published && ( -
Not Published
- )} - {!assignmentInCanvas && ( - - )} - {assignmentInCanvas && ( - - View in Canvas - - )} - {assignmentInCanvas && ( - - )} - {assignmentInCanvas && ( - - )} - - Go Back - +
+
+ +
+
+ {(addToCanvas.isPending || + deleteFromCanvas.isPending || + updateAssignment.isPending) && } + {assignmentInCanvas && !assignmentInCanvas.published && ( +
Not Published
+ )} + {!assignmentInCanvas && ( + + )} + {assignmentInCanvas && ( + + View in Canvas + + )} + {assignmentInCanvas && ( + + )} + {assignmentInCanvas && ( + + )} + + Go Back + +
); } diff --git a/nextjs/src/app/globals.css b/nextjs/src/app/globals.css index d390c8b..f034d98 100644 --- a/nextjs/src/app/globals.css +++ b/nextjs/src/app/globals.css @@ -23,6 +23,10 @@ } .monaco-editor { position: absolute !important; } +.monaco-editor .mtk1 { + @apply text-slate-300; +} + h1 { @apply text-4xl font-bold my-1; } diff --git a/nextjs/src/app/layout.tsx b/nextjs/src/app/layout.tsx index 1f4fd61..bcc07e4 100644 --- a/nextjs/src/app/layout.tsx +++ b/nextjs/src/app/layout.tsx @@ -6,7 +6,6 @@ import { getQueryClient } from "./providersQueryClientUtils"; import { hydrateCourses } from "@/hooks/hookHydration"; import { dehydrate, HydrationBoundary } from "@tanstack/react-query"; import { MyToaster } from "./MyToaster"; -import "katex/dist/katex.min.css"; export const metadata: Metadata = { title: "Canvas Manager 2.0", diff --git a/nextjs/src/hooks/canvas/canvasAssignmentHooks.ts b/nextjs/src/hooks/canvas/canvasAssignmentHooks.ts index 7f4d930..e4ccaac 100644 --- a/nextjs/src/hooks/canvas/canvasAssignmentHooks.ts +++ b/nextjs/src/hooks/canvas/canvasAssignmentHooks.ts @@ -12,8 +12,8 @@ import { LocalAssignment } from "@/models/local/assignment/localAssignment"; export const canvasAssignmentKeys = { assignments: (canvasCourseId: number) => ["canvas", canvasCourseId, "assignments"] as const, - assignment: (canvasCourseId: number, assignmentName: string) => - ["canvas", canvasCourseId, "assignment", assignmentName] as const, + // assignment: (canvasCourseId: number, assignmentName: string) => + // ["canvas", canvasCourseId, "assignment", assignmentName] as const, }; export const useCanvasAssignmentsQuery = () => { diff --git a/nextjs/src/hooks/canvas/canvasHooks.ts b/nextjs/src/hooks/canvas/canvasHooks.ts index 929d45e..3261540 100644 --- a/nextjs/src/hooks/canvas/canvasHooks.ts +++ b/nextjs/src/hooks/canvas/canvasHooks.ts @@ -1,6 +1,5 @@ import { canvasService } from "@/services/canvas/canvasService"; -import { QueryClient, useSuspenseQuery } from "@tanstack/react-query"; -import { canvasCourseModuleKeys } from "./canvasModuleHooks"; +import { useSuspenseQuery } from "@tanstack/react-query"; export const canvasKeys = { allTerms: ["all canvas terms"] as const, diff --git a/nextjs/src/hooks/hookHydration.ts b/nextjs/src/hooks/hookHydration.ts index d09b76f..2586fd2 100644 --- a/nextjs/src/hooks/hookHydration.ts +++ b/nextjs/src/hooks/hookHydration.ts @@ -2,10 +2,18 @@ import { QueryClient } from "@tanstack/react-query"; import { localCourseKeys } from "./localCourse/localCourseKeys"; import { fileStorageService } from "@/services/fileStorage/fileStorageService"; import { LocalCourseSettings } from "@/models/local/localCourse"; +import { canvasAssignmentService } from "@/services/canvas/canvasAssignmentService"; +import { canvasAssignmentKeys } from "./canvas/canvasAssignmentHooks"; +import { LocalAssignment } from "@/models/local/assignment/localAssignment"; +import { LocalCoursePage } from "@/models/local/page/localCoursePage"; +import { LocalQuiz } from "@/models/local/quiz/localQuiz"; +import { canvasQuizService } from "@/services/canvas/canvasQuizService"; +import { canvasPageService } from "@/services/canvas/canvasPageService"; +import { canvasQuizKeys } from "./canvas/canvasQuizHooks"; +import { canvasPageKeys } from "./canvas/canvasPageHooks"; // https://tanstack.com/query/latest/docs/framework/react/guides/ssr export const hydrateCourses = async (queryClient: QueryClient) => { const allSettings = await fileStorageService.settings.getAllCoursesSettings(); - const courseNames = allSettings.map((s) => s.name); await queryClient.prefetchQuery({ queryKey: localCourseKeys.allCoursesSettings, queryFn: () => allSettings, @@ -27,51 +35,7 @@ export const hydrateCourse = async ( courseName ); const modulesData = await Promise.all( - moduleNames.map(async (moduleName) => { - const [assignmentNames, pageNames, quizNames] = await Promise.all([ - await fileStorageService.assignments.getAssignmentNames( - courseName, - moduleName - ), - await fileStorageService.pages.getPageNames(courseName, moduleName), - await fileStorageService.quizzes.getQuizNames(courseName, moduleName), - ]); - - const [assignments, quizzes, pages] = await Promise.all([ - await Promise.all( - assignmentNames.map( - async (assignmentName) => - await fileStorageService.assignments.getAssignment( - courseName, - moduleName, - assignmentName - ) - ) - ), - await Promise.all( - quizNames.map( - async (quizName) => - await fileStorageService.quizzes.getQuiz(courseName, moduleName, quizName) - ) - ), - await Promise.all( - pageNames.map( - async (pageName) => - await fileStorageService.pages.getPage(courseName, moduleName, pageName) - ) - ), - ]); - - return { - moduleName, - assignmentNames, - pageNames, - quizNames, - assignments, - quizzes, - pages, - }; - }) + moduleNames.map((moduleName) => loadAllModuleData(courseName, moduleName)) ); await queryClient.prefetchQuery({ @@ -84,68 +48,146 @@ export const hydrateCourse = async ( }); await Promise.all( - modulesData.map( - async ({ - moduleName, - assignmentNames, - pageNames, - quizNames, - assignments, - quizzes, - pages, - }) => { - await queryClient.prefetchQuery({ - queryKey: localCourseKeys.assignmentNames(courseName, moduleName), - queryFn: () => assignmentNames, - }); - await Promise.all( - assignments.map( - async (assignment) => - await queryClient.prefetchQuery({ - queryKey: localCourseKeys.assignment( - courseName, - moduleName, - assignment.name - ), - queryFn: () => assignment, - }) + modulesData.map((d) => hydrateModuleData(d, courseName, queryClient)) + ); +}; + +export const hydrateCanvasCourse = async ( + canvasCourseId: number, + queryClient: QueryClient +) => { + await Promise.all([ + queryClient.prefetchQuery({ + queryKey: canvasAssignmentKeys.assignments(canvasCourseId), + queryFn: async () => await canvasAssignmentService.getAll(canvasCourseId), + }), + queryClient.prefetchQuery({ + queryKey: canvasQuizKeys.quizzes(canvasCourseId), + queryFn: async () => await canvasQuizService.getAll(canvasCourseId), + }), + queryClient.prefetchQuery({ + queryKey: canvasPageKeys.pagesInCourse(canvasCourseId), + queryFn: async () => await canvasPageService.getAll(canvasCourseId), + }), + ]); +}; + +const loadAllModuleData = async (courseName: string, moduleName: string) => { + const [assignmentNames, pageNames, quizNames] = await Promise.all([ + await fileStorageService.assignments.getAssignmentNames( + courseName, + moduleName + ), + await fileStorageService.pages.getPageNames(courseName, moduleName), + await fileStorageService.quizzes.getQuizNames(courseName, moduleName), + ]); + + const [assignments, quizzes, pages] = await Promise.all([ + await Promise.all( + assignmentNames.map( + async (assignmentName) => + await fileStorageService.assignments.getAssignment( + courseName, + moduleName, + assignmentName ) - ); - await queryClient.prefetchQuery({ - queryKey: localCourseKeys.quizNames(courseName, moduleName), - queryFn: () => quizNames, - }); - await Promise.all( - quizzes.map( - async (quiz) => - await queryClient.prefetchQuery({ - queryKey: localCourseKeys.quiz( - courseName, - moduleName, - quiz.name - ), - queryFn: () => quiz, - }) + ) + ), + await Promise.all( + quizNames.map( + async (quizName) => + await fileStorageService.quizzes.getQuiz( + courseName, + moduleName, + quizName ) - ); - await queryClient.prefetchQuery({ - queryKey: localCourseKeys.pageNames(courseName, moduleName), - queryFn: () => pageNames, - }); - await Promise.all( - pages.map( - async (page) => - await queryClient.prefetchQuery({ - queryKey: localCourseKeys.page( - courseName, - moduleName, - page.name - ), - queryFn: () => page, - }) + ) + ), + await Promise.all( + pageNames.map( + async (pageName) => + await fileStorageService.pages.getPage( + courseName, + moduleName, + pageName ) - ); - } + ) + ), + ]); + + return { + moduleName, + assignmentNames, + pageNames, + quizNames, + assignments, + quizzes, + pages, + }; +}; + +const hydrateModuleData = async ( + { + moduleName, + assignmentNames, + pageNames, + quizNames, + assignments, + quizzes, + pages, + }: { + moduleName: string; + assignmentNames: string[]; + pageNames: string[]; + quizNames: string[]; + assignments: LocalAssignment[]; + quizzes: LocalQuiz[]; + pages: LocalCoursePage[]; + }, + courseName: string, + queryClient: QueryClient +) => { + await queryClient.prefetchQuery({ + queryKey: localCourseKeys.assignmentNames(courseName, moduleName), + queryFn: () => assignmentNames, + }); + await Promise.all( + assignments.map( + async (assignment) => + await queryClient.prefetchQuery({ + queryKey: localCourseKeys.assignment( + courseName, + moduleName, + assignment.name + ), + queryFn: () => assignment, + }) + ) + ); + await queryClient.prefetchQuery({ + queryKey: localCourseKeys.quizNames(courseName, moduleName), + queryFn: () => quizNames, + }); + await Promise.all( + quizzes.map( + async (quiz) => + await queryClient.prefetchQuery({ + queryKey: localCourseKeys.quiz(courseName, moduleName, quiz.name), + queryFn: () => quiz, + }) + ) + ); + await queryClient.prefetchQuery({ + queryKey: localCourseKeys.pageNames(courseName, moduleName), + queryFn: () => pageNames, + }); + await Promise.all( + pages.map( + async (page) => + await queryClient.prefetchQuery({ + queryKey: localCourseKeys.page(courseName, moduleName, page.name), + queryFn: () => page, + }) ) ); }; diff --git a/nextjs/src/models/local/timeUtils.ts b/nextjs/src/models/local/timeUtils.ts index cab4849..0c51d8b 100644 --- a/nextjs/src/models/local/timeUtils.ts +++ b/nextjs/src/models/local/timeUtils.ts @@ -37,7 +37,6 @@ const _getDateFromISO = (value: string): Date | undefined => { }; export const getDateFromString = (value: string): Date | undefined => { - const ampmDateRegex = /^\d{1,2}\/\d{1,2}\/\d{4} \d{1,2}:\d{2}:\d{2}\s{1}[APap][Mm]$/; //"M/D/YYYY h:mm:ss AM/PM" const militaryDateRegex = /^\d{1,2}\/\d{1,2}\/\d{4} \d{1,2}:\d{2}:\d{2}$/; //"MM/DD/YYYY HH:mm:ss" @@ -52,7 +51,7 @@ export const getDateFromString = (value: string): Date | undefined => { const [datePart, timePart] = value.split(" "); return _getDateFromMilitary(datePart, timePart); } else { - console.log("invalid date format", value); + if (value) console.log("invalid date format", value); return undefined; } }; @@ -93,7 +92,6 @@ export const dateToMarkdownString = (date: Date) => { return `${stringMonth}/${stringDay}/${stringYear} ${stringHours}:${stringMinutes}:${stringSeconds}`; }; - export const getDateOnlyMarkdownString = (date: Date) => { - return dateToMarkdownString(date).split(" ")[0] -} \ No newline at end of file + return dateToMarkdownString(date).split(" ")[0]; +}; diff --git a/nextjs/src/services/canvas/canvasAssignmentGroupService.ts b/nextjs/src/services/canvas/canvasAssignmentGroupService.ts index 2237bc7..562315e 100644 --- a/nextjs/src/services/canvas/canvasAssignmentGroupService.ts +++ b/nextjs/src/services/canvas/canvasAssignmentGroupService.ts @@ -1,4 +1,4 @@ -import { canvasApi, canvasServiceUtils } from "./canvasServiceUtils"; +import { canvasApi, paginatedRequest } from "./canvasServiceUtils"; import { axiosClient } from "../axiosUtils"; import { CanvasAssignmentGroup } from "@/models/canvas/assignments/canvasAssignmentGroup"; import { LocalAssignmentGroup } from "@/models/local/assignment/localAssignmentGroup"; @@ -8,7 +8,7 @@ export const canvasAssignmentGroupService = { async getAll(courseId: number): Promise { console.log("Requesting assignment groups"); const url = `${canvasApi}/courses/${courseId}/assignment_groups`; - const assignmentGroups = await canvasServiceUtils.paginatedRequest< + const assignmentGroups = await paginatedRequest< CanvasAssignmentGroup[] >({ url, diff --git a/nextjs/src/services/canvas/canvasAssignmentService.ts b/nextjs/src/services/canvas/canvasAssignmentService.ts index 270e664..061718a 100644 --- a/nextjs/src/services/canvas/canvasAssignmentService.ts +++ b/nextjs/src/services/canvas/canvasAssignmentService.ts @@ -1,75 +1,12 @@ import { CanvasAssignment } from "@/models/canvas/assignments/canvasAssignment"; -import { - canvasApi, - canvasServiceUtils, - paginatedRequest, -} from "./canvasServiceUtils"; +import { canvasApi, paginatedRequest } from "./canvasServiceUtils"; import { LocalAssignment } from "@/models/local/assignment/localAssignment"; import { axiosClient } from "../axiosUtils"; import { markdownToHTMLSafe } from "../htmlMarkdownUtils"; import { CanvasRubricCreationResponse } from "@/models/canvas/assignments/canvasRubricCreationResponse"; import { assignmentPoints } from "@/models/local/assignment/utils/assignmentPointsUtils"; -import { - getDateFromString, - getDateFromStringOrThrow, -} from "@/models/local/timeUtils"; +import { getDateFromString } from "@/models/local/timeUtils"; -const createRubric = async ( - courseId: number, - assignmentCanvasId: number, - localAssignment: LocalAssignment -) => { - const criterion = localAssignment.rubric - .map((rubricItem) => ({ - description: rubricItem.label, - points: rubricItem.points, - ratings: { - 0: { description: "Full Marks", points: rubricItem.points }, - 1: { description: "No Marks", points: 0 }, - }, - })) - .reduce((acc, item, index) => { - return { - ...acc, - [index]: item, - }; - }, {} as { [key: number]: { description: string; points: number; ratings: { [key: number]: { description: string; points: number } } } }); - - const rubricBody = { - rubric_association_id: assignmentCanvasId, - rubric: { - title: `Rubric for Assignment: ${localAssignment.name}`, - association_id: assignmentCanvasId, - association_type: "Assignment", - use_for_grading: true, - criteria: criterion, - }, - rubric_association: { - association_id: assignmentCanvasId, - association_type: "Assignment", - purpose: "grading", - use_for_grading: true, - }, - }; - - const rubricUrl = `${canvasApi}/courses/${courseId}/rubrics`; - const rubricResponse = await axiosClient.post( - rubricUrl, - rubricBody - ); - - if (!rubricResponse.data) throw new Error("Failed to create rubric"); - - const assignmentPointAdjustmentUrl = `${canvasApi}/courses/${courseId}/assignments/${assignmentCanvasId}`; - const assignmentPointAdjustmentBody = { - assignment: { points_possible: assignmentPoints(localAssignment) }, - }; - - await axiosClient.put( - assignmentPointAdjustmentUrl, - assignmentPointAdjustmentBody - ); -}; export const canvasAssignmentService = { async getAll(courseId: number): Promise { @@ -163,3 +100,60 @@ export const canvasAssignmentService = { } }, }; + +const createRubric = async ( + courseId: number, + assignmentCanvasId: number, + localAssignment: LocalAssignment +) => { + const criterion = localAssignment.rubric + .map((rubricItem) => ({ + description: rubricItem.label, + points: rubricItem.points, + ratings: { + 0: { description: "Full Marks", points: rubricItem.points }, + 1: { description: "No Marks", points: 0 }, + }, + })) + .reduce((acc, item, index) => { + return { + ...acc, + [index]: item, + }; + }, {} as { [key: number]: { description: string; points: number; ratings: { [key: number]: { description: string; points: number } } } }); + + const rubricBody = { + rubric_association_id: assignmentCanvasId, + rubric: { + title: `Rubric for Assignment: ${localAssignment.name}`, + association_id: assignmentCanvasId, + association_type: "Assignment", + use_for_grading: true, + criteria: criterion, + }, + rubric_association: { + association_id: assignmentCanvasId, + association_type: "Assignment", + purpose: "grading", + use_for_grading: true, + }, + }; + + const rubricUrl = `${canvasApi}/courses/${courseId}/rubrics`; + const rubricResponse = await axiosClient.post( + rubricUrl, + rubricBody + ); + + if (!rubricResponse.data) throw new Error("Failed to create rubric"); + + const assignmentPointAdjustmentUrl = `${canvasApi}/courses/${courseId}/assignments/${assignmentCanvasId}`; + const assignmentPointAdjustmentBody = { + assignment: { points_possible: assignmentPoints(localAssignment) }, + }; + + await axiosClient.put( + assignmentPointAdjustmentUrl, + assignmentPointAdjustmentBody + ); +}; diff --git a/nextjs/src/services/canvas/canvasServiceUtils.ts b/nextjs/src/services/canvas/canvasServiceUtils.ts index 49cf90e..6845126 100644 --- a/nextjs/src/services/canvas/canvasServiceUtils.ts +++ b/nextjs/src/services/canvas/canvasServiceUtils.ts @@ -14,18 +14,26 @@ const getNextUrl = ( ? (headers.get("link") as string) : ((headers as RawAxiosResponseHeaders)["link"] as string); - if (!linkHeader) return undefined; + if (!linkHeader) { + console.log("could not find link header in the response"); + return undefined; + } const links = linkHeader.split(",").map((link) => link.trim()); const nextLink = links.find((link) => link.includes('rel="next"')); - if (!nextLink) return undefined; + if (!nextLink) { + // console.log( + // "could not find next url in link header, reached end of pagination" + // ); + return undefined; + } const nextUrl = nextLink.split(";")[0].trim().slice(1, -1); return nextUrl; }; -export async function paginatedRequest(request: { +export async function paginatedRequest(request: { url: string; }): Promise { var requestCount = 1; @@ -36,20 +44,19 @@ export async function paginatedRequest(request: { url.toString() ); - if (!Array.isArray(firstData)) { - return firstData; - } + // if (!Array.isArray(firstData)) { + // return firstData; + // } - - var returnData = firstData ? [firstData] : []; + var returnData = [...firstData]; var nextUrl = getNextUrl(firstHeaders); - console.log("got first request", nextUrl, firstHeaders); + // console.log("got first request", nextUrl, firstHeaders); while (nextUrl) { requestCount += 1; const { data, headers } = await axiosClient.get(nextUrl); if (data) { - returnData = [...returnData, data]; + returnData = returnData.concat(data); } nextUrl = getNextUrl(headers); } @@ -60,5 +67,5 @@ export async function paginatedRequest(request: { ); } - return returnData; + return returnData as T; }