/* eslint-disable jsx-a11y/anchor-is-valid */ /* eslint-disable react/jsx-fragments */ import React, { Fragment, forwardRef, useState, useEffect, useRef, useImperativeHandle, } from 'react'; import { CopyToClipboard } from 'react-copy-to-clipboard'; import axios from 'axios'; import { get } from 'lodash'; import PropTypes from 'prop-types'; import { Row } from 'reactstrap'; import { Inputs } from '@buffetjs/custom'; import { useGlobalContext, prefixFileUrlWithBackendUrl } from 'strapi-helper-plugin'; import Cropper from 'cropperjs'; import 'cropperjs/dist/cropper.css'; import { createFileToDownloadName } from '../../utils'; import CardControl from '../CardControl'; import CardControlsWrapper from '../CardControlsWrapper'; import CardPreview from '../CardPreview'; import InfiniteLoadingIndicator from '../InfiniteLoadingIndicator'; import ModalSection from '../ModalSection'; import VideoPlayer from '../VideoPlayer'; import CropWrapper from './CropWrapper'; import FileDetailsBox from './FileDetailsBox'; import FileWrapper from './FileWrapper'; import FormWrapper from './FormWrapper'; import SizeBox from './SizeBox'; import Wrapper from './Wrapper'; import ErrorMessage from './ErrorMessage'; import form from './utils/form'; import isImageType from './utils/isImageType'; import isVideoType from './utils/isVideoType'; const EditForm = forwardRef( ( { canCopyLink, canDownload, components, fileToEdit, isEditingUploadedFile, isFormDisabled, onAbortUpload, onChange, onClickDeleteFileToUpload, onSubmitEdit, setCropResult, toggleDisableForm, }, ref ) => { const { formatMessage } = useGlobalContext(); const [isCropping, setIsCropping] = useState(false); const [infos, setInfos] = useState({ width: null, height: null }); const [src, setSrc] = useState(null); const cacheRef = useRef(performance.now()); const fileURL = get(fileToEdit, ['file', 'url'], null); const prefixedFileURL = fileURL ? prefixFileUrlWithBackendUrl(`${fileURL}?${cacheRef.current}`) : null; const downloadFileName = createFileToDownloadName(fileToEdit); const mimeType = get(fileToEdit, ['file', 'type'], null) || get(fileToEdit, ['file', 'mime'], ''); const isImg = isImageType(mimeType); const isVideo = isVideoType(mimeType); const canCrop = isImg && !mimeType.includes('svg') && !mimeType.includes('gif'); const aRef = useRef(); const imgRef = useRef(); const inputRef = useRef(); const cropper = useRef(); useImperativeHandle(ref, () => ({ click: () => { inputRef.current.click(); setIsCropping(false); }, })); useEffect(() => { if (isImg || isVideo) { if (prefixedFileURL) { setSrc(prefixedFileURL); } else { setSrc(URL.createObjectURL(fileToEdit.file)); } } }, [isImg, isVideo, fileToEdit, prefixedFileURL]); useEffect(() => { if (isCropping) { cropper.current = new Cropper(imgRef.current, { modal: true, initialAspectRatio: 16 / 9, movable: true, zoomable: false, cropBoxResizable: true, background: false, crop: handleResize, }); } else if (cropper.current) { cropper.current.destroy(); setInfos({ width: null, height: null }); toggleDisableForm(false); } return () => { if (cropper.current) { cropper.current.destroy(); } }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [cropper, isCropping]); const handleResize = ({ detail: { height, width } }) => { const roundedDataHeight = Math.round(height); const roundedDataWidth = Math.round(width); setInfos({ width: roundedDataWidth, height: roundedDataHeight }); }; const handleToggleCropMode = () => { setIsCropping(prev => { if (!prev && isEditingUploadedFile) { toggleDisableForm(true); } return !prev; }); }; const handleChange = ({ target: { files } }) => { if (files[0]) { onChange({ target: { name: 'file', value: files[0] } }); } }; const handleClick = async () => { const cropResult = await getCroppedResult(); setCropResult(cropResult); setIsCropping(false); }; const getCroppedResult = () => { return new Promise((resolve, reject) => { try { const canvas = cropper.current.getCroppedCanvas(); canvas.toBlob(async blob => { const { file: { lastModifiedDate, lastModified, name }, } = fileToEdit; resolve( new File([blob], name, { type: mimeType, lastModified, lastModifiedDate, }) ); }); } catch (err) { reject(); } }); }; const handleClickEditCroppedFile = async (e, shouldDuplicate = false) => { try { const file = await getCroppedResult(); onSubmitEdit(e, shouldDuplicate, file, true); } catch (err) { // Silent } finally { setIsCropping(false); } }; const handleClickDelete = () => { onClickDeleteFileToUpload(fileToEdit.originalIndex); }; const handleCopy = () => { strapi.notification.info('notification.link-copied'); }; const handleClickDownload = () => { axios .get(prefixedFileURL, { responseType: 'blob', }) .then(({ data }) => { const blobUrl = URL.createObjectURL(data); aRef.current.download = downloadFileName; aRef.current.href = blobUrl; aRef.current.click(); }) .catch(err => { console.error(err); }); }; const handleSubmit = e => { e.preventDefault(); onSubmitEdit(e); }; const CheckButton = components.CheckControl; return (
{fileToEdit.isUploading ? ( ) : ( {!isCropping ? ( <> {fileURL && ( <> {canDownload && ( )} hidden {canCopyLink && ( )} )} {canCrop && ( )} ) : ( <> )} {isImg ? ( {get(fileToEdit, ) : ( <> {isVideo ? ( ) : ( )} )} {isCropping && infos.width !== null && (   {infos.width} x {infos.height}   )} )} {fileToEdit.hasError && ( {fileToEdit.errorMessage} )}
{form.map(({ key, inputs }) => { return ( {inputs.map(input => { return (
); })}
); })}
{ if (i === 1) { return '*'; } return v; }) .join('/')} />
); } ); EditForm.defaultProps = { canCopyLink: true, canDownload: true, components: { CheckControl: CardControl, }, fileToEdit: null, isEditingUploadedFile: false, isFormDisabled: false, onAbortUpload: () => {}, onChange: () => {}, onClickDeleteFileToUpload: () => {}, onSubmitEdit: e => e.preventDefault(), setCropResult: () => {}, toggleDisableForm: () => {}, }; EditForm.propTypes = { canCopyLink: PropTypes.bool, canDownload: PropTypes.bool, onAbortUpload: PropTypes.func, components: PropTypes.object, fileToEdit: PropTypes.object, isEditingUploadedFile: PropTypes.bool, isFormDisabled: PropTypes.bool, onChange: PropTypes.func, onClickDeleteFileToUpload: PropTypes.func, onSubmitEdit: PropTypes.func, setCropResult: PropTypes.func, toggleDisableForm: PropTypes.func, }; export default EditForm;