mirror of
https://github.com/openmhz/trunk-server.git
synced 2026-11-12 08:47:40 -05:00
added stars and new calls
This commit is contained in:
@@ -241,7 +241,39 @@ function package_call(item) {
|
||||
return call;
|
||||
}
|
||||
|
||||
|
||||
exports.remove_star = function(req, res, next) {
|
||||
var objectId = req.params.id;
|
||||
try {
|
||||
var o_id = ObjectID.createFromHexString(objectId);
|
||||
} catch (err) {
|
||||
console.warn("[" + req.params.shortName + "] Error - /:shortName/call/:id generating ObjectID " + err);
|
||||
res.status(500);
|
||||
res.send(JSON.stringify({
|
||||
success: false,
|
||||
message: err,
|
||||
"_id": objectId
|
||||
}));
|
||||
return;
|
||||
}
|
||||
Call.findOneAndUpdate({ _id: objectId }, { $inc: { star: -1 } }, {new: true },function(err, item) {
|
||||
if (err) {
|
||||
res.status(500);
|
||||
res.send(JSON.stringify({
|
||||
success: false,
|
||||
message: err,
|
||||
"_id": objectId
|
||||
}));
|
||||
} else {
|
||||
var call = package_call(item);
|
||||
req.call = call;
|
||||
res.send(JSON.stringify({
|
||||
success: true,
|
||||
call: call
|
||||
}));
|
||||
next();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
exports.add_star = function(req, res, next) {
|
||||
|
||||
@@ -178,7 +178,7 @@ app.get('/:shortName/calls/older', calls.get_older_calls);
|
||||
app.get('/:shortName/calls/:time/older', calls.get_iphone_calls);
|
||||
app.get('/:shortName/calls', calls.get_calls);
|
||||
app.post('/:shortName/star/:id', calls.add_star);
|
||||
|
||||
app.post('/:shortName/removeStar/:id', calls.remove_star);
|
||||
|
||||
/*------ UPLOADS ---------- upload.single('call'), uploads.upload,*/
|
||||
app.post('/:shortName/upload', upload.single('call'), uploads.upload, async function (req, res) {
|
||||
|
||||
@@ -1,88 +1,44 @@
|
||||
|
||||
import React, { Component } from "react";
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
Table,
|
||||
Icon,
|
||||
Label
|
||||
} from "semantic-ui-react";
|
||||
import { connect } from "react-redux"
|
||||
import { bindActionCreators } from 'redux'
|
||||
import * as callActionCreators from "./call-actions"
|
||||
|
||||
import { addStar, removeStar} from "../features/calls/callsSlice";
|
||||
import { useDispatch } from 'react-redux'
|
||||
|
||||
function mapStateToProps(state, props) {
|
||||
return {
|
||||
shortName: props.shortName
|
||||
const CallItem = (props) => {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
callActions: bindActionCreators(callActionCreators, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class CallItem extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.hideStar = this.hideStar.bind(this);
|
||||
this.showStar = this.showStar.bind(this);
|
||||
this.addStar = this.addStar.bind(this);
|
||||
this.state = {
|
||||
starVisible: false,
|
||||
starClicked: false
|
||||
}
|
||||
}
|
||||
sourceString(call) {
|
||||
var srcString = "";
|
||||
if (call.srcList) {
|
||||
for (var src in call.srcList) {
|
||||
/* srcNum = call.srcList[src].src;
|
||||
if (sources.hasOwnProperty(srcNum)) {
|
||||
srcString = srcString + sources[srcNum].codeName + ", ";
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
return srcString;
|
||||
}
|
||||
|
||||
componentDidUpdate(){
|
||||
if (this.props.activeCall) {
|
||||
console.log("Active call mounted")
|
||||
}
|
||||
}
|
||||
addStar(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.nativeEvent.stopImmediatePropagation();
|
||||
if (!this.state.starClicked) {
|
||||
|
||||
this.props.callActions.addStar(this.props.call._id);
|
||||
this.setState({starClicked: true});
|
||||
}
|
||||
}
|
||||
|
||||
hideStar() {
|
||||
this.setState({ starVisible: false })
|
||||
}
|
||||
|
||||
showStar() {
|
||||
this.setState({ starVisible: true })
|
||||
}
|
||||
|
||||
render() {
|
||||
const call = this.props.call;
|
||||
const [starVisible, setStarVisible] = useState(false);
|
||||
const [starClicked, setStarClicked] = useState(false);
|
||||
const dispatch = useDispatch();
|
||||
const call = props.call;
|
||||
const time = new Date(call.time);
|
||||
const activeCall = props.activeCall;
|
||||
|
||||
const handleStarClicked = (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.nativeEvent.stopImmediatePropagation();
|
||||
if (!starClicked) {
|
||||
setStarClicked(true);
|
||||
dispatch(addStar(props.call._id));
|
||||
} else {
|
||||
setStarClicked(false);
|
||||
dispatch(removeStar(props.call._id));
|
||||
}
|
||||
}
|
||||
|
||||
var rowSelected={};
|
||||
let starButton;
|
||||
var starClickable = {};
|
||||
if (!this.state.starClicked) {
|
||||
if (!starClicked) {
|
||||
starClickable = {link: true };
|
||||
}
|
||||
if (!call.star && this.state.starVisible) {
|
||||
if (!call.star && starVisible) {
|
||||
starButton = <Icon name='star outline' />
|
||||
}
|
||||
|
||||
@@ -98,7 +54,7 @@ render() {
|
||||
</Icon.Group>)
|
||||
}
|
||||
|
||||
if (this.props.activeCall) {
|
||||
if (activeCall) {
|
||||
rowSelected={positive: true,
|
||||
color: "blue",
|
||||
key: "blue",
|
||||
@@ -106,26 +62,21 @@ render() {
|
||||
}
|
||||
}
|
||||
var talkgroup;
|
||||
if ((typeof this.props.talkgroups == 'undefined') || (typeof this.props.talkgroups[call.talkgroupNum] == 'undefined')) {
|
||||
if ((typeof props.talkgroups == 'undefined') || (typeof props.talkgroups[call.talkgroupNum] == 'undefined')) {
|
||||
talkgroup = call.talkgroupNum;
|
||||
} else {
|
||||
talkgroup = this.props.talkgroups[call.talkgroupNum].description;
|
||||
talkgroup = props.talkgroups[call.talkgroupNum].description;
|
||||
}
|
||||
return (
|
||||
<Table.Row onClick={(e) => this.props.onClick({call: call}, e)} {...rowSelected}>
|
||||
<Table.Row onClick={(e) => props.onClick({call: call}, e)} {...rowSelected}>
|
||||
<Table.Cell> {call.len} </Table.Cell>
|
||||
<Table.Cell> {talkgroup} </Table.Cell>
|
||||
<Table.Cell> {time.toLocaleTimeString()} </Table.Cell>
|
||||
<Table.Cell onMouseEnter={this.showStar} onMouseLeave={this.hideStar} onClick={this.addStar}>{starButton}</Table.Cell>
|
||||
<Table.Cell onMouseEnter={()=> setStarVisible(true)} onMouseLeave={() => setStarVisible(false)} onClick={handleStarClicked}>{starButton}</Table.Cell>
|
||||
</Table.Row>
|
||||
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(CallItem)
|
||||
|
||||
export default CallItem;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { Link, useLocation, useParams, useNavigate} from 'react-router-dom';
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { Link, useLocation, useParams, useNavigate } from 'react-router-dom';
|
||||
|
||||
import MediaPlayer from "./MediaPlayer";
|
||||
import FilterModal from "./FilterModal";
|
||||
@@ -10,7 +10,7 @@ import CallInfo from "./CallInfo";
|
||||
import ListCalls from "./ListCalls";
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import { setLive, setShortName, setFilter } from "../features/callPlayer/callPlayerSlice";
|
||||
import { getCalls, getOlderCalls, getNewerCalls} from "../features/calls/callsSlice";
|
||||
import { getCalls, getOlderCalls, getNewerCalls, addCall } from "../features/calls/callsSlice";
|
||||
import { useGetGroupsQuery, useGetTalkgroupsQuery } from '../features/api/apiSlice'
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
import {
|
||||
@@ -24,78 +24,76 @@ import {
|
||||
Button
|
||||
} from "semantic-ui-react";
|
||||
import "./CallPlayer.css";
|
||||
//import setupSocket from '../socket/SetupSocket.js'
|
||||
import queryString from '../query-string';
|
||||
import io from 'socket.io-client';
|
||||
import { setDateFilter } from "./call-actions";
|
||||
|
||||
|
||||
const socket = io(process.env.REACT_APP_BACKEND_SERVER );
|
||||
const socket = io(process.env.REACT_APP_BACKEND_SERVER);
|
||||
|
||||
|
||||
// ----------------------------------------------------
|
||||
function CallPlayer (props) {
|
||||
function CallPlayer(props) {
|
||||
|
||||
const { shortName } = useParams();
|
||||
const { ref: loadOlderRef, inView: loadOlderInView, entry: loadOlderEntry } = useInView({
|
||||
/* Optional options */
|
||||
threshold: 0.5
|
||||
});
|
||||
const { ref: loadNewerRef, inView: loadNewerInView, entry: loadNewerEntry } = useInView({
|
||||
/* Optional options */
|
||||
threshold: 0.5
|
||||
});
|
||||
const { data:groupsData, isSuccess:isGroupsSuccess } = useGetGroupsQuery(shortName);
|
||||
//const { data:callsData, isSuccess:isCallsSuccess } = useGetCallsQuery({shortName});
|
||||
const {loading: callsLoading, data: callsData} = useSelector((state) => state.calls);
|
||||
|
||||
//console.log(callsData);
|
||||
const { data:talkgroupsData, isSuccess:isTalkgroupsSuccess } = useGetTalkgroupsQuery(shortName);
|
||||
//const allCalls = callsData?callsData.ids.map( id => callsData.entities[id] ):[]
|
||||
const { shortName } = useParams();
|
||||
const { ref: loadOlderRef, inView: loadOlderInView, entry: loadOlderEntry } = useInView({
|
||||
/* Optional options */
|
||||
threshold: 0.5
|
||||
});
|
||||
const { ref: loadNewerRef, inView: loadNewerInView, entry: loadNewerEntry } = useInView({
|
||||
/* Optional options */
|
||||
threshold: 0.5
|
||||
});
|
||||
const { data: groupsData, isSuccess: isGroupsSuccess } = useGetGroupsQuery(shortName);
|
||||
//const { data:callsData, isSuccess:isCallsSuccess } = useGetCallsQuery({shortName});
|
||||
const { loading: callsLoading, data: callsData } = useSelector((state) => state.calls);
|
||||
|
||||
const [autoPlay, setAutoPlay] = useState(true);
|
||||
const [addCallScroll, setAddCallScroll] = useState(false);
|
||||
const [currentCall, setCurrentCall] = useState(false);
|
||||
const [prevScrollHeight, setPrevScrollHeight] = useState(0);
|
||||
const [playTime, setPlayTime] = useState(0);
|
||||
const [selectLoadCall, setSelectLoadCall] = useState(false);
|
||||
const [callSelect, setCallSelect] = useState(false);
|
||||
const [urlOptions, setUrlOptions] = useState(false);
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
const [sidebarOpened, setSidebarOpened] = useState(false);
|
||||
const [filterVisible, setFilterVisible] = useState(false);
|
||||
const [groupVisible, setGroupVisible] = useState(false);
|
||||
const [calendarVisible, setCalendarVisible] = useState(false);
|
||||
const [isConnected, setIsConnected] = useState(socket.connected);
|
||||
const [loadCallId, setLoadCallId] = useState(false);
|
||||
//console.log(callsData);
|
||||
const { data: talkgroupsData, isSuccess: isTalkgroupsSuccess } = useGetTalkgroupsQuery(shortName);
|
||||
//const allCalls = callsData?callsData.ids.map( id => callsData.entities[id] ):[]
|
||||
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
const positionRef = useRef();
|
||||
const [autoPlay, setAutoPlay] = useState(true);
|
||||
const [addCallScroll, setAddCallScroll] = useState(false);
|
||||
const [currentCall, setCurrentCall] = useState(false);
|
||||
const [prevScrollHeight, setPrevScrollHeight] = useState(0);
|
||||
const [playTime, setPlayTime] = useState(0);
|
||||
const [selectLoadCall, setSelectLoadCall] = useState(false);
|
||||
const [urlOptions, setUrlOptions] = useState(false);
|
||||
const [isPlaying, setIsPlaying] = useState(false);
|
||||
const [sidebarOpened, setSidebarOpened] = useState(false);
|
||||
const [filterVisible, setFilterVisible] = useState(false);
|
||||
const [groupVisible, setGroupVisible] = useState(false);
|
||||
const [calendarVisible, setCalendarVisible] = useState(false);
|
||||
const [isConnected, setIsConnected] = useState(socket.connected);
|
||||
const [loadCallId, setLoadCallId] = useState(false);
|
||||
|
||||
const filterType = useSelector((state) => state.callPlayer.filterType);
|
||||
const filterGroupId = useSelector((state) => state.callPlayer.filterGroupId);
|
||||
const filterTalkgroups = useSelector((state) => state.callPlayer.filterTalkgroups);
|
||||
const filterStarred = useSelector((state) => state.callPlayer.filterStarred);
|
||||
const filterDate = useSelector((state) => state.callPlayer.filterDate);
|
||||
const live = useSelector((state) => state.callPlayer.live);
|
||||
const uri = queryString.parse(useLocation().search);
|
||||
const pathname = useLocation().pathname;
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
const positionRef = useRef();
|
||||
|
||||
let currentCallId = false;
|
||||
let currentCallMedia = false;
|
||||
const filterType = useSelector((state) => state.callPlayer.filterType);
|
||||
const filterGroupId = useSelector((state) => state.callPlayer.filterGroupId);
|
||||
const filterTalkgroups = useSelector((state) => state.callPlayer.filterTalkgroups);
|
||||
const filterStarred = useSelector((state) => state.callPlayer.filterStarred);
|
||||
const filterDate = useSelector((state) => state.callPlayer.filterDate);
|
||||
const live = useSelector((state) => state.callPlayer.live);
|
||||
const uri = queryString.parse(useLocation().search);
|
||||
const pathname = useLocation().pathname;
|
||||
|
||||
if (currentCall) {
|
||||
currentCallId = currentCall._id;
|
||||
currentCallMedia = currentCall.url;
|
||||
}
|
||||
let currentCallId = false;
|
||||
let currentCallMedia = false;
|
||||
|
||||
if (currentCall) {
|
||||
currentCallId = currentCall._id;
|
||||
currentCallMedia = currentCall.url;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const handlePlayPause = (playing) => setIsPlaying(playing);
|
||||
|
||||
const handlePusherClick = () => {
|
||||
|
||||
const handlePusherClick = () => {
|
||||
if (sidebarOpened) setSidebarOpened(false);
|
||||
}
|
||||
|
||||
@@ -105,35 +103,30 @@ function CallPlayer (props) {
|
||||
const handleCalendarToggle = () => setCalendarVisible(!calendarVisible);
|
||||
|
||||
const playCall = (data) => {
|
||||
setCurrentCall(data.call);
|
||||
setIsPlaying(true);
|
||||
}
|
||||
|
||||
setCurrentCall(data.call);
|
||||
setIsPlaying(true);
|
||||
}
|
||||
|
||||
|
||||
const callEnded = () => {
|
||||
if (callsData) {
|
||||
const currentIndex = callsData.ids.findIndex(callId => callId === currentCallId);
|
||||
if (autoPlay && (currentIndex > 0)) {
|
||||
const nextCallId = callsData.ids[currentIndex - 1];
|
||||
const nextCall = callsData.entities[nextCallId];
|
||||
const currentIndex = callsData.ids.findIndex(callId => callId === currentCallId);
|
||||
if (autoPlay && (currentIndex > 0)) {
|
||||
const nextCallId = callsData.ids[currentIndex - 1];
|
||||
const nextCall = callsData.entities[nextCallId];
|
||||
|
||||
setCurrentCall(nextCall);
|
||||
setIsPlaying(true);
|
||||
setCurrentCall(nextCall);
|
||||
setIsPlaying(true);
|
||||
} else {
|
||||
setIsPlaying(false);
|
||||
}
|
||||
} else {
|
||||
setIsPlaying(false);
|
||||
console.log("Somehow called, callEnded() but callsData was false");
|
||||
}
|
||||
} else {
|
||||
console.log("Somehow called, callEnded() but callsData was false");
|
||||
}
|
||||
}
|
||||
/*const changeUrl = url => callActions.changeUrl(url)
|
||||
|
||||
const getFilterDescription = () => {
|
||||
|
||||
*/
|
||||
|
||||
|
||||
const getFilterDescription = () => {
|
||||
|
||||
var filter = { type: 'all', code: "", filterStarred: false };
|
||||
|
||||
switch (filterType) {
|
||||
@@ -152,16 +145,17 @@ const getFilterDescription = () => {
|
||||
}
|
||||
filter.filterStarred = filterStarred
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const addCall = (data) =>{
|
||||
const handleSocketMessage = (data) => {
|
||||
const message = JSON.parse(data)
|
||||
switch (message.type) {
|
||||
case 'calls':
|
||||
const ref = positionRef;
|
||||
setPrevScrollHeight(positionRef.clientHeight);
|
||||
setAddCallScroll(true);
|
||||
dispatch(addCall(message))
|
||||
/*const refs = this.refs.current;
|
||||
callActions.addCall(message);
|
||||
const newCall = callsById[callsAllIds[0]];
|
||||
@@ -181,32 +175,6 @@ const getFilterDescription = () => {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
socket.on('connect', () => {
|
||||
setIsConnected(true);
|
||||
});
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
setIsConnected(false);
|
||||
});
|
||||
|
||||
socket.on('reconnect', (attempts) => {
|
||||
console.log("Socket Reconnected after attempts: " + attempts); // true
|
||||
|
||||
if (live) {
|
||||
this.startSocket();
|
||||
}
|
||||
})
|
||||
|
||||
socket.on("new message", addCall);
|
||||
|
||||
return () => {
|
||||
socket.off('connect');
|
||||
socket.off('disconnect');
|
||||
socket.off('pong');
|
||||
};
|
||||
}, []);
|
||||
|
||||
const startSocket = () => {
|
||||
const filter = getFilterDescription();
|
||||
socket.emit("start", {
|
||||
@@ -227,7 +195,7 @@ const getFilterDescription = () => {
|
||||
setCurrentCall(false);
|
||||
|
||||
dispatch(getCalls({}));
|
||||
|
||||
|
||||
this.startSocket();
|
||||
}
|
||||
}
|
||||
@@ -235,7 +203,7 @@ const getFilterDescription = () => {
|
||||
|
||||
|
||||
|
||||
const updateUri = () => {
|
||||
const updateUri = () => {
|
||||
var search = "?"
|
||||
switch (filterType) {
|
||||
|
||||
@@ -269,7 +237,7 @@ const updateUri = () => {
|
||||
}
|
||||
search = search + `starred=true`;
|
||||
}
|
||||
navigate(pathname + search, {replace:true});
|
||||
navigate(pathname + search, { replace: true });
|
||||
|
||||
}
|
||||
|
||||
@@ -313,8 +281,7 @@ const updateUri = () => {
|
||||
if (uri.hasOwnProperty('starred')) {
|
||||
const starred = uri['starred'];
|
||||
filter.filterStarred = starred === 'true' ? true : false;
|
||||
|
||||
this.setState({ urlOptions: true });
|
||||
if (!urlOptions) setUrlOptions(true);
|
||||
}
|
||||
|
||||
// is there a time based filter?
|
||||
@@ -322,7 +289,7 @@ const updateUri = () => {
|
||||
const date = new Date(parseInt(uri['time']));
|
||||
filter.filterDate = date.getTime();
|
||||
filter.live = false;
|
||||
this.setState({ urlOptions: true });
|
||||
if (!urlOptions) setUrlOptions(true);
|
||||
}
|
||||
|
||||
// is this just for one call?
|
||||
@@ -332,13 +299,7 @@ const updateUri = () => {
|
||||
setLoadCallId(_id);
|
||||
setSelectLoadCall(true);
|
||||
setAutoPlay(false);
|
||||
this.setState({
|
||||
callId: _id,
|
||||
urlOptions: true,
|
||||
autoPlay: false,
|
||||
callScroll: true,
|
||||
callSelect: true
|
||||
});
|
||||
if (!urlOptions) setUrlOptions(true);
|
||||
//callActions.fetchCallInfo(_id);
|
||||
//callActions.setCallTime(date);
|
||||
}
|
||||
@@ -349,7 +310,7 @@ const updateUri = () => {
|
||||
|
||||
// is there a Filter set?
|
||||
if ((uri.hasOwnProperty('filter-code')) && (uri.hasOwnProperty('filter-type'))) {
|
||||
this.setState({ urlOptions: true });
|
||||
if (!urlOptions) setUrlOptions(true);
|
||||
|
||||
// The Filter is a group
|
||||
if (uri['filter-type'] === "group") {
|
||||
@@ -399,247 +360,187 @@ const updateUri = () => {
|
||||
setCurrentCall(call);
|
||||
}
|
||||
}
|
||||
},[callsData])
|
||||
}, [callsData])
|
||||
|
||||
useEffect(() => {
|
||||
// When a time/date is provided in the URL, it will be added to the filter
|
||||
// When fetchCalls is called it will selected calls that are older
|
||||
//callActions.fetchCalls();
|
||||
//talkgroupActions.fetchTalkgroups(shortName);
|
||||
//groupActions.fetchGroups(shortName);
|
||||
//systemActions.fetchSystems();
|
||||
|
||||
|
||||
|
||||
setStateFromUri();
|
||||
//console.log("Setting short name to: " + shortName)
|
||||
//dispatch(setShortName(shortName));
|
||||
|
||||
return () => {
|
||||
//this.endSocket();
|
||||
stopSocket();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
socket.on('connect', () => {
|
||||
setIsConnected(true);
|
||||
});
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
setIsConnected(false);
|
||||
});
|
||||
|
||||
socket.on('reconnect', (attempts) => {
|
||||
console.log("Socket Reconnected after attempts: " + attempts); // true
|
||||
|
||||
if (live) {
|
||||
this.startSocket();
|
||||
}
|
||||
})
|
||||
|
||||
socket.on("new message", handleSocketMessage);
|
||||
|
||||
return () => {
|
||||
socket.off('connect');
|
||||
socket.off('disconnect');
|
||||
socket.off('pong');
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
updateUri();
|
||||
dispatch(getCalls({}));
|
||||
if (live) {
|
||||
startSocket();
|
||||
}
|
||||
//dispatch(getOlderCalls());
|
||||
}, [shortName,filterGroupId,filterTalkgroups,filterType,filterDate,filterStarred])
|
||||
}, [shortName, filterGroupId, filterTalkgroups, filterType, filterDate, filterStarred])
|
||||
|
||||
|
||||
// Update the Browser URI when any relevant values change
|
||||
useEffect(() => {
|
||||
updateUri();
|
||||
}, [filterGroupId, filterTalkgroups, filterType, filterDate, filterStarred, loadCallId])
|
||||
|
||||
const compareArray = (a1, a2) => {
|
||||
var i = a1.length;
|
||||
while (i--) {
|
||||
if (a1[i] !== a2[i])
|
||||
return false;
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
useEffect( () => {
|
||||
useEffect(() => {
|
||||
if (!urlOptions && groupsData && (groupsData.length > 0)) {
|
||||
setGroupVisible(true);
|
||||
}
|
||||
},[groupsData] )
|
||||
|
||||
/*
|
||||
componentWillUpdate(nextProps, nextState) {
|
||||
}, [groupsData])
|
||||
|
||||
|
||||
const callsChanged = nextProps.callsAllIds[0] !== callsAllIds[0];
|
||||
if (callsChanged) {
|
||||
const { contextRef } = this.state;
|
||||
this.scrollPos = contextRef.scrollTop;
|
||||
this.prevHeight = contextRef.clientHeight;
|
||||
this.autoScroll = true;
|
||||
var archiveLabel = "";
|
||||
if (filterDate) {
|
||||
const filterDateObj = new Date(filterDate);
|
||||
archiveLabel = filterDateObj.toLocaleDateString() + " " + filterDateObj.toLocaleTimeString()
|
||||
}
|
||||
|
||||
var callInfoHeader = "Call Info";
|
||||
var callLink = ""
|
||||
var callDownload = ""
|
||||
if (currentCall) {
|
||||
if ((talkgroupsData) && talkgroupsData[currentCall.talkgroupNum]) {
|
||||
callInfoHeader = talkgroupsData[currentCall.talkgroupNum].description;
|
||||
}
|
||||
|
||||
|
||||
if (callId && !callUrl) {
|
||||
const call = callsById[callId];
|
||||
if (call) {
|
||||
this.setState({ callUrl: call.url });
|
||||
}
|
||||
}
|
||||
}*/
|
||||
/*
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
const { contextRef } = this.state
|
||||
//console.log( contextRef.clientHeight - this.prevHeight );
|
||||
if (this.autoScroll) {
|
||||
this.autoScroll = false;
|
||||
window.scrollBy(0, contextRef.clientHeight - this.prevHeight);
|
||||
}
|
||||
|
||||
// scroll to a call once the calls have loaded
|
||||
if (callScroll && (callsAllIds.length > prevProps.callsAllIds.length)) {
|
||||
const call = callsById[callId];
|
||||
if (call) {
|
||||
this.setState({ callScroll: false });
|
||||
if (this.currentCallRef.current) {
|
||||
this.currentCallRef.current.scrollIntoView({
|
||||
behavior: "auto",
|
||||
block: "center",
|
||||
});
|
||||
}
|
||||
this.scrollPos = contextRef.scrollTop;
|
||||
this.prevHeight = contextRef.clientHeight;
|
||||
}
|
||||
}
|
||||
|
||||
if (callSelect) {
|
||||
const call = callsById[callId];
|
||||
if (call) {
|
||||
const audio = this.audioRef.current;
|
||||
var callUrl = call.url;
|
||||
this.setState({
|
||||
callUrl: callUrl,
|
||||
isPlaying: true,
|
||||
callSelect: false
|
||||
}, () => { audio.playSource(callUrl); }); //scrollToComponent(this.currentCallRef.current);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
//https://stackoverflow.com/questions/36559661/how-can-i-dispatch-from-child-components-in-react-redux
|
||||
//https://stackoverflow.com/questions/42597602/react-onclick-pass-event-with-parameter
|
||||
|
||||
//const { contextRef } = this.state
|
||||
|
||||
var archiveLabel = "";
|
||||
if (filterDate) {
|
||||
const filterDate = new Date(filterDate);
|
||||
archiveLabel = filterDate.toLocaleDateString() + " " + filterDate.toLocaleTimeString()
|
||||
}
|
||||
|
||||
var callInfoHeader = "Call Info";
|
||||
|
||||
|
||||
|
||||
|
||||
var callsAllIds = [];
|
||||
var callsById = false;
|
||||
var callLink = ""
|
||||
var callDownload = ""
|
||||
if (currentCall) {
|
||||
if ((talkgroupsData) && talkgroupsData[currentCall.talkgroupNum]) {
|
||||
callInfoHeader = talkgroupsData[currentCall.talkgroupNum].description;
|
||||
}
|
||||
const callDate = new Date(currentCall.time);
|
||||
callLink = "/system/" + shortName + "?call-id=" + currentCall._id + "&time=" + (callDate.getTime() + 1);
|
||||
callDownload = currentCall.url;
|
||||
}
|
||||
var archive = process.env.REACT_APP_ARCHIVE_DAYS
|
||||
|
||||
var filterLabel = "All"
|
||||
const callDate = new Date(currentCall.time);
|
||||
var search = ""
|
||||
switch (filterType) {
|
||||
case 1:
|
||||
filterLabel = "Group"
|
||||
break;
|
||||
|
||||
case 1:
|
||||
search = `filter-type=group&filter-code=${filterGroupId}&`;
|
||||
break;
|
||||
case 2:
|
||||
filterLabel = "Talkgroups"
|
||||
search = `filter-type=talkgroup&filter-code=${filterTalkgroups}&`;
|
||||
break;
|
||||
default:
|
||||
case 0:
|
||||
filterLabel = "All"
|
||||
break;
|
||||
|
||||
}
|
||||
/* if (calls) {
|
||||
var callRows = calls.map((call) =>
|
||||
<CallItem call={call} key={call.shortName}/>
|
||||
))
|
||||
}*/
|
||||
|
||||
|
||||
return (
|
||||
<div ref={positionRef}>
|
||||
<FilterModal shortName={shortName} open={filterVisible} onClose={handleFilterClose} />
|
||||
<CalendarModal open={calendarVisible} onClose={handleCalendarClose} archive={archive} key={shortName} />
|
||||
<GroupModal shortName={shortName} open={groupVisible} onClose={handleGroupClose} />
|
||||
|
||||
<Sidebar as={Menu} animation='overlay' inverted vertical visible={sidebarOpened}
|
||||
onClick={handlePusherClick} duration={50} width='thin'>
|
||||
<Menu.Item onClick={handlePusherClick} >
|
||||
<span> </span><Icon name="close" inverted={true} link={true} size='small' /></Menu.Item>
|
||||
<Link to="/"><Menu.Item link>Home</Menu.Item></Link>
|
||||
<Link to="/systems"><Menu.Item link>Systems</Menu.Item></Link>
|
||||
<Link to="/about"><Menu.Item link>About</Menu.Item></Link>
|
||||
</Sidebar>
|
||||
<Menu fixed="top">
|
||||
<Menu.Item onClick={handleSidebarToggle}>
|
||||
<Icon name='sidebar' />
|
||||
</Menu.Item>
|
||||
<Menu.Item name='filter-btn' onClick={handleFilterToggle}>
|
||||
<Icon name="filter" />
|
||||
<span className="desktop-only">Filter</span>
|
||||
<Label horizontal={true} color="grey" className="desktop-only">{filterLabel}</Label>
|
||||
</Menu.Item>
|
||||
<Container className="desktop-only" textAlign='center' style={{ fontSize: '1.5rem', paddingLeft: '1em', paddingTop: '.5em' }}>
|
||||
{/*system && system.name*/}
|
||||
</Container>
|
||||
<Menu.Menu position="right">
|
||||
<Menu.Item name='archive-btn' onClick={handleCalendarToggle} active={!live}>
|
||||
<Icon name="calendar" />
|
||||
<span className="desktop-only">
|
||||
{
|
||||
archiveLabel
|
||||
? archiveLabel
|
||||
: "Archive"
|
||||
}
|
||||
</span>
|
||||
</Menu.Item>
|
||||
<Menu.Item name='live-btn' onClick={handleLiveToggle} active={live}>
|
||||
<Icon name="unmute" />
|
||||
<span className="desktop-only">Live</span>
|
||||
</Menu.Item>
|
||||
</Menu.Menu>
|
||||
</Menu>
|
||||
|
||||
|
||||
|
||||
|
||||
<Container className="main">
|
||||
<Sidebar.Pushable>
|
||||
<Sidebar.Pusher
|
||||
onClick={handlePusherClick}
|
||||
style={{ minHeight: '100vh' }}
|
||||
>
|
||||
<div ref={loadNewerRef} />
|
||||
<ListCalls callsData={callsData} activeCallId={currentCallId} talkgroups={talkgroupsData} playCall={playCall} />
|
||||
<div ref={loadOlderRef} style={{height: 50}}/>
|
||||
|
||||
|
||||
</Sidebar.Pusher>
|
||||
</Sidebar.Pushable>
|
||||
<Rail position='right' className="desktop-only" dimmed={sidebarOpened ? "true" : "false"} >
|
||||
<Sticky offset={60} context={positionRef}>
|
||||
<CallInfo call={currentCall} header={callInfoHeader} link={callLink}/>
|
||||
</Sticky>
|
||||
</Rail>
|
||||
</Container>
|
||||
|
||||
<Menu fixed="bottom" compact inverted >
|
||||
<Menu.Item active={autoPlay} onClick={() => setAutoPlay(!autoPlay)}><Icon name="level up" /><span className="desktop-only">Autoplay</span></Menu.Item>
|
||||
<MediaPlayer call={currentCall} onEnded={callEnded} onPlayPause={handlePlayPause} />
|
||||
<Menu.Menu position="right" className="desktop-only">
|
||||
<Menu.Item><SupportModal/></Menu.Item>
|
||||
<Menu.Item><a href={callDownload}><Icon name="download" />Download</a></Menu.Item>
|
||||
<Menu.Item><a href={callLink}><Icon name="at" />Link</a></Menu.Item>
|
||||
</Menu.Menu>
|
||||
</Menu>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
);
|
||||
callLink = "/system/" + shortName + "?" + search + "call-id=" + currentCall._id + "&time=" + (callDate.getTime() + 1);
|
||||
callDownload = currentCall.url;
|
||||
}
|
||||
|
||||
const archive = process.env.REACT_APP_ARCHIVE_DAYS
|
||||
|
||||
var filterLabel = "All"
|
||||
switch (filterType) {
|
||||
case 1:
|
||||
filterLabel = "Group"
|
||||
break;
|
||||
|
||||
case 2:
|
||||
filterLabel = "Talkgroups"
|
||||
break;
|
||||
default:
|
||||
case 0:
|
||||
filterLabel = "All"
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={positionRef}>
|
||||
<FilterModal shortName={shortName} open={filterVisible} onClose={handleFilterClose} />
|
||||
<CalendarModal open={calendarVisible} onClose={handleCalendarClose} archive={archive} key={shortName} />
|
||||
<GroupModal shortName={shortName} open={groupVisible} onClose={handleGroupClose} />
|
||||
|
||||
<Sidebar as={Menu} animation='overlay' inverted vertical visible={sidebarOpened}
|
||||
onClick={handlePusherClick} duration={50} width='thin'>
|
||||
<Menu.Item onClick={handlePusherClick} >
|
||||
<span> </span><Icon name="close" inverted={true} link={true} size='small' /></Menu.Item>
|
||||
<Link to="/"><Menu.Item link>Home</Menu.Item></Link>
|
||||
<Link to="/systems"><Menu.Item link>Systems</Menu.Item></Link>
|
||||
<Link to="/about"><Menu.Item link>About</Menu.Item></Link>
|
||||
</Sidebar>
|
||||
<Menu fixed="top">
|
||||
<Menu.Item onClick={handleSidebarToggle}>
|
||||
<Icon name='sidebar' />
|
||||
</Menu.Item>
|
||||
<Menu.Item name='filter-btn' onClick={handleFilterToggle}>
|
||||
<Icon name="filter" />
|
||||
<span className="desktop-only">Filter</span>
|
||||
<Label horizontal={true} color="grey" className="desktop-only">{filterLabel}</Label>
|
||||
</Menu.Item>
|
||||
<Container className="desktop-only" textAlign='center' style={{ fontSize: '1.5rem', paddingLeft: '1em', paddingTop: '.5em' }}>
|
||||
{/*system && system.name*/}
|
||||
</Container>
|
||||
<Menu.Menu position="right">
|
||||
<Menu.Item name='archive-btn' onClick={handleCalendarToggle} active={!live}>
|
||||
<Icon name="calendar" />
|
||||
<span className="desktop-only">
|
||||
{
|
||||
archiveLabel
|
||||
? archiveLabel
|
||||
: "Archive"
|
||||
}
|
||||
</span>
|
||||
</Menu.Item>
|
||||
<Menu.Item name='live-btn' onClick={handleLiveToggle} active={live}>
|
||||
<Icon name="unmute" />
|
||||
<span className="desktop-only">Live</span>
|
||||
</Menu.Item>
|
||||
</Menu.Menu>
|
||||
</Menu>
|
||||
|
||||
<Container className="main">
|
||||
<Sidebar.Pushable>
|
||||
<Sidebar.Pusher
|
||||
onClick={handlePusherClick}
|
||||
style={{ minHeight: '100vh' }}
|
||||
>
|
||||
<div ref={loadNewerRef} />
|
||||
<ListCalls callsData={callsData} activeCallId={currentCallId} talkgroups={talkgroupsData} playCall={playCall} />
|
||||
<div ref={loadOlderRef} style={{ height: 50 }} />
|
||||
|
||||
|
||||
</Sidebar.Pusher>
|
||||
</Sidebar.Pushable>
|
||||
<Rail position='right' className="desktop-only" dimmed={sidebarOpened ? "true" : "false"} >
|
||||
<Sticky offset={60} context={positionRef}>
|
||||
<CallInfo call={currentCall} header={callInfoHeader} link={callLink} />
|
||||
</Sticky>
|
||||
</Rail>
|
||||
</Container>
|
||||
|
||||
<Menu fixed="bottom" compact inverted >
|
||||
<Menu.Item active={autoPlay} onClick={() => setAutoPlay(!autoPlay)}><Icon name="level up" /><span className="desktop-only">Autoplay</span></Menu.Item>
|
||||
<MediaPlayer call={currentCall} onEnded={callEnded} onPlayPause={handlePlayPause} />
|
||||
<Menu.Menu position="right" className="desktop-only">
|
||||
<Menu.Item><SupportModal /></Menu.Item>
|
||||
<Menu.Item><a href={callDownload}><Icon name="download" />Download</a></Menu.Item>
|
||||
<Menu.Item><a href={callLink}><Icon name="at" />Link</a></Menu.Item>
|
||||
</Menu.Menu>
|
||||
</Menu>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default CallPlayer;
|
||||
|
||||
@@ -125,6 +125,44 @@ const initialState = {
|
||||
return url;
|
||||
}
|
||||
|
||||
export const addStar = createAsyncThunk(
|
||||
'calls/addStar',
|
||||
async(callId,{getState, requestIdleCallback}) => {
|
||||
const {shortName} = getState().callPlayer;
|
||||
const url = process.env.REACT_APP_BACKEND_SERVER + "/" + shortName.toLowerCase() + "/star/" + callId
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: "{}"
|
||||
|
||||
}).then(
|
||||
(data) => data.json()
|
||||
)
|
||||
return res;
|
||||
}
|
||||
)
|
||||
|
||||
export const removeStar = createAsyncThunk(
|
||||
'calls/removeStar',
|
||||
async(callId,{getState, requestIdleCallback}) => {
|
||||
const {shortName} = getState().callPlayer;
|
||||
const url = process.env.REACT_APP_BACKEND_SERVER + "/" + shortName.toLowerCase() + "/removeStar/" + callId
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: "{}"
|
||||
|
||||
}).then(
|
||||
(data) => data.json()
|
||||
)
|
||||
return res;
|
||||
}
|
||||
)
|
||||
|
||||
export const getCalls = createAsyncThunk(
|
||||
'calls/getCalls',
|
||||
async({},{getState, requestId}) => {
|
||||
@@ -162,7 +200,12 @@ export const getCalls = createAsyncThunk(
|
||||
export const callsSlice = createSlice({
|
||||
name: 'calls',
|
||||
initialState,
|
||||
reducers: {},
|
||||
reducers: {
|
||||
|
||||
addCall: (call) => {
|
||||
state.data = callsAdapter.addOne(state.data, call)
|
||||
},
|
||||
},
|
||||
extraReducers: {
|
||||
[getCalls.pending]: (state) => {
|
||||
state.loading = true;
|
||||
@@ -218,6 +261,12 @@ export const callsSlice = createSlice({
|
||||
state.oldestCallTime = new Date(lastTime)
|
||||
}
|
||||
},
|
||||
[addStar.fulfilled]: (state, {payload}) => {
|
||||
state.data.entities[payload.call._id] = payload.call;
|
||||
},
|
||||
[removeStar.fulfilled]: (state, {payload}) => {
|
||||
state.data.entities[payload.call._id] = payload.call;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user