add confirm button for dangerous admin actions

This commit is contained in:
Brandon Egger 2023-09-05 20:27:33 -05:00
parent 8b42377453
commit f66c35a225
4 changed files with 88 additions and 11 deletions

View File

@ -1,4 +1,6 @@
import { ExclamationCircleIcon } from "@heroicons/react/24/solid";
import Link from "next/link"; import Link from "next/link";
import { useEffect, useState } from "react";
const AdminActionBody = ({ const AdminActionBody = ({
label, label,
@ -38,6 +40,53 @@ const AdminActionLink = ({
); );
}; };
const AdminActionConfirmButton = ({
label,
onConfirm,
symbol,
type = "button",
}: {
label: string;
onConfirm?: () => void;
symbol: JSX.Element | undefined;
type?: HTMLButtonElement["type"];
}) => {
const [isConfirmView, setConfirmView] = useState(false);
useEffect(() => {
if (!isConfirmView) {
return;
}
setTimeout(() => {
if (isConfirmView) {
setConfirmView(false);
}
}, 5000);
}, [isConfirmView]);
if (isConfirmView) {
return (
<AdminActionButton
symbol={<ExclamationCircleIcon className="w-4 animate-ping" />}
label={`Confirm ${label}`}
onClick={onConfirm}
type={type}
/>
);
}
return (
<AdminActionButton
symbol={symbol}
label={label}
onClick={() => {
setConfirmView(true);
}}
/>
);
};
const AdminActionButton = ({ const AdminActionButton = ({
label, label,
onClick, onClick,
@ -65,4 +114,4 @@ const AdminActionButton = ({
); );
}; };
export { AdminActionLink, AdminActionButton }; export { AdminActionLink, AdminActionButton, AdminActionConfirmButton };

View File

@ -1,6 +1,9 @@
import { XCircleIcon } from "@heroicons/react/20/solid"; import { XCircleIcon } from "@heroicons/react/20/solid";
import { AdminBarLayout } from "~/components/admin/ControlBar"; import { AdminBarLayout } from "~/components/admin/ControlBar";
import { AdminActionButton, AdminActionLink } from "~/components/admin/common"; import {
AdminActionButton,
AdminActionConfirmButton,
} from "~/components/admin/common";
import Image from "next/image"; import Image from "next/image";
import { import {
ResourceForm, ResourceForm,
@ -87,11 +90,15 @@ const EditResourcePage = () => {
onSubmit(formMethods.getValues()); onSubmit(formMethods.getValues());
}} }}
/>, />,
<AdminActionLink <AdminActionConfirmButton
key="cancel" key="cancel"
symbol={<XCircleIcon className="w-4" />} symbol={<XCircleIcon className="w-4" />}
label="Cancel" label="Cancel"
href={`/resources/${data.id}`} onConfirm={() => {
router.push(`/resources/${data.id}`).catch((error) => {
console.error(error);
});
}}
/>, />,
]} ]}
> >

View File

@ -6,10 +6,14 @@ import { type AuditoryResource, type PlatformLink } from "@prisma/client";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import { AdminBarLayout } from "~/components/admin/ControlBar"; import { AdminBarLayout } from "~/components/admin/ControlBar";
import { AdminActionLink } from "~/components/admin/common"; import {
AdminActionConfirmButton,
AdminActionLink,
} from "~/components/admin/common";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { HeaderFooterLayout } from "~/layouts/HeaderFooterLayout"; import { HeaderFooterLayout } from "~/layouts/HeaderFooterLayout";
import { QueryWaitWrapper } from "~/components/LoadingWrapper"; import { QueryWaitWrapper } from "~/components/LoadingWrapper";
import { TrashIcon } from "@heroicons/react/24/outline";
export const PlatformLinkButton = ({ export const PlatformLinkButton = ({
platformLink, platformLink,
@ -122,13 +126,23 @@ const ResourceViewPage = () => {
return ( return (
<HeaderFooterLayout> <HeaderFooterLayout>
<AdminBarLayout <AdminBarLayout
actions={ actions={[
<AdminActionLink <AdminActionLink
key="edit"
symbol={<PencilSquareIcon className="w-4" />} symbol={<PencilSquareIcon className="w-4" />}
label="Edit Page" label="Edit Page"
href={`${router.asPath}/edit`} href={`${router.asPath}/edit`}
/> />,
} <AdminActionConfirmButton
key="delete"
label="Delete"
symbol={<TrashIcon className="w-4" />}
onConfirm={() => {
// todo
console.log("deleting");
}}
/>,
]}
> >
<div className="mb-12"> <div className="mb-12">
<QueryWaitWrapper query={resourceQuery} Render={ConditionalView} /> <QueryWaitWrapper query={resourceQuery} Render={ConditionalView} />

View File

@ -7,7 +7,10 @@ import {
type UseFormReturn, type UseFormReturn,
} from "react-hook-form"; } from "react-hook-form";
import { AdminBarLayout } from "~/components/admin/ControlBar"; import { AdminBarLayout } from "~/components/admin/ControlBar";
import { AdminActionButton, AdminActionLink } from "~/components/admin/common"; import {
AdminActionButton,
AdminActionConfirmButton,
} from "~/components/admin/common";
import { import {
type ResourceCreateInput, type ResourceCreateInput,
ResourceForm, ResourceForm,
@ -55,11 +58,15 @@ const EditResourcePage = () => {
.catch((error) => console.error(error)); .catch((error) => console.error(error));
}} }}
/>, />,
<AdminActionLink <AdminActionConfirmButton
key="cancel" key="cancel"
symbol={<XCircleIcon className="w-4" />} symbol={<XCircleIcon className="w-4" />}
label="Cancel" label="Cancel"
href={`/resources`} onConfirm={() => {
router.push("/resources").catch((error) => {
console.error(error);
});
}}
/>, />,
]} ]}
> >