This commit is contained in:
Luke Berndt
2021-02-17 22:05:14 -05:00
parent af2e291139
commit eb2414bda8
45 changed files with 205 additions and 253 deletions

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@ account/.eslintcache
admin/.eslintcache admin/.eslintcache
frontend/.eslintcache frontend/.eslintcache
admin/.eslintcache admin/.eslintcache
data/*

View File

@@ -111,6 +111,9 @@ You can then browser to:
- openmhz.test - openmhz.test
- admin.openmhz.test - admin.openmhz.test
*Interesting Note*: Safari 13+ does not like the **.test** TLD and doesn't seem to want to store cookies from the TLD. It seems to work fine in production when you are using a real TLD. I guess use Chrome for local testing or a different TLD for testing, like local.
https://stackoverflow.com/questions/62023857/sharing-cookies-across-test-sub-domains-in-safari-13-not-possible
### Debugging React Apps using Hot Reloading ### Debugging React Apps using Hot Reloading
If you are trying to make changes to any of react frontends, it is a huge pain to have to compile to site and rebuild the container each time you make a change. Instead, simply run the react app in development mode. This will work for the frontends for the: If you are trying to make changes to any of react frontends, it is a huge pain to have to compile to site and rebuild the container each time you make a change. Instead, simply run the react app in development mode. This will work for the frontends for the:
- admin frontend - admin frontend

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -6,15 +6,15 @@
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta
name="description" name="%REACT_APP_SITE_NAME%"
content="Web site created using create-react-app" content="Listen to live Police and Fire radio broadcasts. Archived for 30 days and searchable."
/> />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/apple-touch-icon.png" />
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
--> -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/site.webmanifest" />
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.
@@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>React Redux App</title> <title>%REACT_APP_SITE_NAME%</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,25 +0,0 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View File

@@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

View File

@@ -28,8 +28,8 @@ module.exports = function(app, passport) {
const sess = { const sess = {
/*saveUninitialized: false, /*saveUninitialized: false,
resave: false,*/ resave: false,*/
resave: true, resave: false,
saveUninitialized: true, saveUninitialized: false,
secret: secrets.sessionSecret, secret: secrets.sessionSecret,
proxy: true, proxy: true,
name: "sessionId", name: "sessionId",
@@ -48,12 +48,12 @@ module.exports = function(app, passport) {
console.log('--------------------------'); console.log('--------------------------');
console.log('===> 😊 Starting Server . . .'); console.log('===> 😊 Starting Server . . .');
console.log('===> Environment: ' + node_env); console.log('===> Environment: ' + node_env);
/*if(node_env === 'production') { if(node_env === 'production') {
console.log('===> 🚦 Note: In order for authentication to work in production'); console.log('===> 🚦 Note: In order for authentication to work in production');
console.log('===> you will need a secure HTTPS connection'); console.log('===> you will need a secure HTTPS connection');
sess.cookie.secure = true; // Serve secure cookies sess.cookie.secure = true; // Serve secure cookies
sess.cookie.httpOnly = false; sess.cookie.httpOnly = false;
}*/ }
app.use(session(sess)) app.use(session(sess))

View File

@@ -21,7 +21,7 @@ exports.isLoggedIn = function(req, res, next) {
exports.authenticated = function(req, res, next) { exports.authenticated = function(req, res, next) {
res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate'); res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
//console.log("account/server/controllers/users.js - exports.authenticated() Auth check for user: " + req.user + " is: " + req.isAuthenticated()); console.log("account/server/controllers/users.js - exports.authenticated() Auth check for user: " + req.user + " is: " + req.isAuthenticated());
if (req.isAuthenticated()) { if (req.isAuthenticated()) {
var clientUser = (({ var clientUser = (({
firstName, firstName,

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -6,15 +6,15 @@
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta
name="description" name="%REACT_APP_SITE_NAME%"
content="Web site created using create-react-app" content="Listen to live Police and Fire radio broadcasts. Archived for 30 days and searchable."
/> />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/apple-touch-icon.png" />
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
--> -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/site.webmanifest" />
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.
@@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>React Redux App</title> <title>%REACT_APP_SITE_NAME%</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,25 +0,0 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View File

@@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

View File

@@ -26,8 +26,8 @@ module.exports = function(app, passport) {
app.use(express.static(path.join(process.cwd(), 'public'))); app.use(express.static(path.join(process.cwd(), 'public')));
const sess = { const sess = {
resave: true, resave: false,
saveUninitialized: true, saveUninitialized: false,
secret: secrets.sessionSecret, secret: secrets.sessionSecret,
proxy: true, proxy: true,
name: "sessionId", name: "sessionId",
@@ -46,12 +46,12 @@ module.exports = function(app, passport) {
console.log('--------------------------'); console.log('--------------------------');
console.log('===> 😊 Starting Server . . .'); console.log('===> 😊 Starting Server . . .');
console.log('===> Environment: ' + node_env); console.log('===> Environment: ' + node_env);
/*
if(node_env === 'production') { if(node_env === 'production') {
console.log('===> 🚦 Note: In order for authentication to work in production'); console.log('===> 🚦 Note: In order for authentication to work in production');
console.log('===> you will need a secure HTTPS connection'); console.log('===> you will need a secure HTTPS connection');
sess.cookie.secure = true; // Serve secure cookies sess.cookie.secure = true; // Serve secure cookies
}*/ }
app.use(session(sess)) app.use(session(sess))

View File

@@ -55,6 +55,7 @@ services:
pid: "host" pid: "host"
environment: environment:
- MONGO_NODE_DRIVER_HOST=mongo - MONGO_NODE_DRIVER_HOST=mongo
- NODE_ENV
- REACT_APP_BACKEND_SERVER - REACT_APP_BACKEND_SERVER
- REACT_APP_ADMIN_SERVER - REACT_APP_ADMIN_SERVER
- REACT_APP_FRONTEND_SERVER - REACT_APP_FRONTEND_SERVER
@@ -98,6 +99,7 @@ services:
- REACT_APP_FRONTEND_SERVER - REACT_APP_FRONTEND_SERVER
- REACT_APP_SITE_NAME - REACT_APP_SITE_NAME
- MONGO_NODE_DRIVER_HOST=mongo - MONGO_NODE_DRIVER_HOST=mongo
- NODE_ENV
depends_on: depends_on:
- mongo - mongo
networks: networks:
@@ -132,6 +134,7 @@ services:
- REACT_APP_SITE_NAME - REACT_APP_SITE_NAME
- REACT_APP_ADMIN_EMAIL - REACT_APP_ADMIN_EMAIL
- REACT_APP_COOKIE_DOMAIN - REACT_APP_COOKIE_DOMAIN
- NODE_ENV
depends_on: depends_on:
- mongo - mongo
networks: networks:

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -6,15 +6,15 @@
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta
name="description" name="%REACT_APP_SITE_NAME%"
content="Web site created using create-react-app" content="Listen to live Police and Fire radio broadcasts. Archived for 30 days and searchable."
/> />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/apple-touch-icon.png" />
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
--> -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/site.webmanifest" />
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.
@@ -28,7 +28,7 @@
<script> <script>
window.socket = io('%REACT_APP_BACKEND_SERVER%'); window.socket = io('%REACT_APP_BACKEND_SERVER%');
</script> </script>
<title>React Redux App</title> <title>%REACT_APP_SITE_NAME%</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,25 +0,0 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View File

@@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

View File

@@ -99,7 +99,11 @@ render() {
} }
if (this.props.activeCall) { if (this.props.activeCall) {
rowSelected={positive: true} rowSelected={positive: true,
color: "blue",
key: "blue",
inverted: true
}
} }
var talkgroup; var talkgroup;
if ((typeof this.props.talkgroups == 'undefined') || (typeof this.props.talkgroups[call.talkgroupNum] == 'undefined')) { if ((typeof this.props.talkgroups == 'undefined') || (typeof this.props.talkgroups[call.talkgroupNum] == 'undefined')) {

View File

@@ -47,6 +47,7 @@ class CallPlayer extends React.Component {
this.handleCalendarToggle = this.handleCalendarToggle.bind(this); this.handleCalendarToggle = this.handleCalendarToggle.bind(this);
this.handleCalendarClose = this.handleCalendarClose.bind(this); this.handleCalendarClose = this.handleCalendarClose.bind(this);
this.handleLiveToggle = this.handleLiveToggle.bind(this); this.handleLiveToggle = this.handleLiveToggle.bind(this);
this.handlePlayPause = this.handlePlayPause.bind(this);
this.getFilter = this.getFilter.bind(this); this.getFilter = this.getFilter.bind(this);
this.socket = window.socket; this.socket = window.socket;
this.setupSocket = this.setupSocket.bind(this); this.setupSocket = this.setupSocket.bind(this);
@@ -74,6 +75,9 @@ class CallPlayer extends React.Component {
switchAutoPlay = () => this.setState({ switchAutoPlay = () => this.setState({
autoPlay: !this.state.autoPlay autoPlay: !this.state.autoPlay
}) })
handlePlayPause = (playing) => this.setState({
isPlaying: playing
})
handlePusherClick = () => { handlePusherClick = () => {
const { sidebarOpened } = this.state const { sidebarOpened } = this.state
@@ -256,7 +260,6 @@ class CallPlayer extends React.Component {
if (this.currentCallRef.current) { if (this.currentCallRef.current) {
this.currentCallRef.current.scrollIntoView({ this.currentCallRef.current.scrollIntoView({
behavior: "smooth", behavior: "smooth",
block: "center", block: "center",
}); });
} }
@@ -287,6 +290,12 @@ class CallPlayer extends React.Component {
const newCall = this.props.callsById[this.props.callsAllIds[0]]; const newCall = this.props.callsById[this.props.callsAllIds[0]];
if (!this.state.isPlaying && this.state.autoPlay) { if (!this.state.isPlaying && this.state.autoPlay) {
this.playCall({ call: newCall }); this.playCall({ call: newCall });
if (this.currentCallRef.current) {
this.currentCallRef.current.scrollIntoView({
behavior: "smooth",
block: "center",
});
}
} }
break break
default: default:
@@ -328,6 +337,7 @@ class CallPlayer extends React.Component {
// is this just for one call? // is this just for one call?
if (uri.hasOwnProperty('call-id')) { if (uri.hasOwnProperty('call-id')) {
const _id = uri['call-id']; const _id = uri['call-id'];
const currentCall = this.props.callsById[this.state.callId];
filter.live = false; filter.live = false;
this.setState({ this.setState({
callId: _id, callId: _id,
@@ -336,6 +346,13 @@ class CallPlayer extends React.Component {
autoPlay: false autoPlay: false
}); });
this.props.callActions.fetchCallInfo(_id); this.props.callActions.fetchCallInfo(_id);
if (this.currentCallRef.current) {
this.currentCallRef.current.scrollIntoView({
behavior: "smooth",
block: "center",
});
}
} }
@@ -443,12 +460,6 @@ class CallPlayer extends React.Component {
this.autoScroll = false; this.autoScroll = false;
window.scrollBy(0, contextRef.clientHeight - this.prevHeight); window.scrollBy(0, contextRef.clientHeight - this.prevHeight);
} }
if (this.state.callId != prevState.callId) {
/*this.currentCallRef.current.scrollIntoView({
behavior: "smooth",
block: "start",
});*/
}
} }
//https://stackoverflow.com/questions/36559661/how-can-i-dispatch-from-child-components-in-react-redux //https://stackoverflow.com/questions/36559661/how-can-i-dispatch-from-child-components-in-react-redux
@@ -563,7 +574,7 @@ class CallPlayer extends React.Component {
<Menu fixed="bottom" compact inverted > <Menu fixed="bottom" compact inverted >
<Menu.Item active={this.state.autoPlay} onClick={() => this.switchAutoPlay()}><Icon name="level up" /><span className="desktop-only">Autoplay</span></Menu.Item> <Menu.Item active={this.state.autoPlay} onClick={() => this.switchAutoPlay()}><Icon name="level up" /><span className="desktop-only">Autoplay</span></Menu.Item>
<MediaPlayer ref={this.audioRef} call={currentCall} onEnded={this.callEnded}/> <MediaPlayer ref={this.audioRef} call={currentCall} onEnded={this.callEnded} onPlayPause={this.handlePlayPause}/>
<Menu.Menu position="right" className="desktop-only"> <Menu.Menu position="right" className="desktop-only">
<Menu.Item onClick={this.handleSupportToggle}><Icon name="coffee" />Support OpenMHz</Menu.Item> <Menu.Item onClick={this.handleSupportToggle}><Icon name="coffee" />Support OpenMHz</Menu.Item>
<Menu.Item><a href={callDownload}><Icon name="download" />Download</a></Menu.Item> <Menu.Item><a href={callDownload}><Icon name="download" />Download</a></Menu.Item>

View File

@@ -23,8 +23,8 @@ class MediaPlayer extends React.Component {
isPlaying: false isPlaying: false
} }
} }
handlePause = () => { this.setState({isPlaying: false}); } handlePause = () => { this.setState({isPlaying: false}); this.props.onPlayPause(false); }
handlePlay = () => { this.setState({isPlaying: true}); } handlePlay = () => { this.setState({isPlaying: true}); this.props.onPlayPause(true); }
playPause = () => {const audio = this.audioRef.current.audioEl.current; if (this.state.isPlaying) {audio.pause();} else {audio.play();}} playPause = () => {const audio = this.audioRef.current.audioEl.current; if (this.state.isPlaying) {audio.pause();} else {audio.play();}}
playSource(callUrl) { playSource(callUrl) {
const audio = this.audioRef.current.audioEl.current; const audio = this.audioRef.current.audioEl.current;

View File

@@ -12,6 +12,7 @@ export TAG=2.0
export REACT_APP_ARCHIVE_DAYS=30 export REACT_APP_ARCHIVE_DAYS=30
export STAGE=prod export STAGE=prod
export NODE_ENV="production"
export PROTOCOL="https://" export PROTOCOL="https://"
export REACT_APP_BACKEND_SERVER="${PROTOCOL}api.${DOMAIN_NAME}" export REACT_APP_BACKEND_SERVER="${PROTOCOL}api.${DOMAIN_NAME}"

View File

@@ -12,6 +12,7 @@ export TAG=2.0
export REACT_APP_ARCHIVE_DAYS=30 export REACT_APP_ARCHIVE_DAYS=30
export STAGE=test export STAGE=test
export NODE_ENV="test"
export PROTOCOL="http://" export PROTOCOL="http://"
export REACT_APP_BACKEND_SERVER="${PROTOCOL}api.${DOMAIN_NAME}" export REACT_APP_BACKEND_SERVER="${PROTOCOL}api.${DOMAIN_NAME}"