mirror of
https://github.com/openmhz/trunk-server.git
synced 2026-11-12 08:47:40 -05:00
Gettign going
This commit is contained in:
@@ -1,15 +1,48 @@
|
||||
import React, { Component } from "react"
|
||||
import React, { Component } from "react"
|
||||
import NavigationContainer from "./NavigationContainer"
|
||||
import { Routes, Route } from 'react-router-dom';
|
||||
|
||||
class App extends Component {
|
||||
render() {
|
||||
return(
|
||||
import Restricted from "./Restricted"
|
||||
|
||||
import About from "../Components/About"
|
||||
import System from "../System/System"
|
||||
import ListSystems from "../System/ListSystems"
|
||||
import UpdateSystemContainer from "../System/UpdateSystemContainer"
|
||||
import CreateSystemContainer from "../System/CreateSystemContainer"
|
||||
|
||||
|
||||
const App = (params) => {
|
||||
const {store} = params;
|
||||
return (
|
||||
<div>
|
||||
<NavigationContainer />
|
||||
{this.props.children}
|
||||
<Routes>
|
||||
<Route path="/about" element={ <Restricted><About/></Restricted>} />
|
||||
<Route path="/system/:shortName" element={ <Restricted><System/></Restricted>} />
|
||||
<Route path="/update-system/:shortName" component={Restricted(UpdateSystemContainer, store)} />
|
||||
<Route path="/create-system" component={Restricted(CreateSystemContainer, store)} />
|
||||
<Route path="/list-systems" element={ <Restricted><ListSystems/></Restricted>} />
|
||||
<Route path="/" element={ <Restricted><ListSystems/></Restricted>} />
|
||||
<Route render={() => (<div>Miss</div>)} />
|
||||
</Routes>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
/*
|
||||
return (
|
||||
<div>
|
||||
<NavigationContainer />
|
||||
<Routes>
|
||||
<Route path="/about" element={<About />} component={Restricted(About, store)} />
|
||||
<Route path="/system/:shortName" component={Restricted(SystemContainer, store)} />
|
||||
<Route path="/update-system/:shortName" component={Restricted(UpdateSystemContainer, store)} />
|
||||
<Route path="/create-system" component={Restricted(CreateSystemContainer, store)} />
|
||||
<Route path="/list-systems" component={Restricted(ListSystemsContainer, store)} />
|
||||
<Route path="/" component={Restricted(ListSystemsContainer, store)} />
|
||||
<Route render={() => (<div>Miss</div>)} />
|
||||
</Routes>
|
||||
</div>
|
||||
)*/
|
||||
|
||||
};
|
||||
|
||||
export default App
|
||||
|
||||
@@ -1,12 +1,46 @@
|
||||
// in src/restricted.js
|
||||
import React, { Component } from 'react';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
//import React, { Component } from 'react';
|
||||
import React, { useEffect, useLayoutEffect, useState, useRef, useCallback, useMemo } from "react";
|
||||
import { useSelector, useDispatch } from 'react-redux'
|
||||
import * as types from "../User/user-constants";
|
||||
import axios from "axios";
|
||||
import {
|
||||
Routes,
|
||||
Route,
|
||||
Link,
|
||||
Navigate,
|
||||
Outlet,
|
||||
} from 'react-router-dom';
|
||||
import { authenticateUser } from "../features/user/userSlice";
|
||||
/**
|
||||
* Higher-order component (HOC) to wrap restricted pages
|
||||
*/
|
||||
|
||||
|
||||
const Restricted = ({children }) => {
|
||||
const { authenticated, hasAuthenticated } = useSelector((state) => state.user);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(authenticateUser({}));
|
||||
},[]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!authenticated) {
|
||||
console.log("I loaded things and it is not good")
|
||||
}
|
||||
}, [hasAuthenticated])
|
||||
|
||||
if (authenticated) {
|
||||
return children;;
|
||||
}
|
||||
return <div/>
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
const restricted = (BaseComponent, store) => {
|
||||
|
||||
class Restricted extends Component {
|
||||
componentDidMount() {
|
||||
this.checkAuthentication(this.props);
|
||||
@@ -32,8 +66,6 @@ const restricted = (BaseComponent, store) => {
|
||||
});
|
||||
} else {
|
||||
window.location = process.env.REACT_APP_ACCOUNT_SERVER + "/login?nextLocation=admin";
|
||||
/*history.replace({ pathname: '/login',
|
||||
state: { nextPathname: params.location.pathname } });*/
|
||||
}
|
||||
})
|
||||
.catch(response => {
|
||||
@@ -51,4 +83,6 @@ const restricted = (BaseComponent, store) => {
|
||||
}
|
||||
return withRouter(Restricted);
|
||||
}
|
||||
export default restricted
|
||||
*/
|
||||
|
||||
export default Restricted
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, { Component } from "react";
|
||||
import { Container, Header } from "semantic-ui-react";
|
||||
|
||||
class About extends Component {
|
||||
const About = () => {
|
||||
|
||||
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Container text>
|
||||
<Header size='large'>Share the Air</Header>
|
||||
@@ -18,7 +18,7 @@ class About extends Component {
|
||||
<p> - Luke <a href="mailto:{process.env.REACT_APP_ADMIN_EMAIL}?Subject={process.env.REACT_APP_SITE_NAME}" target="_top">{process.env.REACT_APP_ADMIN_EMAIL}</a> </p>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default About;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import axios from "axios";
|
||||
//import { browserHistory } from "react-router"
|
||||
import * as types from "./group-constants";
|
||||
import { push } from 'connected-react-router';
|
||||
import { push } from '@lagunovsky/redux-react-router'
|
||||
|
||||
// "Log In" action creators
|
||||
function beginCreateGroup() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { Component } from "react";
|
||||
import { Component, useRef } from "react";
|
||||
import SystemCard from "./SystemCard";
|
||||
import {
|
||||
Container,
|
||||
@@ -8,37 +8,40 @@ import {
|
||||
Icon,
|
||||
Button,
|
||||
} from "semantic-ui-react";
|
||||
import { useGetSystemsQuery, } from '../features/api/apiSlice'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { push } from '@lagunovsky/redux-react-router'
|
||||
|
||||
|
||||
// ----------------------------------------------------
|
||||
class ListSystems extends Component {
|
||||
|
||||
state = {
|
||||
const ListSystems = (props) => {
|
||||
const { data, isSuccess } = useGetSystemsQuery();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
let systems = false;
|
||||
if (isSuccess) {
|
||||
systems = data.systems;
|
||||
}
|
||||
componentDidMount() {
|
||||
this.props.fetchSystems();
|
||||
}
|
||||
|
||||
//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 (
|
||||
<div>
|
||||
<Container>
|
||||
<Header as="h1">Radio Systems</Header>
|
||||
<Button onClick={(e) => this.props.changeUrl("/create-system")}><Icon name='plus' />Add System</Button>
|
||||
<Button onClick={(e) => dispatch(push("/create-system"))}><Icon name='plus' />Add System</Button>
|
||||
<Divider />
|
||||
<Card.Group itemsPerRow={4}>
|
||||
{systems.map((system) =>
|
||||
<SystemCard system={system} key={system.shortName} onClick={(e) => this.props.changeUrl("/system/" + system.shortName)}/>
|
||||
{systems &&
|
||||
systems.map((system) =>
|
||||
<SystemCard system={system} key={system.shortName} onClick={(e) => dispatch(push("/system/" + system.shortName))}/>
|
||||
)}
|
||||
</Card.Group>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ListSystems;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,15 +9,13 @@ import {
|
||||
|
||||
|
||||
|
||||
class SystemCard extends Component {
|
||||
|
||||
render() {
|
||||
const SystemCard = (props) => {
|
||||
var location = "";
|
||||
const system = this.props.system;
|
||||
const { system } = props;
|
||||
|
||||
|
||||
|
||||
if (system) {
|
||||
|
||||
|
||||
|
||||
switch (system.systemType) {
|
||||
case "state":
|
||||
@@ -37,26 +35,26 @@ render() {
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Card link onClick={this.props.onClick}>
|
||||
|
||||
<Card.Content>
|
||||
<Header size='medium'>
|
||||
<Header.Content>
|
||||
{system.name}
|
||||
<Header.Subheader>{system.screenName}</Header.Subheader>
|
||||
</Header.Content>
|
||||
</Header>
|
||||
</Card.Content><Card.Content>
|
||||
<Card link onClick={props.onClick}>
|
||||
|
||||
<Card.Description>{system.description}</Card.Description>
|
||||
</Card.Content>
|
||||
<Card.Content extra>
|
||||
<Icon name='marker' />
|
||||
{location}
|
||||
</Card.Content>
|
||||
</Card>
|
||||
<Card.Content>
|
||||
<Header size='medium'>
|
||||
<Header.Content>
|
||||
{system.name}
|
||||
<Header.Subheader>{system.screenName}</Header.Subheader>
|
||||
</Header.Content>
|
||||
</Header>
|
||||
</Card.Content><Card.Content>
|
||||
|
||||
<Card.Description>{system.description}</Card.Description>
|
||||
</Card.Content>
|
||||
<Card.Content extra>
|
||||
<Icon name='marker' />
|
||||
{location}
|
||||
</Card.Content>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default SystemCard;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import axios from "axios";
|
||||
//import { browserHistory } from "react-router"
|
||||
import * as types from "./error-constants";
|
||||
import { push } from 'connected-react-router';
|
||||
import { push } from '@lagunovsky/redux-react-router';
|
||||
|
||||
|
||||
function beginFetch() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import axios from "axios";
|
||||
//import { browserHistory } from "react-router"
|
||||
import * as types from "./system-constants";
|
||||
import { push } from 'connected-react-router';
|
||||
import { push } from '@lagunovsky/redux-react-router';
|
||||
|
||||
|
||||
// "Log In" action creators
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import axios, { post } from 'axios';
|
||||
import axios from 'axios';
|
||||
//import { browserHistory } from "react-router"
|
||||
import * as types from "./talkgroup-constants";
|
||||
import { push } from 'connected-react-router';
|
||||
import { push } from '@lagunovsky/redux-react-router';
|
||||
|
||||
// "Log In" action creators
|
||||
function beginImportTalkgroup() {
|
||||
@@ -58,7 +58,7 @@ function fileUpload(shortName, file){
|
||||
},
|
||||
withCredentials: true
|
||||
}
|
||||
return post(url, formData,config)
|
||||
return axios.post(url, formData,config)
|
||||
}
|
||||
|
||||
// Example of an Async Action Creator
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import axios from "axios";
|
||||
//import { browserHistory } from "react-router"
|
||||
import * as types from "./user-constants";
|
||||
import { push } from 'connected-react-router';
|
||||
import { push } from '@lagunovsky/redux-react-router';
|
||||
|
||||
|
||||
// "Log Out" action creators
|
||||
|
||||
73
admin/src/features/api/apiSlice.js
Normal file
73
admin/src/features/api/apiSlice.js
Normal file
@@ -0,0 +1,73 @@
|
||||
// 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_ADMIN_SERVER}),
|
||||
// The "endpoints" represent operations and requests for this server
|
||||
endpoints: builder => ({
|
||||
// The `getPosts` endpoint is a "query" operation that returns data
|
||||
getTalkgroups: builder.query({
|
||||
// The URL for the request is '/fakeApi/posts'
|
||||
query: (shortName) => ({ url: `/talkgroups/${shortName}`, credentials: "include" })
|
||||
}),
|
||||
getGroups: builder.query({
|
||||
// The URL for the request is '/fakeApi/posts'
|
||||
query: (shortName) => ({ url: `/groups/${shortName}`, credentials: "include" })
|
||||
}),
|
||||
getErrors: builder.query({
|
||||
// The URL for the request is '/fakeApi/posts'
|
||||
query: (shortName) => ({ url: `${process.env.REACT_APP_BACKEND_SERVER}/${shortName}/errors`})
|
||||
}),
|
||||
updateGroup: builder.mutation({
|
||||
query: (group) => ({
|
||||
url: `/groups/${group.shortName}/${group._id}`,
|
||||
method: 'POST',
|
||||
credentials: "include",
|
||||
body: group,
|
||||
}),
|
||||
async onQueryStarted(group, { dispatch, queryFulfilled }) {
|
||||
try {
|
||||
const { data: updatedGroup } = await queryFulfilled
|
||||
const patchResult = dispatch(
|
||||
apiSlice.util.updateQueryData('getGroups', updatedGroup.shortName, (groups) => {
|
||||
const groupIndex = groups.findIndex((obj => obj.groupId == updatedGroup.groupId));
|
||||
groups[groupIndex] = updatedGroup;
|
||||
})
|
||||
)
|
||||
} catch {}
|
||||
},
|
||||
}),
|
||||
createGroup: builder.mutation({
|
||||
query: (group) => ({
|
||||
url: `/groups/${group.shortName}`,
|
||||
method: 'POST',
|
||||
credentials: "include",
|
||||
body: group,
|
||||
}),
|
||||
async onQueryStarted(group, { dispatch, queryFulfilled }) {
|
||||
try {
|
||||
const { data: newGroup } = await queryFulfilled;
|
||||
const patchResult = dispatch(
|
||||
apiSlice.util.updateQueryData('getGroups', newGroup.shortName, (groups) => {
|
||||
groups.push(newGroup);
|
||||
})
|
||||
)
|
||||
} catch {}
|
||||
},
|
||||
}),
|
||||
getSystems: builder.query({
|
||||
// The URL for the request is '/fakeApi/posts'
|
||||
query: () => ({ url: `/systems`, credentials: "include" })
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
// Export the auto-generated hook for the `getPosts` query endpoint
|
||||
export const { useGetGroupsQuery, useGetSystemsQuery, useGetTalkgroupsQuery, useGetErrorsQuery} = apiSlice
|
||||
@@ -1,60 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import {
|
||||
decrement,
|
||||
increment,
|
||||
incrementByAmount,
|
||||
incrementAsync,
|
||||
selectCount,
|
||||
} from './counterSlice';
|
||||
import styles from './Counter.module.css';
|
||||
|
||||
export function Counter() {
|
||||
const count = useSelector(selectCount);
|
||||
const dispatch = useDispatch();
|
||||
const [incrementAmount, setIncrementAmount] = useState('2');
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.row}>
|
||||
<button
|
||||
className={styles.button}
|
||||
aria-label="Increment value"
|
||||
onClick={() => dispatch(increment())}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
<span className={styles.value}>{count}</span>
|
||||
<button
|
||||
className={styles.button}
|
||||
aria-label="Decrement value"
|
||||
onClick={() => dispatch(decrement())}
|
||||
>
|
||||
-
|
||||
</button>
|
||||
</div>
|
||||
<div className={styles.row}>
|
||||
<input
|
||||
className={styles.textbox}
|
||||
aria-label="Set increment amount"
|
||||
value={incrementAmount}
|
||||
onChange={e => setIncrementAmount(e.target.value)}
|
||||
/>
|
||||
<button
|
||||
className={styles.button}
|
||||
onClick={() =>
|
||||
dispatch(incrementByAmount(Number(incrementAmount) || 0))
|
||||
}
|
||||
>
|
||||
Add Amount
|
||||
</button>
|
||||
<button
|
||||
className={styles.asyncButton}
|
||||
onClick={() => dispatch(incrementAsync(Number(incrementAmount) || 0))}
|
||||
>
|
||||
Add Async
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.row:not(:last-child) {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 78px;
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
margin-top: 2px;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
}
|
||||
|
||||
.button {
|
||||
appearance: none;
|
||||
background: none;
|
||||
font-size: 32px;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
outline: none;
|
||||
border: 2px solid transparent;
|
||||
color: rgb(112, 76, 182);
|
||||
padding-bottom: 4px;
|
||||
cursor: pointer;
|
||||
background-color: rgba(112, 76, 182, 0.1);
|
||||
border-radius: 2px;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
|
||||
.textbox {
|
||||
font-size: 32px;
|
||||
padding: 2px;
|
||||
width: 64px;
|
||||
text-align: center;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.button:hover, .button:focus {
|
||||
border: 2px solid rgba(112, 76, 182, 0.4);
|
||||
}
|
||||
|
||||
.button:active {
|
||||
background-color: rgba(112, 76, 182, 0.2);
|
||||
}
|
||||
|
||||
.asyncButton {
|
||||
composes: button;
|
||||
position: relative;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.asyncButton:after {
|
||||
content: "";
|
||||
background-color: rgba(112, 76, 182, 0.15);
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
transition: width 1s linear, opacity 0.5s ease 1s;
|
||||
}
|
||||
|
||||
.asyncButton:active:after {
|
||||
width: 0%;
|
||||
opacity: 1;
|
||||
transition: 0s
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
export const counterSlice = createSlice({
|
||||
name: 'counter',
|
||||
initialState: {
|
||||
value: 0,
|
||||
},
|
||||
reducers: {
|
||||
increment: state => {
|
||||
// Redux Toolkit allows us to write "mutating" logic in reducers. It
|
||||
// doesn't actually mutate the state because it uses the Immer library,
|
||||
// which detects changes to a "draft state" and produces a brand new
|
||||
// immutable state based off those changes
|
||||
state.value += 1;
|
||||
},
|
||||
decrement: state => {
|
||||
state.value -= 1;
|
||||
},
|
||||
incrementByAmount: (state, action) => {
|
||||
state.value += action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
|
||||
|
||||
// The function below is called a thunk and allows us to perform async logic. It
|
||||
// can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This
|
||||
// will call the thunk with the `dispatch` function as the first argument. Async
|
||||
// code can then be executed and other actions can be dispatched
|
||||
export const incrementAsync = amount => dispatch => {
|
||||
setTimeout(() => {
|
||||
dispatch(incrementByAmount(amount));
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
// The function below is called a selector and allows us to select a value from
|
||||
// the state. Selectors can also be defined inline where they're used instead of
|
||||
// in the slice file. For example: `useSelector((state) => state.counter.value)`
|
||||
export const selectCount = state => state.counter.value;
|
||||
|
||||
export default counterSlice.reducer;
|
||||
15
admin/src/features/group/groupSlice.js
Normal file
15
admin/src/features/group/groupSlice.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const groupSlice = createSlice({
|
||||
name: 'group',
|
||||
initialState: {
|
||||
orderChange: false,
|
||||
isWaiting: false,
|
||||
items: {}
|
||||
},
|
||||
reducers: {
|
||||
},
|
||||
})
|
||||
|
||||
// Extract the action creators object and the reducer
|
||||
const { actions, reducer } = groupSlice
|
||||
// Export the reducer, either as a default or named export
|
||||
export default reducer
|
||||
81
admin/src/features/user/userSlice.js
Normal file
81
admin/src/features/user/userSlice.js
Normal file
@@ -0,0 +1,81 @@
|
||||
import {
|
||||
createSlice,
|
||||
createEntityAdapter,
|
||||
createSelector,
|
||||
createAsyncThunk
|
||||
} from '@reduxjs/toolkit'
|
||||
|
||||
|
||||
export const authenticateUser = createAsyncThunk(
|
||||
'user/authenticate',
|
||||
async ({ getState }) => {
|
||||
const url = process.env.REACT_APP_ACCOUNT_SERVER + "/authenticated"
|
||||
const res = await fetch(url, {
|
||||
method: 'GET',
|
||||
credentials: "include"
|
||||
}).then(
|
||||
(data) => data.json()
|
||||
)
|
||||
return res;
|
||||
}
|
||||
)
|
||||
|
||||
export const logoutUser = createAsyncThunk(
|
||||
'user/logout',
|
||||
async ({ getState }) => {
|
||||
const url = process.env.REACT_APP_ACCOUNT_SERVER + "/logout"
|
||||
const res = await fetch(url, {
|
||||
method: 'GET',
|
||||
credentials: "include"
|
||||
}).then(
|
||||
(data) => data.json()
|
||||
)
|
||||
return res;
|
||||
}
|
||||
)
|
||||
|
||||
export const userSlice = createSlice({
|
||||
name: 'user',
|
||||
initialState: {
|
||||
isWaiting: false,
|
||||
authenticated: false,
|
||||
hasAuthenticated: false,
|
||||
userId: ""
|
||||
},
|
||||
reducers: {
|
||||
increment: (state) => {
|
||||
// Redux Toolkit allows us to write "mutating" logic in reducers. It
|
||||
// doesn't actually mutate the state because it uses the Immer library,
|
||||
// which detects changes to a "draft state" and produces a brand new
|
||||
// immutable state based off those changes
|
||||
state.value += 1
|
||||
},
|
||||
},
|
||||
extraReducers: {
|
||||
[authenticateUser.fulfilled]: (state, data) => {
|
||||
const {payload} = data;
|
||||
if (payload.success) {
|
||||
state.authenticated = true;
|
||||
state.hasAuthenticated = true;
|
||||
state.userId = payload.user.userId;
|
||||
} else {
|
||||
state.authenticated = false;
|
||||
state.hasAuthenticated = true;
|
||||
}
|
||||
},
|
||||
[authenticateUser.rejected]: (state, { payload }) => {
|
||||
state.authenticated = false;
|
||||
state.hasAuthenticated = true;
|
||||
|
||||
},
|
||||
[logoutUser.fulfilled]: (state, { payload }) => {
|
||||
if (payload.success) {
|
||||
state.authenticated = false;
|
||||
state.userId = null;
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
// Extract the action creators object and the reducer
|
||||
export const userReducer = userSlice.reducer;
|
||||
@@ -1,40 +1,23 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Provider } from 'react-redux'
|
||||
import { Route, Switch } from 'react-router' // react-router v4/v5
|
||||
import { ConnectedRouter } from 'connected-react-router'
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import configureStore, { history } from './redux-router/configureStore'
|
||||
import 'semantic-ui-css/semantic.min.css'
|
||||
import App from "./App/App"
|
||||
import Restricted from "./App/Restricted"
|
||||
|
||||
import About from "./Components/About"
|
||||
import SystemContainer from "./System/SystemContainer"
|
||||
import ListSystemsContainer from "./System/ListSystemsContainer"
|
||||
import UpdateSystemContainer from "./System/UpdateSystemContainer"
|
||||
import CreateSystemContainer from "./System/CreateSystemContainer"
|
||||
|
||||
const store = configureStore(/* provide initial state if any */)
|
||||
|
||||
|
||||
ReactDOM.render(
|
||||
|
||||
const container = document.getElementById('root');
|
||||
const root = createRoot(container);
|
||||
root.render(
|
||||
<Provider store={store}>
|
||||
<ConnectedRouter history={history}> { /* place ConnectedRouter under Provider */ }
|
||||
<>
|
||||
<App>
|
||||
<Switch>
|
||||
<Route path="/about" component={Restricted(About, store)} />
|
||||
<Route path="/system/:shortName" component={Restricted(SystemContainer, store)} />
|
||||
<Route path="/update-system/:shortName" component={Restricted(UpdateSystemContainer, store)} />
|
||||
<Route path="/create-system" component={Restricted(CreateSystemContainer, store)} />
|
||||
<Route path="/list-systems" component={Restricted(ListSystemsContainer,store)} />
|
||||
<Route path="/" component={Restricted(ListSystemsContainer, store)} />
|
||||
<Route render={() => (<div>Miss</div>)} />
|
||||
</Switch>
|
||||
</App>
|
||||
</>
|
||||
</ConnectedRouter>
|
||||
</Provider>,
|
||||
document.getElementById('root')
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</Provider>
|
||||
)
|
||||
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
|
||||
import { createBrowserHistory } from 'history'
|
||||
import { applyMiddleware, compose, createStore } from 'redux'
|
||||
import { routerMiddleware } from 'connected-react-router'
|
||||
import { createRouterMiddleware } from '@lagunovsky/redux-react-router'
|
||||
import createRootReducer from './reducers'
|
||||
import thunk from 'redux-thunk';
|
||||
import { apiSlice } from '../features/api/apiSlice'
|
||||
|
||||
export const history = createBrowserHistory()
|
||||
|
||||
@@ -15,12 +16,14 @@ export default function configureStore(preloadedState) {
|
||||
preloadedState,
|
||||
compose(
|
||||
applyMiddleware(
|
||||
routerMiddleware(history), // for dispatching history actions
|
||||
createRouterMiddleware(history), // for dispatching history actions
|
||||
thunk,
|
||||
apiSlice.middleware,
|
||||
// ... other middlewares ...
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
return store
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
|
||||
// from https://github.com/supasate/connected-react-router
|
||||
import { combineReducers } from 'redux'
|
||||
import { connectRouter } from 'connected-react-router'
|
||||
import { createRouterReducer } from '@lagunovsky/redux-react-router'
|
||||
import systemReducer from "../System/system-reducer"
|
||||
import talkgroupReducer from "../Talkgroups/talkgroup-reducer"
|
||||
import groupReducer from "../Group/group-reducer"
|
||||
import errorReducer from "../System/error-reducer"
|
||||
import statisticReducer from "../System/statistic-reducer"
|
||||
import permissionReducer from "../Permission/permission-reducer"
|
||||
import userReducer from "../User/user-reducer"
|
||||
import { userSlice, userReducer } from '../features/user/userSlice'
|
||||
import {apiSlice} from "../features/api/apiSlice"
|
||||
|
||||
const createRootReducer = (history) => combineReducers({
|
||||
router: connectRouter(history),
|
||||
router: createRouterReducer (history),
|
||||
system: systemReducer,
|
||||
statistic: statisticReducer,
|
||||
talkgroup: talkgroupReducer,
|
||||
group: groupReducer,
|
||||
user: userReducer,
|
||||
error: errorReducer,
|
||||
permission: permissionReducer
|
||||
permission: permissionReducer,
|
||||
[apiSlice.reducerPath]: apiSlice.reducer,
|
||||
|
||||
})
|
||||
export default createRootReducer
|
||||
|
||||
|
||||
Reference in New Issue
Block a user