Skip to content

Instantly share code, notes, and snippets.

@supertopoz
Created January 27, 2021 04:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save supertopoz/009a6ffb0a90d8c04f97a60775afb8e3 to your computer and use it in GitHub Desktop.
Save supertopoz/009a6ffb0a90d8c04f97a60775afb8e3 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<script src="src/index.js"></script>
</body>
</html>
// SendBird Calls - JS SDK ReadMe https://github.com/sendbird/sendbird-calls-javascript
// npm install
// npm start
import React from "react";
import ReactDOM from "react-dom";
import SendBirdCall from "sendbird-calls";
import Axios from "axios";
import {callStates} from "./settings";
import styled from 'styled-components';
import { getAllUrlParams } from "./utils";
const Wrapper = styled.div`
display: grid;
grid-gap: 15px;
max-width: 280px;
margin: 0 auto;
padding: 5px;
font-family: "Avenir Next", "Helvetica Neue", helvetica, Arial, sans-serif;
`;
const LocalVideo = styled.video`
width: 100%;
height: 100%;
`;
const RemoteVideo = styled.video`
width: 100%;
`;
const RemoteVideoWrapper = styled.div`
overflow: hidden;
border-radius: 20px;
background: ghostwhite;
--aspect-ratio: 16 / 9;
`;
const LocalVideoWrapper = styled.div`
width: 100%;
overflow: hidden;
border-radius: 20px;
`;
const CallsButton = styled.button `
color: white;
background: rgb(130, 94, 235);
font-weight: 600;
cursor: pointer;
min-width: 80px;
padding-left: 16px;
padding-top: 0px;
padding-bottom: 0px;
height: 32px;
border-radius: 4px;
padding: 0;
border: none;
outline: none;
`;
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
appId: "885C2616-DBF8-4BDC-9178-4A1A662614E3",
info: "Idle...",
call: "",
displayPickup: false,
displayEnd: false,
displayCall: true,
callee: undefined,
buttonText: "Loading..."
};
}
componentDidMount() {
SendBirdCall.init(this.state.appId);
this.init(this.getUrlParams());
}
getUrlParams(){
const url = document.location.href;
const params = getAllUrlParams(url);
return {
agent_id : params.agent_id,
ticket_id : params.ticket_id,
html_key : params.html_key
};
}
async init(data) {
const userAuthAndTicket = await this.fetchUserAndTicket(data.agent_id, data.html_key, data.ticket_id);
if (!userAuthAndTicket) return;
const isAuthenticated = await SendBirdCall.authenticate({ userId: data.agent_id, accessToken:userAuthAndTicket });
if (!isAuthenticated.userId) return;
SendBirdCall.connectWebSocket();
}
async fetchUserAndTicket(agent_id, html_key, ticket_id) {
const url = `https://yourserver.com?agent_id=${agent_id}&html_key=${html_key}&ticket_id=${ticket_id}`;
try {
Axios.get(url).then((res, error) => {
let callee = res.data.ticket.customer.sendbirdId;
this.setState({callee, buttonText: "Call to "});
let accessToken = res.data.user.access_token;
return accessToken;
})
} catch (e) {
console.log(e)
}
}
endCall(){
this.state.call.end();
}
makeCall() {
const dialParams = {
userId: this.state.callee,
isVideoCall: true,
callOption: {
localMediaView: document.getElementById('local_video_tag'),
remoteMediaView: document.getElementById('remote_video_tag'),
audioEnabled: true,
}
};
const call = SendBirdCall.dial(dialParams, (call, error) => {
if (error) {}
});
this.addDialOutListener(call)
}
addDialOutListener(call){
this.setState({call, ...callStates.callingOut});
call.onEstablished = (call) => this.setState({ call, ...callStates.established });
call.onConnected = () => this.setState(callStates.connected);
call.onEnded = () => {
let _this = this;
this.setState(callStates.ended);
setTimeout(() => _this.setState({ info: "Waiting..."}), 1000);
};
}
render() {
let button;
if (this.state.displayEnd) button = <CallsButton onClick = {() => this.endCall()}> Hang Up! </CallsButton>
if (this.state.displayCall) button = <CallsButton onClick = {() => this.makeCall()}>{this.state.buttonText}{this.state.callee}</CallsButton>
return ( < Wrapper >
<div style={{fontSize:"0.7rem"}}> { this.state.info } </div>
{ button}
<LocalVideoWrapper>
<LocalVideo id = "local_video_tag" autoPlay style={{background:"ghostwhite"}}/ >
</LocalVideoWrapper>
<RemoteVideoWrapper>
<RemoteVideo id = "remote_video_tag" autoPlay/>
</RemoteVideoWrapper>
</Wrapper>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render( < App / > , rootElement);
export const callStates = {
ringing: {
info: "Ringing... Pick up!",
displayPickup: true,
displayCall: false,
displayCallEnd: false
},
established : {
info: "Call established",
displayPickup: false,
displayCall: false,
displayCallEnd: true
},
connected: {
info: "Call connected",
displayPickup: false,
displayCall: false,
displayEnd: true
},
ended: {
info: "Call ended",
displayPickup: false,
displayEnd: false,
displayCall: true
},
callingOut: {
info: "Calling...",
displayPickup: false,
displayEnd: true,
displayCall: false
}
}
export function getAllUrlParams(url) {
// get query string from url (optional) or window
var queryString = url ? url.split('?')[1] : window.location.search.slice(1);
// we'll store the parameters here
var obj = {};
// if query string exists
if (queryString) {
// stuff after # is not part of query string, so get rid of it
queryString = queryString.split('#')[0];
// split our query string into its component parts
var arr = queryString.split('&');
for (var i = 0; i < arr.length; i++) {
// separate the keys and the values
var a = arr[i].split('=');
// set parameter name and value (use 'true' if empty)
var paramName = a[0];
var paramValue = typeof (a[1]) === 'undefined' ? true : a[1];
// (optional) keep case consistent
// paramName = paramName.toLowerCase();
// if (typeof paramValue === 'string') paramValue = paramValue.toLowerCase();
// if the paramName ends with square brackets, e.g. colors[] or colors[2]
if (paramName.match(/\[(\d+)?\]$/)) {
// create key if it doesn't exist
var key = paramName.replace(/\[(\d+)?\]/, '');
if (!obj[key]) obj[key] = [];
// if it's an indexed array e.g. colors[2]
if (paramName.match(/\[\d+\]$/)) {
// get the index value and add the entry at the appropriate position
var index = /\[(\d+)\]/.exec(paramName)[1];
obj[key][index] = paramValue;
} else {
// otherwise add the value to the end of the array
obj[key].push(paramValue);
}
} else {
// we're dealing with a string
if (!obj[paramName]) {
// if it doesn't exist, create property
obj[paramName] = paramValue;
} else if (obj[paramName] && typeof obj[paramName] === 'string'){
// if property does exist and it's a string, convert it to an array
obj[paramName] = [obj[paramName]];
obj[paramName].push(paramValue);
} else {
// otherwise add the property
obj[paramName].push(paramValue);
}
}
}
}
return obj;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment