React (not native) ask camera permission - reactjs

I have a web app that needs to acces to camera, but I want to ask camera permission manually, because if the web app detects automatically camera permission, it will do it "too late".
What I need is to ask for permission, then I could render a 3rd party javascript function that renders a camera.
With react native is easy, but with normal React I can't find a way to ask when I want those permissions, for Chrome and Safari.
Any idea?

Prior to the link on the comment of #Shubh (thanks) I get it working only for Chrome:
navigator.permissions.query({ name: 'camera' })
.then((permissionObj) => {
console.log(permissionObj.state);
permission = permissionObj.state;
})
.catch((error) => {
console.log('Got error :', error);
});
But this is not supported for iphone IOS (Safari).
Now with getUserMedia() API I have this code semi-working:
let stream = null;
const constraints = {
video: true
};
try {
stream = await navigator.mediaDevices.getUserMedia(constraints);
/* use the stream */
} catch (err) {
/* handle the error */
}
My only problem here is the light on the camera (desktop) get stucked, I'm trying to find now how to "close" the getUserMedia, I just want to grant permissions, like the first way.
Edit: now for turn off the camera I did this:
const askCameraPermission =
async (): Promise<MediaStream | null> => await navigator.mediaDevices.getUserMedia({ video: true });
let localstream: MediaStream | null;
askCameraPermission()
.then(response => {
localstream = response;
})
.then(() => {
localstream?.getTracks().forEach(track => {
track.stop();
});
})
.catch(error => console.log(error));

navigator.getUserMedia({audio:true,video:true}, function(stream) {
stream.getTracks().forEach(x=>x.stop());
}, err=>console.log(err));
Take the stream, get the tracks and stop them to turn off the camera. Camera will still flash, but it will turn off.
Here is the demo: https://codesandbox.io/s/camera-app-86me8?file=/src/App.js

Make sure you check the error in the catch... it told me my problem...didn't have an input device connected!

Related

Why won't my React Native Expo app prompt the user to give permission for notifications?

I am creating a React Native app for Android using Expo, EAS Build.
Following the docs here, I set up notifications for my app, including Firebase Cloud Messaging.
In my code, which is mostly taken from the docs, I check for notifications permission upon app launch using UseEffect, and if the app does not have permission, I request the permissions.
However, when I load the app on my development server, the alert pops up stating, "Failed to get push token for push notification!"
Just to make sure everything else is working, I went and enabled notification permission manually on my device via settings. Then, the app works great. The notifications I am scheduling work. There are no problems.
But obviously, I don't want the user to have to manually go to settings. I'd like the prompt to appear.
Could this be an issue with the development server which will no longer exist once deployed?
Any help appreciated. Thanks.
Here is what I believe to be the relevant code below from my App.js. I expected a prompt to appear for the user when they open the app the first time asking them to give notification permission.
import * as Notifications from "expo-notifications";
// other import statements
Notifications.setNotificationHandler({
handleNotification: async () => {
return {
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: true,
};
},
});
// other code
export default function App() {
// other code
const notificationListener = useRef();
const responseListener = useRef();
useEffect(() => {
registerForPushNotificationsAsync().then(token => setExpoPushToken(token));
// This listener is fired whenever a notification is received while the app is foregrounded
notificationListener.current = Notifications.addNotificationReceivedListener(notification => {
setNotification(notification);
});
// This listener is fired whenever a user taps on or interacts with a notification (works when app is foregrounded, backgrounded, or killed)
responseListener.current = Notifications.addNotificationResponseReceivedListener(response => {
// console.log(response);
});
return () => {
Notifications.removeNotificationSubscription(notificationListener.current);
Notifications.removeNotificationSubscription(responseListener.current);
};
// other unrelated code
}, []);
// code related to the app itself
}
// below is the function i call above upon app launch in order to get notification
// but no prompt comes up for the user
async function registerForPushNotificationsAsync() {
let token;
if (Device.isDevice) {
console.log('about to getPermissionsAsync');
const { status: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
console.log('about to requestPermissionsAsync');
const { status } = await Notifications.requestPermissionsAsync();
console.log('the status gotten by requestPermissionsAsync() is the line below this: ');
console.log(status);
finalStatus = status;
}
if (finalStatus !== 'granted') {
alert('Failed to get push token for push notification!');
return;
}
console.log('about to get token');
token = (await Notifications.getExpoPushTokenAsync({
experienceId: '#johnquiet/buglecallexplore ',
})).data;
console.log('should see token below this line');
console.log(token);
} else {
alert('Must use physical device for Push Notifications');
}
if (Platform.OS === 'android') {
Notifications.setNotificationChannelAsync('alarms', {
name: 'Scheduled Notifications',
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: '#a7e7fa',
});
}
return token;
}
// more unrelated code and styles
On Android 13 the prompt asking to grant the permission will not appear until at least one notification channel is created. Make sure to call Notifications.setNotificationChannelAsync before calling Notifications.getExpoPushTokenAsync.
https://docs.expo.dev/versions/latest/sdk/notifications/#permissions

Cannot get channels moving event in Discord audit log

I'm trying to log the Discord event when someone is moving any channel.
The channelUpdate event works almost like a charm and returning 2 events (two, because of when you moving one channel the rawPosition property is changing in the target's channel and in the channel you swiped the place). Except strange cases when you moved one channel and getting tone of events as if you moved all the server channels at ones. Weird thing, yep.
The problem is the "channelUpdate" event returns only oldChannel and newChannel but not the executor data (who and when).
I've tried to use guild.fetchAuditLogs({ type: 14, limit: 1 }) but looks like it's not returning changing position events. One gets the feeling Discord's log engine is not logging this event OR I'm looking in wrong place. Also tried type 11 and even NULL with no luck on finding rawPosition prop changing.
Please, help me to find the way how to log WHO is changing the channels position or tell me it's not possible at the time.
Some code here:
const Discord = require('discord.js');
const client = new Discord.Client({ shards: 'auto'});
const { prefix, token, witaitoken , guildID, DBUser, DBPass } = require('./config.json');
client.on('ready', async () => {
console.log(`Logged in as ${client.user.tag}!`);
client.user.setActivity(`Star Citizen`, { type: 'PLAYING' });
});
client.on('channelUpdate', (oldChannel, newChannel) => {
if (oldChannel.rawPosition !== newChannel.rawPosition) {
oldChannel.guild.fetchAuditLogs({ limit: 10 })
.then( (audit) => {
const log = audit.entries;
if (!log) return;
fs = require('fs');
fs.appendFile('audit.txt', JSON.stringify(log), function (err) {
if (err) return console.log(err);
});
})
}
});
client.login(token);
client.on("error", (e) => console.error(e));
client.on("warn", (e) => console.warn(e));
client.on("debug", (e) => console.info(e));

reCAPTCHA first attempt causes it to reset. Firebase phoneAuthVerifier

Hello I'm having issues implementing recaptcha into our firebase project. I'm using it with firebase.auth.PhoneAuthProvider, to initially enroll a second factor and then use the recaptcha for multi-factor authentication on login.
I've used the https://cloud.google.com/identity-platform/docs/web/mfa doc for the implementation and it does work but it resets on the first successful attempt. The tickbox gets checked but instantly the whole recaptcha rerenders/is reset.
https://imgur.com/PJCJujo (here is a tiny video of that reset behaviour)
The fact that it is rerendering makes me think it is an error in the implementation and possibly to do with React but I am struggling to solve it.
Login Function
const frontendLogin = () => {
const { email, password } = registerDetails
firebaseApp.auth().signInWithEmailAndPassword(email, password)
.then(data => {
// if (data.user.emailVerified) {
axios.get(`/users/${data.user.uid}`)
.then(res => {
// Handle login for users not enrolled with multi-factor
})
.catch(error => {
console.log(error)
if (error.code === 'auth/multi-factor-auth-required') {
setResolver(error.resolver)
setHints(error.resolver.hints[0])
setPhoneVerifyRequired(true)
// Ask user which second factor to use.
if (error.resolver.hints[selectedIndex].factorId ===
firebase.auth.PhoneMultiFactorGenerator.FACTOR_ID) {
const phoneInfoOptions = {
multiFactorHint: error.resolver.hints[selectedIndex],
session: error.resolver.session
};
const phoneAuthProvider = new firebase.auth.PhoneAuthProvider(appAuth);
const recaptchaVerifier = new firebase.auth.RecaptchaVerifier(
captchaRef.current,
{
'size': 'normal',
'callback': function (response) {
console.log('captcha!')
handleSolved()
},
'expired-callback': function () {
console.log('captcha expired')
},
'hl': locale
},
firebaseApp);
// Send SMS verification code
return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier)
.then(function (verificationId) {
setVerificationId(verificationId)
}).catch(err => console.log(err))
} else {
// Unsupported second factor.
}
} else {
console.log(error)
}
})
}
const handleSolved = () => {
setCaptchad(true)
setIsLoading(false)
}
const handleRecaptcha = () => {
var cred = firebase.auth.PhoneAuthProvider.credential(
verificationId, verificationCode);
console.log(cred)
var multiFactorAssertion =
firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
// Complete sign-in.
resolver.resolveSignIn(multiFactorAssertion)
.then(function (data) {
// User successfully signed in with the second factor phone number.
// Handle login for users enrolled with multi-factor
})
}
I am unsure as to why this approach isn't working but I believe it may be to do with React? I have looked into using a React Recaptcha package but as the docs were just written in javascript I've just tried to implement it in this way.
I haven't deviated too far from the docs only to set state with elements including the verification ID that is returned from the successful recaptcha etc.
I also appreciate I am setting state too much and need to refactor the state at the top of the component but as I'm still fleshing this component out it hasn't been refactored yet so I apologise it's a bit messy!
If anyone has any pointers that would be great or if I need to provide more code then let me know, any help is appreciated!

how display Google-rendered consent form with react-native-firebase/admob

I am trying to integrate google ads to my react native app, so I followed everything from the official docs https://rnfirebase.io/ and I managed to display google ads.
but when it comes to European User Consent I cant display the Google-rendered consent because the result of the method AdsConsentInfo isRequestLocationInEeaOrUnknown is always false even I whitelist my device an set a debug location :
async componentDidMount(){
AdsConsent.addTestDevices(['MY_DEVICE_ID'])
const consentInfo = await AdsConsent.requestInfoUpdate(['pub-XXXXXX']);
await AdsConsent.setDebugGeography(AdsConsentDebugGeography.EEA);
if (
consentInfo.isRequestLocationInEeaOrUnknown &&
consentInfo.status === AdsConsentStatus.UNKNOWN
) {
const formResult = await AdsConsent.showForm({
privacyPolicy: 'https://invertase.io/privacy-policy',
withPersonalizedAds: false,
withNonPersonalizedAds: true,
withAdFree: false,
});
}
}
try and use, use react-native-ads-consent together with firebase ads consent for instance try setting the debug geography with react-native-ads-consent and check location and display the consent form using react-native-firebase ads consent
Place the code block inside a try catch and use a vpn and set the location to any European Country then you will get isRequestLocationInEeaOrUnknown: true
async componentDidMount () {
try {
const consentInfo = await AdsConsent.requestInfoUpdate([
'pub-xxxxxx',
]);
await AdsConsent.setDebugGeography(AdsConsentDebugGeography.EEA);
if (
consentInfo.isRequestLocationInEeaOrUnknown &&
consentInfo.status === AdsConsentStatus.UNKNOWN
) {
const formResult = await AdsConsent.showForm({
privacyPolicy: 'https://www.google.com/privacy-policy/',
withPersonalizedAds: false,
withNonPersonalizedAds: true,
withAdFree: false,
});
console.log('formResult', formResult);
}
} catch (e) {
console.log('error', e.message);
}
}

React Extendable-Media-Recorder Unhandled Rejection (Error): There was no instance of an encoder stored with the given id

In a React project that is written in TypeScript, I use the 'extendable-media-recorder' along with the 'extendable-media-recorder-wav-encoder' (link to repo). This package is used to allow the user to record his/her voice. This works when the user records his/her voice only once but upon recording again and stopping the recording the following error is given:
Media encoder error
This error is given after the user stops the recorder the second time, so starting the recorder again does seem to work. I don't understand where this error comes from since the error and the way it occurs would indicate the error originates from stopping the recorder the second time. However, the code for stopping the recorder does catch potential errors whereas the error states that it is not caught.
The way I use the media-recorder in my code is the following:
import microphoneLogo from '../images/microphone.png'
import stopLogo from '../images/stop.png'
import { MediaRecorder, register } from 'extendable-media-recorder';
import { connect } from 'extendable-media-recorder-wav-encoder';
let mediaRecorder: any;
export default () => {
const [microphoneOn, setMicrophone] = useState<boolean>(false)
const [audioSetUp, setAudioSetUp] = useState<boolean>(false)
//Instantiate the mediaRecorder and create an encoder object.
async function setupAudioRecording() {
let port;
try {
port = await connect();
try {
await register(port);
} catch (e2) {
console.log('E2: ' + e2);
}
} catch (e1) {
console.log('E1: ' + e1);
}
const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
mediaRecorder = new MediaRecorder(mediaStream, {
mimeType: 'audio/wav',
audioBitsPerSecond: 44100,
});
setAudioSetUp(true);
}
async function startRecording() {
try {
mediaRecorder.start();
} catch (e) {
console.log(e);
}
mediaRecorder.addEventListener('dataavailable', ({ data }: any) => {
put(data); //This method sends the blob data to the server to be processed
});
}
async function stopRecording() {
try {
await mediaRecorder?.stop()
} catch (e) {
console.log(e);
}
}
return (
<div className="input">
<input
className="input__microphone"
type="image"
src={microphoneOn ? stopLogo : microphoneLogo}
alt="Microphone"
onClick={handleClick}
/>
</div>
)
}
Does anyone know what causes this error and how I could fix it? Possible suggestions regarding other audio recording libraries (compatible with TypeScript) are also more than welcome.
Many thanks in advance.
I just stumbled upon this today. There was a bug in the code which is hopefully fixed in v6.1.56.
https://github.com/chrisguttandin/extendable-media-recorder/commit/8f639309b93061dd39233ee702c11515cb992d4d
It should now work as expected. Please feel free to open an issue on GitHub if you run into any further problems.

Resources