This commit is contained in:
everythingonblack
2025-07-07 10:52:42 +07:00
parent 23ee6fe309
commit 1ea29e5d1e
6 changed files with 224 additions and 165 deletions

BIN
public/back.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
public/camera.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

BIN
public/send.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

BIN
public/upload.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -5,11 +5,11 @@ const CameraPage = ({ handleClose, handleUploadImage }) => {
const [isCameraActive, setIsCameraActive] = useState(true); const [isCameraActive, setIsCameraActive] = useState(true);
const [uploading, setUploading] = useState(false); const [uploading, setUploading] = useState(false);
const [isMobile, setIsMobile] = useState(false); const [isMobile, setIsMobile] = useState(false);
const [isUploadedFile, setIsUploadedFile] = useState(false); // ✅ NEW STATE
const videoRef = useRef(null); const videoRef = useRef(null);
const canvasRef = useRef(null); const canvasRef = useRef(null);
const fileInputRef = useRef(null); const fileInputRef = useRef(null);
// Check if device is mobile
useEffect(() => { useEffect(() => {
const checkMobile = () => { const checkMobile = () => {
setIsMobile(window.innerWidth <= 768); setIsMobile(window.innerWidth <= 768);
@@ -21,7 +21,6 @@ const CameraPage = ({ handleClose, handleUploadImage }) => {
return () => window.removeEventListener('resize', checkMobile); return () => window.removeEventListener('resize', checkMobile);
}, []); }, []);
// Start the camera when the component mounts
useEffect(() => { useEffect(() => {
const startCamera = async () => { const startCamera = async () => {
try { try {
@@ -37,7 +36,6 @@ const CameraPage = ({ handleClose, handleUploadImage }) => {
}; };
startCamera(); startCamera();
// Cleanup camera stream when component unmounts
return () => { return () => {
if (videoRef.current && videoRef.current.srcObject) { if (videoRef.current && videoRef.current.srcObject) {
const tracks = videoRef.current.srcObject.getTracks(); const tracks = videoRef.current.srcObject.getTracks();
@@ -46,7 +44,6 @@ const CameraPage = ({ handleClose, handleUploadImage }) => {
}; };
}, []); }, []);
// Capture the image from the video stream
const captureImage = () => { const captureImage = () => {
const canvas = canvasRef.current; const canvas = canvasRef.current;
const video = videoRef.current; const video = videoRef.current;
@@ -61,10 +58,10 @@ const CameraPage = ({ handleClose, handleUploadImage }) => {
const capturedImage = canvas.toDataURL('image/jpeg'); const capturedImage = canvas.toDataURL('image/jpeg');
setImage(capturedImage); setImage(capturedImage);
setIsCameraActive(false); setIsCameraActive(false);
setIsUploadedFile(false); // ✅ from camera
} }
}; };
// Handle image upload from file input
const handleFileUpload = e => { const handleFileUpload = e => {
const file = e.target.files[0]; const file = e.target.files[0];
if (file) { if (file) {
@@ -72,15 +69,17 @@ const CameraPage = ({ handleClose, handleUploadImage }) => {
reader.onloadend = () => { reader.onloadend = () => {
setImage(reader.result); setImage(reader.result);
setIsCameraActive(false); setIsCameraActive(false);
setIsUploadedFile(true); // ✅ from file
}; };
reader.readAsDataURL(file); reader.readAsDataURL(file);
} }
}; };
// Cancel the image capture or file upload and restart the camera
const cancelCapture = () => { const cancelCapture = () => {
setImage(null); setImage(null);
setIsCameraActive(true); setIsCameraActive(true);
setIsUploadedFile(false); // ✅ reset
const startCamera = async () => { const startCamera = async () => {
try { try {
const stream = await navigator.mediaDevices.getUserMedia({ const stream = await navigator.mediaDevices.getUserMedia({
@@ -96,71 +95,96 @@ const CameraPage = ({ handleClose, handleUploadImage }) => {
startCamera(); startCamera();
}; };
// Trigger file input click
const triggerFileInput = () => { const triggerFileInput = () => {
fileInputRef.current?.click(); fileInputRef.current?.click();
}; };
const mainContent = ( const mainContent = (
<div style={containerStyle}> <div style={containerStyle}>
{/* Camera/Image Display Area */}
<div style={cameraContainerStyle}> <div style={cameraContainerStyle}>
{isCameraActive && ( {isCameraActive && (
<video ref={videoRef} autoPlay playsInline style={videoStyle} /> <video ref={videoRef} autoPlay playsInline style={videoStyle} />
)} )}
{!isCameraActive && image && ( {!isCameraActive && image && (
<img src={image} alt="Captured or Uploaded" style={imageStyle} /> <img
src={image}
alt="Captured or Uploaded"
style={{
...imageStyle,
objectFit: isUploadedFile ? 'contain' : 'cover',
backgroundColor: '#000',
}}
/>
)} )}
{/* Floating Controls */}
<div style={controlsStyle}> <div style={controlsStyle}>
{isCameraActive ? ( {isCameraActive ? (
<> <>
<button <button
onClick={handleClose} onClick={() => {
style={cancelButtonStyle} handleClose();
}}
style={baseButtonStyle}
aria-label="Cancel and retake" aria-label="Cancel and retake"
> >
<img
src="/back.png"
alt="Kamera"
style={{ height: '26px' }}
/>
</button> </button>
<button <button
onClick={captureImage} onClick={captureImage}
style={captureButtonStyle} style={baseButtonStyle}
aria-label="Capture photo" aria-label="Capture photo"
> >
📸 <img
src="/camera.png"
alt="Kamera"
style={{ height: '24px' }}
/>
</button> </button>
<button <button
onClick={triggerFileInput} onClick={triggerFileInput}
style={uploadButtonStyle} style={baseButtonStyle}
aria-label="Upload from gallery" aria-label="Upload from gallery"
> >
📁 <img
src="/upload.png"
alt="Kamera"
style={{ height: '24px' }}
/>
</button> </button>
</> </>
) : ( ) : (
<> <>
<button <button
onClick={cancelCapture} onClick={cancelCapture}
style={cancelButtonStyle} style={baseButtonStyle}
aria-label="Cancel and retake" aria-label="Cancel and retake"
> >
<img
src="/back.png"
alt="Kamera"
style={{ height: '26px' }}
/>
</button> </button>
<button <button
onClick={() => handleUploadImage(image)} // Pass image data here onClick={() => handleUploadImage(image)}
style={confirmButtonStyle} style={baseButtonStyle}
disabled={uploading} disabled={uploading}
aria-label={uploading ? 'Uploading...' : 'Confirm upload'} aria-label={uploading ? 'Uploading...' : 'Confirm upload'}
> >
{uploading ? '⏳' : '✅'} <img
</button> src="/send.png"
alt="Kamera"
style={{ height: '24px' }}
/> </button>
</> </>
)} )}
</div> </div>
{/* Hidden file input */}
<input <input
ref={fileInputRef} ref={fileInputRef}
type="file" type="file"
@@ -170,28 +194,20 @@ const CameraPage = ({ handleClose, handleUploadImage }) => {
/> />
</div> </div>
{/* Hidden canvas element for capturing the image */}
<canvas ref={canvasRef} style={{ display: 'none' }}></canvas> <canvas ref={canvasRef} style={{ display: 'none' }}></canvas>
</div> </div>
); );
// Desktop layout with left and right sidebars
if (!isMobile) { if (!isMobile) {
return ( return (
<div style={desktopLayoutStyle}> <div style={desktopLayoutStyle}>
{/* Left Sidebar */}
<div style={sidebarStyle}></div> <div style={sidebarStyle}></div>
{/* Main content */}
<div style={mainContentStyle}>{mainContent}</div> <div style={mainContentStyle}>{mainContent}</div>
{/* Right Sidebar */}
<div style={sidebarStyle}></div> <div style={sidebarStyle}></div>
</div> </div>
); );
} }
// Mobile layout (full screen)
return mainContent; return mainContent;
}; };
@@ -222,7 +238,6 @@ const videoStyle = {
const imageStyle = { const imageStyle = {
width: '100%', width: '100%',
height: '100%', height: '100%',
objectFit: 'cover',
}; };
const controlsStyle = { const controlsStyle = {
@@ -249,23 +264,6 @@ const baseButtonStyle = {
transition: 'all 0.2s ease', transition: 'all 0.2s ease',
}; };
const captureButtonStyle = {
...baseButtonStyle,
backgroundColor: '#fff',
color: '#000',
};
const uploadButtonStyle = {
...baseButtonStyle,
backgroundColor: '#4CAF50',
color: '#fff',
};
const cancelButtonStyle = {
...baseButtonStyle,
backgroundColor: '#f44336',
color: '#fff',
};
const confirmButtonStyle = { const confirmButtonStyle = {
...baseButtonStyle, ...baseButtonStyle,
@@ -273,7 +271,6 @@ const confirmButtonStyle = {
color: '#fff', color: '#fff',
}; };
// Desktop styles
const desktopLayoutStyle = { const desktopLayoutStyle = {
display: 'flex', display: 'flex',
height: '100vh', height: '100vh',
@@ -289,26 +286,6 @@ const sidebarStyle = {
borderRight: '1px solid #e0e0e0', borderRight: '1px solid #e0e0e0',
}; };
const sidebarTitleStyle = {
margin: '0 0 30px 0',
fontSize: '24px',
fontWeight: 'bold',
color: '#333',
};
const sidebarContentStyle = {
display: 'flex',
flexDirection: 'column',
gap: '15px',
};
const sidebarTextStyle = {
margin: '0',
fontSize: '16px',
lineHeight: '1.4',
color: '#666',
};
const mainContentStyle = { const mainContentStyle = {
flex: 1, flex: 1,
position: 'relative', position: 'relative',

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import styles from './ChatBot.module.css'; import styles from './ChatBot.module.css';
import Camera from './Camera' import Camera from './Camera';
const ChatBot = ({ existingConversation }) => { const ChatBot = ({ existingConversation }) => {
const [messages, setMessages] = useState([ const [messages, setMessages] = useState([
@@ -15,22 +15,19 @@ const ChatBot = ({ existingConversation }) => {
}, },
]); ]);
const [input, setInput] = useState(''); const [input, setInput] = useState('');
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState('');
const [isPoppedUp, setIsPoppedUp] = useState(''); const [isPoppedUp, setIsPoppedUp] = useState('');
const [name, setName] = useState(''); const [name, setName] = useState('');
const [phoneNumber, setPhoneNumber] = useState(''); const [phoneNumber, setPhoneNumber] = useState('');
const [isOpenCamera, setIsOpenCamera] = useState(false); const [isOpenCamera, setIsOpenCamera] = useState(false);
useEffect(() => {
useEffect(() => {
if (existingConversation && existingConversation.length > 0) { if (existingConversation && existingConversation.length > 0) {
setMessages(existingConversation); setMessages(existingConversation);
} }
}, [existingConversation]) }, [existingConversation]);
useEffect(() => { useEffect(() => {
if (!localStorage.getItem('session')) { if (!localStorage.getItem('session')) {
function generateUUID() { function generateUUID() {
@@ -48,19 +45,107 @@ const ChatBot = ({ existingConversation }) => {
} }
}, []); }, []);
function base64ToFile(base64Data, filename) {
const arr = base64Data.split(',');
const mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
}
const askToBot = async ({ type = 'text', content, tryCount = 0 }) => {
const session = JSON.parse(localStorage.getItem('session'));
if (!session || !session.sessionId) return;
let body;
let headers;
const isBase64Image = type === 'image' && typeof content === 'string' && content.startsWith('data:image/');
if (isBase64Image) {
const file = base64ToFile(content, 'photo.jpg');
const formData = new FormData();
formData.append('sessionId', session.sessionId);
formData.append('lastSeen', new Date().toISOString());
formData.append('name', session.name || '');
formData.append('phoneNumber', session.phoneNumber || '');
formData.append('type', type);
formData.append('image', file);
body = formData;
headers = {};
} else {
body = JSON.stringify({
sessionId: session.sessionId,
lastSeen: new Date().toISOString(),
name: session.name,
phoneNumber: session.phoneNumber,
pertanyaan: content,
type: type,
});
headers = { 'Content-Type': 'application/json' };
}
try {
const response = await fetch('https://bot.kediritechnopark.com/webhook/master-agent/ask', {
method: 'POST',
headers,
body,
});
const data = await response.json();
return data;
} catch (error) {
if (tryCount < 3) {
return new Promise((resolve) =>
setTimeout(() => resolve(askToBot({ type, content, tryCount: tryCount + 1 })), 3000)
);
} else {
console.error('Bot unavailable:', error);
return { jawaban: 'Maaf saya sedang tidak tersedia sekarang, coba lagi nanti' };
}
}
};
const handleUploadImage = async (img) => {
setIsOpenCamera(false);
const newMessages = [
...messages,
{ sender: 'user', img: img, time: getTime() },
];
setMessages(newMessages);
setIsLoading('Menganalisa gambar anda...');
const data = await askToBot({ type: 'image', content: img });
const botAnswer = data.jawaban || 'Maaf, saya tidak bisa menganalisis gambar tersebut.';
setMessages((prev) => [
...prev,
{ sender: 'bot', text: botAnswer, time: getTime() },
]);
setIsLoading('');
};
const sendMessage = async (textOverride = null, name, phoneNumber, tryCount = 0) => { const sendMessage = async (textOverride = null, name, phoneNumber, tryCount = 0) => {
const message = textOverride || input.trim(); const message = textOverride || input.trim();
if (message === '') return; if (message === '') return;
const session = JSON.parse(localStorage.getItem('session')); const session = JSON.parse(localStorage.getItem('session'));
if ((!session || !session.name || !session.phoneNumber) && messages.length > 2) {
if ((!session || !session.name || !session.phoneNumber) && messages.length > 2) { setIsPoppedUp(message);
setIsPoppedUp(message); // munculkan form input
setInput(''); setInput('');
return; return;
} }
// Show user's message immediately
const newMessages = [ const newMessages = [
...messages, ...messages,
{ sender: 'user', text: message, time: getTime() }, { sender: 'user', text: message, time: getTime() },
@@ -68,87 +153,68 @@ const ChatBot = ({ existingConversation }) => {
setMessages(newMessages); setMessages(newMessages);
setInput(''); setInput('');
setIsLoading('Mengetik...');
setIsLoading(true);
try { try {
// Send to backend const data = await askToBot({ type: 'text', content: message, tryCount });
const response = await fetch('https://bot.kediritechnopark.com/webhook/master-agent/ask', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pertanyaan: message, sessionId: JSON.parse(localStorage.getItem('session')).sessionId, lastSeen: new Date().toISOString(), name: JSON.parse(localStorage.getItem('session')).name, phoneNumber: JSON.parse(localStorage.getItem('session')).phoneNumber }),
});
const data = await response.json();
console.log(data)
// Assuming your backend sends back something like: { answer: "text" }
// Adjust this according to your actual response shape
const botAnswer = data.jawaban || 'Maaf saya sedang tidak tersedia sekarang, coba lagi nanti'; const botAnswer = data.jawaban || 'Maaf saya sedang tidak tersedia sekarang, coba lagi nanti';
// Add bot's reply
setMessages(prev => [ setMessages(prev => [
...prev, ...prev,
{ sender: 'bot', text: botAnswer, time: getTime() }, { sender: 'bot', text: botAnswer, time: getTime() },
]); ]);
setIsLoading(false); setIsLoading('');
} catch (error) { } catch (error) {
console.log(tryCount) console.error('Error sending message:', error);
if (tryCount > 3) { if (tryCount >= 3) {
// Add bot's error reply
setMessages(prev => [ setMessages(prev => [
...prev, ...prev,
{ sender: 'bot', text: 'Maaf saya sedang tidak tersedia sekarang, coba lagi nanti', time: getTime() }, { sender: 'bot', text: 'Maaf saya sedang tidak tersedia sekarang, coba lagi nanti', time: getTime() },
]); ]);
setIsLoading(false); setIsLoading('');
return; } else {
setTimeout(() => sendMessage(message, name, phoneNumber, tryCount + 1), 3000);
} }
setTimeout(() => sendMessage(message, name, phoneNumber, tryCount + 1), 3000);
console.error('Fetch error:', error);
} }
}; };
function formatBoldText(text) {
const parts = text.split(/(\*\*[^\*]+\*\*)/g);
return parts.flatMap((part, index) => { function formatBoldText(text) {
const elements = []; const parts = text.split(/(\*\*[^\*]+\*\*)/g);
if (part.startsWith('**') && part.endsWith('**')) { return parts.flatMap((part, index) => {
// Bold text const elements = [];
part = part.slice(2, -2);
part.split('\n').forEach((line, i) => {
if (i > 0) elements.push(<br key={`br-bold-${index}-${i}`} />);
elements.push(<strong key={`bold-${index}-${i}`}>{line}</strong>);
});
} else {
// Normal text
part.split('\n').forEach((line, i) => {
if (i > 0) elements.push(<br key={`br-${index}-${i}`} />);
elements.push(<span key={`text-${index}-${i}`}>{line}</span>);
});
}
return elements; if (part.startsWith('**') && part.endsWith('**')) {
}); part = part.slice(2, -2);
} part.split('\n').forEach((line, i) => {
if (i > 0) elements.push(<br key={`br-bold-${index}-${i}`} />);
elements.push(<strong key={`bold-${index}-${i}`}>{line}</strong>);
});
} else {
part.split('\n').forEach((line, i) => {
if (i > 0) elements.push(<br key={`br-${index}-${i}`} />);
elements.push(<span key={`text-${index}-${i}`}>{line}</span>);
});
}
const handleUploadImage = (e) => { return elements;
console.log(e) });
} }
return ( return (
<div className={styles.chatContainer} > <div className={styles.chatContainer}>
<div className={styles.chatHeader}> <div className={styles.chatHeader}>
<img src="/dermalounge.jpg" alt="Bot Avatar" /> <img src="/dermalounge.jpg" alt="Bot Avatar" />
<strong>DERMALOUNGE</strong> <strong>DERMALOUNGE</strong>
</div> </div>
<div className={styles.chatBody}> <div className={styles.chatBody}>
{isLoading != '' && (
{isLoading && (
<div className={`${styles.messageRow} ${styles.bot}`}> <div className={`${styles.messageRow} ${styles.bot}`}>
<div className={`${styles.message} ${styles.bot}`}> <div className={`${styles.message} ${styles.bot}`}>
<em>Mengetik...</em> <em>{isLoading}</em>
</div> </div>
</div> </div>
)} )}
@@ -159,15 +225,18 @@ const handleUploadImage = (e) => {
> >
<div className={`${styles.message} ${styles[msg.sender]}`}> <div className={`${styles.message} ${styles[msg.sender]}`}>
{msg.sender !== 'bot' {msg.sender !== 'bot'
? msg.text ? (msg.text ?
: (() => { msg.text
try { :
return formatBoldText(msg.text); // Apply formatting here <img style={{ height: '160px', borderRadius: '12px' }} src={msg.img} />
} catch (e) { )
return msg.text; : (() => {
} try {
})()} return formatBoldText(msg.text);
} catch (e) {
return msg.text;
}
})()}
{msg.quickReplies && ( {msg.quickReplies && (
<div className={styles.quickReplies}> <div className={styles.quickReplies}>
{msg.quickReplies.map((reply, i) => ( {msg.quickReplies.map((reply, i) => (
@@ -179,14 +248,14 @@ const handleUploadImage = (e) => {
{reply} {reply}
</div> </div>
))} ))}
<div <div
className={styles.quickReply} className={styles.quickReply}
onClick={() => setIsOpenCamera(true)} onClick={() => setIsOpenCamera(true)}
style={{color: 'white', backgroundColor: '#075e54', display: 'flex', flexDirection: 'row', alignItems:'center'}} style={{ color: 'white', backgroundColor: '#075e54', display: 'flex', flexDirection: 'row', alignItems: 'center' }}
> >
<img style={{marginRight: '5px', height: '14px', filter: 'invert(1)'}}src={'/face.png'}/> <img style={{ marginRight: '5px', height: '14px', filter: 'invert(1)' }} src={'/camera.png'} />
Analisa Kulit Analisa Gambar
</div> </div>
</div> </div>
)} )}
<div className={styles.timestamp}>{msg.time}</div> <div className={styles.timestamp}>{msg.time}</div>
@@ -195,21 +264,34 @@ const handleUploadImage = (e) => {
))} ))}
</div> </div>
<div className={styles.chatInput} /*/style={{ visibility: readOnly ? 'hidden' : 'visible'}}/*/> <div className={styles.chatInput}>
<input <input
type="text" type="text"
placeholder="Ketik pesan..." placeholder="Ketik pesan..."
value={input} value={input}
onChange={(e) => setInput(e.target.value)} onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && sendMessage()} onKeyDown={(e) => e.key === 'Enter' && sendMessage()}
disabled={isLoading} disabled={isLoading != ''}
/> />
<button onClick={() => sendMessage()} disabled={isLoading}> <button onClick={() => sendMessage()} style={{marginLeft: '-40px'}}disabled={isLoading!=''}>
Kirim <img
src="/send.png"
alt="Kirim"
style={{ height: '20px', filter: 'invert(1)' }}
/>
</button>
<button onClick={() => setIsOpenCamera(true)} disabled={isLoading!=''}>
<img
src="/camera.png"
alt="Kamera"
style={{ height: '18px', filter: 'invert(1)' }}
/>
</button> </button>
</div> </div>
{isPoppedUp != '' &&
{isPoppedUp !== '' &&
<div className={styles.PopUp}> <div className={styles.PopUp}>
<div className={`${styles.message} ${styles['bot']}`}> <div className={`${styles.message} ${styles['bot']}`}>
Untuk bisa membantu Anda lebih jauh, boleh saya tahu nama dan nomor telepon Anda? Untuk bisa membantu Anda lebih jauh, boleh saya tahu nama dan nomor telepon Anda?
@@ -218,7 +300,6 @@ const handleUploadImage = (e) => {
<input <input
className={styles.quickReply} className={styles.quickReply}
placeholder="Nama Lengkapmu" placeholder="Nama Lengkapmu"
onFocus={() => console.log('Nama focused')}
value={name} value={name}
onChange={(e) => setName(e.target.value)} onChange={(e) => setName(e.target.value)}
maxLength={40} maxLength={40}
@@ -235,14 +316,11 @@ const handleUploadImage = (e) => {
value={phoneNumber} value={phoneNumber}
onChange={(e) => { onChange={(e) => {
const value = e.target.value; const value = e.target.value;
// Hanya angka, maksimal 11 karakter
if (/^\d{0,11}$/.test(value)) { if (/^\d{0,11}$/.test(value)) {
setPhoneNumber(value); setPhoneNumber(value);
} }
}} }}
onFocus={() => console.log('Telepon focused')}
/> />
</div> </div>
<div <div
@@ -250,13 +328,11 @@ const handleUploadImage = (e) => {
onClick={() => { onClick={() => {
if (name.length > 2 && phoneNumber.length >= 10) { if (name.length > 2 && phoneNumber.length >= 10) {
const sessionData = JSON.parse(localStorage.getItem('session')) || {}; const sessionData = JSON.parse(localStorage.getItem('session')) || {};
sessionData.name = name; sessionData.name = name;
sessionData.phoneNumber = phoneNumber; sessionData.phoneNumber = phoneNumber;
localStorage.setItem('session', JSON.stringify(sessionData)); localStorage.setItem('session', JSON.stringify(sessionData));
setIsPoppedUp('') setIsPoppedUp('');
sendMessage(isPoppedUp) sendMessage(isPoppedUp);
} }
}} }}
> >
@@ -266,7 +342,13 @@ const handleUploadImage = (e) => {
</div> </div>
</div> </div>
} }
{isOpenCamera && <Camera handleClose={()=>setIsOpenCamera(false)} handleUploadImage={(e)=>handleUploadImage(e)}/>}
{isOpenCamera && (
<Camera
handleClose={() => setIsOpenCamera(false)}
handleUploadImage={(e) => handleUploadImage(e)}
/>
)}
</div> </div>
); );
}; };