From b38a7e5c921ab564e84ddeb279194b6592d02bf7 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Sat, 21 Dec 2024 12:39:46 +0100 Subject: [PATCH] refactor: allow submitting same value --- .../input/text-input/useReactiveTextInput.tsx | 3 +- .../client/src/common/hooks/useEventAction.ts | 63 ++++++++++++------- .../SingleLineCell.tsx | 4 +- .../TimeInputDuration.tsx | 9 ++- 4 files changed, 52 insertions(+), 27 deletions(-) diff --git a/apps/client/src/common/components/input/text-input/useReactiveTextInput.tsx b/apps/client/src/common/components/input/text-input/useReactiveTextInput.tsx index ce24b4f80..edec6366a 100644 --- a/apps/client/src/common/components/input/text-input/useReactiveTextInput.tsx +++ b/apps/client/src/common/components/input/text-input/useReactiveTextInput.tsx @@ -16,6 +16,7 @@ export default function useReactiveTextInput( submitOnEnter?: boolean; submitOnCtrlEnter?: boolean; onCancelUpdate?: () => void; + allowSubmitSameValue?: boolean; }, ): UseReactiveTextInputReturn { const [text, setText] = useState(initialText); @@ -48,7 +49,7 @@ export default function useReactiveTextInput( const handleSubmit = useCallback( (valueToSubmit: string) => { // No need to update if it hasn't changed - if (valueToSubmit === initialText) { + if (valueToSubmit === initialText && !options?.allowSubmitSameValue) { options?.onCancelUpdate?.(); } else { const cleanVal = valueToSubmit.trim(); diff --git a/apps/client/src/common/hooks/useEventAction.ts b/apps/client/src/common/hooks/useEventAction.ts index 488fa1823..8204b0709 100644 --- a/apps/client/src/common/hooks/useEventAction.ts +++ b/apps/client/src/common/hooks/useEventAction.ts @@ -225,38 +225,32 @@ export const useEventAction = () => { */ const updateTimer = useCallback( async (eventId: string, field: TimeField, value: string, lockOnUpdate?: boolean) => { - let newValMillis = 0; - - // check for previous keyword - if (value === 'p' || value === 'prev' || value === 'previous') { - newValMillis = getPreviousEnd(); - - // check for adding time keyword - } else if (value.startsWith('+') || value.startsWith('p+') || value.startsWith('p +')) { - // TODO: is this logic solid? - const remainingString = value.substring(1); - newValMillis = getPreviousEnd() + parseUserTime(remainingString); - } else { - newValMillis = parseUserTime(value); + // an empty value with no lock has no domain validity + if (!lockOnUpdate && value === '') { + return; } - // dont allow timer values over 23:59:59 - const cappedMillis = Math.min(newValMillis, dayInMs - MILLIS_PER_SECOND); - const newEvent = { + const newEvent: Partial = { id: eventId, - [field]: cappedMillis, }; // check if we should lock the field if (lockOnUpdate) { if (field === 'timeEnd') { - newEvent.timeStrategy = TimeStrategy.LockEnd; + // an empty value indicates that we should unlock the field + newEvent.timeStrategy = value === '' ? TimeStrategy.LockDuration : TimeStrategy.LockEnd; + newEvent.timeEnd = value === '' ? undefined : calculateNewValue(); } else if (field === 'duration') { - newEvent.timeStrategy = TimeStrategy.LockDuration; - } else if (field === 'timeStart' && value === '') { - // if user removes the time start, we should link to the previous - newEvent.linkStart = 'true'; + // an empty value indicates that we should unlock the field + newEvent.timeStrategy = value === '' ? TimeStrategy.LockEnd : TimeStrategy.LockDuration; + newEvent.duration = value === '' ? undefined : calculateNewValue(); + } else if (field === 'timeStart') { + // an empty values means we should link to the previous + newEvent.linkStart = value === '' ? 'true' : null; + newEvent.timeStart = value === '' ? undefined : calculateNewValue(); } + } else { + newEvent[field] = calculateNewValue(); } try { @@ -265,6 +259,31 @@ export const useEventAction = () => { logAxiosError('Error updating event', error); } + /** + * Utility function to calculate the new time value + */ + function calculateNewValue(): number { + let newValMillis = 0; + + // check for previous keyword + if (value === 'p' || value === 'prev' || value === 'previous') { + newValMillis = getPreviousEnd(); + + // check for adding time keyword + } else if (value.startsWith('+') || value.startsWith('p+') || value.startsWith('p +')) { + // TODO: is this logic solid? + const remainingString = value.substring(1); + newValMillis = getPreviousEnd() + parseUserTime(remainingString); + } else { + newValMillis = parseUserTime(value); + } + // dont allow timer values over 23:59:59 + return Math.min(newValMillis, dayInMs - MILLIS_PER_SECOND); + } + + /** + * Utility function to get the previous event end time + */ function getPreviousEnd(): number { const cachedRundown = queryClient.getQueryData(RUNDOWN); diff --git a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/SingleLineCell.tsx b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/SingleLineCell.tsx index 46444264f..efd7381cf 100644 --- a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/SingleLineCell.tsx +++ b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/SingleLineCell.tsx @@ -5,16 +5,18 @@ import useReactiveTextInput from '../../../../common/components/input/text-input interface SingleLineCellProps { initialValue: string; + allowSubmitSameValue?: boolean; handleUpdate: (newValue: string) => void; handleCancelUpdate?: () => void; } const SingleLineCell = forwardRef((props: SingleLineCellProps, inputRef) => { - const { initialValue, handleUpdate, handleCancelUpdate } = props; + const { initialValue, allowSubmitSameValue, handleUpdate, handleCancelUpdate } = props; const ref = useRef(null); const submitCallback = useCallback((newValue: string) => handleUpdate(newValue), [handleUpdate]); const { value, onChange, onBlur, onKeyDown } = useReactiveTextInput(initialValue, submitCallback, ref, { + allowSubmitSameValue, submitOnEnter: true, // single line should submit on enter submitOnCtrlEnter: true, onCancelUpdate: handleCancelUpdate, diff --git a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/TimeInputDuration.tsx b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/TimeInputDuration.tsx index 1e07fa5f9..3a636cd7a 100644 --- a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/TimeInputDuration.tsx +++ b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/TimeInputDuration.tsx @@ -41,8 +41,9 @@ export default function TimeInputDuration(props: TimeInputDurationProps) { (newValue: string) => { setIsEditing(false); - // Check if there is anything there + // if the user sends an empty string, we want to clear the value if (newValue === '') { + onSubmit(newValue); return; } @@ -59,14 +60,15 @@ export default function TimeInputDuration(props: TimeInputDurationProps) { return; } - if (valueInMillis === initialValue) { + // if the value is the same, we may still want to push the lock change + if (valueInMillis === initialValue && lockedValue) { return; } onSubmit(newValue); setValue(Number(newValue)); }, - [initialValue, onSubmit], + [initialValue, lockedValue, onSubmit], ); // duration times have a special format @@ -77,6 +79,7 @@ export default function TimeInputDuration(props: TimeInputDurationProps) {