Events is functional!!!

Just need to clean some things up and test
This commit is contained in:
Luke Berndt
2023-01-22 21:56:53 -05:00
parent 1ab774ec8f
commit b23734c4a3
14 changed files with 506 additions and 29 deletions

View File

@@ -0,0 +1,133 @@
import React, { useEffect, useLayoutEffect, useState, useRef } from "react";
import { Link, useLocation, useParams, useNavigate } from 'react-router-dom';
import {skipToken} from '@reduxjs/toolkit/query'
import MediaPlayer from "../Call/components/MediaPlayer";
import SupportModal from "../Call/components/SupportModal";
import CallInfo from "../Call/components/CallInfo";
import ListEventCalls from "./ListEventCalls";
import { useSelector, useDispatch } from 'react-redux'
import {
Container,
Label,
Rail,
Sticky,
Menu,
Icon,
Sidebar
} from "semantic-ui-react";
import { useCallLink } from "../Call/components/CallLinks";
import "../Call/CallPlayer.css";
// ----------------------------------------------------
function EventPlayer(props) {
const eventData = props.eventData;
const selectCallId = props.selectCallId;
const [autoPlay, setAutoPlay] = useState(true);
const [currentCall, setCurrentCall] = useState(false);
const [isPlaying, setIsPlaying] = 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 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;
let currentCallId = false;
if (currentCall) {
currentCallId = currentCall._id;
}
const handlePlayPause = (playing) => {
setIsPlaying(playing);
}
const handleAutoPlay = (currentAutoPlay) => {
setAutoPlay(!currentAutoPlay);
}
const playCall = (data) => {
setCurrentCall(data.call);
setIsPlaying(true);
}
const callEnded = () => {
if (eventData) {
const currentIndex = eventData.calls.findIndex(call => call._id === currentCallId);
if (autoPlay && (currentIndex > 0)) {
const nextCall = eventData.calls[currentIndex - 1];
setCurrentCall(nextCall);
setIsPlaying(true);
} else {
setIsPlaying(false);
}
} else {
console.log("Somehow called, callEnded() but callsData was false");
}
}
useEffect(() => {
if ( selectCallId && eventData && !currentCall) {
const call = eventData.calls.find( (call) => call._id == selectCallId);
if (call) {
setCurrentCall(call);
}
}
}, [selectCallId, eventData])
return (
<div ref={positionRef}>
<Container className="main" >
<Sidebar.Pushable>
<Sidebar.Pusher
style={{ minHeight: '100vh' }}
>
<ListEventCalls eventData={eventData} activeCallId={isPlaying?currentCallId:false} playCall={playCall} />
</Sidebar.Pusher>
</Sidebar.Pushable>
<Rail position='right' className="desktop-only" >
<Sticky offset={60} context={positionRef}>
<CallInfo call={currentCall} />
</Sticky>
</Rail>
</Container>
<Menu fixed="bottom" compact inverted >
<Menu.Item active={autoPlay} onClick={() => handleAutoPlay(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 EventPlayer;

View File

@@ -0,0 +1,59 @@
import React, { useEffect, useRef } from "react";
import CallItem from "../Call/components/CallItem";
import {
Icon,
Table,
Ref
} from "semantic-ui-react";
import "../Call/CallPlayer.css";
// ----------------------------------------------------
const ListEventCalls = (props) => {
const activeCallRef = useRef();
//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
useEffect(() => {
if (activeCallRef.current) {
activeCallRef.current.scrollIntoView({
block: "center",
});
}
});
return (
<Table id="calls" unstackable >
<Table.Header >
<Table.Row>
<Table.HeaderCell>Len</Table.HeaderCell>
<Table.HeaderCell>Talkgroup</Table.HeaderCell>
<Table.HeaderCell>Time</Table.HeaderCell>
<Table.HeaderCell><Icon name='star' /></Table.HeaderCell>
</Table.Row>
</Table.Header>
{props.eventData &&
<Table.Body>
{ props.eventData.calls.map((call, index) => {
if (call._id === props.activeCallId) {
return (<Ref innerRef={activeCallRef} key={index} ><CallItem activeCall={true} call={call} key={index} onClick={props.playCall}/></Ref>)
} else {
return <CallItem activeCall={false} call={call} key={index} onClick={props.playCall}/>
}
})
}
</Table.Body>
}
</Table>
);
}
export default ListEventCalls;

View File

@@ -0,0 +1,63 @@
import React, { Component } from "react";
import { Link, useNavigate } from 'react-router-dom'
import {
Container,
Header,
Card,
Icon,
Menu,
Divider,
Table
} from "semantic-ui-react";
import NavBar from "../Common/NavBar"
import { useGetEventsQuery } from "../features/api/apiSlice";
// ----------------------------------------------------
const ListEvents = (props) => {
const dateRange = (start, end) => {
if (start.getYear() != end.getYear()) {
return start.toLocaleDateString('en-us', { weekday:"short", year:"numeric", month:"short", day:"numeric"}) + " " + start.toLocaleTimeString() + " - " + end.toLocaleDateString('en-us', { weekday:"short", year:"numeric", month:"short", day:"numeric"}) + " " + end.toLocaleTimeString();
} else if (start.getMonth() != end.getMonth()) {
return start.toLocaleDateString('en-us', { weekday:"short", month:"short", day:"numeric"}) + " " + start.toLocaleTimeString() + " - " + end.toLocaleDateString('en-us', { weekday:"short", month:"short", day:"numeric"}) + " " + end.toLocaleTimeString();
} else if (start.getDay() != end.getDay()) {
return start.toLocaleDateString('en-us', { weekday:"short", month:"short", day:"numeric"}) + " " + start.toLocaleTimeString() + " - " + end.toLocaleDateString('en-us', { weekday:"short", day:"numeric"}) + " " + end.toLocaleTimeString();
} else {
return start.toLocaleDateString('en-us', { weekday:"short", month:"short", day:"numeric"}) + " " + start.toLocaleTimeString() + " - " + end.toLocaleTimeString();
}
}
const {data:events, isSuccess} = useGetEventsQuery();
const navigate = useNavigate();
return (
<div>
<NavBar/>
<Container >
<Divider horizontal style={{paddingTop:"5em", paddingBottom:"2em"}}><Header as="h1">Events<Icon name='rss' /></Header></Divider>
<Table basic="very">
<Table.Body>
{isSuccess&&events.map((event, index) =>
<Table.Row key={index}>
<Table.Cell><Link to={"/events/"+event._id}><Header as='h3'>{event.title}</Header></Link></Table.Cell>
<Table.Cell>{event.description}</Table.Cell>
<Table.Cell>{event.numCalls} Calls</Table.Cell>
<Table.Cell>{dateRange(new Date(event.startTime),new Date(event.endTime))}</Table.Cell>
</Table.Row>
)}
</Table.Body>
</Table>
</Container>
</div>
);
}
export default ListEvents;

View File

@@ -0,0 +1,152 @@
import React, { useEffect, useLayoutEffect, useState, useRef } from "react";
import { Link, useLocation, useParams, useNavigate } from 'react-router-dom';
import EventPlayer from "./EventPlayer";
import { useSelector, useDispatch } from 'react-redux'
import { useGetEventQuery } from '../features/api/apiSlice'
import queryString from '../query-string';
import {
Container,
Label,
Menu,
Icon,
Sidebar,
Grid,
Statistic,
Header
} from "semantic-ui-react";
import "../Call/CallPlayer.css";
// ----------------------------------------------------
function ViewEvent(props) {
const { id } = useParams();
const { data: eventData, isSuccess: isEventSuccess } = useGetEventQuery(id);
const [autoPlay, setAutoPlay] = useState(true);
const [currentCall, setCurrentCall] = useState(false);
const [isPlaying, setIsPlaying] = useState(false);
const [sidebarOpened, setSidebarOpened] = useState(false);
const [selectCallId, setSelectCallId] = useState(false);
const navigate = useNavigate();
const dispatch = useDispatch();
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 setStateFromUri = async () => {
// is this just for one call?
if (uri.hasOwnProperty('call-id')) {
const _id = uri['call-id'];
setSelectCallId(_id);
}
}
const dateRange = (start, end) => {
if (start.getYear() != end.getYear()) {
return {"part1": start.toLocaleDateString('en-us', { weekday:"short", year:"numeric", month:"short", day:"numeric"}) + " " + start.toLocaleTimeString(), "part2": end.toLocaleDateString('en-us', { weekday:"short", year:"numeric", month:"short", day:"numeric"}) + " " + end.toLocaleTimeString()};
} else if (start.getMonth() != end.getMonth()) {
return {"part1": start.toLocaleDateString('en-us', { weekday:"short", month:"short", day:"numeric"}) + " " + start.toLocaleTimeString(), "part2": end.toLocaleDateString('en-us', { weekday:"short", month:"short", day:"numeric"}) + " " + end.toLocaleTimeString()};
} else if (start.getDay() != end.getDay()) {
return {"part1": start.toLocaleDateString('en-us', { weekday:"short", month:"short", day:"numeric"}) + " " + start.toLocaleTimeString(), "part2": end.toLocaleDateString('en-us', { weekday:"short", day:"numeric"}) + " " + end.toLocaleTimeString()};
} else {
return {"part1": start.toLocaleDateString('en-us', { weekday:"short", month:"short", day:"numeric"}) + " " + start.toLocaleTimeString(), "part2": end.toLocaleTimeString()};
}
}
let dates = {part1: "", part2: ""}
if (eventData) {
dates = dateRange(new Date(eventData.startTime),new Date(eventData.endTime))
}
/*
const dateRange = (start, end) => {
if (start.getYear() != end.getYear()) {
return start.toLocaleDateString('en-us', { weekday:"short", year:"numeric", month:"short", day:"numeric"}) + " " + start.toLocaleTimeString() + " - " + end.toLocaleDateString('en-us', { weekday:"short", year:"numeric", month:"short", day:"numeric"}) + " " + end.toLocaleTimeString();
} else if (start.getMonth() != end.getMonth()) {
return start.toLocaleDateString('en-us', { weekday:"short", month:"short", day:"numeric"}) + " " + start.toLocaleTimeString() + " - " + end.toLocaleDateString('en-us', { weekday:"short", month:"short", day:"numeric"}) + " " + end.toLocaleTimeString();
} else if (start.getDay() != end.getDay()) {
return start.toLocaleDateString('en-us', { weekday:"short", month:"short", day:"numeric"}) + " " + start.toLocaleTimeString() + " - " + end.toLocaleDateString('en-us', { weekday:"short", day:"numeric"}) + " " + end.toLocaleTimeString();
} else {
return start.toLocaleDateString('en-us', { weekday:"short", month:"short", day:"numeric"}) + " " + start.toLocaleTimeString() + " - " + end.toLocaleTimeString();
}
}
let dates = "";
if (eventData) {
dates = dateRange(new Date(eventData.startTime),new Date(eventData.endTime));
}*/
return (
<div >
<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="/events"><Menu.Item link>Events</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>
<Container className="desktop-only" fluid textAlign='left' style={{ fontSize: '1.5rem', paddingLeft: '0.5em', paddingTop: '.5em' }}>
{eventData && eventData.title}
</Container>
</Menu>
<Grid style={{ paddingTop: '4em' }}>
<Grid.Column mobile={0} tablet={0} computer={1} ></Grid.Column>
<Grid.Column mobile={16} tablet={8} computer={4}>
<Container text >
{eventData && eventData.description}
</Container>
</Grid.Column>
<Grid.Column mobile={8} tablet={8} computer={4}>
<Header as="h2">{dates.part1} → <br/>{dates.part2}</Header>
</Grid.Column>
<Grid.Column mobile={8} tablet={8} computer={2}>
<Statistic>
<Statistic.Value>{eventData.numCalls}</Statistic.Value>
<Statistic.Label>Calls</Statistic.Label>
</Statistic>
</Grid.Column>
<Grid.Column mobile={0} tablet={0} computer={5}>
</Grid.Column>
</Grid>
<EventPlayer eventData={eventData} selectCallId={selectCallId} />
</div>
);
}
export default ViewEvent;