Group Video call using React-Native and Node js - node.js
I want to implement conference video call in React-native and node js using without any paid library
I was Implement single Person Video call using react-native-webrtc and node js Socket using Peer-to-Peer
My React-Native files below
My Privider Files
import React, { useState } from "react";
import { Alert } from "react-native";
import {
mediaDevices,
MediaStream,
MediaStreamConstraints,
} from "react-native-webrtc";
import socketio from "socket.io-client";
import ReactNativeForegroundService from "#supersami/rn-foreground-service";
import { MainContext as MainContextType, User } from "../interfaces";
import {
SERVER_URL,
PEER_SERVER_HOST,
PEER_SERVER_PORT,
PEER_SERVER_PATH,
} from "../server";
// #ts-ignore
import Peer from "react-native-peerjs";
import { navigate } from "../helpers/RootNavigation";
import InCallManager from "react-native-incall-manager";
const initialValues: MainContextType = {
username: "",
peerId: "",
users: [],
localStream: null,
remoteStream: null,
remoteUser: null,
initialize: () => {},
setUsername: () => {},
call: () => {},
switchCamera: () => {},
toggleMute: () => {},
isMuted: false,
isShareScreen: false,
toggleSpeacker: () => {},
isSpeaker: true,
swipeWindow: false,
closeCall: () => {},
reset: () => {},
localStreamSet: () => {},
activeCall: null,
};
export const MainContext = React.createContext(initialValues);
interface Props {}
const MainContextProvider: React.FC<Props> = ({ children }) => {
const [username, setUsername] = useState(initialValues.username);
const [peerId, setPeerId] = useState(initialValues.peerId);
const [users, setUsers] = useState<User[]>(initialValues.users);
const [localStream, setLocalStream] = useState<MediaStream | null>(
initialValues.localStream
);
const [remoteStream, setRemoteStream] = useState<MediaStream | null>(
initialValues.remoteStream
);
const [remoteUser, setRemoteUser] = useState<User | null>(null);
const [socket, setSocket] = useState<SocketIOClient.Socket | null>(null);
const [peerServer, setPeerServer] = useState<any>(null);
const [isMuted, setIsMuted] = useState(initialValues.isMuted);
const [swipeWindow, setSwipeWindow] = useState(initialValues.swipeWindow);
const [isShareScreen, setIsShareScreen] = useState(
initialValues.isShareScreen
);
// const localStreamSet=(newstream)=>{
// setLocalStream(null)
// }
const [isSpeaker, setIsSpeaker] = useState(initialValues.isSpeaker);
const [activeCall, setActiveCall] = useState<any>(null);
const initialize = async () => {
const isFrontCamera = true;
const devices = await mediaDevices.enumerateDevices();
const facing = isFrontCamera ? "front" : "environment";
const videoSourceId = devices.find(
(device: any) => device.kind === "videoinput" && device.facing === facing
);
const facingMode = isFrontCamera ? "user" : "environment";
const constraints: MediaStreamConstraints = {
audio: true,
video: {
mandatory: {
minWidth: 1280,
minHeight: 720,
minFrameRate: 30,
},
facingMode,
optional: videoSourceId ? [{ sourceId: videoSourceId }] : [],
},
};
const newStream = await mediaDevices.getUserMedia(constraints);
setLocalStream(newStream as MediaStream);
const io = socketio.connect(SERVER_URL, {
reconnection: true,
autoConnect: true,
});
io.on("connect", () => {
setSocket(io);
io.emit("register", username);
});
io.on("users-change", (users: User[]) => {
setUsers(users);
});
io.on("accepted-call", (user: User) => {
InCallManager.start("video");
setRemoteUser(user);
});
io.on("rejected-call", (user: User) => {
InCallManager.stop();
InCallManager.start();
setRemoteUser(null);
setActiveCall(null);
Alert.alert("Your call request rejected by " + user?.username);
navigate("Users");
});
io.on("not-available", (username: string) => {
setRemoteUser(null);
setActiveCall(null);
Alert.alert(username + " is not available right now");
navigate("Users");
});
const peerServer = new Peer(undefined, {
host: PEER_SERVER_HOST,
path: PEER_SERVER_PATH,
secure: true,
port: PEER_SERVER_PORT,
config: {
iceServers: [
{
urls: [
"stun:stun1.l.google.com:19302",
"stun:stun2.l.google.com:19302",
],
},
],
},
});
peerServer.on("error", (err: Error) =>
);
peerServer.on("open", (peerId: string) => {
setPeerServer(peerServer);
setPeerId(peerId);
io.emit("set-peer-id", peerId);
});
io.on("call", (user: User) => {
peerServer.on("call", (call: any) => {
InCallManager.startRingtone("_BUNDLE_");
setRemoteUser(user);
Alert.alert(
"New Call",
"You have a new call from " + user?.username,
[
{
text: "Reject",
onPress: () => {
InCallManager.stopRingtone();
InCallManager.stop();
io.emit("reject-call", user?.username);
setRemoteUser(null);
setActiveCall(null);
},
style: "cancel",
},
{
text: "Accept",
onPress: () => {
InCallManager.stopRingtone();
InCallManager.start();
InCallManager.setSpeakerphoneOn(true);
io.emit("accept-call", user?.username);
call.answer(newStream);
setActiveCall(call);
navigate("Call");
},
},
],
{ cancelable: false }
);
call.on("stream", (stream: MediaStream) => {
setRemoteStream(stream);
});
call.on("close", () => {
closeCall();
});
call.on("error", () => {});
});
});
};
const call = (user: User) => {
if (!peerServer || !socket) {
Alert.alert("Peer server or socket connection not found");
return;
}
if (!user.peerId) {
Alert.alert("User not connected to peer server");
return;
}
socket.emit("call", user.username);
setRemoteUser(user);
try {
const call = peerServer.call(user.peerId, localStream);
call.on(
"stream",
(stream: MediaStream) => {
setActiveCall(call);
setRemoteStream(stream);
},
(err: Error) => {
console.error("Failed to get call stream", err);
}
);
} catch (error) {
}
};
const switchCamera = () => {
if (localStream) {
// #ts-ignore
localStream.getVideoTracks().forEach((track) => track._switchCamera());
}
};
const toggleMute = () => {
if (localStream)
localStream.getAudioTracks().forEach((track) => {
track.enabled = !track.enabled;
setIsMuted(!track.enabled);
});
};
const toggleswipeWindow = () => {
var templocalstream = localStream;
var tempremotestream = remoteStream;
if (swipeWindow == false) {
setLocalStream(tempremotestream);
setRemoteStream(templocalstream);
setSwipeWindow(!swipeWindow);
} else {
setLocalStream(tempremotestream);
setRemoteStream(templocalstream);
setSwipeWindow(!swipeWindow);
}
};
const toggleScreenShare = async () => {
if (localStream)
if (isShareScreen == false) {
mediaDevices
.getDisplayMedia({ video: true, audio: true })
.then(handleSuccess, handleError);
InCallManager.setKeepScreenOn(true);
setIsShareScreen(true);
} else {
// localStream.getVideoTracks().forEach((track) => {track.stop()}
ReactNativeForegroundService.stop();
InCallManager.setKeepScreenOn(false);
setIsShareScreen(false);
}
};
const toggleSpeacker = () => {
if (localStream) InCallManager.start();
InCallManager.setSpeakerphoneOn(!isSpeaker);
setIsSpeaker(!isSpeaker);
};
const closeCall = () => {
activeCall?.close();
setActiveCall(null);
setRemoteUser(null);
navigate("Users");
Alert.alert("Call is ended");
};
const reset = async () => {
peerServer?.destroy();
socket?.disconnect();
setActiveCall(null);
setRemoteUser(null);
setLocalStream(null);
setRemoteStream(null);
setUsername("");
setPeerId("");
};
const handleError = async (error) => {
};
const handleSuccess = async (stream) => {
localStream.getVideoTracks().forEach((track) => {
localStream.removeTrack(track);
});
localStream.addTrack(stream.getTracks()[0]);
if (swipeWindow == true) {
setRemoteStream(stream);
} else {
setLocalStream(stream);
}
stream.getVideoTracks()[0].addEventListener("ended", () => {
});
};
return (
<MainContext.Provider
value={{
username,
setUsername,
peerId,
setPeerId,
users,
setUsers,
localStream,
setLocalStream,
remoteStream,
setRemoteStream,
initialize,
call,
switchCamera,
toggleMute,
isMuted,
isSpeaker,
toggleSpeacker,
closeCall,
reset,
remoteUser,
activeCall,
toggleScreenShare,
isShareScreen,
toggleswipeWindow,
swipeWindow,
// localStreamSet
}}
>
{children}
</MainContext.Provider>
);
};
export default MainContextProvider;
Callscreen.js File
import React, {useContext} from 'react';
import {
ActivityIndicator,
Dimensions,
StyleSheet,
Text,
View,
TouchableWithoutFeedback,
TouchableHighlight
} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
import {RTCView} from 'react-native-webrtc';
import IconButton from '../components/IconButton';
import icons from '../constants/icons';
import {CallScreenNavigationProp} from '../interfaces/navigation';
import {MainContext} from '../store/MainProvider';
import InCallManager from 'react-native-incall-manager';
const {width, height} = Dimensions.get('window');
import RecordScreen from 'react-native-record-screen';
import Video from 'react-native-video';
interface Props {
navigation: CallScreenNavigationProp;
}
const Call = ({}: Props) => {
const {
localStream,
remoteStream,
activeCall,
remoteUser,
isMuted,
isSpeaker,
toggleSpeacker,
toggleScreenShare,
isShareScreen,
closeCall,
toggleMute,
switchCamera,
swipeWindow,
toggleswipeWindow
} = useContext(MainContext);
React.useEffect(() => {
if (InCallManager.recordPermission !== 'granted') {
InCallManager.requestRecordPermission()
.then((requestedRecordPermissionResult) => {
})
.catch((err) => {
});
}
});
const [recordscreen,setRecordScreen]=React.useState(false)
const btnStyle = React.useMemo(() => {
return recordscreen ? styles.btnActive : styles.btnDefault;
}, [recordscreen]);
const [uri, setUri] = React.useState('');
const _handleOnRecording = async () => {
if (recordscreen) {
setRecordScreen(false);
const res = await RecordScreen.stopRecording().catch((error) =>
console.warn(error)
);
if (res) {
setUri(res.result.outputURL);
}
} else {
setUri('');
setRecordScreen(true);
await RecordScreen.startRecording().catch((error) => {
console.warn(error);
setRecordScreen(false);
setUri('');
});
}
};
return (
<SafeAreaView style={styles.container}>
{uri ? (
<View style={styles.preview}>
<Video
source={{
uri,
}}
style={styles.video}
/>
</View>
) : null}
{remoteStream && (
<RTCView
key={2}
mirror={true}
style={styles.remoteStream}
streamURL={remoteStream.toURL()}
objectFit="cover"
/>
)}
{localStream && (
<View style={styles.myStreamWrapper}>
<TouchableWithoutFeedback onPress={toggleswipeWindow}>
<RTCView
style={styles.myStream}
objectFit="cover"
streamURL={localStream.toURL()}
zOrder={1}
/>
</TouchableWithoutFeedback>
</View>
)}
{!activeCall && (
<View style={styles.spinnerWrapper}>
<ActivityIndicator color="#341EFF" size={120} />
<Text style={styles.callingText}>Calling {remoteUser?.username}</Text>
</View>
)}
<View style={styles.iconsWrapper}>
<IconButton
icon={icons.CHANGE_CAMERA}
onPress={switchCamera}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
{isMuted ? (
<IconButton
icon={icons.UNMUTE}
onPress={toggleMute}
iconColor={'#fff'}
backgroundColor="red"
/>
) : (
<IconButton
icon={icons.MUTE}
onPress={toggleMute}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
)}
{isSpeaker ? (
<IconButton
icon={icons.SPEAKERON}
onPress={toggleSpeacker}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
) : (
<IconButton
icon={icons.SPEAKEROFF}
onPress={toggleSpeacker}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
)}
{recordscreen ? (
<IconButton
icon={icons.RECORDING}
onPress={_handleOnRecording}
iconColor={'#fff'}
backgroundColor="red"
/>
) : (
<IconButton
icon={icons.RECORDING}
onPress={_handleOnRecording}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
)}
{isShareScreen ? (
<IconButton
icon={icons.SCREENSHARE}
onPress={toggleScreenShare}
iconColor={'#fff'}
backgroundColor="red"
/>
) : (
<IconButton
icon={icons.SCREENSHARE}
onPress={toggleScreenShare}
iconColor={'#341EFF'}
backgroundColor="#fff"
/>
)}
<IconButton
icon={icons.END_CALL}
onPress={closeCall}
iconColor={'#fff'}
backgroundColor="red"
/>
</View>
</SafeAreaView>
);
};
export default Call;
const styles = StyleSheet.create({
preview: {
position: 'absolute',
right: 12,
bottom: 116,
width: Dimensions.get('window').width / 2,
height: Dimensions.get('window').height / 3,
zIndex: 1,
padding: 8,
backgroundColor: '#aaa',
},
video: {
flex: 1,
},
container: {
backgroundColor: '#0f0f0f',
flex: 1,
position: 'relative',
},
btnDefault: {
width: 48,
height: 48,
backgroundColor: '#fff',
borderRadius: 24,
borderWidth: 4,
borderStyle: 'solid',
borderColor: '#212121',
},
btnActive: {
width: 36,
height: 36,
backgroundColor: 'red',
borderRadius: 8,
},
myStream: {
height: width * 0.6,
width: width * 0.4,
},
myStreamWrapper: {
position: 'absolute',
bottom: 20,
right: 20,
height: width * 0.6 + 8,
width: width * 0.4 + 8,
backgroundColor: '#333',
borderRadius: 12,
overflow: 'hidden',
justifyContent: 'center',
alignItems: 'center',
},
remoteStreamWrapper: {},
remoteStream: {
width: '100%',
height: '100%',
},
spinnerWrapper: {
top: height * 0.3,
width: '100%',
justifyContent: 'center',
alignItems: 'center',
},
callingText: {
fontSize: 26,
color: '#fff',
},
iconsWrapper: {
position: 'absolute',
bottom: 20,
left: 20,
},
});
Socket Server.js
//socketio
const socketio = require("socket.io");
class SocketService {
io;
constructor() {
this.io = null;
}
listen = (server) => {
this.io = socketio(server);
this.io.users = {};
this.io.on("connection", (socket) => {
socket.on("register", (username) => this.onRegister(socket, username));
socket.on("set-peer-id", (peerId) => this.onSetPeerId(socket, peerId));
socket.on("call", (username) => this.onCall(socket, username));
socket.on("reject-call", (username) =>
this.onRejectCall(socket, username)
);
socket.on("accept-call", (username) =>
this.onAcceptCall(socket, username)
);
console.log(`${Date(Date.now()).toLocaleString()}: new user connected`);
socket.on("disconnect", () => this.onDisconnect(socket));
});
};
onAcceptCall = (socket, username) => {
if (this.io.users[username])
this.io
.to(this.io.users[username].socketId)
.emit("accepted-call", this.io.users[socket.username]);
};
onRejectCall = (socket, username) => {
if (this.io.users[username]) {
this.io
.to(this.io.users[username].socketId)
.emit("rejected-call", this.io.users[socket.username]);
}
};
onCall = (socket, username) => {
if (this.io.users[username]) {
this.io
.to(this.io.users[username].socketId)
.emit("call", this.io.users[socket.username]);
} else {
socket.emit("not-available", username);
}
};
onRegister = (socket, username) => {
console.log("Registered", username);
socket.username = username;
this.io.users[username] = {
username,
peerId: "",
socketId: socket.id,
};
this.onUsersChange(socket);
};
getUsers = () => {
const users = [];
Object.keys(this.io.users).forEach((key) => {
users.push(this.io.users[key]);
});
return users;
};
onUsersChange = (socket) => {
this.io.emit("users-change", this.getUsers());
};
onSetPeerId = (socket, peerId) => {
console.log("Set Peer Id user:", socket.username, " peerId: ", peerId);
this.io.users[socket.username] = {
peerId,
socketId: socket.id,
username: socket.username,
};
this.onUsersChange();
};
onDisconnect = (socket) => {
delete this.io.users[socket.username];
console.log(
`${Date(Date.now()).toLocaleString()} ID:${
socket.username
} user disconnected`
);
this.onUsersChange();
};
emit = (event, userId, data) => {
if (this.io.users[userId]) {
this.io.to(this.io.users[userId]).emit(event, data);
}
};
}
module.exports = new SocketService();
Peer Server.js (2nd API server in Node js)
require('dotenv').config()
const express = require("express");
const { ExpressPeerServer } = require("peer");
const app = express();
app.get("/", (req, res, next) => res.send("Hello world!"));
const http = require("http");
const server = http.createServer(app);
const peerServer = ExpressPeerServer(server, {
debug: true,
path: "/",
});
app.use("/peerjs", peerServer);
server.listen(process.env.PORT || 9000);
Related
React Socketio set online status for multiple users
How can i update online status of multiple users in React.i want that when user A is online,user B and C can also see if user A is online.Here is what i have tried using react usestate but it isnt working function MyOffers() { const [loading, setLoading] = useState(true); const [cookies] = useCookies(); const { enqueueSnackbar } = useSnackbar(); const navigate = useNavigate(); const [data, setData] = useState(false); let { id } = useParams(); const [user, setUser] = useState({ username: null, online: false, }); ////set online status const socket = useContext(SocketContext); useEffect(() => { ifvisible.on('focus', function () { socket.emit('online', user); console.log(user); }); ifvisible.on('blur', function () { socket.emit('offline', user); console.log('offline'); }); return () => { ifvisible.off('focus'); ifvisible.off('blur'); }; }, [user]); useEffect(() => { socket.on('online', (data) => { setUser((prevState) => ({ ...prevState, ...data, })); console.log(user); }); socket.on('offline', (data) => { setUser((prevState) => ({ ...prevState, ...data, })); }); }, [socket]); useEffect(() => { $.ajax({ type: 'POST', url: '/get_offer', headers: { 'X-XSRF-TOKEN': cookies['XSRF-TOKEN'], 'Authorization': `Bearer ${localStorage.getItem('auth')}`, }, data: { id: id, }, success: function (data) { switch (data.success) { case true: setData(data); setLoading(false); break; case false: break; } }, error: function () {}, statusCode: { 403: function () { navigate('/'); }, }, }); }, []); return ( <React.Fragment> <Box flexGrow={1}> {/*seller info*/} <Grid item xs={12} sm={4}> {loading ? ( <Skeleton variant="rectangular" animation="wave" width={'100%'} height={200} sx={{ borderRadius: 2, marginTop: 1 }} /> ) : ( <Item> <Badge color={ data.offer && data.offer[0].user.username === user.username && user.online === true ? 'success' : 'warning' } variant="dot" overlap="circular" anchorOrigin={{ vertical: 'bottom', horizontal: 'right', }} > <Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg" sx={{ width: 56, height: 56 }} /> </Badge> <Typography variant={'h5'}> {data.offer ? data.offer[0].user.username : ''} </Typography> <Typography paragraph> <Rating name="read-only" value={5} readOnly /> <Typography variant={'subtitle1'}>[5]</Typography> </Typography> <CardActions sx={{ display: 'flex', justifyContent: 'space-evenly' }}> <IconButton aria-label="add to favorites"> <LockClockOutlinedIcon /> </IconButton> <IconButton aria-label="share"> <LockClockOutlinedIcon /> </IconButton> </CardActions> </Item> )} </Grid> </Grid> </Box> </React.Fragment> ); } export default MyOffers; i want such when the owner of the offer is online,to update the online status badge of the user viewing the offer.Here is my server code /** * Listen for incoming socket connections */ Ws.io.on('connection', (socket) => { socket.on('online', (data) => { data.online = true; socket.broadcast.emit('online', data); }); socket.on('offline', (data) => { data.online = false; socket.broadcast.emit('offline', data); }); });
React/Postgres sql detail: 'Failing row contains (43, ccc, null, 0, 2022-07-01 15:37:11.631)
**I am getting the error when I am connecting the frontend code as well as backend code with the database maybe the problem might be in front end but pls let me know the meaning of the error because I am newbie.I am getting the error on register pls help me and also when I register the website using frontend it shows me error on **localhost/register enter image description here const express = require('express'); const { listen } = require('express/lib/application'); const bodyParser=require('body-parser'); const bcrypt=require('bcrypt-nodejs') const cors = require('cors') const knex = require('knex'); const { response } = require('express'); const db=knex({ client: 'pg', connection: { host : '127.0.0.1', user : 'postgres', password : '224898', database : 'smart-brain' } }); const app = express(); app.use(bodyParser.json()); app.use(cors()) const database={ users:[ { id:'123', name:'John', email:'John#gmail.com', password:'ABC', entries:0, joined:new Date() }, { id:'124', name:'ABC', email:'ABC', password:'123', entries:0, joined:new Date() } ], login:[ { id:'987', hash:'', email:'John#gmail.com' } ] } app.get('/' ,(req,res)=>{ res.send(database.users); }) app.post('/signin',(req,res)=>{ if(req.body.email===database.users[0].email && req.body.password===database.users[0].password){ res.json(database.users[0]); }else{ res.status(400).json('error login in'); } }) app.post('/register',(req,res)=>{ const{email,name,password}=req.body; db('users') .returning('*') .insert({ email:email, name:name, joined: new Date() }) .then(user=>{ res.json(user[0]); }) . catch(err => console.log(err)) }) app.get('/profile/:id',(req,res)=>{ const{id}=req.params; let found=false; database.users.forEach(user=>{ if(user.id===id){ found=true; return res.json(user); } }) if(!found){ res.status(400).json('not found'); } }) app.put('/image',(req,res)=>{ const{id}=req.body; let found=false; database.users.forEach(user=>{ if(user.id===id){ found=true; user.entries++ return res.json(user.entries); } }) if(!found){ res.status(400).json('not found'); } }) // // Load hash from your password DB. // bcrypt.compare("bacon", hash, function(err, res) { // // res == true // }); // bcrypt.compare("veggies", hash, function(err, res) { // // res = false // }); app.listen(3000,()=>{ console.log('app is running on port 3000 '); }) AND ALSO I AM SHARING FRONTEND APP.JS CODE APP.js code import './App.css'; import Navigation from './Components/Navigation/Navigation'; import FaceRecognition from './Components/FaceRecognition/FaceRecognition'; import Logo from './Components/Logo/Logo' import ImageLinkForm from './Components/ImageLinkForm/ImageLinkForm' import Rank from './Components/Rank/Rank' import { Component } from 'react'; import Particles from "react-tsparticles"; import { loadFull } from "tsparticles"; import SignIn from './Components/SignIn/SignIn'; import Register from './Components/Register/Register' const USER_ID = 'aad'; const PAT = 'bd69e06e68f244ed83b9ce09ee560e7c'; const APP_ID = 'aaa'; const MODEL_ID = 'face-detection'; const MODEL_VERSION_ID = '45fb9a671625463fa646c3523a3087d5'; const particlesOption = { fpsLimit: 120, particles: { links: { color: "#ffffff", distance: 150, enable: true, opacity: 0.5, width: 1, }, collisions: { enable: true, }, move: { direction: "none", enable: true, outModes: { default: "bounce", }, random: true, speed: 5, straight: true, }, }, detectRetina: true, } const particlesInit = async (main) => { await loadFull(main); }; const initialState = { input: '', imageUrl: '', box: {}, route:'signin', isSignedIn:false, user: { id: '', name: '', email: '', joined: '', entries: 0 } }; class App extends Component { constructor() { super(); this.state = initialState; }; loadUser = (data) => { this.setState({ user: { id: data.id, name: data.name, email: data.email, entries: data.entries, joined: data.joined } }) } apiData = () => { const raw = JSON.stringify({ "user_app_id": { "user_id": USER_ID, "app_id": APP_ID }, "inputs": [ { "data": { "image": { "url": this.state.input } } } ] }); const requestOptions = { method: 'POST', headers: { 'Accept': 'application/json', 'Authorization': 'Key ' + PAT }, body: raw }; return requestOptions; } displayFaceBox = (box) => { this.setState({ box: box }); } onInputChange=(event) =>{ this.setState({input: event.target.value}); } onImageSubmit = () => { this.setState({ imageUrl: this.state.input }); const requestOptions = this.apiData(); fetch("https://api.clarifai.com/v2/models/" + MODEL_ID + "/versions/" + MODEL_VERSION_ID + "/outputs", requestOptions) .then(response => response.text()) .then(result => JSON.parse(result)) .then(obj => { if (obj) { fetch('http://localhost:3000/image', { method: 'put', headers: {'content-type': 'application/json'}, body: JSON.stringify({ id: this.state.user.id }) }) .then(response => response.json()) .then(count => { this.setState(Object.assign(this.state.user, {entries: count})) }) } this.displayFaceBox(this.calculateFaceLocation(obj)) }) .catch(error => console.log('error', error)); } calculateFaceLocation = (data) => { const clarifaiFace = data.outputs[0].data.regions[0].region_info.bounding_box; const image = document.getElementById('inputimage'); const width = Number(image.width); const height = Number(image.height); return ({ leftCol: clarifaiFace.left_col * width, topRow: clarifaiFace.top_row * height, rightCol: width - (clarifaiFace.right_col * width), bottomRow: height - (clarifaiFace.bottom_row * height), }) } onRouteChange=(route)=>{ if(route==='signout'){ this.setState({isSignedIn:false}) }else if(route==='home'){ this.setState({isSignedIn:true}) } this.setState({route:route}) } render(){ const { imageUrl, box ,isSignedIn,route} = this.state; return ( <div className="App"> <Particles className='particles' init={particlesInit} options={particlesOption} /> <Navigation isSignedIn={isSignedIn} onRouteChange={this.onRouteChange} />{ route==='home'? <div> <Logo /> <Rank name={this.state.user.name} entries={this.state.user.entries}/> <ImageLinkForm onInputChange={this.onInputChange} onImageSubmit={this.onImageSubmit}/> <FaceRecognition box={box} imageUrl={imageUrl} /> </div> :( route==='signin'? <SignIn loadUser={this.loadUser} onRouteChange={this.onRouteChange} /> : <Register loadUser={this.loadUser}onRouteChange={this.onRouteChange}/> ) } </div> ); } } export default App;
Do not use images for textual information, copy and paste the text into the question. This would make the following easier. From error message code:23502. If you go here Error codes you find that corresponds to 23502 not_null_violation. So the value that is being set to NULL is being entered into a column that has NOT NULL set. Your choices are: a) Make sure the value is not set to NULL. b) If you can have NULL values in the column drop the NOT NULL constraint.
webRTC connection from browser to phone not working
I'm building a project using react native and webRTC with nodejs + ejs. establish connections: 1- browser to browser works well. 2- device to browser works well. 3- browser to device does not work and here is the problem and all codes are the same for socket io and peer connections. // REACT NATIVE PART const [localStream, setLocalStream] = useState<MediaStream|null>(null); const [remoteStream, setRemoteStream] = useState<MediaStream|null>(null); const socket = io(utils.RAW_BACKEND_URL) const peerConnection = new RTCPeerConnection({ iceServers: [ { urls: ['stun:stun.l.google.com:19302'] } ] }) useEffect(()=> { peerConnection.onaddstream = (e) => { setRemoteStream(e.stream); } socket.emit('join-room') socket.on('calling-user', async (args)=> { setOffer(JSON.stringify(args.offer)) await peerConnection.setRemoteDescription(new RTCSessionDescription(args.offer)); utils.showAlertMessage("Calling", "You have a call", [ { text: "Call?", onPress: async ()=> await answerCall() }, { text: "No", } ]) }) socket.on('ic-candidate', async(args)=> { await peerConnection.addIceCandidate(new RTCIceCandidate(args.candidate)) }) socket.on('answer-made', async (args)=> { console.log("HERE"); await peerConnection.setRemoteDescription(new RTCSessionDescription(args.answer)); setShow(true) }) }, []) const getUserMedia = async (callAUser?:boolean) => { let isFront = true, videoSourceId: any = null; try { const availableDevices = await mediaDevices.enumerateDevices(); let videoSourceId; for (let i = 0; i < availableDevices.length; i++) { const sourceInfo = availableDevices[i]; if ( sourceInfo.kind == 'videoinput' && sourceInfo.facing == (isFront ? 'front' : 'environment') ) { videoSourceId = sourceInfo.deviceId; } } const mediaStream = await mediaDevices.getUserMedia({ // audio: true, video: { mandatory: { minWidth: 500, minHeight: 300, minFrameRate: 30, }, facingMode: 'user', optional: [{sourceId: videoSourceId}] } }) setLocalStream(mediaStream); peerConnection.addStream(mediaStream); if(callAUser){ await callUser(); } }catch(err: any) { utils.showAlertMessage("ERRORsss", err.message); } } const callUser = async () => { peerConnection.onicecandidate = e => { if(e.candidate) { socket.emit('candidate', { candidate: e.candidate }) } } const offer = await peerConnection.createOffer(); await peerConnection.setLocalDescription(new RTCSessionDescription(offer)); socket.emit('call-user', { offer: offer }) } const answerCall = async () => { await getUserMedia(); const answer = await peerConnection.createAnswer(); await peerConnection.setLocalDescription(new RTCSessionDescription(answer)); socket.emit('make-answer', { answer }) } return ( <View style={styles.stream}> <Button title="Call" onPress={()=>getUserMedia(true)} /> <Button title="Answer" onPress={()=>answerCall()} /> {localStream != null && <RTCView objectFit={"cover"} streamURL={localStream.toURL()} style={{height: '50%', borderWidth: 1, borderColor: 'red'}} /> } {remoteStream != null && show ? <RTCView objectFit={"cover"} streamURL={remoteStream.toURL()} style={{height: '50%', borderWidth: 1, borderColor: 'blue'}} /> : <Text>{offer}</Text> } </View> ); //js file for serving ejs page const client = io("https://b277-2001-16a2-cb25-a800-f1da-b62e-7f94-42ee.ngrok.io"); const peerConnection = new RTCPeerConnection({ iceServers: [ { urls: ['stun:stun.l.google.com:19302'] } ] }) client.on('answer-made', async (args)=> { await peerConnection.setRemoteDescription(new RTCSessionDescription(args.answer)); sdpAnswer.innerHTML = JSON.stringify(args.answer); }) client.on('answer-made', async (args)=> { await peerConnection.setRemoteDescription(new RTCSessionDescription(args.answer)); sdpAnswer.innerHTML = JSON.stringify(args.answer); }) onst callUser = async () => { await getMedia(); const offer = await peerConnection.createOffer(); await peerConnection.setLocalDescription(new RTCSessionDescription(offer)); peerConnection.onicecandidate = (e) => { if(e.candidate) { client.emit('candidate', { candidate: e.candidate }) } } client.emit('call-user', { offer }) } // socket io part client.join("q2"); client.on('join-room', (args)=> { client.broadcast.to("q2").emit("user-joined", { id: client.id }) }) client.on("call-user", (args) => { client.broadcast.to("q2").emit("calling-user", args); }); client.on("make-answer", (args) => { client.broadcast.to("q2").emit("answer-made", args); }); client.on("candidate", (args) => { client.broadcast.to("q2").emit("ic-candidate", args); }); I hope you can help me what mistake I made and did not figure it. Thanks in advance
How to send the page number, page limit in request body from react js Material-UI datatable for cursor pagination
I am trying to achieve cursor pagination on my data table material-ui-datatables. I am using react js for the front end, express.js backend, and I am using mongo_DB for storage. I want to pass the page number, page limit previous and next as request body from my data table to API and I am using mangoose pagination plugin. import React, { useState, useEffect } from "react"; import MUIDataTable from "mui-datatables"; import axios from "axios"; import PropagateLoader from "react-spinners/PropagateLoader"; // employee_info function employee_info() { let [loading, setLoading] = useState(true); const [Response, setResponse] = useState([]); const get_employee_details = () => { axios .get(configData.SERVER_URL + "/api/get_employee_info") .then((res) => { setResponse(res.data); setLoading(false); }); }; useEffect(() => { const interval = setInterval(() => get_employee_details(), 10000); return () => { clearInterval(interval); }; }, []); if (loading === true) { return ( <div style={style}> <PropagateLoader loading={loading} color={"#36D7B7"} size={30} /> </div> ); } else { return EmployeeInfoTable(setResponse); } } //DataTable function EmployeeInfoTable(value) { if ( typeof value == "undefined" || value == null || value.length == null || value.length < 0 ) { return <div></div>; } const columns = [ { label: "Employee_ID", name: "employee_id" }, { label: "Name", name: "name" }, { label: "Department", name: "department" }, { label: "Manger", name: "manager" }, ]; const data = value.map((item) => { return [ item.employee_id, item.name, item.department, item.manager, ]; }); const options = { caseSensitive: true, responsive: "standard", selectableRows: "none", filter: false, download: false, print: false, viewColumns: false, }; return ( <MUIDataTable title={"Employee_Details"} data={data} columns={columns} options={options} /> ); } Service API const MongoPaging = require('mongo-cursor-pagination'); const express = require("express"); const router = express.Router(); router.get('/get_employee_info', async (req, res, next) => { try { const result = await MongoPaging.find(db.collection('employee'), { query: { employee: req.employee_id }, paginatedField: 'created', fields: { manger: req.manger, }, limit: req.query.limit, next: req.query.next, previous: req.query.previous, } res.json(result); } catch (err) { next(err); } })
Jest + Material-UI : Correctly mocking useMediaQuery
I'm using Material-UI's useMediaQuery() function in one of my components to determine the size prop to use for a <Button> within the component. I'm trying to test that it's working as expected in a jest test, however my current implementation isn't working: describe("Unit: <Navbar> On xs screens", () => { // Incorrectly returns `matches` as `false` **************************** window.matchMedia = jest.fn().mockImplementation( query => { return { matches: true, media: query, onchange: null, addListener: jest.fn(), removeListener: jest.fn() }; } ); it("renders as snapshot", async () => { const width = theme.breakpoints.values.sm - 1; const height = Math.round((width * 9) / 16); Object.defineProperty(window, "innerWidth", { writable: true, configurable: true, value: width }); const { asFragment } = render( <Container backgroundColor={"#ffffff"}> <Navbar /> </Container> ); expect(asFragment()).toMatchSnapshot(); const screenshot = await generateImage({ viewport: { width, height } }); expect(screenshot).toMatchImageSnapshot(); }); }); describe("Unit: <Navbar> On md and up screens", () => { // Correctly returns `matches` as `false` **************************** window.matchMedia = jest.fn().mockImplementation( query => { return { matches: false, media: query, onchange: null, addListener: jest.fn(), removeListener: jest.fn() }; } ); it("renders as snapshot", async () => { const width = theme.breakpoints.values.md; const height = Math.round((width * 9) / 16); Object.defineProperty(window, "innerWidth", { writable: true, configurable: true, value: width }); const { asFragment } = render( <Container backgroundColor={"#ffffff"}> <Navbar /> </Container> ); expect(asFragment()).toMatchSnapshot(); const screenshot = await generateImage({ viewport: { width, height } }); expect(screenshot).toMatchImageSnapshot(); }); }); And the component I'm testing (removed irrelevant parts): const Navbar = () => { const theme = useTheme(); const matchXs = useMediaQuery(theme.breakpoints.down("xs")); return ( <Button size={matchXs ? "medium" : "large"}> Login </Button> ); }; export default Navbar; It's returning matches as false for the first test, even though I've set it to return as true. I know this because it's generating a screenshot and I can see that the button size is set to large for the first test when it should be set to medium. It works as expected in production. How do I correctly get mock useMediaQuery() in a jest test?
The recommended way is using css-mediaquery which is now mentioned in the MUI docs: import mediaQuery from 'css-mediaquery'; function createMatchMedia(width) { return query => ({ matches: mediaQuery.match(query, { width }), addListener: () => {}, removeListener: () => {}, }); } describe('MyTests', () => { beforeAll(() => { window.matchMedia = createMatchMedia(window.innerWidth); }); });
I figured it out... useMediaQuery() needs to re-render the component to work, as the first render will return whatever you define in options.defaultMatches (false by default). Also, the mock needs to be scoped to each test (it), not in the describe. As I'm using react-testing-library, all I have to do is re-render the component again and change the scope of the mock and it works. Here's the working example: const initTest = width => { Object.defineProperty(window, "innerWidth", { writable: true, configurable: true, value: width }); window.matchMedia = jest.fn().mockImplementation( query => { return { matches: width >= theme.breakpoints.values.sm ? true : false, media: query, onchange: null, addListener: jest.fn(), removeListener: jest.fn() }; } ); const height = Math.round((width * 9) / 16); return { width, height }; }; describe("Unit: <Navbar> On xs screens", () => { it("renders as snapshot", async () => { const { width, height } = initTest(theme.breakpoints.values.sm - 1); const { asFragment, rerender} = render( <Container backgroundColor={"#ffffff"}> <Navbar /> </Container> ); rerender( <Container backgroundColor={"#ffffff"}> <Navbar /> </Container> ); expect(asFragment()).toMatchSnapshot(); const screenshot = await generateImage({ viewport: { width, height } }); expect(screenshot).toMatchImageSnapshot(); }); }); describe("Unit: <Navbar> On md and up screens", () => { it("renders as snapshot", async () => { const { width, height } = initTest(theme.breakpoints.values.md); const { asFragment } = render( <Container backgroundColor={"#ffffff"}> <Navbar /> </Container> ); rerender( <Container backgroundColor={"#ffffff"}> <Navbar /> </Container> ); expect(asFragment()).toMatchSnapshot(); const screenshot = await generateImage({ viewport: { width, height } }); expect(screenshot).toMatchImageSnapshot(); }); });
A simple approach that worked for me: component.tsx import { Fade, Grid, useMediaQuery } from '#material-ui/core'; ... const isMobile = useMediaQuery('(max-width:600px)'); component.spec.tsx import { useMediaQuery } from '#material-ui/core'; // not testing for mobile as default jest.mock('#material-ui/core', () => ({ ...jest.requireActual('#material-ui/core'), useMediaQuery: jest.fn().mockReturnValue(false), })); describe('...', () => { it(...) // test case for mobile it('should render something for mobile', () => { ((useMediaQuery as unknown) as jest.Mock).mockReturnValue(true); .... })
Inspired by #iman-mahmoudinasab's accepted answer, here is a TypeScript implementation. Essentially, we would want to create valid MediaQueryList-object: // yarn add -D css-mediaquery #types/css-mediaquery import mediaQuery from 'css-mediaquery'; describe('Foo Bar', () => { beforeAll(() => { function createMatchMedia(width: number) { return (query: string): MediaQueryList => ({ matches: mediaQuery.match(query, { width }) as boolean, media: '', addListener: () => {}, removeListener: () => {}, onchange: () => {}, addEventListener: () => {}, removeEventListener: () => {}, dispatchEvent: () => true, }); } // mock matchMedia for useMediaQuery to work properly window.matchMedia = createMatchMedia(window.innerWidth); }); });
Maybe we can do something like this: const applyMock = (mobile) => { window.matchMedia = jest.fn().mockImplementation((query) => { return { matches: mobile, media: query, addListener: jest.fn(), removeListener: jest.fn(), }; }); }; and use it like this: const mockMediaQueryForMobile = () => applyMock(true); const mockMediaQueryForDesktop = () => applyMock(false);