import { useRef, useState, useCallback, useEffect } from "react"; import { SwitchCamera, CameraOff, Aperture } from "lucide-react"; import { Button } from "@/components/ui/button"; interface CameraCaptureProps { onCapture: (file: File) => void; onClose: () => void; } type FacingMode = "environment" | "user"; export function CameraCapture({ onCapture, onClose }: CameraCaptureProps) { const videoRef = useRef(null); const streamRef = useRef(null); const canvasRef = useRef(null); const [facingMode, setFacingMode] = useState("environment"); const [status, setStatus] = useState<"loading" | "ready" | "error" | "denied">("loading"); const [errorMsg, setErrorMsg] = useState(""); const stopStream = useCallback(() => { if (streamRef.current) { streamRef.current.getTracks().forEach((t) => t.stop()); streamRef.current = null; } }, []); const startCamera = useCallback( async (mode: FacingMode) => { stopStream(); setStatus("loading"); setErrorMsg(""); try { const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: mode, width: { ideal: 1920 }, height: { ideal: 1080 }, }, audio: false, }); streamRef.current = stream; if (videoRef.current) { videoRef.current.srcObject = stream; await videoRef.current.play(); } setStatus("ready"); } catch (err: unknown) { const e = err as DOMException; if (e.name === "NotAllowedError" || e.name === "PermissionDeniedError") { setStatus("denied"); setErrorMsg("Izin kamera ditolak. Buka pengaturan untuk mengizinkan akses kamera."); } else if (e.name === "NotFoundError") { setStatus("error"); setErrorMsg("Kamera tidak ditemukan pada perangkat ini."); } else if (e.name === "NotReadableError") { setStatus("error"); setErrorMsg("Kamera sedang digunakan oleh aplikasi lain."); } else { setStatus("error"); setErrorMsg(`Gagal mengakses kamera: ${e.message}`); } } }, [stopStream], ); // Start camera on mount useEffect(() => { startCamera(facingMode); return () => stopStream(); }, []); // eslint-disable-line react-hooks/exhaustive-deps const toggleFacing = () => { const next = facingMode === "environment" ? "user" : "environment"; setFacingMode(next); startCamera(next); }; const handleCapture = () => { const video = videoRef.current; const canvas = canvasRef.current; if (!video || !canvas) return; const vw = video.videoWidth; const vh = video.videoHeight; canvas.width = vw; canvas.height = vh; const ctx = canvas.getContext("2d"); if (!ctx) return; ctx.drawImage(video, 0, 0, vw, vh); canvas.toBlob( (blob) => { if (!blob) return; const file = new File([blob], `camera-${Date.now()}.jpg`, { type: "image/jpeg", }); stopStream(); onCapture(file); }, "image/jpeg", 0.92, ); }; return (
{/* Viewfinder */}
{status === "loading" && (
Membuka kamera...
)} {(status === "error" || status === "denied") && (

{errorMsg}

)}