mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-17 13:23:35 +00:00
feat: allow editing field from operator (#609)
* feat: allow editing field from operator Co-authored-by: arc-alex <ac@omnivox.dk> * style: functional and presentation tweaks --------- Co-authored-by: arc-alex <ac@omnivox.dk>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { isOntimeEvent, OntimeEvent, SupportedEvent, UserFields } from 'ontime-types';
|
||||
import { getFirstEvent, getLastEvent } from 'ontime-utils';
|
||||
@@ -15,6 +15,7 @@ import useUserFields from '../../common/hooks-query/useUserFields';
|
||||
import { debounce } from '../../common/utils/debounce';
|
||||
import { isStringBoolean } from '../../common/utils/viewUtils';
|
||||
|
||||
import EditModal from './edit-modal/EditModal';
|
||||
import FollowButton from './follow-button/FollowButton';
|
||||
import OperatorBlock from './operator-block/OperatorBlock';
|
||||
import OperatorEvent from './operator-event/OperatorEvent';
|
||||
@@ -25,14 +26,24 @@ import style from './Operator.module.scss';
|
||||
const selectedOffset = 50;
|
||||
|
||||
type TitleFields = Pick<OntimeEvent, 'title' | 'subtitle' | 'presenter'>;
|
||||
export type EditEvent = Pick<OntimeEvent, 'id' | 'cue'> & { fieldLabel?: string; fieldValue: string };
|
||||
export type PartialEdit = EditEvent & {
|
||||
field: keyof UserFields;
|
||||
};
|
||||
|
||||
export default function Operator() {
|
||||
const { data, status } = useRundown();
|
||||
const { data: userFields, status: userFieldsStatus } = useUserFields();
|
||||
const { data: projectData, status: projectDataStatus } = useProjectData();
|
||||
|
||||
const timeoutId = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
const featureData = useOperator();
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
const [showEditPrompt, setShowEditPrompt] = useState(false);
|
||||
const [editEvent, setEditEvent] = useState<PartialEdit | null>(null);
|
||||
|
||||
const [lockAutoScroll, setLockAutoScroll] = useState(false);
|
||||
const selectedRef = useRef<HTMLDivElement | null>(null);
|
||||
const scrollRef = useRef<HTMLDivElement | null>(null);
|
||||
@@ -78,6 +89,30 @@ export default function Operator() {
|
||||
};
|
||||
const debouncedHandleScroll = debounce(handleUserScroll, 1000);
|
||||
|
||||
const handleScroll = () => {
|
||||
if (timeoutId.current) {
|
||||
clearTimeout(timeoutId.current);
|
||||
}
|
||||
timeoutId.current = setTimeout(() => {
|
||||
setShowEditPrompt(false);
|
||||
}, 700);
|
||||
|
||||
setShowEditPrompt(true);
|
||||
|
||||
debouncedHandleScroll();
|
||||
};
|
||||
|
||||
const handleEdit = useCallback(
|
||||
(event: EditEvent) => {
|
||||
const field = searchParams.get('subscribe') as keyof UserFields | null;
|
||||
|
||||
if (field) {
|
||||
setEditEvent({ ...event, field });
|
||||
}
|
||||
},
|
||||
[searchParams],
|
||||
);
|
||||
|
||||
const missingData = !data || !userFields || !projectData;
|
||||
const isLoading = status === 'pending' || userFieldsStatus === 'pending' || projectDataStatus === 'pending';
|
||||
|
||||
@@ -103,6 +138,7 @@ export default function Operator() {
|
||||
<div className={style.operatorContainer}>
|
||||
<NavigationMenu />
|
||||
<ViewParamsEditor paramFields={operatorOptions} />
|
||||
{editEvent && <EditModal event={editEvent} onClose={() => setEditEvent(null)} />}
|
||||
|
||||
<StatusBar
|
||||
projectTitle={projectData.title}
|
||||
@@ -114,12 +150,13 @@ export default function Operator() {
|
||||
lastId={lastEvent?.id}
|
||||
/>
|
||||
|
||||
<div
|
||||
className={style.operatorEvents}
|
||||
onWheel={debouncedHandleScroll}
|
||||
onTouchMove={debouncedHandleScroll}
|
||||
ref={scrollRef}
|
||||
>
|
||||
{subscribe && (
|
||||
<div className={`${style.editPrompt} ${showEditPrompt ? style.show : undefined}`}>
|
||||
Press and hold to edit user field
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={style.operatorEvents} onWheel={handleScroll} onTouchMove={handleScroll} ref={scrollRef}>
|
||||
{data.map((entry) => {
|
||||
if (isOntimeEvent(entry)) {
|
||||
const isSelected = featureData.selectedEventId === entry.id;
|
||||
@@ -139,6 +176,7 @@ export default function Operator() {
|
||||
return (
|
||||
<OperatorEvent
|
||||
key={entry.id}
|
||||
id={entry.id}
|
||||
colour={entry.colour}
|
||||
cue={entry.cue}
|
||||
main={mainField}
|
||||
@@ -153,6 +191,7 @@ export default function Operator() {
|
||||
showSeconds={showSeconds}
|
||||
isPast={isPast}
|
||||
selectedRef={isSelected ? selectedRef : undefined}
|
||||
onLongPress={subscribe ? handleEdit : () => undefined}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user