diff --git a/frontend/src/Call/CallPlayer.js b/frontend/src/Call/CallPlayer.js
index ee39862..09f962e 100644
--- a/frontend/src/Call/CallPlayer.js
+++ b/frontend/src/Call/CallPlayer.js
@@ -1,13 +1,12 @@
import React, { useEffect, useLayoutEffect, useState, useRef } from "react";
import { Link, useLocation, useParams, useNavigate } from 'react-router-dom';
-import MediaPlayer from "./MediaPlayer";
-import FilterModal from "./FilterModal";
-import GroupModal from "./GroupModal";
-import SupportModal from "./SupportModal";
-import CalendarModal from "./CalendarModal";
-import CallInfo from "./CallInfo";
-import ListCalls from "./ListCalls";
+import MediaPlayer from "./components/MediaPlayer";
+
+import SupportModal from "./components/SupportModal";
+
+import CallInfo from "./components/CallInfo";
+import ListCalls from "./components/ListCalls";
import { useSelector, useDispatch } from 'react-redux'
import { setLive, setFilter,setDateFilter } from "../features/callPlayer/callPlayerSlice";
import { getCalls, getOlderCalls, getNewerCalls, addCall } from "../features/calls/callsSlice";
@@ -25,8 +24,8 @@ import {
import "./CallPlayer.css";
import queryString from '../query-string';
import io from 'socket.io-client';
-
-
+import { useCallLink } from "./components/CallLinks";
+import "./CallPlayer.css";
const socket = io(process.env.REACT_APP_BACKEND_SERVER);
@@ -35,6 +34,9 @@ const socket = io(process.env.REACT_APP_BACKEND_SERVER);
function CallPlayer(props) {
const { shortName } = useParams();
+ const selectCallId = props.selectCallId;
+ const callsData = props.callsData;
+
const { ref: loadOlderRef, inView: loadOlderInView } = useInView({
/* Optional options */
threshold: 0.5
@@ -43,37 +45,27 @@ function CallPlayer(props) {
/* Optional options */
threshold: 0.5
});
+
const { data: groupsData, isSuccess: isGroupsSuccess } = useGetGroupsQuery(shortName);
- const { loading: callsLoading, data: callsData } = useSelector((state) => state.calls);
const { data: talkgroupsData, isSuccess: isTalkgroupsSuccess } = useGetTalkgroupsQuery(shortName);
const [autoPlay, setAutoPlay] = useState(true);
const [currentCall, setCurrentCall] = 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 {callLink,callDownload,callTweet} = useCallLink(currentCall)
+
+
+
const navigate = useNavigate();
const dispatch = useDispatch();
const positionRef = useRef(); // lets us get the Y Scroll offset for the Call List
- const pageYOffset = useRef(); // Store the current Scroll Offset in a way that guarantees the latest value is available when Call Data is updated
const shouldPlayAddCallRef = useRef(); // we need to do this to make the current value of isPlaying available in the socket message callback
shouldPlayAddCallRef.current = (!isPlaying && autoPlay)?true: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;
let currentCallId = false;
@@ -86,16 +78,10 @@ function CallPlayer(props) {
setIsPlaying(playing);
}
- const handlePusherClick = () => {
- if (sidebarOpened) setSidebarOpened(false);
- }
const handleAutoPlay = (currentAutoPlay) => {
setAutoPlay(!currentAutoPlay);
}
- const handleSidebarToggle = () => setSidebarOpened(!sidebarOpened);
- const handleFilterToggle = () => setFilterVisible(!filterVisible);
- const handleCalendarToggle = () => setCalendarVisible(!calendarVisible);
const playCall = (data) => {
setCurrentCall(data.call);
@@ -120,190 +106,6 @@ function CallPlayer(props) {
}
}
- const getFilterDescription = () => {
-
- var filter = { type: 'all', code: "", filterStarred: false };
-
- switch (filterType) {
- case 1:
- filter.type = "group";
- filter.code = filterGroupId
- break;
- case 2:
- filter.type = "talkgroup";
- filter.code = filterTalkgroups
- break;
- default:
- case 0:
- filter.type = "all";
- filter.code = ""
- }
- filter.filterStarred = filterStarred
- return filter;
- }
-
-
- const handleSocketMessage = (data) => {
- const message = JSON.parse(data)
- switch (message.type) {
- case 'calls':
-
- pageYOffset.current = positionRef.current.clientHeight;
-
- if (shouldPlayAddCallRef.current) {
- setCurrentCall(message);
- }
- dispatch(addCall(message));
-
- console.log("Got: " + message._id);
- break
- default:
- break
- }
- }
-
- const startSocket = () => {
- const filter = getFilterDescription();
-
- socket.emit("start", {
- filterCode: filter.code,
- filterType: filter.type,
- filterName: "OpenMHz",
- filterStarred: filter.starred,
- shortName: shortName
- });
- }
- const stopSocket = () => {
- socket.emit("stop");
- }
-
- const updateUri = () => {
- var search = "?"
- switch (filterType) {
-
- case 1:
- search = search + `filter-type=group&filter-code=${filterGroupId}`;
- break;
- case 2:
- search = search + `filter-type=talkgroup&filter-code=${filterTalkgroups}`;
- break;
- default:
- case 0:
- break;
-
- }
- if (loadCallId) {
- if (search.length !== 1) {
- search = search + '&';
- }
- search = search + `call-id=${loadCallId}`
- }
- if (filterDate) {
- if (search.length !== 1) {
- search = search + '&';
- }
- search = search + `time=${filterDate}`;
- }
-
- if (filterStarred) {
- if (search.length !== 1) {
- search = search + '&';
- }
- search = search + `starred=true`;
- }
- navigate(pathname + search, { replace: true });
-
- }
-
- const handleLiveToggle = (currentlyLive) => {
- if (!live) {
- dispatch(setDateFilter(false));
- dispatch(setLive(true));
- setCurrentCall(false);
- dispatch(getCalls({}));
-
- startSocket();
- }
- }
-
- const handleCalendarClose = (didUpdate) => {
- setCalendarVisible(!calendarVisible);
-
- if (didUpdate) {
- dispatch(setLive(false));
- setCurrentCall(false);
- stopSocket();
- }
- }
-
- const handleGroupClose = (didUpdate) => {
- setGroupVisible(!groupVisible);
- }
-
- const handleFilterClose = (didUpdate) => {
- setFilterVisible(!filterVisible);
-
- if (didUpdate) {
- setCurrentCall(false);
- }
- }
-
-
- const setStateFromUri = async () => {
- var filter = {
- filterDate: false,
- filterType: 0, // this is "all"
- filterTalkgroups: [],
- filterGroupId: false,
- filterStarred: false,
- live: true,
- shortName: shortName
- };
-
- // is there a star filter?
- if (uri.hasOwnProperty('starred')) {
- const starred = uri['starred'];
- filter.filterStarred = starred === 'true' ? true : false;
- if (!urlOptions) setUrlOptions(true);
- }
-
- // is there a time based filter?
- if (uri.hasOwnProperty('time')) {
- const date = new Date(parseInt(uri['time']));
- filter.filterDate = date.getTime();
- filter.live = false;
- if (!urlOptions) setUrlOptions(true);
- }
-
- // is this just for one call?
- if (uri.hasOwnProperty('call-id')) {
- const _id = uri['call-id'];
- setLoadCallId(_id);
- setAutoPlay(false);
- if (!urlOptions) setUrlOptions(true);
- }
-
- // is there a Filter set?
- if ((uri.hasOwnProperty('filter-code')) && (uri.hasOwnProperty('filter-type'))) {
- if (!urlOptions) setUrlOptions(true);
-
- // The Filter is a group
- if (uri['filter-type'] === "group") {
- filter.filterType = 1;
- filter.filterGroupId = uri["filter-code"];
- }
-
- // The Filter is talkgroups
- if (uri['filter-type'] === 'talkgroup') {
- const tg = uri["filter-code"].split(',').map(Number);
- filter.filterType = 2;
- filter.filterTalkgroups = tg;
- }
- }
-
- dispatch(setFilter(filter));
- }
-
useEffect(() => {
if (loadNewerInView && callsData && (callsData.ids.length > 0)) {
dispatch(getNewerCalls({}));
@@ -318,190 +120,32 @@ function CallPlayer(props) {
}, [loadOlderInView]);
useEffect(() => {
- if ( loadCallId && callsData) {
- const call = callsData.entities[loadCallId];
+ if ( selectCallId && callsData && !currentCall) {
+ const call = callsData.entities[selectCallId];
if (call) {
setCurrentCall(call);
}
}
- }, [callsData])
-
- useLayoutEffect( () => {
- const scrollAmount = parseInt(positionRef.current.clientHeight) - parseInt(pageYOffset.current);
- if (scrollAmount > 0) {
- console.log("useLayoutEffect for callsData - ref: " + pageYOffset.current + " current: " + positionRef.current.clientHeight + " Scroll Amount: " + scrollAmount)
- window.scrollBy(0, scrollAmount);
- }
- }, [callsData])
-
-/*
- useEffect(() => {
-
- }, [callsData]);
-*/
- useEffect(() => {
- setStateFromUri();
- return () => {
- 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(() => {
- dispatch(getCalls({}));
- if (live) {
- startSocket();
- }
- }, [shortName, filterGroupId, filterTalkgroups, filterType, filterDate, filterStarred])
-
-
- // Update the Browser URI when any relevant values change
- useEffect(() => {
- updateUri();
- }, [filterGroupId, filterTalkgroups, filterType, filterDate, filterStarred, loadCallId])
-
-
- useEffect(() => {
- if (!urlOptions && groupsData && (groupsData.length > 0)) {
- setGroupVisible(true);
- }
- }, [groupsData])
+ }, [selectCallId, callsData])
- 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;
- }
- const callDate = new Date(currentCall.time);
- var search = ""
- switch (filterType) {
-
- case 1:
- search = `filter-type=group&filter-code=${filterGroupId}&`;
- break;
- case 2:
- search = `filter-type=talkgroup&filter-code=${filterTalkgroups}&`;
- break;
- default:
- case 0:
- break;
-
- }
- 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 (
-
-
-
-
-
-
-
- Home
- Systems
- About
-
-
-
-
+
-
-
-
+
-
+
diff --git a/frontend/src/Call/Calls.js b/frontend/src/Call/Calls.js
new file mode 100644
index 0000000..9ad7793
--- /dev/null
+++ b/frontend/src/Call/Calls.js
@@ -0,0 +1,408 @@
+import React, { useEffect, useLayoutEffect, useState, useRef } from "react";
+import { Link, useLocation, useParams, useNavigate } from 'react-router-dom';
+
+import FilterModal from "./components/FilterModal";
+import GroupModal from "./components/GroupModal";
+
+import CalendarModal from "./components/CalendarModal";
+import CallPlayer from "./CallPlayer";
+
+import { useSelector, useDispatch } from 'react-redux'
+import { setLive, setFilter,setDateFilter } from "../features/callPlayer/callPlayerSlice";
+import { getCalls, getOlderCalls, getNewerCalls, addCall } from "../features/calls/callsSlice";
+import { useGetGroupsQuery, useGetTalkgroupsQuery } from '../features/api/apiSlice'
+import { useInView } from 'react-intersection-observer';
+import {
+ Container,
+ Label,
+ Rail,
+ Sticky,
+ Menu,
+ Icon,
+ Sidebar
+} from "semantic-ui-react";
+import "./CallPlayer.css";
+import queryString from '../query-string';
+import io from 'socket.io-client';
+
+
+
+
+const socket = io(process.env.REACT_APP_BACKEND_SERVER);
+
+
+// ----------------------------------------------------
+function Calls(props) {
+
+ const { shortName } = useParams();
+
+ const { data: groupsData, isSuccess: isGroupsSuccess } = useGetGroupsQuery(shortName);
+ const { loading: callsLoading, data: callsData } = useSelector((state) => state.calls);
+ const { data: talkgroupsData, isSuccess: isTalkgroupsSuccess } = useGetTalkgroupsQuery(shortName);
+
+
+ const [autoPlay, setAutoPlay] = useState(true);
+ const [currentCall, setCurrentCall] = 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 [selectCallId, setSelectCallId] = useState(false);
+
+ const navigate = useNavigate();
+ const dispatch = useDispatch();
+ const positionRef = useRef(); // lets us get the Y Scroll offset for the Call List
+ const pageYOffset = useRef(); // Store the current Scroll Offset in a way that guarantees the latest value is available when Call Data is updated
+ const shouldPlayAddCallRef = useRef(); // we need to do this to make the current value of isPlaying available in the socket message callback
+ shouldPlayAddCallRef.current = (!isPlaying && autoPlay)?true: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;
+
+ let currentCallId = false;
+
+
+ if (currentCall) {
+ currentCallId = currentCall._id;
+ }
+
+
+ const handlePusherClick = () => {
+ if (sidebarOpened) setSidebarOpened(false);
+ }
+
+ const handleSidebarToggle = () => setSidebarOpened(!sidebarOpened);
+ const handleFilterToggle = () => setFilterVisible(!filterVisible);
+ const handleCalendarToggle = () => setCalendarVisible(!calendarVisible);
+
+
+
+
+ const getFilterDescription = () => {
+
+ let filter = { type: 'all', code: "", filterStarred: false };
+
+ switch (filterType) {
+ case 1:
+ filter.type = "group";
+ filter.code = filterGroupId
+ break;
+ case 2:
+ filter.type = "talkgroup";
+ filter.code = filterTalkgroups
+ break;
+ default:
+ case 0:
+ filter.type = "all";
+ filter.code = ""
+ }
+ filter.filterStarred = filterStarred
+ return filter;
+ }
+
+
+ const handleSocketMessage = (data) => {
+ const message = JSON.parse(data)
+ switch (message.type) {
+ case 'calls':
+
+ pageYOffset.current = positionRef.current.clientHeight;
+
+ setSelectCallId(message._id);
+ dispatch(addCall(message));
+
+ console.log("Got: " + message._id);
+ break
+ default:
+ break
+ }
+ }
+
+ const startSocket = () => {
+ const filter = getFilterDescription();
+
+ socket.emit("start", {
+ filterCode: filter.code,
+ filterType: filter.type,
+ filterName: "OpenMHz",
+ filterStarred: filter.starred,
+ shortName: shortName
+ });
+ }
+ const stopSocket = () => {
+ socket.emit("stop");
+ }
+
+ const updateUri = () => {
+ let search = "?"
+ switch (filterType) {
+
+ case 1:
+ search = search + `filter-type=group&filter-code=${filterGroupId}`;
+ break;
+ case 2:
+ search = search + `filter-type=talkgroup&filter-code=${filterTalkgroups}`;
+ break;
+ default:
+ case 0:
+ break;
+
+ }
+
+ if (filterDate) {
+ if (search.length !== 1) {
+ search = search + '&';
+ }
+ search = search + `time=${filterDate}`;
+ }
+
+ if (filterStarred) {
+ if (search.length !== 1) {
+ search = search + '&';
+ }
+ search = search + `starred=true`;
+ }
+ navigate(pathname + search, { replace: true });
+
+ }
+
+ const handleLiveToggle = (currentlyLive) => {
+ if (!live) {
+ dispatch(setDateFilter(false));
+ dispatch(setLive(true));
+ setCurrentCall(false);
+ dispatch(getCalls({}));
+
+ startSocket();
+ }
+ }
+
+ const handleCalendarClose = (didUpdate) => {
+ setCalendarVisible(!calendarVisible);
+
+ if (didUpdate) {
+ dispatch(setLive(false));
+ setCurrentCall(false);
+ stopSocket();
+ }
+ }
+
+ const handleGroupClose = (didUpdate) => {
+ setGroupVisible(!groupVisible);
+ }
+
+ const handleFilterClose = (didUpdate) => {
+ setFilterVisible(!filterVisible);
+
+ if (didUpdate) {
+ setCurrentCall(false);
+ }
+ }
+
+
+ const setStateFromUri = async () => {
+ let filter = {
+ filterDate: false,
+ filterType: 0, // this is "all"
+ filterTalkgroups: [],
+ filterGroupId: false,
+ filterStarred: false,
+ live: true,
+ shortName: shortName
+ };
+
+ // is there a star filter?
+ if (uri.hasOwnProperty('starred')) {
+ const starred = uri['starred'];
+ filter.filterStarred = starred === 'true' ? true : false;
+ if (!urlOptions) setUrlOptions(true);
+ }
+
+ // is there a time based filter?
+ if (uri.hasOwnProperty('time')) {
+ const date = new Date(parseInt(uri['time']));
+ filter.filterDate = date.getTime();
+ filter.live = false;
+ if (!urlOptions) setUrlOptions(true);
+ }
+
+ // is this just for one call?
+ if (uri.hasOwnProperty('call-id')) {
+ const _id = uri['call-id'];
+ setSelectCallId(_id);
+ setAutoPlay(false);
+ if (!urlOptions) setUrlOptions(true);
+ }
+
+ // is there a Filter set?
+ if ((uri.hasOwnProperty('filter-code')) && (uri.hasOwnProperty('filter-type'))) {
+ if (!urlOptions) setUrlOptions(true);
+
+ // The Filter is a group
+ if (uri['filter-type'] === "group") {
+ filter.filterType = 1;
+ filter.filterGroupId = uri["filter-code"];
+ }
+
+ // The Filter is talkgroups
+ if (uri['filter-type'] === 'talkgroup') {
+ const tg = uri["filter-code"].split(',').map(Number);
+ filter.filterType = 2;
+ filter.filterTalkgroups = tg;
+ }
+ }
+
+ dispatch(setFilter(filter));
+ }
+
+
+
+
+
+ useEffect(() => {
+ setStateFromUri();
+ return () => {
+ 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(() => {
+ dispatch(getCalls({}));
+ if (live) {
+ startSocket();
+ }
+ }, [shortName, filterGroupId, filterTalkgroups, filterType, filterDate, filterStarred])
+
+
+ // Update the Browser URI when any relevant values change
+ useEffect(() => {
+ updateUri();
+ }, [filterGroupId, filterTalkgroups, filterType, filterDate, filterStarred, selectCallId])
+
+/*
+ useEffect(() => {
+ if (!urlOptions && groupsData && (groupsData.length > 0)) {
+ setGroupVisible(true);
+ }
+ }, [groupsData])*/
+
+ useLayoutEffect( () => {
+ const scrollAmount = parseInt(positionRef.current.clientHeight) - parseInt(pageYOffset.current);
+ if (scrollAmount > 0) {
+ console.log("useLayoutEffect for callsData - ref: " + pageYOffset.current + " current: " + positionRef.current.clientHeight + " Scroll Amount: " + scrollAmount)
+ window.scrollBy(0, scrollAmount);
+ }
+ }, [callsData])
+
+
+ let archiveLabel = "";
+ if (filterDate) {
+ const filterDateObj = new Date(filterDate);
+ archiveLabel = filterDateObj.toLocaleDateString() + " " + filterDateObj.toLocaleTimeString()
+ }
+
+
+
+ const archive = process.env.REACT_APP_ARCHIVE_DAYS
+
+ let filterLabel = "All"
+ switch (filterType) {
+ case 1:
+ filterLabel = "Group"
+ break;
+
+ case 2:
+ filterLabel = "Talkgroups"
+ break;
+ default:
+ case 0:
+ filterLabel = "All"
+ }
+
+ return (
+
+
+
+
+
+
+
+
+ Home
+ Systems
+ About
+
+
+
+
+
+
+ );
+}
+
+
+export default Calls;
diff --git a/frontend/src/Call/CalendarModal.css b/frontend/src/Call/components/CalendarModal.css
similarity index 100%
rename from frontend/src/Call/CalendarModal.css
rename to frontend/src/Call/components/CalendarModal.css
diff --git a/frontend/src/Call/CalendarModal.js b/frontend/src/Call/components/CalendarModal.js
similarity index 95%
rename from frontend/src/Call/CalendarModal.js
rename to frontend/src/Call/components/CalendarModal.js
index 76322c2..7f51c23 100644
--- a/frontend/src/Call/CalendarModal.js
+++ b/frontend/src/Call/components/CalendarModal.js
@@ -5,7 +5,7 @@ import {
Icon
} from "semantic-ui-react";
import "./CalendarModal.css";
-import { setDateFilter } from "../features/callPlayer/callPlayerSlice";
+import { setDateFilter } from "../../features/callPlayer/callPlayerSlice";
import DatePicker from 'react-datepicker';
import { useDispatch } from 'react-redux'
import { subDays } from 'date-fns'
diff --git a/frontend/src/Call/components/CallInfo.js b/frontend/src/Call/components/CallInfo.js
new file mode 100644
index 0000000..b6440f7
--- /dev/null
+++ b/frontend/src/Call/components/CallInfo.js
@@ -0,0 +1,96 @@
+import React from "react";
+import { useCallLink } from "./CallLinks";
+import { useGetGroupsQuery, useGetTalkgroupsQuery } from '../../features/api/apiSlice'
+import { Link, useLocation, useParams, useNavigate } from 'react-router-dom';
+import {
+ Header,
+ Divider,
+ List,
+ Segment,
+ Statistic,
+ Icon,
+ Menu
+} from "semantic-ui-react";
+
+// ----------------------------------------------------
+function CallInfo(props) {
+ const { shortName } = useParams();
+ const { data: talkgroupsData, isSuccess: isTalkgroupsSuccess } = useGetTalkgroupsQuery(shortName);
+
+ let srcList = "";
+ let callLength = "-";
+ let callFreq = "-";
+ let callDate = "-";
+ let callTime = "-";
+ let talkgroupNum = "-";
+ let header = "Call Info"
+
+ if (props.call) {
+ const currentCall = props.call;
+ if ((talkgroupsData) && talkgroupsData.talkgroups[currentCall.talkgroupNum]) {
+ header = talkgroupsData.talkgroups[currentCall.talkgroupNum].description;
+ }
+ const time = new Date(currentCall.time);
+ callTime = time.toLocaleTimeString();
+ callDate = time.toLocaleDateString();
+ if (currentCall.freq) {
+ const freq = currentCall.freq / 1000000;
+ callFreq = Math.round(freq * 1000) / 1000;
+ }
+
+
+ srcList = currentCall.srcList.map((source, index) => {source.src}[{source.pos}]);
+ callLength = currentCall.len;
+ talkgroupNum = currentCall.talkgroupNum;
+
+ }
+ const {callLink,callDownload,callTweet} = useCallLink(props.call)
+
+ return (
+
+
+
+
+ {srcList}
+
+
+
+ Seconds
+ {callLength}
+
+
+ Talkgroup
+ {talkgroupNum}
+
+
+
+
+
+
+ {callTime}
+
+
+
+
+
+ {callDate}
+
+
+
+
+
+ {callFreq} MHz
+
+
+
+
+
+
+ );
+}
+
+export default CallInfo;
diff --git a/frontend/src/Call/CallItem.js b/frontend/src/Call/components/CallItem.js
similarity index 94%
rename from frontend/src/Call/CallItem.js
rename to frontend/src/Call/components/CallItem.js
index 9b3c3fb..101a05f 100644
--- a/frontend/src/Call/CallItem.js
+++ b/frontend/src/Call/components/CallItem.js
@@ -6,7 +6,7 @@ import {
} from "semantic-ui-react";
-import { addStar, removeStar } from "../features/calls/callsSlice";
+import { addStar, removeStar } from "../../features/calls/callsSlice";
import { useDispatch } from 'react-redux'
const CallItem = (props) => {
@@ -31,9 +31,9 @@ const CallItem = (props) => {
}
}
- var rowSelected = {};
+ let rowSelected = {};
let starButton;
- var starClickable = {};
+ let starClickable = {};
const onDragStart = (event) => {
// It receives a DragEvent
@@ -78,7 +78,7 @@ const CallItem = (props) => {
inverted: "true"
}
}
- var talkgroup;
+ let talkgroup;
if ((typeof props.talkgroups == 'undefined') || (typeof props.talkgroups[call.talkgroupNum] == 'undefined')) {
talkgroup = call.talkgroupNum;
} else {
diff --git a/frontend/src/Call/components/CallLinks.js b/frontend/src/Call/components/CallLinks.js
new file mode 100644
index 0000000..23a5276
--- /dev/null
+++ b/frontend/src/Call/components/CallLinks.js
@@ -0,0 +1,36 @@
+import { useState, useEffect } from 'react';
+import { useSelector, useDispatch } from 'react-redux';
+
+export function useCallLink(currentCall) {
+ const filterType = useSelector((state) => state.callPlayer.filterType);
+ const filterGroupId = useSelector((state) => state.callPlayer.filterGroupId);
+ const filterTalkgroups = useSelector((state) => state.callPlayer.filterTalkgroups);
+ const shortName = useSelector((state) => state.callPlayer.shortName);
+ if (currentCall) {
+ let search = ""
+ const time = new Date(currentCall.time);
+ const callTime = time.toLocaleTimeString();
+ const callDate = time.toLocaleDateString();
+
+ switch (filterType) {
+
+ case 1:
+ search = `filter-type=group&filter-code=${filterGroupId}&`;
+ break;
+ case 2:
+ search = `filter-type=talkgroup&filter-code=${filterTalkgroups}&`;
+ break;
+ default:
+ case 0:
+ break;
+
+ }
+ const callLink = "/system/" + shortName + "?" + search + "call-id=" + currentCall._id + "&time=" + (time.getTime() + 1);
+ const callDownload = currentCall.url;
+ const callTweet = "https://twitter.com/intent/tweet?url=" + encodeURIComponent(document.location.origin + callLink) + "&via=" + encodeURIComponent("OpenMHz");
+
+ return { callLink, callDownload, callTweet }
+ } else {
+ return { callLink: "", callDownload: "", callTweet: "" }
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/Call/FilterModal.css b/frontend/src/Call/components/FilterModal.css
similarity index 100%
rename from frontend/src/Call/FilterModal.css
rename to frontend/src/Call/components/FilterModal.css
diff --git a/frontend/src/Call/FilterModal.js b/frontend/src/Call/components/FilterModal.js
similarity index 95%
rename from frontend/src/Call/FilterModal.js
rename to frontend/src/Call/components/FilterModal.js
index bf55082..8bbb7fa 100644
--- a/frontend/src/Call/FilterModal.js
+++ b/frontend/src/Call/components/FilterModal.js
@@ -1,6 +1,6 @@
import React, { useState } from "react";
-import { setGroupFilter, setTalkgroupFilter, setAllFilter, setStarredFilter } from "../features/callPlayer/callPlayerSlice";
-import { useGetGroupsQuery, useGetTalkgroupsQuery } from '../features/api/apiSlice'
+import { setGroupFilter, setTalkgroupFilter, setAllFilter, setStarredFilter } from "../../features/callPlayer/callPlayerSlice";
+import { useGetGroupsQuery, useGetTalkgroupsQuery } from '../../features/api/apiSlice'
import { useSelector, useDispatch } from 'react-redux'
import {
Modal,
@@ -64,12 +64,12 @@ function FilterModal(props) {
}
- var obj;
+
let talkgroupList = [];
if (isTalkgroupsSuccess) {
for (const num in talkgroupsData["talkgroups"]) {
const talkgroup = talkgroupsData["talkgroups"][num];
- obj = {
+ const obj = {
key: talkgroup.num,
value: talkgroup.num,
text: talkgroup.description
@@ -82,7 +82,7 @@ function FilterModal(props) {
if (isGroupsSuccess) {
for (const num in groupsData) {
const group = groupsData[num]
- obj = {
+ const obj = {
key: group._id,
value: group._id,
text: group.groupName
diff --git a/frontend/src/Call/components/GroupModal.js b/frontend/src/Call/components/GroupModal.js
new file mode 100644
index 0000000..9b9b450
--- /dev/null
+++ b/frontend/src/Call/components/GroupModal.js
@@ -0,0 +1,73 @@
+import React, { Component, useState } from "react";
+import { useGetGroupsQuery } from '../../features/api/apiSlice'
+import { setGroupFilter } from "../../features/callPlayer/callPlayerSlice";
+import { useSelector, useDispatch } from 'react-redux'
+
+import {
+ Modal,
+ Button,
+ Icon,
+ Dropdown
+} from "semantic-ui-react";
+import "./FilterModal.css";
+
+function GroupModal (props) {
+ const shortName = useSelector((state) => state.callPlayer.shortName);
+ const { data, isError, isLoading, isSuccess,error } = useGetGroupsQuery(props.shortName);
+ const [open, setOpen] = useState(false);
+ const [selectedGroup, setSelectedGroup] = useState(false);
+ const dispatch = useDispatch()
+ const onClose = props.onClose;
+
+ function handleDone(onClose) {
+
+ if (selectedGroup) {
+ dispatch(setGroupFilter(selectedGroup))
+ //dispatch({type: types.SET_GROUP_FILTER, groupId: selectedGroup })
+ onClose(true);
+ } else {
+ onClose(false);
+ }
+}
+
+
+ let groupOptions = []
+
+ if (isSuccess) {
+
+ for (const num in data) {
+ const group = data[num];
+ const obj = {
+ key: group._id,
+ value: group._id,
+ text: group.groupName
+ }
+ groupOptions.push(obj);
+ }
+}
+
+
+ return (
+
+ setOpen(false)} onOpen={() => setOpen(true)} size='tiny'>
+
+ Select a Group
+
+
+ Choose the type of calls you want to listen to
+ setSelectedGroup(data.value)} />
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default GroupModal;
diff --git a/frontend/src/Call/ListCalls.js b/frontend/src/Call/components/ListCalls.js
similarity index 96%
rename from frontend/src/Call/ListCalls.js
rename to frontend/src/Call/components/ListCalls.js
index ed11a25..3a6059d 100644
--- a/frontend/src/Call/ListCalls.js
+++ b/frontend/src/Call/components/ListCalls.js
@@ -5,7 +5,7 @@ import {
Table,
Ref
} from "semantic-ui-react";
-import "./CallPlayer.css";
+import "../CallPlayer.css";
// ----------------------------------------------------
const ListCalls = (props) => {
@@ -34,7 +34,7 @@ const ListCalls = (props) => {
- {callsData != false &&
+ {callsData &&
{
diff --git a/frontend/src/Call/MediaPlayer.js b/frontend/src/Call/components/MediaPlayer.js
similarity index 96%
rename from frontend/src/Call/MediaPlayer.js
rename to frontend/src/Call/components/MediaPlayer.js
index 0afcfe5..49e5a56 100644
--- a/frontend/src/Call/MediaPlayer.js
+++ b/frontend/src/Call/components/MediaPlayer.js
@@ -22,16 +22,16 @@ const MediaPlayer = (props) => {
const handlePlay = () => { setIsPlaying(true); parentHandlePlayPause(true); }
const playPause = () => { const audio = audioRef.current.audioEl.current; if (isPlaying) { audio.pause(); } else { audio.play(); } }
- var call = props.call;
+ const call = props.call;
useEffect(() => {
const audio = audioRef.current.audioEl.current;
- var onEnded = props.onEnded;
+ const onEnded = props.onEnded;
setSourceIndex(0);
if (call) {
audio.src = call.url;
- var playPromise = audio.play();
+ const playPromise = audio.play();
// In browsers that don’t yet support this functionality,
// playPromise won’t be defined.
diff --git a/frontend/src/Call/SupportModal.js b/frontend/src/Call/components/SupportModal.js
similarity index 100%
rename from frontend/src/Call/SupportModal.js
rename to frontend/src/Call/components/SupportModal.js
diff --git a/frontend/src/index.js b/frontend/src/index.js
index 34b44a9..a2cd078 100644
--- a/frontend/src/index.js
+++ b/frontend/src/index.js
@@ -17,7 +17,7 @@ import Main from "./Main/Main"
import ListSystems from "./System/ListSystems"
// Call
-import CallPlayer from "./Call/CallPlayer"
+import Calls from "./Call/Calls"
import AboutComponent from "./About/AboutComponent"
@@ -32,7 +32,7 @@ root.render(
} />
} />
- } />
+ } />
} />