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 { 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 { getMediaTypeForFilename } from "common/MediaType";
import { ELYSIA_FORM_DATA } from "elysia";
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() {
const id = PieceId(useParams().pieceId!);
const piece = useLoading(() => client.piece.get({ query: { id } }));
const attachments = useLoading(() => client.piece({ pieceId: id }).attachment.get());
if (piece.isLoading || attachments.isLoading) {
return (
);
}
return (
{piece.error !== null || attachments.error !== null ? (
`Wystąpił błąd: ${[piece.error?.value, attachments.error?.value].filter(Boolean).join(", ")}`
) : piece.data[0] === undefined ? (
"Utwór nie istnieje"
) : (<>
>)}
);
}
namespace PieceForm {
export interface Props {
readonly piece: Piece;
}
}
function PieceForm(props: PieceForm.Props) {
const [name, setName] = useState(props.piece.name);
const [composer, setComposer] = useState(props.piece.composer ?? "");
const [lyricist, setLyricist] = useState(props.piece.lyricist ?? "");
const [arranger, setArranger] = useState(props.piece.arranger ?? "");
const nameId = useId();
const composerId = useId();
const lyricistId = useId();
const arrangerId = useId();
const [isLoading, setIsLoading] = useState(false);
const onSubmit: FormEventHandler = async (e) => {
e.preventDefault();
const delay = timeout(250);
try {
setIsLoading(true);
const { error } = await client.piece({ pieceId: props.piece.pieceId }).put({
name,
composer: composer.length > 0 ? composer : null,
lyricist: lyricist.length > 0 ? lyricist : null,
arranger: arranger.length > 0 ? arranger : null,
});
if (error) {
console.error(error.value);
return;
}
} finally {
await delay;
setIsLoading(false);
}
}
return (
);
}
namespace Attachments {
export interface Props {
readonly pieceId: PieceId;
readonly attachments: readonly Attachment[];
readonly setAttachments: Updater;
}
}
function Attachments(props: Attachments.Props) {
return (
Nazwa pliku
Typ
Dodano
Zmodyfikowano
Akcje
{props.attachments.map((attachment) => (
))}
);
}
namespace AttachmentRow {
export interface Props {
readonly attachment: Attachment;
readonly setAttachments: Updater;
}
}
function AttachmentRow(props: AttachmentRow.Props) {
const download = useCallback(async () => {
const { error, data: _data } = await client
.piece({ pieceId: props.attachment.pieceId })
.attachment({ attachmentId: props.attachment.attachmentId })
.get();
if (error !== null) {
console.error(error.value);
return;
}
const data = _data as unknown as typeof _data[ELYSIA_FORM_DATA];
const url = URL.createObjectURL(data.data);
const a = document.createElement("a");
a.href = url;
a.download = data.filename;
a.click();
URL.revokeObjectURL(url);
}, [props.attachment.attachmentId, props.attachment.pieceId]);
const open = useCallback(async (event: MouseEvent) => {
if (props.attachment.mediaType !== "application/pdf") {
return;
}
event.preventDefault();
const { error, data: _data } = await client
.piece({ pieceId: props.attachment.pieceId })
.attachment({ attachmentId: props.attachment.attachmentId })
.get();
if (error !== null) {
console.error(error.value);
return;
}
const data = _data as unknown as typeof _data[ELYSIA_FORM_DATA];
const url = URL.createObjectURL(data.data);
window.open(url, "_target");
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 (
{props.attachment.mediaType === "application/vnd.recordare.musicxml"
|| props.attachment.mediaType === "application/vnd.recordare.musicxml+xml"
|| props.attachment.mediaType === "application/pdf" ? (
{props.attachment.filename}
) : (
props.attachment.filename
)}
{props.attachment.mediaType}
{props.attachment.createdAt}
{props.attachment.createdBy !== null && <>
przez {props.attachment.createdBy}>}
{props.attachment.modifiedAt === null && props.attachment.modifiedBy === null ? "\u2014"
: props.attachment.modifiedAt !== null && props.attachment.modifiedBy === null ? props.attachment.modifiedAt
: props.attachment.modifiedAt === null ? `przez ${props.attachment.createdBy}`
: <>{props.attachment.createdAt}
przez {props.attachment.createdBy}>}
);
}
namespace AttachmentForm {
export interface Props {
readonly pieceId: PieceId;
readonly setAttachments: Updater;
}
}
function AttachmentForm(props: AttachmentForm.Props) {
const [isLoading, setIsLoading] = useState(false);
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);
for (const file of e.dataTransfer.files) {
const mediaType = getMediaTypeForFilename(file.name);
if (mediaType === undefined) {
continue;
}
const { data, error } = await client.piece({ pieceId: props.pieceId }).attachment.post({
filename: file.name,
mediaType,
data: file,
});
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
>)}
);
}