mirror of
https://github.com/cpvalente/ontime.git
synced 2026-09-06 23:09:08 +00:00
0fea4064c3
* chore: upgrade relevant libraries * feat(skip): add skip styling to paginated items * chore: upgrade relevant libraries * Fix: issue with text colour (#214) * fix: adjust text colour from context * fix: issue with wrong proptype * fix issue with vite migration (#217) * hotfix: 1.8.2 issues vite migration * fix: file import options * feat(55): styling * refactor: remove onhover option for entry block * refactor: relocate logging provider * refactor: convert to typescript * feat(55): add event editor * refactor: extract event actions * fix: bad import * feat(55): redesign components * fix: issues with not awaiting async * refactor: replace socket with subscription * refactor: remove unused * style: small tweaks * refactor: extract event actions * refactor: cleanup debug * refactor: chakra imports * fix: optimistic mutations * refactor: handle promise rejections * refactor: validation * fix: rq optimistic mutations * feat: add playback feedback to block * refactor: no optimistic adding of events * refactor: simplify cursor state * styles: cleanup editor style * refactor: cleanup duration update * fix: revert package upgrade (issues with vitest) * fix: prevent cyclic imports * refactor: extract data fetcher * refactor: typescript migration * chore: update tests
135 lines
4.0 KiB
React
135 lines
4.0 KiB
React
import { useEffect, useRef, useState } from 'react';
|
|
import QRCode from 'react-qr-code';
|
|
import { ReactComponent as Emptyimage } from 'assets/images/empty.svg';
|
|
import NavLogo from 'common/components/nav/NavLogo';
|
|
import { formatDisplay } from 'common/utils/dateConfig';
|
|
import { AnimatePresence, motion } from 'framer-motion';
|
|
import PropTypes from 'prop-types';
|
|
|
|
import { overrideStylesURL } from '../../../common/api/apiConstants';
|
|
import Paginator from '../../../common/components/paginator/Paginator';
|
|
import { useRuntimeStylesheet } from '../../../common/hooks/useRuntimeStylesheet';
|
|
import { formatTime } from '../../../common/utils/time';
|
|
|
|
import './Pip.scss';
|
|
|
|
const formatOptions = {
|
|
showSeconds: true,
|
|
format: 'hh:mm:ss a',
|
|
};
|
|
|
|
export default function Pip(props) {
|
|
const { time, backstageEvents, selectedId, general, viewSettings } = props;
|
|
const { shouldRender } = useRuntimeStylesheet(viewSettings?.overrideStyles && overrideStylesURL);
|
|
const ref = useRef(null);
|
|
const [filteredEvents, setFilteredEvents] = useState(null);
|
|
const [pageNumber, setPageNumber] = useState(0);
|
|
const [currentPage, setCurrentPage] = useState(0);
|
|
|
|
// Set window title
|
|
useEffect(() => {
|
|
document.title = 'ontime - Pip';
|
|
}, []);
|
|
|
|
// calculate delays if any
|
|
useEffect(() => {
|
|
if (backstageEvents == null) return;
|
|
|
|
const events = [...backstageEvents];
|
|
|
|
// Add running delay
|
|
let delay = 0;
|
|
for (const e of events) {
|
|
if (e.type === 'block') delay = 0;
|
|
else if (e.type === 'delay') delay = delay + e.duration;
|
|
else if (e.type === 'event' && delay > 0) {
|
|
e.timeStart += delay;
|
|
e.timeEnd += delay;
|
|
}
|
|
}
|
|
|
|
// filter just events
|
|
setFilteredEvents(events.filter((e) => e.type === 'event'));
|
|
}, [backstageEvents]);
|
|
|
|
// defer rendering until we load stylesheets
|
|
if (!shouldRender) {
|
|
return null;
|
|
}
|
|
|
|
// Format messages
|
|
const showInfo = general.backstageInfo !== '' && general.backstageInfo != null;
|
|
let stageTimer = formatDisplay(Math.abs(time.running), true);
|
|
if (time.isNegative) stageTimer = `-${stageTimer}`;
|
|
|
|
const clock = formatTime(time.clock, formatOptions);
|
|
|
|
return (
|
|
<div className='pip'>
|
|
<NavLogo />
|
|
|
|
<div className='event-title'>{general.title}</div>
|
|
|
|
<div className='today-container'>
|
|
<div className='today-header-block'>
|
|
<div className='label'>Today</div>
|
|
<div className='nav'>
|
|
{pageNumber > 1 &&
|
|
[...Array(pageNumber).keys()].map((i) => (
|
|
<div
|
|
key={i}
|
|
className={i === currentPage ? 'nav-item nav-item--selected' : 'nav-item'}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
<Paginator
|
|
selectedId={selectedId}
|
|
events={filteredEvents}
|
|
isBackstage
|
|
limit={14}
|
|
time={20}
|
|
setCurrentPage={setCurrentPage}
|
|
setPageNumber={setPageNumber}
|
|
/>
|
|
</div>
|
|
|
|
<div className='pip-placeholder' ref={ref}>
|
|
<Emptyimage className='pip-placeholder__empty' />
|
|
</div>
|
|
|
|
<AnimatePresence>
|
|
{showInfo && (
|
|
<motion.div className='info-container'>
|
|
<div className='label'>Info</div>
|
|
<div className='info-message'>{general.backstageInfo}</div>
|
|
<div className='qr'>
|
|
{general.url != null && general.url !== '' && (
|
|
<QRCode value={general.url} size={window.innerWidth / 12} level='L' />
|
|
)}
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
|
|
<div className='clock-container'>
|
|
<div className='label'>Time Now</div>
|
|
<div className='clock'>{clock}</div>
|
|
</div>
|
|
|
|
<div className='timer-container'>
|
|
<div className='label'>Stage Timer</div>
|
|
<div className='timer'>{stageTimer}</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
Pip.propTypes = {
|
|
time: PropTypes.object,
|
|
backstageEvents: PropTypes.object,
|
|
selectedId: PropTypes.string,
|
|
general: PropTypes.object,
|
|
viewSettings: PropTypes.object,
|
|
};
|