Conversation
…mes early adopter to early access.
ErikSin
left a comment
There was a problem hiding this comment.
I think we can get ride of the provider completely and hold all the state in observationsList/index.tsx. Because it is a tab IT always remain mounted, so if the user sets state in that page, that state does not reset when the user navigates away (like it normally does in react). So therefore we dont actually need a context to hold the state.
Eg:
export function ObservationList(){
const isEarlyAccessEnabled = useEarlyAccessState(s => s.isEarlyAccessEnabled);
const [filterMode, setFilterMode] = React.useState<'all' | 'mine'>('all');
const lastInteractionRef = React.useRef<number | null>(null);
useFocusEffect(
// check on every navigation event back to this page whether it has been an hour and the filter should reset
React.useCallback(() => {
if (
lastInteractionRef.current !== null &&
Date.now() - lastInteractionRef.current > 1_HOUR
) {
setFilterMode('all');
lastInteractionRef.current = null;
}
}, []),
);
function handleFilterModeChange(mode: 'all' | 'mine'){
setFilterMode(mode);
lastInteractionRef.current = Date.now();
{
const filteredData = //filtered data here
return (
{isEarlyAccessEnabled && (
<ObservationFilterToggle
filterMode={filterMode}
onFilterModeChange={handleFilterModeChange}
/>
)}
< observations={filteredData}
...REST OF OBSERVATION LIST />
)
}What do you think? This feel a little more verbose, but simpler architecturally
| createJSONStorage, | ||
| persist as createPersistedState, | ||
| } from 'zustand/middleware'; | ||
| import * as v from 'valibot'; |
There was a problem hiding this comment.
I don't think we should use a persisted store here. The requirement is that when the app resets, the state reset (it goes back to showing all observations). In otherwords it does not need to know the state before it was reset since its alway shows all observations and therefore, the state does not need to be persisted.
| <EarlyAccessStoreProvider | ||
| value={earlyAccessStore}> | ||
| <AuthProvider>{children}</AuthProvider> | ||
| <ObservationFilterStoreProvider |
There was a problem hiding this comment.
I think we should scope this provider. The ObservationFilterStoreProvider is only being used by the observation list, so lets just wrap the observation list in this context so its not being consumed by the entire app
There was a problem hiding this comment.
Upon further thought, I don't think we need a provider. The state can live all in the observation list
| React.useEffect(() => { | ||
| if (isEarlyAccessEnabled) { | ||
| checkAndResetIfNeeded(); | ||
| } | ||
| }, [isEarlyAccessEnabled, checkAndResetIfNeeded]); |
There was a problem hiding this comment.
this check should happen everytime the user is navigated back to this page. The requirement is that it should reset every hour. Right now it will only reset if early access is enabled or disabled.
There could be the case where the user is on this page for over an hour (and hasn't navigated away and back to this page). If thats the case, it wont reset, but I think that is ok. We would have to create a timer, which feel like overkill and I think it ok to just check on navigation events.
|
@ErikSin, I am afraid to say I didn't realize the state was not reset when the user navigated away! So I think your solution is a great one given that truth. |
I only know this from spending DAYS trying to figure out why the location hook we were using in the map screen was not unmounting when the user navigated away. |
ErikSin
left a comment
There was a problem hiding this comment.
It looks good. Sorry you had to go through the work of creating and deleting the provider, but the subsequent changes are architecturally really simple which is nice.
1 minor problem, but not a blocker
| setFilterMode('all'); | ||
| lastInteractionRef.current = null; | ||
| } | ||
| }, []), | ||
| ); | ||
|
|
||
| React.useEffect(() => { | ||
| if (!isEarlyAccessEnabled) { | ||
| setFilterMode('all'); | ||
| lastInteractionRef.current = null; | ||
| } | ||
| }, [isEarlyAccessEnabled]); | ||
|
|
||
| function handleFilterModeChange(mode: 'all' | 'mine') { | ||
| setFilterMode(mode); | ||
| lastInteractionRef.current = Date.now(); |
There was a problem hiding this comment.
There is a slight discrepancy in how we are setting the lastInteractionRef. In the useFocusEffect and the useEffect when filterMode is being set to all we are setting lastInteractionRef to null. In the handleFilterModeChange we are setting lastInteractionRef to a date regardless.
I think the best would be to just change it in handleFilterModeChange
eg:
function handleFilterModeChange(mode: 'all' | 'mine') {
setFilterMode(mode);
lastInteractionRef.current = mode === 'mine' ? Date.now() : null;
}| React.useEffect(() => { | ||
| if (!isEarlyAccessEnabled) { | ||
| setFilterMode('all'); | ||
| lastInteractionRef.current = null; | ||
| } | ||
| }, [isEarlyAccessEnabled]); |
There was a problem hiding this comment.
Sorry, one more thing, I think we can get rid of this useEffect entitely. I think the filteredData handles the early access state.
If the user had it filterMode set to 'mine' and then turned off the early access, the state would not be reset (but the user would still see ALL observations). And then if they turn early access on again (before 1 hour has passed), THEN the state would be set to 'mine' which i don't think is a problem
added on top of #1782
closes #1711
Summary
Implementation details
ObservationFilterContext(Zustand + MMKV persistence) manages filter statecreatedByfield on observation/track documents to match the current device IDTesting
tests/e2e/specs/observations/observation-filter-toggle.test.ts) covering:docs/EndToEndTests/Observations.mdScreenshots
No Toggle (no early access)
All

Just You
