This commit is contained in:
Luke Berndt
2023-01-29 22:03:35 -05:00
9 changed files with 88 additions and 47 deletions

View File

@@ -6,6 +6,7 @@ import CallInfo from "./components/CallInfo";
import ListCalls from "./components/ListCalls"; import ListCalls from "./components/ListCalls";
import { useSelector, useDispatch } from 'react-redux' import { useSelector, useDispatch } from 'react-redux'
import { useGetTalkgroupsQuery } from '../features/api/apiSlice' import { useGetTalkgroupsQuery } from '../features/api/apiSlice'
import { playedCall } from "../features/calls/callsSlice";
import { useInView } from 'react-intersection-observer'; import { useInView } from 'react-intersection-observer';
import { import {
Container, Container,
@@ -72,6 +73,7 @@ function CallPlayer(props) {
const playCall = (data) => { const playCall = (data) => {
setCurrentCall(data.call); setCurrentCall(data.call);
dispatch(playedCall(data.call._id));
setIsPlaying(true); setIsPlaying(true);
} }
@@ -83,6 +85,7 @@ function CallPlayer(props) {
const nextCall = callsData.entities[nextCallId]; const nextCall = callsData.entities[nextCallId];
setCurrentCall(nextCall); setCurrentCall(nextCall);
dispatch(playedCall(nextCall._id));
setIsPlaying(true); setIsPlaying(true);
} else { } else {
setIsPlaying(false); setIsPlaying(false);
@@ -93,7 +96,7 @@ function CallPlayer(props) {
} }
useEffect(() => { useEffect(() => {
if (loadNewerInView && callsData && (callsData.ids.length > 0)) { if (!live && loadNewerInView && callsData && (callsData.ids.length > 0)) {
handleNewer(); handleNewer();
} }
}, [loadNewerInView]); }, [loadNewerInView]);
@@ -115,7 +118,9 @@ function CallPlayer(props) {
if (selectCallId && callsData && !isPlaying && autoPlay) { if (selectCallId && callsData && !isPlaying && autoPlay) {
const call = callsData.entities[selectCallId]; const call = callsData.entities[selectCallId];
if (call) { if (call) {
setIsPlaying(true);
setCurrentCall(call); setCurrentCall(call);
dispatch(playedCall(call._id));
} }
} }
}, [selectCallId, callsData]) }, [selectCallId, callsData])

View File

@@ -7,8 +7,8 @@ import CallPlayer from "./CallPlayer";
import { useSelector, useDispatch } from 'react-redux' 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, getOlderCalls, getNewerCalls } from "../features/calls/callsSlice"; import { getCalls, addCall, getOlderCalls, getNewerCalls } from "../features/calls/callsSlice";
import { useGetGroupsQuery, useGetTalkgroupsQuery } from '../features/api/apiSlice' import { useGetGroupsQuery, useGetSystemsQuery, } from '../features/api/apiSlice'
import { selectSystem } from "../features/systems/systemsSlice";
import { import {
Container, Container,
Label, Label,
@@ -30,9 +30,10 @@ const socket = io(process.env.REACT_APP_BACKEND_SERVER);
function Calls(props) { function Calls(props) {
const { shortName } = useParams(); const { shortName } = useParams();
const { data: allSystems, isSuccess } = useGetSystemsQuery();
const { data: groupsData, isSuccess: isGroupsSuccess } = useGetGroupsQuery(shortName); const { data: groupsData, isSuccess: isGroupsSuccess } = useGetGroupsQuery(shortName);
const { loading: callsLoading, data: callsData } = useSelector((state) => state.calls); const { loading: callsLoading, data: callsData } = useSelector((state) => state.calls);
const [autoPlay, setAutoPlay] = useState(true); const [autoPlay, setAutoPlay] = useState(true);
const [currentCall, setCurrentCall] = useState(false); const [currentCall, setCurrentCall] = useState(false);
const [urlOptions, setUrlOptions] = useState(false); const [urlOptions, setUrlOptions] = useState(false);
@@ -61,12 +62,15 @@ function Calls(props) {
const pathname = useLocation().pathname; const pathname = useLocation().pathname;
let currentCallId = false; let currentCallId = false;
let system = false;
if (currentCall) { if (currentCall) {
currentCallId = currentCall._id; currentCallId = currentCall._id;
} }
if (allSystems) {
system = allSystems.systems.find( (system) => system.shortName === shortName)
}
const handlePusherClick = () => { const handlePusherClick = () => {
if (sidebarOpened) setSidebarOpened(false); if (sidebarOpened) setSidebarOpened(false);
@@ -210,8 +214,10 @@ useLayoutEffect(() => {
if (pageYOffset.current) { if (pageYOffset.current) {
const scrollAmount = parseInt(positionRef.current.clientHeight) - parseInt(pageYOffset.current.position); const scrollAmount = parseInt(positionRef.current.clientHeight) - parseInt(pageYOffset.current.position);
if (pageYOffset.current.direction == "top") { if (pageYOffset.current.direction == "top") {
window.scrollBy({left: 0, top: scrollAmount, behavior: "auto"}); window.scrollBy({left: 0, top: scrollAmount, behavior: "auto"});
pageYOffset.current = {direction: "bottom", position: positionRef.current.clientHeight}; // reset PageY to be the current height incase callsData changes for other reasons
} else { } else {
pageYOffset.current = {direction: "bottom", position: positionRef.current.clientHeight};
//window.scrollBy(0, -1 * scrollAmount); //window.scrollBy(0, -1 * scrollAmount);
} }
} }
@@ -381,7 +387,7 @@ useLayoutEffect(() => {
<Label horizontal={true} color="grey" className="desktop-only">{filterLabel}</Label> <Label horizontal={true} color="grey" className="desktop-only">{filterLabel}</Label>
</Menu.Item> </Menu.Item>
<Container className="desktop-only" textAlign='center' style={{ fontSize: '1.5rem', paddingLeft: '1em', paddingTop: '.5em' }}> <Container className="desktop-only" textAlign='center' style={{ fontSize: '1.5rem', paddingLeft: '1em', paddingTop: '.5em' }}>
{/*system && system.name*/} {system && system.name}
</Container> </Container>
<Menu.Menu position="right"> <Menu.Menu position="right">
<Menu.Item name='archive-btn' onClick={handleCalendarToggle} active={!live}> <Menu.Item name='archive-btn' onClick={handleCalendarToggle} active={!live}>

View File

@@ -89,11 +89,21 @@ const CallItem = (props) => {
} else { } else {
talkgroup = talkgroups.talkgroups[call.talkgroupNum].description; talkgroup = talkgroups.talkgroups[call.talkgroupNum].description;
} }
let playStatus = (<></>)
if (activeCall) {
playStatus = (<Icon name="play" size='small' color="green"/>)
} else if (!call.played) {
playStatus = (<Icon name="chevron right" size='small' disabled/>)
}
return ( return (
<Table.Row draggable="true" onClick={(e) => props.onClick({ call: call }, e)} {...rowSelected} onDragStart={onDragStart} data-callid={call._id}> <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>{playStatus}</Table.Cell>
<Table.Cell> {talkgroup} </Table.Cell> <Table.Cell>{call.len}</Table.Cell>
<Table.Cell> {time.toLocaleTimeString()} </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.Cell onMouseEnter={() => setStarVisible(true)} onMouseLeave={() => setStarVisible(false)} onClick={handleStarClicked}>{starButton}</Table.Cell>
</Table.Row> </Table.Row>
); );

View File

@@ -33,6 +33,7 @@ const ListCalls = (props) => {
<Table id="calls" unstackable > <Table id="calls" unstackable >
<Table.Header > <Table.Header >
<Table.Row> <Table.Row>
<Table.HeaderCell> </Table.HeaderCell>
<Table.HeaderCell>Len</Table.HeaderCell> <Table.HeaderCell>Len</Table.HeaderCell>
<Table.HeaderCell>Talkgroup</Table.HeaderCell> <Table.HeaderCell>Talkgroup</Table.HeaderCell>
<Table.HeaderCell>Time</Table.HeaderCell> <Table.HeaderCell>Time</Table.HeaderCell>

View File

@@ -18,9 +18,20 @@ const MediaPlayer = (props) => {
const [isPlaying, setIsPlaying] = useState(false); const [isPlaying, setIsPlaying] = useState(false);
const parentHandlePlayPause = props.onPlayPause const parentHandlePlayPause = props.onPlayPause
const handlePause = () => { setIsPlaying(false); parentHandlePlayPause(false); } const handlePause = () => { setIsPlaying(false); }
const handlePlay = () => { setIsPlaying(true); parentHandlePlayPause(true); } const handlePlay = () => { setIsPlaying(true); }
const playPause = () => { const audio = audioRef.current.audioEl.current; if (isPlaying) { audio.pause(); } else { audio.play(); } } const playPause = () => {
const audio = audioRef.current.audioEl.current;
if (isPlaying) {
setIsPlaying(false);
parentHandlePlayPause(false);
audio.pause();
} else {
setIsPlaying(true);
parentHandlePlayPause(true);
audio.play();
}
}
const call = props.call; const call = props.call;

View File

@@ -16,7 +16,7 @@ import {
return ( return (
<Menu fixed="top"> <Menu fixed="top">
<Link to="/"><Menu.Item link><Icon name='arrow left' /> Home</Menu.Item></Link> <Link to="/"><Menu.Item link><Icon name='arrow left' /> Home</Menu.Item></Link>
<Link to="/systems"><Menu.Item link>Listen</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="/events"><Menu.Item link>Events</Menu.Item></Link>
<Link to="/about"><Menu.Item link>About</Menu.Item></Link> <Link to="/about"><Menu.Item link>About</Menu.Item></Link>
</Menu> </Menu>

View File

@@ -52,33 +52,30 @@ const ListSystems = (props) => {
<div ref={contextRef}> <div ref={contextRef}>
<NavBar /> <NavBar />
<Container > <Container >
<Divider horizontal style={{ paddingTop: "5em", paddingBottom: "2em" }}><Header as="h1">Radio Systems<Icon name='rss' /></Header></Divider> <Divider horizontal style={{ paddingTop: "5em", paddingBottom: "2em" }}><Header as="h1">Radio Systems<Icon name='rss' /></Header></Divider>
<Grid centered columns={2}> <Grid centered columns={2}>
<Grid.Column width="15"> <Grid.Column width="15">
<List horizontal> <List horizontal>
{stateList} {stateList}
<List.Item> <List.Item>
<List.Content> <List.Content>
<List.Header><a href="#international">International</a></List.Header> <List.Header><a href="#international">International</a></List.Header>
</List.Content> </List.Content>
</List.Item> </List.Item>
</List> </List>
{systemsByState} {systemsByState}
{international} {international}
</Grid.Column>
</Grid.Column> <Grid.Column width="1" only='computer'>
<Grid.Column width="1"> <Sticky offset={60} context={contextRef}>
<Sticky offset={60} context={contextRef}> <Segment>
<Segment> <List >
<List > {stateList}
{stateList} </List>
</List> </Segment>
</Segment> </Sticky>
</Sticky> </Grid.Column>
</Grid.Column> </Grid>
</Grid>
</Container> </Container>
</div> </div>
); );

View File

@@ -65,8 +65,7 @@ const initialState = {
loading: false, loading: false,
data: callsAdapter.getInitialState(), data: callsAdapter.getInitialState(),
oldestCallTime: now, oldestCallTime: now,
newestCallTime: now, newestCallTime: now
adjustCallScroll: false
} }
function buildUrlParams(a) { function buildUrlParams(a) {
@@ -201,9 +200,12 @@ export const callsSlice = createSlice({
initialState, initialState,
reducers: { reducers: {
addCall: (state, action) => { addCall: (state, action) => {
state.data = callsAdapter.addOne(state.data, action.payload) const call = {...action.payload, played: false}
state.adjustCallScroll = true; state.data = callsAdapter.addOne(state.data, call)
}, },
playedCall: (state,action) => {
state.data = callsAdapter.updateOne(state.data,{id: action.payload, changes: {played: true}});
}
}, },
extraReducers: { extraReducers: {
[getCalls.pending]: (state) => { [getCalls.pending]: (state) => {
@@ -214,7 +216,8 @@ export const callsSlice = createSlice({
}, },
[getCalls.fulfilled]: (state, {payload}) => { [getCalls.fulfilled]: (state, {payload}) => {
state.loading = false; state.loading = false;
state.data = callsAdapter.setAll(state.data, payload.calls) const calls = payload.calls.map( (call) => ({...call, played: false}));
state.data = callsAdapter.setAll(state.data, calls)
if (state.data && (state.data.ids.length > 0)) { if (state.data && (state.data.ids.length > 0)) {
const first = state.data.ids[0] const first = state.data.ids[0]
const firstTime = state.data.entities[first].time; const firstTime = state.data.entities[first].time;
@@ -232,7 +235,8 @@ export const callsSlice = createSlice({
}, },
[getOlderCalls.fulfilled]: (state, {payload}) => { [getOlderCalls.fulfilled]: (state, {payload}) => {
state.loading = false; state.loading = false;
state.data = callsAdapter.addMany(state.data, payload.calls) const calls = payload.calls.map( (call) => ({...call, played: false}));
state.data = callsAdapter.addMany(state.data, calls)
if (state.data && (state.data.ids.length > 0)) { if (state.data && (state.data.ids.length > 0)) {
const first = state.data.ids[0] const first = state.data.ids[0]
const firstTime = state.data.entities[first].time; const firstTime = state.data.entities[first].time;
@@ -250,7 +254,8 @@ export const callsSlice = createSlice({
}, },
[getNewerCalls.fulfilled]: (state, {payload}) => { [getNewerCalls.fulfilled]: (state, {payload}) => {
state.loading = false; state.loading = false;
state.data = callsAdapter.addMany(state.data, payload.calls) const calls = payload.calls.map( (call) => ({...call, played: false}));
state.data = callsAdapter.addMany(state.data, calls)
if (state.data && (state.data.ids.length > 0)) { if (state.data && (state.data.ids.length > 0)) {
const first = state.data.ids[0] const first = state.data.ids[0]
const firstTime = state.data.entities[first].time; const firstTime = state.data.entities[first].time;
@@ -268,5 +273,5 @@ export const callsSlice = createSlice({
} }
} }
}) })
export const { addCall } = callsSlice.actions export const { addCall, playedCall } = callsSlice.actions
export const callsReducer = callsSlice.reducer; export const callsReducer = callsSlice.reducer;

View File

@@ -24,3 +24,9 @@ export const selectActiveSystems = createSelector(
(state) => null, (state) => null,
(systems) => systems.filter(system => system.active === true) (systems) => systems.filter(system => system.active === true)
) )
export const selectSystem = createSelector(
selectAllSystems,
(state) => null,
(systems, shortName) => systems.find(system => system.shortName === shortName)
)