diff --git a/packages/frontend/src/routes/Attachment.tsx b/packages/frontend/src/routes/Attachment.tsx index d010512..ac5e54c 100644 --- a/packages/frontend/src/routes/Attachment.tsx +++ b/packages/frontend/src/routes/Attachment.tsx @@ -4,7 +4,7 @@ import { AttachmentId } from "common"; import { Match } from "effect"; import JSZip from "jszip"; import { OpenSheetMusicDisplay } from "opensheetmusicdisplay"; -import { useCallback, useEffect, useRef } from "react"; +import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react"; import { useParams } from "react-router-dom"; export default function Attachment() { @@ -14,19 +14,62 @@ export default function Attachment() { const { isLoading, error, data } = useLoading(client.getAttachment(attachmentId), [attachmentId]); + if (isLoading) { + return ( +
+
Ładowanie…
+
+ ); + } + + if (error !== null) { + return ( +
+
+ Wystąpił błąd: {Match.value(error).pipe( + Match.tag("FetchError", () => "Nie można połączyć się z serwerem"), + Match.tag("NotFound", () => "Załącznik nie istnieje"), + Match.tag("Unauthenticated", () => "Zaloguj się, aby kontynuować"), + Match.tag("Unauthorized", () => "Nie posiadasz uprawnień"), + Match.exhaustive, + )} +
+
+ ); + } + + if (data.mediaType === "application/vnd.recordare.musicxml" || data.mediaType === "application/vnd.recordare.musicxml+xml") { + return ; + } else if (data.mediaType === "application/pdf") { + return ; + } else { + return null; + } +}; + +namespace MusicXmlAttachment { + export interface Props { + readonly data: Uint8Array; + readonly mediaType: + | "application/vnd.recordare.musicxml" + | "application/vnd.recordare.musicxml+xml" + ; + } +} + +function MusicXmlAttachment({ data, mediaType }: MusicXmlAttachment.Props) { + const containerRef = useRef(null); const renderFn = useRef void)>(null); const load = useCallback(async () => { - if (isLoading || error !== null) return; - - let musixXmlData: Uint8Array = data.data; + let musixXmlData: Uint8Array = data; /* If the file is the compressed .mxl file, we do the uncompression * ourselves, because apparently OpenSheetMusicDisplay is incapable. */ - if (data.mediaType === "application/vnd.recordare.musicxml") { + if (mediaType === "application/vnd.recordare.musicxml") { const zip = new JSZip(); await zip.loadAsync(musixXmlData); @@ -78,7 +121,7 @@ export default function Attachment() { render(); renderFn.current = render; - }, [data, error, isLoading]); + }, [data]); useEffect(() => void load(), [load]); @@ -91,29 +134,39 @@ export default function Attachment() { }; }, []); - if (isLoading) { - return ( -
-
Ładowanie…
-
- ); - } - - if (error !== null) { - return ( -
-
- Wystąpił błąd: {Match.value(error).pipe( - Match.tag("FetchError", () => "Nie można połączyć się z serwerem"), - Match.tag("NotFound", () => "Załącznik nie istnieje"), - Match.tag("Unauthenticated", () => "Zaloguj się, aby kontynuować"), - Match.tag("Unauthorized", () => "Nie posiadasz uprawnień"), - Match.exhaustive, - )} -
-
- ); - } - return
; -}; +} + +namespace PdfAttachment { + export interface Props { + readonly data: Uint8Array; + readonly filename: string; + readonly mediaType: "application/pdf"; + } +} + +function PdfAttachment({ + data, + filename, + mediaType, +}: PdfAttachment.Props) { + + const [url, setUrl] = useState(""); + + useLayoutEffect(() => { + const file = new File([data], filename, { type: mediaType }); + const url = URL.createObjectURL(file); + + setUrl(url); + + return () => { URL.revokeObjectURL(url); }; + }, [data, mediaType]); + + return url && ( + + ); +} diff --git a/packages/frontend/src/routes/Piece.tsx b/packages/frontend/src/routes/Piece.tsx index 2b1d426..27d5697 100644 --- a/packages/frontend/src/routes/Piece.tsx +++ b/packages/frontend/src/routes/Piece.tsx @@ -233,21 +233,6 @@ function AttachmentRow(props: AttachmentRow.Props) { URL.revokeObjectURL(url); }).pipe(Effect.runPromise); - const open = (event: MouseEvent) => Effect.gen(function* () { - if (props.attachment.mediaType !== "application/pdf") { - return; - } - - event.preventDefault(); - - const { data, mediaType } = yield* client.getAttachment(props.attachment.attachmentId); - const blob = new Blob([data], { type: mediaType }); - - const url = URL.createObjectURL(blob); - window.open(url, "_target"); - URL.revokeObjectURL(url); - }).pipe(Effect.runPromise); - const doDelete = () => Effect.gen(function* () { yield* client.deleteAttachment(props.attachment.attachmentId); yield* pieceCache.update(props.attachment.pieceId, mapProp("attachments", Array.filter((a) => a.attachmentId !== props.attachment.attachmentId))); @@ -280,7 +265,7 @@ function AttachmentRow(props: AttachmentRow.Props) { {props.attachment.mediaType === "application/vnd.recordare.musicxml" || props.attachment.mediaType === "application/vnd.recordare.musicxml+xml" || props.attachment.mediaType === "application/pdf" ? ( - + {props.attachment.filename} ) : (