mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-22 07:29:08 +00:00
general data from node
This commit is contained in:
+11
-12
@@ -19,18 +19,17 @@ const SStageManager = withSocket(StageManager);
|
|||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<SocketProvider>
|
<SocketProvider>
|
||||||
<div className='App'>
|
<QueryClientProvider client={queryClient}>
|
||||||
<Switch>
|
<div className='App'>
|
||||||
<Route exact path='/' component={SDefault} />
|
<Switch>
|
||||||
<Route path='/sm' component={SStageManager} />
|
<Route exact path='/' component={SDefault} />
|
||||||
<Route path='/speaker' component={SSpeaker} />
|
<Route exact path='/sm' component={SStageManager} />
|
||||||
<Route path='/speakersimple' component={SSpeakerSimple} />
|
<Route exact path='/speaker' component={SSpeaker} />
|
||||||
|
<Route exact path='/speakersimple' component={SSpeakerSimple} />
|
||||||
<QueryClientProvider client={queryClient}>
|
<Route exact path='/editor' component={Editor} />
|
||||||
<Route path='/editor' component={Editor} />
|
</Switch>
|
||||||
</QueryClientProvider>
|
</div>
|
||||||
</Switch>
|
</QueryClientProvider>
|
||||||
</div>
|
|
||||||
</SocketProvider>
|
</SocketProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,25 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
|
import { eventsNamespace, fetchAllEvents } from '../../app/api/eventsApi';
|
||||||
|
import { fetchSettings, settingsNamespace } from '../../app/api/settingsApi';
|
||||||
import { useSocket } from '../../app/context/socketContext';
|
import { useSocket } from '../../app/context/socketContext';
|
||||||
import { stringFromMillis } from '../../common/dateConfig';
|
import { stringFromMillis } from '../../common/dateConfig';
|
||||||
|
|
||||||
const withSocket = (Component) => {
|
const withSocket = (Component) => {
|
||||||
const WrappedComponent = (props) => {
|
const WrappedComponent = (props) => {
|
||||||
|
const {
|
||||||
|
data: eventsData,
|
||||||
|
status: eventsDataStatus,
|
||||||
|
isError: eventsDataIsError,
|
||||||
|
} = useQuery(eventsNamespace, fetchAllEvents);
|
||||||
|
const {
|
||||||
|
data: genData,
|
||||||
|
status: genDataStatus,
|
||||||
|
isError: genDataIsError,
|
||||||
|
} = useQuery(settingsNamespace, fetchSettings);
|
||||||
|
|
||||||
|
const [events, setEvents] = useState([]);
|
||||||
|
|
||||||
const socket = useSocket();
|
const socket = useSocket();
|
||||||
const [pres, setPres] = useState({
|
const [pres, setPres] = useState({
|
||||||
text: '',
|
text: '',
|
||||||
@@ -31,6 +47,13 @@ const withSocket = (Component) => {
|
|||||||
subtitleNext: '',
|
subtitleNext: '',
|
||||||
presenterNext: '',
|
presenterNext: '',
|
||||||
});
|
});
|
||||||
|
const [selectedId, setSelectedId] = useState({});
|
||||||
|
const [general, setGeneral] = useState({
|
||||||
|
title: '',
|
||||||
|
url: '',
|
||||||
|
publicInfo: '',
|
||||||
|
backstageInfo: '',
|
||||||
|
});
|
||||||
|
|
||||||
// Ask for update on load
|
// Ask for update on load
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -56,11 +79,16 @@ const withSocket = (Component) => {
|
|||||||
setTimer({ ...data });
|
setTimer({ ...data });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle timer
|
// Handle titles
|
||||||
socket.on('titles', (data) => {
|
socket.on('titles', (data) => {
|
||||||
setTitles({ ...data });
|
setTitles({ ...data });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle selected event
|
||||||
|
socket.on('selected-id', (data) => {
|
||||||
|
setSelectedId(data);
|
||||||
|
});
|
||||||
|
|
||||||
// Ask for up to date data
|
// Ask for up to date data
|
||||||
socket.emit('get-messages');
|
socket.emit('get-messages');
|
||||||
|
|
||||||
@@ -70,6 +98,9 @@ const withSocket = (Component) => {
|
|||||||
// Ask for up titles
|
// Ask for up titles
|
||||||
socket.emit('get-titles');
|
socket.emit('get-titles');
|
||||||
|
|
||||||
|
// Ask for up selected
|
||||||
|
socket.emit('get-selected-id');
|
||||||
|
|
||||||
// Clear listeners
|
// Clear listeners
|
||||||
return () => {
|
return () => {
|
||||||
socket.off('messages-public');
|
socket.off('messages-public');
|
||||||
@@ -77,9 +108,23 @@ const withSocket = (Component) => {
|
|||||||
socket.off('messages-lower');
|
socket.off('messages-lower');
|
||||||
socket.off('timer');
|
socket.off('timer');
|
||||||
socket.off('titles');
|
socket.off('titles');
|
||||||
|
socket.off('selected-id');
|
||||||
};
|
};
|
||||||
}, [socket]);
|
}, [socket]);
|
||||||
|
|
||||||
|
// Filter events only to pass down
|
||||||
|
useEffect(() => {
|
||||||
|
if (eventsData == null) return;
|
||||||
|
const e = eventsData.filter((d) => d.type === 'event');
|
||||||
|
setEvents(e);
|
||||||
|
}, [eventsData]);
|
||||||
|
|
||||||
|
// Set general data
|
||||||
|
useEffect(() => {
|
||||||
|
if (genData == null) return;
|
||||||
|
setGeneral(genData);
|
||||||
|
}, [genData]);
|
||||||
|
|
||||||
/********************************************/
|
/********************************************/
|
||||||
/*** + titleManager ***/
|
/*** + titleManager ***/
|
||||||
/*** WRAP INFORMATION RELATED TO TITLES ***/
|
/*** WRAP INFORMATION RELATED TO TITLES ***/
|
||||||
@@ -114,6 +159,9 @@ const withSocket = (Component) => {
|
|||||||
lower={lower}
|
lower={lower}
|
||||||
title={titleManager}
|
title={titleManager}
|
||||||
time={timeManager}
|
time={timeManager}
|
||||||
|
events={events}
|
||||||
|
selectedId={selectedId}
|
||||||
|
general={general}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,19 +1,27 @@
|
|||||||
import QRCode from 'react-qr-code';
|
import QRCode from 'react-qr-code';
|
||||||
import { formatDisplay } from '../../../common/dateConfig';
|
import { formatDisplay } from '../../../common/dateConfig';
|
||||||
import style from './StageManager.module.css';
|
import style from './StageManager.module.css';
|
||||||
|
import TodayItem from './TodayItem';
|
||||||
|
|
||||||
export default function StageManager(props) {
|
export default function StageManager(props) {
|
||||||
const { pres, publ, lower, title, time } = props;
|
const { pres, publ, lower, title, time, events, selectedId, general } = props;
|
||||||
|
|
||||||
|
// Format messages
|
||||||
const showPubl = publ.text !== '' && publ.visible;
|
const showPubl = publ.text !== '' && publ.visible;
|
||||||
const stageTimer =
|
const stageTimer =
|
||||||
time.currentSeconds != null && !isNaN(time.currentSeconds)
|
time.currentSeconds != null && !isNaN(time.currentSeconds)
|
||||||
? formatDisplay(time.currentSeconds, true)
|
? formatDisplay(time.currentSeconds, true)
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
|
// Keep track of order
|
||||||
|
// 0 - events before
|
||||||
|
// 1 - running event
|
||||||
|
// 2 - future event
|
||||||
|
let selectedYet = 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.container__gray}>
|
<div className={style.container__gray}>
|
||||||
<div className={style.eventTitle}>A hamburger life</div>
|
<div className={style.eventTitle}>{general.title}</div>
|
||||||
<div className={style.nowContainer}>
|
<div className={style.nowContainer}>
|
||||||
<div className={style.label}>Now</div>
|
<div className={style.label}>Now</div>
|
||||||
<div className={style.nowTitle}>{title.titleNow}</div>
|
<div className={style.nowTitle}>{title.titleNow}</div>
|
||||||
@@ -29,32 +37,20 @@ export default function StageManager(props) {
|
|||||||
<div className={style.todayContainer}>
|
<div className={style.todayContainer}>
|
||||||
<div className={style.label}>Today</div>
|
<div className={style.label}>Today</div>
|
||||||
<div className={style.entries}>
|
<div className={style.entries}>
|
||||||
<div class={style.entryPast}>
|
{events.map((e) => {
|
||||||
<div className={style.entryStart}>10:30</div>
|
if (e.id === selectedId) selectedYet = 1;
|
||||||
<div className={style.entryEnd}>10:45</div>
|
else if (selectedYet === 1) selectedYet = 2;
|
||||||
<div className={style.entryTitle}>A dress to the nation</div>
|
return (
|
||||||
</div>
|
<TodayItem
|
||||||
<div class={style.entryPast}>
|
selected={selectedYet}
|
||||||
<div className={style.entryStart}>10:30</div>
|
timeStart={e.timeStart}
|
||||||
<div className={style.entryEnd}>10:45</div>
|
timeEnd={e.timeEnd}
|
||||||
<div className={style.entryTitle}>A dress to the nation</div>
|
title={e.title}
|
||||||
</div>
|
/>
|
||||||
<div class={style.entryPast}>
|
);
|
||||||
<div className={style.entryStart}>10:30</div>
|
})}
|
||||||
<div className={style.entryEnd}>10:45</div>
|
|
||||||
<div className={style.entryTitle}>A dress to the nation</div>
|
|
||||||
</div>
|
|
||||||
<div class={style.entryNow}>
|
|
||||||
<div className={style.entryStart}>10:30</div>
|
|
||||||
<div className={style.entryEnd}>10:45</div>
|
|
||||||
<div className={style.entryTitle}>Are burguers real</div>
|
|
||||||
</div>
|
|
||||||
<div class={style.entryFuture}>
|
|
||||||
<div className={style.entryStart}>10:30</div>
|
|
||||||
<div className={style.entryEnd}>10:45</div>
|
|
||||||
<div className={style.entryTitle}>Up to midnight</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={style.nav}>
|
<div className={style.nav}>
|
||||||
<div className={style.navItem} />
|
<div className={style.navItem} />
|
||||||
<div className={style.navItem} />
|
<div className={style.navItem} />
|
||||||
@@ -84,16 +80,16 @@ export default function StageManager(props) {
|
|||||||
<div className={style.infoContainer}>
|
<div className={style.infoContainer}>
|
||||||
<div className={style.label}>Info</div>
|
<div className={style.label}>Info</div>
|
||||||
<div className={style.infoMessages}>
|
<div className={style.infoMessages}>
|
||||||
<div className={style.info}>Water in the public bathroom</div>
|
<div className={style.info}>{general.backstageInfo}</div>
|
||||||
<div className={style.info}>Wifi Password: bemywifi</div>
|
|
||||||
<div className={style.info}>Have a nice day</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={style.qr}>
|
<div className={style.qr}>
|
||||||
<QRCode
|
{general.url != null && general.url !== '' && (
|
||||||
value='www.carlosvalente.com'
|
<QRCode
|
||||||
size={window.innerWidth / 10}
|
value='www.carlosvalente.com'
|
||||||
level='L'
|
size={window.innerWidth / 12}
|
||||||
/>
|
level='L'
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600;800&display=swap');
|
||||||
|
|
||||||
.container__gray,
|
.container__gray,
|
||||||
.container__grayFinished {
|
.container__grayFinished {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -30,8 +32,9 @@
|
|||||||
|
|
||||||
.eventTitle {
|
.eventTitle {
|
||||||
grid-area: titl;
|
grid-area: titl;
|
||||||
font-size: 4vw;
|
font-size: 3vw;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
text-decoration: underline #ff7597 0.5vh;
|
||||||
padding-top: 0.2vh;
|
padding-top: 0.2vh;
|
||||||
padding-left: 1vw;
|
padding-left: 1vw;
|
||||||
}
|
}
|
||||||
@@ -206,15 +209,18 @@
|
|||||||
grid-area: info;
|
grid-area: info;
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|
||||||
|
grid-template-rows: 3vh minmax(0, 1fr);
|
||||||
grid-template-columns: 3fr 1fr;
|
grid-template-columns: 3fr 1fr;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
'titl qr'
|
'titl .'
|
||||||
'info qr';
|
'binf qr';
|
||||||
|
gap: 0.5vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
.infoMessages {
|
.infoMessages {
|
||||||
grid-area: info;
|
grid-area: binf;
|
||||||
font-size: 1.5vw;
|
font-size: 1.5vw;
|
||||||
|
white-space: pre-line;
|
||||||
}
|
}
|
||||||
|
|
||||||
.qr {
|
.qr {
|
||||||
@@ -236,6 +242,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.clock {
|
.clock {
|
||||||
|
font-family: 'Open Sans', sans-serif;
|
||||||
font-size: 3vw;
|
font-size: 3vw;
|
||||||
line-height: 3vw;
|
line-height: 3vw;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { stringFromMillis } from '../../../common/dateConfig';
|
||||||
|
import style from './StageManager.module.css';
|
||||||
|
export default function TodayItem(props) {
|
||||||
|
const { selected, timeStart, timeEnd, title } = props;
|
||||||
|
|
||||||
|
// Format timers
|
||||||
|
const start = timeStart ? stringFromMillis(timeStart, false) : '';
|
||||||
|
const end = timeEnd ? stringFromMillis(timeEnd, false) : '';
|
||||||
|
|
||||||
|
// select styling
|
||||||
|
let selectStyle = style.entryPast;
|
||||||
|
if (selected === 1) selectStyle = style.entryNow;
|
||||||
|
else if (selected === 2) selectStyle = style.entryFuture;
|
||||||
|
return (
|
||||||
|
<div class={selectStyle}>
|
||||||
|
<div className={style.entryStart}>{start}</div>
|
||||||
|
<div className={style.entryEnd}>{end}</div>
|
||||||
|
<div className={style.entryTitle}>{title}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
// get database
|
||||||
|
const db = require('../app.js').db;
|
||||||
|
const table = 'settings';
|
||||||
|
|
||||||
|
function getSettings() {
|
||||||
|
return db.get(table).value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create controller for GET request to 'settings'
|
||||||
|
// Returns ACK message
|
||||||
|
exports.getAll = async (req, res) => {
|
||||||
|
const settings = getSettings();
|
||||||
|
if (settings) res.json(settings);
|
||||||
|
else res.sendStatus(400);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create controller for POST request to 'settings'
|
||||||
|
// Returns ACK message
|
||||||
|
exports.post = async (req, res) => {
|
||||||
|
if (!req.body) {
|
||||||
|
res.status(400).send(`No object found in request`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: validate data
|
||||||
|
try {
|
||||||
|
db.get(table)
|
||||||
|
.assign({ ...req.body })
|
||||||
|
.write();
|
||||||
|
res.sendStatus(200);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(400).send(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create controller for GET request to 'settings/title'
|
||||||
|
// Returns ACK message
|
||||||
|
exports.titleGet = async (req, res) => {
|
||||||
|
const settings = getSettings();
|
||||||
|
|
||||||
|
if (settings) res.json(settings.title);
|
||||||
|
else res.sendStatus(400);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create controller for POST request to 'settings/title'
|
||||||
|
// Returns ACK message
|
||||||
|
exports.titlePost = async (req, res) => {
|
||||||
|
if (!req.body) {
|
||||||
|
res.status(400).send(`No object found in request`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: validate data
|
||||||
|
try {
|
||||||
|
db.get(table).assign({ title: req.body.title }).write();
|
||||||
|
res.sendStatus(200);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(400).send(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create controller for GET request to '/settings/url'
|
||||||
|
// Returns ACK message
|
||||||
|
exports.urlGet = async (req, res) => {
|
||||||
|
let event = getEventOptions();
|
||||||
|
|
||||||
|
if (event) res.json(event.url);
|
||||||
|
else res.sendStatus(400);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create controller for POST request to '/settings/url'
|
||||||
|
// Returns ACK message
|
||||||
|
exports.urlPost = async (req, res) => {
|
||||||
|
if (!req.body) {
|
||||||
|
res.status(400).send(`No object found in request`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: validate data
|
||||||
|
try {
|
||||||
|
db.get(table).assign({ url: req.body.url }).write();
|
||||||
|
res.sendStatus(200);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(400).send(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create controller for GET request to 'settings/publicInfo'
|
||||||
|
// Returns ACK message
|
||||||
|
exports.publicInfoGet = async (req, res) => {
|
||||||
|
const settings = getSettings();
|
||||||
|
|
||||||
|
if (settings) res.json(settings.publicInfo);
|
||||||
|
else res.sendStatus(400);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create controller for POST request to '/settings/publicInfo'
|
||||||
|
// Returns ACK message
|
||||||
|
exports.publicInfoPost = async (req, res) => {
|
||||||
|
if (!req.body) {
|
||||||
|
res.status(400).send(`No object found in request`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: validate data
|
||||||
|
try {
|
||||||
|
db.get(table).assign({ publicInfo: req.body.publicInfo }).write();
|
||||||
|
res.sendStatus(200);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(400).send(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create controller for GET request to 'settings/backstageInfo'
|
||||||
|
// Returns ACK message
|
||||||
|
exports.backstageInfoGet = async (req, res) => {
|
||||||
|
const settings = getSettings();
|
||||||
|
|
||||||
|
if (settings) res.json(settings.backstageInfo);
|
||||||
|
else res.sendStatus(400);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create controller for POST request to '/settings/info'
|
||||||
|
// Returns ACK message
|
||||||
|
exports.backstageInfoPost = async (req, res) => {
|
||||||
|
if (!req.body) {
|
||||||
|
res.status(400).send(`No object found in request`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: validate data
|
||||||
|
try {
|
||||||
|
db.get(table).assign({ backstageInfo: req.body.backstageInfo }).write();
|
||||||
|
res.sendStatus(200);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(400).send(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create controller for GET request to 'settings/osc'
|
||||||
|
// Returns ACK message
|
||||||
|
exports.osc = async (req, res) => {
|
||||||
|
res.send('Not yet implemented').status(500);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user