From 6f50a7b9c8c8cb2c57eb0a06c7fdde43602b2102 Mon Sep 17 00:00:00 2001 From: Luke Berndt Date: Mon, 16 Jan 2023 21:16:13 -0500 Subject: [PATCH] fixed up the other windows --- frontend/src/About/AboutComponent.js | 77 ++++++------ frontend/src/Call/CalendarModalContainer.js | 28 ----- frontend/src/Call/CallPlayer.js | 11 +- frontend/src/Call/CallPlayerContainer.js | 69 ----------- frontend/src/Call/FilterModalContainer.js | 34 ------ frontend/src/Call/GroupModalContainer.js | 27 ----- frontend/src/Main/Main.js | 123 +++++++++++--------- frontend/src/Main/MainContainer.js | 16 --- frontend/src/System/ListSystems.js | 20 ++-- frontend/src/features/api/apiSlice.js | 23 +++- frontend/src/index.js | 8 +- 11 files changed, 141 insertions(+), 295 deletions(-) delete mode 100644 frontend/src/Call/CalendarModalContainer.js delete mode 100644 frontend/src/Call/CallPlayerContainer.js delete mode 100644 frontend/src/Call/FilterModalContainer.js delete mode 100644 frontend/src/Call/GroupModalContainer.js delete mode 100644 frontend/src/Main/MainContainer.js diff --git a/frontend/src/About/AboutComponent.js b/frontend/src/About/AboutComponent.js index 9a41605..afb6345 100644 --- a/frontend/src/About/AboutComponent.js +++ b/frontend/src/About/AboutComponent.js @@ -3,45 +3,42 @@ import { Link } from 'react-router-dom' import { Container, Header, Divider, Icon, Menu, Button } from "semantic-ui-react"; -class AboutComponent extends Component { +const AboutComponent = () => { + return ( +
+ + Home + Listen + + +
About
+ +

I wrote Trunk Recorder because I was curious + about what my local fire station was up to and I put together the original version of OpenMHz because I + figured other people might want to listen to the recordings too.

+

The latest version of this site makes it easy for other people running Trunk Recorder to share their recrodings. + I am hoping that making it easier to listen to what our local fire, police and EMS have to go through everyday will + lead to greater appreciation for all the work they do that goes largely unseen. I am personally amazed by the number + of medical runs the DC's Fire and EMS department has to cover every day, and the shocking number of them that are ODs.

+ +

Each system should have a 30 day archive. This is to help make sure things don't get overloaded and make sure I don't get a crazy bill + at the end of the month.

+

- Luke luke@robotastic.com

+ +
Open Source
+

Have changes you would like to suggest? Want to run your own server for your community? The source code for OpenMHz has been released:

+

Trunk Server

+
Support
+

If OpenMHz brings you joy, think about becoming a supporter! It will cover hosting costs and help keep me focused on development.

+ +

+ +
+
+ ); +} - render() { - return ( -
- - Home - Listen - - -
About
- -

I wrote Trunk Recorder because I was curious - about what my local fire station was up to and I put together the original version of OpenMHz because I - figured other people might want to listen to the recordings too.

-

The latest version of this site makes it easy for other people running Trunk Recorder to share their recrodings. - I am hoping that making it easier to listen to what our local fire, police and EMS have to go through everyday will - lead to greater appreciation for all the work they do that goes largely unseen. I am personally amazed by the number - of medical runs the DC's Fire and EMS department has to cover every day, and the shocking number of them that are ODs.

- -

Each system should have a 30 day archive. This is to help make sure things don't get overloaded and make sure I don't get a crazy bill - at the end of the month.

-

- Luke luke@robotastic.com

- -
Open Source
-

Have changes you would like to suggest? Want to run your own server for your community? The source code for OpenMHz has been released:

-

Trunk Server

-
Support
-

If OpenMHz brings you joy, think about becoming a supporter! It will cover hosting costs and help keep me focused on development.

- -

- -
-
- ); - } - } - - export default AboutComponent; \ No newline at end of file +export default AboutComponent; \ No newline at end of file diff --git a/frontend/src/Call/CalendarModalContainer.js b/frontend/src/Call/CalendarModalContainer.js deleted file mode 100644 index 4e30e1a..0000000 --- a/frontend/src/Call/CalendarModalContainer.js +++ /dev/null @@ -1,28 +0,0 @@ -import { connect } from "react-redux" -import * as callActionCreators from "./call-actions" -import { bindActionCreators } from 'redux' -import CalendarModal from "./CalendarModal" - -function mapStateToProps(state, props) { - return { - groups: state.group.items[props.shortName], - talkgroups: state.talkgroup.items[props.shortName], - talkgroupsIsWaiting: state.talkgroup.isWaiting, - groupsIsWaiting: state.group.isWaiting, - shortName: props.shortName, - activeTab: state.call.filterType, - selectedTalkgroups: state.call.filterTalkgroups - } -} - -function mapDispatchToProps(dispatch) { - return { - callActions: bindActionCreators(callActionCreators, dispatch) - } -} - - -export default connect( - mapStateToProps, - mapDispatchToProps -)(CalendarModal) diff --git a/frontend/src/Call/CallPlayer.js b/frontend/src/Call/CallPlayer.js index b687f63..b476b65 100644 --- a/frontend/src/Call/CallPlayer.js +++ b/frontend/src/Call/CallPlayer.js @@ -5,7 +5,7 @@ import MediaPlayer from "./MediaPlayer"; import FilterModal from "./FilterModal"; import GroupModal from "./GroupModal"; import SupportModal from "./SupportModal"; -import CalendarModal from "./CalendarModalContainer"; +import CalendarModal from "./CalendarModal"; import CallInfo from "./CallInfo"; import ListCalls from "./ListCalls"; import { useSelector, useDispatch } from 'react-redux' @@ -50,9 +50,7 @@ function CallPlayer(props) { const [autoPlay, setAutoPlay] = useState(true); - const [addCallScroll, setAddCallScroll] = useState(false); const [currentCall, setCurrentCall] = useState(false); - const [prevScrollHeight, setPrevScrollHeight] = useState(0); const [urlOptions, setUrlOptions] = useState(false); const [isPlaying, setIsPlaying] = useState(false); const [sidebarOpened, setSidebarOpened] = useState(false); @@ -155,13 +153,10 @@ function CallPlayer(props) { case 'calls': const ref = positionRef.current; pageYOffset.current = positionRef.current.clientHeight; - setPrevScrollHeight(positionRef.current.clientHeight); - console.log("Prior to setAddCallScroll, addCallScroll was: " + addCallScroll); - setAddCallScroll(true); + if (shouldPlayAddCallRef.current) { setCurrentCall(message); } - console.log("Prior to addCall, addCallScroll was: " + addCallScroll); dispatch(addCall(message)); console.log("Got: " + message._id); @@ -349,7 +344,7 @@ function CallPlayer(props) { useLayoutEffect( () => { const scrollAmount = parseInt(positionRef.current.clientHeight) - parseInt(pageYOffset.current); if (scrollAmount > 0) { - console.log("useLayoutEffect for callsData - state prevScrollHeight: " + prevScrollHeight + " ref: " + pageYOffset.current + " current: " + positionRef.current.clientHeight + " Scroll Amount: " + scrollAmount) + console.log("useLayoutEffect for callsData - ref: " + pageYOffset.current + " current: " + positionRef.current.clientHeight + " Scroll Amount: " + scrollAmount) window.scrollBy(0, scrollAmount); } }, [callsData]) diff --git a/frontend/src/Call/CallPlayerContainer.js b/frontend/src/Call/CallPlayerContainer.js deleted file mode 100644 index fb12af3..0000000 --- a/frontend/src/Call/CallPlayerContainer.js +++ /dev/null @@ -1,69 +0,0 @@ -import { connect } from "react-redux" -import * as callActionCreators from "./call-actions" -import * as talkgroupActionCreators from "../Talkgroups/talkgroup-actions" -import * as groupActionCreators from "../Group/group-actions" -import * as systemActionCreators from "../System/system-actions" -import { bindActionCreators } from 'redux' -import CallPlayer from "./CallPlayer" -import { - useLocation, - useNavigate, - useParams -} from "react-router-dom"; - -// glorious solution here: https://stackoverflow.com/questions/71097375/how-can-i-use-withrouter-in-react-router-v6-for-passing-props -function withRouter(Component) { - function ComponentWithRouterProp(props) { - let location = useLocation(); - let navigate = useNavigate(); - let params = useParams(); - return ( - - ); - } - - return ComponentWithRouterProp; -} - -function mapStateToProps(state, props) { - const shortName = props.router.params.shortName; - return { - callsById: state.call.byId, - callsAllIds: state.call.allIds, - oldestCallTime: state.call.oldestCallTime, - newestCallTime: state.call.newestCallTime, - live: state.call.live, - filterDate: state.call.filterDate, - filterType: state.call.filterType, - filterTalkgroups: state.call.filterTalkgroups, - filterGroupId: state.call.filterGroupId, - filterStarred: state.call.filterStarred, - system: state.system.items.find((item) => item.shortName === shortName), - groups: state.group.items[shortName], - talkgroups: state.talkgroup.items[shortName], - callsIsWaiting: state.call.isWaiting, - systemIsWaiting: state.system.isWaiting, - talkgroupsIsWaiting: state.talkgroup.isWaiting, - groupsIsWaiting: state.group.isWaiting, - location: props.router.location, - shortName: shortName - } -} - -function mapDispatchToProps(dispatch) { - return { - groupActions: bindActionCreators(groupActionCreators, dispatch), - systemActions: bindActionCreators(systemActionCreators, dispatch), - callActions: bindActionCreators(callActionCreators, dispatch), - talkgroupActions: bindActionCreators(talkgroupActionCreators, dispatch) - } -} - - -export default withRouter(connect( - mapStateToProps, - mapDispatchToProps -)(CallPlayer)) diff --git a/frontend/src/Call/FilterModalContainer.js b/frontend/src/Call/FilterModalContainer.js deleted file mode 100644 index 0181368..0000000 --- a/frontend/src/Call/FilterModalContainer.js +++ /dev/null @@ -1,34 +0,0 @@ -import { connect } from "react-redux" -import * as talkgroupActionCreators from "../Talkgroups/talkgroup-actions" -import * as groupActionCreators from "../Group/group-actions" -import * as callActionCreators from "./call-actions" -import { bindActionCreators } from 'redux' -import FilterModal from "./FilterModal" - -function mapStateToProps(state, props) { - return { - groups: state.group.items[props.shortName], - talkgroups: state.talkgroup.items[props.shortName], - talkgroupsIsWaiting: state.talkgroup.isWaiting, - groupsIsWaiting: state.group.isWaiting, - shortName: props.shortName, - activeTab: state.call.filterType, - selectedTalkgroups: state.call.filterTalkgroups, - selectedGroup: state.call.filterGroupId, - filterStarred: state.call.filterStarred - } -} - -function mapDispatchToProps(dispatch) { - return { - groupActions: bindActionCreators(groupActionCreators, dispatch), - talkgroupActions: bindActionCreators(talkgroupActionCreators, dispatch), - callActions: bindActionCreators(callActionCreators, dispatch) - } -} - - -export default connect( - mapStateToProps, - mapDispatchToProps -)(FilterModal) diff --git a/frontend/src/Call/GroupModalContainer.js b/frontend/src/Call/GroupModalContainer.js deleted file mode 100644 index b5109f0..0000000 --- a/frontend/src/Call/GroupModalContainer.js +++ /dev/null @@ -1,27 +0,0 @@ -import { connect } from "react-redux" -import * as groupActionCreators from "../Group/group-actions" -import * as callActionCreators from "./call-actions" -import { bindActionCreators } from 'redux' -import GroupModal from "./GroupModal" - -function mapStateToProps(state, props) { - return { - groups: state.group.items[props.shortName], - groupsIsWaiting: state.group.isWaiting, - shortName: props.shortName, - selectedGroup: state.call.filterGroupId - } -} - -function mapDispatchToProps(dispatch) { - return { - groupActions: bindActionCreators(groupActionCreators, dispatch), - callActions: bindActionCreators(callActionCreators, dispatch) - } -} - - -export default connect( - mapStateToProps, - mapDispatchToProps -)(GroupModal) diff --git a/frontend/src/Main/Main.js b/frontend/src/Main/Main.js index 8545836..dc1aa96 100644 --- a/frontend/src/Main/Main.js +++ b/frontend/src/Main/Main.js @@ -1,4 +1,4 @@ -import React, { Component } from "react"; +import React, { Component, useState, useEffect, useRef } from "react"; import { Link } from 'react-router-dom' import SystemCard from "../System/SystemCard"; import "./Main.css"; @@ -17,6 +17,9 @@ import { } from 'semantic-ui-react' +import { useSelector, useDispatch } from 'react-redux' +import { selectAllSystems, selectActiveSystems, useGetSystemsQuery } from "../features/api/apiSlice"; + /* Responsive component was removed from Semantic UI. This is discussed here: https://github.com/Semantic-Org/Semantic-UI-React/pull/4008 */ const AppMedia = createMedia({ @@ -80,15 +83,14 @@ General flow: - componentDidMount(): it will call fetchSystem() this will perform an HTTP request if Systems does not exist, and then add System to Props */ -class DesktopContainer extends Component { - state = {} +const DesktopContainer = (props) => { + const [fixed, setFixed] = useState(false); + const hideFixedMenu = () => setFixed(false) + const showFixedMenu = () => setFixed(true) - hideFixedMenu = () => this.setState({ fixed: false }) - showFixedMenu = () => this.setState({ fixed: true }) + + const { children } = props - render() { - const { children } = this.props - const { fixed } = this.state return ( @@ -128,26 +130,24 @@ class DesktopContainer extends Component { ) } -} + /* DesktopContainer.propTypes = { children: PropTypes.node, } */ -class MobileContainer extends Component { - state = {} +const MobileContainer = (props) => { - handlePusherClick = () => { - const { sidebarOpened } = this.state + const [sidebarOpened, setSidebarOpened] = useState(false); - if (sidebarOpened) this.setState({ sidebarOpened: false }) + const handlePusherClick = () => { + setSidebarOpened(!sidebarOpened) } - handleToggle = () => this.setState({ sidebarOpened: !this.state.sidebarOpened }) + const handleToggle = () => setSidebarOpened(!sidebarOpened) - render() { - const { children } = this.props - const { sidebarOpened } = this.state + + const { children } = props return ( @@ -162,7 +162,7 @@ class MobileContainer extends Component {
@@ -181,7 +181,7 @@ class MobileContainer extends Component { - + {process.env.REACT_APP_SITE_NAME} @@ -196,7 +196,6 @@ class MobileContainer extends Component { ) } -} /* MobileContainer.propTypes = { children: PropTypes.node, @@ -210,41 +209,62 @@ const ResponsiveContainer = ({ children }) => ( ) // ---------------------------------------------------- -class Main extends Component { - constructor(props) { - super(props); - this.advanceSystem = this.advanceSystem.bind(this); - this.state = { duration: 500, visible: true, currentSystem: 0} - } +const Main = (props) => { - - - handleChange = (e, { name, value }) => this.setState({ [name]: value }) - - handleVisibility = () => this.setState({ visible: !this.state.visible }) - - advanceSystem() { - var currentSystem = this.state.currentSystem + 1; - if (currentSystem > this.props.system.items.length) { - currentSystem = 0; - } - this.setState({ visible: !this.state.visible, currentSystem }); - } - - componentDidMount() { - this.props.fetchSystems(); - this.interval = setInterval(() => this.advanceSystem(), 3000); - } + const [visible, setVisible] = useState(true); + const [duration, setDuration] = useState(500); + const [currentSystem, setCurrentSystem] = useState(0); + const dispatch = useDispatch(); + const {data:systems, isSuccess} = useGetSystemsQuery(); //= selectAllSystems(); - componentWillUnmount() { - clearInterval(this.interval); + + + + function useInterval(callback, delay) { + const savedCallback = useRef(); + + // Remember the latest callback. + useEffect(() => { + savedCallback.current = callback; + }, [callback]); + + // Set up the interval. + useEffect(() => { + function tick() { + savedCallback.current(); + } + if (delay !== null) { + let id = setInterval(tick, delay); + return () => clearInterval(id); + } + }, [delay]); } + const handleVisibility = () => setVisible(!visible); + + const advanceSystem = () => { + if (isSuccess) { + let nextSystem = currentSystem + 1; + if (nextSystem > systems.systems.length) { + nextSystem = 0; + } + setCurrentSystem(nextSystem); + setVisible(!visible); + } + //this.setState({ visible: !this.state.visible, currentSystem }); + } + + useInterval( ()=>{ advanceSystem()}, 3000) + + + //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 -render() { - const system = this.props.system.items[this.state.currentSystem]; + let system = false; + if (isSuccess) { + system = systems.systems[currentSystem]; + } return ( <> @@ -254,9 +274,9 @@ render() { - { system && ( + { system && ( - this.props.changeUrl("/system/" + system.shortName)}/> + props.changeUrl("/system/" + system.shortName)}/> )} @@ -351,6 +371,5 @@ render() { ); } -} export default Main; diff --git a/frontend/src/Main/MainContainer.js b/frontend/src/Main/MainContainer.js deleted file mode 100644 index 8ba167c..0000000 --- a/frontend/src/Main/MainContainer.js +++ /dev/null @@ -1,16 +0,0 @@ -import { connect } from "react-redux" -import * as systemActions from "../System/system-actions" -import Main from "./Main" - -function mapStateToProps(state) { - return { - system: state.system - } -} - - - -export default connect( - mapStateToProps, - systemActions -)(Main) diff --git a/frontend/src/System/ListSystems.js b/frontend/src/System/ListSystems.js index f5f8cf0..7e01cbf 100644 --- a/frontend/src/System/ListSystems.js +++ b/frontend/src/System/ListSystems.js @@ -10,22 +10,15 @@ import { Divider } from "semantic-ui-react"; +import { selectAllSystems, selectActiveSystems, useGetSystemsQuery } from "../features/api/apiSlice"; // ---------------------------------------------------- -class ListSystems extends Component { - state = { - requestMessage: "", - } +const ListSystems = (props) => { + - componentDidMount() { - this.props.fetchSystems(); - } + const {data:systems, isSuccess} = useGetSystemsQuery(); -//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 - render() { - const systems = this.props.system.items; return (
@@ -35,7 +28,8 @@ class ListSystems extends Component {
Radio Systems
- {systems.map((system) => + + {isSuccess&&systems.systems.map((system) => system.active&& this.props.changeUrl("/system/" + system.shortName)}/> // this.props.changeUrl("/system/" + system.shortName)}/> )} @@ -44,6 +38,6 @@ class ListSystems extends Component {
); } -} + export default ListSystems; diff --git a/frontend/src/features/api/apiSlice.js b/frontend/src/features/api/apiSlice.js index 6101e9e..59c2425 100644 --- a/frontend/src/features/api/apiSlice.js +++ b/frontend/src/features/api/apiSlice.js @@ -1,13 +1,13 @@ // Import the RTK Query methods from the React-specific entry point import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' - +import { createSelector} from '@reduxjs/toolkit' // Define our single API slice object export const apiSlice = createApi({ // The cache reducer expects to be added at `state.api` (already default - this is optional) reducerPath: 'api', - + // All of our requests will have URLs starting with '/fakeApi' baseQuery: fetchBaseQuery({ baseUrl: process.env.REACT_APP_BACKEND_SERVER }), // The "endpoints" represent operations and requests for this server @@ -25,9 +25,24 @@ export const apiSlice = createApi({ // The URL for the request is '/fakeApi/posts' query: (shortName) => ({ url: `/${shortName}/talkgroups` }) }), - + }) }) +export const selectSystemsResult = apiSlice.endpoints.getSystems.select(); + +const emptySystems = [] + +export const selectAllSystems = createSelector( + selectSystemsResult, + systemsResult => systemsResult?.data ?? emptySystems +) + +export const selectActiveSystems = createSelector( + selectAllSystems, + (state, userId) => userId, + (systems, userId) => systems.find(system => system.active === true) +) + // Export the auto-generated hook for the `getPosts` query endpoint -export const { useGetGroupsQuery, useGetSystemsQuery, useGetTalkgroupsQuery, useGetCallsQuery } = apiSlice +export const { useGetGroupsQuery, useGetSystemsQuery, useGetTalkgroupsQuery } = apiSlice diff --git a/frontend/src/index.js b/frontend/src/index.js index e7ca077..34b44a9 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.js @@ -11,10 +11,10 @@ import 'semantic-ui-css/semantic.min.css' //import withTracker from './withTracker'; // Main -import MainContainer from "./Main/MainContainer" +import Main from "./Main/Main" // System -import ListSystemsContainer from "./System/ListSystemsContainer" +import ListSystems from "./System/ListSystems" // Call import CallPlayer from "./Call/CallPlayer" @@ -30,8 +30,8 @@ root.render( - } /> - } /> + } /> + } /> } /> } />