diff --git a/.husky/pre-commit b/.husky/pre-commit index 7c28348..6aa9ebf 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - npx lint-staged --allow-empty diff --git a/app/routes/org.program.$programId.templates.$templateId.delete.ts b/app/routes/org.program.$programId.templates.$templateId.delete.ts deleted file mode 100644 index fe85dca..0000000 --- a/app/routes/org.program.$programId.templates.$templateId.delete.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { Route } from "./+types/org.program.$programId.templates.$templateId.delete"; -import { redirect } from "react-router"; -import { requireAdminWithProgram } from "~/lib/auth.server"; -import { deleteTemplate } from "~/lib/template.server"; - -export async function action({ request, params }: Route.ActionArgs) { - await requireAdminWithProgram(request, Number(params.programId)); - - await deleteTemplate(Number(params.templateId), Number(params.programId)); - - return redirect(`/org/program/${params.programId}/templates`); -} - -export async function loader({ params }: Route.LoaderArgs) { - return redirect(`/org/program/${params.programId}/templates/${params.templateId}/edit-meta`); -} - - -// @todo improve user-facing error handling with an ErrorBoundary and a Dialog diff --git a/app/routes/org.program.$programId.templates.$templateId.delete.tsx b/app/routes/org.program.$programId.templates.$templateId.delete.tsx new file mode 100644 index 0000000..d9bdf30 --- /dev/null +++ b/app/routes/org.program.$programId.templates.$templateId.delete.tsx @@ -0,0 +1,91 @@ +import { useEffect } from "react"; +import type { Route } from "./+types/org.program.$programId.templates.$templateId.delete"; +import { + isRouteErrorResponse, + redirect, + useNavigate, + useRouteError, + type ErrorResponse, +} from "react-router"; +import { requireAdminWithProgram } from "~/lib/auth.server"; +import { deleteTemplate } from "~/lib/template.server"; + +import { Button } from "~/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogFooter, + DialogTitle, +} from "~/components/ui/dialog"; + +export async function action({ request, params }: Route.ActionArgs) { + await requireAdminWithProgram(request, Number(params.programId)); + + await deleteTemplate(Number(params.templateId), Number(params.programId)); + + return redirect(`/org/program/${params.programId}/templates`); +} + +export async function loader({ params }: Route.LoaderArgs) { + return redirect( + `/org/program/${params.programId}/templates/${params.templateId}/edit-meta`, + ); +} + +export function ErrorBoundary() { + const error = useRouteError(); + const navigate = useNavigate(); + console.error(error); + + let additionalInfo = ""; + if (isRouteErrorResponse(error)) { + const routeError = error as ErrorResponse; + if (routeError.statusText.includes("P2003")) { + additionalInfo = + " Please delete all the certificates drived from this template before deleting the template."; + } + } + + useEffect(() => { + const down = (e: KeyboardEvent) => { + if (e.key === "Escape") { + e.preventDefault(); + navigate(-2); + } + }; + + document.addEventListener("keydown", down); + return () => document.removeEventListener("keydown", down); + }, [navigate]); + + return ( + { + if (!open) navigate(-2); + }} + > + + + Error + + The template could not be deleted. + {additionalInfo} + + + + + + + + + ); +}