From cda2a88ba3a1320e9be2a44770ef9d5e79b1b979 Mon Sep 17 00:00:00 2001 From: Nikolaj Frey Date: Mon, 24 Jul 2023 11:36:25 +1000 Subject: [PATCH] feat: feature/mvp-sprint-1 Fixed nested path not being reactive when setThingtime is run --- remix/app/Providers/ThingtimeProvider.tsx | 120 ++++++++++++------- remix/app/components/Commander/Commander.tsx | 34 +++--- remix/app/components/Rainbow/Rainbow.tsx | 6 +- remix/app/components/Thingtime/Thingtime.tsx | 16 ++- 4 files changed, 108 insertions(+), 68 deletions(-) diff --git a/remix/app/Providers/ThingtimeProvider.tsx b/remix/app/Providers/ThingtimeProvider.tsx index 7ac29c2..950c9b7 100644 --- a/remix/app/Providers/ThingtimeProvider.tsx +++ b/remix/app/Providers/ThingtimeProvider.tsx @@ -83,54 +83,77 @@ const initialThingtime = smarts.merge(initialValues, force) // console.error("Caught error restoring thingtime from localstorage", err) // } +initialThingtime.thingtime = initialThingtime +initialThingtime.tt = initialThingtime + export const ThingtimeProvider = (props: any): JSX.Element => { const [thingtime, rawSet] = React.useState(initialThingtime) - const set = React.useCallback((newThingtime) => { - newThingtime.tt = newThingtime - newThingtime.thingtime = newThingtime - rawSet(newThingtime) - }, []) - const thingtimeRef = React.useRef(thingtime) const stateRef = React.useRef({ c: 1, }) + const set = React.useCallback((newThingtime) => { + const thingtimeReference = { + ...newThingtime, + } + + thingtimeReference.tt = thingtimeReference + thingtimeReference.thingtime = thingtimeReference + rawSet(thingtimeReference) + }, []) + const setThingtime = React.useCallback( (path, value) => { - const prevThingtime = thingtime + const newThingtime = thingtime - const newThingtime = { - ...prevThingtime, - } + const paths = smarts.parsePropertyPath(path) - newThingtime.tt = newThingtime - newThingtime.thingtime = newThingtime + console.log("nik paths", paths) - // check if first characters of path starts with thingtime or tt and strip from path + // find first parent where a path is undefined + // paths is array of path parts such as ["path1", "path2", "path3"] + // we want to create a new reference at the first object which has an undefined part of the path + // and is an object itself + // so that react will detect the change and re-render + // "path1" = { ...thingtime["path1"] } if path1.path2 undefined + // "path1.path2" = { ...thingtime["path1"]["path2"] } if path1.path2.path3 undefined + // "path1.path2.path3" = { ...thingtime["path1"]["path2"]["path3"] } + // etc + let done = false + paths.forEach((pathPart, index) => { + if (!done) { + const pathParts = paths.slice(0, index + 1) + const tmpPath = pathParts.join(".") + const parentPath = pathParts.slice(0, -1).join(".") - // path = sanitise(path) + const valAtPath = smarts.getsmart(newThingtime, tmpPath) - console.log("nik setting newThingtime value at path", path, value) + if (parentPath) { + if (typeof valAtPath !== "object" || valAtPath === null) { + const parentVal = smarts.getsmart(newThingtime, parentPath) + if (typeof parentVal === "object") { + const newParent = Array.isArray(parentVal) + ? [...parentVal] + : { ...parentVal } + smarts.setsmart(newThingtime, parentPath, newParent) + } + done = true + } + } + } + }) + + console.log( + "nik setting newThingtime value at path", + path, + "value: ", + value + ) smarts.setsmart(newThingtime, path, value) - // subtract last path part from dot delimitted path - // prop1.prop2.prop3 => prop1.prop2 - const pathParts = path.split(".") - pathParts.pop() - const parentPath = pathParts.join(".") - - if (parentPath?.length) { - console.log("nik updating parentPath dependancies", parentPath) - const parent = smarts.getsmart(newThingtime, parentPath) - - const newParent = Array.isArray(parent) ? [...parent] : { ...parent } - - smarts.setsmart(newThingtime, parentPath, newParent) - } - set(newThingtime) }, [thingtime, set] @@ -150,19 +173,23 @@ export const ThingtimeProvider = (props: any): JSX.Element => { ) const populatePaths = React.useCallback((obj, path, paths, seen = []) => { - Object.keys(obj).forEach((key) => { - const val = obj[key] - const newPath = path ? `${path}${path ? "." : ""}${key}` : key - if (typeof val === "object") { - paths.push(newPath) - if (!seen?.includes(val)) { - seen.push(val) - populatePaths(val, newPath, paths, seen) + try { + Object.keys(obj).forEach((key) => { + const val = obj[key] + const newPath = path ? `${path}${path ? "." : ""}${key}` : key + if (typeof val === "object") { + paths.push(newPath) + if (!seen?.includes(val)) { + seen.push(val) + populatePaths(val, newPath, paths, seen) + } + } else { + paths.push(newPath) } - } else { - paths.push(newPath) - } - }) + }) + } catch { + // nothing + } }, []) const paths = React.useMemo(() => { @@ -180,6 +207,8 @@ export const ThingtimeProvider = (props: any): JSX.Element => { try { const thingtimeFromLocalStorage = window.localStorage.getItem("thingtime") + console.log("nik thingtimeFromLocalStorage", thingtimeFromLocalStorage) + if (thingtimeFromLocalStorage) { const parsed = parse(thingtimeFromLocalStorage) if (parsed) { @@ -192,7 +221,10 @@ export const ThingtimeProvider = (props: any): JSX.Element => { const withVersionUpdates = smarts.merge(newVersionData, parsed) newThingtime = smarts.merge(force, withVersionUpdates) } - console.log("nik setting new thingtime", newThingtime) + console.log( + "nik setting new thingtime from localStorage", + newThingtime + ) console.log("nik localIsValid", localIsValid) set(newThingtime) } @@ -249,7 +281,7 @@ export const ThingtimeProvider = (props: any): JSX.Element => { return () => { window.removeEventListener("keydown", keyListener) } - }, [setThingtime, thingtime]) + }, [setThingtime, thingtime, set]) const value = { thingtime, diff --git a/remix/app/components/Commander/Commander.tsx b/remix/app/components/Commander/Commander.tsx index f6a0300..cf02e55 100644 --- a/remix/app/components/Commander/Commander.tsx +++ b/remix/app/components/Commander/Commander.tsx @@ -48,7 +48,7 @@ export const Commander = (props) => { return thingtime?.settings?.commanderActive }, [thingtime?.settings?.commanderActive]) - console.log("nik commanderActive", commanderActive) + // console.log("nik commanderActive", commanderActive) // commanderActive useEffect React.useEffect(() => { @@ -109,7 +109,7 @@ export const Commander = (props) => { ] return [pathRaw?.trim(), valRaw?.trim()] } - console.log("nik sanitizedCommand", sanitizedCommand) + // console.log("nik sanitizedCommand", sanitizedCommand) return [sanitizedCommand] }, [ // inputValue, @@ -180,28 +180,28 @@ export const Commander = (props) => { ) const commandContainsPath = React.useMemo(() => { - console.log("nik command", commandPath) - console.log("nik suggestions", suggestions) + // console.log("nik command", commandPath) + // console.log("nik suggestions", suggestions) const commandIncludesSuggestion = suggestions?.find((suggestion) => { return commandPath?.includes(suggestion) }) - console.log("nik commandIncludesSuggestion", commandIncludesSuggestion) + // console.log("nik commandIncludesSuggestion", commandIncludesSuggestion) // return false return commandIncludesSuggestion }, [commandPath, suggestions]) const openCommander = React.useCallback(() => { - console.log("nik commander opening commander") + // console.log("nik commander opening commander") setThingtime("settings.commanderActive", true) }, [setThingtime]) const closeCommander = React.useCallback( (e?: any) => { if (!e?.defaultPrevented) { - console.log("nik 123123 commander event closeCommander ", e) + // console.log("nik 123123 commander event closeCommander ", e) if (thingtime?.settings?.commanderActive) { - console.log("nik commander closing commander") - console.log("nik setting commanderActive to false") + // console.log("nik commander closing commander") + // console.log("nik setting commanderActive to false") setThingtime("settings.commanderActive", false) } } @@ -261,11 +261,11 @@ export const Commander = (props) => { } if (commanderActive) { try { - console.log("nik Commander onEnter") - console.log("nik commandIsAction", commandIsAction) - console.log("nik commandContainsPath", commandContainsPath) + // console.log("nik Commander onEnter") + // console.log("nik commandIsAction", commandIsAction) + // console.log("nik commandContainsPath", commandContainsPath) - console.log("nik onEnter commandPath", commandPath) + // console.log("nik onEnter commandPath", commandPath) if (commandIsAction) { // nothing @@ -276,10 +276,10 @@ export const Commander = (props) => { const realVal = evalFn() const prevVal = getThingtime(commandPath) const parentPath = getParentPath(commandPath) - console.log("nik realVal", realVal) - console.log("nik prevVal", prevVal) - console.log("nik parentPath", parentPath) - console.log("nik commandPath", commandPath) + // console.log("nik realVal", realVal) + // console.log("nik prevVal", prevVal) + // console.log("nik parentPath", parentPath) + // console.log("nik commandPath", commandPath) setThingtime(commandPath, realVal) if (!prevVal) { setContextPath(parentPath) diff --git a/remix/app/components/Rainbow/Rainbow.tsx b/remix/app/components/Rainbow/Rainbow.tsx index 8e406f4..8e2de6e 100644 --- a/remix/app/components/Rainbow/Rainbow.tsx +++ b/remix/app/components/Rainbow/Rainbow.tsx @@ -183,9 +183,9 @@ export const Rainbow = (allProps: any): JSX.Element => { const render = true - useTrace("Rainbow", { - props, - }) + // useTrace("Rainbow", { + // props, + // }) return ( <> diff --git a/remix/app/components/Thingtime/Thingtime.tsx b/remix/app/components/Thingtime/Thingtime.tsx index b424833..91c0d1a 100644 --- a/remix/app/components/Thingtime/Thingtime.tsx +++ b/remix/app/components/Thingtime/Thingtime.tsx @@ -73,8 +73,12 @@ export const Thingtime = (props) => { const keys = React.useMemo(() => { if (validKeyTypes?.includes(typeof thing)) { - const keysRet = Object.keys(thing) - return keysRet + try { + const keysRet = Object.keys(thing) + return keysRet + } catch { + // nothing + } } else { return [] } @@ -136,7 +140,11 @@ export const Thingtime = (props) => { // err, // thing // ) - return setCircular(false)}>Click to Expand + return ( + setCircular(false)}> + Click to Expand + + ) } } else { return "Something!" @@ -271,7 +279,7 @@ export const Thingtime = (props) => { }, 1) }} > - + )