Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve error handling #194

Merged
merged 15 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 24 additions & 20 deletions frontend/src/EditTimetable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
useQuery,
useQueryClient,
} from "@tanstack/react-query";
import { ErrorComponent, Route } from "@tanstack/react-router";
import { ErrorComponent, Route, notFound } from "@tanstack/react-router";
import axios, { AxiosError } from "axios";
import {
AlertOctagon,
Expand All @@ -36,6 +36,7 @@ import {
} from "../../lib/src";
import { userWithTimetablesType } from "../../lib/src/index";
import authenticatedRoute from "./AuthenticatedRoute";
import NotFound from "./components/NotFound";
import { TimetableGrid } from "./components/TimetableGrid";
import { SideMenu } from "./components/side-menu";
import Spinner from "./components/spinner";
Expand Down Expand Up @@ -148,32 +149,24 @@ const editTimetableRoute = new Route({
});
}

if (
error instanceof AxiosError &&
error.response &&
error.response.status === 404
) {
throw notFound();
}

throw error;
}),
component: EditTimetable,
notFoundComponent: NotFound,
errorComponent: ({ error }) => {
const { toast } = useToast();

if (error instanceof AxiosError) {
if (error.response) {
switch (error.response.status) {
case 404:
toast({
title: "Error",
description:
"message" in error.response.data
? error.response.data.message
: "API returned 404",
variant: "destructive",
action: (
<ToastAction altText="Report issue: https://github.com/crux-bphc/chronofactorem-rewrite/issues">
<a href="https://github.com/crux-bphc/chronofactorem-rewrite/issues">
Report
</a>
</ToastAction>
),
});
break;
case 500:
toast({
title: "Server Error",
Expand Down Expand Up @@ -905,8 +898,15 @@ function EditTimetable() {
</Tooltip>
)}
<Tooltip>
<TooltipTrigger asChild>
<TooltipTrigger
className={
timetableQueryResult.data.archived
? "cursor-not-allowed"
: ""
}
>
<Button
disabled={timetableQueryResult.data.archived}
variant="ghost"
className="rounded-full p-3"
onClick={() => {
Expand All @@ -923,7 +923,11 @@ function EditTimetable() {
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Copy Timetable</p>
<p>
{timetableQueryResult.data.archived
? "Cannot copy archived timetable"
: "Copy Timetable"}
</p>
</TooltipContent>
</Tooltip>
{userQueryResult.data.id ===
Expand Down
12 changes: 0 additions & 12 deletions frontend/src/NotFound.tsx

This file was deleted.

59 changes: 37 additions & 22 deletions frontend/src/ViewTimetable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
useQuery,
useQueryClient,
} from "@tanstack/react-query";
import { ErrorComponent, Route } from "@tanstack/react-router";
import { ErrorComponent, Route, notFound } from "@tanstack/react-router";
import axios, { AxiosError } from "axios";
import { toPng } from "html-to-image";
import {
Expand All @@ -29,6 +29,7 @@ import {
} from "../../lib/src/index";
import { userWithTimetablesType } from "../../lib/src/index";
import authenticatedRoute from "./AuthenticatedRoute";
import NotFound from "./components/NotFound";
import { TimetableGrid } from "./components/TimetableGrid";
import { SideMenu } from "./components/side-menu";
import Spinner from "./components/spinner";
Expand Down Expand Up @@ -147,32 +148,24 @@ const viewTimetableRoute = new Route({
});
}

if (
error instanceof AxiosError &&
error.response &&
error.response.status === 404
) {
throw notFound();
}

throw error;
}),
component: ViewTimetable,
notFoundComponent: NotFound,
errorComponent: ({ error }) => {
const { toast } = useToast();

if (error instanceof AxiosError) {
if (error.response) {
switch (error.response.status) {
case 404:
toast({
title: "Error",
description:
"message" in error.response.data
? error.response.data.message
: "API returned 404",
variant: "destructive",
action: (
<ToastAction altText="Report issue: https://github.com/crux-bphc/chronofactorem-rewrite/issues">
<a href="https://github.com/crux-bphc/chronofactorem-rewrite/issues">
Report
</a>
</ToastAction>
),
});
break;
case 500:
toast({
title: "Server Error",
Expand Down Expand Up @@ -910,8 +903,15 @@ function ViewTimetable() {
{userQueryResult.data.id ===
timetableQueryResult.data.authorId && (
<Tooltip>
<TooltipTrigger asChild>
<TooltipTrigger
className={
timetableQueryResult.data.archived
? "cursor-not-allowed"
: ""
}
>
<Button
disabled={timetableQueryResult.data.archived}
variant="ghost"
className="rounded-full p-3"
onClick={() =>
Expand All @@ -926,13 +926,24 @@ function ViewTimetable() {
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Edit Timetable</p>
<p>
{timetableQueryResult.data.archived
? "Cannot edit archived timetable"
: "Edit Timetable"}
</p>
</TooltipContent>
</Tooltip>
)}
<Tooltip>
<TooltipTrigger asChild>
<TooltipTrigger
className={
timetableQueryResult.data.archived
? "cursor-not-allowed"
: ""
}
>
<Button
disabled={timetableQueryResult.data.archived}
variant="ghost"
className="rounded-full p-3"
onClick={() => {
Expand All @@ -946,7 +957,11 @@ function ViewTimetable() {
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Copy Timetable</p>
<p>
{timetableQueryResult.data.archived
? "Cannot copy archived timetable"
: "Copy Timetable"}
</p>
</TooltipContent>
</Tooltip>
{userQueryResult.data.id ===
Expand Down
24 changes: 24 additions & 0 deletions frontend/src/components/NotFound.tsx
skoriop marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { router } from "../main";

const NotFound = () => (
<div className="h-[calc(100vh-68px)] w-full flex flex-col justify-center items-center">
<h1 className="text-9xl font-extrabold text-white tracking-widest">404</h1>
<div className="bg-[#FF6A3D] px-2 text-sm rounded rotate-12 absolute">
Page Not Found
</div>
<div className="mt-5">
<div className="relative inline-block text-sm font-medium text-[#FF6A3D] group active:text-orange-500 focus:outline-none focus:ring">
<span className="absolute inset-0 transition-transform translate-x-0.5 translate-y-0.5 bg-[#FF6A3D] group-hover:translate-y-0 group-hover:translate-x-0" />

{/* <span
onClick={() => router.navigate({ to: "/" })}
className="cursor-pointer relative block px-8 py-3 bg-[#1A2238] border border-current"
>
skoriop marked this conversation as resolved.
Show resolved Hide resolved
GO HOME
</span> */}
</div>
</div>
</div>
);

export default NotFound;
8 changes: 4 additions & 4 deletions frontend/src/components/announcements.tsx
skoriop marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import axios from "axios";
import { DialogTrigger } from "@radix-ui/react-dialog";
import { Megaphone } from "lucide-react";
import type { z } from "zod";
import type { announcementType } from "../../../lib/src";
import { announcementType } from "../../../lib/src";
import { Button } from "./ui/button";

const fetchAnnouncements = async (): Promise<
z.infer<typeof announcementType>[]
> => {
const response = await axios.get<z.infer<typeof announcementType>[]>(
"api/user/announcements",
"/api/user/announcements",
);
return response.data;
};
Expand All @@ -42,9 +42,9 @@ function Announcements() {
</DialogHeader>
<DialogDescription asChild>
<div className="flex flex-col-reverse mx-3 mt-1 gap-3 divide-y divide-y-reverse">
{announcements?.length ? (
{Array.isArray(announcements) && announcements?.length ? (
skoriop marked this conversation as resolved.
Show resolved Hide resolved
announcements
.sort(
?.sort(
skoriop marked this conversation as resolved.
Show resolved Hide resolved
(a, b) =>
new Date(a.createdAt as string).getTime() -
new Date(b.createdAt as string).getTime(),
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ import finalizeTimetableRoute from "./FinalizeTimetable";
import getDegreesRoute from "./GetDegrees";
import homeRoute from "./Home";
import loginRoute from "./Login";
import notFoundRoute from "./NotFound";
import RootComponent from "./RootComponent";
import viewTimetableRoute from "./ViewTimetable";
import NotFound from "./components/NotFound";
import "./index.css";

const queryClient = new QueryClient({
Expand Down Expand Up @@ -63,7 +63,7 @@ export const router = new Router({
context: {
queryClient,
},
notFoundRoute: notFoundRoute,
defaultNotFoundComponent: NotFound,
});

// Register things for typesafety
Expand Down
6 changes: 3 additions & 3 deletions lib/src/zodFieldTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ export const namedTimetableIDType = (name?: string) =>
invalid_type_error: addNameToString("timetable id not a string", name),
required_error: addNameToString("timetable id is required", name),
})
.min(4, {
message: addNameToString("timetable id is an invalid id", name),
});
// .min(4, {
// message: addNameToString("timetable id is an invalid id", name),
// });

export const timetableIDType = namedTimetableIDType();

Expand Down
Loading