mirror of
https://github.com/openmhz/trunk-server.git
synced 2026-11-11 00:07:30 -05:00
support for multiple systems in an Event
This commit is contained in:
@@ -4,9 +4,9 @@ import MediaPlayer from "./components/MediaPlayer";
|
||||
import SupportModal from "./components/SupportModal";
|
||||
import CallInfo from "./components/CallInfo";
|
||||
import ListCalls from "./components/ListCalls";
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import { getOlderCalls, getNewerCalls } from "../features/calls/callsSlice";
|
||||
import { useGetGroupsQuery, useGetTalkgroupsQuery } from '../features/api/apiSlice'
|
||||
import { useGetTalkgroupsQuery } from '../features/api/apiSlice'
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
import {
|
||||
Container,
|
||||
@@ -32,7 +32,6 @@ 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
|
||||
@@ -53,6 +52,7 @@ function CallPlayer(props) {
|
||||
const stickyRef = useRef(); // lets us get the Y Scroll offset for the Call List
|
||||
const positionRef = useRef(); // lets us get the Y Scroll offset for the Call List
|
||||
const shouldPlayAddCallRef = useRef(); // we need to do this to make the current value of isPlaying available in the socket message callback
|
||||
const live = useSelector((state) => state.callPlayer.live);
|
||||
shouldPlayAddCallRef.current = (!isPlaying && autoPlay)?true:false;
|
||||
|
||||
let currentCallId = false;
|
||||
@@ -92,7 +92,7 @@ function CallPlayer(props) {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (loadNewerInView && callsData && (callsData.ids.length > 0)) {
|
||||
if (loadNewerInView && !live && callsData && (callsData.ids.length > 0)) {
|
||||
dispatch(getNewerCalls({}));
|
||||
}
|
||||
}, [loadNewerInView]);
|
||||
|
||||
@@ -5,7 +5,7 @@ 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 { setLive, setFilter, setDateFilter } from "../features/callPlayer/callPlayerSlice";
|
||||
import { getCalls, addCall } from "../features/calls/callsSlice";
|
||||
import { useGetGroupsQuery, useGetTalkgroupsQuery } from '../features/api/apiSlice'
|
||||
|
||||
@@ -52,7 +52,7 @@ function Calls(props) {
|
||||
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;
|
||||
shouldPlayAddCallRef.current = (!isPlaying && autoPlay) ? true : false;
|
||||
|
||||
const filterType = useSelector((state) => state.callPlayer.filterType);
|
||||
const filterGroupId = useSelector((state) => state.callPlayer.filterGroupId);
|
||||
@@ -106,8 +106,9 @@ function Calls(props) {
|
||||
switch (message.type) {
|
||||
case 'calls':
|
||||
|
||||
pageYOffset.current = positionRef.current.clientHeight;
|
||||
|
||||
if (positionRef.current) {
|
||||
pageYOffset.current = positionRef.current.clientHeight;
|
||||
}
|
||||
setSelectCallId(message._id);
|
||||
dispatch(addCall(message));
|
||||
|
||||
@@ -273,7 +274,7 @@ function Calls(props) {
|
||||
}
|
||||
})
|
||||
|
||||
socket.on("new message", handleSocketMessage );
|
||||
socket.on("new message", handleSocketMessage);
|
||||
|
||||
return () => {
|
||||
socket.off('connect');
|
||||
@@ -295,15 +296,18 @@ function Calls(props) {
|
||||
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);
|
||||
useEffect(() => {
|
||||
pageYOffset.current = positionRef.current.clientHeight;
|
||||
}, [callsData])
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const scrollAmount = parseInt(pageYOffset.current) - parseInt(positionRef.current.clientHeight);
|
||||
if (scrollAmount > 0) {
|
||||
window.scrollBy(0, scrollAmount);
|
||||
}
|
||||
@@ -376,7 +380,7 @@ function Calls(props) {
|
||||
</Menu.Item>
|
||||
</Menu.Menu>
|
||||
</Menu>
|
||||
<CallPlayer callsData={callsData} selectCallId={selectCallId} />
|
||||
<CallPlayer callsData={callsData} selectCallId={selectCallId} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
Message
|
||||
} from "semantic-ui-react";
|
||||
import { useAddNewEventMutation, useGetTalkgroupsQuery } from '../../features/api/apiSlice'
|
||||
import { setPlaylist, addToPlaylist, removeFromPLaylist } from '../../features/callPlayer/callPlayerSlice';
|
||||
import PlaylistItem from "./PlaylistItem"
|
||||
|
||||
function PlaylistBuilder(props) {
|
||||
@@ -26,31 +27,17 @@ function PlaylistBuilder(props) {
|
||||
const { data: talkgroupsData, isSuccess: isTalkgroupsSuccess } = useGetTalkgroupsQuery(shortName);
|
||||
const [addNewEvent, { isLoading }] = useAddNewEventMutation()
|
||||
const { loading: callsLoading, data: callsData } = useSelector((state) => state.calls);
|
||||
const [playlist, setPlaylist] = useState([]);
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [title, setTitle] = useState("")
|
||||
const [description, setDescription] = useState("")
|
||||
const handleTitleChange = (e, { name, value }) => setTitle(value);
|
||||
const handleDescriptionChange = (e, { name, value }) => setDescription(value);
|
||||
const playlist = useSelector((state) => state.callPlayer.playlist);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
|
||||
const compareCalls = (a, b) => {
|
||||
const aTimestamp = new Date(a.time).getTime()
|
||||
const bTimestamp = new Date(b.time).getTime()
|
||||
if (aTimestamp > bTimestamp) {
|
||||
return -1
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
const addCall = (call) => {
|
||||
const found = playlist.find(c => c._id == call._id);
|
||||
if (!found) {
|
||||
playlist.push(call);
|
||||
setPlaylist([...playlist.sort(compareCalls)])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const onDragOver = (event) => {
|
||||
// It also receives a DragEvent.
|
||||
@@ -67,6 +54,9 @@ function PlaylistBuilder(props) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
const removeItem = (call) => {
|
||||
dispatch(removeFromPLaylist(call))
|
||||
}
|
||||
|
||||
const onDrop = (event) => {
|
||||
// Here, we will:
|
||||
@@ -74,18 +64,10 @@ function PlaylistBuilder(props) {
|
||||
// - and reset the DnD state
|
||||
var callId = event.dataTransfer.getData("call-id");
|
||||
console.log("Dropping: " + callId);
|
||||
addCall(callsData.entities[callId])
|
||||
dispatch(addToPlaylist(callsData.entities[callId]))
|
||||
}
|
||||
|
||||
const removeItem = (call) => {
|
||||
if (call) {
|
||||
const found = playlist.findIndex(c => c._id == call._id);
|
||||
if (found!=-1) {
|
||||
playlist.splice(found,1)
|
||||
setPlaylist([...playlist.sort(compareCalls)])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let listItems = "";
|
||||
|
||||
@@ -93,10 +75,12 @@ const removeItem = (call) => {
|
||||
let tgAlpha = call.talkgroupNum;
|
||||
if (talkgroupsData) {
|
||||
const talkgroup = talkgroupsData.talkgroups[call.talkgroupNum]
|
||||
tgAlpha = talkgroup.alpha?talkgroup.alpha:tgAlpha;
|
||||
if (talkgroup && talkgroup.alpha!=" ") {
|
||||
tgAlpha = talkgroup.alpha;
|
||||
}
|
||||
}
|
||||
|
||||
return ( <PlaylistItem call={call} tgAlpha={tgAlpha} index={index} removeItem={removeItem}/> )
|
||||
return (<PlaylistItem call={call} tgAlpha={tgAlpha} index={index} removeItem={removeItem} />)
|
||||
})
|
||||
|
||||
const submitPlaylist = () => {
|
||||
@@ -104,81 +88,80 @@ const removeItem = (call) => {
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
console.log(title)
|
||||
setOpen(false)
|
||||
const callIds = playlist.map( (call) => call._id)
|
||||
const callIds = playlist.map((call) => call._id)
|
||||
const event = {
|
||||
title,
|
||||
description,
|
||||
callIds
|
||||
}
|
||||
addNewEvent(event)
|
||||
setTitle("")
|
||||
setDescription("")
|
||||
setPlaylist([])
|
||||
addNewEvent(event);
|
||||
setTitle("");
|
||||
setDescription("");
|
||||
dispatch(setPlaylist([]));
|
||||
}
|
||||
|
||||
let content = (<Header as="h3" icon textAlign='center' style={{paddingTop: "3em"}}><Icon name='target' />Drag Calls Here</Header>)
|
||||
let content = (<Header as="h3" icon textAlign='center' style={{ paddingTop: "3em" }}><Icon name='target' />Drag Calls Here</Header>)
|
||||
if (playlist.length > 0) {
|
||||
content = (<Table basic="very">
|
||||
<Table.Body>
|
||||
{listItems}
|
||||
</Table.Body>
|
||||
</Table>)
|
||||
<Table.Body>
|
||||
{listItems}
|
||||
</Table.Body>
|
||||
</Table>)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
onClose={() => setOpen(false)}
|
||||
onOpen={() => setOpen(true)}
|
||||
open={open}
|
||||
>
|
||||
<Modal.Header>Submit an Event</Modal.Header>
|
||||
<Modal.Content>
|
||||
|
||||
<Modal.Description>
|
||||
<Message icon>
|
||||
<Icon name='warning sign' />
|
||||
<Message.Content>The Events feature is a work in progress! Things may break, change, or get deleted. Contact me with ideas or problems: luke@robotastic.com</Message.Content>
|
||||
<Modal
|
||||
onClose={() => setOpen(false)}
|
||||
onOpen={() => setOpen(true)}
|
||||
open={open}
|
||||
>
|
||||
<Modal.Header>Submit an Event</Modal.Header>
|
||||
<Modal.Content>
|
||||
|
||||
<Modal.Description>
|
||||
<Message icon>
|
||||
<Icon name='warning sign' />
|
||||
<Message.Content>The Events feature is a work in progress! Things may break, change, or get deleted. Contact me with ideas or problems: luke@robotastic.com</Message.Content>
|
||||
</Message>
|
||||
<Header>Event</Header>
|
||||
<Form>
|
||||
|
||||
<Form.Input
|
||||
name="title"
|
||||
value={title}
|
||||
label="Title"
|
||||
onChange={handleTitleChange}
|
||||
<Header>Event</Header>
|
||||
<Form>
|
||||
|
||||
<Form.Input
|
||||
name="title"
|
||||
value={title}
|
||||
label="Title"
|
||||
onChange={handleTitleChange}
|
||||
/>
|
||||
<Form.TextArea
|
||||
name="description"
|
||||
value={description}
|
||||
label="Description"
|
||||
placeholder='Please describe the event'
|
||||
onChange={handleDescriptionChange}
|
||||
<Form.TextArea
|
||||
name="description"
|
||||
value={description}
|
||||
label="Description"
|
||||
placeholder='Please describe the event'
|
||||
onChange={handleDescriptionChange}
|
||||
/>
|
||||
</Form>
|
||||
</Modal.Description>
|
||||
</Modal.Content>
|
||||
<Modal.Actions>
|
||||
<Button color='black' onClick={() => setOpen(false)}>
|
||||
Nope
|
||||
</Button>
|
||||
<Button
|
||||
content="Submit"
|
||||
labelPosition='right'
|
||||
icon='checkmark'
|
||||
onClick={handleSubmit}
|
||||
positive
|
||||
/>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
<Tab.Pane attached='bottom' onDragOver={onDragOver} onDrop={onDrop} style={{overflowY: "auto", height: 300}}>
|
||||
</Form>
|
||||
</Modal.Description>
|
||||
</Modal.Content>
|
||||
<Modal.Actions>
|
||||
<Button color='black' onClick={() => setOpen(false)}>
|
||||
Nope
|
||||
</Button>
|
||||
<Button
|
||||
content="Submit"
|
||||
labelPosition='right'
|
||||
icon='checkmark'
|
||||
onClick={handleSubmit}
|
||||
positive
|
||||
/>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
<Tab.Pane attached='bottom' onDragOver={onDragOver} onDrop={onDrop} style={{ overflowY: "auto", height: 300 }}>
|
||||
{content}
|
||||
</Tab.Pane>
|
||||
<Menu fluid widths={2}>
|
||||
<Menu.Item name="clear" onClick={() => setPlaylist([])}><Icon name='delete' />Clear</Menu.Item>
|
||||
<Menu.Item name="clear" onClick={() => dispatch(setPlaylist([]))}><Icon name='delete' />Clear</Menu.Item>
|
||||
<Menu.Item active name="submit" onClick={submitPlaylist}><Icon name="cloud upload" />Submit</Menu.Item>
|
||||
</Menu>
|
||||
</>
|
||||
|
||||
@@ -17,6 +17,16 @@ const initialState = {
|
||||
live: false
|
||||
}
|
||||
|
||||
const compareCalls = (a, b) => {
|
||||
const aTimestamp = new Date(a.time).getTime()
|
||||
const bTimestamp = new Date(b.time).getTime()
|
||||
if (aTimestamp > bTimestamp) {
|
||||
return -1
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
export const callPlayerSlice = createSlice({
|
||||
name: 'callPlayer',
|
||||
initialState,
|
||||
@@ -33,6 +43,23 @@ export const callPlayerSlice = createSlice({
|
||||
state.playlist = action.payload;
|
||||
}
|
||||
},
|
||||
removeFromPlaylist: (state, action) => {
|
||||
const call = action.payload;
|
||||
if (call) {
|
||||
const found = state.playlist.findIndex(c => c._id == call._id);
|
||||
if (found != -1) {
|
||||
state.playlist = state.playlist.splice(found, 1)
|
||||
}
|
||||
}
|
||||
},
|
||||
addToPlaylist: (state, action) => {
|
||||
const call = action.payload;
|
||||
const found = state.playlist.find(c => c._id == call._id);
|
||||
if (!found) {
|
||||
const newlist = [...state.playlist, call];
|
||||
state.playlist = newlist.sort(compareCalls);
|
||||
}
|
||||
},
|
||||
setFilter: (state,action) => {
|
||||
var filter={};
|
||||
state.live = !action.payload.live ? state.live : action.payload.live;
|
||||
@@ -75,7 +102,7 @@ export const callPlayerSlice = createSlice({
|
||||
})
|
||||
|
||||
// Action creators are generated for each case reducer function
|
||||
export const { setCurrentCallId, setCallTime, setFilter, setLive, setShortName, setDateFilter, setStarredFilter, setAllFilter, setGroupFilter, setTalkgroupFilter } = callPlayerSlice.actions
|
||||
export const { setCurrentCallId, setCallTime, setFilter, setLive, setPlaylist, removeFromPLaylist, addToPlaylist, setShortName, setDateFilter, setStarredFilter, setAllFilter, setGroupFilter, setTalkgroupFilter } = callPlayerSlice.actions
|
||||
|
||||
export default callPlayerSlice.reducer
|
||||
|
||||
|
||||
Reference in New Issue
Block a user