chore: components cleanup

This commit is contained in:
redglow
2026-06-21 14:29:29 +02:00
parent fb79565e27
commit 3d91bf0a63
5 changed files with 157 additions and 90 deletions
@@ -0,0 +1,45 @@
import {
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
} from "@mui/material";
import type { Announcement } from "../services";
import { AnnouncementTableRow } from "./AnnouncementTableRow";
export interface AnnouncementTableProps {
announcements: Announcement[];
openDeleteConfirmation(announcement: Announcement): void;
}
export function AnnouncementTable({
announcements,
openDeleteConfirmation,
}: AnnouncementTableProps) {
return (
<TableContainer>
<Table>
<TableHead>
<TableRow>
<TableCell />
<TableCell>Title</TableCell>
<TableCell>Text</TableCell>
<TableCell>Publication Date</TableCell>
<TableCell />
</TableRow>
</TableHead>
<TableBody>
{announcements.map((a) => (
<AnnouncementTableRow
key={a.id}
announcement={a}
openDeleteConfirmation={openDeleteConfirmation}
/>
))}
</TableBody>
</Table>
</TableContainer>
);
}
@@ -0,0 +1,30 @@
import DeleteIcon from "@mui/icons-material/Delete";
import { IconButton, TableCell, TableRow } from "@mui/material";
import type { Announcement } from "../services";
export interface AnnouncementTableRowProps {
announcement: Announcement;
openDeleteConfirmation(announcement: Announcement): void;
}
export function AnnouncementTableRow({
openDeleteConfirmation,
announcement,
}: AnnouncementTableRowProps) {
return (
<TableRow>
<TableCell>{announcement.id}</TableCell>
<TableCell>{announcement.title}</TableCell>
<TableCell>
{announcement.text.substring(0, 50) +
(announcement.text.length > 50 ? "..." : "")}
</TableCell>
<TableCell>{announcement.publication_date.toString()}</TableCell>
<TableCell>
<IconButton onClick={() => openDeleteConfirmation(announcement)}>
<DeleteIcon />
</IconButton>
</TableCell>
</TableRow>
);
}
@@ -0,0 +1,45 @@
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
} from "@mui/material";
import type { Announcement } from "../services";
export interface DeleteAnnouncementDialogProps {
isDeleteConfirmationOpen: boolean;
denyDelete(): void;
confirmDelete(): void;
announcement: Announcement;
}
export function DeleteAnnouncementDialog({
announcement,
confirmDelete,
denyDelete,
isDeleteConfirmationOpen,
}: DeleteAnnouncementDialogProps) {
return (
<Dialog
open={isDeleteConfirmationOpen}
onClose={denyDelete}
role="alertdialog"
>
<DialogTitle>Delete announcement</DialogTitle>
<DialogContent>
<DialogContentText>
Do you want to delete the announcement{" "}
<strong>{announcement.title}</strong>?
</DialogContentText>
<DialogActions>
<Button onClick={denyDelete} autoFocus>
No
</Button>
<Button onClick={confirmDelete}>Yes</Button>
</DialogActions>
</DialogContent>
</Dialog>
);
}
+17 -90
View File
@@ -1,41 +1,12 @@
import DeleteIcon from "@mui/icons-material/Delete";
import {
Alert,
Box,
Button,
CircularProgress,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
IconButton,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Typography,
} from "@mui/material";
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 z from "zod";
import { AnnouncementTable } from "../components/AnnouncementTable";
import { DeleteAnnouncementDialog } from "../components/DeleteAnnouncementDialog";
import { RouterButton } from "../components/RouterButton";
import { useBoolean } from "../components/use-boolean";
const Announcements = z.array(
z.object({
id: z.number(),
title: z.string(),
text: z.string(),
publication_date: z.iso.datetime().transform((arg) => new Date(arg)),
image: z.string(),
}),
);
type Announcement = z.infer<typeof Announcements>[0];
import { type Announcement, getAnnouncements } from "../services";
export const Route = createFileRoute("/")({
component: RouteComponent,
@@ -45,13 +16,7 @@ function RouteComponent() {
// the query to retrieve the announcements
const announcementsQuery = useQuery({
queryKey: ["announcements"],
queryFn: async () => {
const response = await fetch("/api/announcements");
const data = await response.json();
const announcements = Announcements.parse(data);
console.log(announcements);
return announcements;
},
queryFn: getAnnouncements,
retry: false,
});
@@ -100,56 +65,18 @@ function RouteComponent() {
<Alert severity="error">Error (see console)</Alert>
) : (
<>
<TableContainer>
<Table>
<TableHead>
<TableRow>
<TableCell />
<TableCell>Title</TableCell>
<TableCell>Text</TableCell>
<TableCell>Publication Date</TableCell>
<TableCell />
</TableRow>
</TableHead>
<TableBody>
{announcementsQuery.data.map((a) => (
<TableRow key={a.id}>
<TableCell>{a.id}</TableCell>
<TableCell>{a.title}</TableCell>
<TableCell>
{a.text.substring(0, 50) +
(a.text.length > 50 ? "..." : "")}
</TableCell>
<TableCell>{a.publication_date.toString()}</TableCell>
<TableCell>
<IconButton onClick={() => openDeleteConfirmation(a)}>
<DeleteIcon />
</IconButton>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<Dialog
open={isDeleteConfirmationOpen}
onClose={closeDeleteConfirmation}
role="alertdialog"
>
<DialogTitle>Delete announcement</DialogTitle>
<DialogContent>
<DialogContentText>
Do you want to delete the announcement{" "}
<strong>{announcementForLatestDeleteAttempt?.title}</strong>?
</DialogContentText>
<DialogActions>
<Button onClick={closeDeleteConfirmation} autoFocus>
No
</Button>
<Button onClick={closeDeleteConfirmation}>Yes</Button>
</DialogActions>
</DialogContent>
</Dialog>
<AnnouncementTable
announcements={announcementsQuery.data}
openDeleteConfirmation={openDeleteConfirmation}
/>
{announcementForLatestDeleteAttempt && (
<DeleteAnnouncementDialog
announcement={announcementForLatestDeleteAttempt}
confirmDelete={closeDeleteConfirmation}
denyDelete={closeDeleteConfirmation}
isDeleteConfirmationOpen={isDeleteConfirmationOpen}
/>
)}
</>
)}
</Box>
+20
View File
@@ -0,0 +1,20 @@
import z from "zod";
const Announcements = z.array(
z.object({
id: z.number(),
title: z.string(),
text: z.string(),
publication_date: z.iso.datetime().transform((arg) => new Date(arg)),
image: z.string(),
}),
);
export type Announcement = z.infer<typeof Announcements>[0];
export async function getAnnouncements() {
const response = await fetch("/api/announcements");
const data = await response.json();
const announcements = Announcements.parse(data);
return announcements;
}