feat: delete implementation
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { deleteAnnouncement, getAnnouncements } from "./services";
|
||||
|
||||
const announcementsQueryKey = ["announcements"];
|
||||
|
||||
export function useAnnouncementsQuery() {
|
||||
const announcementsQuery = useQuery({
|
||||
queryKey: announcementsQueryKey,
|
||||
queryFn: getAnnouncements,
|
||||
retry: false,
|
||||
});
|
||||
|
||||
return announcementsQuery;
|
||||
}
|
||||
|
||||
export function useDeleteAnnouncementMutation() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
async mutationFn(announcementId: number) {
|
||||
await deleteAnnouncement(announcementId);
|
||||
},
|
||||
async onSuccess() {
|
||||
await queryClient.invalidateQueries({ queryKey: ["announcements"] });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,3 +1,9 @@
|
||||
import { QueryClient } from "@tanstack/react-query";
|
||||
import { QueryCache, QueryClient } from "@tanstack/react-query";
|
||||
|
||||
export const queryClient = new QueryClient();
|
||||
export const queryClient = new QueryClient({
|
||||
queryCache: new QueryCache({
|
||||
onError(error) {
|
||||
console.error(error);
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -32,7 +32,7 @@ function RouteComponent() {
|
||||
<Box
|
||||
component="form"
|
||||
enctype="multipart/form-data"
|
||||
action="/api/announcements/add"
|
||||
action="/api/announcements"
|
||||
method="POST"
|
||||
sx={{
|
||||
display: "flex",
|
||||
|
||||
+18
-15
@@ -1,31 +1,21 @@
|
||||
import { Alert, Box, CircularProgress, Typography } from "@mui/material";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { AnnouncementTable } from "../components/AnnouncementTable";
|
||||
import { DeleteAnnouncementDialog } from "../components/DeleteAnnouncementDialog";
|
||||
import { RouterButton } from "../components/RouterButton";
|
||||
import { useBoolean } from "../components/use-boolean";
|
||||
import { type Announcement, getAnnouncements } from "../services";
|
||||
import { useAnnouncementsQuery, useDeleteAnnouncementMutation } from "../hooks";
|
||||
import type { Announcement } from "../services";
|
||||
|
||||
export const Route = createFileRoute("/")({
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
// the query to retrieve the announcements
|
||||
const announcementsQuery = useQuery({
|
||||
queryKey: ["announcements"],
|
||||
queryFn: getAnnouncements,
|
||||
retry: false,
|
||||
});
|
||||
const announcementsQuery = useAnnouncementsQuery();
|
||||
|
||||
// log error only if we get one
|
||||
useEffect(() => {
|
||||
if (announcementsQuery.error) {
|
||||
console.log(announcementsQuery.error);
|
||||
}
|
||||
}, [announcementsQuery.error]);
|
||||
const deleteAnnouncementMutation = useDeleteAnnouncementMutation();
|
||||
|
||||
// delete confirmation dialog status
|
||||
const [
|
||||
@@ -40,6 +30,7 @@ function RouteComponent() {
|
||||
announcementForLatestDeleteAttempt,
|
||||
setAnnouncementForLatestDeleteAttempt,
|
||||
] = useState<Announcement | undefined>(undefined);
|
||||
|
||||
const openDeleteConfirmation = useCallback(
|
||||
(a: Announcement) => {
|
||||
openDeleteConfirmationDialog();
|
||||
@@ -48,6 +39,18 @@ function RouteComponent() {
|
||||
[openDeleteConfirmationDialog],
|
||||
);
|
||||
|
||||
const confirmDelete = useCallback(() => {
|
||||
closeDeleteConfirmation();
|
||||
if (announcementForLatestDeleteAttempt === undefined) {
|
||||
throw new Error("Cannot delete announcement without an attempt set.");
|
||||
}
|
||||
deleteAnnouncementMutation.mutate(announcementForLatestDeleteAttempt?.id);
|
||||
}, [
|
||||
announcementForLatestDeleteAttempt,
|
||||
closeDeleteConfirmation,
|
||||
deleteAnnouncementMutation.mutate,
|
||||
]);
|
||||
|
||||
// handle loading / error / show values
|
||||
return (
|
||||
<Box sx={{ flexDirection: "column", display: "flex", gap: "3em" }}>
|
||||
@@ -72,7 +75,7 @@ function RouteComponent() {
|
||||
{announcementForLatestDeleteAttempt && (
|
||||
<DeleteAnnouncementDialog
|
||||
announcement={announcementForLatestDeleteAttempt}
|
||||
confirmDelete={closeDeleteConfirmation}
|
||||
confirmDelete={confirmDelete}
|
||||
denyDelete={closeDeleteConfirmation}
|
||||
isDeleteConfirmationOpen={isDeleteConfirmationOpen}
|
||||
/>
|
||||
|
||||
@@ -18,3 +18,10 @@ export async function getAnnouncements() {
|
||||
const announcements = Announcements.parse(data);
|
||||
return announcements;
|
||||
}
|
||||
|
||||
export async function deleteAnnouncement(announcementId: number) {
|
||||
const response = await fetch(`/api/announcements/${announcementId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
await response.text();
|
||||
}
|
||||
|
||||
+14
-1
@@ -21,11 +21,15 @@ const AddInput = z.object({
|
||||
}),
|
||||
});
|
||||
|
||||
const DeleteInput = z.object({
|
||||
announcementId: z.coerce.number().positive(),
|
||||
});
|
||||
|
||||
app.get("/hello", (_, res) => {
|
||||
res.send("Hello Vite + React + TypeScript!");
|
||||
});
|
||||
|
||||
app.post("/api/announcements/add", upload.single("image"), async (req, res) => {
|
||||
app.post("/api/announcements", upload.single("image"), async (req, res) => {
|
||||
const addInput = AddInput.parse(req);
|
||||
await db
|
||||
.insertInto("announcements")
|
||||
@@ -49,6 +53,15 @@ app.get("/api/announcements", async (_, res) => {
|
||||
res.json(announcements);
|
||||
});
|
||||
|
||||
app.delete("/api/announcements/:announcementId", async (req, res) => {
|
||||
const { announcementId } = DeleteInput.parse(req.params);
|
||||
await db
|
||||
.deleteFrom("announcements")
|
||||
.where("id", "=", announcementId)
|
||||
.execute();
|
||||
res.status(204).send();
|
||||
});
|
||||
|
||||
ViteExpress.listen(app, 3000, () =>
|
||||
console.log("Server is listening on port 3000..."),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user