feat: image preview
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
import CloudUploadIcon from "@mui/icons-material/CloudUpload";
|
||||
import {
|
||||
Button,
|
||||
FormLabel,
|
||||
TextareaAutosize,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { Box, styled } from "@mui/system";
|
||||
import { DatePicker } from "@mui/x-date-pickers";
|
||||
import { type ChangeEvent, useState } from "react";
|
||||
import type { Announcement } from "../services";
|
||||
|
||||
const VisuallyHiddenInput = styled("input")({
|
||||
clip: "rect(0 0 0 0)",
|
||||
clipPath: "inset(50%)",
|
||||
height: 1,
|
||||
overflow: "hidden",
|
||||
position: "absolute",
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
whiteSpace: "nowrap",
|
||||
width: 1,
|
||||
});
|
||||
|
||||
export interface AddOrEditAnnouncementProps {
|
||||
announcement?: Announcement;
|
||||
}
|
||||
|
||||
function blobToDataURL(blob: Blob): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (_e) => resolve(reader.result as string);
|
||||
reader.onerror = (_e) => reject(reader.error);
|
||||
reader.onabort = (_e) => reject(new Error("Read aborted"));
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
|
||||
export function AddOrEditAnnouncement({
|
||||
announcement,
|
||||
}: AddOrEditAnnouncementProps) {
|
||||
const [currentImageUrl, setCurrentImageUrl] = useState<string | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
return (
|
||||
<Box
|
||||
component="form"
|
||||
encType="multipart/form-data"
|
||||
action="/api/announcements"
|
||||
method="POST"
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
"& > :not(style)": { m: 1, width: "25ch" },
|
||||
}}
|
||||
noValidate
|
||||
autoComplete="off"
|
||||
>
|
||||
<TextField
|
||||
name="title"
|
||||
label="Title"
|
||||
defaultValue={announcement?.title}
|
||||
></TextField>
|
||||
<FormLabel>Text:</FormLabel>
|
||||
<TextareaAutosize
|
||||
name="text"
|
||||
minRows={6}
|
||||
defaultValue={announcement?.text}
|
||||
/>
|
||||
<FormLabel>Publication Date:</FormLabel>
|
||||
<DatePicker
|
||||
name="publication_date"
|
||||
defaultValue={
|
||||
announcement ? new Date(announcement.publication_date) : undefined
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
component="label"
|
||||
variant="contained"
|
||||
tabIndex={-1}
|
||||
startIcon={<CloudUploadIcon />}
|
||||
>
|
||||
Upload files
|
||||
<VisuallyHiddenInput
|
||||
type="file"
|
||||
name="image"
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
console.log(event.target.files);
|
||||
const file =
|
||||
event.target.files && event.target.files.length > 0
|
||||
? event.target.files[0]
|
||||
: undefined;
|
||||
if (file === undefined) {
|
||||
setCurrentImageUrl(undefined);
|
||||
return;
|
||||
}
|
||||
blobToDataURL(file).then(setCurrentImageUrl).catch(console.error);
|
||||
}}
|
||||
/>
|
||||
</Button>
|
||||
<Typography>Current image:</Typography>
|
||||
{currentImageUrl ? (
|
||||
<img src={currentImageUrl} alt="Current" />
|
||||
) : (
|
||||
<Typography>None</Typography>
|
||||
)}
|
||||
<Button variant="contained" type="submit">
|
||||
Submit
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user