From 020f00b8fcb4c45fb8def424fbb13a4116d6864a Mon Sep 17 00:00:00 2001 From: Luke Berndt Date: Tue, 10 Jan 2023 10:14:01 -0500 Subject: [PATCH] loading using an Async Thunk --- frontend/src/Call/CallPlayer.js | 12 ++- frontend/src/Call/ListCalls.js | 17 ++-- frontend/src/features/calls/callsSlice.js | 110 ++++++++++++++++++++-- frontend/src/redux-router/reducers.js | 3 +- 4 files changed, 123 insertions(+), 19 deletions(-) diff --git a/frontend/src/Call/CallPlayer.js b/frontend/src/Call/CallPlayer.js index 01f80d3..773b461 100644 --- a/frontend/src/Call/CallPlayer.js +++ b/frontend/src/Call/CallPlayer.js @@ -10,6 +10,7 @@ import CallInfo from "./CallInfo"; import ListCalls from "./ListCalls"; import { useSelector, useDispatch } from 'react-redux' import { setLive } from "../features/callPlayer/callPlayerSlice"; +import { getCalls} from "../features/calls/callsSlice"; import { useGetGroupsQuery, useGetTalkgroupsQuery } from '../features/api/apiSlice' import { selectAllCalls, useGetCallsQuery, callsAdapter } from "../features/calls/callsSlice"; import { @@ -37,10 +38,12 @@ function CallPlayer (props) { const { shortName } = useParams(); const { data:groupsData, isSuccess:isGroupsSuccess } = useGetGroupsQuery(shortName); - const { data:callsData, isSuccess:isCallsSuccess } = useGetCallsQuery({shortName}); + //const { data:callsData, isSuccess:isCallsSuccess } = useGetCallsQuery({shortName}); + const {loading, data: callsData} = useSelector((state) => state.calls); + //console.log(callsData); const { data:talkgroupsData, isSuccess:isTalkgroupsSuccess } = useGetTalkgroupsQuery(shortName); - const allCalls = callsData?callsData.ids.map( id => callsData.entities[id] ):[] + //const allCalls = callsData?callsData.ids.map( id => callsData.entities[id] ):[] const [requestMessage, setRequestMessage] = useState(""); const [callUrl, setCallUrl] = useState(""); const [autoPlay, setAutoPlay] = useState(true); @@ -383,6 +386,7 @@ const getFilter = () => { this.startSocket(shortName, filterType, filterCode, filter.filterStarred); }*/ dispatch(setShortName(shortName)); + dispatch(getCalls({shortName})); return () => { //this.endSocket(); }; @@ -594,8 +598,8 @@ const getFilter = () => { style={{ minHeight: '100vh' }} > - - + + diff --git a/frontend/src/Call/ListCalls.js b/frontend/src/Call/ListCalls.js index 57b22bc..f5f7c74 100644 --- a/frontend/src/Call/ListCalls.js +++ b/frontend/src/Call/ListCalls.js @@ -13,6 +13,7 @@ class ListCalls extends React.Component { //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 callsData = this.props.callsData; return ( @@ -24,20 +25,24 @@ class ListCalls extends React.Component { - + {callsData != false && + - {this.props.callsAllIds.map((callId, index) => { + { + this.props.callsData.ids.map((callId, index) => { if (callId === this.props.activeCallId) { - return () + return () } else { - return + return } }) - } + + } + }
- + ); } diff --git a/frontend/src/features/calls/callsSlice.js b/frontend/src/features/calls/callsSlice.js index 36822d6..5e197d9 100644 --- a/frontend/src/features/calls/callsSlice.js +++ b/frontend/src/features/calls/callsSlice.js @@ -1,9 +1,11 @@ import { createSlice, createEntityAdapter, - createSelector + createSelector, + createAsyncThunk } from '@reduxjs/toolkit' + /* import { apiSlice } from '../api/apiSlice' // in order for the initial fetch to happen this call needs to be made in index.js @@ -24,10 +26,6 @@ import { method: "GET", params: { filterType, filterCode }, }), - /*query: () => ({ - url: `/test/calls`, - method: "GET" - }),*/ transformResponse: responseData => { responseData = responseData.calls; return callsAdapter.setAll(initialState, responseData) @@ -55,9 +53,105 @@ const selectCallsData = createSelector( export const { selectAll: selectAllCalls, selectById: selectCallById } = callsAdapter.getSelectors(state => { return selectCallsData(state) ?? initialState }) +*/ +const now = new Date(); +export const callsAdapter = createEntityAdapter({ + selectId: (call) => call._id, + sortComparer: (a, b) => a.time.localeCompare(b.time), +}) + +const initialState = { + loading: false, + data: callsAdapter.getInitialState(), + oldestCallTime: now, + newestCallTime: now, + } + + function buildUrlParams(a) { + return Object.keys(a).map(function(k) { + return encodeURIComponent(k) + '=' + encodeURIComponent(a[k]) + }).join('&') + } + + function buildCallUrl(shortName,filterType=0,filterGroupId=false, filterTalkgroups=false,filterDate=false, date=false, direction=false,filterStarred=false) { + var params = {}; + var url = ""; + + + if ((typeof direction === 'string') && (typeof date === 'number')) { + url = url + '/' + direction; + params["time"] = date; + } else { + if (filterDate){ + url = url + '/older' + params["time"] = filterDate; + } + } + if (filterStarred) { + params["filter-starred"] = true; + } + switch(filterType) { + case 1: + params["filter-type"] = "group"; + params["filter-code"] = filterGroupId; + break; + case 2: + params["filter-type"] = "talkgroup"; + params["filter-code"] = filterTalkgroups; + break; + default: + case 0: + } /* -export const {selectAll: selectAllCalls} = callsAdapter.getSelectors((state) => { - return state.api} - );*/ + if (this.filterCode != "") { + params["filter-code"] = this.filterCode; + } + if (this.filterType == this.FilterType.Group) { + params["filter-type"] = "group"; + params["filter-name"] = this.filterName; + } + if (this.filterType == this.FilterType.Talkgroup) { + params["filter-type"] = "talkgroup"; + } + if (this.filterType == this.FilterType.Unit) { + params["filter-type"] = "unit"; + } + */ + // url = startUp.backend_server + "/" + startUp.shortName.toLowerCase() + "/calls" + url + '?' + buildUrlParams(params); + url = process.env.REACT_APP_BACKEND_SERVER + "/" + shortName + "/calls" + url + '?' + buildUrlParams(params); + console.log("Trying to fetch data from this url: " + url); + return url; + } +export const getCalls = createAsyncThunk( + 'calls/getCalls', + async({shortName,filterType=0,filterGroupId=false, filterTalkgroups=false, filterStarred=false }) => { + const url = buildCallUrl(shortName, filterType, filterGroupId,filterTalkgroups, filterStarred); + const res = await fetch(url).then( + (data) => data.json() + ) + return res; + }) + +export const callsSlice = createSlice({ + name: 'calls', + initialState, + reducers: {}, + extraReducers: { + [getCalls.pending]: (state) => { + state.loading = true; + }, + [getCalls.fulfilled]: (state, {payload}) => { + state.loading = false; + state.data = callsAdapter.setAll(state.data, payload.calls) + state.newestCallTime = new Date(payload.calls[0].time) + state.oldestCallTime = new Date(payloads.calls[payloads.calls.length-1].time) + }, + [getCalls.rejected]: (state) => { + state.loading = false; + } + } +}) + +export const callsReducer = callsSlice.reducer; diff --git a/frontend/src/redux-router/reducers.js b/frontend/src/redux-router/reducers.js index 4ef6dae..3b8bc7a 100644 --- a/frontend/src/redux-router/reducers.js +++ b/frontend/src/redux-router/reducers.js @@ -8,7 +8,7 @@ import groupReducer from "../Group/group-reducer" import callReducer from "../Call/call-reducer" import {apiSlice} from "../features/api/apiSlice" import callPlayerSlice from "../features/callPlayer/callPlayerSlice" - +import callsSlice, { callsReducer } from "../features/calls/callsSlice" export default (history) => combineReducers({ router: connectRouter(history), @@ -17,6 +17,7 @@ export default (history) => combineReducers({ group: groupReducer, callPlayer: callPlayerSlice, call: callReducer, + calls: callsReducer, [apiSlice.reducerPath]: apiSlice.reducer, }) \ No newline at end of file