UNPKG

@paroicms/front-media-gallery

Version:

Basic media gallery react component for Paroi CMS.

96 lines (94 loc) 4.77 kB
import "../assets/styles/index.scss"; import { useAppLog, useWrapAsync } from "@paroicms/front-app-log"; import { showToast } from "@paroicms/internal-front-lib"; import { classNames } from "primereact/utils"; import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { FileDrop } from "./FileDrop"; import GalleryItem from "./GalleryItem/GalleryItem"; import ReorderMedias from "./ReorderMedias/ReorderMedias"; import UploadPlaceholder from "./UploadPlaceholder/UploadPlaceholder"; let uploadIdSeq = 0; export function MediaGallery({ getMedias, deleteMedia, httpUploadMedia, className, reorderMedias, accept, acceptFilter, handle, direction = "row", onMediaAction, remainingMediaPlaces, updateMediaCount, isMobile, getMediaProperties, updateMediaAttachedData, contentLanguage, }) { const { t } = useTranslation(); const appLog = useAppLog(); const wrapAsync = useWrapAsync(); const [medias, setMedias] = useState([]); const [uploadingFiles, setUploadingFiles] = useState([]); const [isDragging, setIsDragging] = useState(false); const setImageOnState = async () => { const medias = await getMedias(handle); setMedias(medias); updateMediaCount?.({ handle: handle, count: medias.length }); }; const handleDeleteMedia = async (mediaUid) => { await deleteMedia({ mediaUid, handle }); await setImageOnState(); showToast(t("TextDocumentEditScreen.mediaDeleted"), { severity: "info" }); }; const uploadSelectedFiles = (selectedFiles) => { const files = (acceptFilter ? selectedFiles.filter(acceptFilter) : selectedFiles).map((file) => ({ uploadId: ++uploadIdSeq, file, handler: httpUploadMedia({ file, handle: handle }), progress: 0, })); for (const file of files) { const { handler } = file; handler.promise .catch(() => { showToast(t("TextDocumentEditScreen.uploadError", { fileName: file.file.name }), { severity: "error", }); }) .then(() => onUploadEnd(file.uploadId)) .catch((error) => appLog.error("[media-gallery]", error)); handler.onProgress = (progress) => { file.progress = progress; }; } setUploadingFiles([...uploadingFiles, ...files]); }; const onUploadEnd = async (uploadId) => { await setImageOnState(); setUploadingFiles((oldFiles) => oldFiles.filter((f) => f.uploadId !== uploadId)); }; const reorderMediasAndRefresh = async (payload) => { if (reorderMedias) { await reorderMedias({ mediaUids: payload.map((item) => item.uid), handle, }); await setImageOnState(); } }; const updateMediaCaption = async (mediaUid, caption) => { await updateMediaAttachedData(mediaUid, { caption }); await setImageOnState(); }; useEffect(wrapAsync(setImageOnState), [handle]); function onDropFiles(files) { if (remainingMediaPlaces === 0) { showToast(t("frontMediaGallery.mediaLimitReached"), { severity: "warn" }); return; } uploadSelectedFiles([...files]); } const galleryItems = (<> {medias.map((item) => (<GalleryItem isMobile={isMobile} key={item.uid} media={item} attachedData={item.attachedData} onDelete={() => handleDeleteMedia(item.uid)} onClick={onMediaAction ? () => onMediaAction(item) : undefined} getMediaProperties={getMediaProperties} updateCaption={updateMediaCaption} contentLanguage={contentLanguage}/>))} {uploadingFiles.map((item) => (<UploadPlaceholder key={item.uploadId} localMedia={item.file} handler={item.handler}/>))} </>); return (<FileDrop onDropFiles={onDropFiles} onDraggingChange={setIsDragging}> <div className={classNames("MediaGallery", direction, className)}> {medias.length > 1 && reorderMedias && (<ReorderMedias isMobile={isMobile} medias={medias} setOrdering={reorderMediasAndRefresh}/>)} <span className={classNames("MediaGallery-fileSelectorBtn", direction, { dragging: isDragging, mobile: !!isMobile, })}> {t("frontMediaGallery.chooseAFile")} <input className="MediaGallery-fileSelectorInput" type="file" name="files" accept={accept} multiple disabled={remainingMediaPlaces === 0} onChange={(ev) => ev.target.files && uploadSelectedFiles([...ev.target.files])}/> </span> {direction === "row" ? (galleryItems) : (<div className={classNames("Gallery", direction)}>{galleryItems}</div>)} </div> </FileDrop>); }