From 3bf73fe4750f59e1b5615614894e9645334c6ba6 Mon Sep 17 00:00:00 2001
From: lenisko <10072920+lenisko@users.noreply.github.com>
Date: Mon, 15 Dec 2025 23:48:12 +0100
Subject: [PATCH 1/3] feat: hidden persistence
---
packages/locales/lib/human/en.json | 2 +
packages/locales/lib/human/pl.json | 2 +
src/features/drawer/settings/index.jsx | 11 ++
src/features/gym/GymPopup.jsx | 4 +-
src/features/nest/NestPopup.jsx | 4 +-
src/features/pokemon/PokemonPopup.jsx | 3 +-
src/features/pokestop/PokestopPopup.jsx | 4 +-
src/features/station/StationPopup.jsx | 9 +-
src/features/tappable/TappablePopup.jsx | 9 +-
src/store/useMemory.js | 4 +-
src/utils/pokemon/hiddenPokemon.js | 155 ++++++++++++++++++++++++
11 files changed, 194 insertions(+), 13 deletions(-)
create mode 100644 src/utils/pokemon/hiddenPokemon.js
diff --git a/packages/locales/lib/human/en.json b/packages/locales/lib/human/en.json
index b99cb961e..966dcfd7f 100644
--- a/packages/locales/lib/human/en.json
+++ b/packages/locales/lib/human/en.json
@@ -138,6 +138,8 @@
"exclude_lure": "Exclude Lure",
"timer": "Timer",
"hide": "Hide",
+ "hidden_for_hour": "Hidden for an hour",
+ "clean_hidden": "Clean Hidden",
"tier": "Tier",
"slots": "Slots",
"mega": "Mega",
diff --git a/packages/locales/lib/human/pl.json b/packages/locales/lib/human/pl.json
index 077c4b17b..cf3310edf 100644
--- a/packages/locales/lib/human/pl.json
+++ b/packages/locales/lib/human/pl.json
@@ -228,6 +228,8 @@
"has_quest_indicator": "Alternatywny kolor dla Pokéstopów z zadaniami",
"help": "Pomoc",
"hide": "Ukryj",
+ "hidden_for_hour": "Schowano na godzinę",
+ "clean_hidden": "Wyczyść schowane",
"hide_editor": "Ukryj edytor",
"historic_rarity": "Rzadkość historyczna",
"hisuian": "Hisuian",
diff --git a/src/features/drawer/settings/index.jsx b/src/features/drawer/settings/index.jsx
index 69254ecb8..875e5691e 100644
--- a/src/features/drawer/settings/index.jsx
+++ b/src/features/drawer/settings/index.jsx
@@ -9,6 +9,7 @@ import InsightsIcon from '@mui/icons-material/Insights'
import NotificationsActiveIcon from '@mui/icons-material/NotificationsActive'
import NotificationsOffIcon from '@mui/icons-material/NotificationsOff'
import LogoDevIcon from '@mui/icons-material/LogoDev'
+import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'
import { useTranslation } from 'react-i18next'
import { useMemory } from '@store/useMemory'
@@ -22,6 +23,7 @@ import { LocaleSelection } from '@components/inputs/LocaleSelection'
import { DividerWithMargin } from '@components/StyledDivider'
import { BoolToggle } from '@components/inputs/BoolToggle'
import { BasicListButton } from '@components/inputs/BasicListButton'
+import { clearHiddenEntities } from '@utils/pokemon/hiddenPokemon'
import { DrawerActions } from '../components/Actions'
import { GeneralSetting } from './General'
@@ -70,6 +72,15 @@ export function Settings() {
)}
+ {
+ clearHiddenEntities()
+ useMemory.setState({ hideList: new Set() })
+ }}
+ label="clean_hidden"
+ >
+
+
diff --git a/src/features/gym/GymPopup.jsx b/src/features/gym/GymPopup.jsx
index a05b62b33..e64b143d2 100644
--- a/src/features/gym/GymPopup.jsx
+++ b/src/features/gym/GymPopup.jsx
@@ -37,6 +37,7 @@ import { getTimeUntil } from '@utils/getTimeUntil'
import { formatInterval } from '@utils/formatInterval'
import { usePokemonBackgroundVisuals } from '@hooks/usePokemonBackgroundVisuals'
import { getFormDisplay } from '@utils/getFormDisplay'
+import { addHiddenEntity, showHideSnackbar } from '@utils/pokemon/hiddenPokemon'
import { useWebhook } from './useWebhook'
@@ -747,7 +748,8 @@ const DropdownOptions = ({
const handleHide = () => {
handleClose()
- useMemory.setState((prev) => ({ hideList: new Set(prev.hideList).add(id) }))
+ useMemory.setState({ hideList: addHiddenEntity(id) })
+ showHideSnackbar(t('hidden_for_hour'))
}
const handleExclude = (key) => {
diff --git a/src/features/nest/NestPopup.jsx b/src/features/nest/NestPopup.jsx
index 35c55c377..7324e2e7d 100644
--- a/src/features/nest/NestPopup.jsx
+++ b/src/features/nest/NestPopup.jsx
@@ -16,6 +16,7 @@ import { setDeepStore } from '@store/useStorage'
import { getTimeUntil } from '@utils/getTimeUntil'
import { useAnalytics } from '@hooks/useAnalytics'
import { Navigation } from '@components/popups/Navigation'
+import { addHiddenEntity, showHideSnackbar } from '@utils/pokemon/hiddenPokemon'
/** @param {number} timeSince */
const getColor = (timeSince) => {
@@ -62,7 +63,8 @@ export function NestPopup({
const handleClose = () => setAnchorEl(null)
const handleHide = () => {
setAnchorEl(null)
- useMemory.setState((prev) => ({ hideList: new Set(prev.hideList).add(id) }))
+ useMemory.setState({ hideList: addHiddenEntity(id) })
+ showHideSnackbar(t('hidden_for_hour'))
}
const handleExclude = () => {
diff --git a/src/features/pokemon/PokemonPopup.jsx b/src/features/pokemon/PokemonPopup.jsx
index f88937713..87903e950 100644
--- a/src/features/pokemon/PokemonPopup.jsx
+++ b/src/features/pokemon/PokemonPopup.jsx
@@ -33,6 +33,7 @@ import { GET_TAPPABLE_BY_ID } from '@services/queries/tappable'
import { usePokemonBackgroundVisual } from '@hooks/usePokemonBackgroundVisuals'
import { BackgroundCard } from '@components/popups/BackgroundCard'
import { getFormDisplay } from '@utils/getFormDisplay'
+import { addHiddenEntity } from '@utils/pokemon/hiddenPokemon'
const rowClass = { width: 30, fontWeight: 'bold' }
@@ -357,7 +358,7 @@ const Header = ({ pokemon, metaData, iconUrl, userSettings, isTutorial }) => {
const handleHide = () => {
setAnchorEl(null)
- useMemory.setState((prev) => ({ hideList: new Set(prev.hideList).add(id) }))
+ useMemory.setState({ hideList: addHiddenEntity(id) })
}
const handleExclude = () => {
diff --git a/src/features/pokestop/PokestopPopup.jsx b/src/features/pokestop/PokestopPopup.jsx
index 14a9fbde9..7523f006b 100644
--- a/src/features/pokestop/PokestopPopup.jsx
+++ b/src/features/pokestop/PokestopPopup.jsx
@@ -35,6 +35,7 @@ import { useGetAvailable } from '@hooks/useGetAvailable'
import { parseQuestConditions } from '@utils/parseConditions'
import { Img } from '@components/Img'
import { readableProbability } from '@utils/readableProbability'
+import { addHiddenEntity, showHideSnackbar } from '@utils/pokemon/hiddenPokemon'
import {
usePokemonBackgroundVisuals,
usePokemonBackgroundVisual,
@@ -341,7 +342,8 @@ const MenuActions = ({
const handleHide = () => {
setAnchorEl(null)
- useMemory.setState((prev) => ({ hideList: new Set(prev.hideList).add(id) }))
+ useMemory.setState({ hideList: addHiddenEntity(id) })
+ showHideSnackbar(t('hidden_for_hour'))
}
/** @param {string} key */
diff --git a/src/features/station/StationPopup.jsx b/src/features/station/StationPopup.jsx
index 5b13d60ed..d32040747 100644
--- a/src/features/station/StationPopup.jsx
+++ b/src/features/station/StationPopup.jsx
@@ -27,6 +27,7 @@ import { Img, PokemonImg } from '@components/Img'
import { useFormatStore } from '@store/useFormatStore'
import { useRelativeTimer } from '@hooks/useRelativeTime'
import { useAnalytics } from '@hooks/useAnalytics'
+import { addHiddenEntity, showHideSnackbar } from '@utils/pokemon/hiddenPokemon'
import { BackgroundCard } from '@components/popups/BackgroundCard'
import { Title } from '@components/popups/Title'
import {
@@ -169,10 +170,10 @@ function StationMenu({
() => [
{
name: 'hide',
- action: () =>
- useMemory.setState((prev) => ({
- hideList: new Set(prev.hideList).add(id),
- })),
+ action: () => {
+ useMemory.setState({ hideList: addHiddenEntity(id) })
+ showHideSnackbar(t('hidden_for_hour'))
+ },
},
{
name: 'exclude_battle',
diff --git a/src/features/tappable/TappablePopup.jsx b/src/features/tappable/TappablePopup.jsx
index 0da263d43..d8d9bdc9e 100644
--- a/src/features/tappable/TappablePopup.jsx
+++ b/src/features/tappable/TappablePopup.jsx
@@ -20,6 +20,8 @@ import { StatusIcon } from '@components/StatusIcon'
import { Title } from '@components/popups/Title'
import { getTimeUntil } from '@utils/getTimeUntil'
+import { addHiddenEntity, showHideSnackbar } from '@utils/pokemon/hiddenPokemon'
+
import { getTappableDisplaySettings } from './displayRules'
/**
@@ -107,10 +109,9 @@ export function TappablePopup({ tappable, rewardIcon }) {
const handleHide = React.useCallback(() => {
setMenuAnchorEl(null)
if (tappable.id === undefined || tappable.id === null) return
- useMemory.setState((prev) => ({
- hideList: new Set(prev.hideList).add(tappable.id),
- }))
- }, [tappable.id])
+ useMemory.setState({ hideList: addHiddenEntity(tappable.id) })
+ showHideSnackbar(t('hidden_for_hour'))
+ }, [tappable.id, t])
const handleExclude = React.useCallback(() => {
setMenuAnchorEl(null)
diff --git a/src/store/useMemory.js b/src/store/useMemory.js
index d4ed1630c..18ff6c990 100644
--- a/src/store/useMemory.js
+++ b/src/store/useMemory.js
@@ -2,6 +2,8 @@
import { create } from 'zustand'
+import { getHiddenEntitySet } from '@utils/pokemon/hiddenPokemon'
+
/**
* TODO: Finish this
* @typedef {{
@@ -151,7 +153,7 @@ export const useMemory = create(() => ({
locationCards: {},
routeTypes: {},
},
- hideList: new Set(),
+ hideList: getHiddenEntitySet(),
timerList: [],
timeOfDay: 'day',
extraUserFields: [],
diff --git a/src/utils/pokemon/hiddenPokemon.js b/src/utils/pokemon/hiddenPokemon.js
new file mode 100644
index 000000000..0a87b22e5
--- /dev/null
+++ b/src/utils/pokemon/hiddenPokemon.js
@@ -0,0 +1,155 @@
+// @ts-check
+
+const STORAGE_KEY = 'pokemon-hide-list'
+const SNACKBAR_COUNT_KEY = 'pokemon-hide-snackbar-count'
+const MAX_AGE_MS = 60 * 60 * 1000 // 1 hour
+const MAX_SNACKBAR_SHOWS = 3
+
+/**
+ * @typedef {{ id: string | number, ts: number }} HiddenEntry
+ */
+
+/**
+ * Load hidden Pokemon entries from localStorage
+ * @returns {HiddenEntry[]}
+ */
+function loadEntries() {
+ try {
+ const raw = localStorage.getItem(STORAGE_KEY)
+ if (!raw) return []
+ const parsed = JSON.parse(raw)
+ return Array.isArray(parsed) ? parsed : []
+ } catch {
+ return []
+ }
+}
+
+/**
+ * Save hidden Pokemon entries to localStorage
+ * @param {HiddenEntry[]} entries
+ */
+function saveEntries(entries) {
+ try {
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(entries))
+ } catch {
+ // localStorage may be full or disabled
+ }
+}
+
+/**
+ * Clean entries older than 1 hour
+ * @param {HiddenEntry[]} entries
+ * @returns {HiddenEntry[]}
+ */
+function cleanOldEntries(entries) {
+ const now = Date.now()
+ return entries.filter((e) => now - e.ts < MAX_AGE_MS)
+}
+
+/**
+ * Add an entity ID to the hidden list with timestamp, cleaning old entries
+ * @param {string | number} id
+ * @returns {Set} Updated hideList Set
+ */
+export function addHiddenEntity(id) {
+ const entries = cleanOldEntries(loadEntries())
+ if (!entries.some((e) => e.id === id)) {
+ entries.push({ id, ts: Date.now() })
+ }
+ saveEntries(entries)
+ return new Set(entries.map((e) => e.id))
+}
+
+/**
+ * Get the current hidden entity Set from localStorage (cleaned)
+ * @returns {Set}
+ */
+export function getHiddenEntitySet() {
+ const entries = cleanOldEntries(loadEntries())
+ saveEntries(entries) // persist cleaned list
+ return new Set(entries.map((e) => e.id))
+}
+
+/** @type {{ current: number | null }} */
+const snackbarTimer = { current: null }
+
+/** @type {{ current: HTMLDivElement | null }} */
+const snackbarRef = { current: null }
+
+/**
+ * Get snackbar show count from localStorage
+ * @returns {number}
+ */
+function getSnackbarCount() {
+ try {
+ return parseInt(localStorage.getItem(SNACKBAR_COUNT_KEY) || '0', 10)
+ } catch {
+ return 0
+ }
+}
+
+/**
+ * Increment snackbar show count in localStorage
+ */
+function incrementSnackbarCount() {
+ try {
+ const count = getSnackbarCount() + 1
+ localStorage.setItem(SNACKBAR_COUNT_KEY, String(count))
+ } catch {
+ // localStorage may be full or disabled
+ }
+}
+
+/**
+ * Show a temporary snackbar message for 2 seconds (max 3 times total)
+ * @param {string} message
+ */
+export function showHideSnackbar(message) {
+ if (getSnackbarCount() >= MAX_SNACKBAR_SHOWS) {
+ return
+ }
+
+ if (snackbarTimer.current) {
+ clearTimeout(snackbarTimer.current)
+ }
+ if (snackbarRef.current) {
+ snackbarRef.current.remove()
+ }
+
+ incrementSnackbarCount()
+
+ const snackbar = document.createElement('div')
+ snackbar.textContent = message
+ snackbar.style.cssText = `
+ position: fixed;
+ bottom: 24px;
+ left: 50%;
+ transform: translateX(-50%);
+ background: rgba(50, 50, 50, 0.95);
+ color: white;
+ padding: 8px 16px;
+ border-radius: 4px;
+ font-size: 14px;
+ z-index: 10000;
+ pointer-events: none;
+ `
+ document.body.appendChild(snackbar)
+ snackbarRef.current = snackbar
+
+ snackbarTimer.current = window.setTimeout(() => {
+ snackbar.remove()
+ snackbarRef.current = null
+ snackbarTimer.current = null
+ }, 2000)
+}
+
+/**
+ * Clear all hidden entities from localStorage
+ */
+export function clearHiddenEntities() {
+ try {
+ localStorage.removeItem(STORAGE_KEY)
+ } catch {
+ // localStorage may be disabled
+ }
+}
From 92fa16b90f971be5bd3ff80cc560907b9273fd59 Mon Sep 17 00:00:00 2001
From: lenisko <10072920+lenisko@users.noreply.github.com>
Date: Tue, 16 Dec 2025 02:14:18 +0100
Subject: [PATCH 2/3] fix: rename utils for cleanup fix: clean outdated storage
15s after map loads
---
src/features/drawer/settings/index.jsx | 2 +-
src/features/gym/GymPopup.jsx | 2 +-
src/features/nest/NestPopup.jsx | 2 +-
src/features/pokemon/PokemonPopup.jsx | 2 +-
src/features/pokestop/PokestopPopup.jsx | 2 +-
src/features/station/StationPopup.jsx | 2 +-
src/features/tappable/TappablePopup.jsx | 2 +-
src/pages/map/components/Container.jsx | 9 ++++++
src/store/useMemory.js | 2 +-
.../hiddenPokemon.js => hiddenEntities.js} | 31 +++++++++++++------
10 files changed, 39 insertions(+), 17 deletions(-)
rename src/utils/{pokemon/hiddenPokemon.js => hiddenEntities.js} (79%)
diff --git a/src/features/drawer/settings/index.jsx b/src/features/drawer/settings/index.jsx
index 875e5691e..d07f2eba6 100644
--- a/src/features/drawer/settings/index.jsx
+++ b/src/features/drawer/settings/index.jsx
@@ -23,7 +23,7 @@ import { LocaleSelection } from '@components/inputs/LocaleSelection'
import { DividerWithMargin } from '@components/StyledDivider'
import { BoolToggle } from '@components/inputs/BoolToggle'
import { BasicListButton } from '@components/inputs/BasicListButton'
-import { clearHiddenEntities } from '@utils/pokemon/hiddenPokemon'
+import { clearHiddenEntities } from '@utils/hiddenEntities'
import { DrawerActions } from '../components/Actions'
import { GeneralSetting } from './General'
diff --git a/src/features/gym/GymPopup.jsx b/src/features/gym/GymPopup.jsx
index e64b143d2..d7905ba56 100644
--- a/src/features/gym/GymPopup.jsx
+++ b/src/features/gym/GymPopup.jsx
@@ -37,7 +37,7 @@ import { getTimeUntil } from '@utils/getTimeUntil'
import { formatInterval } from '@utils/formatInterval'
import { usePokemonBackgroundVisuals } from '@hooks/usePokemonBackgroundVisuals'
import { getFormDisplay } from '@utils/getFormDisplay'
-import { addHiddenEntity, showHideSnackbar } from '@utils/pokemon/hiddenPokemon'
+import { addHiddenEntity, showHideSnackbar } from '@utils/hiddenEntities'
import { useWebhook } from './useWebhook'
diff --git a/src/features/nest/NestPopup.jsx b/src/features/nest/NestPopup.jsx
index 7324e2e7d..9df705834 100644
--- a/src/features/nest/NestPopup.jsx
+++ b/src/features/nest/NestPopup.jsx
@@ -16,7 +16,7 @@ import { setDeepStore } from '@store/useStorage'
import { getTimeUntil } from '@utils/getTimeUntil'
import { useAnalytics } from '@hooks/useAnalytics'
import { Navigation } from '@components/popups/Navigation'
-import { addHiddenEntity, showHideSnackbar } from '@utils/pokemon/hiddenPokemon'
+import { addHiddenEntity, showHideSnackbar } from '@utils/hiddenEntities'
/** @param {number} timeSince */
const getColor = (timeSince) => {
diff --git a/src/features/pokemon/PokemonPopup.jsx b/src/features/pokemon/PokemonPopup.jsx
index 87903e950..3fc5dbf2b 100644
--- a/src/features/pokemon/PokemonPopup.jsx
+++ b/src/features/pokemon/PokemonPopup.jsx
@@ -33,7 +33,7 @@ import { GET_TAPPABLE_BY_ID } from '@services/queries/tappable'
import { usePokemonBackgroundVisual } from '@hooks/usePokemonBackgroundVisuals'
import { BackgroundCard } from '@components/popups/BackgroundCard'
import { getFormDisplay } from '@utils/getFormDisplay'
-import { addHiddenEntity } from '@utils/pokemon/hiddenPokemon'
+import { addHiddenEntity } from '@utils/hiddenEntities'
const rowClass = { width: 30, fontWeight: 'bold' }
diff --git a/src/features/pokestop/PokestopPopup.jsx b/src/features/pokestop/PokestopPopup.jsx
index 7523f006b..772356add 100644
--- a/src/features/pokestop/PokestopPopup.jsx
+++ b/src/features/pokestop/PokestopPopup.jsx
@@ -35,7 +35,7 @@ import { useGetAvailable } from '@hooks/useGetAvailable'
import { parseQuestConditions } from '@utils/parseConditions'
import { Img } from '@components/Img'
import { readableProbability } from '@utils/readableProbability'
-import { addHiddenEntity, showHideSnackbar } from '@utils/pokemon/hiddenPokemon'
+import { addHiddenEntity, showHideSnackbar } from '@utils/hiddenEntities'
import {
usePokemonBackgroundVisuals,
usePokemonBackgroundVisual,
diff --git a/src/features/station/StationPopup.jsx b/src/features/station/StationPopup.jsx
index d32040747..05eb990f7 100644
--- a/src/features/station/StationPopup.jsx
+++ b/src/features/station/StationPopup.jsx
@@ -27,7 +27,7 @@ import { Img, PokemonImg } from '@components/Img'
import { useFormatStore } from '@store/useFormatStore'
import { useRelativeTimer } from '@hooks/useRelativeTime'
import { useAnalytics } from '@hooks/useAnalytics'
-import { addHiddenEntity, showHideSnackbar } from '@utils/pokemon/hiddenPokemon'
+import { addHiddenEntity, showHideSnackbar } from '@utils/hiddenEntities'
import { BackgroundCard } from '@components/popups/BackgroundCard'
import { Title } from '@components/popups/Title'
import {
diff --git a/src/features/tappable/TappablePopup.jsx b/src/features/tappable/TappablePopup.jsx
index d8d9bdc9e..0be0c0b0f 100644
--- a/src/features/tappable/TappablePopup.jsx
+++ b/src/features/tappable/TappablePopup.jsx
@@ -20,7 +20,7 @@ import { StatusIcon } from '@components/StatusIcon'
import { Title } from '@components/popups/Title'
import { getTimeUntil } from '@utils/getTimeUntil'
-import { addHiddenEntity, showHideSnackbar } from '@utils/pokemon/hiddenPokemon'
+import { addHiddenEntity, showHideSnackbar } from '@utils/hiddenEntities'
import { getTappableDisplaySettings } from './displayRules'
diff --git a/src/pages/map/components/Container.jsx b/src/pages/map/components/Container.jsx
index ffacef9a8..4aad52db4 100644
--- a/src/pages/map/components/Container.jsx
+++ b/src/pages/map/components/Container.jsx
@@ -9,6 +9,7 @@ import { ScanOnDemand } from '@features/scanner'
import { WebhookMarker, WebhookAreaSelection } from '@features/webhooks'
import { ActiveWeather } from '@features/weather'
import { timeCheck } from '@utils/timeCheck'
+import { cleanupHiddenEntities } from '@utils/hiddenEntities'
import { Effects } from './Effects'
import { DataView } from './Data'
@@ -38,6 +39,14 @@ const MAX_BOUNDS = /** @type {[[number, number], [number, number]]} */ ([
export function Container() {
const { location, zoom } = useStorage.getState()
+ // Cleanup hidden entities 15 seconds after map loads
+ React.useEffect(() => {
+ const timer = setTimeout(() => {
+ cleanupHiddenEntities(useMemory.setState)
+ }, 15000)
+ return () => clearTimeout(timer)
+ }, [])
+
return (
} Updated hideList Set
*/
export function addHiddenEntity(id) {
- const entries = cleanOldEntries(loadEntries())
+ const entries = loadEntries()
if (!entries.some((e) => e.id === id)) {
entries.push({ id, ts: Date.now() })
}
@@ -61,15 +61,28 @@ export function addHiddenEntity(id) {
}
/**
- * Get the current hidden entity Set from localStorage (cleaned)
+ * Get the current hidden entity Set from localStorage
* @returns {Set}
*/
export function getHiddenEntitySet() {
- const entries = cleanOldEntries(loadEntries())
- saveEntries(entries) // persist cleaned list
+ const entries = loadEntries()
return new Set(entries.map((e) => e.id))
}
+/**
+ * Clean outdated hidden entries (older than 1 hour) from localStorage
+ * Updates both localStorage and the in-memory hideList
+ * @param {(state: { hideList: Set }) => void} setState
+ */
+export function cleanupHiddenEntities(setState) {
+ const entries = loadEntries()
+ const cleaned = cleanOldEntries(entries)
+ if (cleaned.length !== entries.length) {
+ saveEntries(cleaned)
+ setState({ hideList: new Set(cleaned.map((e) => e.id)) })
+ }
+}
+
/** @type {{ current: number | null }} */
const snackbarTimer = { current: null }
From 1930da739b10ddba391ebc107247ed76595ec077 Mon Sep 17 00:00:00 2001
From: lenisko <10072920+lenisko@users.noreply.github.com>
Date: Sat, 20 Dec 2025 16:48:50 +0100
Subject: [PATCH 3/3] fix: clean hidden every 15s
---
src/pages/map/components/Container.jsx | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/src/pages/map/components/Container.jsx b/src/pages/map/components/Container.jsx
index 4aad52db4..95c1cd0b5 100644
--- a/src/pages/map/components/Container.jsx
+++ b/src/pages/map/components/Container.jsx
@@ -39,12 +39,13 @@ const MAX_BOUNDS = /** @type {[[number, number], [number, number]]} */ ([
export function Container() {
const { location, zoom } = useStorage.getState()
- // Cleanup hidden entities 15 seconds after map loads
+ // Cleanup hidden entities every 15 seconds
React.useEffect(() => {
- const timer = setTimeout(() => {
- cleanupHiddenEntities(useMemory.setState)
- }, 15000)
- return () => clearTimeout(timer)
+ const interval = setInterval(
+ () => cleanupHiddenEntities(useMemory.setState),
+ 15000,
+ )
+ return () => clearInterval(interval)
}, [])
return (