diff --git a/src/Camera.js b/src/Camera.js
new file mode 100644
index 0000000..dd775aa
--- /dev/null
+++ b/src/Camera.js
@@ -0,0 +1,317 @@
+import React, { useState, useRef, useEffect } from 'react';
+
+const CameraPage = ({ handleClose, handleUploadImage }) => {
+ const [image, setImage] = useState(null);
+ const [isCameraActive, setIsCameraActive] = useState(true);
+ const [uploading, setUploading] = useState(false);
+ const [isMobile, setIsMobile] = useState(false);
+ const videoRef = useRef(null);
+ const canvasRef = useRef(null);
+ const fileInputRef = useRef(null);
+
+ // Check if device is mobile
+ useEffect(() => {
+ const checkMobile = () => {
+ setIsMobile(window.innerWidth <= 768);
+ };
+
+ checkMobile();
+ window.addEventListener('resize', checkMobile);
+
+ return () => window.removeEventListener('resize', checkMobile);
+ }, []);
+
+ // Start the camera when the component mounts
+ useEffect(() => {
+ const startCamera = async () => {
+ try {
+ const stream = await navigator.mediaDevices.getUserMedia({
+ video: { facingMode: 'environment' },
+ });
+ if (videoRef.current) {
+ videoRef.current.srcObject = stream;
+ }
+ } catch (error) {
+ console.error('Error accessing camera:', error);
+ }
+ };
+ startCamera();
+
+ // Cleanup camera stream when component unmounts
+ return () => {
+ if (videoRef.current && videoRef.current.srcObject) {
+ const tracks = videoRef.current.srcObject.getTracks();
+ tracks.forEach(track => track.stop());
+ }
+ };
+ }, []);
+
+ // Capture the image from the video stream
+ const captureImage = () => {
+ const canvas = canvasRef.current;
+ const video = videoRef.current;
+
+ if (video && canvas) {
+ canvas.width = video.videoWidth;
+ canvas.height = video.videoHeight;
+
+ const ctx = canvas.getContext('2d');
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
+
+ const capturedImage = canvas.toDataURL('image/jpeg');
+ setImage(capturedImage);
+ setIsCameraActive(false);
+ }
+ };
+
+ // Handle image upload from file input
+ const handleFileUpload = e => {
+ const file = e.target.files[0];
+ if (file) {
+ const reader = new FileReader();
+ reader.onloadend = () => {
+ setImage(reader.result);
+ setIsCameraActive(false);
+ };
+ reader.readAsDataURL(file);
+ }
+ };
+
+ // Cancel the image capture or file upload and restart the camera
+ const cancelCapture = () => {
+ setImage(null);
+ setIsCameraActive(true);
+ const startCamera = async () => {
+ try {
+ const stream = await navigator.mediaDevices.getUserMedia({
+ video: { facingMode: 'environment' },
+ });
+ if (videoRef.current) {
+ videoRef.current.srcObject = stream;
+ }
+ } catch (error) {
+ console.error('Error accessing camera:', error);
+ }
+ };
+ startCamera();
+ };
+
+ // Trigger file input click
+ const triggerFileInput = () => {
+ fileInputRef.current?.click();
+ };
+
+ const mainContent = (
+
+ {/* Camera/Image Display Area */}
+
+ {isCameraActive && (
+
+ )}
+
+ {!isCameraActive && image && (
+

+ )}
+
+ {/* Floating Controls */}
+
+ {isCameraActive ? (
+ <>
+
+
+
+ >
+ ) : (
+ <>
+
+
+ >
+ )}
+
+
+ {/* Hidden file input */}
+
+
+
+ {/* Hidden canvas element for capturing the image */}
+
+
+ );
+
+ // Desktop layout with left and right sidebars
+ if (!isMobile) {
+ return (
+
+ {/* Left Sidebar */}
+
+
+ {/* Main content */}
+
{mainContent}
+
+ {/* Right Sidebar */}
+
+
+ );
+ }
+
+ // Mobile layout (full screen)
+ return mainContent;
+};
+
+// Styles
+const containerStyle = {
+ position: 'absolute',
+ width: '100%',
+ height: '100vh',
+ backgroundColor: '#000',
+ overflow: 'hidden',
+};
+
+const cameraContainerStyle = {
+ position: 'relative',
+ width: '100%',
+ height: '100%',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+};
+
+const videoStyle = {
+ width: '100%',
+ height: '100%',
+ objectFit: 'cover',
+};
+
+const imageStyle = {
+ width: '100%',
+ height: '100%',
+ objectFit: 'cover',
+};
+
+const controlsStyle = {
+ position: 'absolute',
+ bottom: '30px',
+ left: '50%',
+ transform: 'translateX(-50%)',
+ display: 'flex',
+ gap: '20px',
+ alignItems: 'center',
+};
+
+const baseButtonStyle = {
+ width: '60px',
+ height: '60px',
+ borderRadius: '50%',
+ border: 'none',
+ fontSize: '24px',
+ cursor: 'pointer',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)',
+ 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 = {
+ ...baseButtonStyle,
+ backgroundColor: '#4CAF50',
+ color: '#fff',
+};
+
+// Desktop styles
+const desktopLayoutStyle = {
+ display: 'flex',
+ height: '100vh',
+ fontFamily: 'Arial, sans-serif',
+};
+
+const sidebarStyle = {
+ width: '250px',
+ backgroundColor: '#fff',
+ color: '#333',
+ padding: '20px',
+ boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)',
+ 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 = {
+ flex: 1,
+ position: 'relative',
+};
+
+export default CameraPage;
diff --git a/src/ChatBot.js b/src/ChatBot.js
index 720a95e..6c6c6ff 100644
--- a/src/ChatBot.js
+++ b/src/ChatBot.js
@@ -1,5 +1,6 @@
import React, { useState, useEffect } from 'react';
import styles from './ChatBot.module.css';
+import Camera from './Camera'
const ChatBot = ({ existingConversation }) => {
const [messages, setMessages] = useState([
@@ -22,6 +23,8 @@ const ChatBot = ({ existingConversation }) => {
const [isPoppedUp, setIsPoppedUp] = useState('');
const [name, setName] = useState('');
const [phoneNumber, setPhoneNumber] = useState('');
+
+ const [isOpenCamera, setIsOpenCamera] = useState(false);
useEffect(() => {
if (existingConversation && existingConversation.length > 0) {
@@ -129,6 +132,9 @@ function formatBoldText(text) {
});
}
+const handleUploadImage = (e) => {
+ console.log(e)
+}
return (
@@ -175,11 +181,11 @@ function formatBoldText(text) {
))}
sendMessage('analist')}
+ onClick={() => setIsOpenCamera(true)}
style={{color: 'white', backgroundColor: '#075e54', display: 'flex', flexDirection: 'row', alignItems:'center'}}
>
![]()
- Analisa Wajah
+ Analisa Kulit
)}
@@ -260,6 +266,7 @@ function formatBoldText(text) {
}
+ {isOpenCamera && setIsOpenCamera(false)} handleUploadImage={(e)=>handleUploadImage(e)}/>}
);
};