From 3ee35659cea374374e1672f8853ddbe9f6efcfd4 Mon Sep 17 00:00:00 2001
From: rlazarini <remi.lazarini@cea.fr>
Date: Tue, 26 Mar 2024 10:48:46 +0100
Subject: [PATCH] [dome/forms] fix useForceUpdate() + commited state added to
 useBuffer() + status function added for fieldState

---
 ivette/src/dome/renderer/dome.tsx         |  4 +-
 ivette/src/dome/renderer/layout/forms.tsx | 57 +++++++++++++++++++----
 2 files changed, 51 insertions(+), 10 deletions(-)

diff --git a/ivette/src/dome/renderer/dome.tsx b/ivette/src/dome/renderer/dome.tsx
index a2922165005..4e3378c960a 100644
--- a/ivette/src/dome/renderer/dome.tsx
+++ b/ivette/src/dome/renderer/dome.tsx
@@ -562,8 +562,8 @@ export function popupMenu(
    Returns a callback to trigger a render on demand.
 */
 export function useForceUpdate(): () => void {
-  const [tac, onTic] = React.useState(false);
-  return () => onTic(!tac);
+  const [, onTic] = React.useState(false);
+  return React.useCallback(() => onTic((tac) => !tac), []);
 }
 
 /**
diff --git a/ivette/src/dome/renderer/layout/forms.tsx b/ivette/src/dome/renderer/layout/forms.tsx
index 8a99feaabea..30ce592c92d 100644
--- a/ivette/src/dome/renderer/layout/forms.tsx
+++ b/ivette/src/dome/renderer/layout/forms.tsx
@@ -115,6 +115,33 @@ function isValidArray(err: FieldError[]): boolean {
   return true;
 }
 
+/**
+ * A fieldState can be stable or unstable.
+ *
+ * A stable fieldState means that the value of the field valid
+ * and has no reset value.
+ *
+ * There are three cases of an unstable fieldState :
+ * - Error : There is an error in the field.
+ * - Resetable : The fieldState has a reset value.
+ * - Commitable : The fieldState has a reset value and is valid (!Error).
+ */
+export function isError<A>( state: FieldState<A> ): boolean {
+  return !isValid(state.error);
+}
+
+export function isResetAble<A>( state: FieldState<A> ): boolean {
+  return state.reset !== undefined;
+}
+
+export function isCommitAble<A>( state: FieldState<A> ): boolean {
+  return isResetAble(state) && !isError(state);
+}
+
+export function isStable<A>( state: FieldState<A> ): boolean {
+  return !isResetAble(state) && !isError(state);
+}
+
 /* -------------------------------------------------------------------------- */
 /* --- Buffer Controller                                                  --- */
 /* -------------------------------------------------------------------------- */
@@ -241,11 +268,12 @@ export function useBuffer<A>(
   equal?: Equal<A>,
 ): FieldState<A> {
   const { value, error, reset, onChanged } = state;
-  const [modified, setModified] = React.useState(false);
-  const [buffer, setBuffer] = React.useState<A>(value);
-  const [berror, setBerror] = React.useState<FieldError>(error);
+  const [ modified, setModified ] = React.useState(false);
+  const [ commited, setCommited ] = React.useState(false);
+  const [ buffer, setBuffer ] = React.useState<A>(value);
+  const [ berror, setBerror ] = React.useState<FieldError>(error);
 
-  const valid = !isValid(berror);
+  const valid = isValid(berror);
   const rollback = reset ?? value;
 
   // --- Error Count
@@ -255,6 +283,17 @@ export function useBuffer<A>(
     return () => remote.removeError();
   }, [remote, valid]);
 
+  /* TODO :
+   * add a timeout to handle the case where the server takes
+   * this old value before the new value is returned to the field.
+   */
+  React.useEffect(() => {
+    setCommited((val) => {
+      if(!val) setModified(false);
+      return true;
+    });
+  }, [value]);
+
   // --- Reset
   React.useEffect(() => {
     if (modified) {
@@ -273,7 +312,7 @@ export function useBuffer<A>(
     if (modified) {
       const doCommit = (): void => {
         if (valid) {
-          setModified(false);
+          setCommited(false);
           onChanged(buffer, undefined, false);
         } else {
           setModified(false);
@@ -292,13 +331,15 @@ export function useBuffer<A>(
       setModified(!isReset);
       setBuffer(newValue);
       setBerror(newError);
-      if (isReset && !compare(equal, newValue, value))
+      if (isReset && !compare(equal, newValue, value)) {
+        setCommited(false);
         onChanged(newValue, newError, isReset);
+      }
     }, [equal, value, onChanged]);
 
   return {
-    value: modified ? buffer : value,
-    error: modified ? berror : error,
+    value: modified || !commited ? buffer : value,
+    error: modified || !commited ? berror : error,
     reset: reset ?? (modified ? value : undefined),
     onChanged: onLocalChange,
   };
-- 
GitLab