refactor: allow submitting same value

This commit is contained in:
Carlos Valente
2024-12-21 12:39:46 +01:00
committed by Carlos Valente
parent b173b5a8e8
commit b38a7e5c92
4 changed files with 52 additions and 27 deletions
@@ -16,6 +16,7 @@ export default function useReactiveTextInput(
submitOnEnter?: boolean; submitOnEnter?: boolean;
submitOnCtrlEnter?: boolean; submitOnCtrlEnter?: boolean;
onCancelUpdate?: () => void; onCancelUpdate?: () => void;
allowSubmitSameValue?: boolean;
}, },
): UseReactiveTextInputReturn { ): UseReactiveTextInputReturn {
const [text, setText] = useState<string>(initialText); const [text, setText] = useState<string>(initialText);
@@ -48,7 +49,7 @@ export default function useReactiveTextInput(
const handleSubmit = useCallback( const handleSubmit = useCallback(
(valueToSubmit: string) => { (valueToSubmit: string) => {
// No need to update if it hasn't changed // No need to update if it hasn't changed
if (valueToSubmit === initialText) { if (valueToSubmit === initialText && !options?.allowSubmitSameValue) {
options?.onCancelUpdate?.(); options?.onCancelUpdate?.();
} else { } else {
const cleanVal = valueToSubmit.trim(); const cleanVal = valueToSubmit.trim();
+41 -22
View File
@@ -225,38 +225,32 @@ export const useEventAction = () => {
*/ */
const updateTimer = useCallback( const updateTimer = useCallback(
async (eventId: string, field: TimeField, value: string, lockOnUpdate?: boolean) => { async (eventId: string, field: TimeField, value: string, lockOnUpdate?: boolean) => {
let newValMillis = 0; // an empty value with no lock has no domain validity
if (!lockOnUpdate && value === '') {
// check for previous keyword return;
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 const newEvent: Partial<OntimeEvent> = {
const cappedMillis = Math.min(newValMillis, dayInMs - MILLIS_PER_SECOND);
const newEvent = {
id: eventId, id: eventId,
[field]: cappedMillis,
}; };
// check if we should lock the field // check if we should lock the field
if (lockOnUpdate) { if (lockOnUpdate) {
if (field === 'timeEnd') { 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') { } else if (field === 'duration') {
newEvent.timeStrategy = TimeStrategy.LockDuration; // an empty value indicates that we should unlock the field
} else if (field === 'timeStart' && value === '') { newEvent.timeStrategy = value === '' ? TimeStrategy.LockEnd : TimeStrategy.LockDuration;
// if user removes the time start, we should link to the previous newEvent.duration = value === '' ? undefined : calculateNewValue();
newEvent.linkStart = 'true'; } 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 { try {
@@ -265,6 +259,31 @@ export const useEventAction = () => {
logAxiosError('Error updating event', error); 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 { function getPreviousEnd(): number {
const cachedRundown = queryClient.getQueryData<RundownCached>(RUNDOWN); const cachedRundown = queryClient.getQueryData<RundownCached>(RUNDOWN);
@@ -5,16 +5,18 @@ import useReactiveTextInput from '../../../../common/components/input/text-input
interface SingleLineCellProps { interface SingleLineCellProps {
initialValue: string; initialValue: string;
allowSubmitSameValue?: boolean;
handleUpdate: (newValue: string) => void; handleUpdate: (newValue: string) => void;
handleCancelUpdate?: () => void; handleCancelUpdate?: () => void;
} }
const SingleLineCell = forwardRef((props: SingleLineCellProps, inputRef) => { const SingleLineCell = forwardRef((props: SingleLineCellProps, inputRef) => {
const { initialValue, handleUpdate, handleCancelUpdate } = props; const { initialValue, allowSubmitSameValue, handleUpdate, handleCancelUpdate } = props;
const ref = useRef<HTMLInputElement | null>(null); const ref = useRef<HTMLInputElement | null>(null);
const submitCallback = useCallback((newValue: string) => handleUpdate(newValue), [handleUpdate]); const submitCallback = useCallback((newValue: string) => handleUpdate(newValue), [handleUpdate]);
const { value, onChange, onBlur, onKeyDown } = useReactiveTextInput(initialValue, submitCallback, ref, { const { value, onChange, onBlur, onKeyDown } = useReactiveTextInput(initialValue, submitCallback, ref, {
allowSubmitSameValue,
submitOnEnter: true, // single line should submit on enter submitOnEnter: true, // single line should submit on enter
submitOnCtrlEnter: true, submitOnCtrlEnter: true,
onCancelUpdate: handleCancelUpdate, onCancelUpdate: handleCancelUpdate,
@@ -41,8 +41,9 @@ export default function TimeInputDuration(props: TimeInputDurationProps) {
(newValue: string) => { (newValue: string) => {
setIsEditing(false); setIsEditing(false);
// Check if there is anything there // if the user sends an empty string, we want to clear the value
if (newValue === '') { if (newValue === '') {
onSubmit(newValue);
return; return;
} }
@@ -59,14 +60,15 @@ export default function TimeInputDuration(props: TimeInputDurationProps) {
return; return;
} }
if (valueInMillis === initialValue) { // if the value is the same, we may still want to push the lock change
if (valueInMillis === initialValue && lockedValue) {
return; return;
} }
onSubmit(newValue); onSubmit(newValue);
setValue(Number(newValue)); setValue(Number(newValue));
}, },
[initialValue, onSubmit], [initialValue, lockedValue, onSubmit],
); );
// duration times have a special format // duration times have a special format
@@ -77,6 +79,7 @@ export default function TimeInputDuration(props: TimeInputDurationProps) {
<SingleLineCell <SingleLineCell
ref={inputRef} ref={inputRef}
initialValue={timeString} initialValue={timeString}
allowSubmitSameValue={!lockedValue} // if the value is not locked, submitting will lock the value
handleUpdate={handleUpdate} handleUpdate={handleUpdate}
handleCancelUpdate={handleFakeBlur} handleCancelUpdate={handleFakeBlur}
/> />