import { useState } from "react";
import { useHotkeys } from "react-hotkeys-hook";
import { AiOutlineCloudUpload } from "react-icons/ai";
import { toast } from "react-toastify";
import { Flex, Spinner, Text } from "theme-ui";
import { uploadSliceScreenshot } from "@/features/slices/actions/uploadSliceScreenshot";
import { ScreenshotPreview } from "@/legacy/components/ScreenshotPreview";
import { acceptedImagesTypes } from "@/legacy/lib/consts";
import { ComponentUI } from "@/legacy/lib/models/common/ComponentUI";
import useSliceMachineActions from "@/modules/useSliceMachineActions";
import useCustomScreenshot from "./useCustomScreenshot";
interface DropZoneProps {
imageTypes?: string[];
variationID: string;
slice: ComponentUI;
onUploadSuccess?: (newSlice: ComponentUI) => void;
}
const DragActiveView = () => {
return (
Drop file here
Maximum upload size file: 128Mb
);
};
export const UploadIcon = ({
isActive,
}: {
isActive: boolean;
}): JSX.Element => (
);
const DropZone: React.FC = ({
variationID,
slice,
imageTypes = acceptedImagesTypes,
onUploadSuccess,
}) => {
const maybeScreenshot = slice.screenshots[variationID];
const { saveSliceCustomScreenshotSuccess } = useSliceMachineActions();
const [isDragActive, setIsDragActive] = useState(false);
const [isHover, setIsHover] = useState(false);
const [isUploadingScreenshot, setIsUploadingScreenshot] = useState(false);
useHotkeys(["meta+v", "ctrl+v"], () => void handlePaste(), [
variationID,
slice,
]);
const { FileInputRenderer, fileInputProps } = useCustomScreenshot({
onHandleFile: async (file: File, isDragActive: boolean) => {
setIsUploadingScreenshot(true);
const newSlice = await uploadSliceScreenshot({
slice,
file,
method: isDragActive ? "dragAndDrop" : "upload",
variationId: variationID,
});
setIsHover(false);
const screenshot = newSlice?.screenshots[variationID];
if (screenshot) {
// Sync with redux store
saveSliceCustomScreenshotSuccess(variationID, screenshot, newSlice);
onUploadSuccess && onUploadSuccess(newSlice);
}
setIsUploadingScreenshot(false);
},
});
const handleFile = async (file: File) => {
if (file.size > 128000000) {
return toast.error("File is too big. Max file size: 128Mb.");
}
setIsUploadingScreenshot(true);
const newSlice = await uploadSliceScreenshot({
slice,
file,
method: "dragAndDrop",
variationId: variationID,
});
const screenshot = newSlice?.screenshots[variationID];
if (screenshot) {
// Sync with redux store
saveSliceCustomScreenshotSuccess(variationID, screenshot, newSlice);
onUploadSuccess && onUploadSuccess(newSlice);
}
setIsUploadingScreenshot(false);
};
const supportsClipboardRead = typeof navigator.clipboard.read === "function";
const handlePaste = async () => {
if (!supportsClipboardRead) return;
try {
const clipboardItems = await navigator.clipboard.read();
if (clipboardItems[0] !== undefined) {
const maybeType = clipboardItems[0].types.find((type) =>
imageTypes.map((t) => `image/${t}`).includes(type),
);
if (maybeType !== undefined) {
const blob = await clipboardItems[0].getType(maybeType);
const file = new File([blob], "file");
return handleFile(file);
}
}
} catch (e) {
console.error("Could not paste file", e);
}
};
const handleDrop = (event: React.DragEvent) => {
event.preventDefault();
setIsDragActive(false);
const maybeFile = event.dataTransfer.files?.[0];
if (maybeFile !== undefined) {
if (imageTypes.some((t) => `image/${t}` === maybeFile.type)) {
return void handleFile(maybeFile);
}
return toast.error(
`Only files of type ${imageTypes.join(", ")} are accepted.`,
);
}
};
const createDragActiveState =
(bool: boolean) => (e: React.DragEvent) => {
e.preventDefault();
setIsDragActive(bool);
};
const createHoverState =
(bool: boolean) => (e: React.MouseEvent) => {
e.preventDefault();
setIsHover(bool);
};
return (
e.preventDefault()}
onDrop={handleDrop}
>
{isUploadingScreenshot ? (
<>
Uploading file ...
>
) : null}
{!isUploadingScreenshot && maybeScreenshot !== undefined ? (
) : null}
{!isUploadingScreenshot ? (
{supportsClipboardRead ? "Paste, drop or ..." : "Drop or ..."}
Maximum file size: 128Mb
) : null}
{isDragActive ? : null}
);
};
export default DropZone;