Split out navbar so that it doesn't rerender everything so much.

This commit is contained in:
Matthew Stratford 2021-01-23 23:40:08 +00:00
parent 9613363e20
commit 81d443123a

View file

@ -1,5 +1,5 @@
import React, { useRef, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { shallowEqual, useDispatch, useSelector } from "react-redux";
import Clock from "react-live-clock";
import Stopwatch from "react-stopwatch";
@ -161,31 +161,6 @@ export function NavBarMyRadio() {
}
export function NavBarMain() {
const dispatch = useDispatch();
const broadcastState = useSelector((state: RootState) => state.broadcast);
const settings = useSelector((state: RootState) => state.settings);
const playerState = useSelector((state: RootState) => state.mixer.players);
let playerPFLs: boolean[] = [];
playerState.forEach((player) => {
playerPFLs.push(player.pfl);
});
const isPFL = useSelector((state) => playerPFLs).some((x) => x === true);
const [connectButtonAnimating, setConnectButtonAnimating] = useState(false);
const prevRegistrationStage = useRef(broadcastState.stage);
useEffect(() => {
if (broadcastState.stage !== prevRegistrationStage.current) {
setConnectButtonAnimating(false);
}
prevRegistrationStage.current = broadcastState.stage;
}, [broadcastState.stage]);
const { planSaveError, planSaving } = useSelector(
(state: RootState) => state.showplan
);
return (
<>
<ul className="nav navbar-nav navbar-left">
@ -207,115 +182,188 @@ export function NavBarMain() {
timezone={"europe/london"}
/>
</li>
{planSaving && (
<li className="btn rounded-0 py-2 nav-item alert-info">
<FaSpinner className="nav-spin mb-1" /> Saving show plan...
</li>
)}
{planSaveError && (
<li className="btn rounded-0 py-2 nav-item alert-danger">
<FaExclamationTriangle className="p-0 mr-1" />
{planSaveError}
</li>
)}
<SavingAlert />
</ul>
<ul className="nav navbar-nav navbar-right mr-0 pr-0">
<li className="nav-item" style={{ color: "white" }}>
<div className="nav-link">
<b>{nicifyConnectionState(broadcastState.connectionState)}</b>
</div>
<RegisterButton />
<RecordingButton />
<OptionsButton />
<MeterBridge />
</ul>
</>
);
}
function SavingAlert() {
const { planSaveError, planSaving } = useSelector(
(state: RootState) => state.showplan
);
return (
<>
{planSaving && (
<li className="btn rounded-0 py-2 nav-item alert-info">
<FaSpinner className="nav-spin mb-1" /> Saving show plan...
</li>
)}
{planSaveError && (
<li className="btn rounded-0 py-2 nav-item alert-danger">
<FaExclamationTriangle className="p-0 mr-1" />
{planSaveError}
</li>
)}
</>
);
}
function RegisterButton() {
const dispatch = useDispatch();
const broadcastState = useSelector((state: RootState) => state.broadcast);
const [connectButtonAnimating, setConnectButtonAnimating] = useState(false);
const prevRegistrationStage = useRef(broadcastState.stage);
useEffect(() => {
if (broadcastState.stage !== prevRegistrationStage.current) {
setConnectButtonAnimating(false);
}
prevRegistrationStage.current = broadcastState.stage;
}, [broadcastState.stage]);
return (
<>
<li className="nav-item" style={{ color: "white" }}>
<div className="nav-link">
<b>{nicifyConnectionState(broadcastState.connectionState)}</b>
</div>
</li>
<li
className="btn btn-outline-light rounded-0 pt-2 pb-1 nav-item nav-link connect"
onClick={() => {
setConnectButtonAnimating(true);
switch (broadcastState.stage) {
case "NOT_REGISTERED":
dispatch(BroadcastState.goOnAir());
break;
case "REGISTERED":
dispatch(BroadcastState.cancelTimeslot());
break;
}
}}
>
{connectButtonAnimating ? (
<>
<FaBroadcastTower size={17} className="mr-2" />
<FaSpinner size={17} className="nav-spin mr-2" />
</>
) : (
<>
<FaBroadcastTower size={17} className="mr-2" />
{broadcastState.stage === "NOT_REGISTERED" && "Register"}
{broadcastState.stage === "REGISTERED" && "Stop"}
</>
)}
</li>
</>
);
}
function RecordingButton() {
const recordingState = useSelector(
(state: RootState) => state.broadcast.recordingState
);
const enableRecording = useSelector(
(state: RootState) => state.settings.enableRecording
);
const dispatch = useDispatch();
return (
<>
{enableRecording && (
<li
className="btn btn-outline-light rounded-0 pt-2 pb-1 nav-item nav-link connect"
onClick={() => {
setConnectButtonAnimating(true);
switch (broadcastState.stage) {
case "NOT_REGISTERED":
dispatch(BroadcastState.goOnAir());
break;
case "REGISTERED":
dispatch(BroadcastState.cancelTimeslot());
break;
}
}}
className={
"btn rounded-0 pt-2 pb-1 nav-item nav-link " +
(recordingState === "CONNECTED"
? "btn-outline-danger active"
: "btn-outline-light")
}
onClick={() =>
dispatch(
recordingState === "NOT_CONNECTED"
? BroadcastState.startRecording()
: BroadcastState.stopRecording()
)
}
>
{connectButtonAnimating ? (
<>
<FaBroadcastTower size={17} className="mr-2" />
<FaSpinner size={17} className="nav-spin mr-2" />
</>
<FaCircle
size={17}
className={
recordingState === "CONNECTED" ? "rec-blink" : "rec-stop"
}
/>{" "}
{recordingState === "CONNECTED" ? (
<Stopwatch
seconds={0}
minutes={0}
hours={0}
render={({ formatted }) => {
return <span>{formatted}</span>;
}}
/>
) : (
<>
<FaBroadcastTower size={17} className="mr-2" />
{broadcastState.stage === "NOT_REGISTERED" && "Register"}
{broadcastState.stage === "REGISTERED" && "Stop"}
</>
"Record"
)}
</li>
{settings.enableRecording && (
<li
className={
"btn rounded-0 pt-2 pb-1 nav-item nav-link " +
(broadcastState.recordingState === "CONNECTED"
? "btn-outline-danger active"
: "btn-outline-light")
}
onClick={() =>
dispatch(
broadcastState.recordingState === "NOT_CONNECTED"
? BroadcastState.startRecording()
: BroadcastState.stopRecording()
)
}
>
<FaCircle
size={17}
className={
broadcastState.recordingState === "CONNECTED"
? "rec-blink"
: "rec-stop"
}
/>{" "}
{broadcastState.recordingState === "CONNECTED" ? (
<Stopwatch
seconds={0}
minutes={0}
hours={0}
render={({ formatted }) => {
return <span>{formatted}</span>;
}}
/>
) : (
"Record"
)}
</li>
)}
<li
className="btn btn-outline-light rounded-0 pt-2 pb-1 nav-item nav-link"
onClick={() => dispatch(OptionsMenuState.open())}
>
<FaCog size={17} /> Options
</li>
{settings.proMode && isPFL && (
<li
className="btn btn-danger rounded-0 pt-2 pb-1 nav-item nav-link clear-pfl"
onClick={() => dispatch(setChannelPFL(-1, false))}
>
<FaHeadphonesAlt size={17} /> Clear PFL
</li>
)}
)}
</>
);
}
function OptionsButton() {
const dispatch = useDispatch();
return (
<li
className="btn btn-outline-light rounded-0 pt-2 pb-1 nav-item nav-link"
onClick={() => dispatch(OptionsMenuState.open())}
>
<FaCog size={17} /> Options
</li>
);
}
<li className={"nav-item px-2 nav-vu" + (isPFL ? " pfl-live" : "")}>
function MeterBridge() {
const dispatch = useDispatch();
const proMode = useSelector((state: RootState) => state.settings.proMode);
const playerPFLs = useSelector(
(state: RootState) => state.mixer.players.map((x) => x.pfl),
shallowEqual
);
const isPFL = useSelector((state) => playerPFLs).some((x) => x === true);
return (
<>
{proMode && isPFL && (
<li
className="btn btn-danger rounded-0 pt-2 pb-1 nav-item nav-link clear-pfl"
onClick={() => dispatch(setChannelPFL(-1, false))}
>
<FaHeadphonesAlt size={17} /> Clear PFL
</li>
)}
<li className={"nav-item px-2 nav-vu" + (isPFL ? " pfl-live" : "")}>
{isPFL && (
<VUMeter
width={235}
height={isPFL ? 34 : 40}
source={isPFL ? "pfl" : "master"}
height={34}
source="pfl"
range={[-40, 3]}
stereo={true}
/>
</li>
</ul>
)}
{!isPFL && (
<VUMeter
width={235}
height={40}
source="master"
range={[-40, 3]}
stereo={true}
/>
)}
</li>
</>
);
}