better matching

This commit is contained in:
2024-08-26 12:52:55 -06:00
parent 884e465df6
commit cafe04faf6
15 changed files with 232 additions and 33 deletions

View File

@@ -0,0 +1,3 @@
export async function GET() {
return Response.json([]);
}

View File

@@ -1,9 +1,11 @@
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import { createQueryClient } from "@/services/utils/queryClient";
import { dehydrate } from "@tanstack/react-query";
import { MyQueryClientProvider } from "@/services/utils/MyQueryClientProvider";
import { hydrateCourses } from "@/hooks/hookHydration";
import { LoadingAndErrorHandling } from "@/components/LoadingAndErrorHandling";
import { createQueryClientForServer } from "@/services/utils/queryClientServer";
const inter = Inter({ subsets: ["latin"] });
@@ -12,9 +14,9 @@ export const metadata: Metadata = {
};
export async function getDehydratedClient() {
const queryClient = createQueryClient();
const queryClient = createQueryClientForServer();
// await hydrateOpenSections(queryClient);
await hydrateCourses(queryClient);
const dehydratedState = dehydrate(queryClient);
return dehydratedState;
}
@@ -25,10 +27,13 @@ export default async function RootLayout({
children: React.ReactNode;
}>) {
const dehydratedState = await getDehydratedClient();
return (
<html lang="en">
<MyQueryClientProvider dehydratedState={dehydratedState}>
<body className={inter.className}>{children}</body>
<LoadingAndErrorHandling>
<body className={inter.className}>{children}</body>
</LoadingAndErrorHandling>
</MyQueryClientProvider>
</html>
);

View File

@@ -1,12 +1,12 @@
import { canvasAssignmentService } from "@/services/canvas/canvasAssignmentService";
export default async function Home() {
const assignments = await canvasAssignmentService.getAll(960410);
"use client"
import { useLocalCoursesQuery } from "@/hooks/localCoursesHooks";
export default function Home() {
const { data: courses } = useLocalCoursesQuery();
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
{assignments.map((assignment) => (
<div key={assignment.id}>{assignment.name}</div>
{courses.map((c) => (
<div key={c.settings.name}>{c.settings.name} </div>
))}
</main>
);

View File

@@ -0,0 +1,30 @@
import { QueryErrorResetBoundary } from "@tanstack/react-query";
import { FC, ReactNode, Suspense } from "react";
import { ErrorBoundary } from "react-error-boundary";
export const LoadingAndErrorHandling: FC<{ children: ReactNode }> = ({
children,
}) => {
return (
<QueryErrorResetBoundary>
{({ reset }) => (
<ErrorBoundary
onReset={reset}
fallbackRender={(props) => (
<div className="text-center">
<div className="p-3">{JSON.stringify(props.error)}</div>
<button
className="btn btn-outline-secondary"
onClick={() => props.resetErrorBoundary()}
>
Try again
</button>
</div>
)}
>
<Suspense fallback={<div>loading...</div>}>{children}</Suspense>
</ErrorBoundary>
)}
</QueryErrorResetBoundary>
);
};

View File

@@ -0,0 +1,10 @@
import { QueryClient } from "@tanstack/react-query";
import { localCourseKeys } from "./localCoursesHooks";
import { fileStorageService } from "@/services/fileStorage/fileStorageService";
export const hydrateCourses = async (queryClient: QueryClient) => {
await queryClient.prefetchQuery({
queryKey: localCourseKeys.allCourses,
queryFn: async () => await fileStorageService.loadSavedCourses(),
});
};

View File

@@ -0,0 +1,17 @@
import { LocalCourse } from "@/models/local/localCourse";
import { useSuspenseQuery } from "@tanstack/react-query";
import axios from "axios";
export const localCourseKeys = {
allCourses: ["all courses"] as const,
};
export const useLocalCoursesQuery = () =>
useSuspenseQuery({
queryKey: localCourseKeys.allCourses,
queryFn: async (): Promise<LocalCourse[]> => {
const url = `/api/courses`;
const response = await axios.get(url);
return response.data;
},
});

View File

@@ -0,0 +1,19 @@
import { describe, it, expect } from "vitest";
import { getDateFromString } from "../timeUtils";
describe("Can properly handle expected date formats", () => {
it("can use AM/PM dates", () =>{
const dateString = "8/27/2024 1:00:00AM"
const dateObject = getDateFromString(dateString)
expect(dateObject).not.toBeUndefined()
})
it("can use 24 hour dates", () =>{
const dateString = "8/27/2024 23:95:00"
const dateObject = getDateFromString(dateString)
expect(dateObject).not.toBeUndefined()
})
})

View File

@@ -1,24 +1,39 @@
export const getDateFromString = (value: string) => {
// may need to check for other formats
const validDateRegex =
/\d{2}\/\d{2}\/\d{4} [0-2][0-9]:[0-5][0-9]:[0-5][0-9]/;
// Updated regex to match both formats: "MM/DD/YYYY HH:mm:ss" and "M/D/YYYY h:mm:ss AM/PM"
const validDateRegex = /^\d{1,2}\/\d{1,2}\/\d{4} \d{1,2}:\d{2}:\d{2}(?:\s?[APap][Mm])?$/;
if (!validDateRegex.test(value)) {
console.log("invalid date format", value);
return undefined;
}
const [datePart, timePart] = value.split(" ");
const [datePart, timePartWithMeridian] = value.split(" ");
const [day, month, year] = datePart.split("/").map(Number);
let [timePart, meridian] = timePartWithMeridian.split(" ");
const [hours, minutes, seconds] = timePart.split(":").map(Number);
const date = new Date(year, month - 1, day, hours, minutes, seconds);
let adjustedHours = hours;
if (meridian) {
meridian = meridian.toUpperCase();
if (meridian === "PM" && hours < 12) {
adjustedHours += 12;
} else if (meridian === "AM" && hours === 12) {
adjustedHours = 0;
}
}
const date = new Date(year, month - 1, day, adjustedHours, minutes, seconds);
if (isNaN(date.getTime())) {
console.log("could not parse time out of value", value);
return undefined;
}
return date;
};
export const verifyDateStringOrUndefined = (
value: string
): string | undefined => {

View File

@@ -5,6 +5,7 @@ import { courseMarkdownLoader } from "./utils/couresMarkdownLoader";
import { courseMarkdownSaver } from "./utils/courseMarkdownSaver";
const basePath = process.env.STORAGE_DIRECTORY ?? "./storage";
console.log("base path", basePath);
export const fileStorageService = {
async saveCourseAsync(

View File

@@ -3,6 +3,7 @@
import {
DehydratedState,
hydrate,
HydrationBoundary,
QueryClientProvider,
} from "@tanstack/react-query";
import React from "react";
@@ -15,9 +16,9 @@ export const MyQueryClientProvider: FC<{
}> = ({ children, dehydratedState }) => {
const [queryClient] = useState(createQueryClient());
hydrate(queryClient, dehydratedState);
return (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
<QueryClientProvider client={queryClient}>
<HydrationBoundary state={dehydratedState}>{children}</HydrationBoundary>
</QueryClientProvider>
);
};

View File

@@ -0,0 +1,20 @@
import { MutationCache, QueryCache, QueryClient } from "@tanstack/react-query";
export const createQueryClientForServer = () => new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
retry: 0,
},
mutations: {
onError: (e) => console.log(e),
retry: 0,
},
},
queryCache: new QueryCache({
onError: (e) => console.log(e),
}),
mutationCache: new MutationCache({
onError: (e) => console.log(e),
}),
});