mirror of
https://github.com/openmhz/trunk-server.git
synced 2026-11-14 01:37:48 -05:00
113
frontend/src/Call/CallInfo.js
Normal file
113
frontend/src/Call/CallInfo.js
Normal file
@@ -0,0 +1,113 @@
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
Header,
|
||||
Divider,
|
||||
List,
|
||||
Segment,
|
||||
Statistic,
|
||||
Icon,
|
||||
Menu,
|
||||
Tab
|
||||
} from "semantic-ui-react";
|
||||
import PlaylistBuilder from "./PlaylistBuilder"
|
||||
// ----------------------------------------------------
|
||||
function CallInfo(props) {
|
||||
|
||||
|
||||
|
||||
let srcList = "";
|
||||
let callLength = "-";
|
||||
let callFreq = "-";
|
||||
let callDate = "-";
|
||||
let callTime = "-";
|
||||
let talkgroupNum = "-";
|
||||
let callDownload = "";
|
||||
let callTweet = "";
|
||||
if (props.call) {
|
||||
const currentCall = props.call;
|
||||
var time = new Date(currentCall.time);
|
||||
callTime = time.toLocaleTimeString();
|
||||
callDate = time.toLocaleDateString();
|
||||
if (currentCall.freq) {
|
||||
var freq = currentCall.freq / 1000000;
|
||||
callFreq = Math.round(freq * 1000) / 1000;
|
||||
}
|
||||
|
||||
srcList = currentCall.srcList.map((source, index) => <List.Item key={index}>{source.src}[{source.pos}]</List.Item>);
|
||||
callLength = currentCall.len;
|
||||
talkgroupNum = currentCall.talkgroupNum;
|
||||
callDownload = currentCall.url;
|
||||
callTweet = "https://twitter.com/intent/tweet?url=" + encodeURIComponent(document.location.origin + props.link) + "&via=" + encodeURIComponent("OpenMHz");
|
||||
}
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
const handleTabChange = (e, data) => setActiveTab(data.activeIndex);
|
||||
|
||||
|
||||
|
||||
const panes = [
|
||||
{
|
||||
menuItem: 'Call Info', render: () => {
|
||||
return (
|
||||
<div>
|
||||
<Tab.Pane attached='bottom'>
|
||||
<List bulleted horizontal link>
|
||||
{srcList}
|
||||
</List>
|
||||
<Divider />
|
||||
<Statistic size='small'>
|
||||
<Statistic.Label>Seconds</Statistic.Label>
|
||||
<Statistic.Value>{callLength}</Statistic.Value>
|
||||
</Statistic>
|
||||
<Statistic size='small'>
|
||||
<Statistic.Label>Talkgroup</Statistic.Label>
|
||||
<Statistic.Value>{talkgroupNum}</Statistic.Value>
|
||||
</Statistic>
|
||||
|
||||
<List divided verticalAlign='middle'>
|
||||
<List.Item>
|
||||
<Icon name="wait" />
|
||||
<List.Content>
|
||||
{callTime}
|
||||
</List.Content>
|
||||
</List.Item>
|
||||
<List.Item>
|
||||
<Icon name="calendar outline" />
|
||||
<List.Content>
|
||||
{callDate}
|
||||
</List.Content>
|
||||
</List.Item>
|
||||
<List.Item>
|
||||
<Icon name="cubes" />
|
||||
<List.Content>
|
||||
{callFreq} MHz
|
||||
</List.Content>
|
||||
</List.Item>
|
||||
</List>
|
||||
|
||||
</Tab.Pane>
|
||||
<Menu>
|
||||
<a href={callTweet}><Menu.Item name="tweet" ><Icon name='twitter' />Tweet</Menu.Item></a>
|
||||
<a href={callDownload}><Menu.Item name="download"><Icon name="download" />Download</Menu.Item></a>
|
||||
<a href={props.link}><Menu.Item name="link"><Icon name="at" />Link</Menu.Item></a>
|
||||
</Menu>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
menuItem: 'Playlist', render: () => {
|
||||
return (
|
||||
<PlaylistBuilder />
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
return (
|
||||
<div>
|
||||
<Tab menu={{ attached: 'top' }} panes={panes} defaultActiveIndex={activeTab} onTabChange={handleTabChange} />
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CallInfo;
|
||||
@@ -344,6 +344,7 @@ function Calls(props) {
|
||||
<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="/events"><Menu.Item link>Events</Menu.Item></Link>
|
||||
<Link to="/about"><Menu.Item link>About</Menu.Item></Link>
|
||||
</Sidebar>
|
||||
<Menu fixed="top">
|
||||
|
||||
146
frontend/src/Call/GroupModal.js
Normal file
146
frontend/src/Call/GroupModal.js
Normal file
@@ -0,0 +1,146 @@
|
||||
import React, { 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 { 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];
|
||||
var obj = {
|
||||
key: group._id,
|
||||
value: group._id,
|
||||
text: group.groupName
|
||||
}
|
||||
groupOptions.push(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
|
||||
<Modal open={props.open} onClose={() => setOpen(false)} onOpen={() => setOpen(true)} size='tiny'>
|
||||
|
||||
<Modal.Header>Select a Group</Modal.Header>
|
||||
<Modal.Content >
|
||||
<Modal.Description>
|
||||
<p>Choose the type of calls you want to listen to</p>
|
||||
<Dropdown placeholder='Group...' fluid selection options={groupOptions} name='selectedGroup' onChange={(e, data) => setSelectedGroup(data.value)} />
|
||||
|
||||
</Modal.Description>
|
||||
|
||||
</Modal.Content>
|
||||
<Modal.Actions>
|
||||
<Button onClick={()=> handleDone(onClose)} >
|
||||
<Icon name='headphones' /> Listen
|
||||
</Button>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
|
||||
)
|
||||
}
|
||||
/*
|
||||
class GroupModal extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.handleInputChange = this.handleInputChange.bind(this);
|
||||
this.handleDone = this.handleDone.bind(this);
|
||||
this.handleClose = this.handleClose.bind(this);
|
||||
|
||||
this.state = {
|
||||
open: false,
|
||||
selectedGroup: false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
handleInputChange = (e, { name, value }) => this.setState({ [name]: value });
|
||||
handleClose = () => this.props.onClose(false);
|
||||
|
||||
handleDone(event) {
|
||||
|
||||
if (this.state.selectedGroup) {
|
||||
this.props.callActions.setGroupFilter(this.state.selectedGroup);
|
||||
this.props.onClose(true);
|
||||
} else {
|
||||
this.props.onClose(false);
|
||||
}
|
||||
|
||||
}
|
||||
componentDidUpdate(prevProps) {
|
||||
|
||||
const filterChanged = (prevProps.selectedGroup !== this.props.selectedGroup);
|
||||
if (filterChanged) {
|
||||
this.setState({ selectedGroup: this.props.selectedGroup});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
|
||||
var groupList = [];
|
||||
if (this.props.groups) {
|
||||
for (const num in this.props.groups) {
|
||||
const group = this.props.groups[num];
|
||||
var obj = {
|
||||
key: group._id,
|
||||
value: group._id,
|
||||
text: group.groupName
|
||||
}
|
||||
groupList.push(obj);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
<Modal open={this.props.open} onClose={this.handleClose} size='tiny' >
|
||||
<Modal.Header>Select a Group</Modal.Header>
|
||||
<Modal.Content >
|
||||
<Modal.Description>
|
||||
<p>Choose the type of calls you want to listen to</p>
|
||||
<Dropdown placeholder='Group...' fluid selection options={groupList} name='selectedGroup' onChange={this.handleInputChange} />
|
||||
|
||||
</Modal.Description>
|
||||
|
||||
</Modal.Content>
|
||||
<Modal.Actions>
|
||||
<Button onClick={this.handleDone} >
|
||||
<Icon name='headphones' /> Listen
|
||||
</Button>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
|
||||
)
|
||||
}
|
||||
}*/
|
||||
|
||||
export default GroupModal;
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import { useCallLink } from "./CallLinks";
|
||||
import { useGetGroupsQuery, useGetTalkgroupsQuery } from '../../features/api/apiSlice'
|
||||
import { Link, useLocation, useParams, useNavigate } from 'react-router-dom';
|
||||
@@ -9,9 +9,11 @@ import {
|
||||
Segment,
|
||||
Statistic,
|
||||
Icon,
|
||||
Menu
|
||||
Menu,
|
||||
Tab
|
||||
} from "semantic-ui-react";
|
||||
|
||||
import PlaylistBuilder from "./PlaylistBuilder"
|
||||
import CallInfoPane from "./CallInfoPane"
|
||||
// ----------------------------------------------------
|
||||
function CallInfo(props) {
|
||||
const { shortName } = useParams();
|
||||
@@ -44,51 +46,35 @@ function CallInfo(props) {
|
||||
talkgroupNum = currentCall.talkgroupNum;
|
||||
|
||||
}
|
||||
const {callLink,callDownload,callTweet} = useCallLink(props.call)
|
||||
const { callLink, callDownload, callTweet } = useCallLink(props.call)
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
const handleTabChange = (e, data) => setActiveTab(data.activeIndex);
|
||||
|
||||
const panes = [
|
||||
{
|
||||
menuItem: { key: 'info', icon: 'info', content: 'Call Info' }, render: () => {
|
||||
return (
|
||||
|
||||
<Tab.Pane attached='bottom'>
|
||||
<CallInfoPane call={props.call} />
|
||||
</Tab.Pane>
|
||||
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
menuItem: { key: 'list', icon: 'list', content: 'Create Event' }, render: () => {
|
||||
return (
|
||||
<PlaylistBuilder />
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Segment padded attached>
|
||||
<Header as='h1'>{header}</Header>
|
||||
<List bulleted horizontal link>
|
||||
{srcList}
|
||||
</List>
|
||||
<Divider />
|
||||
<Statistic size='small'>
|
||||
<Statistic.Label>Seconds</Statistic.Label>
|
||||
<Statistic.Value>{callLength}</Statistic.Value>
|
||||
</Statistic>
|
||||
<Statistic size='small'>
|
||||
<Statistic.Label>Talkgroup</Statistic.Label>
|
||||
<Statistic.Value>{talkgroupNum}</Statistic.Value>
|
||||
</Statistic>
|
||||
|
||||
<List divided verticalAlign='middle'>
|
||||
<List.Item>
|
||||
<Icon name="wait" />
|
||||
<List.Content>
|
||||
{callTime}
|
||||
</List.Content>
|
||||
</List.Item>
|
||||
<List.Item>
|
||||
<Icon name="calendar outline" />
|
||||
<List.Content>
|
||||
{callDate}
|
||||
</List.Content>
|
||||
</List.Item>
|
||||
<List.Item>
|
||||
<Icon name="cubes" />
|
||||
<List.Content>
|
||||
{callFreq} MHz
|
||||
</List.Content>
|
||||
</List.Item>
|
||||
</List>
|
||||
</Segment>
|
||||
<Menu attached='bottom'>
|
||||
<a href={callTweet}><Menu.Item name="tweet" ><Icon name='twitter' />Tweet</Menu.Item></a>
|
||||
<a href={callDownload}><Menu.Item name="download"><Icon name="download" />Download</Menu.Item></a>
|
||||
<a href={callLink}><Menu.Item name="link"><Icon name="at" />Link</Menu.Item></a>
|
||||
</Menu>
|
||||
<Tab menu={{ attached: 'top', fluid: true, widths: 2 }} panes={panes} defaultActiveIndex={activeTab} onTabChange={handleTabChange} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
98
frontend/src/Call/components/CallInfoPane.js
Normal file
98
frontend/src/Call/components/CallInfoPane.js
Normal file
@@ -0,0 +1,98 @@
|
||||
import React, { useState } from "react";
|
||||
import { useCallLink } from "./CallLinks";
|
||||
import {skipToken} from '@reduxjs/toolkit/query'
|
||||
import { useGetGroupsQuery, useGetTalkgroupsQuery } from '../../features/api/apiSlice'
|
||||
import { Link, useLocation, useParams, useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
Header,
|
||||
Divider,
|
||||
List,
|
||||
Segment,
|
||||
Statistic,
|
||||
Icon,
|
||||
Menu,
|
||||
Tab
|
||||
} from "semantic-ui-react";
|
||||
import PlaylistBuilder from "./PlaylistBuilder"
|
||||
// ----------------------------------------------------
|
||||
function CallInfoPane(props) {
|
||||
|
||||
|
||||
let srcList = "";
|
||||
let callLength = "-";
|
||||
let callFreq = "-";
|
||||
let callDate = "-";
|
||||
let callTime = "-";
|
||||
let talkgroupNum = "-";
|
||||
let header = "Call Info"
|
||||
const currentCall = props.call?props.call:false;
|
||||
|
||||
|
||||
|
||||
const { data: talkgroupsData, isSuccess: isTalkgroupsSuccess } = useGetTalkgroupsQuery(currentCall?currentCall.shortName:skipToken);
|
||||
|
||||
if (currentCall) {
|
||||
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) => <List.Item key={index}>{source.src}[{source.pos}]</List.Item>);
|
||||
callLength = currentCall.len;
|
||||
talkgroupNum = currentCall.talkgroupNum;
|
||||
|
||||
}
|
||||
const { callLink, callDownload, callTweet } = useCallLink(props.call)
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header as='h1'>{header}</Header>
|
||||
<List bulleted horizontal link>
|
||||
{srcList}
|
||||
</List>
|
||||
<Divider />
|
||||
<Statistic size='small'>
|
||||
<Statistic.Label>Seconds</Statistic.Label>
|
||||
<Statistic.Value>{callLength}</Statistic.Value>
|
||||
</Statistic>
|
||||
<Statistic size='small'>
|
||||
<Statistic.Label>Talkgroup</Statistic.Label>
|
||||
<Statistic.Value>{talkgroupNum}</Statistic.Value>
|
||||
</Statistic>
|
||||
|
||||
<List divided verticalAlign='middle'>
|
||||
<List.Item>
|
||||
<Icon name="wait" />
|
||||
<List.Content>
|
||||
{callTime}
|
||||
</List.Content>
|
||||
</List.Item>
|
||||
<List.Item>
|
||||
<Icon name="calendar outline" />
|
||||
<List.Content>
|
||||
{callDate}
|
||||
</List.Content>
|
||||
</List.Item>
|
||||
<List.Item>
|
||||
<Icon name="cubes" />
|
||||
<List.Content>
|
||||
{callFreq} MHz
|
||||
</List.Content>
|
||||
</List.Item>
|
||||
</List>
|
||||
<Divider />
|
||||
<Menu secondary fluid widths={2}>
|
||||
<Menu.Item name="download" href={callDownload}><Icon name="download" />Download</Menu.Item>
|
||||
<Menu.Item name="link" href={callLink}><Icon name="at" />Link</Menu.Item>
|
||||
</Menu>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default CallInfoPane;
|
||||
@@ -7,16 +7,21 @@ import {
|
||||
|
||||
|
||||
import { addStar, removeStar } from "../../features/calls/callsSlice";
|
||||
|
||||
import { useDispatch } from 'react-redux'
|
||||
|
||||
const CallItem = (props) => {
|
||||
|
||||
const call = props.call;
|
||||
const shortName = props.shortName;
|
||||
const talkgroups = props.talkgroups;
|
||||
const activeCall = props.activeCall;
|
||||
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();
|
||||
@@ -34,6 +39,23 @@ const CallItem = (props) => {
|
||||
let rowSelected = {};
|
||||
let starButton;
|
||||
let starClickable = {};
|
||||
|
||||
const onDragStart = (event) => {
|
||||
// It receives a DragEvent
|
||||
// which inherits properties from
|
||||
// MouseEvent and Event
|
||||
// so we can access the element
|
||||
// through event.currentTarget
|
||||
|
||||
// Later, we'll save
|
||||
// in a hook variable
|
||||
// the item being dragged
|
||||
const callId = event.currentTarget.dataset.callid;
|
||||
event.dataTransfer.setData("call-id", callId);
|
||||
console.log("Dragging: " + callId);
|
||||
|
||||
}
|
||||
|
||||
if (!starClicked) {
|
||||
starClickable = { link: true };
|
||||
}
|
||||
@@ -62,20 +84,18 @@ const CallItem = (props) => {
|
||||
}
|
||||
}
|
||||
let talkgroup;
|
||||
if ((typeof props.talkgroups == 'undefined') || (typeof props.talkgroups[call.talkgroupNum] == 'undefined')) {
|
||||
if ((typeof talkgroups== 'undefined') || (typeof talkgroups.talkgroups[call.talkgroupNum] == 'undefined')) {
|
||||
talkgroup = call.talkgroupNum;
|
||||
} else {
|
||||
talkgroup = props.talkgroups[call.talkgroupNum].description;
|
||||
talkgroup = talkgroups.talkgroups[call.talkgroupNum].description;
|
||||
}
|
||||
return (
|
||||
<Table.Row onClick={(e) => props.onClick({ call: call }, e)} {...rowSelected}>
|
||||
<Table.Row draggable="true" onClick={(e) => props.onClick({ call: call }, e)} {...rowSelected} onDragStart={onDragStart} data-callid={call._id}>
|
||||
<Table.Cell> {call.len} </Table.Cell>
|
||||
<Table.Cell> {talkgroup} </Table.Cell>
|
||||
<Table.Cell> {time.toLocaleTimeString()} </Table.Cell>
|
||||
<Table.Cell onMouseEnter={() => setStarVisible(true)} onMouseLeave={() => setStarVisible(false)} onClick={handleStarClicked}>{starButton}</Table.Cell>
|
||||
</Table.Row>
|
||||
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { useParams } from 'react-router-dom';
|
||||
import CallItem from "./CallItem";
|
||||
import {
|
||||
Icon,
|
||||
@@ -6,11 +7,13 @@ import {
|
||||
Ref
|
||||
} from "semantic-ui-react";
|
||||
import "../CallPlayer.css";
|
||||
import { useGetTalkgroupsQuery } from '../../features/api/apiSlice'
|
||||
|
||||
// ----------------------------------------------------
|
||||
const ListCalls = (props) => {
|
||||
const activeCallRef = useRef();
|
||||
|
||||
const { shortName } = useParams();
|
||||
const { data: talkgroupsData, isSuccess: isTalkgroupsSuccess } = useGetTalkgroupsQuery(shortName);
|
||||
//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
|
||||
|
||||
@@ -42,9 +45,9 @@ const ListCalls = (props) => {
|
||||
{
|
||||
props.callsData.ids.map((callId, index) => {
|
||||
if (callId === props.activeCallId) {
|
||||
return (<Ref innerRef={activeCallRef} key={index} ><CallItem activeCall={true} call={props.callsData.entities[callId]} talkgroups={props.talkgroups} key={index} onClick={props.playCall}/></Ref>)
|
||||
return (<Ref innerRef={activeCallRef} key={index} ><CallItem activeCall={true} call={props.callsData.entities[callId]} talkgroups={talkgroupsData} key={index} onClick={props.playCall}/></Ref>)
|
||||
} else {
|
||||
return <CallItem activeCall={false} call={props.callsData.entities[callId]} talkgroups={props.talkgroups} key={index} onClick={props.playCall}/>
|
||||
return <CallItem activeCall={false} call={props.callsData.entities[callId]} talkgroups={talkgroupsData} key={index} onClick={props.playCall}/>
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
185
frontend/src/Call/components/PlaylistBuilder.js
Normal file
185
frontend/src/Call/components/PlaylistBuilder.js
Normal file
@@ -0,0 +1,185 @@
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import { useParams } from 'react-router-dom';
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
Header,
|
||||
Divider,
|
||||
List,
|
||||
ListItem,
|
||||
Segment,
|
||||
Statistic,
|
||||
Icon,
|
||||
Menu,
|
||||
Tab,
|
||||
Table,
|
||||
Modal,
|
||||
Button,
|
||||
Image,
|
||||
Form,
|
||||
Message
|
||||
} from "semantic-ui-react";
|
||||
import { useAddNewEventMutation, useGetTalkgroupsQuery } from '../../features/api/apiSlice'
|
||||
|
||||
function PlaylistBuilder(props) {
|
||||
const { shortName } = useParams();
|
||||
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 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.
|
||||
// Later, we'll read the position
|
||||
// of the item from event.currentTarget
|
||||
// and store the updated list state
|
||||
|
||||
// We need to prevent the default behavior
|
||||
// of this event, in order for the onDrop
|
||||
// event to fire.
|
||||
// It may sound weird, but the default is
|
||||
// to cancel out the drop.
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
|
||||
const onDrop = (event) => {
|
||||
// Here, we will:
|
||||
// - update the rendered list
|
||||
// - and reset the DnD state
|
||||
var callId = event.dataTransfer.getData("call-id");
|
||||
console.log("Dropping: " + callId);
|
||||
addCall(callsData.entities[callId])
|
||||
}
|
||||
let listItems = "";
|
||||
|
||||
listItems = playlist.map((call, index) => {
|
||||
let tgAlpha = call.talkgroupNum;
|
||||
if (talkgroupsData) {
|
||||
const talkgroup = talkgroupsData.talkgroups[call.talkgroupNum]
|
||||
tgAlpha = talkgroup.alpha?talkgroup.alpha:tgAlpha;
|
||||
}
|
||||
|
||||
const time = new Date(call.time);
|
||||
const callTime = time.toLocaleTimeString();
|
||||
const callDate = time.toLocaleDateString();
|
||||
|
||||
return ( <Table.Row key={index}>
|
||||
<Table.Cell>{call.len} </Table.Cell>
|
||||
<Table.Cell>{tgAlpha}</Table.Cell>
|
||||
<Table.Cell>{callTime}</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
})
|
||||
|
||||
const submitPlaylist = () => {
|
||||
setOpen(true)
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
console.log(title)
|
||||
setOpen(false)
|
||||
const callIds = playlist.map( (call) => call._id)
|
||||
const event = {
|
||||
title,
|
||||
description,
|
||||
callIds
|
||||
}
|
||||
addNewEvent(event)
|
||||
setTitle("")
|
||||
setDescription("")
|
||||
setPlaylist([])
|
||||
}
|
||||
|
||||
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>)
|
||||
}
|
||||
|
||||
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>
|
||||
</Message>
|
||||
<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>
|
||||
</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}>
|
||||
{content}
|
||||
</Tab.Pane>
|
||||
<Menu fluid widths={2}>
|
||||
<Menu.Item name="clear" onClick={() => setPlaylist([])}><Icon name='delete' />Clear</Menu.Item>
|
||||
<Menu.Item active name="submit" onClick={submitPlaylist}><Icon name="cloud upload" />Submit</Menu.Item>
|
||||
</Menu>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default PlaylistBuilder;
|
||||
Reference in New Issue
Block a user