@paroicms/bo-media-gallery
Version:
Basic media gallery react component for Paroi CMS.
67 lines (65 loc) • 3.51 kB
JSX
import "../assets/styles/index.scss";
import { useAsyncEffect, useWrapAsync } from "@paroi/use-async-effect";
import { useShowToast } from "@paroicms/internal-bo-lib";
import { classNames } from "primereact/utils";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { FileDrop } from "./FileDrop.jsx";
import GalleryItem from "./GalleryItem/GalleryItem.jsx";
import ReorderMedias from "./ReorderMedias/ReorderMedias.jsx";
import UploadPlaceholder from "./UploadPlaceholder/UploadPlaceholder.jsx";
export function MediaGallery({ deleteMedia, className, reorderMedias, accept, handle, direction = "row", onMediaAction, limitManager, isMobile, getMediaProperties, updateMediaAttachedData, contentLanguage, uploadFiles, uploadingFiles, refreshMedias, medias, }) {
const { t } = useTranslation();
const [isDragging, setIsDragging] = useState(false);
const wrapAsync = useWrapAsync();
const showToast = useShowToast();
const handleDeleteMedia = async (mediaUid) => {
await deleteMedia({ mediaUid, handle });
await refreshMedias();
showToast(t("DocumentEditPanel.mediaDeleted"), { severity: "info" });
};
const reorderMediasAndRefresh = async (payload) => {
if (reorderMedias) {
await reorderMedias({
mediaUids: payload.map((item) => item.uid),
handle,
});
await refreshMedias();
}
};
const updateMediaCaption = async (mediaUid, caption) => {
await updateMediaAttachedData(mediaUid, { caption });
await refreshMedias();
};
useAsyncEffect(refreshMedias, [handle]);
async function onDropFiles(files) {
if (limitManager?.remainingMediaPlaces === 0) {
showToast(t("frontMediaGallery.mediaLimitReached"), { severity: "warn" });
return;
}
await uploadFiles([...files]);
await refreshMedias();
}
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={wrapAsync(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={limitManager?.remainingMediaPlaces === 0} onChange={wrapAsync(async (ev) => {
if (!ev.target.files)
return;
await uploadFiles([...ev.target.files]);
await refreshMedias();
})}/>
</span>
{direction === "row" ? (galleryItems) : (<div className={classNames("Gallery", direction)}>{galleryItems}</div>)}
</div>
</FileDrop>);
}