@paroicms/front-media-gallery
Version:
Basic media gallery react component for Paroi CMS.
83 lines (81 loc) • 3.77 kB
JSX
import { useAppLog, useWrapAsync } from "@paroicms/front-app-log";
import { showToast } from "@paroicms/internal-front-lib";
import { classNames } from "primereact/utils";
import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { FileDrop } from "./FileDrop";
import GalleryItem from "./GalleryItem/GalleryItem";
import { ImagePicker } from "./ImagePicker/ImagePicker";
import UploadPlaceholder from "./UploadPlaceholder/UploadPlaceholder";
let uploadIdSeq = 0;
export function SingleMedia({ mediaHandle, getMedia, getMediaByUid, httpUploadMedia, deleteMedia, accept, acceptFilter, label, remainingMediaPlaces, updateMediaCount, isMobile, updateMediaAttachedData, contentLanguage, }) {
const wrapAsync = useWrapAsync();
const appLog = useAppLog();
const { t } = useTranslation();
const [initialized, setInitialized] = useState(false);
const [media, setMedia] = useState();
const [uploadingFile, setUploadingFile] = useState();
const imagePickerRef = useRef();
useEffect(wrapAsync(async () => {
setInitialized(false);
await loadMedias();
setInitialized(true);
}), [mediaHandle]);
const updateMediaCaption = async (mediaUid, caption) => {
await updateMediaAttachedData(mediaUid, { caption });
await loadMedias();
};
async function loadMedias() {
const medias = await getMedia(mediaHandle);
setMedia(medias);
updateMediaCount?.({ handle: mediaHandle, count: medias ? 1 : 0 });
}
const uploadSelectedFile = (selectedFiles) => {
const files = acceptFilter ? selectedFiles.filter(acceptFilter) : selectedFiles;
if (files.length === 0)
return;
const file = files[0];
const handler = httpUploadMedia({ file, handle: mediaHandle });
const newFile = {
uploadId: ++uploadIdSeq,
file,
handler,
};
handler.promise
.catch(async () => {
showToast(t("TextDocumentEditScreen.uploadError", { fileName: file.name }), {
severity: "error",
});
})
.then(async () => {
setUploadingFile(undefined);
await loadMedias();
})
.catch((error) => appLog.error("[single-media]", error));
setUploadingFile(newFile);
};
const handleReplace = () => {
imagePickerRef.current?.open();
};
const handleDeleteMedia = async () => {
if (!media || !deleteMedia)
return;
await deleteMedia(mediaHandle);
setMedia(undefined);
updateMediaCount?.({ handle: mediaHandle, count: 0 });
};
function onDropFiles(files) {
if (remainingMediaPlaces === 0) {
showToast(t("frontMediaGallery.mediaLimitReached"), { severity: "warn" });
return;
}
uploadSelectedFile([...files]);
}
return (<FileDrop onDropFiles={onDropFiles}>
<div className="SingleMedia w-8rem">
<ImagePicker className={classNames("single", { hidden: (initialized && media) || uploadingFile })} ref={imagePickerRef} label={label ?? t("frontMediaGallery.chooseAFile")} accept={accept} multiple={false} onFilesSelect={uploadSelectedFile} disabled={remainingMediaPlaces === 0}/>
{uploadingFile && (<UploadPlaceholder localMedia={uploadingFile.file} handler={uploadingFile.handler}/>)}
{!uploadingFile && media && (<GalleryItem key={media.uid} media={media} attachedData={media.attachedData} onReplace={handleReplace} onDelete={handleDeleteMedia} isMobile={isMobile} getMediaProperties={getMediaByUid} updateCaption={updateMediaCaption} contentLanguage={contentLanguage}/>)}
</div>
</FileDrop>);
}