diff --git a/src/Utils/cameraPermissionHandler.ts b/src/Utils/cameraPermissionHandler.ts index 61f59a73019..c4a55ba685c 100644 --- a/src/Utils/cameraPermissionHandler.ts +++ b/src/Utils/cameraPermissionHandler.ts @@ -1,24 +1,30 @@ -import { useTranslation } from "react-i18next"; +import { useCallback, useState } from "react"; import { toast } from "sonner"; -const { t } = useTranslation(); +export const handleCameraPermission = () => { + const [toastShown, setToastShown] = useState(false); -let toastShown = false; + const requestPermission = useCallback( + async (device: "camera", cameraFacingMode: string = "user") => { + try { + setToastShown(false); + const constraints = + device === "camera" + ? { video: { facingMode: cameraFacingMode } } + : { audio: true }; -export const handleCameraPermission = async ( - cameraFacingMode: string, - onPermissionDenied: () => void, -) => { - toastShown = false; - try { - await navigator.mediaDevices.getUserMedia({ - video: { facingMode: cameraFacingMode }, - }); - } catch (_error) { - if (!toastShown) { - toastShown = true; - toast.warning(t("camera_permission_denied")); - } - onPermissionDenied(); - } + await navigator.mediaDevices.getUserMedia(constraints); + return true; + } catch (_error) { + if (!toastShown) { + setToastShown(true); + toast.warning(`${device} permission denied`); + } + return false; // Permission denied + } + }, + [toastShown], + ); + + return { requestPermission }; }; diff --git a/src/components/Common/AvatarEditModal.tsx b/src/components/Common/AvatarEditModal.tsx index a6996a642d5..33fbb6b3ddd 100644 --- a/src/components/Common/AvatarEditModal.tsx +++ b/src/components/Common/AvatarEditModal.tsx @@ -79,6 +79,7 @@ const AvatarEditModal = ({ ); const { t } = useTranslation(); const [isDragging, setIsDragging] = useState(false); + const { requestPermission } = handleCameraPermission(); const handleSwitchCamera = useCallback(() => { setConstraint( @@ -394,9 +395,13 @@ const AvatarEditModal = ({ ref={webRef} videoConstraints={constraint} onUserMediaError={async () => { - await handleCameraPermission("user", () => - setIsCameraOpen(false), + const hasPermission = await requestPermission( + "camera", + "user", ); + if (!hasPermission) { + setIsCameraOpen(false); + } }} /> diff --git a/src/components/Files/CameraCaptureDialog.tsx b/src/components/Files/CameraCaptureDialog.tsx index 8ee66a313d6..8165dd2326e 100644 --- a/src/components/Files/CameraCaptureDialog.tsx +++ b/src/components/Files/CameraCaptureDialog.tsx @@ -15,6 +15,8 @@ import { import useBreakpoints from "@/hooks/useBreakpoints"; +import { handleCameraPermission } from "@/Utils/cameraPermissionHandler"; + export interface CameraCaptureDialogProps { open: boolean; onOpenChange: (open: boolean) => void; @@ -26,6 +28,8 @@ export interface CameraCaptureDialogProps { export default function CameraCaptureDialog(props: CameraCaptureDialogProps) { const { open, onOpenChange, onCapture, onResetCapture, setPreview } = props; const isLaptopScreen = useBreakpoints({ lg: true, default: false }); + const { requestPermission } = handleCameraPermission(); + const [stream, setStream] = useState(null); const [cameraFacingMode, setCameraFacingMode] = useState( isLaptopScreen ? "user" : "environment", @@ -41,17 +45,25 @@ export default function CameraCaptureDialog(props: CameraCaptureDialogProps) { useEffect(() => { if (!open) return; - let stream: MediaStream | null = null; - navigator.mediaDevices - .getUserMedia({ video: { facingMode: cameraFacingMode } }) - .then((mediaStream) => { - stream = mediaStream; - }) - .catch(() => { - toast.warning(t("camera_permission_denied")); + const getCameraStream = async () => { + const hasPermission = await requestPermission("camera", cameraFacingMode); + if (!hasPermission) { onOpenChange(false); - }); + return; + } + + try { + const mediaStream = await navigator.mediaDevices.getUserMedia({ + video: { facingMode: cameraFacingMode }, + }); + setStream(mediaStream); + } catch (error) { + console.error("Error accessing camera:", error); + } + }; + + getCameraStream(); return () => { if (stream) {