import React, { useCallback, useEffect, useState } from "react";
import VideoContainerView from "../selfView/VideoContainerView";
import Button from "src/common/Button/Button";
import { useTwilioUserMediaContext } from "../../call-sdk/context/TwilioUserMediaContext";
import { useNavigate } from "react-router-dom";
import ErrorBoundary from "../ErrorBoundary";
import { datadogRum } from "@datadog/browser-rum";
import HelpScreenDialog from "./HelpScreen/HelpScreenDialog";
import { useCall } from "src/call-sdk/context/CallContext";
import { useToast } from "src/context/ToastContext";
import {
PermisionContainer,
AccessContainer,
ButtonContainer,
HelpContainer,
} from "./PermissionStyles";
import Typography from "@mui/material/Typography";
import { Alert, AlertTitle, IconButton } from "@mui/material";
const Permission = () => {
const {
requestMediaPermission,
reRequestMediaPermission,
audioDeviceId,
videoDeviceId,
isMediaPermissionGranted,
isMediaPermissionDenied,
isMediaPermissionDeniedByUser,
destroyMedia,
} = useTwilioUserMediaContext();
const navigate = useNavigate();
const [helpClicked, setHelpClicked] = useState(false);
const [showErrorBanner, setShowErrorBanner] = useState(false)
// const [isCameraAccess, setIsCameraAccess] = useState(false)//set state to indicate camera accesss
const call = useCall();
const toast = useToast()
const handleRequestPermission = useCallback(() => {
if (!isMediaPermissionGranted) {
requestMediaPermission({
type: "ideal",
audioDeviceId: audioDeviceId ?? "",
videoDeviceId: videoDeviceId ?? "",
});
}
}, [
audioDeviceId,
isMediaPermissionGranted,
requestMediaPermission,
videoDeviceId,
]);
const handleReRequest = useCallback(() => {
datadogRum.addAction("user clicked try again - reaccesing permissions ");
// setIsCameraAccess(true)
reRequestMediaPermission({
type: "ideal",
audioDeviceId: audioDeviceId ?? "",
videoDeviceId: videoDeviceId ?? "",
});
}, [audioDeviceId, reRequestMediaPermission, videoDeviceId]);
// Function to check if the device is iOS
const isIOS = () => {
return /iPad|iPhone|iPod/.test(navigator.userAgent);
};
const handleIOSpermission = () => {
destroyMedia();
call.destroy();
datadogRum.addAction(
"user clicked on Try again in IOS - reaccesing permissions"
);
navigate({ pathname: `/qr-reconnecting` }, { replace: true });
};
useEffect(() => {
changeAddressBarColor();
if (isMediaPermissionGranted) {
navigate({ pathname: "/qr-connecting" }, { replace: true });
// if (isCameraAccess){//show the version only if accessing the camera
// //extract OS version from user agent
console.log("camera access..........")
const osversion = navigator.userAgent.match(/(iPad|iPhone|Android).*?([d.]+)/);
if(osversion){
const version = osversion[2]
window.alert("operating system version: " + version)
if (parseFloat(version)>=16){
setShowErrorBanner(true)
toast.error("Error while showing the self view in this version",
// {
// action:(
// <Button>undo</Button>
// )}
)
}
}
} else if (isMediaPermissionDenied) {
datadogRum.addAction("user denied permissions ");
} else {
handleRequestPermission();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isMediaPermissionGranted, isMediaPermissionDenied, navigate]);
const changeAddressBarColor = () => {
let metas = document.head.getElementsByTagName("meta");
metas[2].content = "#000000";
document.body.style.backgroundColor = "#000000";
};
const handleHelpClose = () => {
setHelpClicked(false);
};
const handleHelpOpen = () => {
setHelpClicked(true);
};
const handleErrorBannerAction = () =>{
console.log("Action button clicked")
//toast.info("action button clicked")
}
return (
<ErrorBoundary>
<PermisionContainer>
<VideoContainerView />
{showErrorBanner && (
<Alert
action={
<Button color="inherit" size = "small" onClick={handleErrorBannerAction}>
UNDO
</Button>
}
>
</Alert>
)}
{(!isMediaPermissionGranted || isMediaPermissionDenied) && (
<AccessContainer>
{isMediaPermissionDeniedByUser && (
<div>
<p className="oops">Oops!</p>
<p className="instruction">
Please try again by allowing access to your camera and
microphone
</p>
</div>
)}
<ButtonContainer>
{isMediaPermissionDeniedByUser && (
<Button
onClick={() => {
if (isIOS()) {
handleIOSpermission();
} else {
handleReRequest();
}
}}
fullWidth
>
Try Again
</Button>
)}
</ButtonContainer>
{isMediaPermissionDeniedByUser && (
<HelpContainer onClick={handleHelpOpen}>
<Typography style={{ color: "#1884EB", fontSize: "20px" }}>
Need Help?
</Typography>
</HelpContainer>
)}
</AccessContainer>
)}
</PermisionContainer>
<HelpScreenDialog open={helpClicked} onClose={handleHelpClose} />
</ErrorBoundary>
);
};
export default Permission;
ToastContext.ts:
import { Button, IconButton, Snackbar, SnackbarOrigin } from "@mui/material";
import Alert from "@mui/material/Alert";
import React, { createContext, useCallback, useContext, useState } from "react";
type ToastOptions = {
// timeout: number;
origin: SnackbarOrigin;
};
type ToastSuccess = (message: string, options?: ToastOptions) => void;
type ToastError = (message: string, options?: ToastOptions) => void;
type ToastContextValue = {
success: ToastSuccess;
error: ToastError;
};
export const ToastContext = createContext<ToastContextValue>({
success: () => {},
error: () => {},
});
type ToastMessage = {
id: string;
type: "success" | "error";
message: string;
options: ToastOptions;
open: boolean;
};
const defaultOptions: ToastOptions = {
// timeout: 5000,
origin: {
horizontal: "center",
vertical: "top",
},
};
export const ToastProvider: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const [messages, setMessages] = useState<ToastMessage[]>([]);
const success: ToastSuccess = useCallback(
(message, options = defaultOptions) => {
const newMessage: ToastMessage = {
id: Date.now().toString(),
type: "success",
message,
options,
open: true,
};
setMessages((prevMessages) => [...prevMessages, newMessage]);
},
[]
);
const error: ToastError = useCallback((message, options = defaultOptions) => {
const newMessage: ToastMessage = {
id: Date.now().toString(),
type: "error",
message,
options,
open: true,
};
setMessages((prevMessages) => [...prevMessages, newMessage]);
}, []);
const onClose = (messageId: string) => {
const filteredMessages = messages.filter(
(message) => message.id !== messageId
);
setMessages([...filteredMessages]);
};
return (
<ToastContext.Provider value={{ success, error }}>
{children}
{messages.map((message) => (
<Snackbar
key={message.id}
open={message.open}
// autoHideDuration={message.options.timeout}
onClose={() => onClose(message.id)}
anchorOrigin={message.options.origin}
>
<Alert
variant="filled"
severity={message.type}
onClose={() => onClose(message.id)}
>
{message.message}
</Alert>
</Snackbar>
))}
</ToastContext.Provider>
);
};
export const ToastConsumer = ToastContext.Consumer;
export const useToast = () => useContext(ToastContext);
I had added toast error message if the os version of iphone is greator or equals to 16.
Now I want to display the action button on the Error banner beside the error message
and when I click on that button I want to show some steps of instructions. I have
tried giving button name inside action props like “UNDO” but button is not
getting display along the with the toast message. Any leads would be appreciated.