diff --git a/esbuild.config.mjs b/esbuild.config.mjs index 0de6574f4..69aa15f8a 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -124,12 +124,7 @@ const esbuild = { metafile: true, minify: isRelease || !isDevelopment, logLevel: isDevelopment ? 'info' : 'error', - target: [ - 'safari11', - 'chrome64', - 'firefox58', - 'edge88', - ], + target: ['safari11.1', 'chrome64', 'firefox66', 'edge88'], watch: isDevelopment ? { onRebuild(error) { diff --git a/package.json b/package.json index 19fdbc308..1d86322dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "reactmap", - "version": "1.2.3", + "version": "1.2.4", "description": "React based frontend map.", "main": "ReactMap.mjs", "author": "TurtIeSocks <58572875+TurtIeSocks@users.noreply.github.com>", @@ -106,6 +106,6 @@ "react-window": "^1.8.6", "require-from-string": "^2.0.2", "suncalc": "^1.8.0", - "zustand": "^3.3.3" + "zustand": "^4.0.0-rc.1" } } diff --git a/server/src/graphql/mapTypes.js b/server/src/graphql/mapTypes.js index 8a84f4b76..c60ba1f94 100644 --- a/server/src/graphql/mapTypes.js +++ b/server/src/graphql/mapTypes.js @@ -1,7 +1,15 @@ const { gql } = require('apollo-server-express') module.exports = gql` - + type Available { + masterfile: JSON + pokestops: [String] + gyms: [String] + pokemon: [String] + nests: [String] + filters: JSON + } + type Badge { id: String name: String diff --git a/server/src/graphql/resolvers.js b/server/src/graphql/resolvers.js index b31d053f2..3ba5b0ad7 100644 --- a/server/src/graphql/resolvers.js +++ b/server/src/graphql/resolvers.js @@ -3,7 +3,6 @@ const GraphQLJSON = require('graphql-type-json') const { AuthenticationError, UserInputError } = require('apollo-server-core') const config = require('../services/config') -const { Event } = require('../services/initialization') const { User, Badge } = require('../models/index') const Utility = require('../services/Utility') const Fetch = require('../services/Fetch') @@ -11,6 +10,21 @@ const Fetch = require('../services/Fetch') module.exports = { JSON: GraphQLJSON, Query: { + available: (_, args, { Event, perms, version }) => { + if (args.version && args.version !== version) throw new UserInputError('old_client') + if (!perms) throw new AuthenticationError('session_expired') + const available = { + pokemon: perms.pokemon ? Event.available.pokemon : [], + gyms: perms.gyms ? Event.available.gyms : [], + nests: perms.nests ? Event.available.nests : [], + pokestops: perms.pokestops ? Event.available.pokestops : [], + } + return { + ...available, + masterfile: { ...Event.masterfile, invasions: Event.invasions }, + filters: Utility.buildDefaultFilters(perms, available), + } + }, badges: async (_, args, { req, perms, Db, version }) => { if (args.version && args.version !== version) throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') diff --git a/server/src/graphql/typeDefs.js b/server/src/graphql/typeDefs.js index fb83f2862..49b1966be 100644 --- a/server/src/graphql/typeDefs.js +++ b/server/src/graphql/typeDefs.js @@ -11,6 +11,7 @@ module.exports = gql` scalar JSON type Query { + available(version: String): Available badges(version: String): [Badge] devices(version: String): [Device] geocoder(search: String, name: String, version: String): [Geocoder] diff --git a/server/src/routes/rootRouter.js b/server/src/routes/rootRouter.js index 942500fcc..ac4e2a07a 100644 --- a/server/src/routes/rootRouter.js +++ b/server/src/routes/rootRouter.js @@ -97,6 +97,7 @@ rootRouter.get('/settings', async (req, res) => { user: await getUser(), settings: {}, authMethods: config.authMethods, + masterfile: { ...Event.masterfile, invasions: Event.invasions }, config: { map: { ...config.map, @@ -199,8 +200,6 @@ rootRouter.get('/settings', async (req, res) => { serverSettings.userSettings = clientValues serverSettings.clientMenus = clientMenus - serverSettings.masterfile = { ...Event.masterfile, invasions: Event.invasions } - if (config.webhooks.length && serverSettings.user?.perms?.webhooks?.length) { serverSettings.webhooks = {} const filtered = config.webhooks.filter(webhook => serverSettings.user.perms.webhooks.includes(webhook.name)) diff --git a/src/components/Map.jsx b/src/components/Map.jsx index cfc4255b8..5379a2a29 100644 --- a/src/components/Map.jsx +++ b/src/components/Map.jsx @@ -6,6 +6,9 @@ import L from 'leaflet' import Utility from '@services/Utility' import { useStatic, useStore } from '@hooks/useStore' +import useRefresh from '@hooks/useRefresh' +import useGenerate from '@hooks/useGenerate' + import Nav from './layout/Nav' import QueryData from './QueryData' import Webhook from './layout/dialogs/webhooks/Webhook' @@ -67,13 +70,14 @@ export default function Map({ serverSettings: const [error, setError] = useState('') const [windowState, setWindowState] = useState(true) const [active, setActive] = useState(true) - const [lc] = useState(L.control.locate({ position: 'bottomright', icon: 'fas fa-location-arrow', keepCurrentZoomLevel: true, setView: 'untilPan', })) + const startFetching = useRefresh(active) + useGenerate() const onMove = useCallback((latLon) => { const newCenter = latLon || map.getCenter() @@ -110,6 +114,12 @@ export default function Map({ serverSettings: } }, [settings.navigationControls]) + useEffect(() => { + if (active) { + startFetching() + } + }, [active]) + return ( <> + ) } diff --git a/src/components/layout/dialogs/filters/MenuTile.jsx b/src/components/layout/dialogs/filters/MenuTile.jsx index 907a07cc8..73e8426f2 100644 --- a/src/components/layout/dialogs/filters/MenuTile.jsx +++ b/src/components/layout/dialogs/filters/MenuTile.jsx @@ -9,7 +9,8 @@ export default function MenuTile({ }) { const [name, setName] = useState(true) const { - tileItem, columnCount, tempFilters, setTempFilters, toggleAdvMenu, isMobile, type, toggleSlotsMenu, Utility, + tileItem, columnCount, tempFilters, setTempFilters, toggleAdvMenu, + isMobile, type, toggleSlotsMenu, Utility, standard, } = data const item = tileItem[rowIndex * columnCount + columnIndex] @@ -19,12 +20,12 @@ export default function MenuTile({ } const handleFilterChange = () => { + const newFilter = tempFilters[item.id] + ? { ...tempFilters[item.id], enabled: !tempFilters[item.id].enabled } + : { ...standard, enabled: true } setTempFilters({ ...tempFilters, - [item.id]: { - ...tempFilters[item.id], - enabled: !tempFilters[item.id].enabled, - }, + [item.id]: newFilter, }) Utility.analytics('Filtering', `${item.name} Status: ${!tempFilters[item.id]?.enabled}`, type) } diff --git a/src/components/layout/general/Menu.jsx b/src/components/layout/general/Menu.jsx index ae9ee8dd4..c926cfd87 100644 --- a/src/components/layout/general/Menu.jsx +++ b/src/components/layout/general/Menu.jsx @@ -86,7 +86,7 @@ export default function Menu({ setAdvancedFilter({ open, id, - tempFilters: tempFilters[id], + tempFilters: tempFilters[id] ?? filters.standard, standard: filters.standard, }) } else if (id === 'global') { @@ -233,6 +233,7 @@ export default function Menu({ Utility, toggleWebhook, webhookCategory, + standard: filters.standard, }} Tile={Tile} /> diff --git a/src/hooks/useConfig.js b/src/hooks/useConfig.js index 0c33983e5..540f8555d 100644 --- a/src/hooks/useConfig.js +++ b/src/hooks/useConfig.js @@ -5,8 +5,6 @@ import * as Sentry from '@sentry/react' import Utility from '@services/Utility' import { useStore, useStatic } from '@hooks/useStore' -import useGenerate from '@hooks/useGenerate' - export default function useConfig(serverSettings, paramLocation) { Utility.analytics('User', serverSettings.user ? `${serverSettings.user.username} (${serverSettings.user.id})` : 'Not Logged In', 'Permissions', true) @@ -34,7 +32,6 @@ export default function useConfig(serverSettings, paramLocation) { const setUi = useStatic(state => state.setUi) const setStaticFilters = useStatic(state => state.setFilters) const setWebhookData = useStatic(state => state.setWebhookData) - const setMenuFilters = useStatic(state => state.setMenuFilters) const setIsNight = useStatic(state => state.setIsNight) const localState = JSON.parse(localStorage.getItem('local-state')) @@ -121,7 +118,6 @@ export default function useConfig(serverSettings, paramLocation) { } setIcons(serverSettings.Icons.selection) setStaticIcons(serverSettings.Icons) - setMenuFilters(useGenerate()) setConfig(serverSettings.config) setWebhookData(serverSettings.webhooks) diff --git a/src/hooks/useGenerate.js b/src/hooks/useGenerate.js index 07b9ccd77..8904945a7 100644 --- a/src/hooks/useGenerate.js +++ b/src/hooks/useGenerate.js @@ -1,4 +1,4 @@ -import { useMemo, useCallback } from 'react' +import { useEffect, useCallback } from 'react' import { useTranslation } from 'react-i18next' import genPokemon from '@services/filtering/genPokemon' @@ -12,14 +12,13 @@ export default function useGenerate() { const { pokemon } = useStatic(useCallback(s => s.masterfile, [])) const { gyms, pokestops } = useStatic(useCallback(s => s.filters, [])) const staticMenus = useStatic(useCallback(s => s.menus, [])) + const setMenuFilters = useStatic(s => s.setMenuFilters) - const pokeFilters = useMemo(() => genPokemon(t, pokemon, staticMenus.pokemon.categories), [localStorage.getItem('i18nextLng')]) - const gymFilters = useMemo(() => genGyms(t, gyms, staticMenus.gyms.categories), [localStorage.getItem('i18nextLng')]) - const stopFilters = useMemo(() => genPokestops(t, pokemon, pokestops, staticMenus.pokestops.categories), [localStorage.getItem('i18nextLng')]) + useEffect(() => { + const pokeFilters = genPokemon(t, pokemon, staticMenus.pokemon.categories) + const gymFilters = genGyms(t, gyms, staticMenus.gyms.categories) + const stopFilters = genPokestops(t, pokemon, pokestops, staticMenus.pokestops.categories) - return { - ...gymFilters, - ...stopFilters, - ...pokeFilters, - } + setMenuFilters({ ...gymFilters, ...stopFilters, ...pokeFilters }) + }, [localStorage.getItem('i18nextLng'), pokemon]) } diff --git a/src/hooks/useRefresh.js b/src/hooks/useRefresh.js new file mode 100644 index 000000000..6858762a8 --- /dev/null +++ b/src/hooks/useRefresh.js @@ -0,0 +1,29 @@ +import { useLazyQuery } from '@apollo/client' +import getAvailable from '@services/queries/available' +import { useEffect } from 'react' + +import { useStatic } from './useStore' + +export default function useRefresh(active) { + const setAvailable = useStatic(s => s.setAvailable) + const setMasterfile = useStatic(s => s.setMasterfile) + const setStaticFilters = useStatic(s => s.setFilters) + + const [startFetching, { data }] = useLazyQuery(getAvailable, { + variables: { version: inject.VERSION }, + fetchPolicy: active ? 'network-only' : 'cache-only', + pollInterval: 1000 * 60 * 10, + skip: !active, + }) + + useEffect(() => { + if (data?.available) { + const { masterfile, filters, ...rest } = data.available + setAvailable(rest) + setMasterfile(masterfile) + setStaticFilters(filters) + } + }, [data]) + + return startFetching +} diff --git a/src/services/queries/available.js b/src/services/queries/available.js new file mode 100644 index 000000000..a2f07ab43 --- /dev/null +++ b/src/services/queries/available.js @@ -0,0 +1,16 @@ +import { gql } from '@apollo/client' + +const getAvailable = gql` + query Available($version: String) { + available(version: $version) { + masterfile + pokestops + gyms + pokemon + nests + filters + } + } +` + +export default getAvailable diff --git a/yarn.lock b/yarn.lock index ef86b951a..71128da84 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4688,6 +4688,11 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" +use-sync-external-store@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.1.0.tgz#3343c3fe7f7e404db70f8c687adf5c1652d34e82" + integrity sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ== + util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -4898,7 +4903,9 @@ zen-observable@^0.8.14: resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== -zustand@^3.3.3: - version "3.5.5" - resolved "https://registry.yarnpkg.com/zustand/-/zustand-3.5.5.tgz#628458ad70621ddc2a17dbee49be963e5c0dccb5" - integrity sha512-iTiJoxzYFtiD7DhscgwK2P4Kft1JcZEI2U7mG8IxiOFM4KpBAiJZfFop3r/3wbCuyltXI6ph1Fx90e4j/S43XA== +zustand@^4.0.0-rc.1: + version "4.0.0-rc.1" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.0.0-rc.1.tgz#ec30a3afc03728adec7e1bd7bcc3592176372201" + integrity sha512-qgcs7zLqBdHu0PuT3GW4WCIY5SgXdsv30GQMu9Qpp1BA2aS+sNS8l4x0hWuyEhjXkN+701aGWawhKDv6oWJAcw== + dependencies: + use-sync-external-store "1.1.0"