import { useCallback, useState, useEffect } from "react";
import Cropper from "react-easy-crop";
import checkIfItFallbackImage from "@calcom/lib/checkIfItFallbackImage";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { ButtonColor } from "../..";
import { Button, Dialog, DialogClose, DialogContent, DialogTrigger, DialogFooter } from "../..";
import { showToast } from "../toast";
import { useFileReader, createImage, Slider } from "./Common";
import type { FileEvent, Area } from "./Common";
type BannerUploaderProps = {
id: string;
buttonMsg: string;
handleAvatarChange: (imageSrc: string) => void;
imageSrc?: string;
target: string;
triggerButtonColor?: ButtonColor;
uploadInstruction?: string;
disabled?: boolean;
height: number;
width: number;
};
function CropContainer({
onCropComplete,
imageSrc,
}: {
imageSrc: string;
onCropComplete: (croppedAreaPixels: Area) => void;
}) {
const { t } = useLocale();
const [crop, setCrop] = useState({ x: 0, y: 0 });
const [zoom, setZoom] = useState(1);
const handleZoomSliderChange = (value: number) => {
value < 1 ? setZoom(1) : setZoom(value);
};
return (
onCropComplete(croppedAreaPixels)}
onZoomChange={setZoom}
/>
);
}
export default function BannerUploader({
target,
id,
buttonMsg,
handleAvatarChange,
triggerButtonColor,
imageSrc,
uploadInstruction,
disabled = false,
height,
width,
}: BannerUploaderProps) {
const { t } = useLocale();
const [croppedAreaPixels, setCroppedAreaPixels] = useState(null);
const [{ result }, setFile] = useFileReader({
method: "readAsDataURL",
});
const onInputFile = async (e: FileEvent) => {
if (!e.target.files?.length) {
return;
}
const limit = 5 * 1000000; // max limit 5mb
const file = e.target.files[0];
if (file.size > limit) {
showToast(t("image_size_limit_exceed"), "error");
} else {
setFile(file);
}
};
const showCroppedImage = useCallback(
async (croppedAreaPixels: Area | null) => {
try {
if (!croppedAreaPixels) return;
const croppedImage = await getCroppedImg(
result as string /* result is always string when using readAsDataUrl */,
croppedAreaPixels,
height,
width
);
handleAvatarChange(croppedImage);
} catch (e) {
console.error(e);
}
},
[result, height, width, handleAvatarChange]
);
useEffect(() => {
const checkDimensions = async () => {
const image = await createImage(
result as string /* result is always string when using readAsDataUrl */
);
if (image.naturalWidth !== width || image.naturalHeight !== height) {
showToast(t("org_banner_instructions", { height, width }), "warning");
}
};
if (result) {
checkDimensions();
}
}, [result]);
return (
);
}
async function getCroppedImg(
imageSrc: string,
pixelCrop: Area,
height: number,
width: number
): Promise {
const image = await createImage(imageSrc);
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
if (!ctx) throw new Error("Context is null, this should never happen.");
canvas.width = width;
canvas.height = height;
ctx.drawImage(
image,
pixelCrop.x,
pixelCrop.y,
pixelCrop.width,
pixelCrop.height,
0,
0,
canvas.width,
canvas.height
);
return canvas.toDataURL("image/png");
}