Skip to main content

withBatchStartUpdate

Package

@rpldy/uploady

Installation

npm install @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.