From e221543dc7fafc2ac7a7cb8f5cb23057e884b4f9 Mon Sep 17 00:00:00 2001 From: Bianca Procopio Date: Sun, 31 Mar 2024 14:45:08 -0600 Subject: [PATCH] initial setup for edit multiple events --- .../components/input/text-input/TextInput.tsx | 2 +- .../src/features/rundown/RundownExport.tsx | 5 +- .../rundown/event-editor/EventEditor.tsx | 63 ++------ .../event-editor/EventEditorWrapper.tsx | 141 ++++++++++++++++++ .../composite/EventEditorTitles.tsx | 2 +- .../event-editor/composite/EventTextArea.tsx | 2 +- .../event-editor/composite/EventTextInput.tsx | 2 +- 7 files changed, 162 insertions(+), 55 deletions(-) create mode 100644 apps/client/src/features/rundown/event-editor/EventEditorWrapper.tsx diff --git a/apps/client/src/common/components/input/text-input/TextInput.tsx b/apps/client/src/common/components/input/text-input/TextInput.tsx index a395cff48..b6e6acfd6 100644 --- a/apps/client/src/common/components/input/text-input/TextInput.tsx +++ b/apps/client/src/common/components/input/text-input/TextInput.tsx @@ -1,7 +1,7 @@ import { useCallback, useRef } from 'react'; import { Input, Textarea } from '@chakra-ui/react'; -import { EventEditorSubmitActions } from '../../../../features/rundown/event-editor/EventEditor'; +import { EventEditorSubmitActions } from '../../../../features/rundown/event-editor/EventEditorWrapper'; import { Size } from '../../../models/Util.type'; import useReactiveTextInput from './useReactiveTextInput'; diff --git a/apps/client/src/features/rundown/RundownExport.tsx b/apps/client/src/features/rundown/RundownExport.tsx index acd8acdb4..eb191fd4f 100644 --- a/apps/client/src/features/rundown/RundownExport.tsx +++ b/apps/client/src/features/rundown/RundownExport.tsx @@ -4,11 +4,10 @@ import { IoArrowUp } from '@react-icons/all-files/io5/IoArrowUp'; import ErrorBoundary from '../../common/components/error-boundary/ErrorBoundary'; import { handleLinks } from '../../common/utils/linkUtils'; import { cx } from '../../common/utils/styleUtils'; - -import EventEditor from './event-editor/EventEditor'; import RundownWrapper from './RundownWrapper'; import style from './RundownExport.module.scss'; +import EventEditorWrapper from './event-editor/EventEditorWrapper'; const RundownExport = () => { const isExtracted = window.location.pathname.includes('/rundown'); @@ -26,7 +25,7 @@ const RundownExport = () => {
- +
diff --git a/apps/client/src/features/rundown/event-editor/EventEditor.tsx b/apps/client/src/features/rundown/event-editor/EventEditor.tsx index 2cfe98715..53c4bf3e4 100644 --- a/apps/client/src/features/rundown/event-editor/EventEditor.tsx +++ b/apps/client/src/features/rundown/event-editor/EventEditor.tsx @@ -1,14 +1,11 @@ -import { CSSProperties, useCallback, useEffect, useState } from 'react'; +import { CSSProperties } from 'react'; import { useSearchParams } from 'react-router-dom'; import { Button } from '@chakra-ui/react'; -import { CustomFieldLabel, isOntimeEvent, OntimeEvent } from 'ontime-types'; +import { CustomFieldLabel, OntimeEvent } from 'ontime-types'; import CopyTag from '../../../common/components/copy-tag/CopyTag'; -import { useEventAction } from '../../../common/hooks/useEventAction'; import useCustomFields from '../../../common/hooks-query/useCustomFields'; -import useRundown from '../../../common/hooks-query/useRundown'; import { getAccessibleColour } from '../../../common/utils/styleUtils'; -import { useEventSelection } from '../useEventSelection'; import EventEditorTimes from './composite/EventEditorTimes'; import EventEditorTitles from './composite/EventEditorTitles'; @@ -20,48 +17,16 @@ export type EventEditorSubmitActions = keyof OntimeEvent; export type EditorUpdateFields = 'cue' | 'title' | 'note' | 'colour' | CustomFieldLabel; -export default function EventEditor() { - const selectedEvents = useEventSelection((state) => state.selectedEvents); - const { data } = useRundown(); +interface EventEditorProps { + event: OntimeEvent | null; + handleSubmit: (field: EditorUpdateFields, value: string) => void; + isMultiple: boolean; +} + +export default function EventEditor({ event, handleSubmit, isMultiple }: EventEditorProps) { const { data: customFields } = useCustomFields(); - const { order, rundown } = data; - const { updateEvent } = useEventAction(); const [_searchParams, setSearchParams] = useSearchParams(); - const [event, setEvent] = useState(null); - - useEffect(() => { - if (order.length === 0) { - setEvent(null); - return; - } - - const selectedEventId = order.find((eventId) => selectedEvents.has(eventId)); - if (!selectedEventId) { - setEvent(null); - return; - } - const event = rundown[selectedEventId]; - - if (event && isOntimeEvent(event)) { - setEvent(event); - } else { - setEvent(null); - } - }, [order, rundown, selectedEvents]); - - const handleSubmit = useCallback( - (field: EditorUpdateFields, value: string) => { - if (field.startsWith('custom-')) { - const fieldLabel = field.split('custom-')[1]; - updateEvent({ id: event?.id, custom: { [fieldLabel]: { value } } }); - } else { - updateEvent({ id: event?.id, [field]: value }); - } - }, - [event?.id, updateEvent], - ); - const handleOpenCustomManager = () => { setSearchParams({ settings: 'project_settings__custom' }); }; @@ -128,10 +93,12 @@ export default function EventEditor() { })} -
- {`/ontime/load/id "${event.id}"`} - {`/ontime/load/cue "${event.cue}"`} -
+ {!isMultiple ? ( +
+ {`/ontime/load/id "${event.id}"`} + {`/ontime/load/cue "${event.cue}"`} +
+ ) : null} ); } diff --git a/apps/client/src/features/rundown/event-editor/EventEditorWrapper.tsx b/apps/client/src/features/rundown/event-editor/EventEditorWrapper.tsx new file mode 100644 index 000000000..e12d90576 --- /dev/null +++ b/apps/client/src/features/rundown/event-editor/EventEditorWrapper.tsx @@ -0,0 +1,141 @@ +import { useCallback, useEffect, useState } from 'react'; +import { useSearchParams } from 'react-router-dom'; +import { + CustomFieldLabel, + EndAction, + isOntimeEvent, + OntimeEvent, + SupportedEvent, + TimerType, + TimeStrategy, +} from 'ontime-types'; + +import { useEventAction } from '../../../common/hooks/useEventAction'; +import useRundown from '../../../common/hooks-query/useRundown'; +import { useEventSelection } from '../useEventSelection'; + +import style from './EventEditor.module.scss'; +import EventEditorTest from './EventEditor'; + +export type EventEditorSubmitActions = keyof OntimeEvent; + +export type EditorUpdateFields = 'cue' | 'title' | 'note' | 'colour' | CustomFieldLabel; + +export default function EventEditorWrapper() { + const selectedEvents = useEventSelection((state) => state.selectedEvents); + const { data } = useRundown(); + const { order, rundown } = data; + const { updateEvent } = useEventAction(); + const [_searchParams] = useSearchParams(); + console.log({ selectedEvents, order }, 'size: ', selectedEvents.size); + + const [event, setEvent] = useState(null); + + useEffect(() => { + if (order.length === 0) { + setEvent(null); + return; + } + + const selectedEventId = order.find((eventId) => selectedEvents.has(eventId)); + if (!selectedEventId) { + setEvent(null); + return; + } + const event = rundown[selectedEventId]; + + if (event && isOntimeEvent(event)) { + setEvent(event); + } else { + setEvent(null); + } + }, [order, rundown, selectedEvents]); + + const handleSingleSubmit = useCallback( + (field: EditorUpdateFields, value: string) => { + if (field.startsWith('custom-')) { + const fieldLabel = field.split('custom-')[1]; + updateEvent({ id: event?.id, custom: { [fieldLabel]: { value } } }); + } else { + updateEvent({ id: event?.id, [field]: value }); + } + }, + [event?.id, updateEvent], + ); + + const handleMultipleSubmits = useCallback( + (field: EditorUpdateFields, value: string) => { + if (field.startsWith('custom-')) { + // const fieldLabel = field.split('custom-')[1]; + // updateEvent({ id: event?.id, custom: { [fieldLabel]: { value } } }); + } else { + // updateEvent({ id: event?.id, [field]: value }); + } + }, + [event?.id, updateEvent], + ); + + if (!event) { + return ( +
+ Select an event to edit +
+ ); + } + + const getMultipleEvent = (): OntimeEvent => { + const allHaveSameValue = (arr: any[], propertyName: string) => { + if (!arr || arr.length <= 0) return false; + return arr.every((obj) => JSON.stringify(obj[propertyName]) === JSON.stringify(arr[0][propertyName])); + }; + + const events: OntimeEvent[] = []; + let eventsIds: string = ''; + + for (const event of selectedEvents) { + const data = rundown[event]; + if (data && isOntimeEvent(data)) { + events.push(data); + eventsIds += `${event} `; + } + } + + const multipleEvents: OntimeEvent = { + id: eventsIds.trim().split(' ').join(', '), + colour: allHaveSameValue(events, 'colour') ? events[0]['colour'] : '', + custom: allHaveSameValue(events, 'custom') ? events[0]['custom'] : {}, + duration: allHaveSameValue(events, 'duration') ? events[0]['duration'] : 600000, + endAction: allHaveSameValue(events, 'endAction') ? events[0]['endAction'] : EndAction.None, + delay: allHaveSameValue(events, 'delay') ? events[0]['delay'] : 0, + isPublic: allHaveSameValue(events, 'isPublic') ? events[0]['isPublic'] : true, + linkStart: allHaveSameValue(events, 'linkStart') ? events[0]['linkStart'] : null, + note: allHaveSameValue(events, 'note') ? events[0]['note'] : '', + revision: allHaveSameValue(events, 'revision') ? events[0]['revision'] : 0, + skip: allHaveSameValue(events, 'skip') ? events[0]['skip'] : false, + timeDanger: allHaveSameValue(events, 'timeDanger') ? events[0]['timeDanger'] : 60000, + timeEnd: allHaveSameValue(events, 'timeEnd') ? events[0]['timeEnd'] : 600000, + timeStart: allHaveSameValue(events, 'timeStart') ? events[0]['timeStart'] : 0, + timeStrategy: allHaveSameValue(events, 'timeStrategy') ? events[0]['timeStrategy'] : TimeStrategy.LockDuration, + timeWarning: allHaveSameValue(events, 'timeWarning') ? events[0]['timeWarning'] : 120000, + timerType: allHaveSameValue(events, 'timerType') ? events[0]['timerType'] : TimerType.CountDown, + title: allHaveSameValue(events, 'title') ? events[0]['title'] : '', + type: allHaveSameValue(events, 'type') ? events[0]['type'] : SupportedEvent.Event, + cue: allHaveSameValue(events, 'cue') ? events[0]['cue'] : '0.01', + }; + + return { + ...event, + ...multipleEvents, + }; + }; + + return ( +
+ {selectedEvents.size <= 1 ? ( + + ) : ( + + )} +
+ ); +} diff --git a/apps/client/src/features/rundown/event-editor/composite/EventEditorTitles.tsx b/apps/client/src/features/rundown/event-editor/composite/EventEditorTitles.tsx index a4d764427..0e6d64c5c 100644 --- a/apps/client/src/features/rundown/event-editor/composite/EventEditorTitles.tsx +++ b/apps/client/src/features/rundown/event-editor/composite/EventEditorTitles.tsx @@ -3,7 +3,7 @@ import { Input } from '@chakra-ui/react'; import { sanitiseCue } from 'ontime-utils'; import SwatchSelect from '../../../../common/components/input/colour-input/SwatchSelect'; -import { type EditorUpdateFields } from '../EventEditor'; +import { type EditorUpdateFields } from '../EventEditorWrapper'; import EventTextArea from './EventTextArea'; import EventTextInput from './EventTextInput'; diff --git a/apps/client/src/features/rundown/event-editor/composite/EventTextArea.tsx b/apps/client/src/features/rundown/event-editor/composite/EventTextArea.tsx index 64ad94888..70cb355c5 100644 --- a/apps/client/src/features/rundown/event-editor/composite/EventTextArea.tsx +++ b/apps/client/src/features/rundown/event-editor/composite/EventTextArea.tsx @@ -3,7 +3,7 @@ import { CSSProperties, useCallback } from 'react'; import { AutoTextArea } from '../../../../common/components/input/auto-text-area/AutoTextArea'; import useReactiveTextInput from '../../../../common/components/input/text-input/useReactiveTextInput'; import { cx } from '../../../../common/utils/styleUtils'; -import { EditorUpdateFields } from '../EventEditor'; +import { EditorUpdateFields } from '../EventEditorWrapper'; import style from '../EventEditor.module.scss'; diff --git a/apps/client/src/features/rundown/event-editor/composite/EventTextInput.tsx b/apps/client/src/features/rundown/event-editor/composite/EventTextInput.tsx index dff73b40d..24017bec5 100644 --- a/apps/client/src/features/rundown/event-editor/composite/EventTextInput.tsx +++ b/apps/client/src/features/rundown/event-editor/composite/EventTextInput.tsx @@ -2,7 +2,7 @@ import { useCallback } from 'react'; import { Input, InputProps } from '@chakra-ui/react'; import useReactiveTextInput from '../../../../common/components/input/text-input/useReactiveTextInput'; -import { EditorUpdateFields } from '../EventEditor'; +import { EditorUpdateFields } from '../EventEditorWrapper'; import style from '../EventEditor.module.scss';