chore: components cleanup
This commit is contained in:
@@ -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
@@ -1,41 +1,12 @@
|
|||||||
import DeleteIcon from "@mui/icons-material/Delete";
|
import { Alert, Box, CircularProgress, Typography } from "@mui/material";
|
||||||
import {
|
|
||||||
Alert,
|
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
CircularProgress,
|
|
||||||
Dialog,
|
|
||||||
DialogActions,
|
|
||||||
DialogContent,
|
|
||||||
DialogContentText,
|
|
||||||
DialogTitle,
|
|
||||||
IconButton,
|
|
||||||
Table,
|
|
||||||
TableBody,
|
|
||||||
TableCell,
|
|
||||||
TableContainer,
|
|
||||||
TableHead,
|
|
||||||
TableRow,
|
|
||||||
Typography,
|
|
||||||
} from "@mui/material";
|
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { createFileRoute } from "@tanstack/react-router";
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
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 { RouterButton } from "../components/RouterButton";
|
||||||
import { useBoolean } from "../components/use-boolean";
|
import { useBoolean } from "../components/use-boolean";
|
||||||
|
import { type Announcement, getAnnouncements } from "../services";
|
||||||
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];
|
|
||||||
|
|
||||||
export const Route = createFileRoute("/")({
|
export const Route = createFileRoute("/")({
|
||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
@@ -45,13 +16,7 @@ function RouteComponent() {
|
|||||||
// the query to retrieve the announcements
|
// the query to retrieve the announcements
|
||||||
const announcementsQuery = useQuery({
|
const announcementsQuery = useQuery({
|
||||||
queryKey: ["announcements"],
|
queryKey: ["announcements"],
|
||||||
queryFn: async () => {
|
queryFn: getAnnouncements,
|
||||||
const response = await fetch("/api/announcements");
|
|
||||||
const data = await response.json();
|
|
||||||
const announcements = Announcements.parse(data);
|
|
||||||
console.log(announcements);
|
|
||||||
return announcements;
|
|
||||||
},
|
|
||||||
retry: false,
|
retry: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -100,56 +65,18 @@ function RouteComponent() {
|
|||||||
<Alert severity="error">Error (see console)</Alert>
|
<Alert severity="error">Error (see console)</Alert>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<TableContainer>
|
<AnnouncementTable
|
||||||
<Table>
|
announcements={announcementsQuery.data}
|
||||||
<TableHead>
|
openDeleteConfirmation={openDeleteConfirmation}
|
||||||
<TableRow>
|
/>
|
||||||
<TableCell />
|
{announcementForLatestDeleteAttempt && (
|
||||||
<TableCell>Title</TableCell>
|
<DeleteAnnouncementDialog
|
||||||
<TableCell>Text</TableCell>
|
announcement={announcementForLatestDeleteAttempt}
|
||||||
<TableCell>Publication Date</TableCell>
|
confirmDelete={closeDeleteConfirmation}
|
||||||
<TableCell />
|
denyDelete={closeDeleteConfirmation}
|
||||||
</TableRow>
|
isDeleteConfirmationOpen={isDeleteConfirmationOpen}
|
||||||
</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>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user