feat: feature/mvp-sprint-1 Fixed nested path not being reactive when setThingtime is run

This commit is contained in:
Nikolaj Frey 2023-07-24 11:36:25 +10:00
parent 39a0973b7c
commit cda2a88ba3
4 changed files with 108 additions and 68 deletions

View File

@ -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,

View File

@ -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)

View File

@ -183,9 +183,9 @@ export const Rainbow = (allProps: any): JSX.Element => {
const render = true
useTrace("Rainbow", {
props,
})
// useTrace("Rainbow", {
// props,
// })
return (
<>

View File

@ -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 <Box onClick={() => setCircular(false)}>Click to Expand</Box>
return (
<Box cursor="pointer" onClick={() => setCircular(false)}>
Click to Expand
</Box>
)
}
} else {
return "Something!"
@ -271,7 +279,7 @@ export const Thingtime = (props) => {
}, 1)
}}
>
<Switch colorScheme="red" isChecked={thing}></Switch>
<Switch isChecked={thing}></Switch>
</Box>
</AtomicWrapper>
)