diff --git a/app/components/AudioCallBox.js b/app/components/AudioCallBox.js
index 9495277..c02d40b 100644
--- a/app/components/AudioCallBox.js
+++ b/app/components/AudioCallBox.js
@@ -1,231 +1,232 @@
import React, { Component } from 'react';
import { View, Platform } from 'react-native';
import { IconButton, Dialog, Text } from 'react-native-paper';
import PropTypes from 'prop-types';
import autoBind from 'auto-bind';
import Logger from "../../Logger";
import CallOverlay from './CallOverlay';
import DTMFModal from './DTMFModal';
import EscalateConferenceModal from './EscalateConferenceModal';
import UserIcon from './UserIcon';
import utils from '../utils';
import styles from '../assets/styles/blink/_AudioCallBox.scss';
const logger = new Logger("AudioCallBox");
class AudioCallBox extends Component {
constructor(props) {
super(props);
autoBind(this);
this.state = {
active : false,
audioMuted : false,
showDtmfModal : false,
showEscalateConferenceModal : false
};
// this.speechEvents = null;
this.remoteAudio = React.createRef();
}
componentDidMount() {
// This component is used both for as 'local media' and as the in-call component.
// Thus, if the call is not null it means we are beyond the 'local media' phase
// so don't call the mediaPlaying prop.
if (this.props.call != null) {
switch (this.props.call.state) {
case 'established':
this.attachStream(this.props.call);
break;
case 'incoming':
this.props.mediaPlaying();
// fall through
default:
this.props.call.on('stateChanged', this.callStateChanged);
break;
}
} else {
this.props.mediaPlaying();
}
}
- componentWillReceiveProps(nextProps) {
+ //getDerivedStateFromProps(nextProps, state) {
+ UNSAFE_componentWillReceiveProps(nextProps) {
if (this.props.call == null && nextProps.call) {
if (nextProps.call.state === 'established') {
this.attachStream(nextProps.call);
} else {
nextProps.call.on('stateChanged', this.callStateChanged);
}
}
}
componentWillUnmount() {
clearTimeout(this.callTimer);
// if (this.speechEvents !== null) {
// this.speechEvents.stop();
// this.speechEvents = null;
// }
}
callStateChanged(oldState, newState, data) {
if (newState === 'established') {
this.attachStream(this.props.call);
}
}
attachStream(call) {
this.setState({stream: call.getRemoteStreams()[0]}); //we dont use it anywhere though as audio gets automatically piped
// const options = {
// interval: 225,
// play: false
// };
// this.speechEvents = hark(remoteStream, options);
// this.speechEvents.on('speaking', () => {
// this.setState({active: true});
// });
// this.speechEvents.on('stopped_speaking', () => {
// this.setState({active: false});
// });
}
escalateToConference(participants) {
this.props.escalateToConference(participants);
}
hangupCall(event) {
event.preventDefault();
this.props.hangupCall();
}
muteAudio(event) {
event.preventDefault();
//const localStream = this.props.call.getLocalStreams()[0];
if(this.state.audioMuted) {
logger.debug('Unmute microphone');
this.props.callKeepToggleMute(false);
//localStream.getAudioTracks()[0].enabled = true;
this.setState({audioMuted: false});
} else {
logger.debug('Mute microphone');
//localStream.getAudioTracks()[0].enabled = false;
this.props.callKeepToggleMute(true);
this.setState({audioMuted: true});
}
}
showDtmfModal() {
this.setState({showDtmfModal: true});
}
hideDtmfModal() {
this.setState({showDtmfModal: false});
}
toggleEscalateConferenceModal() {
this.setState({
showEscalateConferenceModal: !this.state.showEscalateConferenceModal
});
}
render() {
let remoteIdentity;
if (this.props.call !== null) {
remoteIdentity = this.props.call.remoteIdentity;
} else {
remoteIdentity = {uri: this.props.remoteUri};
}
const buttonClass = (Platform.OS === 'ios') ? styles.iosButton : styles.androidButton;
let displayName = (this.props.remoteDisplayName && this.props.remoteUri !== this.props.remoteDisplayName) ? this.props.remoteDisplayName: this.props.remoteUri;
return (
{displayName}
{ (this.props.remoteDisplayName && this.props.remoteUri !== this.props.remoteDisplayName) ?
{this.props.remoteUri}
: null }
);
}
}
AudioCallBox.propTypes = {
remoteUri : PropTypes.string.isRequired,
call : PropTypes.object,
remoteDisplayName : PropTypes.string,
escalateToConference : PropTypes.func,
hangupCall : PropTypes.func,
mediaPlaying : PropTypes.func,
callKeepSendDtmf : PropTypes.func,
callKeepToggleMute : PropTypes.func,
toggleSpeakerPhone : PropTypes.func,
speakerPhoneEnabled : PropTypes.bool
};
export default AudioCallBox;
diff --git a/app/components/Call.js b/app/components/Call.js
index cbed758..a7ad526 100644
--- a/app/components/Call.js
+++ b/app/components/Call.js
@@ -1,226 +1,227 @@
import React, { Component } from 'react';
import { View } from 'react-native';
import PropTypes from 'prop-types';
import assert from 'assert';
import debug from 'react-native-debug';
import autoBind from 'auto-bind';
import Logger from "../../Logger";
import AudioCallBox from './AudioCallBox';
import LocalMedia from './LocalMedia';
import VideoBox from './VideoBox';
import config from '../config';
const logger = new Logger("Call");
class Call extends Component {
constructor(props) {
super(props);
autoBind(this);
if (this.props.localMedia && this.props.localMedia.getVideoTracks().length === 0) {
//logger.debug('Will send audio only');
this.state = {audioOnly: true};
} else {
this.state = {audioOnly: false};
}
// If current call is available on mount we must have incoming
if (this.props.currentCall != null) {
this.props.currentCall.on('stateChanged', this.callStateChanged);
}
}
- componentWillReceiveProps(nextProps) {
+ //getDerivedStateFromProps(nextProps, state) {
+ UNSAFE_componentWillReceiveProps(nextProps) {
// Needed for switching to incoming call while in a call
if (this.props.currentCall != null && this.props.currentCall != nextProps.currentCall) {
if (nextProps.currentCall != null) {
nextProps.currentCall.on('stateChanged', this.callStateChanged);
} else {
this.props.currentCall.removeListener('stateChanged', this.callStateChanged);
}
}
}
callStateChanged(oldState, newState, data) {
// console.log('Call: callStateChanged', newState, '->', newState);
if (newState === 'established') {
// Check the media type again, remote can choose to not accept all offered media types
const currentCall = this.props.currentCall;
const remoteHasStreams = currentCall.getRemoteStreams().length > 0;
const remoteHasNoVideoTracks = currentCall.getRemoteStreams()[0].getVideoTracks().length === 0;
const remoteIsRecvOnly = currentCall.remoteMediaDirections.video[0] === 'recvonly';
const remoteIsInactive = currentCall.remoteMediaDirections.video[0] === 'inactive';
if (remoteHasStreams && (remoteHasNoVideoTracks || remoteIsRecvOnly || remoteIsInactive) && !this.state.audioOnly) {
console.log('Media type changed to audio');
// Stop local video
if (this.props.localMedia.getVideoTracks().length !== 0) {
currentCall.getLocalStreams()[0].getVideoTracks()[0].stop();
}
this.setState({audioOnly: true});
this.props.speakerphoneOff();
} else {
this.forceUpdate();
}
currentCall.removeListener('stateChanged', this.callStateChanged);
// Switch to video earlier. The callOverlay has a handle on
// 'established'. It starts a timer. To prevent a state updating on
// unmounted component we try to switch on 'accept'. This means we get
// to localMedia first.
} else if (newState === 'accepted') {
// Switch if we have audioOnly and local videotracks. This means
// the call object switched and we are transitioning to an
// incoming call.
if (this.state.audioOnly && this.props.localMedia && this.props.localMedia.getVideoTracks().length !== 0) {
console.log('Media type changed to video on accepted');
this.setState({audioOnly: false});
this.props.speakerphoneOn();
}
}
this.forceUpdate();
}
findObjectByKey(array, key, value) {
for (var i = 0; i < array.length; i++) {
if (array[i][key] === value) {
return array[i];
}
}
return null;
}
call() {
assert(this.props.currentCall === null, 'currentCall is not null');
let options = {pcConfig: {iceServers: config.iceServers}, id: this.props.callUUID};
options.localStream = this.props.localMedia;
let call = this.props.account.call(this.props.targetUri, options);
call.on('stateChanged', this.callStateChanged);
}
answerCall() {
assert(this.props.currentCall !== null, 'currentCall is null');
let options = {pcConfig: {iceServers: config.iceServers}};
options.localStream = this.props.localMedia;
this.props.currentCall.answer(options);
}
hangupCall() {
let callUUID = this.props.currentCall._callkeepUUID;
this.props.currentCall.removeListener('stateChanged', this.callStateChanged);
this.props.hangupCall(callUUID);
}
mediaPlaying() {
if (this.props.currentCall === null) {
this.call();
} else {
this.answerCall();
}
}
render() {
//console.log('Call: render call to', this.props.targetUri);
let box = null;
let remoteUri = this.props.targetUri;
let remoteDisplayName = remoteUri;
if (this.props.currentCall !== null && this.props.currentCall.state == 'established') {
remoteUri = this.props.currentCall.remoteIdentity.uri;
remoteDisplayName = this.props.currentCall.remoteIdentity.displayName || this.props.currentCall.remoteIdentity.uri;
} else {
remoteUri = this.props.targetUri;
remoteDisplayName = this.props.targetUri;
}
if (remoteUri.indexOf('3333@') > -1) {
remoteDisplayName = 'Video Test';
} else if (remoteUri.indexOf('4444@') > -1) {
remoteDisplayName = 'Echo Test';
} else {
if (this.props.contacts) {
var contact_obj = this.findObjectByKey(this.props.contacts, 'remoteParty', remoteUri);
if (contact_obj) {
remoteDisplayName = contact_obj.displayName;
}
}
}
if (this.props.localMedia !== null) {
if (this.state.audioOnly) {
box = (
);
} else {
if (this.props.currentCall != null && this.props.currentCall.state === 'established') {
box = (
);
} else {
//console.log('Will render local media');
if (this.props.currentCall && this.props.currentCall.state && this.props.currentCall.state === 'terminated') {
// do not render
} else {
box = (
);
}
}
}
}
return box;
}
}
Call.propTypes = {
targetUri : PropTypes.string.isRequired,
account : PropTypes.object.isRequired,
hangupCall : PropTypes.func.isRequired,
localMedia : PropTypes.object,
currentCall : PropTypes.object,
shareScreen : PropTypes.func,
escalateToConference : PropTypes.func,
generatedVideoTrack : PropTypes.bool,
callKeepSendDtmf : PropTypes.func,
callKeepToggleMute : PropTypes.func,
speakerphoneOn : PropTypes.func,
speakerphoneOff : PropTypes.func,
callUUID : PropTypes.string,
contacts : PropTypes.array
};
export default Call;
diff --git a/app/components/CallByUriBox.js b/app/components/CallByUriBox.js
index aeb8e46..11062bb 100644
--- a/app/components/CallByUriBox.js
+++ b/app/components/CallByUriBox.js
@@ -1,103 +1,104 @@
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { Title, Button, TextInput } from 'react-native-paper';
import autoBind from 'auto-bind';
import { View } from 'react-native';
import Call from './Call';
class CallByUriBox extends Component {
constructor(props) {
super(props);
autoBind(this);
this.state = {
displayName: ''
};
this._notificationCenter = null;
}
componentDidMount() {
this._notificationCenter = this.props.notificationCenter();
}
- componentWillReceiveProps(nextProps) {
+ //getDerivedStateFromProps(nextProps, state) {
+ UNSAFE_componentWillReceiveProps(nextProps) {
if (!this.props.currentCall && nextProps.currentCall) {
nextProps.currentCall.on('stateChanged', this.callStateChanged);
}
}
callStateChanged(oldState, newState, data) {
if (newState === 'terminated') {
this._notificationCenter.postSystemNotification('Thanks for calling with Sylk!', {timeout: 10});
}
}
handleDisplayNameChange(event) {
this.setState({displayName: event.target.value});
}
handleSubmit(event) {
event.preventDefault();
this.props.handleCallByUri(this.state.displayName, this.props.targetUri);
}
render() {
const validInput = this.state.displayName !== '';
let content;
if (this.props.localMedia !== null) {
content = (
);
} else {
content = (
You've been invited to call {this.props.targetUri}
);
}
return (
{content}
);
}
}
CallByUriBox.propTypes = {
handleCallByUri : PropTypes.func.isRequired,
notificationCenter : PropTypes.func.isRequired,
hangupCall : PropTypes.func.isRequired,
shareScreen : PropTypes.func.isRequired,
targetUri : PropTypes.string,
localMedia : PropTypes.object,
account : PropTypes.object,
currentCall : PropTypes.object,
generatedVideoTrack : PropTypes.bool
};
export default CallByUriBox;
diff --git a/app/components/CallOverlay.js b/app/components/CallOverlay.js
index b7112ba..789243c 100644
--- a/app/components/CallOverlay.js
+++ b/app/components/CallOverlay.js
@@ -1,121 +1,122 @@
import React from 'react';
import { View, Text } from 'react-native';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import moment from 'moment';
import momentFormat from 'moment-duration-format';
import autoBind from 'auto-bind';
import { Appbar } from 'react-native-paper';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
class CallOverlay extends React.Component {
constructor(props) {
super(props);
autoBind(this);
this.duration = null;
this.timer = null;
this._isMounted = true;
}
componentDidMount() {
if (this.props.call) {
if (this.props.call.state === 'established') {
this.startTimer();
} else if (this.props.call.state !== 'terminated') {
this.props.call.on('stateChanged', this.callStateChanged);
}
}
}
- componentWillReceiveProps(nextProps) {
+ //getDerivedStateFromProps(nextProps, state) {
+ UNSAFE_componentWillReceiveProps(nextProps) {
if (this.props.call == null && nextProps.call) {
if (nextProps.call.state === 'established') {
this.startTimer();
} else if (nextProps.call.state !== 'terminated') {
nextProps.call.on('stateChanged', this.callStateChanged);
}
}
}
componentWillUnmount() {
this._isMounted = false;
clearTimeout(this.timer);
}
callStateChanged(oldState, newState, data) {
// Prevent starting timer when we are unmounted
if (newState === 'established' && this._isMounted) {
this.startTimer();
this.props.call.removeListener('stateChanged', this.callStateChanged);
}
}
startTimer() {
if (this.timer !== null) {
// already armed
return;
}
// TODO: consider using window.requestAnimationFrame
const startTime = new Date();
this.timer = setInterval(() => {
this.duration = moment.duration(new Date() - startTime).format('hh:mm:ss', {trim: false});
if (this.props.show) {
this.forceUpdate();
}
}, 300);
}
render() {
let header = null;
let displayName = this.props.remoteUri;
if (this.props.remoteDisplayName && this.props.remoteDisplayName !== this.props.remoteUri) {
displayName = this.props.remoteDisplayName;
}
if (this.props.show) {
let callDetail;
if (this.duration !== null) {
callDetail = {this.duration};
callDetail = 'Duration:' + this.duration;
} else {
callDetail = 'Connecting...'
}
if (this.props.remoteUri.search('videoconference') > -1) {
header = (
);
} else {
header = (
);
}
}
return header
}
}
CallOverlay.propTypes = {
show: PropTypes.bool.isRequired,
remoteUri: PropTypes.string.isRequired,
remoteDisplayName: PropTypes.string,
call: PropTypes.object
};
export default CallOverlay;
diff --git a/app/components/ConferenceByUriBox.js b/app/components/ConferenceByUriBox.js
index a8e375b..e8de716 100644
--- a/app/components/ConferenceByUriBox.js
+++ b/app/components/ConferenceByUriBox.js
@@ -1,122 +1,123 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import autoBind from 'auto-bind';
import { View } from 'react-native';
import { Title, Button, TextInput } from 'react-native-paper';
import Conference from './Conference';
class ConferenceByUriBox extends React.Component {
constructor(props) {
super(props);
autoBind(this);
this.state = {
displayName: ''
};
this._notificationCenter = null;
}
componentDidMount() {
this._notificationCenter = this.props.notificationCenter();
}
- componentWillReceiveProps(nextProps) {
+ //getDerivedStateFromProps(nextProps, state) {
+ UNSAFE_componentWillReceiveProps(nextProps) {
if (!this.props.currentCall && nextProps.currentCall) {
nextProps.currentCall.on('stateChanged', this.callStateChanged);
}
}
callStateChanged(oldState, newState, data) {
if (newState === 'terminated') {
this._notificationCenter.postSystemNotification('Thanks for calling with Sylk!', {timeout: 10});
}
}
handleDisplayNameChange(event) {
this.setState({displayName: event.target.value});
}
handleSubmit(event) {
event.preventDefault();
let displayName;
if (this.state.displayName === '') {
this.setState({displayName: 'Guest'});
displayName = 'Guest';
} else {
displayName = this.state.displayName;
// Bug in SIPSIMPLE, display name can't end with \ else we don't join chat
if (displayName.endsWith('\\')) {
displayName = displayName.slice(0, -1);
}
}
this.props.handler(displayName, this.props.targetUri);
}
render() {
let content;
if (this.props.localMedia !== null) {
content = (
);
} else {
const classes = classNames({
'capitalize' : true,
'btn' : true,
'btn-lg' : true,
'btn-block' : true,
'btn-primary': true
});
const friendlyName = this.props.targetUri.split('@')[0];
content = (
You're about to join a conference! {friendlyName}
);
}
return (
{content}
);
}
}
ConferenceByUriBox.propTypes = {
notificationCenter : PropTypes.func.isRequired,
handler : PropTypes.func.isRequired,
hangupCall : PropTypes.func.isRequired,
shareScreen : PropTypes.func.isRequired,
targetUri : PropTypes.string,
localMedia : PropTypes.object,
account : PropTypes.object,
currentCall : PropTypes.object,
generatedVideoTrack : PropTypes.bool
};
export default ConferenceByUriBox;
diff --git a/app/components/ConferenceModal.js b/app/components/ConferenceModal.js
index 926fa65..9e28426 100644
--- a/app/components/ConferenceModal.js
+++ b/app/components/ConferenceModal.js
@@ -1,97 +1,98 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { View } from 'react-native';
import { Portal, Dialog, Button, Text, TextInput, Surface, Chip } from 'react-native-paper';
import KeyboardAwareDialog from './KeyBoardAwareDialog';
const DialogType = Platform.OS === 'ios' ? KeyboardAwareDialog : Dialog;
import config from '../config';
import styles from '../assets/styles/blink/_ConferenceModal.scss';
class ConferenceModal extends Component {
constructor(props) {
super(props);
this.state = {
conferenceTargetUri: props.targetUri.split('@')[0],
managed: false
};
this.handleConferenceTargetChange = this.handleConferenceTargetChange.bind(this);
this.onHide = this.onHide.bind(this);
this.joinAudio = this.joinAudio.bind(this);
this.joinVideo = this.joinVideo.bind(this);
}
- componentWillReceiveProps(nextProps) {
+ //getDerivedStateFromProps(nextProps, state) {
+ UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({conferenceTargetUri: nextProps.targetUri.split('@')[0]});
}
handleConferenceTargetChange(value) {
this.setState({conferenceTargetUri: value});
}
joinAudio(event) {
event.preventDefault();
const uri = `${this.state.conferenceTargetUri.replace(/[\s()-]/g, '')}@${config.defaultConferenceDomain}`;
this.props.handleConferenceCall(uri.toLowerCase(), {audio: true, video: false});
}
joinVideo(event) {
event.preventDefault();
const uri = `${this.state.conferenceTargetUri.replace(/[\s()-]/g, '')}@${config.defaultConferenceDomain}`;
this.props.handleConferenceCall(uri.toLowerCase(), {audio: true, video: true});
}
onHide() {
this.props.handleConferenceCall(null);
}
render() {
const validUri = this.state.conferenceTargetUri.length > 0 && this.state.conferenceTargetUri.indexOf('@') === -1;
return (
Join Conference
);
}
}
ConferenceModal.propTypes = {
show: PropTypes.bool.isRequired,
handleConferenceCall: PropTypes.func.isRequired,
targetUri: PropTypes.string.isRequired
};
export default ConferenceModal;
diff --git a/app/components/HistoryTileBox.js b/app/components/HistoryTileBox.js
index f0da246..b254dd3 100644
--- a/app/components/HistoryTileBox.js
+++ b/app/components/HistoryTileBox.js
@@ -1,236 +1,238 @@
import React, { Component} from 'react';
import autoBind from 'auto-bind';
import PropTypes from 'prop-types';
import { SafeAreaView, ScrollView, View, FlatList, Text } from 'react-native';
import HistoryCard from './HistoryCard';
import utils from '../utils';
import DigestAuthRequest from 'digest-auth-request';
import storage from '../storage';
import uuid from 'react-native-uuid';
import styles from '../assets/styles/blink/_HistoryTileBox.scss';
class HistoryTileBox extends Component {
constructor(props) {
super(props);
autoBind(this);
this.state = {
serverHistory: [],
refreshHistory: this.props.refreshHistory
}
const echoTest = {
remoteParty: '4444@sylk.link',
displayName: 'Echo test',
type: 'contact',
label: 'Call to test microphone',
id: uuid.v4()
};
const videoTest = {
remoteParty: '3333@sylk.link',
displayName: 'Video test',
type: 'contact',
label: 'Call to test video',
id: uuid.v4()
};
const echoTestCard = Object.assign({}, echoTest);
const videoTestCard = Object.assign({}, videoTest);
let initialContacts = [echoTestCard, videoTestCard];
this.initialContacts = initialContacts;
storage.get('history').then((history) => {
if (history) {
this.setState({localHistory: history});
}
});
}
componentDidMount() {
this.getServerHistory();
}
refreshHistory = res => this.setState({ serverHistory: res.history})
renderItem(item) {
return(
);
}
findObjectByKey(array, key, value) {
for (var i = 0; i < array.length; i++) {
if (array[i][key] === value) {
return array[i];
}
}
return null;
}
+
+ //getDerivedStateFromProps(nextProps, state) {
UNSAFE_componentWillReceiveProps(props) {
if (props.refreshHistory !== this.state.refreshHistory) {
this.getServerHistory();
}
}
getServerHistory() {
let history = [];
utils.timestampedLog('Requesting call history from server');
let getServerCallHistory = new DigestAuthRequest(
'GET',
`${this.props.config.serverCallHistoryUrl}?action=get_history&realm=${this.props.account.id.split('@')[1]}`,
this.props.account.id.split('@')[0],
this.props.password
);
// Disable logging
getServerCallHistory.loggingOn = false;
getServerCallHistory.request((data) => {
if (data.success !== undefined && data.success === false) {
logger.debug('Error getting call history from server: %o', data.error_message)
return;
}
if (data.placed) {
data.placed.map(elem => {elem.direction = 'placed'; return elem});
history = history.concat(data.placed);
}
if (data.received) {
data.received.map(elem => {elem.direction = 'received'; return elem});
history = history.concat(data.received);
}
if (history) {
history.sort((a, b) => (a.startTime < b.startTime) ? 1 : -1)
const known = [];
history = history.filter((elem) => {
if (known.indexOf(elem.remoteParty) <= -1) {
elem.type = 'history';
var contact_obj = this.findObjectByKey(this.props.contacts, 'remoteParty', elem.remoteParty);
if (contact_obj) {
elem.displayName = contact_obj.name;
elem.photo = contact_obj.photo;
// TODO update icon here
} else {
elem.photo = null;
}
elem.label = elem.direction;
if (!elem.displayName) {
elem.displayName = elem.remoteParty;
}
if (!elem.media || !Array.isArray(elem.media)) {
elem.media = ['audio'];
}
if (elem.remoteParty.indexOf('@videoconference') > -1) {
elem.remoteParty = elem.remoteParty.split('@')[0] + '@videoconference.' + this.props.config.defaultDomain;
}
if ((elem.media.indexOf('audio') > -1 || elem.media.indexOf('video') > -1) &&
(elem.remoteParty !== this.props.account.id || elem.direction !== 'placed')) {
known.push(elem.remoteParty);
if (elem.remoteParty.indexOf('3333@') > -1) {
// see Call.js as well if we change this
elem.displayName = 'Video Test';
}
if (elem.remoteParty.indexOf('4444@') > -1) {
// see Call.js as well if we change this
elem.displayName = 'Echo Test';
}
elem.id = uuid.v4();
return elem;
}
}
});
if (history.length < 3) {
history = history.concat(this.initialContacts);
}
this.setState({serverHistory: history});
}
}, (errorCode) => {
logger.debug('Error getting call history from server: %o', errorCode)
});
}
render() {
//utils.timestampedLog('Render history');
// Join URIs from local and server history for input
let matchedContacts = [];
let items = this.state.serverHistory.filter(historyItem => historyItem.remoteParty.startsWith(this.props.targetUri));
let searchExtraItems = this.props.contacts;
searchExtraItems.concat(this.initialContacts);
if (this.props.targetUri && this.props.targetUri.length > 2 && !this.props.selectedContact) {
matchedContacts = searchExtraItems.filter(contact => (contact.remoteParty.toLowerCase().search(this.props.targetUri) > -1 || contact.displayName.toLowerCase().search(this.props.targetUri) > -1));
} else if (this.props.selectedContact && this.props.selectedContact.type === 'contact') {
matchedContacts.push(this.props.selectedContact);
}
items = items.concat(matchedContacts);
//console.log(items);
items = items.slice(0, 8);
//utils.timestampedLog('Render history in', this.props.orientation);
let columns = 1;
if (this.props.isTablet) {
columns = this.props.orientation === 'landscape' ? 3 : 2;
} else {
columns = this.props.orientation === 'landscape' ? 2 : 1;
}
return (
item.id}
key={this.props.orientation}
/>
);
}
}
HistoryTileBox.propTypes = {
account : PropTypes.object.isRequired,
password : PropTypes.string.isRequired,
config : PropTypes.object.isRequired,
targetUri : PropTypes.string,
selectedContact : PropTypes.object,
contacts : PropTypes.array,
orientation : PropTypes.string,
setTargetUri : PropTypes.func,
isTablet : PropTypes.bool,
refreshHistory : PropTypes.bool
};
export default HistoryTileBox;