mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-10 18:03:47 +00:00
113 lines
3.9 KiB
TypeScript
113 lines
3.9 KiB
TypeScript
import { EntryId, OntimeEvent, OntimeGroup, isOntimeGroup } from 'ontime-types';
|
|
import { useState } from 'react';
|
|
import { IoArrowBack, IoClose, IoSaveOutline } from 'react-icons/io5';
|
|
import { useNavigate } from 'react-router';
|
|
|
|
import Button from '../../common/components/buttons/Button';
|
|
import { ExtendedEntry } from '../../common/utils/rundownMetadata';
|
|
import { cx } from '../../common/utils/styleUtils';
|
|
import ClockTime from '../common/clock-time/ClockTime';
|
|
import { makeSubscriptionsUrl } from './countdown.utils';
|
|
|
|
import './Countdown.scss';
|
|
|
|
interface CountdownSelectProps {
|
|
events: ExtendedEntry<OntimeEvent | OntimeGroup>[];
|
|
subscriptions: EntryId[];
|
|
disableEdit: () => void;
|
|
}
|
|
|
|
export default function CountdownSelect({ events, subscriptions, disableEdit }: CountdownSelectProps) {
|
|
const [selected, setSelected] = useState<EntryId[]>(subscriptions);
|
|
const navigate = useNavigate();
|
|
|
|
/**
|
|
* Toggles an entry from the selected set
|
|
*/
|
|
const toggleSelect = (entryId: EntryId) => {
|
|
setSelected((prev) => {
|
|
if (prev.includes(entryId)) {
|
|
// If the entry is already selected, remove it
|
|
return prev.filter((id) => id !== entryId);
|
|
}
|
|
return [...prev, entryId];
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Creates a URL with the selected subscriptions
|
|
* and navigates to it
|
|
*/
|
|
const applySelection = () => {
|
|
// we remove events that no longer exist to avoid stale subscriptions
|
|
const filteredSelected = selected.filter((id) => events.some((event) => event.id === id));
|
|
const url = makeSubscriptionsUrl(window.location.href, filteredSelected);
|
|
disableEdit();
|
|
setSelected([]);
|
|
navigate(url.search.toString());
|
|
};
|
|
|
|
// make a copy of the selected array for quick lookup
|
|
const selectedIds = new Set(selected);
|
|
|
|
return (
|
|
<div className='list-container'>
|
|
{events.map((event) => {
|
|
const title = event.title || '{no title}';
|
|
const isSelected = selectedIds.has(event.id);
|
|
const isGroup = isOntimeGroup(event);
|
|
const isGroupedEvent = !isGroup && Boolean(event.parent);
|
|
|
|
return (
|
|
<div
|
|
key={event.id}
|
|
role='button'
|
|
tabIndex={0}
|
|
onClick={() => toggleSelect(event.id)}
|
|
onKeyDown={(e) => {
|
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
toggleSelect(event.id);
|
|
e.stopPropagation();
|
|
}
|
|
}}
|
|
className={cx([
|
|
'sub',
|
|
isSelected && 'sub--selected',
|
|
isGroup && 'sub--group',
|
|
isGroupedEvent && 'sub--in-group',
|
|
])}
|
|
>
|
|
<div
|
|
className='sub__binder'
|
|
style={{ '--user-color': event?.colour ?? '', '--group-color': event.groupColour ?? 'transparent' }}
|
|
/>
|
|
<div className='sub__schedule'>
|
|
<ClockTime value={event.timeStart} preferredFormat12='h:mm a' preferredFormat24='HH:mm' />
|
|
→
|
|
<ClockTime value={event.timeEnd} preferredFormat12='h:mm a' preferredFormat24='HH:mm' />
|
|
</div>
|
|
<div className='sub__label'>{isSelected ? 'Click to remove' : 'Click to add'}</div>
|
|
<div className='sub__title'>
|
|
{isGroup && <span className='sub__eyebrow'>Group</span>}
|
|
{title}
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
|
|
<div className='fab-container'>
|
|
<div className='selection-count'>{selected.length} selected</div>
|
|
<Button variant='subtle' size='xlarge' onClick={disableEdit}>
|
|
<IoArrowBack /> Go back
|
|
</Button>
|
|
<Button variant='subtle' size='xlarge' onClick={() => setSelected([])} disabled={selected.length === 0}>
|
|
<IoClose /> Clear
|
|
</Button>
|
|
<Button variant='primary' size='xlarge' disabled={events.length < 1} onClick={applySelection}>
|
|
<IoSaveOutline /> Save
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|