Android_Retail/src/Components/Forms/CropUpload.jsx

550 lines
17 KiB
JavaScript

import React, { useState, useEffect, useCallback } from 'react';
import { Upload, Modal } from 'antd';
import { uploadImage } from '../../Features/upload/upload';
import { useDispatch } from 'react-redux';
import ImageCropper from '../../Components/Forms/Cropper2.jsx';
import ShapeCropper from './ShapeCropper.jsx';
import { PiCropBold } from 'react-icons/pi';
import { FiPenTool } from 'react-icons/fi';
import { DefaultModal } from '../../Components/Modal/DefaultModal.jsx';
import '../../Styles/Product/Product.scss';
import { Messages } from '../Notifications/Messages.jsx';
import { isMobile } from 'react-device-detect';
import Camera from '../MobileComponent/Camera.jsx';
import useHasCamera from '../../utils/useHasCamera.js';
const allowedTypes = [
'image/jpeg',
'image/png',
'image/webp',
'image/svg+xml',
'image/gif',
'image/avif',
];
const CropUpload = ({
updateImageUrl,
ImageLink,
onlineImage,
isProductList = {},
handleClose = () => { }
}) => {
const dispatch = useDispatch();
const hasCamera = useHasCamera();
const [messageType, setMessageType] = useState(null);
const [messageData, setMessageData] = useState(null);
const [fileList, setFileList] = useState([]);
const [previewVisible, setPreviewVisible] = useState(false);
const [previewImage, setPreviewImage] = useState('');
const [editImageOpen, setEditImageOpen] = useState(false);
const [croppedImage, setCroppedImage] = useState(null);
const [shapedImage, setShapedImage] = useState(false);
const [cropImage, setCropImage] = useState(false);
const [shapedData, setShapedData] = useState(null);
const [resizedImageUrl, setResizedImageUrl] = useState('');
useEffect(() => {
if (ImageLink != '' && ImageLink != null) {
updateImageUrl(ImageLink);
setFileList([
{
uid: `${Date.now()}-${Math.random()}`, // Ensures uniqueness
name: `image${Date.now()}-${Math.random()}.png`,
status: 'done',
url: ImageLink,
},
]);
} else {
updateImageUrl();
// setFileList([]);
// handleRemove()
}
}, [ImageLink]);
useEffect(() => {
if (ImageLink != '' && ImageLink != null) {
if (Object.keys(isProductList)?.length > 0) {
const { isProductListPutapi } = isProductList;
if (isProductListPutapi) {
setFileList([
{
uid: `${Date.now()}-${Math.random()}`, // Ensures uniqueness
name: `image${Date.now()}-${Math.random()}.png`,
status: 'done',
url: ImageLink,
},
]);
} else {
setFileList([]);
}
} else {
// setFileList([]);
}
} else {
// setFileList([]);
}
}, []);
useEffect(() => {
if (onlineImage !== '' && onlineImage != null && onlineImage != undefined) {
setEditImageOpen(true);
handleResizeImage(onlineImage);
} else {
setShapedImage(false);
setCropImage(false);
}
}, [onlineImage]);
useEffect(() => {
if (fileList.length > 0) {
const imageUrl = fileList?.[0]?.url;
if (imageUrl !== '' && imageUrl !== null && imageUrl !== undefined) {
handleResizeImage(imageUrl);
} else {
setShapedImage(false);
setCropImage(false);
}
}
}, [fileList]);
const handleResizeImage = async (imageUrl) => {
try {
const resizedImageUrl = await resizeImage(imageUrl, 300, 150);
setResizedImageUrl(resizedImageUrl);
} catch (error) {
console.error('Error resizing image:', error);
}
};
const SetDefault = async () => {
setEditImageOpen(false);
setCroppedImage(null);
setShapedData(null);
setShapedImage(false);
setCropImage(false);
updateImageUrl(
onlineImage !== '' && onlineImage != null
? onlineImage
: fileList?.[0]?.['url'] != '' && fileList?.[0]?.['url'] != null
? fileList?.[0]?.['url']
: ''
);
if (Object.keys(isProductList)?.length > 0) {
const { isProductListPutapi, record, imagePutFunction } = isProductList;
if (isProductListPutapi) {
imagePutFunction(
onlineImage !== '' && onlineImage != null
? onlineImage
: fileList?.[0]?.['url'] != '' && fileList?.[0]?.['url'] != null
? fileList?.[0]?.['url']
: '',
record
);
handleClose();
setMessageData("Image updated successfully");
setMessageType("success");
}
}
};
const handleEditImageCancle = () => {
setCroppedImage(null);
setShapedData(null);
setEditImageOpen(false);
updateImageUrl('');
setFileList([]);
setShapedImage(false);
setCropImage(false);
};
const handleSubmit = async () => {
const base64 = croppedImage;
const byteCharacters = atob(base64?.split(',')[1]);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: 'image/png' });
const file = new File([blob], 'cropped_image.png', { type: 'image/png' });
try {
await handleUpload({
file,
onSuccess: () => console.log('Upload successful'),
onError: () => console.error('Upload failed'),
});
setEditImageOpen(false);
await setCroppedImage(null);
setShapedImage(false);
setCropImage(false);
handleClose();
setMessageData("Image updated successfully");
setMessageType("success");
} catch (error) {
console.error('Error in handleUpload:', error);
}
};
const handleShapeSubmit = async () => {
const base64 = shapedData[0];
const byteCharacters = atob(base64?.split(',')[1]);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: 'image/png' });
const file = new File([blob], 'cropped_image.png', { type: 'image/png' });
try {
await handleUpload({
file,
onSuccess: () => console.log('Upload successful'),
onError: () => console.error('Upload failed'),
});
setEditImageOpen(false);
await setShapedData(null);
setShapedImage(false);
setCropImage(false);
handleClose();
setMessageData("Image updated successfully");
setMessageType("success");
} catch (error) {
console.error('Error in handleUpload:', error);
}
};
const handleCancel = () => setPreviewVisible(false);
const onChange = async ({ fileList: newFileList }) => {
setFileList(newFileList);
if (Object.keys(isProductList)?.length > 0) {
const { isProductListPutapi } = isProductList;
if (isProductListPutapi && newFileList?.[0]?.originFileObj) {
const file = newFileList[0].originFileObj;
try {
const res = await dispatch(uploadImage(file)).unwrap();
if (res?.data?.status) {
updateImageUrl(res?.data?.image);
if (res?.data?.image) {
setFileList([
{
uid: `${Date.now()}-${Math.random()}`, // Ensures uniqueness
name: `image${Date.now()}-${Math.random()}.png`,
status: 'done',
url: res?.data?.image,
},
]);
}
}
} catch (error) {
console.error('Image upload failed:', error);
}
}
}
if (newFileList?.length > 0) {
setEditImageOpen(true);
}
};
const onPreview = async (file) => {
let src = file.url;
if (!src) {
src = await new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(file.originFileObj);
reader.onload = () => resolve(reader.result);
});
}
setPreviewImage(src);
setPreviewVisible(true);
};
const handleCrop = (croppedData) => {
setCroppedImage(croppedData);
};
const handleShape = (shapedData) => {
setShapedData(shapedData);
};
const handleUpload = async ({ file, onSuccess, onError }) => {
try {
if (!file) {
console.error('File object is null or undefined.');
onError();
return;
}
const data = await dispatch(uploadImage(file)).unwrap();
if (data?.data?.status) {
if (Object.keys(isProductList)?.length > 0) {
const { isProductListPutapi, record, imagePutFunction } =
isProductList;
if (isProductListPutapi) {
imagePutFunction(data?.data?.image, record);
setFileList([{ url: data?.data?.image }]);
onSuccess(); // Trigger onSuccess to indicate a successful upload
setCroppedImage(null);
setShapedData(null);
} else {
updateImageUrl(data?.data?.image);
setFileList([{ url: data?.data?.image }]);
onSuccess(); // Trigger onSuccess to indicate a successful upload
setCroppedImage(null);
setShapedData(null);
}
} else {
updateImageUrl(data?.data?.image);
setFileList([{ url: data?.data?.image }]);
onSuccess(); // Trigger onSuccess to indicate a successful upload
setCroppedImage(null);
setShapedData(null);
}
} else {
console.error('API request was not successful:', data?.data?.error);
onError(); // Trigger onError to indicate a failed upload
}
} catch (error) {
console.error('Error calling API:', error);
onError(); // Trigger onError in case of an error
}
};
const handleRemove = () => {
if (Object.keys(isProductList)?.length > 0) {
const { isProductListPutapi, record, imagePutFunction } = isProductList;
if (isProductListPutapi) {
imagePutFunction('', record);
}
}
updateImageUrl('');
setEditImageOpen(false);
setShapedImage(false);
setCropImage(false);
};
const handleShapeCrop = () => {
setShapedImage(true);
setCropImage(false);
setCroppedImage(null);
};
const handleCropTool = () => {
setCropImage(true);
setShapedImage(false);
setShapedData(null);
};
function resizeImage(imageUrl, width, height) {
if (!imageUrl) {
// Handle the case where imageUrl is null or undefined
console.error('Image URL is null or undefined.');
return Promise.reject('Image URL is null or undefined.');
}
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'anonymous'; // Set crossOrigin to handle cross-origin images
img.onload = function () {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);
const resizedImageUrl = canvas.toDataURL();
resolve(resizedImageUrl);
};
img.onerror = function (error) {
reject(error);
};
img.src = imageUrl;
});
}
const beforeUpload = (file) => {
const isAllowed = allowedTypes.includes(file.type);
if (!isAllowed) {
Modal.error({
title: 'Invalid File Type',
content:
'Only JPG, JPEG, PNG, WEBP, SVG, GIF, and AVIF files are allowed.',
});
}
return isAllowed || Upload.LIST_IGNORE; // prevents adding to fileList if invalid
};
const onComplete = useCallback(() => {
setMessageData(null);
setMessageType(null);
}, []);
return (
<>
<Messages
messageType={messageType}
messageData={messageData}
onComplete={onComplete}
/>
<div
className={
Object.keys(isProductList)?.length > 0
? fileList.length > 0
? 'cropUploadFieldSmall'
: 'cropUploadFieldSmallNoData'
: ''
}
>
<Upload
action="https://run.mocky.io/v3/435e224c-44fb-4773-9faf-380c5e6a2188"
listType="picture-card"
fileList={fileList}
customRequest={handleUpload} // Use customRequest to handle the upload process manually
onChange={onChange}
onPreview={onPreview}
onRemove={handleRemove}
beforeUpload={beforeUpload}
>
{fileList.length < 1 && '+ Upload'}
</Upload>
</div>
<Modal visible={previewVisible} onCancel={handleCancel} footer={null}>
<img alt="Preview" style={{ width: '100%' }} src={previewImage} />
</Modal>
{isMobile && fileList?.length == 0 && hasCamera && <>
<div style={{ textAlign: "center", margin: "6px 0", fontFamily: "Poppins", fontWeight: "500" }}>OR</div>
<Camera
handleCapture={async (e) => {
const file = e.target.files?.[0];
if (!file) return;
try {
await handleUpload({
file,
onSuccess: () => {
setEditImageOpen(true);
},
onError: () => {
console.error("Upload failed");
}
});
} catch (error) {
console.error(error);
}
}}
/>
</>}
<DefaultModal
title="Edit Image"
width={800}
open={editImageOpen}
footer={
(cropImage && croppedImage === null) ||
(shapedImage && shapedData === null)
? false
: true
}
buttonText="SUBMIT"
children={
<>
<div className="shape-crop">
{!croppedImage && !cropImage && !shapedImage && (
<div>
<img
src={
onlineImage !== '' && onlineImage != null
? onlineImage
: fileList?.[0]?.['url'] != '' &&
fileList?.[0]?.['url'] != null
? fileList?.[0]?.['url']
: ''
}
style={{ width: '200px', height: '100px' }}
alt="Edit Image"
/>
</div>
)}
<div className="shape-crop-div">
<div
className="crop-button"
style={{ backgroundColor: cropImage && '#52c41a' }}
onClick={() => handleCropTool()}
>
<div>
<PiCropBold className="crop-icon" />
</div>
<div>Crop Tool</div>
</div>
<div
className="crop-button"
style={{ backgroundColor: shapedImage && '#52c41a' }}
onClick={() => handleShapeCrop()}
>
<div>
<FiPenTool className="crop-icon" />
</div>
<div>Pen Tool</div>
</div>
</div>
<div>
{cropImage && (
<ImageCropper
imageUrl={
onlineImage !== '' && onlineImage != null
? onlineImage
: fileList?.[0]?.['url'] != '' &&
fileList?.[0]?.['url'] != null
? fileList?.[0]?.['url']
: ''
}
onCrop={handleCrop}
/>
)}
{croppedImage && cropImage && (
<div
style={{
display: 'flex',
alignItems: 'center',
flexDirection: 'column',
gap: '2rem',
}}
>
<h4 style={{ marginLeft: '-33rem' }}>
Cropped Image Preview
</h4>
<img
src={croppedImage}
alt="Cropped Image"
style={{ width: '200px', height: '100px' }}
/>
</div>
)}
{shapedImage && (
<ShapeCropper
imageUrl={
resizedImageUrl !== '' && resizedImageUrl !== null
? resizedImageUrl
: ''
}
onShape={handleShape}
/>
)}
</div>
</div>
</>
}
handleSubmit={
croppedImage == null && shapedData == null
? SetDefault
: croppedImage != null
? handleSubmit
: handleShapeSubmit
}
handleCancel={handleEditImageCancle}
/>
</>
);
};
export default CropUpload;