diff --git a/packages/frontend/src/routes/Piece.tsx b/packages/frontend/src/routes/Piece.tsx
index 1774102..97ae063 100644
--- a/packages/frontend/src/routes/Piece.tsx
+++ b/packages/frontend/src/routes/Piece.tsx
@@ -2,16 +2,17 @@ import { client } from "@/client";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
-import { FileReducer } from "@/FileReducer";
import { useLoading } from "@/hooks/useLoading";
+import { Updater } from "@/hooks/useStore";
import { timeout } from "@/lib/utils";
import { Label } from "@radix-ui/react-label";
import type { Attachment, Piece } from "backend/database";
+import clsx from "clsx";
import { PieceId } from "common";
-import { ACCEPTED_EXTENSIONS } from "common/MediaType";
+import { getMediaTypeForFilename } from "common/MediaType";
import { ELYSIA_FORM_DATA } from "elysia";
-import { Download, Loader2, Trash } from "lucide-react";
-import { FormEventHandler, MouseEvent, useCallback, useId, useReducer, useRef, useState } from "react";
+import { Download, Loader2, Trash, UploadCloud } from "lucide-react";
+import { DragEventHandler, FormEventHandler, MouseEvent, useCallback, useId, useState } from "react";
import { Link, useParams } from "react-router-dom";
export function Piece() {
@@ -40,9 +41,9 @@ export function Piece() {
Utwór
Załączniki
-
+
-
+
>)}
);
@@ -143,6 +144,7 @@ namespace Attachments {
export interface Props {
readonly pieceId: PieceId;
readonly attachments: readonly Attachment[];
+ readonly setAttachments: Updater;
}
}
@@ -160,7 +162,13 @@ function Attachments(props: Attachments.Props) {
- {props.attachments.map((attachment) => )}
+ {props.attachments.map((attachment) => (
+
+ ))}
@@ -170,6 +178,7 @@ function Attachments(props: Attachments.Props) {
namespace AttachmentRow {
export interface Props {
readonly attachment: Attachment;
+ readonly setAttachments: Updater;
}
}
@@ -218,6 +227,22 @@ function AttachmentRow(props: AttachmentRow.Props) {
URL.revokeObjectURL(url);
}, [props.attachment.mediaType, props.attachment.attachmentId, props.attachment.pieceId]);
+ const doDelete = useCallback(async () => {
+
+ const { error } = await client
+ .piece({ pieceId: props.attachment.pieceId })
+ .attachment({ attachmentId: props.attachment.attachmentId })
+ .delete();
+
+ if (error !== null) {
+ console.error(error.value);
+ return;
+ }
+
+ props.setAttachments((prev) => prev.filter((a) => a.attachmentId !== props.attachment.attachmentId));
+
+ }, [props.attachment.attachmentId, props.attachment.pieceId]);
+
return (
@@ -246,7 +271,7 @@ function AttachmentRow(props: AttachmentRow.Props) {
-
@@ -257,86 +282,75 @@ function AttachmentRow(props: AttachmentRow.Props) {
namespace AttachmentForm {
export interface Props {
readonly pieceId: PieceId;
+ readonly setAttachments: Updater;
}
}
function AttachmentForm(props: AttachmentForm.Props) {
- const [{ filename, mediaType, file }, reduce] = useReducer(FileReducer, FileReducer.initial);
-
- const filenameId = useId();
- const mediaTypeId = useId();
- const fileId = useId();
-
- const fileInputRef = useRef(null);
-
const [isLoading, setIsLoading] = useState(false);
- const onSubmit: FormEventHandler = async (e) => {
+ const onDragOver: DragEventHandler = async (e) => {
+ e.preventDefault();
+ e.dataTransfer.dropEffect = "copy";
+ };
+
+ const onDrop: DragEventHandler = async (e) => {
e.preventDefault();
+ if (isLoading) {
+ return;
+ }
+
+ const delay = timeout(250);
try {
setIsLoading(true);
- const { error } = await client.piece({ pieceId: props.pieceId }).attachment.post({
- filename,
- mediaType,
- data: file!,
- });
+ for (const file of e.dataTransfer.files) {
+ const mediaType = getMediaTypeForFilename(file.name);
+ if (mediaType === undefined) {
+ continue;
+ }
- if (error) {
- console.error(error.value);
- return;
- }
+ const { data, error } = await client.piece({ pieceId: props.pieceId }).attachment.post({
+ filename: file.name,
+ mediaType,
+ data: file,
+ });
- reduce(FileReducer.reset);
- if (fileInputRef.current !== null) {
- fileInputRef.current.files = null;
+ if (error !== null) {
+ console.error(error.value);
+ continue;
+ }
+
+ props.setAttachments((prev) => {
+ const next = [...prev, data];
+ next.sort((a, b) => a.filename.localeCompare(b.filename));
+ return next;
+ });
}
} finally {
+ await delay;
setIsLoading(false);
}
}
return (
-
+
+ {isLoading ? (<>
+
+
Wysyłanie załączników…
+ >) : (<>
+
+
Przeciągnij i upuść tutaj załączniki
+ >)}
+
);
}