withBatchStartUpdate
Package
Installation
- npm
- Yarn
- pnpm
npm install @rpldy/uploady
yarn add @rpldy/uploady
pnpm add @rpldy/uploady
Details
export interface WithRequestPreSendUpdateProps {
id: string;
}
type withBatchStartUpdate =<P extends WithRequestPreSendUpdateProps>(Comp: React.FC<P> | React.ComponentType<P>) =>
React.FC<Omit<P, "updateRequest" | "requestData">>;
HOC to enable components to interact with the upload data and options of the batch (just-in-time) before the items are processed and requests are sent.
This makes it possible to create a UI that will allow the user to interact and possibly make changes to different or all items within the batch before a single request is made. For example: cropping multiple items prior to upload.
When rendering the HOC's output, the id of the batch must be provided as a prop. The id of the batch can be obtained using the useBatchAddListener
import React, { useState, useCallback } from "react";
import Cropper from "react-easy-crop";
import Uploady, { withBatchStartUpdate } from "@rpldy/uploady";
import UploadButton from "@rpldy/upload-button";
import UploadPreview from "@rpldy/upload-preview";
import cropImage from "./my-image-crop-code";
const CropperForMultiCrop = ({ item, url, setCropForItem }) => {
const [crop, setCrop] = useState({ x: 0, y: 0 });
const [cropPixels, setCropPixels] = useState(null);
const onSaveCrop = async () => {
const cropped = await cropImage(url, item.file, cropPixels);
setCropForItem(item.id, cropped);
};
const onCropComplete = useCallback((croppedArea, croppedAreaPixels) => {
setCropPixels(croppedAreaPixels);
}, []);
return (<div>
<Cropper
image={url}
crop={crop}
onCropChange={setCrop}
onCropComplete={onCropComplete}
/>
{cropPixels &&
<Button onClick={onSaveCrop} id="save-crop-btn">Save Crop</Button>}
</div>);
};
const BatchCrop = withBatchStartUpdate((props) => {
const { id, updateRequest, requestData } = props;
const [cropped, setCropped] = useState({});
const hasData = !!(id && requestData);
const setCropForItem = (id, data) => {
setCropped((cropped) => ({ ...cropped, [id]: data }));
};
const onUploadAll = () => {
if (updateRequest) {
const readyItems = requestData.items
.map((item) => {
item.file = cropped[item.id] || item.file;
return item;
});
//update the items in the batch with the cropped files
updateRequest({ items: readyItems });
}
};
const getPreviewCompProps = useCallback((item) => {
return ({
onPreviewSelected: setSelected,
isCroppedSet: cropped[item.id],
});
}, [cropped, setSelected]);
return (<div>
{hasData &&
<button onClick={onUploadAll}>Upload All</button>}
<UploadPreview
rememberPreviousBatches
PreviewComponent={ItemPreviewThumb}
fallbackUrl="https://icon-library.net/images/image-placeholder-icon/image-placeholder-icon-6.jpg"
previewComponentProps={getPreviewCompProps}
/>
{selectedItem && hasData &&
<CropperForMultiCrop
{...selected}
item={selectedItem}
setCropForItem={setCropForItem}
/>}
</div>);
});
const MultiCropQueue = () => {
const [currentBatch, setCurrentBatch] = useState(null);
useBatchAddListener((batch) => setCurrentBatch(batch.id));
return <BatchCrop id={currentBatch} />;
};
export const MyApp = () => {
return <Uploady destination={{ url: "my-server.com/upload" }}>
<UploadButton />
<MultiCropQueue />
</Uploady>;
};
See the Multi Crop Guide for a full example.