Skip to content

Commit aa239e3

Browse files
authored
Merge pull request #92 from nebulabroadcast/martastain/channel-switcher
Add channel switcher to Navbar
2 parents 417a635 + ccd6b4a commit aa239e3

File tree

8 files changed

+97
-9
lines changed

8 files changed

+97
-9
lines changed

frontend/src/actions.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const initialState = {
88
selectedAssets: [],
99
focusedAsset: null,
1010
pageTitle: '',
11+
currentChannel: JSON.parse(localStorage.getItem('currentChannel') || 'null'),
1112
}
1213

1314
const contextSlice = createSlice({
@@ -66,6 +67,13 @@ const contextSlice = createSlice({
6667
state.sendToIds = undefined
6768
state.sendToDialogVisible = false
6869
},
70+
71+
setCurrentChannel: (state, action) => {
72+
console.debug('setCurrentChannel', action.payload)
73+
state.currentChannel = action.payload
74+
localStorage.setItem('currentChannel', JSON.stringify(action.payload))
75+
return state
76+
},
6977
},
7078
})
7179

@@ -79,6 +87,7 @@ export const {
7987
setPageTitle,
8088
showSendToDialog,
8189
hideSendToDialog,
90+
setCurrentChannel,
8291
} = contextSlice.actions
8392

8493
export default contextSlice.reducer

frontend/src/app.jsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@ import ServicesPage from '/src/pages/ServicesPage'
1515
import ToolPage from '/src/pages/ToolPage'
1616
import ProfilePage from '/src/pages/ProfilePage'
1717
import UsersPage from '/src/pages/UsersPage'
18+
import Dropdown from '/src/components/Dropdown'
1819

1920
const App = () => {
2021
const [accessToken, setAccessToken] = useLocalStorage('accessToken', null)
2122
const [errorCode, setErrorCode] = useState(null)
2223
const [loading, setLoading] = useState(true)
2324
const [initData, setInitData] = useState(null)
25+
const [channels, setChannels] = useState([])
2426

2527
// Ensure server connection
2628

@@ -56,6 +58,24 @@ const App = () => {
5658
.finally(() => setLoading(false))
5759
}, [accessToken])
5860

61+
useEffect(() => {
62+
if (initData?.settings?.channels) {
63+
setChannels(initData.settings.channels)
64+
const mostRecentChannel = JSON.parse(
65+
localStorage.getItem('currentChannel')
66+
)
67+
if (mostRecentChannel) {
68+
setCurrentChannel(mostRecentChannel)
69+
} else if (initData.settings.channels.length > 0) {
70+
setCurrentChannel(initData.settings.channels[0])
71+
}
72+
}
73+
}, [initData])
74+
75+
const handleChannelChange = (channel) => {
76+
setCurrentChannel(channel)
77+
}
78+
5979
// Render
6080

6181
if (loading) return <LoadingPage />

frontend/src/components/Dropdown.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ const Dropdown = ({
7777
contentStyle = {},
7878
value = null,
7979
disabled = false,
80+
defaultValue = null,
8081
}) => {
8182
if (align === 'right') contentStyle['right'] = 0
8283

frontend/src/containers/Navbar.jsx

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import nebula from '/src/nebula'
22
import styled from 'styled-components'
33
import { useMemo } from 'react'
4-
import { useSelector } from 'react-redux'
4+
import { useSelector, useDispatch } from 'react-redux'
55
import { NavLink, useNavigate } from 'react-router-dom'
6+
import { setCurrentChannel } from '/src/actions'
67

78
import { Navbar, Dropdown } from '/src/components'
89

@@ -83,8 +84,9 @@ const logout = () => {
8384

8485
const NavBar = () => {
8586
const navigate = useNavigate()
87+
const dispatch = useDispatch()
8688
const focusedAsset = useSelector((state) => state.context.focusedAsset)
87-
89+
const currentChannel = useSelector((state) => state.context.currentChannel)
8890
const mamSuffix = focusedAsset ? `?asset=${focusedAsset}` : ''
8991

9092
const mainMenuOptions = useMemo(() => {
@@ -114,6 +116,35 @@ const NavBar = () => {
114116
return result
115117
}, [])
116118

119+
const channelSwitcher = useMemo(() => {
120+
if ((nebula.settings?.playout_channels || []).length < 2) {
121+
if (nebula.settings?.playout_channels.length === 1) {
122+
dispatch(setCurrentChannel(nebula.settings.playout_channels[0].id))
123+
}
124+
return null
125+
}
126+
127+
if (!nebula.experimental) return null
128+
129+
const channelOptions = nebula.settings?.playout_channels.map((channel) => ({
130+
label: channel.name,
131+
onClick: () => dispatch(setCurrentChannel(channel.id)),
132+
}))
133+
134+
const currentChannelName = nebula.settings?.playout_channels.find(
135+
(channel) => channel.id === currentChannel
136+
)?.name
137+
138+
return (
139+
<Dropdown
140+
align="right"
141+
options={channelOptions}
142+
buttonStyle={{ background: 'none' }}
143+
label={currentChannelName}
144+
/>
145+
)
146+
}, [nebula.settings?.playout_channels, currentChannel])
147+
117148
return (
118149
<Navbar>
119150
<div className="left">
@@ -136,6 +167,7 @@ const NavBar = () => {
136167
<PageTitle />
137168
</div>
138169
<div className="right">
170+
{channelSwitcher}
139171
<Dropdown
140172
icon="apps"
141173
align="right"

frontend/src/hooks.jsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,19 @@ const useLocalStorage = (key, initialValue) => {
8686
console.error(error)
8787
}
8888
}
89+
90+
useEffect(() => {
91+
const handleStorageChange = () => {
92+
const item = window.localStorage.getItem(key)
93+
setStoredValue(item ? JSON.parse(item) : initialValue)
94+
}
95+
96+
window.addEventListener('storage', handleStorageChange)
97+
return () => {
98+
window.removeEventListener('storage', handleStorageChange)
99+
}
100+
}, [key, initialValue])
101+
89102
return [storedValue, setValue]
90103
}
91104

frontend/src/nebula.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ const nebula = {
6363
return result
6464
},
6565

66+
getPlayoutChannel(id_channel) {
67+
for (const channel of this.settings?.playoutChannels || []) {
68+
if (channel.id === id_channel) return channel
69+
}
70+
},
71+
6672
getFolderName(id_folder) {
6773
for (const folder of this.settings?.folders || []) {
6874
if (folder.id === id_folder) return folder.name

frontend/src/pages/Rundown/Rundown.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { useState, useEffect, useMemo } from 'react'
2+
import { useDispatch, useSelector } from 'react-redux'
23
import nebula from '/src/nebula'
34

45
import RundownNav from './RundownNav'
56
import RundownTable from './RundownTable'
67

78
const Rundown = () => {
89
const [startTime, setStartTime] = useState(null)
10+
const currentChannel = useSelector((state) => state.context.currentChannel)
911
const [rundown, setRundown] = useState(null)
1012

1113
const onResponse = (response) => {
@@ -20,10 +22,10 @@ const Rundown = () => {
2022
if (!startTime) return
2123
const requestParams = {
2224
date: startTime.toISOString().split('T')[0],
23-
id_channel: 1,
25+
id_channel: currentChannel,
2426
}
2527
nebula.request('rundown', requestParams).then(onResponse).catch(onError)
26-
}, [startTime])
28+
}, [startTime, currentChannel])
2729

2830
return (
2931
<main className="column">

frontend/src/pages/Scheduler/Scheduler.jsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useState, useEffect, useMemo } from 'react'
2-
import { useDispatch } from 'react-redux'
2+
import { useDispatch, useSelector } from 'react-redux'
33
import { setPageTitle } from '/src/actions'
44
import { toast } from 'react-toastify'
55

@@ -15,6 +15,11 @@ const Scheduler = ({ draggedAsset }) => {
1515
const [startTime, setStartTime] = useState(getWeekStart())
1616
const [events, setEvents] = useState([])
1717
const [editorData, setEditorData] = useState(null)
18+
const currentChannel = useSelector((state) => state.context.currentChannel)
19+
20+
const channelConfig = useMemo(() => {
21+
return nebula.getPlayoutChannel(currentChannel)
22+
}, [currentChannel])
1823

1924
const onResponse = (response) => {
2025
const events = response.data.events
@@ -33,7 +38,7 @@ const Scheduler = ({ draggedAsset }) => {
3338
}
3439

3540
const requestParams = {
36-
id_channel: 1,
41+
id_channel: currentChannel,
3742
date: DateTime.fromJSDate(startTime).toFormat('yyyy-MM-dd'),
3843
}
3944

@@ -66,7 +71,7 @@ const Scheduler = ({ draggedAsset }) => {
6671
setEditorData(null)
6772
}
6873

69-
for (const field of nebula.settings.playout_channels[0].fields) {
74+
for (const field of channelConfig?.fields || []) {
7075
const key = field.name
7176
if (event[key] === undefined) continue
7277
payload.meta[key] = event[key]
@@ -87,13 +92,13 @@ const Scheduler = ({ draggedAsset }) => {
8792

8893
useEffect(() => {
8994
loadEvents()
90-
}, [startTime])
95+
}, [startTime, currentChannel])
9196

9297
useEffect(() => {
9398
// console.log('Week start time changed', startTime)
9499
const pageTitle = createTitle(startTime)
95100
dispatch(setPageTitle({ title: pageTitle }))
96-
}, [startTime])
101+
}, [startTime, currentChannel])
97102

98103
//
99104
// Context menu

0 commit comments

Comments
 (0)