diff --git a/.eslintignore b/.eslintignore index db4c6d9b6..8baa9f15c 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,5 @@ dist -node_modules \ No newline at end of file +node_modules +public/missing-locales +public/images/custom +public/images/uicons \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index 32fb02bd8..63aa8e312 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,7 +2,8 @@ "extends": [ "airbnb", "airbnb/rules/react", - "eslint:recommended" + "eslint:recommended", + "prettier" ], "parserOptions": { "ecmaVersion": "latest" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e09776e06..758f5878c 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -2,20 +2,29 @@ name: Lint on: [push] jobs: - Lint: + lint: + name: Run Basic Checks runs-on: ubuntu-latest - strategy: - matrix: - node-version: [16.x] steps: - - uses: actions/checkout@v1 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} + - name: Checkout Code + id: checkout-code + uses: actions/checkout@v3 + with: + fetch-depth: 2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 + with: + node-version: 16 + cache: 'yarn' - - name: Test the Testcases - run: - npm install -g yarn - yarn install - yarn build + - name: Install Dependencies + run: yarn + + - name: Lint + run: yarn eslint:check + + - name: Prettier + run: yarn prettier:check + + - name: Build + run: yarn build diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..8baa9f15c --- /dev/null +++ b/.prettierignore @@ -0,0 +1,5 @@ +dist +node_modules +public/missing-locales +public/images/custom +public/images/uicons \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..05c968c02 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "semi": false, + "trailingComma": "all", + "singleQuote": true +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json index d75a05ba5..89f244ad1 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -5,6 +5,7 @@ "lokalise.i18n-ally", "esbenp.prettier-vscode", "leizongmin.node-module-intellisense", - "eg2.vscode-npm-script" + "eg2.vscode-npm-script", + "graphql.vscode-graphql" ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index f84806569..4bb8cedef 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,19 +3,12 @@ "public/base-locales" ], "i18n-ally.keystyle": "flat", - "[typescript]": { - "editor.autoClosingBrackets": "always", - "editor.defaultFormatter": "vscode.typescript-language-features" - }, - "[typescriptreact]": { - "editor.defaultFormatter": "vscode.typescript-language-features" - }, "[javascript]": { "editor.autoClosingBrackets": "always", - "editor.defaultFormatter": "vscode.typescript-language-features" + "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[javascriptreact]": { "editor.autoClosingBrackets": "always", - "editor.defaultFormatter": "vscode.typescript-language-features" + "editor.defaultFormatter": "esbenp.prettier-vscode" }, } \ No newline at end of file diff --git a/package.json b/package.json index c5f400436..c19ac46b8 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,11 @@ "migrate:make": "knex --knexfile server/knexfile.cjs migrate:make", "migrate:latest": "knex --knexfile server/knexfile.cjs migrate:latest", "migrate:rollback": "knex --knexfile server/knexfile.cjs migrate:rollback", - "release": "node server/scripts/newRelease.js" + "release": "node server/scripts/newRelease.js", + "prettier:check": "prettier --check \"**/*.{js,jsx}\"", + "prettier:fix": "prettier --write \"**/*.{js,jsx}\"", + "eslint:check": "eslint \"**/*.{js,jsx}\"", + "eslint:fix": "eslint \"**/*.{js,jsx}\" --fix" }, "engines": { "node": ">=16", @@ -39,12 +43,14 @@ "esbuild-server": "^0.1.0", "eslint": "^8.9.0", "eslint-config-airbnb": "^19.0.4", + "eslint-config-prettier": "^8.3.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-plugin-import": "^2.25.4", "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-react": "^7.28.0", "eslint-plugin-react-hooks": "^4.3.0", - "nodemon": "^2.0.7" + "nodemon": "^2.0.7", + "prettier": "^2.6.2" }, "dependencies": { "@apollo/client": "^3.3.11", @@ -108,4 +114,4 @@ "suncalc": "^1.8.0", "zustand": "^4.0.0-rc.1" } -} +} \ No newline at end of file diff --git a/server/scripts/configMigration.js b/server/scripts/configMigration.js index d2280d718..c0fef0e71 100644 --- a/server/scripts/configMigration.js +++ b/server/scripts/configMigration.js @@ -1,94 +1,105 @@ /* eslint-disable no-console */ const fs = require('fs') -const oldConfig = require('../src/configs/config.json') +const { resolve } = require('path') -const convertObjToArr = (obj) => obj ? Object.entries(obj).map(([k, v]) => ({ - name: k, - ...v, -})) : undefined +const oldConfig = JSON.parse( + fs.readFileSync(resolve(__dirname, '../src/configs/config.json')), +) -const convertMapObject = (obj) => obj ? ({ - general: { - title: obj?.title, - headerTitle: obj?.headerTitle, - startLat: obj?.startLat, - startLon: obj?.startLon, - startZoom: obj?.startZoom, - minZoom: obj?.minZoom, - maxZoom: obj?.maxZoom, - interactionRangeZoom: obj?.interactionRangeZoom, - }, - localeSelection: obj?.localeSelection, - customRoutes: { - discordAuthUrl: obj?.discordAuthUrl, - telegramAuthUrl: obj?.telegramAuthUrl, - telegramBotName: obj?.telegramBotEnvRef, - localAuthUrl: obj?.localAuthUrl, - }, - links: { - discordInvite: obj?.discordInvite, - feedbackLink: obj?.feedbackLink, - statsLink: obj?.statsLink, - rolesLinksName: obj?.rolesLinksName, - rolesLink: obj?.rolesLink, - }, - holidayEffects: { - christmasSnow: obj?.christmasSnow, - newYearsFireworks: obj?.newYearsFireworks, - valentinesDay: obj?.valentinesDay, - }, - misc: { - enableMapJsFilter: obj?.legacyPkmnFilter, - questRewardTypeFilters: obj?.questRewardTypeFilters, - fetchLatestInvasions: obj?.fetchLatestInvasions, - invasionCacheHrs: obj?.invasionCacheHrs, - navigationControls: obj?.navigationControls, - forceTutorial: obj?.forceTutorial, - enableTutorial: obj?.enableTutorial, - enableUserProfile: obj?.enableUserProfile, - enableQuestSetSelector: obj?.enableQuestSetSelector, - noScanAreaOverlay: obj?.noScanAreaOverlay, - }, - theme: obj?.theme, - clustering: { - gyms: { - zoomLevel: obj?.clusterZoomLevels?.gyms, - forcedLimit: obj?.clusterZoomLevels?.forcedClusterLimit, - }, - pokestops: { - zoomLevel: obj?.clusterZoomLevels?.pokestops, - forcedLimit: obj?.clusterZoomLevels?.forcedClusterLimit, - }, - pokemon: { - zoomLevel: obj?.clusterZoomLevels?.pokemon, - forcedLimit: obj?.clusterZoomLevels?.forcedClusterLimit, - }, - portals: { - zoomLevel: obj?.clusterZoomLevels?.portals, - forcedLimit: obj?.clusterZoomLevels?.forcedClusterLimit, - }, - spawnpoints: { - zoomLevel: obj?.clusterZoomLevels?.spawnpoints, - forcedLimit: obj?.clusterZoomLevels?.forcedClusterLimit, - }, - }, - messageOfTheDay: obj?.messageOfTheDay - ? ensureMotd(obj?.messageOfTheDay) - : undefined, - donationPage: obj?.donationPage, - loginPage: obj?.loginPage, -}) : undefined +const convertObjToArr = (obj) => + obj + ? Object.entries(obj).map(([k, v]) => ({ + name: k, + ...v, + })) + : undefined + +const convertMapObject = (obj) => + obj + ? { + general: { + title: obj?.title, + headerTitle: obj?.headerTitle, + startLat: obj?.startLat, + startLon: obj?.startLon, + startZoom: obj?.startZoom, + minZoom: obj?.minZoom, + maxZoom: obj?.maxZoom, + interactionRangeZoom: obj?.interactionRangeZoom, + }, + localeSelection: obj?.localeSelection, + customRoutes: { + discordAuthUrl: obj?.discordAuthUrl, + telegramAuthUrl: obj?.telegramAuthUrl, + telegramBotName: obj?.telegramBotEnvRef, + localAuthUrl: obj?.localAuthUrl, + }, + links: { + discordInvite: obj?.discordInvite, + feedbackLink: obj?.feedbackLink, + statsLink: obj?.statsLink, + rolesLinksName: obj?.rolesLinksName, + rolesLink: obj?.rolesLink, + }, + holidayEffects: { + christmasSnow: obj?.christmasSnow, + newYearsFireworks: obj?.newYearsFireworks, + valentinesDay: obj?.valentinesDay, + }, + misc: { + enableMapJsFilter: obj?.legacyPkmnFilter, + questRewardTypeFilters: obj?.questRewardTypeFilters, + fetchLatestInvasions: obj?.fetchLatestInvasions, + invasionCacheHrs: obj?.invasionCacheHrs, + navigationControls: obj?.navigationControls, + forceTutorial: obj?.forceTutorial, + enableTutorial: obj?.enableTutorial, + enableUserProfile: obj?.enableUserProfile, + enableQuestSetSelector: obj?.enableQuestSetSelector, + noScanAreaOverlay: obj?.noScanAreaOverlay, + }, + theme: obj?.theme, + clustering: { + gyms: { + zoomLevel: obj?.clusterZoomLevels?.gyms, + forcedLimit: obj?.clusterZoomLevels?.forcedClusterLimit, + }, + pokestops: { + zoomLevel: obj?.clusterZoomLevels?.pokestops, + forcedLimit: obj?.clusterZoomLevels?.forcedClusterLimit, + }, + pokemon: { + zoomLevel: obj?.clusterZoomLevels?.pokemon, + forcedLimit: obj?.clusterZoomLevels?.forcedClusterLimit, + }, + portals: { + zoomLevel: obj?.clusterZoomLevels?.portals, + forcedLimit: obj?.clusterZoomLevels?.forcedClusterLimit, + }, + spawnpoints: { + zoomLevel: obj?.clusterZoomLevels?.spawnpoints, + forcedLimit: obj?.clusterZoomLevels?.forcedClusterLimit, + }, + }, + messageOfTheDay: obj?.messageOfTheDay + ? ensureMotd(obj?.messageOfTheDay) + : undefined, + donationPage: obj?.donationPage, + loginPage: obj?.loginPage, + } + : undefined const ensureMotd = (obj) => { if (obj?.messages) { - const updateFieldRec = (messages) => messages.map(message => { - if (message.messages) { - message.components = updateFieldRec(message.messages) - delete message.messages - } - return message - }) - obj.components = obj.messages.map(m => { + const updateFieldRec = (messages) => + messages.map((message) => { + if (message.messages) { + message.components = updateFieldRec(message.messages) + delete message.messages + } + return message + }) + obj.components = obj.messages.map((m) => { if (m.type !== 'parent') return m if (m.messages) { m.components = m.components || updateFieldRec(m.messages) @@ -102,19 +113,31 @@ const ensureMotd = (obj) => { } const mergeAuth = async () => { - let authMethods = await fs.promises.readdir(`${__dirname}/../src/strategies`) - .then(files => files - .filter(file => file !== 'local.js' && file !== 'discord.js' && file !== 'telegram.js')) + let authMethods = await fs.promises + .readdir(`${__dirname}/../src/strategies`) + .then((files) => + files.filter( + (file) => + file !== 'local.js' && + file !== 'discord.js' && + file !== 'telegram.js', + ), + ) if (authMethods?.length) { - authMethods = authMethods.map(file => file.replace('.js', '')) - console.log('Found Custom Auth Methods:', authMethods, '\n', 'You should double check these were migrated correctly!') + authMethods = authMethods.map((file) => file.replace('.js', '')) + console.log( + 'Found Custom Auth Methods:', + authMethods, + '\n', + 'You should double check these were migrated correctly!', + ) } - const flattenArray = (perm) => ([ - ...oldConfig?.discord?.perms?.[perm]?.roles || [], - ...oldConfig?.telegram?.perms?.[perm]?.roles || [], - ...authMethods.flatMap(m => oldConfig?.[m]?.perms[perm]?.roles || []), - ]) + const flattenArray = (perm) => [ + ...(oldConfig?.discord?.perms?.[perm]?.roles || []), + ...(oldConfig?.telegram?.perms?.[perm]?.roles || []), + ...authMethods.flatMap((m) => oldConfig?.[m]?.perms[perm]?.roles || []), + ] const discordObj = (obj, name) => ({ name, @@ -146,22 +169,28 @@ const mergeAuth = async () => { type: 'local', }) - const checkEnabled = (perm) => oldConfig?.discord?.perms?.[perm]?.enabled - || oldConfig?.telegram?.perms?.[perm]?.enabled || false + const checkEnabled = (perm) => + oldConfig?.discord?.perms?.[perm]?.enabled || + oldConfig?.telegram?.perms?.[perm]?.enabled || + false const baseAuth = { strategies: [], areaRestrictions: [ - ...oldConfig?.discord?.areaRestrictions || [], - ...oldConfig?.telegram?.areaRestrictions || [], - ...oldConfig?.local?.areaRestrictions || [], - ...authMethods.flatMap(m => oldConfig?.[m]?.areaRestrictions || []), + ...(oldConfig?.discord?.areaRestrictions || []), + ...(oldConfig?.telegram?.areaRestrictions || []), + ...(oldConfig?.local?.areaRestrictions || []), + ...authMethods.flatMap((m) => oldConfig?.[m]?.areaRestrictions || []), ], excludeFromTutorial: oldConfig?.excludeFromTutorial - ? oldConfig.excludeFromTutorial.map(perm => perm === 's2cells' ? 'scanCells' : perm) + ? oldConfig.excludeFromTutorial.map((perm) => + perm === 's2cells' ? 'scanCells' : perm, + ) : undefined, alwaysEnabledPerms: oldConfig?.alwaysEnabledPerms - ? oldConfig.alwaysEnabledPerms.map(perm => perm === 's2cells' ? 'scanCells' : perm) + ? oldConfig.alwaysEnabledPerms.map((perm) => + perm === 's2cells' ? 'scanCells' : perm, + ) : undefined, perms: { map: { @@ -251,11 +280,11 @@ const mergeAuth = async () => { if (oldConfig?.local) { baseAuth.strategies.push(localObj(oldConfig?.local, 'local')) if (oldConfig?.local?.perms) { - oldConfig.local.perms.forEach(perm => { + oldConfig.local.perms.forEach((perm) => { if (perm === 's2cells') { baseAuth.perms.scanCells.roles.push('local') } else { - Object.keys(baseAuth.perms).forEach(key => { + Object.keys(baseAuth.perms).forEach((key) => { if (perm.includes(key)) { baseAuth.perms[key].roles.push('local') } @@ -264,7 +293,7 @@ const mergeAuth = async () => { }) } } - authMethods.forEach(m => { + authMethods.forEach((m) => { if (m.toLowerCase().includes('discord')) { baseAuth.strategies.push(discordObj(oldConfig[m], m)) } else if (m.toLowerCase().includes('telegram')) { @@ -272,7 +301,11 @@ const mergeAuth = async () => { } else if (m.toLowerCase().includes('local')) { baseAuth.strategies.push(localObj(oldConfig[m], m)) } else { - console.warn('Unable to process Auth Method:', m, 'you will need to manually migrate this!') + console.warn( + 'Unable to process Auth Method:', + m, + 'you will need to manually migrate this!', + ) } }) return baseAuth @@ -297,23 +330,25 @@ const rebuildConfig = async () => ({ }, multiDomains: oldConfig.multiDomains ? Object.entries(oldConfig.multiDomains).map(([domain, values]) => ({ - domain, - ...convertMapObject(values), - })) + domain, + ...convertMapObject(values), + })) : undefined, map: convertMapObject(oldConfig?.map), clientSideOptions: oldConfig?.clientSideOptions, - defaultFilters: oldConfig?.defaultFilters ? { - ...oldConfig?.defaultFilters, - pokemon: { - ...oldConfig?.defaultFilters?.pokemon, - globalValues: { - ...oldConfig?.defaultFilters?.pokemon?.globalValues, - pvp: oldConfig?.defaultFilters?.pokemon?.pvpValues, - }, - pvpValues: undefined, - }, - } : undefined, + defaultFilters: oldConfig?.defaultFilters + ? { + ...oldConfig?.defaultFilters, + pokemon: { + ...oldConfig?.defaultFilters?.pokemon, + globalValues: { + ...oldConfig?.defaultFilters?.pokemon?.globalValues, + pvp: oldConfig?.defaultFilters?.pokemon?.pvpValues, + }, + pvpValues: undefined, + }, + } + : undefined, database: { settings: { ...oldConfig?.database?.settings, @@ -321,7 +356,7 @@ const rebuildConfig = async () => ({ reactMapHandlesPvp: undefined, pvpLevels: undefined, }, - schemas: Object.values(oldConfig?.database?.schemas).map(s => { + schemas: Object.values(oldConfig?.database?.schemas).map((s) => { if (s.useFor.includes('s2cell')) { const s2cellIndex = s.useFor.indexOf('s2cell') s.useFor[s2cellIndex] = 'scanCell' @@ -341,13 +376,16 @@ const rebuildConfig = async () => ({ const cleanConfig = (obj, round) => { Object.entries(obj).forEach(([key, value]) => { if (Array.isArray(value)) { - value.forEach(subObj => { + value.forEach((subObj) => { if (typeof subObj === 'object') { cleanConfig(subObj, round) } }) } else if (typeof value === 'object') { - if (!Object.keys(value).length || Object.values(value).every(v => v === undefined)) { + if ( + !Object.keys(value).length || + Object.values(value).every((v) => v === undefined) + ) { delete obj[key] console.log('Removed empty object:', key, round) } else { @@ -371,7 +409,7 @@ const migrator = async () => { `${__dirname}/../src/configs/local.json`, JSON.stringify(config, null, 2), 'utf8', - () => { }, + () => {}, ) } diff --git a/server/scripts/createLocales.js b/server/scripts/createLocales.js index 3b201c20d..bdce8cd2f 100644 --- a/server/scripts/createLocales.js +++ b/server/scripts/createLocales.js @@ -10,77 +10,123 @@ const missingFolder = path.resolve(__dirname, '../../public/missing-locales') const locales = async () => { const localTranslations = await fs.promises.readdir(appLocalesFolder) - const englishRef = fs.readFileSync(path.resolve(appLocalesFolder, 'en.json'), { encoding: 'utf8', flag: 'r' }) - - fs.mkdir(finalLocalesFolder, (error) => error ? console.log('[LOCALES] Locales folder already exists, skipping') : console.log('[LOCALES] locales folder created')) - - const availableRemote = await fetchJson('https://raw.githubusercontent.com/WatWowMap/pogo-translations/master/index.json') - - await Promise.all(localTranslations.map(async locale => { - const reactMapTranslations = fs.readFileSync(path.resolve(appLocalesFolder, locale), { encoding: 'utf8', flag: 'r' }) - const baseName = locale.replace('.json', '') - const trimmedRemoteFiles = {} - - fs.mkdir(`${finalLocalesFolder}/${baseName}`, (error) => error ? {} : console.log(`[LOCALES] ${locale} folder created`)) - - try { - const hasRemote = availableRemote.includes(locale) - const remoteFiles = await fetchJson(`https://raw.githubusercontent.com/WatWowMap/pogo-translations/master/static/locales/${hasRemote ? baseName : 'en'}.json`) + const englishRef = fs.readFileSync( + path.resolve(appLocalesFolder, 'en.json'), + { encoding: 'utf8', flag: 'r' }, + ) + + fs.mkdir(finalLocalesFolder, (error) => + error + ? console.log('[LOCALES] Locales folder already exists, skipping') + : console.log('[LOCALES] locales folder created'), + ) + + const availableRemote = await fetchJson( + 'https://raw.githubusercontent.com/WatWowMap/pogo-translations/master/index.json', + ) + + await Promise.all( + localTranslations.map(async (locale) => { + const reactMapTranslations = fs.readFileSync( + path.resolve(appLocalesFolder, locale), + { encoding: 'utf8', flag: 'r' }, + ) + const baseName = locale.replace('.json', '') + const trimmedRemoteFiles = {} + + fs.mkdir(`${finalLocalesFolder}/${baseName}`, (error) => + error ? {} : console.log(`[LOCALES] ${locale} folder created`), + ) + + try { + const hasRemote = availableRemote.includes(locale) + const remoteFiles = await fetchJson( + `https://raw.githubusercontent.com/WatWowMap/pogo-translations/master/static/locales/${ + hasRemote ? baseName : 'en' + }.json`, + ) + + if (!hasRemote) { + console.warn( + '[LOCALES] No remote translation found for', + locale, + 'using English', + ) + } - if (!hasRemote) { - console.warn('[LOCALES] No remote translation found for', locale, 'using English') + Object.keys(remoteFiles).forEach((key) => { + if ( + !key.startsWith('desc_') && + !key.startsWith('pokemon_category_') + ) { + if (key.startsWith('quest_') || key.startsWith('challenge_')) { + trimmedRemoteFiles[key] = remoteFiles[key] + .replace(/%\{/g, '{{') + .replace(/\}/g, '}}') + } else { + trimmedRemoteFiles[key] = remoteFiles[key] + } + } + }) + } catch (e) { + console.warn(e, '\n', locale) } - Object.keys(remoteFiles).forEach(key => { - if (!key.startsWith('desc_') && !key.startsWith('pokemon_category_')) { - if (key.startsWith('quest_') || key.startsWith('challenge_')) { - trimmedRemoteFiles[key] = remoteFiles[key] - .replace(/%\{/g, '{{') - .replace(/\}/g, '}}') - } else { - trimmedRemoteFiles[key] = remoteFiles[key] - } - } - }) - } catch (e) { - console.warn(e, '\n', locale) - } - - const finalTranslations = { - ...JSON.parse(englishRef), - ...trimmedRemoteFiles, - ...JSON.parse(reactMapTranslations), - } - fs.writeFile( - path.resolve(finalLocalesFolder, baseName, 'translation.json'), - JSON.stringify(finalTranslations, null, 2), - 'utf8', - () => { }, - ) - console.log(`[LOCALES] ${locale}`, 'file saved.') - })) + const finalTranslations = { + ...JSON.parse(englishRef), + ...trimmedRemoteFiles, + ...JSON.parse(reactMapTranslations), + } + fs.writeFile( + path.resolve(finalLocalesFolder, baseName, 'translation.json'), + JSON.stringify(finalTranslations, null, 2), + 'utf8', + () => {}, + ) + console.log(`[LOCALES] ${locale}`, 'file saved.') + }), + ) } const missing = async () => { const localTranslations = await fs.promises.readdir(appLocalesFolder) - const englishRef = JSON.parse(fs.readFileSync(path.resolve(appLocalesFolder, 'en.json'), { encoding: 'utf8', flag: 'r' })) - - fs.mkdir(missingFolder, (error) => error ? {} : console.log('[LOCALES] Locales folder created')) - - localTranslations.forEach(locale => { - const reactMapTranslations = JSON.parse(fs.readFileSync(path.resolve(appLocalesFolder, locale), { encoding: 'utf8', flag: 'r' })) + const englishRef = JSON.parse( + fs.readFileSync(path.resolve(appLocalesFolder, 'en.json'), { + encoding: 'utf8', + flag: 'r', + }), + ) + + fs.mkdir(missingFolder, (error) => + error ? {} : console.log('[LOCALES] Locales folder created'), + ) + + localTranslations.forEach((locale) => { + const reactMapTranslations = JSON.parse( + fs.readFileSync(path.resolve(appLocalesFolder, locale), { + encoding: 'utf8', + flag: 'r', + }), + ) const missingKeys = {} - Object.keys(englishRef).forEach(key => { + Object.keys(englishRef).forEach((key) => { if (!reactMapTranslations[key]) { - missingKeys[key] = process.argv.includes('--ally') ? `t('${key}')` : englishRef[key] + missingKeys[key] = process.argv.includes('--ally') + ? `t('${key}')` + : englishRef[key] } }) fs.writeFile( - path.resolve(missingFolder, process.argv.includes('--ally') ? locale.replace('.json', '.js') : locale), + path.resolve( + missingFolder, + process.argv.includes('--ally') + ? locale.replace('.json', '.js') + : locale, + ), JSON.stringify(missingKeys, null, 2), 'utf8', - () => { }, + () => {}, ) console.log(`[LOCALES] ${locale}`, 'file saved.') }) @@ -93,6 +139,8 @@ if (require.main === module) { locales().then(() => console.log('[LOCALES] Translations generated')) if (process.argv[2] === '--missing') { - missing().then(() => console.log('[LOCALES] Missing translations generated')) + missing().then(() => + console.log('[LOCALES] Missing translations generated'), + ) } } diff --git a/server/scripts/genEnvConfig.js b/server/scripts/genEnvConfig.js index c2dbcd494..b732e766f 100644 --- a/server/scripts/genEnvConfig.js +++ b/server/scripts/genEnvConfig.js @@ -2,7 +2,8 @@ const fs = require('fs') const sourceConfig = require('../src/configs/default.json') -const camelToSnake = str => str.replace(/([a-z](?=[A-Z]))/g, '$1_').toUpperCase() +const camelToSnake = (str) => + str.replace(/([a-z](?=[A-Z]))/g, '$1_').toUpperCase() const recursiveObjCheck = (obj, key = '', parentKey = '') => { const snakeKey = `${parentKey}${camelToSnake(key)}` @@ -11,9 +12,10 @@ const recursiveObjCheck = (obj, key = '', parentKey = '') => { } if (typeof obj === 'object') { return Object.fromEntries( - Object.entries(obj).map(([k, v]) => ( - [k, recursiveObjCheck(v, k, key ? `${snakeKey}_` : snakeKey)] - )), + Object.entries(obj).map(([k, v]) => [ + k, + recursiveObjCheck(v, k, key ? `${snakeKey}_` : snakeKey), + ]), ) } return typeof obj === 'string' diff --git a/server/scripts/generateMasterfile.js b/server/scripts/generateMasterfile.js index a251531b9..ed57b315b 100644 --- a/server/scripts/generateMasterfile.js +++ b/server/scripts/generateMasterfile.js @@ -10,7 +10,7 @@ const getRarityLevel = (id, pkmn) => { let pkmnRarity for (const [tier, pokemon] of Object.entries(defaultRarity)) { if (rarity?.[tier]?.length) { - if (rarity[tier].includes((parseInt(id)))) { + if (rarity[tier].includes(parseInt(id))) { pkmnRarity = tier } } else if (pokemon.includes(parseInt(id))) { @@ -25,9 +25,11 @@ const getRarityLevel = (id, pkmn) => { const generate = async (save) => { try { - const masterfile = await fetchJson('https://raw.githubusercontent.com/WatWowMap/Masterfile-Generator/master/master-latest-react-map.json') + const masterfile = await fetchJson( + 'https://raw.githubusercontent.com/WatWowMap/Masterfile-Generator/master/master-latest-react-map.json', + ) - Object.values(masterfile.pokemon).forEach(pokemon => { + Object.values(masterfile.pokemon).forEach((pokemon) => { pokemon.rarity = getRarityLevel(pokemon.pokedexId, pokemon) pokemon.types = pokemon.types || [] delete pokemon.mythical @@ -39,7 +41,7 @@ const generate = async (save) => { path.resolve(`${__dirname}/../src/data/masterfile.json`), JSON.stringify(masterfile, null, 2), 'utf8', - () => { }, + () => {}, ) } return masterfile diff --git a/server/scripts/newRelease.js b/server/scripts/newRelease.js index 4673d9ee4..f717f203d 100644 --- a/server/scripts/newRelease.js +++ b/server/scripts/newRelease.js @@ -24,18 +24,24 @@ try { throw new Error(err1) } console.log(stdout1) - exec(`sentry-cli releases files ${version} upload-sourcemaps ${path.resolve(__dirname, '../../dist')}`, (err2, stdout2) => { - if (err2) { - throw new Error(err2) - } - console.log(stdout2) - exec(`sentry-cli releases finalize ${version}`, (err3, stdout3) => { - if (err3) { - throw new Error(err3) + exec( + `sentry-cli releases files ${version} upload-sourcemaps ${path.resolve( + __dirname, + '../../dist', + )}`, + (err2, stdout2) => { + if (err2) { + throw new Error(err2) } - console.log(stdout3) - }) - }) + console.log(stdout2) + exec(`sentry-cli releases finalize ${version}`, (err3, stdout3) => { + if (err3) { + throw new Error(err3) + } + console.log(stdout3) + }) + }, + ) }) }) } catch (e) { diff --git a/server/scripts/poracleToGeoJSON.js b/server/scripts/poracleToGeoJSON.js index 1c4bdbd7d..36bbfcbbb 100644 --- a/server/scripts/poracleToGeoJSON.js +++ b/server/scripts/poracleToGeoJSON.js @@ -1,17 +1,23 @@ /* eslint-disable no-console */ /** -* Credits: https://gist.github.com/moriakaice -* Editor: PJ0tterr -* Created on: 15-01-2022 -* Modified on: 23-01-2022 -*/ + * Credits: https://gist.github.com/moriakaice + * Editor: PJ0tterr + * Created on: 15-01-2022 + * Modified on: 23-01-2022 + */ const fs = require('fs') const path = require('path') // Set Path where for area.json -const configFolderArea = path.resolve(__dirname, '../../server/src/configs/areas.json') -const geofencesFile = path.resolve(__dirname, '../../server/src/configs/geofence.json') +const configFolderArea = path.resolve( + __dirname, + '../../server/src/configs/areas.json', +) +const geofencesFile = path.resolve( + __dirname, + '../../server/src/configs/geofence.json', +) if (fs.existsSync(geofencesFile)) { const outGeoJSON = { @@ -37,7 +43,6 @@ if (fs.existsSync(geofencesFile)) { name: inGeofence.name || '', color: inGeofence.color || '#000000', id: inGeofence.id || 0, - }, geometry: { type: 'Polygon', @@ -49,16 +54,27 @@ if (fs.existsSync(geofencesFile)) { inGeofence.path[j] = [coord[1], coord[0]] } const lastCoords = inGeofence.path.slice(-1) - if (inGeofence.path[0][0] !== lastCoords[0][0] || inGeofence.path[0][1] !== lastCoords[0][1]) { + if ( + inGeofence.path[0][0] !== lastCoords[0][0] || + inGeofence.path[0][1] !== lastCoords[0][1] + ) { inGeofence.path.push(inGeofence.path[0]) } outGeofence.geometry.coordinates[0] = inGeofence.path outGeoJSON.features.push(outGeofence) } - const outFilePath = path.resolve(path.dirname(configFolderArea), 'areas.json') + const outFilePath = path.resolve( + path.dirname(configFolderArea), + 'areas.json', + ) - fs.writeFile(outFilePath, JSON.stringify(outGeoJSON, null, 2), 'utf8', () => { - console.log(`${outFilePath} file saved.`) - }) + fs.writeFile( + outFilePath, + JSON.stringify(outGeoJSON, null, 2), + 'utf8', + () => { + console.log(`${outFilePath} file saved.`) + }, + ) }) } diff --git a/server/src/graphql/mapTypes.js b/server/src/graphql/mapTypes.js index f8683a45b..8e6762f48 100644 --- a/server/src/graphql/mapTypes.js +++ b/server/src/graphql/mapTypes.js @@ -1,27 +1,27 @@ const { gql } = require('apollo-server-express') module.exports = gql` - type Available { - masterfile: JSON - pokestops: [String] - gyms: [String] - pokemon: [String] - nests: [String] - filters: JSON - questConditions: JSON - } - - type Badge { - id: String - name: String - url: String - lat: Float - lon: Float - badge: Int - deleted: Boolean - } - - type Geocoder { + type Available { + masterfile: JSON + pokestops: [String] + gyms: [String] + pokemon: [String] + nests: [String] + filters: JSON + questConditions: JSON + } + + type Badge { + id: String + name: String + url: String + lat: Float + lon: Float + badge: Int + deleted: Boolean + } + + type Geocoder { latitude: Float longitude: Float streetNumber: String @@ -37,7 +37,7 @@ module.exports = gql` } type Geometry { - type: String + type: String coordinates: [[[Float]]] } diff --git a/server/src/graphql/poracleTypes.js b/server/src/graphql/poracleTypes.js index e970c2599..4eed84499 100644 --- a/server/src/graphql/poracleTypes.js +++ b/server/src/graphql/poracleTypes.js @@ -155,7 +155,7 @@ module.exports = gql` shiny: Boolean description: String } - + type PoracleNest { uid: Int id: ID diff --git a/server/src/graphql/resolvers.js b/server/src/graphql/resolvers.js index 829907447..d6d90151f 100644 --- a/server/src/graphql/resolvers.js +++ b/server/src/graphql/resolvers.js @@ -11,7 +11,8 @@ module.exports = { JSON: GraphQLJSON, Query: { available: (_, args, { Event, Db, perms, version }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + 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 : [], @@ -27,7 +28,8 @@ module.exports = { } }, badges: async (_, args, { req, perms, Db, version }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') if (perms?.gymBadges) { @@ -37,7 +39,8 @@ module.exports = { return [] }, devices: (_, args, { perms, Db, version }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') if (perms?.devices) { @@ -46,7 +49,8 @@ module.exports = { return [] }, geocoder: (_, args, { perms, version, Event }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') if (perms?.webhooks) { @@ -58,7 +62,8 @@ module.exports = { return [] }, gyms: (_, args, { perms, version, req, Db }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') if (perms?.gyms || perms?.raids) { @@ -67,7 +72,8 @@ module.exports = { return [] }, gymsSingle: (_, args, { perms, version, Db }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') if (perms?.[args.perm]) { @@ -76,7 +82,8 @@ module.exports = { return {} }, nests: (_, args, { perms, version, Db }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') if (perms?.nests) { @@ -85,7 +92,8 @@ module.exports = { return [] }, nestsSingle: (_, args, { perms, version, Db }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') if (perms?.[args.perm]) { @@ -94,19 +102,23 @@ module.exports = { return {} }, pokestops: (_, args, { perms, version, Db }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') - if (perms?.pokestops - || perms?.lures - || perms?.quests - || perms?.invasions) { + if ( + perms?.pokestops || + perms?.lures || + perms?.quests || + perms?.invasions + ) { return Db.getAll('Pokestop', perms, args) } return [] }, pokestopsSingle: (_, args, { perms, version, Db }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') if (perms?.[args.perm]) { @@ -115,7 +127,8 @@ module.exports = { return {} }, pokemon: (_, args, { perms, version, Db }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') if (perms?.pokemon) { @@ -127,7 +140,8 @@ module.exports = { return [] }, pokemonSingle: (_, args, { perms, version, Db }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') if (perms?.[args.perm]) { @@ -136,7 +150,8 @@ module.exports = { return {} }, portals: (_, args, { perms, version, Db }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') if (perms?.portals) { @@ -145,7 +160,8 @@ module.exports = { return [] }, portalsSingle: (_, args, { perms, version, Db }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') if (perms?.[args.perm]) { @@ -154,7 +170,8 @@ module.exports = { return {} }, scanCells: (_, args, { perms, version, Db }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') if (perms?.scanCells && args.zoom >= config.map.scanCellsZoom) { @@ -163,7 +180,8 @@ module.exports = { return [] }, scanAreas: (_, args, { perms, version, req }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') const scanAreas = config.scanAreas[req.headers.host] @@ -172,8 +190,8 @@ module.exports = { if (perms?.scanAreas && scanAreas.features.length) { try { scanAreas.features = scanAreas.features - .filter(feature => !feature.properties.hidden) - .sort((a, b) => (a.properties.name > b.properties.name) ? 1 : -1) + .filter((feature) => !feature.properties.hidden) + .sort((a, b) => (a.properties.name > b.properties.name ? 1 : -1)) } catch (e) { console.warn('[WARN] Failed to sort scan areas', e.message) } @@ -182,7 +200,8 @@ module.exports = { return [{ features: [] }] }, search: async (_, args, { Event, perms, version, Db }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') const { category, webhookName, search } = args @@ -199,11 +218,16 @@ module.exports = { const results = await Db.search('Gym', perms, args) const webhook = webhookName ? Event.webhookObj[webhookName] : null if (webhook && results.length) { - const withFormatted = await Promise.all(results.map(async result => ({ - ...result, - formatted: - await Utility.geocoder(webhook.server.nominatimUrl, { lat: result.lat, lon: result.lon }, true), - }))) + const withFormatted = await Promise.all( + results.map(async (result) => ({ + ...result, + formatted: await Utility.geocoder( + webhook.server.nominatimUrl, + { lat: result.lat, lon: result.lon }, + true, + ), + })), + ) return withFormatted } return results @@ -212,13 +236,15 @@ module.exports = { return Db.search('Portal', perms, args) case 'nests': return Db.search('Nest', perms, args) - default: return [] + default: + return [] } } return [] }, searchQuest: (_, args, { perms, version, Db }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') const { category, search } = args @@ -231,7 +257,8 @@ module.exports = { return [] }, spawnpoints: (_, args, { perms, version, Db }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') if (perms?.spawnpoints) { @@ -240,22 +267,30 @@ module.exports = { return [] }, submissionCells: async (_, args, { perms, version, Db }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') - if (perms?.submissionCells && args.zoom >= config.map.submissionZoom - 1) { + if ( + perms?.submissionCells && + args.zoom >= config.map.submissionZoom - 1 + ) { const [pokestops, gyms] = await Db.submissionCells(args) - return [{ - placementCells: args.zoom >= config.map.submissionZoom - ? Utility.getPlacementCells(args, pokestops, gyms) - : [], - typeCells: Utility.getTypeCells(args, pokestops, gyms), - }] + return [ + { + placementCells: + args.zoom >= config.map.submissionZoom + ? Utility.getPlacementCells(args, pokestops, gyms) + : [], + typeCells: Utility.getTypeCells(args, pokestops, gyms), + }, + ] } return [{ placementCells: [], typeCells: [] }] }, weather: (_, args, { perms, version, Db }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') if (perms?.weather) { @@ -264,16 +299,23 @@ module.exports = { return [] }, webhook: (_, args, { perms, version, req }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') if (perms?.webhooks) { - return Fetch.webhookApi(args.category, Utility.evalWebhookId(req.user), args.status, args.name) + return Fetch.webhookApi( + args.category, + Utility.evalWebhookId(req.user), + args.status, + args.name, + ) } return {} }, scanner: (_, args, { perms, version }) => { - if (args.version && args.version !== version) throw new UserInputError('old_client') + if (args.version && args.version !== version) + throw new UserInputError('old_client') if (!perms) throw new AuthenticationError('session_expired') const { category, method, data } = args @@ -291,7 +333,13 @@ module.exports = { const perms = req.user ? req.user.perms : false const { category, data, status, name } = args if (perms?.webhooks?.includes(name)) { - return Fetch.webhookApi(category, Utility.evalWebhookId(req.user), status, name, data) + return Fetch.webhookApi( + category, + Utility.evalWebhookId(req.user), + status, + name, + data, + ) } return {} }, @@ -318,15 +366,21 @@ module.exports = { return false }, checkUsername: async (_, args) => { - const results = await User.query() - .where('username', args.username) + const results = await User.query().where('username', args.username) return Boolean(results.length) }, setGymBadge: async (_, args, { req }) => { const perms = req.user ? req.user.perms : false if (perms?.gymBadges && req?.user?.id) { - if (await Badge.query().where('gymId', args.gymId).andWhere('userId', req.user.id).first()) { - await Badge.query().where('gymId', args.gymId).andWhere('userId', req.user.id) + if ( + await Badge.query() + .where('gymId', args.gymId) + .andWhere('userId', req.user.id) + .first() + ) { + await Badge.query() + .where('gymId', args.gymId) + .andWhere('userId', req.user.id) .update({ badge: args.badge }) } else { await Badge.query().insert({ diff --git a/server/src/graphql/typeDefs.js b/server/src/graphql/typeDefs.js index 49b1966be..80ca90aa6 100644 --- a/server/src/graphql/typeDefs.js +++ b/server/src/graphql/typeDefs.js @@ -15,25 +15,120 @@ module.exports = gql` badges(version: String): [Badge] devices(version: String): [Device] geocoder(search: String, name: String, version: String): [Geocoder] - gyms(minLat: Float, maxLat: Float, minLon: Float, maxLon: Float, ts: Int, filters: JSON, version: String): [Gym] + gyms( + minLat: Float + maxLat: Float + minLon: Float + maxLon: Float + ts: Int + filters: JSON + version: String + ): [Gym] gymsSingle(id: ID, perm: String, version: String): Gym - nests(minLat: Float, maxLat: Float, minLon: Float, maxLon: Float, ts: Int, filters: JSON, version: String): [Nest] + nests( + minLat: Float + maxLat: Float + minLon: Float + maxLon: Float + ts: Int + filters: JSON + version: String + ): [Nest] nestsSingle(id: ID, perm: String, version: String): Nest - pokestops(minLat: Float, maxLat: Float, minLon: Float, maxLon: Float, ts: Int, midnight: Int, filters: JSON, version: String): [Pokestop] + pokestops( + minLat: Float + maxLat: Float + minLon: Float + maxLon: Float + ts: Int + midnight: Int + filters: JSON + version: String + ): [Pokestop] pokestopsSingle(id: ID, perm: String, version: String): Pokestop - pokemon(minLat: Float, maxLat: Float, minLon: Float, maxLon: Float, ts: Int, filters: JSON, version: String): [Pokemon] + pokemon( + minLat: Float + maxLat: Float + minLon: Float + maxLon: Float + ts: Int + filters: JSON + version: String + ): [Pokemon] pokemonSingle(id: ID, perm: String, version: String): Pokemon - portals(minLat: Float, maxLat: Float, minLon: Float, maxLon: Float, ts: Int, filters: JSON, version: String): [Portal] + portals( + minLat: Float + maxLat: Float + minLon: Float + maxLon: Float + ts: Int + filters: JSON + version: String + ): [Portal] portalsSingle(id: ID, perm: String, version: String): Portal - scanCells(minLat: Float, maxLat: Float, minLon: Float, maxLon: Float, ts: Int, filters: JSON, zoom: Int, version: String): [ScanCell] + scanCells( + minLat: Float + maxLat: Float + minLon: Float + maxLon: Float + ts: Int + filters: JSON + zoom: Int + version: String + ): [ScanCell] scanAreas(version: String): [ScanArea] - search(search: String, category: String, lat: Float, lon: Float, locale: String, webhookName: String, ts: Int, midnight: Int, version: String): [Search] - searchQuest(search: String, category: String, lat: Float, lon: Float, locale: String, webhookName: String, midnight: Int, version: String): [SearchQuest] - spawnpoints(minLat: Float, maxLat: Float, minLon: Float, maxLon: Float, ts: Int, filters: JSON, version: String): [Spawnpoint] - submissionCells(minLat: Float, maxLat: Float, minLon: Float, maxLon: Float, ts: Int, zoom: Int, version: String): [SubmissionCell] + search( + search: String + category: String + lat: Float + lon: Float + locale: String + webhookName: String + ts: Int + midnight: Int + version: String + ): [Search] + searchQuest( + search: String + category: String + lat: Float + lon: Float + locale: String + webhookName: String + midnight: Int + version: String + ): [SearchQuest] + spawnpoints( + minLat: Float + maxLat: Float + minLon: Float + maxLon: Float + ts: Int + filters: JSON + version: String + ): [Spawnpoint] + submissionCells( + minLat: Float + maxLat: Float + minLon: Float + maxLon: Float + ts: Int + zoom: Int + version: String + ): [SubmissionCell] weather(version: String): [Weather] - webhook(category: String, status: String, name: String, version: String): Poracle - scanner(category: String, method: String, data: JSON, version: String): ScannerApi + webhook( + category: String + status: String + name: String + version: String + ): Poracle + scanner( + category: String + method: String + data: JSON + version: String + ): ScannerApi } type Mutation { diff --git a/server/src/index.js b/server/src/index.js index 0d4d9ab69..54e002d57 100644 --- a/server/src/index.js +++ b/server/src/index.js @@ -43,7 +43,10 @@ const server = new ApolloServer({ if (config.devOptions.enabled) { console.warn(e) } - if (e instanceof ValidationError || e?.message.includes('skipUndefined()')) { + if ( + e instanceof ValidationError || + e?.message.includes('skipUndefined()') + ) { return { message: 'old_client' } } if (['old_client', 'session_expired'].includes(e.message)) { @@ -57,20 +60,25 @@ const server = new ApolloServer({ server.start().then(() => server.applyMiddleware({ app, path: '/graphql' })) if (config.devOptions.enabled) { - app.use(logger((tokens, req, res) => [ - tokens.method(req, res), - tokens.url(req, res), - tokens.status(req, res), - tokens['response-time'](req, res), - 'ms', - req.user ? `- ${req.user.username}` : 'Not Logged In', - '-', - req.headers['x-forwarded-for'], - ].join(' '))) + app.use( + logger((tokens, req, res) => + [ + tokens.method(req, res), + tokens.url(req, res), + tokens.status(req, res), + tokens['response-time'](req, res), + 'ms', + req.user ? `- ${req.user.username}` : 'Not Logged In', + '-', + req.headers['x-forwarded-for'], + ].join(' '), + ), + ) } const RateLimitTime = config.api.rateLimit.time * 60 * 1000 -const MaxRequestsPerHour = config.api.rateLimit.requests * (RateLimitTime / 1000) +const MaxRequestsPerHour = + config.api.rateLimit.requests * (RateLimitTime / 1000) const rateLimitOptions = { windowMs: RateLimitTime, // Time window in milliseconds @@ -97,17 +105,19 @@ app.use(express.json({ limit: '50mb' })) app.use(express.static(path.join(__dirname, config.devOptions.clientPath))) -app.use(session({ - name: 'discord', - key: 'session', - secret: config.api.sessionSecret, - store: sessionStore, - resave: true, - saveUninitialized: false, - cookie: { maxAge: 86400000 * config.api.cookieAgeDays }, -})) - -config.authentication.strategies.forEach(strategy => { +app.use( + session({ + name: 'discord', + key: 'session', + secret: config.api.sessionSecret, + store: sessionStore, + resave: true, + saveUninitialized: false, + cookie: { maxAge: 86400000 * config.api.cookieAgeDays }, + }), +) + +config.authentication.strategies.forEach((strategy) => { if (strategy.enabled) { require(`./strategies/${strategy.name}.js`) console.log(`[AUTH] Strategy ${strategy.name} initialized`) @@ -132,16 +142,23 @@ passport.deserializeUser(async (user, done) => { } }) -i18next.use(Backend).init({ - lng: 'en', - fallbackLng: 'en', - preload: config.map.localeSelection, - ns: ['translation'], - defaultNS: 'translation', - backend: { loadPath: path.resolve(`${__dirname}/../../public/locales/{{lng}}/{{ns}}.json`) }, -}, (err, t) => { - if (err) return console.error(err) -}) +i18next.use(Backend).init( + { + lng: 'en', + fallbackLng: 'en', + preload: config.map.localeSelection, + ns: ['translation'], + defaultNS: 'translation', + backend: { + loadPath: path.resolve( + `${__dirname}/../../public/locales/{{lng}}/{{ns}}.json`, + ), + }, + }, + (err, t) => { + if (err) return console.error(err) + }, +) app.use(rootRouter, requestRateLimiter) @@ -151,31 +168,31 @@ app.use((err, req, res, next) => { switch (err.message) { case 'NoCodeProvided': return res.redirect('/404') - case 'Failed to fetch user\'s guilds': + case "Failed to fetch user's guilds": return res.redirect('/login') default: return res.redirect('/') } }) -Db.determineType() - .then(async () => { - await Promise.all([ - Event.getUicons(config.icons.styles), - Event.getMasterfile(), - Event.getInvasions(), - Event.getWebhooks(config), - Event.setAvailable('gyms', 'Gym', Db), - Event.setAvailable('pokestops', 'Pokestop', Db), - Event.setAvailable('pokemon', 'Pokemon', Db), - Event.setAvailable('nests', 'Nest', Db), - ]) - .then(() => { - Event.addAvailable() - app.listen(config.port, config.interface, () => { - console.log(`[INIT] Server is now listening at http://${config.interface}:${config.port}`) - }) - }) +Db.determineType().then(async () => { + await Promise.all([ + Event.getUicons(config.icons.styles), + Event.getMasterfile(), + Event.getInvasions(), + Event.getWebhooks(config), + Event.setAvailable('gyms', 'Gym', Db), + Event.setAvailable('pokestops', 'Pokestop', Db), + Event.setAvailable('pokemon', 'Pokemon', Db), + Event.setAvailable('nests', 'Nest', Db), + ]).then(() => { + Event.addAvailable() + app.listen(config.port, config.interface, () => { + console.log( + `[INIT] Server is now listening at http://${config.interface}:${config.port}`, + ) + }) }) +}) module.exports = app diff --git a/server/src/models/Badge.js b/server/src/models/Badge.js index d40ca1d52..6a2c22655 100644 --- a/server/src/models/Badge.js +++ b/server/src/models/Badge.js @@ -1,6 +1,8 @@ const { Model } = require('objection') const { - database: { settings: { userTableName, gymBadgeTableName } }, + database: { + settings: { userTableName, gymBadgeTableName }, + }, } = require('../services/config') module.exports = class Badge extends Model { @@ -33,8 +35,6 @@ module.exports = class Badge extends Model { } static async getAll(userId) { - return this.query() - .where('userId', userId) - .andWhere('badge', '>', 0) + return this.query().where('userId', userId).andWhere('badge', '>', 0) } } diff --git a/server/src/models/Device.js b/server/src/models/Device.js index 2bcdb8943..ebcc5d1ab 100644 --- a/server/src/models/Device.js +++ b/server/src/models/Device.js @@ -10,23 +10,21 @@ module.exports = class Device extends Model { const { areaRestrictions } = perms const query = this.query() if (settings.isMad) { - query.join('trs_status', 'settings_device.device_id', 'trs_status.device_id') + query + .join('trs_status', 'settings_device.device_id', 'trs_status.device_id') .join('settings_area', 'trs_status.area_id', 'settings_area.area_id') .select([ 'settings_device.name AS id', 'settings_area.name AS instance_name', 'mode AS type', - raw('UNIX_TIMESTAMP(lastProtoDateTime)') - .as('last_seen'), - raw('X(currentPos)') - .as('last_lat'), - raw('Y(currentPos)') - .as('last_lon'), - raw(true) - .as('isMad'), + raw('UNIX_TIMESTAMP(lastProtoDateTime)').as('last_seen'), + raw('X(currentPos)').as('last_lat'), + raw('Y(currentPos)').as('last_lon'), + raw(true).as('isMad'), ]) } else { - query.join('instance', 'device.instance_name', 'instance.name') + query + .join('instance', 'device.instance_name', 'instance.name') .select( 'uuid AS id', 'last_seen', @@ -34,10 +32,8 @@ module.exports = class Device extends Model { 'last_lon', 'type', 'instance_name', - raw('json_extract(data, "$.area")') - .as('route'), - raw('json_extract(data, "$.radius")') - .as('radius'), + raw('json_extract(data, "$.area")').as('route'), + raw('json_extract(data, "$.radius")').as('radius'), ) } if (areaRestrictions.length) { diff --git a/server/src/models/Filters.js b/server/src/models/Filters.js index ad4c4c280..c14d3f586 100644 --- a/server/src/models/Filters.js +++ b/server/src/models/Filters.js @@ -1,5 +1,9 @@ /* eslint-disable max-classes-per-file */ -const { api: { pvp: { leagues } } } = require('../services/config') +const { + api: { + pvp: { leagues }, + }, +} = require('../services/config') class GenericFilter { constructor(enabled, size) { @@ -17,7 +21,13 @@ class PokemonFilter extends GenericFilter { this.def_iv = def || [0, 15] this.sta_iv = sta || [0, 15] this.level = level || [1, 35] - leagues.forEach(league => this[league.name] = pvp || [(league.minRank || 1), (league.maxRank || 100)]) + leagues.forEach( + (league) => + (this[league.name] = pvp || [ + league.minRank || 1, + league.maxRank || 100, + ]), + ) } } diff --git a/server/src/models/Gym.js b/server/src/models/Gym.js index b31b9dc07..051fec57c 100644 --- a/server/src/models/Gym.js +++ b/server/src/models/Gym.js @@ -6,15 +6,47 @@ const { Event } = require('../services/initialization') const getAreaSql = require('../services/functions/getAreaSql') const { api: { searchResultsLimit, queryLimits, gymValidDataLimit, hideOldGyms }, - defaultFilters: { gyms: { baseTeamIds, baseGymSlotAmounts } }, + defaultFilters: { + gyms: { baseTeamIds, baseGymSlotAmounts }, + }, } = require('../services/config') const Badge = require('./Badge') -const coreFields = ['id', 'name', 'url', 'lat', 'lon', 'updated', 'last_modified_timestamp'] +const coreFields = [ + 'id', + 'name', + 'url', + 'lat', + 'lon', + 'updated', + 'last_modified_timestamp', +] -const gymFields = ['available_slots', 'ex_raid_eligible', 'ar_scan_eligible', 'team_id', 'in_battle', 'guarding_pokemon_id', 'total_cp', 'power_up_points', 'power_up_level', 'power_up_end_timestamp'] +const gymFields = [ + 'available_slots', + 'ex_raid_eligible', + 'ar_scan_eligible', + 'team_id', + 'in_battle', + 'guarding_pokemon_id', + 'total_cp', + 'power_up_points', + 'power_up_level', + 'power_up_end_timestamp', +] -const raidFields = ['raid_level', 'raid_battle_timestamp', 'raid_end_timestamp', 'raid_pokemon_id', 'raid_pokemon_form', 'raid_pokemon_gender', 'raid_pokemon_costume', 'raid_pokemon_evolution', 'raid_pokemon_move_1', 'raid_pokemon_move_2'] +const raidFields = [ + 'raid_level', + 'raid_battle_timestamp', + 'raid_end_timestamp', + 'raid_pokemon_id', + 'raid_pokemon_form', + 'raid_pokemon_gender', + 'raid_pokemon_costume', + 'raid_pokemon_evolution', + 'raid_pokemon_move_1', + 'raid_pokemon_move_2', +] module.exports = class Gym extends Model { static get tableName() { @@ -22,15 +54,29 @@ module.exports = class Gym extends Model { } static async getAll(perms, args, { isMad, availableSlotsCol }, userId) { - const { gyms: gymPerms, raids: raidPerms, areaRestrictions, gymBadges } = perms const { - onlyAllGyms, onlyRaids, onlyExEligible, onlyInBattle, onlyArEligible, onlyRaidTier, onlyGymBadges, onlyBadge, ts, + gyms: gymPerms, + raids: raidPerms, + areaRestrictions, + gymBadges, + } = perms + const { + onlyAllGyms, + onlyRaids, + onlyExEligible, + onlyInBattle, + onlyArEligible, + onlyRaidTier, + onlyGymBadges, + onlyBadge, + ts, } = args.filters - const safeTs = ts || Math.floor((new Date()).getTime() / 1000) + const safeTs = ts || Math.floor(new Date().getTime() / 1000) const query = this.query() if (isMad) { - query.leftJoin('gymdetails', 'gym.gym_id', 'gymdetails.gym_id') + query + .leftJoin('gymdetails', 'gym.gym_id', 'gymdetails.gym_id') .leftJoin('raid', 'gym.gym_id', 'raid.gym_id') .select([ 'gym.gym_id AS id', @@ -53,22 +99,23 @@ module.exports = class Gym extends Model { 'evolution AS raid_pokemon_evolution', 'move_1 AS raid_pokemon_move_1', 'move_2 AS raid_pokemon_move_2', - raw('UNIX_TIMESTAMP(last_modified)') - .as('last_modified_timestamp'), - raw('UNIX_TIMESTAMP(end)') - .as('raid_end_timestamp'), - raw('UNIX_TIMESTAMP(start)') - .as('raid_battle_timestamp'), - raw('UNIX_TIMESTAMP(gym.last_scanned)') - .as('updated'), + raw('UNIX_TIMESTAMP(last_modified)').as('last_modified_timestamp'), + raw('UNIX_TIMESTAMP(end)').as('raid_end_timestamp'), + raw('UNIX_TIMESTAMP(start)').as('raid_battle_timestamp'), + raw('UNIX_TIMESTAMP(gym.last_scanned)').as('updated'), ]) if (hideOldGyms) { - query.whereRaw(`UNIX_TIMESTAMP(gym.last_scanned) > ${Date.now() / 1000 - (gymValidDataLimit * 86400)}`) + query.whereRaw( + `UNIX_TIMESTAMP(gym.last_scanned) > ${ + Date.now() / 1000 - gymValidDataLimit * 86400 + }`, + ) } } else if (hideOldGyms) { - query.where('updated', '>', Date.now() / 1000 - (gymValidDataLimit * 86400)) + query.where('updated', '>', Date.now() / 1000 - gymValidDataLimit * 86400) } - query.whereBetween(isMad ? 'latitude' : 'lat', [args.minLat, args.maxLat]) + query + .whereBetween(isMad ? 'latitude' : 'lat', [args.minLat, args.maxLat]) .andWhereBetween(isMad ? 'longitude' : 'lon', [args.minLon, args.maxLon]) .andWhere(isMad ? 'enabled' : 'deleted', isMad) @@ -77,38 +124,54 @@ module.exports = class Gym extends Model { const teams = [] const eggs = [] const slots = [] - const actualBadge = onlyBadge === 'all' ? 'all' : onlyBadge && +onlyBadge.replace('badge_', '') + const actualBadge = + onlyBadge === 'all' + ? 'all' + : onlyBadge && +onlyBadge.replace('badge_', '') - const userBadges = onlyGymBadges && gymBadges && userId - ? await Badge.query() - .where('userId', userId) - .andWhere('badge', ...(actualBadge === 'all' ? ['>', 0] : [actualBadge])) - : [] + const userBadges = + onlyGymBadges && gymBadges && userId + ? await Badge.query() + .where('userId', userId) + .andWhere( + 'badge', + ...(actualBadge === 'all' ? ['>', 0] : [actualBadge]), + ) + : [] - Object.keys(args.filters).forEach(gym => { + Object.keys(args.filters).forEach((gym) => { switch (gym.charAt(0)) { case 'r': - case 'o': break - case 'e': eggs.push(gym.slice(1)); break - case 't': teams.push(gym.slice(1).split('-')[0]); break - case 'g': slots.push({ - team: gym.slice(1).split('-')[0], - slots: baseGymSlotAmounts.length - gym.slice(1).split('-')[1], - }); break - default: { - const [id, form] = gym.split('-') - raidBosses.add(id) - raidForms.add(form) - } break + case 'o': + break + case 'e': + eggs.push(gym.slice(1)) + break + case 't': + teams.push(gym.slice(1).split('-')[0]) + break + case 'g': + slots.push({ + team: gym.slice(1).split('-')[0], + slots: baseGymSlotAmounts.length - gym.slice(1).split('-')[1], + }) + break + default: + { + const [id, form] = gym.split('-') + raidBosses.add(id) + raidForms.add(form) + } + break } }) const finalTeams = [] - const finalSlots = Object.fromEntries(baseTeamIds.map(team => [team, []])) + const finalSlots = Object.fromEntries(baseTeamIds.map((team) => [team, []])) - teams.forEach(team => { + teams.forEach((team) => { let slotCount = 0 - slots.forEach(slot => { + slots.forEach((slot) => { if (slot.team === team) { slotCount += 1 finalSlots[team].push(+slot.slots) @@ -120,13 +183,24 @@ module.exports = class Gym extends Model { } }) - if (!onlyArEligible && !onlyExEligible && !onlyInBattle && !userBadges.length) { + if ( + !onlyArEligible && + !onlyExEligible && + !onlyInBattle && + !userBadges.length + ) { // Does some checks if no special filters are enabled if (!onlyRaids && onlyAllGyms && !slots.length && !finalTeams.length) { // Returns nothing if gyms are enabled but no teams are selected return [] } - if (!onlyAllGyms && onlyRaids && onlyRaidTier === 'all' && !raidBosses.size && !eggs.length) { + if ( + !onlyAllGyms && + onlyRaids && + onlyRaidTier === 'all' && + !raidBosses.size && + !eggs.length + ) { // Returns nothing if only raids are enabled without any filters return [] } @@ -136,19 +210,19 @@ module.exports = class Gym extends Model { } } - query.andWhere(gym => { + query.andWhere((gym) => { if (onlyExEligible && gymPerms) { - gym.orWhere(ex => { + gym.orWhere((ex) => { ex.where(isMad ? 'is_ex_raid_eligible' : 'ex_raid_eligible', 1) }) } if (onlyInBattle && gymPerms) { - gym.orWhere(battle => { + gym.orWhere((battle) => { battle.where(isMad ? 'is_in_battle' : 'in_battle', 1) }) } if (onlyArEligible && gymPerms) { - gym.orWhere(ar => { + gym.orWhere((ar) => { ar.where(isMad ? 'is_ar_scan_eligible' : 'ar_scan_eligible', 1) }) } @@ -159,52 +233,83 @@ module.exports = class Gym extends Model { gym.orWhereNotNull('team_id') } else { if (finalTeams.length) { - gym.orWhere(team => { + gym.orWhere((team) => { team.whereIn('team_id', finalTeams) }) } Object.entries(finalSlots).forEach(([team, teamSlots]) => { if (teamSlots.length) { - gym.orWhere(gymSlot => { - gymSlot.where('team_id', team) - .whereIn(isMad ? 'slots_available' : availableSlotsCol, teamSlots) + gym.orWhere((gymSlot) => { + gymSlot + .where('team_id', team) + .whereIn( + isMad ? 'slots_available' : availableSlotsCol, + teamSlots, + ) }) } }) } } if (userBadges.length) { - gym.orWhereIn(isMad ? 'gym.gym_id' : 'id', userBadges.map(badge => badge.gymId)) + gym.orWhereIn( + isMad ? 'gym.gym_id' : 'id', + userBadges.map((badge) => badge.gymId), + ) } if (onlyRaids && raidPerms) { if (onlyRaidTier === 'all') { if (raidBosses.size) { - gym.orWhere(raid => { - raid.where(isMad ? 'end' : 'raid_end_timestamp', '>=', isMad ? this.knex().fn.now() : safeTs) - .whereIn(isMad ? 'pokemon_id' : 'raid_pokemon_id', [...raidBosses]) - .whereIn(isMad ? 'raid.form' : 'raid_pokemon_form', [...raidForms]) + gym.orWhere((raid) => { + raid + .where( + isMad ? 'end' : 'raid_end_timestamp', + '>=', + isMad ? this.knex().fn.now() : safeTs, + ) + .whereIn(isMad ? 'pokemon_id' : 'raid_pokemon_id', [ + ...raidBosses, + ]) + .whereIn(isMad ? 'raid.form' : 'raid_pokemon_form', [ + ...raidForms, + ]) }) } if (eggs.length) { - gym.orWhere(egg => { + gym.orWhere((egg) => { if (eggs.length === 6) { egg.where(isMad ? 'level' : 'raid_level', '>', 0) } else { egg.whereIn(isMad ? 'level' : 'raid_level', eggs) } - egg.andWhere(eggStatus => { - eggStatus.where(isMad ? 'start' : 'raid_battle_timestamp', '>=', isMad ? this.knex().fn.now() : safeTs) - .orWhere(unknownEggs => { - unknownEggs.where(isMad ? 'pokemon_id' : 'raid_pokemon_id', 0) - .andWhere(isMad ? 'end' : 'raid_end_timestamp', '>=', isMad ? this.knex().fn.now() : safeTs) + egg.andWhere((eggStatus) => { + eggStatus + .where( + isMad ? 'start' : 'raid_battle_timestamp', + '>=', + isMad ? this.knex().fn.now() : safeTs, + ) + .orWhere((unknownEggs) => { + unknownEggs + .where(isMad ? 'pokemon_id' : 'raid_pokemon_id', 0) + .andWhere( + isMad ? 'end' : 'raid_end_timestamp', + '>=', + isMad ? this.knex().fn.now() : safeTs, + ) }) }) }) } } else { - gym.orWhere(raidTier => { - raidTier.where(isMad ? 'level' : 'raid_level', onlyRaidTier) - .andWhere(isMad ? 'end' : 'raid_end_timestamp', '>=', isMad ? this.knex().fn.now() : safeTs) + gym.orWhere((raidTier) => { + raidTier + .where(isMad ? 'level' : 'raid_level', onlyRaidTier) + .andWhere( + isMad ? 'end' : 'raid_end_timestamp', + '>=', + isMad ? this.knex().fn.now() : safeTs, + ) }) } } @@ -213,12 +318,16 @@ module.exports = class Gym extends Model { getAreaSql(query, areaRestrictions, isMad) } - const secondaryFilter = queryResults => { + const secondaryFilter = (queryResults) => { const filteredResults = [] - const userBadgeObj = Object.fromEntries(userBadges.map(b => [b.gymId, b.badge])) + const userBadgeObj = Object.fromEntries( + userBadges.map((b) => [b.gymId, b.badge]), + ) - queryResults.forEach(gym => { - const newGym = Object.fromEntries(coreFields.map(field => [field, gym[field]])) + queryResults.forEach((gym) => { + const newGym = Object.fromEntries( + coreFields.map((field) => [field, gym[field]]), + ) const isRaid = gym.raid_end_timestamp > safeTs const isEgg = isRaid && !gym.raid_pokemon_id @@ -229,18 +338,29 @@ module.exports = class Gym extends Model { if (gym.availble_slots !== undefined) { gym.available_slots = gym.availble_slots } - if (gym.updated > Date.now() / 1000 - (gymValidDataLimit * 86400)) { - gymFields.forEach(field => newGym[field] = gym[field]) + if (gym.updated > Date.now() / 1000 - gymValidDataLimit * 86400) { + gymFields.forEach((field) => (newGym[field] = gym[field])) } } - if (onlyRaids && raidPerms && (onlyRaidTier === 'all' - ? (args.filters[`${gym.raid_pokemon_id}-${gym.raid_pokemon_form}`] && isRaid) || (args.filters[`e${gym.raid_level}`] && isEgg) - : onlyRaidTier === gym.raid_level && (isRaid || isEgg))) { - raidFields.forEach(field => newGym[field] = gym[field]) + if ( + onlyRaids && + raidPerms && + (onlyRaidTier === 'all' + ? (args.filters[ + `${gym.raid_pokemon_id}-${gym.raid_pokemon_form}` + ] && + isRaid) || + (args.filters[`e${gym.raid_level}`] && isEgg) + : onlyRaidTier === gym.raid_level && (isRaid || isEgg)) + ) { + raidFields.forEach((field) => (newGym[field] = gym[field])) newGym.hasRaid = true } - if ((onlyAllGyms || onlyExEligible || onlyArEligible || onlyInBattle) && (finalTeams.includes(gym.team_id) - || finalSlots[gym.team_id]?.includes(gym.available_slots))) { + if ( + (onlyAllGyms || onlyExEligible || onlyArEligible || onlyInBattle) && + (finalTeams.includes(gym.team_id) || + finalSlots[gym.team_id]?.includes(gym.available_slots)) + ) { newGym.hasGym = true } if (newGym.hasRaid || newGym.badge || newGym.hasGym) { @@ -253,7 +373,7 @@ module.exports = class Gym extends Model { } static async getAvailable({ isMad, availableSlotsCol }) { - const ts = Math.floor((new Date()).getTime() / 1000) + const ts = Math.floor(new Date().getTime() / 1000) const results = await this.query() .select([ isMad ? 'pokemon_id AS raid_pokemon_id' : 'raid_pokemon_id', @@ -261,7 +381,11 @@ module.exports = class Gym extends Model { isMad ? 'level AS raid_level' : 'raid_level', ]) .from(isMad ? 'raid' : 'gym') - .where(isMad ? 'end' : 'raid_end_timestamp', '>=', isMad ? this.knex().fn.now() : ts) + .where( + isMad ? 'end' : 'raid_end_timestamp', + '>=', + isMad ? this.knex().fn.now() : ts, + ) .andWhere(isMad ? 'level' : 'raid_level', '>', 0) .groupBy([ isMad ? 'pokemon_id' : 'raid_pokemon_id', @@ -274,13 +398,10 @@ module.exports = class Gym extends Model { 'team_id AS team', isMad ? 'slots_available AS slots' : `${availableSlotsCol} AS slots`, ]) - .groupBy([ - 'team_id', - isMad ? 'slots_available' : availableSlotsCol, - ]) + .groupBy(['team_id', isMad ? 'slots_available' : availableSlotsCol]) .then((r) => { const unique = new Set() - r.forEach(result => { + r.forEach((result) => { if (result.slots) { unique.add(`g${result.team}-${result.slots}`) } else { @@ -290,15 +411,18 @@ module.exports = class Gym extends Model { return [...unique] }) if (!results.length) { - return { available: [...teamResults, ...await fetchRaids()] } + return { available: [...teamResults, ...(await fetchRaids())] } } return { - available: [...teamResults, ...results.flatMap(result => { - if (result.raid_pokemon_id) { - return `${result.raid_pokemon_id}-${result.raid_pokemon_form}` - } - return [`e${result.raid_level}`, `r${result.raid_level}`] - })], + available: [ + ...teamResults, + ...results.flatMap((result) => { + if (result.raid_pokemon_id) { + return `${result.raid_pokemon_id}-${result.raid_pokemon_form}` + } + return [`e${result.raid_level}`, `r${result.raid_level}`] + }), + ], } } @@ -327,10 +451,10 @@ module.exports = class Gym extends Model { static async searchRaids(perms, args, { isMad }, distance) { const { search, locale } = args - const pokemonIds = Object.keys(Event.masterfile.pokemon).filter(pkmn => ( - i18next.t(`poke_${pkmn}`, { lng: locale }).toLowerCase().includes(search) - )) - const safeTs = args.ts || Math.floor((new Date()).getTime() / 1000) + const pokemonIds = Object.keys(Event.masterfile.pokemon).filter((pkmn) => + i18next.t(`poke_${pkmn}`, { lng: locale }).toLowerCase().includes(search), + ) + const safeTs = args.ts || Math.floor(new Date().getTime() / 1000) const query = this.query() .select([ 'name', @@ -341,17 +465,28 @@ module.exports = class Gym extends Model { isMad ? 'raid.form AS raid_pokemon_form' : 'raid_pokemon_form', isMad ? 'raid.gender AS raid_pokemon_gender' : 'raid_pokemon_gender', isMad ? 'raid.costume AS raid_pokemon_costume' : 'raid_pokemon_costume', - isMad ? 'evolution AS raid_pokemon_evolution' : 'raid_pokemon_evolution', + isMad + ? 'evolution AS raid_pokemon_evolution' + : 'raid_pokemon_evolution', distance, ]) .whereIn(isMad ? 'pokemon_id' : 'raid_pokemon_id', pokemonIds) .limit(searchResultsLimit) .orderBy('distance') - .andWhere(isMad ? 'start' : 'raid_battle_timestamp', '<=', isMad ? this.knex().fn.now() : safeTs) - .andWhere(isMad ? 'end' : 'raid_end_timestamp', '>=', isMad ? this.knex().fn.now() : safeTs) + .andWhere( + isMad ? 'start' : 'raid_battle_timestamp', + '<=', + isMad ? this.knex().fn.now() : safeTs, + ) + .andWhere( + isMad ? 'end' : 'raid_end_timestamp', + '>=', + isMad ? this.knex().fn.now() : safeTs, + ) .andWhere(isMad ? 'enabled' : 'deleted', isMad) if (isMad) { - query.leftJoin('gymdetails', 'gym.gym_id', 'gymdetails.gym_id') + query + .leftJoin('gymdetails', 'gym.gym_id', 'gymdetails.gym_id') .leftJoin('raid', 'gym.gym_id', 'raid.gym_id') } if (perms.areaRestrictions?.length) { @@ -361,27 +496,28 @@ module.exports = class Gym extends Model { } static async getBadges(userGyms, _, { isMad }) { - const query = this.query() - .select([ - '*', - isMad ? 'gym.gym_id AS id' : 'gym.id', - isMad ? 'latitude AS lat' : 'lat', - isMad ? 'longitude AS lon' : 'lon', - isMad ? 'enabled' : 'deleted', - ]) + const query = this.query().select([ + '*', + isMad ? 'gym.gym_id AS id' : 'gym.id', + isMad ? 'latitude AS lat' : 'lat', + isMad ? 'longitude AS lon' : 'lon', + isMad ? 'enabled' : 'deleted', + ]) if (isMad) { query.leftJoin('gymdetails', 'gym.gym_id', 'gymdetails.gym_id') } - const results = await query - .whereIn(isMad ? 'gym.gym_id' : 'gym.id', userGyms.map(gym => gym.gymId)) + const results = await query.whereIn( + isMad ? 'gym.gym_id' : 'gym.id', + userGyms.map((gym) => gym.gymId), + ) return results - .map(gym => { + .map((gym) => { if (typeof gym.enabled === 'boolean') { gym.deleted = !gym.enabled } - const gymBadge = userGyms.find(userGym => userGym.gymId === gym.id) + const gymBadge = userGyms.find((userGym) => userGym.gymId === gym.id) if (gymBadge) { gym.badge = gymBadge.badge @@ -406,21 +542,21 @@ module.exports = class Gym extends Model { static getSubmissions(args, { isMad }) { const query = this.query() - .whereBetween(`lat${isMad ? 'itude' : ''}`, [args.minLat - 0.025, args.maxLat + 0.025]) - .andWhereBetween(`lon${isMad ? 'gitude' : ''}`, [args.minLon - 0.025, args.maxLon + 0.025]) + .whereBetween(`lat${isMad ? 'itude' : ''}`, [ + args.minLat - 0.025, + args.maxLat + 0.025, + ]) + .andWhereBetween(`lon${isMad ? 'gitude' : ''}`, [ + args.minLon - 0.025, + args.maxLon + 0.025, + ]) .andWhere(isMad ? 'enabled' : 'deleted', isMad) if (isMad) { - query.select([ - 'gym_id AS id', - 'latitude AS lat', - 'longitude AS lon', - ]) + query.select(['gym_id AS id', 'latitude AS lat', 'longitude AS lon']) } else { - query.select(['id', 'lat', 'lon']) - .andWhere(poi => { - poi.whereNull('sponsor_id') - .orWhere('sponsor_id', 0) - }) + query.select(['id', 'lat', 'lon']).andWhere((poi) => { + poi.whereNull('sponsor_id').orWhere('sponsor_id', 0) + }) } return query } diff --git a/server/src/models/Nest.js b/server/src/models/Nest.js index ce61f6dde..89b4ce92c 100644 --- a/server/src/models/Nest.js +++ b/server/src/models/Nest.js @@ -4,7 +4,9 @@ const { Event } = require('../services/initialization') const getAreaSql = require('../services/functions/getAreaSql') const { api: { searchResultsLimit, queryLimits }, - defaultFilters: { nests: { avgFilter } }, + defaultFilters: { + nests: { avgFilter }, + }, } = require('../services/config') const fetchNests = require('../services/api/fetchNests') @@ -20,7 +22,7 @@ module.exports = class Nest extends Model { static async getAll(perms, args) { const { areaRestrictions } = perms const pokemon = [] - Object.keys(args.filters).forEach(pkmn => { + Object.keys(args.filters).forEach((pkmn) => { if (!pkmn.startsWith('o')) { pokemon.push(pkmn.split('-')[0]) } @@ -38,9 +40,9 @@ module.exports = class Nest extends Model { } const results = await query.limit(queryLimits.nests) - const fixedForms = queryResults => { + const fixedForms = (queryResults) => { const returnedResults = [] - queryResults.forEach(pkmn => { + queryResults.forEach((pkmn) => { if (pkmn.pokemon_form == 0 || pkmn.pokemon_form === null) { const formId = Event.masterfile.pokemon[pkmn.pokemon_id].defaultFormId if (formId) pkmn.pokemon_form = formId @@ -61,20 +63,24 @@ module.exports = class Nest extends Model { .orderBy('pokemon_id', 'asc') return { - available: results.length ? results.map(pokemon => { - if (pokemon.pokemon_form == 0 || pokemon.pokemon_form === null) { - return `${pokemon.pokemon_id}-${Event.masterfile.pokemon[pokemon.pokemon_id].defaultFormId || 0}` - } - return `${pokemon.pokemon_id}-${pokemon.pokemon_form || 0}` - }) : fetchNests(), + available: results.length + ? results.map((pokemon) => { + if (pokemon.pokemon_form == 0 || pokemon.pokemon_form === null) { + return `${pokemon.pokemon_id}-${ + Event.masterfile.pokemon[pokemon.pokemon_id].defaultFormId || 0 + }` + } + return `${pokemon.pokemon_id}-${pokemon.pokemon_form || 0}` + }) + : fetchNests(), } } static async search(perms, args, { isMad }, distance) { const { search, locale } = args - const pokemonIds = Object.keys(Event.masterfile.pokemon).filter(pkmn => ( - i18next.t(`poke_${pkmn}`, { lng: locale }).toLowerCase().includes(search) - )) + const pokemonIds = Object.keys(Event.masterfile.pokemon).filter((pkmn) => + i18next.t(`poke_${pkmn}`, { lng: locale }).toLowerCase().includes(search), + ) const query = this.query() .select([ 'nest_id AS id', diff --git a/server/src/models/Pokemon.js b/server/src/models/Pokemon.js index 76d387098..616bdc5cd 100644 --- a/server/src/models/Pokemon.js +++ b/server/src/models/Pokemon.js @@ -4,14 +4,26 @@ const { Model, raw, ref } = require('objection') const { Event } = require('../services/initialization') const legacyFilter = require('../services/legacyFilter') const { - api: { pvp: { minCp: pvpMinCp, leagues, reactMapHandlesPvp, leagueObj }, queryLimits }, + api: { + pvp: { minCp: pvpMinCp, leagues, reactMapHandlesPvp, leagueObj }, + queryLimits, + }, } = require('../services/config') const getAreaSql = require('../services/functions/getAreaSql') const { Pvp } = require('../services/initialization') -const levelCalc = 'IFNULL(IF(cp_multiplier < 0.734, ROUND(58.35178527 * cp_multiplier * cp_multiplier - 2.838007664 * cp_multiplier + 0.8539209906), ROUND(171.0112688 * cp_multiplier - 95.20425243)), NULL)' -const ivCalc = 'IFNULL((individual_attack + individual_defense + individual_stamina) / 0.45, NULL)' -const keys = ['iv', 'level', 'atk_iv', 'def_iv', 'sta_iv', ...leagues.map(league => league.name)] +const levelCalc = + 'IFNULL(IF(cp_multiplier < 0.734, ROUND(58.35178527 * cp_multiplier * cp_multiplier - 2.838007664 * cp_multiplier + 0.8539209906), ROUND(171.0112688 * cp_multiplier - 95.20425243)), NULL)' +const ivCalc = + 'IFNULL((individual_attack + individual_defense + individual_stamina) / 0.45, NULL)' +const keys = [ + 'iv', + 'level', + 'atk_iv', + 'def_iv', + 'sta_iv', + ...leagues.map((league) => league.name), +] const madKeys = { iv: raw(ivCalc), level: raw(levelCalc), @@ -20,14 +32,17 @@ const madKeys = { sta_iv: 'individual_stamina', } -const getMadSql = q => ( - q.leftJoin('trs_spawn', 'pokemon.spawnpoint_id', 'trs_spawn.spawnpoint') - .leftJoin('pokemon_display', 'pokemon.encounter_id', 'pokemon_display.encounter_id') +const getMadSql = (q) => + q + .leftJoin('trs_spawn', 'pokemon.spawnpoint_id', 'trs_spawn.spawnpoint') + .leftJoin( + 'pokemon_display', + 'pokemon.encounter_id', + 'pokemon_display.encounter_id', + ) .select([ '*', - ref('pokemon.encounter_id') - .castTo('CHAR') - .as('id'), + ref('pokemon.encounter_id').castTo('CHAR').as('id'), 'pokemon.latitude AS lat', 'pokemon.longitude AS lon', 'individual_attack AS atk_iv', @@ -40,18 +55,14 @@ const getMadSql = q => ( 'pokemon_display.pokemon AS display_pokemon_id', 'pokemon_display.form AS ditto_form', 'weather_boosted_condition AS weather', - raw('IF(calc_endminsec IS NOT NULL, 1, NULL)') - .as('expire_timestamp_verified'), - raw('Unix_timestamp(disappear_time)') - .as('expire_timestamp'), - raw('Unix_timestamp(last_modified)') - .as('updated'), - raw(ivCalc) - .as('iv'), - raw(levelCalc) - .as('level'), + raw('IF(calc_endminsec IS NOT NULL, 1, NULL)').as( + 'expire_timestamp_verified', + ), + raw('Unix_timestamp(disappear_time)').as('expire_timestamp'), + raw('Unix_timestamp(last_modified)').as('updated'), + raw(ivCalc).as('iv'), + raw(levelCalc).as('level'), ]) -) module.exports = class Pokemon extends Model { static get tableName() { @@ -59,18 +70,26 @@ module.exports = class Pokemon extends Model { } static async getAll(perms, args, { isMad, pvpV2 }) { + const { iv: ivs, pvp, areaRestrictions } = perms const { - iv: ivs, pvp, areaRestrictions, - } = perms - const { - onlyStandard, onlyIvOr, onlyXlKarp, onlyXsRat, onlyZeroIv, onlyHundoIv, onlyPvpMega, onlyLinkGlobal, ts, + onlyStandard, + onlyIvOr, + onlyXlKarp, + onlyXsRat, + onlyZeroIv, + onlyHundoIv, + onlyPvpMega, + onlyLinkGlobal, + ts, } = args.filters let queryPvp = false const safeTs = ts || Math.floor(Date.now() / 1000) // quick check to make sure no Pokemon are returned when none are enabled for users with only Pokemon perms if (!ivs && !pvp) { - const noPokemonSelect = Object.keys(args.filters).find(x => x.charAt(0) !== 'o') + const noPokemonSelect = Object.keys(args.filters).find( + (x) => x.charAt(0) !== 'o', + ) if (!noPokemonSelect) return [] } @@ -78,14 +97,17 @@ module.exports = class Pokemon extends Model { const rankCheck = pkmn.rank <= max && pkmn.rank >= min const cpCheck = pvpV2 || reactMapHandlesPvp || pkmn.cp >= pvpMinCp[league] const megaCheck = !pkmn.evolution || onlyPvpMega - const capCheck = pvpV2 || reactMapHandlesPvp ? pkmn.capped || args.filters[`onlyPvp${pkmn.cap}`] : true + const capCheck = + pvpV2 || reactMapHandlesPvp + ? pkmn.capped || args.filters[`onlyPvp${pkmn.cap}`] + : true return rankCheck && cpCheck && megaCheck && capCheck } const getRanks = (league, data, filterId) => { const [min, max] = getMinMax(filterId, league) let best = 4096 - const filtered = data.filter(pkmn => { + const filtered = data.filter((pkmn) => { const valid = pvpCheck(pkmn, league, min, max) if (valid && pkmn.rank < best) best = pkmn.rank return valid @@ -122,7 +144,7 @@ module.exports = class Pokemon extends Model { const parsed = {} const pvpKeys = ['great', 'ultra'] - pvpKeys.forEach(league => { + pvpKeys.forEach((league) => { if (pokemon[`pvp_rankings_${league}_league`]) { parsed[league] = JSON.parse(pokemon[`pvp_rankings_${league}_league`]) } @@ -131,12 +153,13 @@ module.exports = class Pokemon extends Model { } // checks if filters are set to default and skips them if so - const arrayCheck = (filter, key) => filter[key]?.every((v, i) => v === onlyStandard[key][i]) + const arrayCheck = (filter, key) => + filter[key]?.every((v, i) => v === onlyStandard[key][i]) // cycles through the above arrayCheck - const getRelevantKeys = filter => { + const getRelevantKeys = (filter) => { const relevantKeys = [] - keys.forEach(key => { + keys.forEach((key) => { if (!arrayCheck(filter, key)) { relevantKeys.push(key) } @@ -146,7 +169,7 @@ module.exports = class Pokemon extends Model { // generates specific SQL for each slider that isn't set to default, along with perm checks const generateSql = (queryBase, filter, relevant) => { - relevant.forEach(key => { + relevant.forEach((key) => { switch (key) { case 'level': case 'atk_iv': @@ -155,43 +178,58 @@ module.exports = class Pokemon extends Model { case 'iv': if (ivs) { queryBase.andWhereBetween(isMad ? madKeys[key] : key, filter[key]) - } break + } + break default: if (pvp) { queryPvp = true - if (!relevant.includes('iv') - && !relevant.includes('level') - && !relevant.includes('atk_iv') - && !relevant.includes('def_iv') - && !relevant.includes('sta_iv')) { + if ( + !relevant.includes('iv') && + !relevant.includes('level') && + !relevant.includes('atk_iv') && + !relevant.includes('def_iv') && + !relevant.includes('sta_iv') + ) { // doesn't return everything if only pvp stats for individual pokemon queryBase.whereNull('pokemon_id') } - } break + } + break } }) } - const globalCheck = (pkmn) => onlyLinkGlobal ? args.filters[`${pkmn.pokemon_id}-${pkmn.form}`] : true + const globalCheck = (pkmn) => + onlyLinkGlobal ? args.filters[`${pkmn.pokemon_id}-${pkmn.form}`] : true // query builder const query = this.query() if (isMad) { getMadSql(query) } - query.where(isMad ? 'disappear_time' : 'expire_timestamp', '>=', isMad ? this.knex().fn.now() : safeTs) - .andWhereBetween(isMad ? 'pokemon.latitude' : 'lat', [args.minLat, args.maxLat]) - .andWhereBetween(isMad ? 'pokemon.longitude' : 'lon', [args.minLon, args.maxLon]) - .andWhere(ivOr => { + query + .where( + isMad ? 'disappear_time' : 'expire_timestamp', + '>=', + isMad ? this.knex().fn.now() : safeTs, + ) + .andWhereBetween(isMad ? 'pokemon.latitude' : 'lat', [ + args.minLat, + args.maxLat, + ]) + .andWhereBetween(isMad ? 'pokemon.longitude' : 'lon', [ + args.minLon, + args.maxLon, + ]) + .andWhere((ivOr) => { for (const [pkmn, filter] of Object.entries(args.filters)) { if (pkmn.includes('-')) { const relevantFilters = getRelevantKeys(filter) const [id, form] = pkmn.split('-') - ivOr.orWhere(poke => { + ivOr.orWhere((poke) => { if (id === '132') { poke.where('pokemon_id', id) } else { - poke.where('pokemon_id', id) - .andWhere('pokemon.form', form) + poke.where('pokemon_id', id).andWhere('pokemon.form', form) } if (relevantFilters.length) { generateSql(poke, filter, relevantFilters, true) @@ -207,12 +245,10 @@ module.exports = class Pokemon extends Model { } } if (onlyXlKarp) { - ivOr.orWhere('pokemon_id', 129) - .andWhere('weight', '>=', 13.125) + ivOr.orWhere('pokemon_id', 129).andWhere('weight', '>=', 13.125) } if (onlyXsRat) { - ivOr.orWhere('pokemon_id', 19) - .andWhere('weight', '<=', 2.40625) + ivOr.orWhere('pokemon_id', 19).andWhere('weight', '<=', 2.40625) } if (onlyZeroIv && ivs) { ivOr.orWhere(isMad ? raw(ivCalc) : 'iv', 0) @@ -231,7 +267,7 @@ module.exports = class Pokemon extends Model { const listOfIds = [] // form checker - results.forEach(pkmn => { + results.forEach((pkmn) => { let noPvp = true if (pkmn.pokemon_id === 132 && !pkmn.ditto_form) { pkmn.ditto_form = pkmn.form @@ -244,10 +280,13 @@ module.exports = class Pokemon extends Model { pkmn.seen_type = 'encounter' } } - if (pvp && ((pkmn.pvp_rankings_great_league - || pkmn.pvp_rankings_ultra_league - || pkmn.pvp) - || (isMad && reactMapHandlesPvp && pkmn.cp))) { + if ( + pvp && + (pkmn.pvp_rankings_great_league || + pkmn.pvp_rankings_ultra_league || + pkmn.pvp || + (isMad && reactMapHandlesPvp && pkmn.cp)) + ) { noPvp = false listOfIds.push(pkmn.id) pvpResults.push(pkmn) @@ -266,11 +305,24 @@ module.exports = class Pokemon extends Model { } else { pvpQuery.select(['*', raw(true).as('pvpCheck')]) } - pvpQuery.where(isMad ? 'disappear_time' : 'expire_timestamp', '>=', isMad ? this.knex().fn.now() : safeTs) - .andWhereBetween(isMad ? 'pokemon.latitude' : 'lat', [args.minLat, args.maxLat]) - .andWhereBetween(isMad ? 'pokemon.longitude' : 'lon', [args.minLon, args.maxLon]) + pvpQuery + .where( + isMad ? 'disappear_time' : 'expire_timestamp', + '>=', + isMad ? this.knex().fn.now() : safeTs, + ) + .andWhereBetween(isMad ? 'pokemon.latitude' : 'lat', [ + args.minLat, + args.maxLat, + ]) + .andWhereBetween(isMad ? 'pokemon.longitude' : 'lon', [ + args.minLon, + args.maxLon, + ]) if (isMad && listOfIds.length) { - pvpQuery.whereRaw(`pokemon.encounter_id NOT IN ( ${listOfIds.join(',')} )`) + pvpQuery.whereRaw( + `pokemon.encounter_id NOT IN ( ${listOfIds.join(',')} )`, + ) } else { pvpQuery.whereNotIn('id', listOfIds) } @@ -279,19 +331,22 @@ module.exports = class Pokemon extends Model { } else if (pvpV2) { pvpQuery.whereNotNull('pvp') } else { - pvpQuery.andWhere(pvpBuilder => { - pvpBuilder.whereNotNull('pvp_rankings_great_league') + pvpQuery.andWhere((pvpBuilder) => { + pvpBuilder + .whereNotNull('pvp_rankings_great_league') .orWhereNotNull('pvp_rankings_ultra_league') }) } if (areaRestrictions?.length) { getAreaSql(pvpQuery, areaRestrictions, isMad, 'pokemon') } - pvpResults.push(...await pvpQuery.limit(queryLimits.pokemonPvp - results.length)) + pvpResults.push( + ...(await pvpQuery.limit(queryLimits.pokemonPvp - results.length)), + ) } // filter pokes with pvp data - pvpResults.forEach(pkmn => { + pvpResults.forEach((pkmn) => { const parsed = reactMapHandlesPvp ? Pvp.resultWithCache(pkmn, safeTs) : getParsedPvp(pkmn) @@ -303,7 +358,7 @@ module.exports = class Pokemon extends Model { pkmn.form = Event.masterfile.pokemon[pkmn.pokemon_id].defaultFormId } if (!pkmn.seen_type) pkmn.seen_type = 'encounter' - Object.keys(parsed).forEach(league => { + Object.keys(parsed).forEach((league) => { if (leagueObj[league]) { const { filtered, best } = getRanks(league, parsed[league], filterId) if (filtered.length) { @@ -312,7 +367,10 @@ module.exports = class Pokemon extends Model { } } }) - if ((Object.keys(pkmn.cleanPvp).length || !pkmn.pvpCheck) && globalCheck(pkmn)) { + if ( + (Object.keys(pkmn.cleanPvp).length || !pkmn.pvpCheck) && + globalCheck(pkmn) + ) { finalResults.push(pkmn) } }) @@ -320,11 +378,21 @@ module.exports = class Pokemon extends Model { } static async getLegacy(perms, args, { isMad }) { - const ts = Math.floor((new Date()).getTime() / 1000) + const ts = Math.floor(new Date().getTime() / 1000) const query = this.query() - .where(isMad ? 'disappear_time' : 'expire_timestamp', '>=', isMad ? this.knex().fn.now() : ts) - .andWhereBetween(isMad ? 'pokemon.latitude' : 'lat', [args.minLat, args.maxLat]) - .andWhereBetween(isMad ? 'pokemon.longitude' : 'lon', [args.minLon, args.maxLon]) + .where( + isMad ? 'disappear_time' : 'expire_timestamp', + '>=', + isMad ? this.knex().fn.now() : ts, + ) + .andWhereBetween(isMad ? 'pokemon.latitude' : 'lat', [ + args.minLat, + args.maxLat, + ]) + .andWhereBetween(isMad ? 'pokemon.longitude' : 'lon', [ + args.minLon, + args.maxLon, + ]) if (isMad) { getMadSql(query) } @@ -336,13 +404,19 @@ module.exports = class Pokemon extends Model { } static async getAvailable({ isMad }) { - const ts = Math.floor((new Date()).getTime() / 1000) + const ts = Math.floor(new Date().getTime() / 1000) const results = await this.query() .select('pokemon_id', 'form') - .where(isMad ? 'disappear_time' : 'expire_timestamp', '>=', isMad ? this.knex().fn.now() : ts) + .where( + isMad ? 'disappear_time' : 'expire_timestamp', + '>=', + isMad ? this.knex().fn.now() : ts, + ) .groupBy('pokemon_id', 'form') .orderBy('pokemon_id', 'form') - return { available: results.map(pkmn => `${pkmn.pokemon_id}-${pkmn.form}`) } + return { + available: results.map((pkmn) => `${pkmn.pokemon_id}-${pkmn.form}`), + } } static getOne(id, { isMad }) { diff --git a/server/src/models/Pokestop.js b/server/src/models/Pokestop.js index aec882d4d..dd593b941 100644 --- a/server/src/models/Pokestop.js +++ b/server/src/models/Pokestop.js @@ -5,7 +5,12 @@ const { Event } = require('../services/initialization') const fetchQuests = require('../services/api/fetchQuests') const getAreaSql = require('../services/functions/getAreaSql') const { - api: { searchResultsLimit, queryLimits, stopValidDataLimit, hideOldPokestops }, + api: { + searchResultsLimit, + queryLimits, + stopValidDataLimit, + hideOldPokestops, + }, database: { settings }, map, } = require('../services/config') @@ -31,7 +36,7 @@ const madQuestProps = { with_ar: true, stardust_amount: true, } -Object.keys(questProps).forEach(key => { +Object.keys(questProps).forEach((key) => { questPropsAlt[`alternative_${key}`] = true madQuestProps[key] = true }) @@ -45,22 +50,43 @@ module.exports = class Pokestop extends Model { return 'pokestop' } - static async getAll(perms, args, { isMad, hasAltQuests, hasMultiInvasions, multiInvasionMs, hasRewardAmount }) { - const { filters: { - onlyLures, onlyQuests, onlyInvasions, onlyArEligible, onlyAllPokestops, - }, ts, midnight: clientMidnight } = args - const midnight = settings.hideOldQuests - ? clientMidnight || 0 - : 0 - const safeTs = ts || Math.floor((new Date()).getTime() / 1000) + static async getAll( + perms, + args, + { + isMad, + hasAltQuests, + hasMultiInvasions, + multiInvasionMs, + hasRewardAmount, + }, + ) { + const { + filters: { + onlyLures, + onlyQuests, + onlyInvasions, + onlyArEligible, + onlyAllPokestops, + }, + ts, + midnight: clientMidnight, + } = args + const midnight = settings.hideOldQuests ? clientMidnight || 0 : 0 + const safeTs = ts || Math.floor(new Date().getTime() / 1000) const { - lures: lurePerms, quests: questPerms, invasions: invasionPerms, pokestops: pokestopPerms, areaRestrictions, + lures: lurePerms, + quests: questPerms, + invasions: invasionPerms, + pokestops: pokestopPerms, + areaRestrictions, } = perms const query = this.query() if (isMad) { - query.leftJoin('trs_quest', 'pokestop.pokestop_id', 'trs_quest.GUID') + query + .leftJoin('trs_quest', 'pokestop.pokestop_id', 'trs_quest.GUID') .select([ '*', 'pokestop_id AS id', @@ -75,38 +101,50 @@ module.exports = class Pokestop extends Model { 'quest_reward AS quest_rewards', 'quest_pokemon_form_id AS quest_form_id', 'quest_pokemon_costume_id AS quest_costume_id', - raw('UNIX_TIMESTAMP(last_modified)') - .as('last_modified_timestamp'), - raw('UNIX_TIMESTAMP(lure_expiration)') - .as('lure_expire_timestamp'), - raw('UNIX_TIMESTAMP(last_updated)') - .as('updated'), - raw('UNIX_TIMESTAMP(incident_expiration)') - .as('incident_expire_timestamp'), + raw('UNIX_TIMESTAMP(last_modified)').as('last_modified_timestamp'), + raw('UNIX_TIMESTAMP(lure_expiration)').as('lure_expire_timestamp'), + raw('UNIX_TIMESTAMP(last_updated)').as('updated'), + raw('UNIX_TIMESTAMP(incident_expiration)').as( + 'incident_expire_timestamp', + ), ]) if (hideOldPokestops) { - query.whereRaw(`UNIX_TIMESTAMP(last_updated) > ${Date.now() / 1000 - (stopValidDataLimit * 86400)}`) + query.whereRaw( + `UNIX_TIMESTAMP(last_updated) > ${ + Date.now() / 1000 - stopValidDataLimit * 86400 + }`, + ) } } else if (hideOldPokestops) { - query.where('pokestop.updated', '>', Date.now() / 1000 - (stopValidDataLimit * 86400)) + query.where( + 'pokestop.updated', + '>', + Date.now() / 1000 - stopValidDataLimit * 86400, + ) } if (hasMultiInvasions) { - query.leftJoin('incident', 'pokestop.id', 'incident.pokestop_id') + query + .leftJoin('incident', 'pokestop.id', 'incident.pokestop_id') .select([ '*', 'pokestop.updated', 'pokestop.id AS id', 'incident.id AS incidentId', - raw(multiInvasionMs - ? 'FLOOR(incident.updated_ms / 1000) AS incident_updated' - : 'incident.updated AS incident_updated'), - raw(multiInvasionMs - ? 'FLOOR(incident.expiration_ms / 1000) AS incident_expire_timestamp' - : 'incident.expiration AS incident_expire_timestamp'), + raw( + multiInvasionMs + ? 'FLOOR(incident.updated_ms / 1000) AS incident_updated' + : 'incident.updated AS incident_updated', + ), + raw( + multiInvasionMs + ? 'FLOOR(incident.expiration_ms / 1000) AS incident_expire_timestamp' + : 'incident.expiration AS incident_expire_timestamp', + ), 'incident.character AS grunt_type', ]) } - query.whereBetween(isMad ? 'latitude' : 'lat', [args.minLat, args.maxLat]) + query + .whereBetween(isMad ? 'latitude' : 'lat', [args.minLat, args.maxLat]) .andWhereBetween(isMad ? 'longitude' : 'lon', [args.minLon, args.maxLon]) .andWhere(isMad ? 'enabled' : 'deleted', isMad) if (areaRestrictions?.length) { @@ -125,152 +163,266 @@ module.exports = class Pokestop extends Model { const xlCandy = [] const general = [] // preps arrays for interested objects - Object.keys(args.filters).forEach(pokestop => { + Object.keys(args.filters).forEach((pokestop) => { switch (pokestop.charAt(0)) { - case 'o': break - case 'd': stardust.push(pokestop.slice(1).split('-')[0]); break - case 'i': invasions.push(pokestop.slice(1)); break - case 'l': lures.push(pokestop.slice(1)); break - case 'm': energy.push(pokestop.slice(1)); break - case 'q': items.push(pokestop.slice(1)); break - case 'c': candy.push(pokestop.slice(1)); break - case 'x': xlCandy.push(pokestop.slice(1)); break - case 'u': general.push(pokestop.slice(1)); break - default: pokemon.push(pokestop.split('-')[0]); break + case 'o': + break + case 'd': + stardust.push(pokestop.slice(1).split('-')[0]) + break + case 'i': + invasions.push(pokestop.slice(1)) + break + case 'l': + lures.push(pokestop.slice(1)) + break + case 'm': + energy.push(pokestop.slice(1)) + break + case 'q': + items.push(pokestop.slice(1)) + break + case 'c': + candy.push(pokestop.slice(1)) + break + case 'x': + xlCandy.push(pokestop.slice(1)) + break + case 'u': + general.push(pokestop.slice(1)) + break + default: + pokemon.push(pokestop.split('-')[0]) + break } }) // builds the query - query.andWhere(stops => { + query.andWhere((stops) => { if (onlyLures && lurePerms) { - stops.orWhere(lure => { - lure.whereIn(isMad ? 'active_fort_modifier' : 'lure_id', lures) - .andWhere(isMad ? 'lure_expiration' : 'lure_expire_timestamp', '>=', isMad ? this.knex().fn.now() : safeTs) + stops.orWhere((lure) => { + lure + .whereIn(isMad ? 'active_fort_modifier' : 'lure_id', lures) + .andWhere( + isMad ? 'lure_expiration' : 'lure_expire_timestamp', + '>=', + isMad ? this.knex().fn.now() : safeTs, + ) }) } if (onlyQuests && questPerms) { - stops.orWhere(quest => { - quest.where(timestamps => { + stops.orWhere((quest) => { + quest.where((timestamps) => { timestamps.where('quest_timestamp', '>=', midnight) if (hasAltQuests) { - timestamps.orWhere('alternative_quest_timestamp', '>=', midnight) + timestamps.orWhere( + 'alternative_quest_timestamp', + '>=', + midnight, + ) } }) - quest.andWhere(questTypes => { - questTypes.orWhereIn('quest_item_id', items) + quest.andWhere((questTypes) => { + questTypes + .orWhereIn('quest_item_id', items) .orWhereIn('quest_pokemon_id', pokemon) if (hasAltQuests) { - questTypes.orWhereIn('alternative_quest_item_id', items) + questTypes + .orWhereIn('alternative_quest_item_id', items) .orWhereIn('alternative_quest_pokemon_id', pokemon) } if (hasRewardAmount) { - questTypes.orWhereIn(isMad ? 'quest_stardust' : 'quest_reward_amount', stardust) + questTypes.orWhereIn( + isMad ? 'quest_stardust' : 'quest_reward_amount', + stardust, + ) if (hasAltQuests) { - questTypes.orWhereIn('alternative_quest_reward_amount', stardust) + questTypes.orWhereIn( + 'alternative_quest_reward_amount', + stardust, + ) } } else { - stardust.forEach(amount => { - questTypes.orWhere(dust => { - dust.where('quest_reward_type', 3) - .andWhere(raw(`json_extract(quest_rewards, "$[0].info.amount") = ${amount}`)) + stardust.forEach((amount) => { + questTypes.orWhere((dust) => { + dust + .where('quest_reward_type', 3) + .andWhere( + raw( + `json_extract(quest_rewards, "$[0].info.amount") = ${amount}`, + ), + ) }) if (hasAltQuests) { - questTypes.orWhere(altDust => { - altDust.where('alternative_quest_reward_type', 3) - .andWhere(raw(`json_extract(alternative_quest_rewards, "$[0].info.amount") = ${amount}`)) + questTypes.orWhere((altDust) => { + altDust + .where('alternative_quest_reward_type', 3) + .andWhere( + raw( + `json_extract(alternative_quest_rewards, "$[0].info.amount") = ${amount}`, + ), + ) }) } }) } - energy.forEach(megaEnergy => { + energy.forEach((megaEnergy) => { const [pokeId, amount] = megaEnergy.split('-') if (hasRewardAmount) { - questTypes.orWhere(mega => { - mega.where('quest_reward_type', 12) - .andWhere(isMad ? 'quest_item_amount' : 'quest_reward_amount', amount) + questTypes.orWhere((mega) => { + mega + .where('quest_reward_type', 12) + .andWhere( + isMad ? 'quest_item_amount' : 'quest_reward_amount', + amount, + ) .andWhere('quest_pokemon_id', pokeId) }) if (hasAltQuests) { - questTypes.orWhere(altMega => { - altMega.where('alternative_quest_reward_type', 12) + questTypes.orWhere((altMega) => { + altMega + .where('alternative_quest_reward_type', 12) .andWhere('alternative_quest_reward_amount', amount) .andWhere('alternative_quest_pokemon_id', pokeId) }) } } else { - questTypes.orWhere(mega => { + questTypes.orWhere((mega) => { mega.where('quest_reward_type', 12) if (hasRewardAmount) { - mega.andWhere('quest_reward_amount', amount) + mega + .andWhere('quest_reward_amount', amount) .andWhere('quest_pokemon_id', pokeId) } else { - mega.andWhere(raw(`json_extract(${isMad ? 'quest_reward' : 'quest_rewards'}, "$[0].${isMad ? 'mega_resource' : 'info'}.pokemon_id") = ${pokeId}`)) - .andWhere(raw(`json_extract(${isMad ? 'quest_reward' : 'quest_rewards'}, "$[0].${isMad ? 'mega_resource' : 'info'}.amount") = ${amount}`)) + mega + .andWhere( + raw( + `json_extract(${ + isMad ? 'quest_reward' : 'quest_rewards' + }, "$[0].${ + isMad ? 'mega_resource' : 'info' + }.pokemon_id") = ${pokeId}`, + ), + ) + .andWhere( + raw( + `json_extract(${ + isMad ? 'quest_reward' : 'quest_rewards' + }, "$[0].${ + isMad ? 'mega_resource' : 'info' + }.amount") = ${amount}`, + ), + ) } }) if (hasAltQuests) { - questTypes.orWhere(altMega => { + questTypes.orWhere((altMega) => { altMega.where('alternative_quest_reward_type', 12) if (hasRewardAmount) { - altMega.andWhere('alternative_quest_reward_amount', amount) + altMega + .andWhere('alternative_quest_reward_amount', amount) .andWhere('alternative_quest_pokemon_id', pokeId) } else { - altMega.andWhere(raw(`json_extract(alternative_quest_rewards, "$[0].info.pokemon_id") = ${pokeId}`)) - .andWhere(raw(`json_extract(alternative_quest_rewards, "$[0].info.amount") = ${amount}`)) + altMega + .andWhere( + raw( + `json_extract(alternative_quest_rewards, "$[0].info.pokemon_id") = ${pokeId}`, + ), + ) + .andWhere( + raw( + `json_extract(alternative_quest_rewards, "$[0].info.amount") = ${amount}`, + ), + ) } }) } } }) if (hasRewardAmount) { - questTypes.orWhere('quest_reward_type', 4) + questTypes + .orWhere('quest_reward_type', 4) .whereIn('quest_pokemon_id', candy) if (hasAltQuests) { - questTypes.orWhere('alternative_quest_reward_type', 4) + questTypes + .orWhere('alternative_quest_reward_type', 4) .whereIn('alternative_quest_pokemon_id', candy) } } else { - candy.forEach(poke => { - questTypes.orWhere(candies => { - candies.where('quest_reward_type', 4) - .where(raw(`json_extract(${isMad ? 'quest_reward' : 'quest_rewards'}, "$[0].${isMad ? 'candy' : 'info'}.pokemon_id") = ${poke}`)) + candy.forEach((poke) => { + questTypes.orWhere((candies) => { + candies + .where('quest_reward_type', 4) + .where( + raw( + `json_extract(${ + isMad ? 'quest_reward' : 'quest_rewards' + }, "$[0].${ + isMad ? 'candy' : 'info' + }.pokemon_id") = ${poke}`, + ), + ) }) if (hasAltQuests) { - questTypes.orWhere(altCandies => { - altCandies.where('alternative_quest_reward_type', 4) - .where(raw(`json_extract(alternative_quest_rewards, "$[0].info.pokemon_id") = ${poke}`)) + questTypes.orWhere((altCandies) => { + altCandies + .where('alternative_quest_reward_type', 4) + .where( + raw( + `json_extract(alternative_quest_rewards, "$[0].info.pokemon_id") = ${poke}`, + ), + ) }) } }) } if (hasRewardAmount) { - questTypes.orWhere('quest_reward_type', 9) + questTypes + .orWhere('quest_reward_type', 9) .whereIn('quest_pokemon_id', xlCandy) if (hasAltQuests) { - questTypes.orWhere('alternative_quest_reward_type', 9) + questTypes + .orWhere('alternative_quest_reward_type', 9) .whereIn('alternative_quest_pokemon_id', xlCandy) } } else { - xlCandy.forEach(poke => { - questTypes.orWhere(xlCandies => { - xlCandies.where('quest_reward_type', 9) - .where(raw(`json_extract(${isMad ? 'quest_reward' : 'quest_rewards'}, "$[0].${isMad ? 'xl_candy' : 'info'}.pokemon_id") = ${poke}`)) + xlCandy.forEach((poke) => { + questTypes.orWhere((xlCandies) => { + xlCandies + .where('quest_reward_type', 9) + .where( + raw( + `json_extract(${ + isMad ? 'quest_reward' : 'quest_rewards' + }, "$[0].${ + isMad ? 'xl_candy' : 'info' + }.pokemon_id") = ${poke}`, + ), + ) }) if (hasAltQuests) { - questTypes.orWhere(altXlCandies => { - altXlCandies.where('alternative_quest_reward_type', 9) - .where(raw(`json_extract(alternative_quest_rewards, "$[0].info.pokemon_id") = ${poke}`)) + questTypes.orWhere((altXlCandies) => { + altXlCandies + .where('alternative_quest_reward_type', 9) + .where( + raw( + `json_extract(alternative_quest_rewards, "$[0].info.pokemon_id") = ${poke}`, + ), + ) }) } }) } if (general.length && map.enableQuestRewardTypeFilters) { - questTypes.orWhere(rewardType => { + questTypes.orWhere((rewardType) => { rewardType.whereIn('quest_reward_type', general) }) if (hasAltQuests) { - questTypes.orWhere(altRewardType => { - altRewardType.whereIn('alternative_quest_reward_type', general) + questTypes.orWhere((altRewardType) => { + altRewardType.whereIn( + 'alternative_quest_reward_type', + general, + ) }) } } @@ -279,111 +431,198 @@ module.exports = class Pokestop extends Model { } if (onlyInvasions && invasionPerms) { if (hasMultiInvasions) { - stops.orWhere(invasion => { - invasion.whereIn('character', invasions) - .andWhere(multiInvasionMs ? 'expiration_ms' : 'expiration', '>=', safeTs * (multiInvasionMs ? 1000 : 1)) + stops.orWhere((invasion) => { + invasion + .whereIn('character', invasions) + .andWhere( + multiInvasionMs ? 'expiration_ms' : 'expiration', + '>=', + safeTs * (multiInvasionMs ? 1000 : 1), + ) }) } else { - stops.orWhere(invasion => { - invasion.whereIn(isMad ? 'incident_grunt_type' : 'grunt_type', invasions) - .andWhere(isMad ? 'incident_expiration' : 'incident_expire_timestamp', '>=', isMad ? this.knex().fn.now() : safeTs) + stops.orWhere((invasion) => { + invasion + .whereIn( + isMad ? 'incident_grunt_type' : 'grunt_type', + invasions, + ) + .andWhere( + isMad ? 'incident_expiration' : 'incident_expire_timestamp', + '>=', + isMad ? this.knex().fn.now() : safeTs, + ) }) } } if (onlyArEligible && pokestopPerms) { - stops.orWhere(ar => { + stops.orWhere((ar) => { ar.where(isMad ? 'is_ar_scan_eligible' : 'ar_scan_eligible', 1) }) } }) } const results = await query - const normalized = isMad ? this.mapMAD(results, safeTs) : this.mapRDM(results, safeTs) - if (normalized.length > queryLimits.pokestops) normalized.length = queryLimits.pokestops - return this.secondaryFilter(normalized, args.filters, isMad, safeTs, midnight, perms) + const normalized = isMad + ? this.mapMAD(results, safeTs) + : this.mapRDM(results, safeTs) + if (normalized.length > queryLimits.pokestops) + normalized.length = queryLimits.pokestops + return this.secondaryFilter( + normalized, + args.filters, + isMad, + safeTs, + midnight, + perms, + ) } static fieldAssigner(target, source, fields) { - fields.forEach(field => (target[field] = source[field])) + fields.forEach((field) => (target[field] = source[field])) } // filters and removes unwanted data - static secondaryFilter(queryResults, filters, isMad, safeTs, midnight, perms) { + static secondaryFilter( + queryResults, + filters, + isMad, + safeTs, + midnight, + perms, + ) { const filteredResults = [] for (let i = 0; i < queryResults.length; i += 1) { const pokestop = queryResults[i] const filtered = {} - this.fieldAssigner(filtered, pokestop, ['id', 'lat', 'lon', 'enabled', 'url', 'name', 'last_modified_timestamp', 'updated']) + this.fieldAssigner(filtered, pokestop, [ + 'id', + 'lat', + 'lon', + 'enabled', + 'url', + 'name', + 'last_modified_timestamp', + 'updated', + ]) if (perms.pokestops) { - this.fieldAssigner(filtered, pokestop, ['ar_scan_eligible', 'power_up_points', 'power_up_level', 'power_up_end_timestamp']) + this.fieldAssigner(filtered, pokestop, [ + 'ar_scan_eligible', + 'power_up_points', + 'power_up_level', + 'power_up_end_timestamp', + ]) } - if (perms.invasions && (filters.onlyAllPokestops || filters.onlyInvasions)) { + if ( + perms.invasions && + (filters.onlyAllPokestops || filters.onlyInvasions) + ) { filtered.invasions = filters.onlyAllPokestops ? pokestop.invasions - : pokestop.invasions.filter(invasion => filters[`i${invasion.grunt_type}`]) + : pokestop.invasions.filter( + (invasion) => filters[`i${invasion.grunt_type}`], + ) } - if (perms.lures - && (filters.onlyAllPokestops - || (filters.onlyLures && pokestop.lure_expire_timestamp >= safeTs && filters[`l${pokestop.lure_id}`]))) { - this.fieldAssigner(filtered, pokestop, ['lure_id', 'lure_expire_timestamp']) + if ( + perms.lures && + (filters.onlyAllPokestops || + (filters.onlyLures && + pokestop.lure_expire_timestamp >= safeTs && + filters[`l${pokestop.lure_id}`])) + ) { + this.fieldAssigner(filtered, pokestop, [ + 'lure_id', + 'lure_expire_timestamp', + ]) } if (perms.quests && (filters.onlyAllPokestops || filters.onlyQuests)) { filtered.quests = [] - pokestop.quests.forEach(quest => { - if (quest.quest_reward_type && ( - !map.enableQuestSetSelector - || filters.onlyShowQuestSet === 'both' - || (filters.onlyShowQuestSet === 'with_ar' && quest.with_ar) - || (filters.onlyShowQuestSet === 'without_ar' && !quest.with_ar) - )) { + pokestop.quests.forEach((quest) => { + if ( + quest.quest_reward_type && + (!map.enableQuestSetSelector || + filters.onlyShowQuestSet === 'both' || + (filters.onlyShowQuestSet === 'with_ar' && quest.with_ar) || + (filters.onlyShowQuestSet === 'without_ar' && !quest.with_ar)) + ) { const newQuest = {} if (isMad) { this.parseMadRewards(quest) } else { this.parseRdmRewards(quest) } - const fields = ['quest_type', 'quest_timestamp', 'quest_target', 'quest_conditions', 'quest_task', 'quest_reward_type', 'quest_rewards', 'with_ar', 'quest_title'] + const fields = [ + 'quest_type', + 'quest_timestamp', + 'quest_target', + 'quest_conditions', + 'quest_task', + 'quest_reward_type', + 'quest_rewards', + 'with_ar', + 'quest_title', + ] switch (quest.quest_reward_type) { case 2: newQuest.key = `q${quest.quest_item_id}` - fields.push('quest_item_id', 'item_amount'); break + fields.push('quest_item_id', 'item_amount') + break case 3: newQuest.key = `d${quest.stardust_amount}` - fields.push('stardust_amount'); break + fields.push('stardust_amount') + break case 4: newQuest.key = `c${quest.candy_pokemon_id}` - fields.push('candy_pokemon_id', 'candy_amount'); break + fields.push('candy_pokemon_id', 'candy_amount') + break case 7: quest.quest_form_id = quest.quest_form_id ?? 0 newQuest.key = `${quest.quest_pokemon_id}-${quest.quest_form_id}` - fields.push('quest_pokemon_id', 'quest_form_id', 'quest_costume_id', 'quest_gender_id', 'quest_shiny'); break + fields.push( + 'quest_pokemon_id', + 'quest_form_id', + 'quest_costume_id', + 'quest_gender_id', + 'quest_shiny', + ) + break case 9: newQuest.key = `x${quest.xl_candy_pokemon_id}` - fields.push('xl_candy_pokemon_id', 'xl_candy_amount'); break + fields.push('xl_candy_pokemon_id', 'xl_candy_amount') + break case 12: newQuest.key = `m${quest.mega_pokemon_id}-${quest.mega_amount}` - fields.push('mega_pokemon_id', 'mega_amount'); break + fields.push('mega_pokemon_id', 'mega_amount') + break default: newQuest.key = `u${quest.quest_reward_type}` } - if (quest.quest_timestamp >= midnight && (filters.onlyAllPokestops - || (filters[newQuest.key] - && (filters[newQuest.key].adv ? quest.quest_title === filters[newQuest.key].adv : true)) - || (filters[`u${quest.quest_reward_type}`] && map.enableQuestRewardTypeFilters))) { + if ( + quest.quest_timestamp >= midnight && + (filters.onlyAllPokestops || + (filters[newQuest.key] && + (filters[newQuest.key].adv + ? quest.quest_title === filters[newQuest.key].adv + : true)) || + (filters[`u${quest.quest_reward_type}`] && + map.enableQuestRewardTypeFilters)) + ) { this.fieldAssigner(newQuest, quest, fields) filtered.quests.push(newQuest) } } }) } - if ((pokestop.ar_scan_eligible && filters.onlyArEligible) - || filters.onlyAllPokestops - || filtered.quests?.length - || filtered.invasions?.length - || filtered.lure_id) { + if ( + (pokestop.ar_scan_eligible && filters.onlyArEligible) || + filters.onlyAllPokestops || + filtered.quests?.length || + filtered.invasions?.length || + filtered.lure_id + ) { filteredResults.push(filtered) } } @@ -398,10 +637,12 @@ module.exports = class Pokestop extends Model { const invasion = {} if (filtered[result.id]) { - Object.keys(madQuestProps).forEach(field => (quest[field] = result[field])) + Object.keys(madQuestProps).forEach( + (field) => (quest[field] = result[field]), + ) } else { filtered[result.id] = { quests: [], invasions: [] } - Object.keys(result).forEach(field => { + Object.keys(result).forEach((field) => { if (madQuestProps[field]) { quest[field] = result[field] } else if (invasionProps[field]) { @@ -431,12 +672,12 @@ module.exports = class Pokestop extends Model { const invasion = {} if (filtered[result.id]) { - Object.keys(invasionProps).forEach(field => ( - invasion[field] = result[field] - )) + Object.keys(invasionProps).forEach( + (field) => (invasion[field] = result[field]), + ) } else { filtered[result.id] = { invasions: [], quests: [] } - Object.keys(result).forEach(field => { + Object.keys(result).forEach((field) => { if (questProps[field]) { quest[field] = result[field] } else if (questPropsAlt[field]) { @@ -461,8 +702,14 @@ module.exports = class Pokestop extends Model { return Object.values(filtered) } - static async getAvailable({ isMad, hasAltQuests, hasMultiInvasions, multiInvasionMs, hasRewardAmount }) { - const ts = Math.floor((new Date()).getTime() / 1000) + static async getAvailable({ + isMad, + hasAltQuests, + hasMultiInvasions, + multiInvasionMs, + hasRewardAmount, + }) { + const ts = Math.floor(new Date().getTime() / 1000) const finalList = new Set() const conditions = {} const queries = {} @@ -485,9 +732,17 @@ module.exports = class Pokestop extends Model { .groupBy('quest_item_id', 'quest_title', 'quest_target') if (hasAltQuests) { queries.itemsAlt = this.query() - .select('alternative_quest_item_id AS quest_item_id', 'alternative_quest_title AS quest_title', 'alternative_quest_target AS quest_target') + .select( + 'alternative_quest_item_id AS quest_item_id', + 'alternative_quest_title AS quest_title', + 'alternative_quest_target AS quest_target', + ) .where('alternative_quest_reward_type', 2) - .groupBy('alternative_quest_item_id', 'alternative_quest_title', 'alternative_quest_target') + .groupBy( + 'alternative_quest_item_id', + 'alternative_quest_title', + 'alternative_quest_target', + ) } if (isMad) { queries.stardust = this.query() @@ -496,32 +751,52 @@ module.exports = class Pokestop extends Model { .where('quest_stardust', '>', 0) .groupBy('amount', 'quest_title', 'quest_target') } else { - queries.stardust = this.query() - .where('quest_reward_type', 3) + queries.stardust = this.query().where('quest_reward_type', 3) if (hasRewardAmount) { queries.stardust - .select('quest_reward_amount AS amount', 'quest_title', 'quest_target') + .select( + 'quest_reward_amount AS amount', + 'quest_title', + 'quest_target', + ) .where('quest_reward_amount', '>', 0) .groupBy('amount', 'quest_title', 'quest_target') } else { queries.stardust .select('quest_title', 'quest_target') - .distinct(raw('json_extract(quest_rewards, "$[0].info.amount")') - .as('amount')) + .distinct( + raw('json_extract(quest_rewards, "$[0].info.amount")').as('amount'), + ) } if (hasAltQuests) { - queries.stardustAlt = this.query() - .where('alternative_quest_reward_type', 3) + queries.stardustAlt = this.query().where( + 'alternative_quest_reward_type', + 3, + ) if (hasRewardAmount) { queries.stardustAlt - .select('alternative_quest_reward_amount AS amount', 'alternative_quest_title AS quest_title', 'alternative_quest_target AS quest_target') + .select( + 'alternative_quest_reward_amount AS amount', + 'alternative_quest_title AS quest_title', + 'alternative_quest_target AS quest_target', + ) .where('alternative_quest_reward_amount', '>', 0) - .groupBy('amount', 'alternative_quest_title', 'alternative_quest_target') + .groupBy( + 'amount', + 'alternative_quest_title', + 'alternative_quest_target', + ) } else { queries.stardustAlt - .select('alternative_quest_title AS quest_title', 'alternative_quest_target AS quest_target') - .distinct(raw('json_extract(alternative_quest_rewards, "$[0].info.amount")') - .as('amount')) + .select( + 'alternative_quest_title AS quest_title', + 'alternative_quest_target AS quest_target', + ) + .distinct( + raw( + 'json_extract(alternative_quest_rewards, "$[0].info.amount")', + ).as('amount'), + ) } } } @@ -531,31 +806,54 @@ module.exports = class Pokestop extends Model { if (hasRewardAmount) { queries.mega .select('quest_title', 'quest_target') - .distinct(`${isMad ? 'quest_item_amount' : 'quest_reward_amount'} AS amount`) + .distinct( + `${isMad ? 'quest_item_amount' : 'quest_reward_amount'} AS amount`, + ) .distinct('quest_pokemon_id AS id') } else { queries.mega .select('quest_title', 'quest_target') - .distinct(raw(`json_extract(${isMad ? 'quest_reward' : 'quest_rewards'}, "$[0].${isMad ? 'mega_resource' : 'info'}.pokemon_id")`) - .as('id')) - .distinct(raw(`json_extract(${isMad ? 'quest_reward' : 'quest_rewards'}, "$[0].${isMad ? 'mega_resource' : 'info'}.amount")`) - .as('amount')) + .distinct( + raw( + `json_extract(${isMad ? 'quest_reward' : 'quest_rewards'}, "$[0].${ + isMad ? 'mega_resource' : 'info' + }.pokemon_id")`, + ).as('id'), + ) + .distinct( + raw( + `json_extract(${isMad ? 'quest_reward' : 'quest_rewards'}, "$[0].${ + isMad ? 'mega_resource' : 'info' + }.amount")`, + ).as('amount'), + ) } if (hasAltQuests) { - queries.megaAlt = this.query() - .where('alternative_quest_reward_type', 12) + queries.megaAlt = this.query().where('alternative_quest_reward_type', 12) if (hasRewardAmount) { queries.megaAlt - .select('alternative_quest_title AS quest_title', 'alternative_quest_target AS quest_target') + .select( + 'alternative_quest_title AS quest_title', + 'alternative_quest_target AS quest_target', + ) .distinct('alternative_quest_reward_amount AS amount') .distinct('alternative_quest_pokemon_id AS id') } else { queries.megaAlt - .select('alternative_quest_title AS quest_title', 'alternative_quest_target AS quest_target') - .distinct(raw('json_extract(alternative_quest_rewards, "$[0].info.pokemon_id")') - .as('id')) - .distinct(raw('json_extract(alternative_quest_rewards, "$[0].info.amount")') - .as('amount')) + .select( + 'alternative_quest_title AS quest_title', + 'alternative_quest_target AS quest_target', + ) + .distinct( + raw( + 'json_extract(alternative_quest_rewards, "$[0].info.pokemon_id")', + ).as('id'), + ) + .distinct( + raw( + 'json_extract(alternative_quest_rewards, "$[0].info.amount")', + ).as('amount'), + ) } } queries.candy = this.query() @@ -565,7 +863,10 @@ module.exports = class Pokestop extends Model { .where('quest_reward_type', 4) if (hasAltQuests) { queries.candyAlt = this.query() - .select('alternative_quest_title AS quest_title', 'alternative_quest_target AS quest_target') + .select( + 'alternative_quest_title AS quest_title', + 'alternative_quest_target AS quest_target', + ) .distinct('alternative_quest_pokemon_id AS quest_pokemon_id') .where('alternative_quest_reward_type', 4) } @@ -576,27 +877,48 @@ module.exports = class Pokestop extends Model { .where('quest_reward_type', 9) if (hasAltQuests) { queries.xlCandyAlt = this.query() - .select('alternative_quest_title AS quest_title', 'alternative_quest_target AS quest_target') + .select( + 'alternative_quest_title AS quest_title', + 'alternative_quest_target AS quest_target', + ) .distinct('alternative_quest_pokemon_id AS quest_pokemon_id') .where('alternative_quest_reward_type', 9) } if (isMad) { queries.pokemon = this.query() - .select('quest_pokemon_id', 'quest_pokemon_form_id AS form', 'quest_title', 'quest_target') + .select( + 'quest_pokemon_id', + 'quest_pokemon_form_id AS form', + 'quest_title', + 'quest_target', + ) .from('trs_quest') .where('quest_reward_type', 7) - .groupBy('quest_pokemon_id', 'quest_pokemon_form_id', 'quest_title', 'quest_target') + .groupBy( + 'quest_pokemon_id', + 'quest_pokemon_form_id', + 'quest_title', + 'quest_target', + ) } else { queries.pokemon = this.query() .distinct('quest_pokemon_id') - .select(raw('json_extract(quest_rewards, "$[0].info.form_id")') - .as('form'), 'quest_title', 'quest_target') + .select( + raw('json_extract(quest_rewards, "$[0].info.form_id")').as('form'), + 'quest_title', + 'quest_target', + ) .where('quest_reward_type', 7) if (hasAltQuests) { queries.pokemonAlt = this.query() .distinct('alternative_quest_pokemon_id AS quest_pokemon_id') - .select(raw('json_extract(alternative_quest_rewards, "$[0].info.form_id")') - .as('form'), 'alternative_quest_title AS quest_title', 'alternative_quest_target AS quest_target') + .select( + raw( + 'json_extract(alternative_quest_rewards, "$[0].info.form_id")', + ).as('form'), + 'alternative_quest_title AS quest_title', + 'alternative_quest_target AS quest_target', + ) .where('alternative_quest_reward_type', 7) } } @@ -604,56 +926,128 @@ module.exports = class Pokestop extends Model { queries.invasions = this.query() .leftJoin('incident', 'pokestop.id', 'incident.pokestop_id') .distinct('incident.character AS grunt_type') - .where(multiInvasionMs ? 'expiration_ms' : 'incident.expiration', '>=', ts * (multiInvasionMs ? 1000 : 1)) + .where( + multiInvasionMs ? 'expiration_ms' : 'incident.expiration', + '>=', + ts * (multiInvasionMs ? 1000 : 1), + ) .orderBy('grunt_type') } else { queries.invasions = this.query() .distinct(isMad ? 'incident_grunt_type AS grunt_type' : 'grunt_type') - .where(isMad ? 'incident_expiration' : 'incident_expire_timestamp', '>=', isMad ? this.knex().fn.now() : ts) + .where( + isMad ? 'incident_expiration' : 'incident_expire_timestamp', + '>=', + isMad ? this.knex().fn.now() : ts, + ) .orderBy('grunt_type') } queries.lures = this.query() .select(isMad ? 'active_fort_modifier AS lure_id' : 'lure_id') - .andWhere(isMad ? 'lure_expiration' : 'lure_expire_timestamp', '>=', isMad ? this.knex().fn.now() : ts) + .andWhere( + isMad ? 'lure_expiration' : 'lure_expire_timestamp', + '>=', + isMad ? this.knex().fn.now() : ts, + ) .groupBy(isMad ? 'active_fort_modifier' : 'lure_id') .orderBy(isMad ? 'active_fort_modifier' : 'lure_id') const resolved = Object.fromEntries( await Promise.all( - Object.entries(queries).map(async ([key, query]) => ([key, await query])), + Object.entries(queries).map(async ([key, query]) => [key, await query]), ), ) Object.entries(resolved).forEach(([questType, rewards]) => { switch (questType) { case 'itemsAlt': - case 'items': rewards.forEach(reward => process(`q${reward.quest_item_id}`, reward.quest_title, reward.quest_target)); break + case 'items': + rewards.forEach((reward) => + process( + `q${reward.quest_item_id}`, + reward.quest_title, + reward.quest_target, + ), + ) + break case 'megaAlt': - case 'mega': rewards.forEach(reward => process(`m${reward.id}-${reward.amount}`, reward.quest_title, reward.quest_target)); break + case 'mega': + rewards.forEach((reward) => + process( + `m${reward.id}-${reward.amount}`, + reward.quest_title, + reward.quest_target, + ), + ) + break case 'stardustAlt': - case 'stardust': rewards.forEach(reward => process(`d${reward.amount}`, reward.quest_title, reward.quest_target)); break + case 'stardust': + rewards.forEach((reward) => + process( + `d${reward.amount}`, + reward.quest_title, + reward.quest_target, + ), + ) + break case 'candyAlt': - case 'candy': rewards.forEach(reward => process(`c${reward.id}`, reward.quest_title, reward.quest_target)); break + case 'candy': + rewards.forEach((reward) => + process(`c${reward.id}`, reward.quest_title, reward.quest_target), + ) + break case 'xlCandyAlt': - case 'xlCandy': rewards.forEach(reward => process(`x${reward.id}`, reward.quest_title, reward.quest_target)); break - case 'lures': rewards.forEach(reward => finalList.add(`l${reward.lure_id}`)); break - case 'invasions': rewards.forEach(reward => finalList.add(`i${reward.grunt_type}`)); break - default: rewards.forEach(reward => process(`${reward.quest_pokemon_id}-${reward.form ?? 0}`, reward.quest_title, reward.quest_target)); break + case 'xlCandy': + rewards.forEach((reward) => + process(`x${reward.id}`, reward.quest_title, reward.quest_target), + ) + break + case 'lures': + rewards.forEach((reward) => finalList.add(`l${reward.lure_id}`)) + break + case 'invasions': + rewards.forEach((reward) => finalList.add(`i${reward.grunt_type}`)) + break + default: + rewards.forEach((reward) => + process( + `${reward.quest_pokemon_id}-${reward.form ?? 0}`, + reward.quest_title, + reward.quest_target, + ), + ) + break } }) - return { available: finalList.size ? [...finalList] : await fetchQuests(), conditions } + return { + available: finalList.size ? [...finalList] : await fetchQuests(), + conditions, + } } static parseRdmRewards = (quest) => { if (quest.quest_reward_type) { const { info } = JSON.parse(quest.quest_rewards)[0] switch (quest.quest_reward_type) { - case 2: Object.keys(info).forEach(x => (quest[`item_${x}`] = info[x])); break - case 3: Object.keys(info).forEach(x => (quest[`stardust_${x}`] = info[x])); break - case 4: Object.keys(info).forEach(x => (quest[`candy_${x}`] = info[x])); break - case 7: Object.keys(info).forEach(x => (quest[`quest_${x}`] = info[x])); break - case 9: Object.keys(info).forEach(x => (quest[`xl_candy_${x}`] = info[x])); break - case 12: Object.keys(info).forEach(x => (quest[`mega_${x}`] = info[x])); break - default: break + case 2: + Object.keys(info).forEach((x) => (quest[`item_${x}`] = info[x])) + break + case 3: + Object.keys(info).forEach((x) => (quest[`stardust_${x}`] = info[x])) + break + case 4: + Object.keys(info).forEach((x) => (quest[`candy_${x}`] = info[x])) + break + case 7: + Object.keys(info).forEach((x) => (quest[`quest_${x}`] = info[x])) + break + case 9: + Object.keys(info).forEach((x) => (quest[`xl_candy_${x}`] = info[x])) + break + case 12: + Object.keys(info).forEach((x) => (quest[`mega_${x}`] = info[x])) + break + default: + break } } return quest @@ -661,15 +1055,28 @@ module.exports = class Pokestop extends Model { static parseMadRewards = (quest) => { if (quest.quest_reward_type) { - const { - item, candy, xl_candy, mega_resource, - } = JSON.parse(quest.quest_rewards)[0] + const { item, candy, xl_candy, mega_resource } = JSON.parse( + quest.quest_rewards, + )[0] switch (quest.quest_reward_type) { - case 2: Object.keys(item).forEach(x => (quest[`item_${x}`] = item[x])); break - case 4: Object.keys(candy).forEach(x => (quest[`candy_${x}`] = candy[x])); break - case 9: Object.keys(xl_candy).forEach(x => (quest[`xl_candy_${x}`] = candy[x])); break - case 12: Object.keys(mega_resource).forEach(x => (quest[`mega_${x}`] = mega_resource[x])); break - default: break + case 2: + Object.keys(item).forEach((x) => (quest[`item_${x}`] = item[x])) + break + case 4: + Object.keys(candy).forEach((x) => (quest[`candy_${x}`] = candy[x])) + break + case 9: + Object.keys(xl_candy).forEach( + (x) => (quest[`xl_candy_${x}`] = candy[x]), + ) + break + case 12: + Object.keys(mega_resource).forEach( + (x) => (quest[`mega_${x}`] = mega_resource[x]), + ) + break + default: + break } } return quest @@ -699,27 +1106,31 @@ module.exports = class Pokestop extends Model { const { search, locale, midnight: clientMidnight } = args const midnight = settings.hideOldQuests ? clientMidnight : 0 - const pokemonIds = Object.keys(Event.masterfile.pokemon).filter(pkmn => ( - i18next.t(`poke_${pkmn}`, { lng: locale }) + const pokemonIds = Object.keys(Event.masterfile.pokemon).filter((pkmn) => + i18next + .t(`poke_${pkmn}`, { lng: locale }) .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') .toLowerCase() - .includes(search) - )) - const itemIds = Object.keys(Event.masterfile.items).filter(item => ( - i18next.t(`item_${item}`, { lng: locale }) - .normalize('NFD') - .replace(/[\u0300-\u036f]/g, '') - .toLowerCase() - .includes(search) - )) - const rewardTypes = Object.keys(Event.masterfile.questRewardTypes).filter(rType => ( - i18next.t(`quest_reward_${rType}`, { lng: locale }) + .includes(search), + ) + const itemIds = Object.keys(Event.masterfile.items).filter((item) => + i18next + .t(`item_${item}`, { lng: locale }) .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') .toLowerCase() - .includes(search) - )) + .includes(search), + ) + const rewardTypes = Object.keys(Event.masterfile.questRewardTypes).filter( + (rType) => + i18next + .t(`quest_reward_${rType}`, { lng: locale }) + .normalize('NFD') + .replace(/[\u0300-\u036f]/g, '') + .toLowerCase() + .includes(search), + ) const query = this.query() .select([ @@ -732,15 +1143,17 @@ module.exports = class Pokestop extends Model { ]) .where(isMad ? 'enabled' : 'deleted', isMad) .andWhere('quest_timestamp', '>=', midnight || 0) - .andWhere(quests => { - quests.whereIn('quest_pokemon_id', pokemonIds) + .andWhere((quests) => { + quests + .whereIn('quest_pokemon_id', pokemonIds) .orWhereIn('quest_item_id', itemIds) .orWhereIn('quest_reward_type', rewardTypes) }) .limit(searchResultsLimit) .orderBy('distance') if (isMad) { - query.leftJoin('trs_quest', 'pokestop.pokestop_id', 'trs_quest.GUID') + query + .leftJoin('trs_quest', 'pokestop.pokestop_id', 'trs_quest.GUID') .select([ 'quest_stardust AS stardust_amount', 'quest_pokemon_form_id AS quest_form_id', @@ -751,15 +1164,16 @@ module.exports = class Pokestop extends Model { getAreaSql(query, perms.areaRestrictions, isMad) } const results = await query - const mapped = results.map(q => ({ ...q, with_ar: q.with_ar ?? true })) + const mapped = results.map((q) => ({ ...q, with_ar: q.with_ar ?? true })) if (hasAltQuests) { const altQuestQuery = this.query() .select(['*', distance]) .where('deleted', false) .andWhere('alternative_quest_timestamp', '>=', midnight || 0) - .andWhere(quests => { - quests.whereIn('alternative_quest_pokemon_id', pokemonIds) + .andWhere((quests) => { + quests + .whereIn('alternative_quest_pokemon_id', pokemonIds) .orWhereIn('alternative_quest_item_id', itemIds) .orWhereIn('alternative_quest_reward_type', rewardTypes) }) @@ -769,7 +1183,7 @@ module.exports = class Pokestop extends Model { getAreaSql(altQuestQuery, perms.areaRestrictions, isMad) } const altQuestResults = await altQuestQuery - const remapped = altQuestResults.map(result => ({ + const remapped = altQuestResults.map((result) => ({ ...result, quest_rewards: result.alternative_quest_rewards, quest_reward_type: result.alternative_quest_reward_type, @@ -783,7 +1197,11 @@ module.exports = class Pokestop extends Model { mapped.sort((a, b) => a.distance - b.distance) mapped.length = searchResultsLimit } - return mapped.map(result => isMad ? this.parseMadRewards(result) : this.parseRdmRewards(result)).filter(x => x) + return mapped + .map((result) => + isMad ? this.parseMadRewards(result) : this.parseRdmRewards(result), + ) + .filter((x) => x) } static getOne(id, { isMad }) { @@ -798,21 +1216,21 @@ module.exports = class Pokestop extends Model { static getSubmissions(args, { isMad }) { const query = this.query() - .whereBetween(`lat${isMad ? 'itude' : ''}`, [args.minLat - 0.025, args.maxLat + 0.025]) - .andWhereBetween(`lon${isMad ? 'gitude' : ''}`, [args.minLon - 0.025, args.maxLon + 0.025]) + .whereBetween(`lat${isMad ? 'itude' : ''}`, [ + args.minLat - 0.025, + args.maxLat + 0.025, + ]) + .andWhereBetween(`lon${isMad ? 'gitude' : ''}`, [ + args.minLon - 0.025, + args.maxLon + 0.025, + ]) .andWhere(isMad ? 'enabled' : 'deleted', isMad) if (isMad) { - query.select([ - 'pokestop_id AS id', - 'latitude AS lat', - 'longitude AS lon', - ]) + query.select(['pokestop_id AS id', 'latitude AS lat', 'longitude AS lon']) } else { - query.select(['id', 'lat', 'lon']) - .andWhere(poi => { - poi.whereNull('sponsor_id') - .orWhere('sponsor_id', 0) - }) + query.select(['id', 'lat', 'lon']).andWhere((poi) => { + poi.whereNull('sponsor_id').orWhere('sponsor_id', 0) + }) } return query } diff --git a/server/src/models/Portal.js b/server/src/models/Portal.js index 27f051954..cd8409de3 100644 --- a/server/src/models/Portal.js +++ b/server/src/models/Portal.js @@ -14,7 +14,11 @@ module.exports = class Portal extends Model { const query = this.query() .whereBetween('lat', [args.minLat, args.maxLat]) .andWhereBetween('lon', [args.minLon, args.maxLon]) - .andWhere('updated', '>', (Date.now() / 1000) - portalUpdateLimit * 60 * 60 * 24) + .andWhere( + 'updated', + '>', + Date.now() / 1000 - portalUpdateLimit * 60 * 60 * 24, + ) if (areaRestrictions?.length) { getAreaSql(query, areaRestrictions) } @@ -24,16 +28,13 @@ module.exports = class Portal extends Model { static async search(perms, args, { isMad }, distance) { const { areaRestrictions } = perms const query = this.query() - .select([ - 'name', - 'id', - 'lat', - 'lon', - 'url', - distance, - ]) + .select(['name', 'id', 'lat', 'lon', 'url', distance]) .whereRaw(`LOWER(name) LIKE '%${args.search}%'`) - .andWhere('updated', '>', (Date.now() / 1000) - portalUpdateLimit * 60 * 60 * 24) + .andWhere( + 'updated', + '>', + Date.now() / 1000 - portalUpdateLimit * 60 * 60 * 24, + ) .limit(searchResultsLimit) .orderBy('distance') if (areaRestrictions?.length) { diff --git a/server/src/models/ScanCell.js b/server/src/models/ScanCell.js index 20e9d8861..8627e9629 100644 --- a/server/src/models/ScanCell.js +++ b/server/src/models/ScanCell.js @@ -1,7 +1,9 @@ const { Model, ref } = require('objection') const getPolyVector = require('../services/functions/getPolyVector') const getAreaSql = require('../services/functions/getAreaSql') -const { api: { queryLimits } } = require('../services/config') +const { + api: { queryLimits }, +} = require('../services/config') module.exports = class ScanCell extends Model { static get tableName() { @@ -11,18 +13,22 @@ module.exports = class ScanCell extends Model { static async getAll(perms, args, { isMad }) { const { areaRestrictions } = perms const query = this.query() - .select(['*', ref('id') - .castTo('CHAR') - .as('id')]) - .whereBetween(`center_lat${isMad ? 'itude' : ''}`, [args.minLat - 0.01, args.maxLat + 0.01]) - .andWhereBetween(`center_lon${isMad ? 'gitude' : ''}`, [args.minLon - 0.01, args.maxLon + 0.01]) + .select(['*', ref('id').castTo('CHAR').as('id')]) + .whereBetween(`center_lat${isMad ? 'itude' : ''}`, [ + args.minLat - 0.01, + args.maxLat + 0.01, + ]) + .andWhereBetween(`center_lon${isMad ? 'gitude' : ''}`, [ + args.minLon - 0.01, + args.maxLon + 0.01, + ]) if (areaRestrictions?.length) { getAreaSql(query, areaRestrictions, isMad, 's2cell') } const results = await query .limit(queryLimits.scanCells) .from(isMad ? 'trs_s2cells' : 's2cell') - return results.map(cell => ({ + return results.map((cell) => ({ ...cell, polygon: getPolyVector(cell.id, 'polygon'), })) diff --git a/server/src/models/Session.js b/server/src/models/Session.js index 0af86b7a9..838a880a0 100644 --- a/server/src/models/Session.js +++ b/server/src/models/Session.js @@ -1,5 +1,9 @@ const { Model } = require('objection') -const { database: { settings: { sessionTableName } } } = require('../services/config') +const { + database: { + settings: { sessionTableName }, + }, +} = require('../services/config') module.exports = class Session extends Model { static get tableName() { diff --git a/server/src/models/Spawnpoint.js b/server/src/models/Spawnpoint.js index b9b441c22..2584900c3 100644 --- a/server/src/models/Spawnpoint.js +++ b/server/src/models/Spawnpoint.js @@ -1,6 +1,8 @@ const { Model, raw } = require('objection') const getAreaSql = require('../services/functions/getAreaSql') -const { api: { queryLimits } } = require('../services/config') +const { + api: { queryLimits }, +} = require('../services/config') module.exports = class Spawnpoint extends Model { static get tableName() { @@ -15,14 +17,16 @@ module.exports = class Spawnpoint extends Model { 'spawnpoint AS id', 'latitude AS lat', 'longitude AS lon', - raw('ROUND(calc_endminsec)') - .as('despawn_sec'), - raw('UNIX_TIMESTAMP(last_scanned)') - .as('updated'), + raw('ROUND(calc_endminsec)').as('despawn_sec'), + raw('UNIX_TIMESTAMP(last_scanned)').as('updated'), ]) } - query.whereBetween(`lat${isMad ? 'itude' : ''}`, [args.minLat, args.maxLat]) - .andWhereBetween(`lon${isMad ? 'gitude' : ''}`, [args.minLon, args.maxLon]) + query + .whereBetween(`lat${isMad ? 'itude' : ''}`, [args.minLat, args.maxLat]) + .andWhereBetween(`lon${isMad ? 'gitude' : ''}`, [ + args.minLon, + args.maxLon, + ]) if (areaRestrictions?.length) { getAreaSql(query, areaRestrictions, isMad) } diff --git a/server/src/models/User.js b/server/src/models/User.js index c14889c7d..3f4b4b63a 100644 --- a/server/src/models/User.js +++ b/server/src/models/User.js @@ -1,7 +1,9 @@ /* eslint-disable no-console */ const { Model } = require('objection') const { - database: { settings: { userTableName, gymBadgeTableName } }, + database: { + settings: { userTableName, gymBadgeTableName }, + }, } = require('../services/config') module.exports = class User extends Model { @@ -13,7 +15,11 @@ module.exports = class User extends Model { await this.query() .update({ [`${strategy}Perms`]: null }) .where({ [`${strategy}Id`]: userId }) - .then(() => console.log(`[${botName}] Cleared ${strategy} perms for user ${userId}`)) + .then(() => + console.log( + `[${botName}] Cleared ${strategy} perms for user ${userId}`, + ), + ) } static get relationMappings() { diff --git a/server/src/models/Weather.js b/server/src/models/Weather.js index abb7dc7fb..25818a3b9 100644 --- a/server/src/models/Weather.js +++ b/server/src/models/Weather.js @@ -1,6 +1,8 @@ const { Model, ref, raw } = require('objection') const getPolyVector = require('../services/functions/getPolyVector') -const { api: { weatherCellLimit } } = require('../services/config') +const { + api: { weatherCellLimit }, +} = require('../services/config') module.exports = class Weather extends Model { static get tableName() { @@ -8,26 +10,24 @@ module.exports = class Weather extends Model { } static async getAll(_perms, _args, { isMad }) { - const query = this.query() - .select([ - '*', - ref(isMad ? 's2_cell_id' : 'id') - .castTo('CHAR') - .as('id'), - ]) + const query = this.query().select([ + '*', + ref(isMad ? 's2_cell_id' : 'id') + .castTo('CHAR') + .as('id'), + ]) if (isMad) { query.select([ 'gameplay_weather AS gameplay_condition', - raw('UNIX_TIMESTAMP(last_updated)') - .as('updated'), + raw('UNIX_TIMESTAMP(last_updated)').as('updated'), ]) } else { - const ts = Math.floor((new Date()).getTime() / 1000) - const ms = ts - (weatherCellLimit * 60 * 60 * 24) + const ts = Math.floor(new Date().getTime() / 1000) + const ms = ts - weatherCellLimit * 60 * 60 * 24 query.where('updated', '>=', ms) } const results = await query - return results.map(cell => ({ + return results.map((cell) => ({ ...cell, polygon: getPolyVector(cell.id, true), })) diff --git a/server/src/routes/api/apiIndex.js b/server/src/routes/api/apiIndex.js index a7e479024..d5a2e8108 100644 --- a/server/src/routes/api/apiIndex.js +++ b/server/src/routes/api/apiIndex.js @@ -8,7 +8,7 @@ const fs = require('fs') // Loads in the API V1 Routes, including custom ones fs.readdir(`${__dirname}/v1/`, (e, files) => { if (e) return console.error(e, 'Error initializing an API endpoint') - files.forEach(file => { + files.forEach((file) => { try { router.use(`/v1/${file.replace('.js', '')}`, require(`./v1/${file}`)) console.log(`[API] Loaded ${file}`) diff --git a/server/src/routes/api/v1/available.js b/server/src/routes/api/v1/available.js index 4fa62adfc..b74188a5f 100644 --- a/server/src/routes/api/v1/available.js +++ b/server/src/routes/api/v1/available.js @@ -16,65 +16,87 @@ const resolveCategory = (category) => { case 'gym': case 'gyms': case 'raid': - case 'raids': return 'raids' + case 'raids': + return 'raids' case 'pokestop': case 'pokestops': case 'quest': - case 'quests': return 'quests' + case 'quests': + return 'quests' case 'pokemon': - case 'pokemons': return 'pokemon' - default: return 'all' + case 'pokemons': + return 'pokemon' + default: + return 'all' } } const getAll = async (compare) => { const available = compare ? await Promise.all([ - Db.getAvailable('Pokemon'), - Db.getAvailable('Pokestop'), - Db.getAvailable('Gym'), - Db.getAvailable('Nest'), - ]) + Db.getAvailable('Pokemon'), + Db.getAvailable('Pokestop'), + Db.getAvailable('Gym'), + Db.getAvailable('Nest'), + ]) : [ - Event.available.pokemon, - Event.available.pokestops, - Event.available.gyms, - Event.available.nests, - ] - return Object.fromEntries(Object.keys(queryObj).map((key, i) => [key, available[i]])) + Event.available.pokemon, + Event.available.pokestops, + Event.available.gyms, + Event.available.nests, + ] + return Object.fromEntries( + Object.keys(queryObj).map((key, i) => [key, available[i]]), + ) } router.get(['/', '/:category'], async (req, res) => { - const { model, category } = queryObj[resolveCategory(req.params.category)] || {} + const { model, category } = + queryObj[resolveCategory(req.params.category)] || {} const { current, equal } = req.query try { - if (api.reactMapSecret && req.headers['react-map-secret'] === api.reactMapSecret) { + if ( + api.reactMapSecret && + req.headers['react-map-secret'] === api.reactMapSecret + ) { if (model && category) { - const available = current !== undefined - ? await Db.getAvailable(model) - : Event.available[category] + const available = + current !== undefined + ? await Db.getAvailable(model) + : Event.available[category] available.sort((a, b) => a.localeCompare(b)) if (equal !== undefined) { - const compare = current !== undefined - ? Event.available[category] - : await Db.getAvailable(model) + const compare = + current !== undefined + ? Event.available[category] + : await Db.getAvailable(model) compare.sort((a, b) => a.localeCompare(b)) - res.status(200).json(available.every((item, i) => item === compare[i])) + res + .status(200) + .json(available.every((item, i) => item === compare[i])) } else { res.status(200).json(available) } } else { const available = await getAll(current) - Object.values(available).forEach(c => c.sort((a, b) => a.localeCompare(b))) + Object.values(available).forEach((c) => + c.sort((a, b) => a.localeCompare(b)), + ) if (equal !== undefined) { const compare = await getAll(!current) - Object.values(compare).forEach(c => c.sort((a, b) => a.localeCompare(b))) + Object.values(compare).forEach((c) => + c.sort((a, b) => a.localeCompare(b)), + ) - res.status(200).json(Object.keys(available).every(cat => ( - available[cat].every((item, j) => item === compare[cat][j]) - ))) + res + .status(200) + .json( + Object.keys(available).every((cat) => + available[cat].every((item, j) => item === compare[cat][j]), + ), + ) } else { res.status(200).json(available) } @@ -90,9 +112,13 @@ router.get(['/', '/:category'], async (req, res) => { }) router.put('/:category', async (req, res) => { - const { model, category } = queryObj[resolveCategory(req.params.category)] || {} + const { model, category } = + queryObj[resolveCategory(req.params.category)] || {} try { - if (api.reactMapSecret && req.headers['react-map-secret'] === api.reactMapSecret) { + if ( + api.reactMapSecret && + req.headers['react-map-secret'] === api.reactMapSecret + ) { if (model && category) { await Event.setAvailable(category, model, Db) } else { @@ -103,11 +129,17 @@ router.put('/:category', async (req, res) => { Event.setAvailable('nests', 'Nest', Db), ]) } - res.status(200).json({ status: `updated availabled for ${category || 'all'}` }) + res + .status(200) + .json({ status: `updated availabled for ${category || 'all'}` }) } else { throw new Error('Incorrect or missing API secret') } - console.log(`[API] api/v1/${path.parse(__filename).name} - updated availabled for ${category || 'all'}`) + console.log( + `[API] api/v1/${path.parse(__filename).name} - updated availabled for ${ + category || 'all' + }`, + ) } catch (e) { console.error(`[API] api/v1/${path.parse(__filename).name}`, e) res.status(500).json({ status: 'ServerError', reason: e.message }) diff --git a/server/src/routes/api/v1/sessions.js b/server/src/routes/api/v1/sessions.js index 2d3b71ea0..0194ee948 100644 --- a/server/src/routes/api/v1/sessions.js +++ b/server/src/routes/api/v1/sessions.js @@ -5,10 +5,12 @@ const { Session } = require('../../../models/index') router.get('/', async (req, res) => { try { - if (api.reactMapSecret && req.headers['react-map-secret'] === api.reactMapSecret) { - const ts = Math.floor((new Date()).getTime() / 1000) - res.status(200).json(await Session.query() - .where('expires', '>=', ts)) + if ( + api.reactMapSecret && + req.headers['react-map-secret'] === api.reactMapSecret + ) { + const ts = Math.floor(new Date().getTime() / 1000) + res.status(200).json(await Session.query().where('expires', '>=', ts)) } else { throw new Error('Incorrect or missing API secret') } @@ -20,9 +22,13 @@ router.get('/', async (req, res) => { }) router.get('/hasValid/:id', async (req, res) => { try { - if (api.reactMapSecret && req.headers['react-map-secret'] === api.reactMapSecret) { - const results = await Session.query() - .whereRaw(`json_extract(data, '$.passport.user.id') = ${req.params.id}`) + if ( + api.reactMapSecret && + req.headers['react-map-secret'] === api.reactMapSecret + ) { + const results = await Session.query().whereRaw( + `json_extract(data, '$.passport.user.id') = ${req.params.id}`, + ) res.status(200).json({ valid: Boolean(results.length), length: results.length, @@ -38,7 +44,10 @@ router.get('/hasValid/:id', async (req, res) => { router.get('/clearSessions/:id', async (req, res) => { try { - if (api.reactMapSecret && req.headers['react-map-secret'] === api.reactMapSecret) { + if ( + api.reactMapSecret && + req.headers['react-map-secret'] === api.reactMapSecret + ) { const results = await Session.query() .whereRaw(`json_extract(data, '$.passport.user.id') = ${req.params.id}`) .delete() @@ -48,7 +57,10 @@ router.get('/clearSessions/:id', async (req, res) => { } console.log(`[API] api/v1/sessions/clearSessions/${req.params.id}`) } catch (e) { - console.error(`[API Error] api/v1/sessions/clearSessions/${req.params.id}`, e) + console.error( + `[API Error] api/v1/sessions/clearSessions/${req.params.id}`, + e, + ) res.status(500).json({ status: 'ServerError', reason: e.message }) } }) diff --git a/server/src/routes/api/v1/users.js b/server/src/routes/api/v1/users.js index 3ec98b4f6..a97db2ea3 100644 --- a/server/src/routes/api/v1/users.js +++ b/server/src/routes/api/v1/users.js @@ -5,7 +5,10 @@ const { User } = require('../../../models/index') router.get('/', async (req, res) => { try { - if (api.reactMapSecret && req.headers['react-map-secret'] === api.reactMapSecret) { + if ( + api.reactMapSecret && + req.headers['react-map-secret'] === api.reactMapSecret + ) { res.status(200).json(await User.query()) } else { throw new Error('Incorrect or missing API secret') @@ -19,7 +22,10 @@ router.get('/', async (req, res) => { router.get('/:id', async (req, res) => { try { - if (api.reactMapSecret && req.headers['react-map-secret'] === api.reactMapSecret) { + if ( + api.reactMapSecret && + req.headers['react-map-secret'] === api.reactMapSecret + ) { res.status(200).json(await User.query().findById(req.params.id)) } else { throw new Error('Incorrect or missing API secret') diff --git a/server/src/routes/authRouter.js b/server/src/routes/authRouter.js index 2bb16e2fd..f9f78a474 100644 --- a/server/src/routes/authRouter.js +++ b/server/src/routes/authRouter.js @@ -3,22 +3,32 @@ /* eslint-disable no-console */ const router = require('express').Router() const passport = require('passport') -const { isValidSession, clearOtherSessions } = require('../services/sessionStore') -const { authentication: { strategies } } = require('../services/config') +const { + isValidSession, + clearOtherSessions, +} = require('../services/sessionStore') +const { + authentication: { strategies }, +} = require('../services/config') // Loads up the base auth routes and any custom ones -strategies.forEach(strategy => { - const method = strategy.type === 'discord' || strategy.type === 'telegram' ? 'get' : 'post' +strategies.forEach((strategy) => { + const method = + strategy.type === 'discord' || strategy.type === 'telegram' ? 'get' : 'post' if (strategy.enabled) { - router[method](`/${strategy.name}`, passport.authenticate(strategy.name, { - failureRedirect: '/', - successRedirect: '/', - })) router[method]( - `/${strategy.name}/callback`, - async (req, res, next) => passport.authenticate(strategy.name, async (err, user, info) => { - if (err) { return next(err) } + `/${strategy.name}`, + passport.authenticate(strategy.name, { + failureRedirect: '/', + successRedirect: '/', + }), + ) + router[method](`/${strategy.name}/callback`, async (req, res, next) => + passport.authenticate(strategy.name, async (err, user, info) => { + if (err) { + return next(err) + } if (!user) { res.status(401).json(info.message) } else { @@ -26,7 +36,9 @@ strategies.forEach(strategy => { return req.login(user, async () => { const { id } = user if (!(await isValidSession(id))) { - console.debug('[Session] Detected multiple sessions, clearing old ones...') + console.debug( + '[Session] Detected multiple sessions, clearing old ones...', + ) await clearOtherSessions(id, req.sessionID) } return res.redirect('/') @@ -38,7 +50,11 @@ strategies.forEach(strategy => { } })(req, res, next), ) - console.log(`[AUTH] ${method.toUpperCase()} /auth/${strategy.name}/callback route initialized`) + console.log( + `[AUTH] ${method.toUpperCase()} /auth/${ + strategy.name + }/callback route initialized`, + ) } }) diff --git a/server/src/routes/rootRouter.js b/server/src/routes/rootRouter.js index d13d39c36..4a198dec3 100644 --- a/server/src/routes/rootRouter.js +++ b/server/src/routes/rootRouter.js @@ -27,8 +27,16 @@ rootRouter.get('/logout', (req, res) => { rootRouter.post('/clientError', (req) => { if (req.headers.version === version && req.isAuthenticated()) { - const { body: { error }, user } = req - const userName = user?.username || user?.discordId || user?.telegramId || user?.id || 'Unknown' + const { + body: { error }, + user, + } = req + const userName = + user?.username || + user?.discordId || + user?.telegramId || + user?.id || + 'Unknown' if (error && config.devOptions.clientErrors) { console.error('[CLIENT]', error, `- User: ${userName}`) } @@ -43,13 +51,17 @@ rootRouter.get('/area/:area/:zoom?', (req, res) => { ? scanAreas[req.headers.host] : scanAreas.main if (validScanAreas.features.length) { - const foundArea = validScanAreas.features.find(a => a.properties.name.toLowerCase() === area.toLowerCase()) + const foundArea = validScanAreas.features.find( + (a) => a.properties.name.toLowerCase() === area.toLowerCase(), + ) if (foundArea) { const [lon, lat] = center(foundArea).geometry.coordinates return res.redirect(`/@/${lat}/${lon}/${zoom || 18}`) } if (manualAreas.length) { - const { lat, lon } = manualAreas.find(a => a.name.toLowerCase() === area.toLowerCase()) + const { lat, lon } = manualAreas.find( + (a) => a.name.toLowerCase() === area.toLowerCase(), + ) return res.redirect(`/@/${lat}/${lon}/${zoom || 18}`) } return res.redirect('/404') @@ -62,20 +74,32 @@ rootRouter.get('/area/:area/:zoom?', (req, res) => { rootRouter.get('/settings', async (req, res) => { try { - if (config.authentication.alwaysEnabledPerms.length || !config.authMethods.length) { + if ( + config.authentication.alwaysEnabledPerms.length || + !config.authMethods.length + ) { if (req.session.tutorial === undefined) { req.session.tutorial = !config.map.forceTutorial } req.session.perms = { areaRestrictions: Utility.areaPerms(['none']), webhooks: [], - scanner: Object.keys(config.scanner).filter((key) => key !== 'backendConfig' && config.scanner[key].enabled && !config.scanner[key].discordRoles.length && !config.scanner[key].telegramGroups.length), + scanner: Object.keys(config.scanner).filter( + (key) => + key !== 'backendConfig' && + config.scanner[key].enabled && + !config.scanner[key].discordRoles.length && + !config.scanner[key].telegramGroups.length, + ), } - config.authentication.alwaysEnabledPerms.forEach(perm => { + config.authentication.alwaysEnabledPerms.forEach((perm) => { if (config.authentication.perms[perm]) { req.session.perms[perm] = true } else { - console.warn('[AUTH] Invalid Perm in "alwaysEnabledPerms" array:', perm) + console.warn( + '[AUTH] Invalid Perm in "alwaysEnabledPerms" array:', + perm, + ) } }) req.session.save() @@ -87,13 +111,24 @@ rootRouter.get('/settings', async (req, res) => { const user = await User.query().findById(req.user.id) if (user) { delete user.password - return { ...req.user, ...user, valid: true, username: user.username || req.user.username } + return { + ...req.user, + ...user, + valid: true, + username: user.username || req.user.username, + } } - console.log('[SESSION] Legacy user detected, forcing logout, User ID:', req?.user?.id) + console.log( + '[SESSION] Legacy user detected, forcing logout, User ID:', + req?.user?.id, + ) req.logout() return { valid: false, tutorial: !config.map.forceTutorial } } catch (e) { - console.log('[SESSION] Issue finding user, forcing logout, User ID:', req?.user?.id) + console.log( + '[SESSION] Issue finding user, forcing logout, User ID:', + req?.user?.id, + ) req.logout() return { valid: false, tutorial: !config.map.forceTutorial } } @@ -114,9 +149,15 @@ rootRouter.get('/settings', async (req, res) => { excludeList: config.authentication.excludeFromTutorial, polling: config.api.polling, }, - localeSelection: Object.fromEntries(config.map.localeSelection.map(l => [l, { name: l }])), - tileServers: Object.fromEntries(config.tileServers.map(s => [s.name, s])), - navigation: Object.fromEntries(config.navigation.map(n => [n.name, n])), + localeSelection: Object.fromEntries( + config.map.localeSelection.map((l) => [l, { name: l }]), + ), + tileServers: Object.fromEntries( + config.tileServers.map((s) => [s.name, s]), + ), + navigation: Object.fromEntries( + config.navigation.map((n) => [n.name, n]), + ), drawer: { temporary: {}, persistent: {}, @@ -132,17 +173,21 @@ rootRouter.get('/settings', async (req, res) => { enableScanNext: config.scanner.scanNext.enabled, scanNextShowScanCount: config.scanner.scanNext.showScanCount, scanNextShowScanQueue: config.scanner.scanNext.showScanQueue, - scanNextAreaRestriction: config.scanner.scanNext.scanNextAreaRestriction, + scanNextAreaRestriction: + config.scanner.scanNext.scanNextAreaRestriction, enableScanZone: config.scanner.scanZone.enabled, scanZoneShowScanCount: config.scanner.scanZone.showScanCount, scanZoneShowScanQueue: config.scanner.scanZone.showScanQueue, - advancedScanZoneOptions: config.scanner.scanZone.advancedScanZoneOptions, + advancedScanZoneOptions: + config.scanner.scanZone.advancedScanZoneOptions, scanZoneRadius: config.scanner.scanZone.scanZoneRadius, scanZoneSpacing: config.scanner.scanZone.scanZoneSpacing, scanZoneMaxSize: config.scanner.scanZone.scanZoneMaxSize, - scanZoneAreaRestriction: config.scanner.scanZone.scanZoneAreaRestriction, + scanZoneAreaRestriction: + config.scanner.scanZone.scanZoneAreaRestriction, }, - gymValidDataLimit: Date.now() / 1000 - (config.api.gymValidDataLimit * 86400), + gymValidDataLimit: + Date.now() / 1000 - config.api.gymValidDataLimit * 86400, }, available: { pokemon: [], pokestops: [], gyms: [], nests: [] }, } @@ -152,23 +197,37 @@ rootRouter.get('/settings', async (req, res) => { serverSettings.loggedIn = req.user // keys that are being sent to the frontend but are not options - const ignoreKeys = ['map', 'manualAreas', 'limit', 'icons', 'scanner', 'gymValidDataLimit'] + const ignoreKeys = [ + 'map', + 'manualAreas', + 'limit', + 'icons', + 'scanner', + 'gymValidDataLimit', + ] - Object.keys(serverSettings.config).forEach(setting => { + Object.keys(serverSettings.config).forEach((setting) => { try { if (!ignoreKeys.includes(setting)) { const category = serverSettings.config[setting] - Object.keys(category).forEach(option => { + Object.keys(category).forEach((option) => { category[option].name = option }) - if (config.map[setting] && typeof config.map[setting] !== 'object') { + if ( + config.map[setting] && + typeof config.map[setting] !== 'object' + ) { serverSettings.settings[setting] = config.map[setting] } else { - serverSettings.settings[setting] = category[Object.keys(category)[0]].name + serverSettings.settings[setting] = + category[Object.keys(category)[0]].name } } } catch (e) { - console.warn(`Error setting ${setting}, most likely means there are no options set in the config`, e.message) + console.warn( + `Error setting ${setting}, most likely means there are no options set in the config`, + e.message, + ) } }) @@ -182,11 +241,14 @@ rootRouter.get('/settings', async (req, res) => { ? await Db.getAvailable('Gym') : Event.available.gyms } - if (serverSettings.user.perms.quests - || serverSettings.user.perms.pokestops - || serverSettings.user.perms.invasions - || serverSettings.user.perms.lures) { - serverSettings.available.pokestops = config.api.queryOnSessionInit.quests + if ( + serverSettings.user.perms.quests || + serverSettings.user.perms.pokestops || + serverSettings.user.perms.invasions || + serverSettings.user.perms.lures + ) { + serverSettings.available.pokestops = config.api.queryOnSessionInit + .quests ? await Db.getAvailable('Pokestop') : Event.available.pokestops serverSettings.available.withConditions = Db.questConditions @@ -196,57 +258,101 @@ rootRouter.get('/settings', async (req, res) => { ? await Db.getAvailable('Nest') : Event.available.nests } - if (Object.values(config.api.queryOnSessionInit).some(v => v)) { + if (Object.values(config.api.queryOnSessionInit).some((v) => v)) { Event.addAvailable() - serverSettings.masterfile = { ...Event.masterfile, invasions: Event.invasions } + serverSettings.masterfile = { + ...Event.masterfile, + invasions: Event.invasions, + } } - serverSettings.defaultFilters = Utility.buildDefaultFilters(serverSettings.user.perms, serverSettings.available) + serverSettings.defaultFilters = Utility.buildDefaultFilters( + serverSettings.user.perms, + serverSettings.available, + ) // Backup in case there are Pokemon/Quests/Raids etc that are not in the masterfile // Primary for quest rewards that are form unset, despite normally have a set form - serverSettings.ui = Utility.buildPrimaryUi(serverSettings.defaultFilters, serverSettings.user.perms) + serverSettings.ui = Utility.buildPrimaryUi( + serverSettings.defaultFilters, + serverSettings.user.perms, + ) serverSettings.menus = Utility.buildAdvMenus(serverSettings.available) - const { clientValues, clientMenus } = Utility.buildClientOptions(serverSettings.user.perms) + const { clientValues, clientMenus } = Utility.buildClientOptions( + serverSettings.user.perms, + ) serverSettings.userSettings = clientValues serverSettings.clientMenus = clientMenus - if (config.webhooks.length && serverSettings.user?.perms?.webhooks?.length) { + if ( + config.webhooks.length && + serverSettings.user?.perms?.webhooks?.length + ) { serverSettings.webhooks = {} - const filtered = config.webhooks.filter(webhook => serverSettings.user.perms.webhooks.includes(webhook.name)) + const filtered = config.webhooks.filter((webhook) => + serverSettings.user.perms.webhooks.includes(webhook.name), + ) try { - await Promise.all(filtered.map(async webhook => { - if (webhook.enabled && Event.webhookObj?.[webhook.name]?.client?.valid) { - const webhookId = Utility.evalWebhookId(serverSettings.user) - const { strategy, webhookStrategy } = serverSettings.user + await Promise.all( + filtered.map(async (webhook) => { + if ( + webhook.enabled && + Event.webhookObj?.[webhook.name]?.client?.valid + ) { + const webhookId = Utility.evalWebhookId(serverSettings.user) + const { strategy, webhookStrategy } = serverSettings.user - const remoteData = await Fetch.webhookApi('allProfiles', webhookId, 'GET', webhook.name) - const { areas } = await Fetch.webhookApi('humans', webhookId, 'GET', webhook.name) + const remoteData = await Fetch.webhookApi( + 'allProfiles', + webhookId, + 'GET', + webhook.name, + ) + const { areas } = await Fetch.webhookApi( + 'humans', + webhookId, + 'GET', + webhook.name, + ) - if (remoteData && areas) { - serverSettings.webhooks[webhook.name] = remoteData.human.admin_disable - ? Event.webhookObj[webhook.name].client - : { - ...Event.webhookObj[webhook.name].client, - ...remoteData, - hasNominatim: Boolean(Event.webhookObj[webhook.name].server.nominatimUrl), - locale: remoteData.human.language || Event.webhookObj[webhook.name].client.locale, - available: areas - .sort((a, b) => a.name.localeCompare(b.name)) - .filter(area => area.userSelectable !== false) - .map(area => area.name), - templates: Event.webhookObj[webhook.name].client.templates[webhookStrategy || strategy], - } + if (remoteData && areas) { + serverSettings.webhooks[webhook.name] = remoteData.human + .admin_disable + ? Event.webhookObj[webhook.name].client + : { + ...Event.webhookObj[webhook.name].client, + ...remoteData, + hasNominatim: Boolean( + Event.webhookObj[webhook.name].server.nominatimUrl, + ), + locale: + remoteData.human.language || + Event.webhookObj[webhook.name].client.locale, + available: areas + .sort((a, b) => a.name.localeCompare(b.name)) + .filter((area) => area.userSelectable !== false) + .map((area) => area.name), + templates: + Event.webhookObj[webhook.name].client.templates[ + webhookStrategy || strategy + ], + } + } } - } - })) + }), + ) } catch (e) { serverSettings.webhooks = null - console.warn('[AUTH]', e.message, 'Unable to fetch webhook data, this is unlikely an issue with ReactMap, check to make sure the user is registered in the webhook database. User ID:', serverSettings.user.id) + console.warn( + '[AUTH]', + e.message, + 'Unable to fetch webhook data, this is unlikely an issue with ReactMap, check to make sure the user is registered in the webhook database. User ID:', + serverSettings.user.id, + ) } } } diff --git a/server/src/services/DbCheck.js b/server/src/services/DbCheck.js index 6a774b173..6eff86f39 100644 --- a/server/src/services/DbCheck.js +++ b/server/src/services/DbCheck.js @@ -5,16 +5,18 @@ const extend = require('extend') module.exports = class DbCheck { constructor(validModels, dbSettings, queryDebug, apiSettings, distanceUnit) { - this.validModels = validModels.flatMap(s => s.useFor) + this.validModels = validModels.flatMap((s) => s.useFor) this.singleModels = ['User', 'Badge', 'Session'] this.searchLimit = apiSettings.searchLimit this.models = {} this.questConditions = {} this.connections = dbSettings.schemas - .filter(s => s.useFor.length) + .filter((s) => s.useFor.length) .map((schema, i) => { - schema.useFor.forEach(category => { - const capital = `${category.charAt(0).toUpperCase()}${category.slice(1)}` + schema.useFor.forEach((category) => { + const capital = `${category.charAt(0).toUpperCase()}${category.slice( + 1, + )}` if (!this.models[capital]) { this.models[capital] = [] } @@ -42,49 +44,68 @@ module.exports = class DbCheck { } static getDistance(args, isMad, distanceUnit) { - return raw(`ROUND(( ${distanceUnit === 'mi' ? '3959' : '6371'} * acos( cos( radians(${args.lat}) ) * cos( radians( ${isMad ? 'latitude' : 'lat'} ) ) * cos( radians( ${isMad ? 'longitude' : 'lon'} ) - radians(${args.lon}) ) + sin( radians(${args.lat}) ) * sin( radians( ${isMad ? 'latitude' : 'lat'} ) ) ) ),2)`).as('distance') + return raw( + `ROUND(( ${ + distanceUnit === 'mi' ? '3959' : '6371' + } * acos( cos( radians(${args.lat}) ) * cos( radians( ${ + isMad ? 'latitude' : 'lat' + } ) ) * cos( radians( ${isMad ? 'longitude' : 'lon'} ) - radians(${ + args.lon + }) ) + sin( radians(${args.lat}) ) * sin( radians( ${ + isMad ? 'latitude' : 'lat' + } ) ) ) ),2)`, + ).as('distance') } async determineType() { - console.log(`[DB] Determining database types for ${this.connections.length} connection${this.connections.length > 1 ? 's' : ''}`) - await Promise.all(this.connections.map(async (schema, i) => { - try { - const [isMad, pvpV2] = await schema('pokemon').columnInfo() - .then(columns => [ - 'cp_multiplier' in columns, - 'pvp' in columns, - ]) - const [hasRewardAmount, hasAltQuests] = await schema('pokestop').columnInfo() - .then(columns => ([ - ('quest_reward_amount' in columns || isMad), - 'alternative_quest_type' in columns, - ])) - const [hasMultiInvasions, multiInvasionMs] = await schema('incident').columnInfo() - .then(columns => ([ - 'character' in columns, - 'expiration_ms' in columns, - ])) - const [availableSlotsCol] = await schema('gym').columnInfo() - .then(columns => ([ - 'availble_slots' in columns ? 'availble_slots' : 'available_slots', - ])) - Object.entries(this.models).forEach(([category, sources]) => { - sources.forEach((source, j) => { - if (source.connection === i) { - this.models[category][j].isMad = isMad - this.models[category][j].pvpV2 = pvpV2 - this.models[category][j].hasRewardAmount = hasRewardAmount - this.models[category][j].hasAltQuests = hasAltQuests - this.models[category][j].hasMultiInvasions = hasMultiInvasions - this.models[category][j].multiInvasionMs = multiInvasionMs - this.models[category][j].availableSlotsCol = availableSlotsCol - } + console.log( + `[DB] Determining database types for ${ + this.connections.length + } connection${this.connections.length > 1 ? 's' : ''}`, + ) + await Promise.all( + this.connections.map(async (schema, i) => { + try { + const [isMad, pvpV2] = await schema('pokemon') + .columnInfo() + .then((columns) => ['cp_multiplier' in columns, 'pvp' in columns]) + const [hasRewardAmount, hasAltQuests] = await schema('pokestop') + .columnInfo() + .then((columns) => [ + 'quest_reward_amount' in columns || isMad, + 'alternative_quest_type' in columns, + ]) + const [hasMultiInvasions, multiInvasionMs] = await schema('incident') + .columnInfo() + .then((columns) => [ + 'character' in columns, + 'expiration_ms' in columns, + ]) + const [availableSlotsCol] = await schema('gym') + .columnInfo() + .then((columns) => [ + 'availble_slots' in columns + ? 'availble_slots' + : 'available_slots', + ]) + Object.entries(this.models).forEach(([category, sources]) => { + sources.forEach((source, j) => { + if (source.connection === i) { + this.models[category][j].isMad = isMad + this.models[category][j].pvpV2 = pvpV2 + this.models[category][j].hasRewardAmount = hasRewardAmount + this.models[category][j].hasAltQuests = hasAltQuests + this.models[category][j].hasMultiInvasions = hasMultiInvasions + this.models[category][j].multiInvasionMs = multiInvasionMs + this.models[category][j].availableSlotsCol = availableSlotsCol + } + }) }) - }) - } catch (e) { - console.error('[DB]', e.message) - } - })) + } catch (e) { + console.error('[DB]', e.message) + } + }), + ) } bindConnections(models) { @@ -101,16 +122,24 @@ module.exports = class DbCheck { models[model].knex(this.connections[sources[0].connection]) } else { sources.forEach((source, i) => { - this.models[model][i].SubModel = models[model].bindKnex(this.connections[source.connection]) + this.models[model][i].SubModel = models[model].bindKnex( + this.connections[source.connection], + ) }) } - console.log(`[DB] Bound ${model} to ${sources.length} connection${sources.length > 1 ? 's' : ''}`) + console.log( + `[DB] Bound ${model} to ${sources.length} connection${ + sources.length > 1 ? 's' : '' + }`, + ) }) } catch (e) { console.error(` Error: ${e.message} - Info: Only ${[this.validModels].join(', ')} are valid options in the useFor arrays + Info: Only ${[this.validModels].join( + ', ', + )} are valid options in the useFor arrays `) process.exit(9) } @@ -131,25 +160,38 @@ module.exports = class DbCheck { } async getAll(model, perms, args, userId, method = 'getAll') { - const data = await Promise.all(this.models[model].map(async (source) => ( - source.SubModel[method](perms, args, source, userId) - ))) + const data = await Promise.all( + this.models[model].map(async (source) => + source.SubModel[method](perms, args, source, userId), + ), + ) return DbCheck.deDupeResults(data) } async getOne(model, id, method = 'getOne') { - const data = await Promise.all(this.models[model].map(async (source) => ( - source.SubModel[method](id, source) - ))) + const data = await Promise.all( + this.models[model].map(async (source) => + source.SubModel[method](id, source), + ), + ) const cleaned = DbCheck.deDupeResults(data.filter(Boolean)) return (Array.isArray(cleaned) ? cleaned[0] : cleaned) || {} } async search(model, perms, args, method = 'search') { - const data = await Promise.all(this.models[model].map(async (source) => ( - source.SubModel[method](perms, args, source, DbCheck.getDistance(args, source.isMad, this.distanceUnit)) - ))) - const deDuped = DbCheck.deDupeResults(data).sort((a, b) => a.distance - b.distance) + const data = await Promise.all( + this.models[model].map(async (source) => + source.SubModel[method]( + perms, + args, + source, + DbCheck.getDistance(args, source.isMad, this.distanceUnit), + ), + ), + ) + const deDuped = DbCheck.deDupeResults(data).sort( + (a, b) => a.distance - b.distance, + ) if (deDuped.length > this.searchLimit) { deDuped.length = this.searchLimit } @@ -157,12 +199,16 @@ module.exports = class DbCheck { } async submissionCells(args) { - const stopData = await Promise.all(this.models.Pokestop.map(async (source) => ( - source.SubModel.getSubmissions(args, source) - ))) - const gymData = await Promise.all(this.models.Gym.map(async (source) => ( - source.SubModel.getSubmissions(args, source) - ))) + const stopData = await Promise.all( + this.models.Pokestop.map(async (source) => + source.SubModel.getSubmissions(args, source), + ), + ) + const gymData = await Promise.all( + this.models.Gym.map(async (source) => + source.SubModel.getSubmissions(args, source), + ), + ) return [DbCheck.deDupeResults(stopData), DbCheck.deDupeResults(gymData)] } @@ -170,18 +216,27 @@ module.exports = class DbCheck { if (this.models[model]) { console.log(`[DB] Querying available for ${model}`) try { - const results = await Promise.all(this.models[model].map(async (source) => ( - source.SubModel.getAvailable(source) - ))) + const results = await Promise.all( + this.models[model].map(async (source) => + source.SubModel.getAvailable(source), + ), + ) console.log(`[DB] Setting available for ${model}`) if (model === 'Pokestop') { - results.forEach(result => { + results.forEach((result) => { if ('conditions' in result) { - this.questConditions = extend(true, this.questConditions, result.conditions) + this.questConditions = extend( + true, + this.questConditions, + result.conditions, + ) } }) this.questConditions = Object.fromEntries( - Object.entries(this.questConditions).map(([key, titles]) => [key, Object.values(titles)]), + Object.entries(this.questConditions).map(([key, titles]) => [ + key, + Object.values(titles), + ]), ) } if (results.length === 1) return results[0].available @@ -195,8 +250,17 @@ module.exports = class DbCheck { return [...returnSet] } } catch (e) { - console.warn('[WARN] Unable to query available for:', model, '\n', e.message) - if (model === 'Nest') console.warn('[WARN] This is likely due to "nest" being in a useFor array but not in the database') + console.warn( + '[WARN] Unable to query available for:', + model, + '\n', + e.message, + ) + if (model === 'Nest') { + console.warn( + '[WARN] This is likely due to "nest" being in a useFor array but not in the database', + ) + } return [] } } diff --git a/server/src/services/DiscordClient.js b/server/src/services/DiscordClient.js index 089b21070..4e7d31275 100644 --- a/server/src/services/DiscordClient.js +++ b/server/src/services/DiscordClient.js @@ -6,7 +6,11 @@ /* eslint-disable import/no-dynamic-require */ /* global BigInt */ const fs = require('fs') -const { authentication: { alwaysEnabledPerms }, scanner, webhooks } = require('./config') +const { + authentication: { alwaysEnabledPerms }, + scanner, + webhooks, +} = require('./config') const Utility = require('./Utility') module.exports = class DiscordMapClient { @@ -25,15 +29,19 @@ module.exports = class DiscordMapClient { try { const members = await this.client.guilds.cache .get(guildId) - .members - .fetch() + .members.fetch() const member = members.get(userId) const roles = member.roles.cache - .filter(x => BigInt(x.id).toString()) + .filter((x) => BigInt(x.id).toString()) .keyArray() return roles } catch (e) { - console.error('[DISCORD] Failed to get roles in guild', guildId, 'for user', userId) + console.error( + '[DISCORD] Failed to get roles in guild', + guildId, + 'for user', + userId, + ) } return [] } @@ -55,25 +63,31 @@ module.exports = class DiscordMapClient { } async getPerms(user) { - const perms = Object.fromEntries(Object.keys(this.config.perms).map(x => [x, false])) + const perms = Object.fromEntries( + Object.keys(this.config.perms).map((x) => [x, false]), + ) perms.areaRestrictions = [] perms.webhooks = [] perms.scanner = [] try { const { guildsFull } = user - const guilds = user.guilds.map(guild => guild.id) + const guilds = user.guilds.map((guild) => guild.id) if (this.config.allowedUsers.includes(user.id)) { - Object.keys(perms).forEach((key) => perms[key] = true) + Object.keys(perms).forEach((key) => (perms[key] = true)) perms.areaRestrictions = [] - perms.webhooks = webhooks.map(x => x.name) - perms.scanner = Object.keys(scanner).map(x => x !== 'backendConfig' && scanner[x].enabled && x).filter(x => x !== false) - console.log(`[DISCORD] User ${user.username}#${user.discriminator} (${user.id}) in allowed users list, skipping guild and role check.`) + perms.webhooks = webhooks.map((x) => x.name) + perms.scanner = Object.keys(scanner) + .map((x) => x !== 'backendConfig' && scanner[x].enabled && x) + .filter((x) => x !== false) + console.log( + `[DISCORD] User ${user.username}#${user.discriminator} (${user.id}) in allowed users list, skipping guild and role check.`, + ) return perms } for (let i = 0; i < this.config.blockedGuilds.length; i += 1) { const guildId = this.config.blockedGuilds[i] if (guilds.includes(guildId)) { - perms.blocked = guildsFull.find(x => x.id === guildId).name + perms.blocked = guildsFull.find((x) => x.id === guildId).name return perms } } @@ -98,8 +112,12 @@ module.exports = class DiscordMapClient { } } } - perms.areaRestrictions.push(...Utility.areaPerms(userRoles, 'discord')) - perms.webhooks.push(...Utility.webhookPerms(userRoles, 'discordRoles')) + perms.areaRestrictions.push( + ...Utility.areaPerms(userRoles, 'discord'), + ) + perms.webhooks.push( + ...Utility.webhookPerms(userRoles, 'discordRoles'), + ) perms.scanner.push(...Utility.scannerPerms(userRoles, 'discordRoles')) } } @@ -120,9 +138,7 @@ module.exports = class DiscordMapClient { return } try { - const channel = await this.client.channels.cache - .get(channelId) - .fetch() + const channel = await this.client.channels.cache.get(channelId).fetch() if (channel && message) { channel.send(message) } diff --git a/server/src/services/EventManager.js b/server/src/services/EventManager.js index 7f5b4f3f9..1f506f67c 100644 --- a/server/src/services/EventManager.js +++ b/server/src/services/EventManager.js @@ -13,7 +13,8 @@ module.exports = class EventManager { this.invasions = masterfile.invasions this.available = { gyms: [], pokestops: [], pokemon: [], nests: [] } this.uicons = [] - this.baseUrl = 'https://raw.githubusercontent.com/WatWowMap/wwm-uicons/main/' + this.baseUrl = + 'https://raw.githubusercontent.com/WatWowMap/wwm-uicons/main/' this.webhookObj = {} } @@ -64,7 +65,7 @@ module.exports = class EventManager { async getUicons(styles) { console.log('[EVENT] Fetching Latest UICONS') - if (!styles.some(icon => icon.path === this.baseUrl)) { + if (!styles.some((icon) => icon.path === this.baseUrl)) { styles.push({ name: 'Base', path: this.baseUrl, @@ -82,42 +83,68 @@ module.exports = class EventManager { }, }) } - this.uicons = await Promise.all(styles.map(async style => { - try { - const response = style.path.startsWith('http') - ? await fetchJson(`${style.path}/index.json`) - : JSON.parse(await fs.readFile(path.resolve(__dirname, `../../../public/images/uicons/${style.path}/index.json`))) - return { ...style, data: response } - } catch (e) { - console.warn('[WARN] Failed to generate latest uicons for:', style, '\n', e.message) - console.warn(`[WARN] Make sure the path follows one of these two formats: \n\tRemote: ${this.baseUrl}\n\tLocal: wwm-uicons (And the uicons folder is found at /public/images/uicons/wwm-uicons/)`) - } - })) + this.uicons = await Promise.all( + styles.map(async (style) => { + try { + const response = style.path.startsWith('http') + ? await fetchJson(`${style.path}/index.json`) + : JSON.parse( + await fs.readFile( + path.resolve( + __dirname, + `../../../public/images/uicons/${style.path}/index.json`, + ), + ), + ) + return { ...style, data: response } + } catch (e) { + console.warn( + '[WARN] Failed to generate latest uicons for:', + style, + '\n', + e.message, + ) + console.warn( + `[WARN] Make sure the path follows one of these two formats: \n\tRemote: ${this.baseUrl}\n\tLocal: wwm-uicons (And the uicons folder is found at /public/images/uicons/wwm-uicons/)`, + ) + } + }), + ) this.uicons = this.uicons.filter(Boolean) } async getInvasions() { console.log('[EVENT] Fetching Latest Invasions') try { - this.invasions = await fetchJson('https://raw.githubusercontent.com/ccev/pogoinfo/v2/active/grunts.json') - .then(response => response ? Object.fromEntries( - Object.entries(this.invasions).map(([type, info]) => { - const latest = response[type] - const newInvasion = this.invasions[type] - if (info.encounters) { - Object.keys(info.encounters).forEach((position, i) => { - if (latest?.active) { - newInvasion.encounters[position] = latest.lineup.team[i].map((pkmn, j) => ( - pkmn.template === 'UNSET' && info.encounters[position][j] - ? info.encounters[position][j] - : { id: pkmn.id, form: pkmn.form })) - newInvasion.second_reward = latest.lineup.rewards.length > 1 + this.invasions = await fetchJson( + 'https://raw.githubusercontent.com/ccev/pogoinfo/v2/active/grunts.json', + ).then((response) => + response + ? Object.fromEntries( + Object.entries(this.invasions).map(([type, info]) => { + const latest = response[type] + const newInvasion = this.invasions[type] + if (info.encounters) { + Object.keys(info.encounters).forEach((position, i) => { + if (latest?.active) { + newInvasion.encounters[position] = latest.lineup.team[ + i + ].map((pkmn, j) => + pkmn.template === 'UNSET' && + info.encounters[position][j] + ? info.encounters[position][j] + : { id: pkmn.id, form: pkmn.form }, + ) + newInvasion.second_reward = + latest.lineup.rewards.length > 1 + } + }) } - }) - } - return [type, newInvasion] - }), - ) : this.invasions) + return [type, newInvasion] + }), + ) + : this.invasions, + ) } catch (e) { console.warn('[WARN] Unable to generate latest invasions:\n', e.message) } @@ -136,7 +163,7 @@ module.exports = class EventManager { addAvailable() { Object.entries(this.available).forEach(([category, entries]) => { - entries.forEach(item => { + entries.forEach((item) => { if (!Number.isNaN(parseInt(item.charAt(0)))) { const [id, form] = item.split('-') if (!this.masterfile.pokemon[id]) { @@ -153,7 +180,9 @@ module.exports = class EventManager { } if (!this.masterfile.pokemon[id].forms[form]) { this.masterfile.pokemon[id].forms[form] = { name: '*', category } - console.log(`[MF] Added ${this.masterfile.pokemon[id].name} Key: ${item} to masterfile. (${category})`) + console.log( + `[MF] Added ${this.masterfile.pokemon[id].name} Key: ${item} to masterfile. (${category})`, + ) } } }) @@ -161,8 +190,13 @@ module.exports = class EventManager { } async getWebhooks(config) { - await Promise.all(config.webhooks.map(async webhook => { - this.webhookObj = { ...this.webhookObj, [webhook.name]: await initWebhooks(webhook, config) } - })) + await Promise.all( + config.webhooks.map(async (webhook) => { + this.webhookObj = { + ...this.webhookObj, + [webhook.name]: await initWebhooks(webhook, config), + } + }), + ) } } diff --git a/server/src/services/PvpWrapper.js b/server/src/services/PvpWrapper.js index 6d09789ee..64e51e9ae 100644 --- a/server/src/services/PvpWrapper.js +++ b/server/src/services/PvpWrapper.js @@ -10,9 +10,8 @@ module.exports = class PvpWrapper extends Ohbem { levelCaps: config.levels, cachingStrategy: Ohbem.cachingStrategies.memoryHeavy, }) - this.rmCache = new NodeCache({ stdTTL: 60 * 60 * 1.5 }); - - (async () => { + this.rmCache = new NodeCache({ stdTTL: 60 * 60 * 1.5 }) + ;(async () => { this.updatePokemonData(await Ohbem.fetchPokemonData()) })() } @@ -36,7 +35,13 @@ module.exports = class PvpWrapper extends Ohbem { this.rmCache.set(key, result, pokemon.expire_timestamp - currentTs) return result } catch (e) { - console.error('[PKMN] Unable to process PVP Stats for Pokemon with ID#: ', pokemon.id, `#${pokemon.pokemon_id} - ${pokemon.form}`, '\n', e.message) + console.error( + '[PKMN] Unable to process PVP Stats for Pokemon with ID#: ', + pokemon.id, + `#${pokemon.pokemon_id} - ${pokemon.form}`, + '\n', + e.message, + ) return {} } } diff --git a/server/src/services/api/fetchJson.js b/server/src/services/api/fetchJson.js index 81d88b439..1e9946967 100644 --- a/server/src/services/api/fetchJson.js +++ b/server/src/services/api/fetchJson.js @@ -2,7 +2,11 @@ const fetch = require('node-fetch') const { AbortError } = require('node-fetch') -module.exports = async function fetchJson(url, options = undefined, log = false) { +module.exports = async function fetchJson( + url, + options = undefined, + log = false, +) { const controller = new AbortController() const timeout = setTimeout(() => { diff --git a/server/src/services/api/fetchNests.js b/server/src/services/api/fetchNests.js index 7c60e8a5b..4c7a08eca 100644 --- a/server/src/services/api/fetchNests.js +++ b/server/src/services/api/fetchNests.js @@ -1,12 +1,19 @@ /* eslint-disable no-console */ const fetchJson = require('./fetchJson') -const { api: { nestHemisphere } } = require('../config') +const { + api: { nestHemisphere }, +} = require('../config') const { Event } = require('../initialization') module.exports = async function fetchNests() { try { - const { [nestHemisphere]: nesting } = await fetchJson('https://raw.githubusercontent.com/ccev/pogoinfo/v2/nests/species-ids.json') - return nesting.map(pokemon => `${pokemon}-${Event.masterfile.pokemon[pokemon].defaultFormId}`) + const { [nestHemisphere]: nesting } = await fetchJson( + 'https://raw.githubusercontent.com/ccev/pogoinfo/v2/nests/species-ids.json', + ) + return nesting.map( + (pokemon) => + `${pokemon}-${Event.masterfile.pokemon[pokemon].defaultFormId}`, + ) } catch (e) { console.warn(e, '\nUnable to fetch available nests from GitHub') return [] diff --git a/server/src/services/api/fetchQuests.js b/server/src/services/api/fetchQuests.js index 21f02241d..7d07bc8de 100644 --- a/server/src/services/api/fetchQuests.js +++ b/server/src/services/api/fetchQuests.js @@ -4,22 +4,39 @@ const { Event } = require('../initialization') module.exports = async function fetchQuests() { try { - const quests = await fetchJson('https://raw.githubusercontent.com/ccev/pogoinfo/v2/active/quests.json') - const grunts = await fetchJson('https://raw.githubusercontent.com/ccev/pogoinfo/v2/active/grunts.json') + const quests = await fetchJson( + 'https://raw.githubusercontent.com/ccev/pogoinfo/v2/active/quests.json', + ) + const grunts = await fetchJson( + 'https://raw.githubusercontent.com/ccev/pogoinfo/v2/active/grunts.json', + ) const questsInfo = [] - Object.values(quests).forEach(questType => { - questType.forEach(task => { - task.rewards.forEach(reward => { + Object.values(quests).forEach((questType) => { + questType.forEach((task) => { + task.rewards.forEach((reward) => { switch (reward.type) { - case 'stardust': questsInfo.push(`d${reward.amount}`); break - case 'item': questsInfo.push(`q${reward.id}`); break - case 'energy': questsInfo.push(`m${reward.reward.id}-${reward.amount}`); break - default: questsInfo.push(`${reward.reward.id}-${reward.reward.form || Event.masterfile.pokemon[reward.reward.id].defaultFormId}`); break + case 'stardust': + questsInfo.push(`d${reward.amount}`) + break + case 'item': + questsInfo.push(`q${reward.id}`) + break + case 'energy': + questsInfo.push(`m${reward.reward.id}-${reward.amount}`) + break + default: + questsInfo.push( + `${reward.reward.id}-${ + reward.reward.form || + Event.masterfile.pokemon[reward.reward.id].defaultFormId + }`, + ) + break } }) }) }) - Object.keys(grunts).forEach(grunt => { + Object.keys(grunts).forEach((grunt) => { if (grunts[grunt].active) { questsInfo.push(`i${grunt}`) } @@ -29,7 +46,10 @@ module.exports = async function fetchQuests() { } return questsInfo } catch (e) { - console.warn(e, '\nUnable to fetch available quests and invasions from GitHub') + console.warn( + e, + '\nUnable to fetch available quests and invasions from GitHub', + ) return [] } } diff --git a/server/src/services/api/fetchRaids.js b/server/src/services/api/fetchRaids.js index e0d34373c..3331354ba 100644 --- a/server/src/services/api/fetchRaids.js +++ b/server/src/services/api/fetchRaids.js @@ -4,12 +4,20 @@ const { Event } = require('../initialization') module.exports = async function fetchRaids() { try { - const pogoInfoResults = await fetchJson('https://raw.githubusercontent.com/ccev/pogoinfo/v2/active/raids.json') + const pogoInfoResults = await fetchJson( + 'https://raw.githubusercontent.com/ccev/pogoinfo/v2/active/raids.json', + ) const raidsInfo = [] - Object.entries(pogoInfoResults).forEach(raidTier => { + Object.entries(pogoInfoResults).forEach((raidTier) => { const [egg, bosses] = raidTier raidsInfo.push(`e${egg}`, `r${egg}`) - bosses.forEach(boss => raidsInfo.push(`${boss.id}-${boss.form || Event.masterfile.pokemon[boss.id].defaultFormId}`)) + bosses.forEach((boss) => + raidsInfo.push( + `${boss.id}-${ + boss.form || Event.masterfile.pokemon[boss.id].defaultFormId + }`, + ), + ) }) return raidsInfo } catch (e) { diff --git a/server/src/services/api/resolveQuickHook.js b/server/src/services/api/resolveQuickHook.js index d89e05a7d..a51315989 100644 --- a/server/src/services/api/resolveQuickHook.js +++ b/server/src/services/api/resolveQuickHook.js @@ -4,50 +4,72 @@ const { Event } = require('../initialization') const getWildCards = (category, gymBattles) => { switch (category) { - case 'gym': return { team: 4, slot_changes: true, battle_changes: gymBattles } + case 'gym': + return { team: 4, slot_changes: true, battle_changes: gymBattles } case 'egg': - case 'raid': return { level: 90 } - default: return {} + case 'raid': + return { level: 90 } + default: + return {} } } -module.exports = async function resolveQuickHook(category, discordId, webhookName, data) { +module.exports = async function resolveQuickHook( + category, + discordId, + webhookName, + data, +) { const webhook = Event.webhookObj[webhookName] try { switch (category) { - case 'quickGym': { - const subCategories = ['raid', 'egg', 'gym'] - await Promise.all(subCategories.map(async subCategory => { - const post = await fetchJson(`${webhook.server.host}:${webhook.server.port}/api/tracking/${subCategory}/${discordId}`, { - method: 'POST', - body: JSON.stringify({ - ...webhook.client.info[subCategory].defaults, - ...getWildCards(subCategory, webhook.client.gymBattles), - gym_id: data.id, + case 'quickGym': + { + const subCategories = ['raid', 'egg', 'gym'] + await Promise.all( + subCategories.map(async (subCategory) => { + const post = await fetchJson( + `${webhook.server.host}:${webhook.server.port}/api/tracking/${subCategory}/${discordId}`, + { + method: 'POST', + body: JSON.stringify({ + ...webhook.client.info[subCategory].defaults, + ...getWildCards(subCategory, webhook.client.gymBattles), + gym_id: data.id, + }), + headers: { + 'X-Poracle-Secret': webhook.server.poracleSecret, + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + }, + ) + if (!post) { + throw new Error(`Failed to post ${subCategory} webhook`) + } }), - headers: { - 'X-Poracle-Secret': webhook.server.poracleSecret, - Accept: 'application/json', - 'Content-Type': 'application/json', - }, - }) - if (!post) { - throw new Error(`Failed to post ${subCategory} webhook`) - } - })) - } break - default: break + ) + } + break + default: + break } return { - ...await fetchJson(`${webhook.server.host}:${webhook.server.port}/api/tracking/allProfiles/${discordId}`, { - method: 'GET', - headers: { 'X-Poracle-Secret': webhook.server.poracleSecret }, - }), + ...(await fetchJson( + `${webhook.server.host}:${webhook.server.port}/api/tracking/allProfiles/${discordId}`, + { + method: 'GET', + headers: { 'X-Poracle-Secret': webhook.server.poracleSecret }, + }, + )), status: 'success', message: 'Success', } } catch (e) { - console.log(e.message, 'There was a problem processing that webhook request') + console.log( + e.message, + 'There was a problem processing that webhook request', + ) return { status: 'error', message: e.message } } } diff --git a/server/src/services/api/scannerApi.js b/server/src/services/api/scannerApi.js index 4b2e67062..dce481ab8 100644 --- a/server/src/services/api/scannerApi.js +++ b/server/src/services/api/scannerApi.js @@ -20,48 +20,114 @@ module.exports = async function scannerApi(category, method, data = null) { const headers = {} switch (config.scanner.backendConfig.platform) { case 'mad': - case 'rdm': Object.assign(headers, { Authorization: `Basic ${Buffer.from(`${config.scanner.backendConfig.apiUsername}:${config.scanner.backendConfig.apiPassword}`).toString('base64')}` }); break - default: break + case 'rdm': + Object.assign(headers, { + Authorization: `Basic ${Buffer.from( + `${config.scanner.backendConfig.apiUsername}:${config.scanner.backendConfig.apiPassword}`, + ).toString('base64')}`, + }) + break + default: + break } const payloadObj = {} switch (category) { - case 'scanNext': { - console.log(`[scannerApi] Request to scan new location by ${data.username}${data.userId ? ` (${data.userId})` : ''} - type ${data.scanNextType}: ${data.scanNextLocation[0].toFixed(5)},${data.scanNextLocation[1].toFixed(5)}`) - const coords = config.scanner.backendConfig.platform === 'mad' ? `${parseFloat(data.scanNextCoords[0][0].toFixed(5))},${parseFloat(data.scanNextCoords[0][1].toFixed(5))}` - : JSON.stringify(data.scanNextCoords.map(coord => ( - { lat: parseFloat(coord[0].toFixed(5)), lon: parseFloat(coord[1].toFixed(5)) }))) - Object.assign(payloadObj, { - url: config.scanner.backendConfig.platform === 'mad' ? `${config.scanner.backendConfig.apiEndpoint}/send_gps?origin=${encodeURIComponent(config.scanner.scanNext.scanNextDevice)}&coords=${coords}&sleeptime=${config.scanner.scanNext.scanNextSleeptime}` - : `${config.scanner.backendConfig.apiEndpoint}/set_data?scan_next=true&instance=${encodeURIComponent(config.scanner.scanNext.scanNextInstance)}&coords=${coords}`, - options: { method, headers }, - }) - } break - case 'scanZone': { - console.log(`[scannerApi] Request to scan new zone by ${data.username}${data.userId ? ` (${data.userId})` : ''} - size ${data.scanZoneSize}: ${data.scanZoneLocation[0].toFixed(5)},${data.scanZoneLocation[1].toFixed(5)}`) - const coords = JSON.stringify(data.scanZoneCoords.map(coord => ( - { lat: parseFloat(coord[0].toFixed(5)), lon: parseFloat(coord[1].toFixed(5)) }))) - Object.assign(payloadObj, { - url: `${config.scanner.backendConfig.apiEndpoint}/set_data?scan_next=true&instance=${encodeURIComponent(config.scanner.scanZone.scanZoneInstance)}&coords=${coords}`, - options: { method, headers }, - }) - } break + case 'scanNext': + { + console.log( + `[scannerApi] Request to scan new location by ${data.username}${ + data.userId ? ` (${data.userId})` : '' + } - type ${data.scanNextType}: ${data.scanNextLocation[0].toFixed( + 5, + )},${data.scanNextLocation[1].toFixed(5)}`, + ) + const coords = + config.scanner.backendConfig.platform === 'mad' + ? `${parseFloat( + data.scanNextCoords[0][0].toFixed(5), + )},${parseFloat(data.scanNextCoords[0][1].toFixed(5))}` + : JSON.stringify( + data.scanNextCoords.map((coord) => ({ + lat: parseFloat(coord[0].toFixed(5)), + lon: parseFloat(coord[1].toFixed(5)), + })), + ) + Object.assign(payloadObj, { + url: + config.scanner.backendConfig.platform === 'mad' + ? `${ + config.scanner.backendConfig.apiEndpoint + }/send_gps?origin=${encodeURIComponent( + config.scanner.scanNext.scanNextDevice, + )}&coords=${coords}&sleeptime=${ + config.scanner.scanNext.scanNextSleeptime + }` + : `${ + config.scanner.backendConfig.apiEndpoint + }/set_data?scan_next=true&instance=${encodeURIComponent( + config.scanner.scanNext.scanNextInstance, + )}&coords=${coords}`, + options: { method, headers }, + }) + } + break + case 'scanZone': + { + console.log( + `[scannerApi] Request to scan new zone by ${data.username}${ + data.userId ? ` (${data.userId})` : '' + } - size ${data.scanZoneSize}: ${data.scanZoneLocation[0].toFixed( + 5, + )},${data.scanZoneLocation[1].toFixed(5)}`, + ) + const coords = JSON.stringify( + data.scanZoneCoords.map((coord) => ({ + lat: parseFloat(coord[0].toFixed(5)), + lon: parseFloat(coord[1].toFixed(5)), + })), + ) + Object.assign(payloadObj, { + url: `${ + config.scanner.backendConfig.apiEndpoint + }/set_data?scan_next=true&instance=${encodeURIComponent( + config.scanner.scanZone.scanZoneInstance, + )}&coords=${coords}`, + options: { method, headers }, + }) + } + break case 'getQueue': - if (scannerQueue[data.typeName].timestamp - > (Date.now() - config.scanner.backendConfig.queueRefreshInterval * 1000)) { - console.log(`[scannerApi] Returning queue from memory for method ${data.typeName}: ${scannerQueue[data.typeName].queue}`) + if ( + scannerQueue[data.typeName].timestamp > + Date.now() - config.scanner.backendConfig.queueRefreshInterval * 1000 + ) { + console.log( + `[scannerApi] Returning queue from memory for method ${ + data.typeName + }: ${scannerQueue[data.typeName].queue}`, + ) return { status: 'ok', message: scannerQueue[data.typeName].queue } } console.log(`[scannerApi] Getting queue for method ${data.typeName}`) Object.assign(payloadObj, { - url: `${config.scanner.backendConfig.apiEndpoint}/get_data?${data.type}=true&queue_size=true&instance=${encodeURIComponent(config.scanner[data.typeName][`${data.typeName}Instance`])}`, + url: `${config.scanner.backendConfig.apiEndpoint}/get_data?${ + data.type + }=true&queue_size=true&instance=${encodeURIComponent( + config.scanner[data.typeName][`${data.typeName}Instance`], + )}`, options: { method, headers }, - }); break + }) + break default: - console.warn('[scannerApi] Api call without category'); break + console.warn('[scannerApi] Api call without category') + break } if (payloadObj.options.body) { - Object.assign(payloadObj.options.headers, { Accept: 'application/json', 'Content-Type': 'application/json' }) + Object.assign(payloadObj.options.headers, { + Accept: 'application/json', + 'Content-Type': 'application/json', + }) } const scannerResponse = await fetch(payloadObj.url, payloadObj.options) @@ -71,26 +137,49 @@ module.exports = async function scannerApi(category, method, data = null) { if (scannerResponse.status === 200 && category === 'getQueue') { const { data: queueData } = await scannerResponse.json() - console.log(`[scannerApi] Returning received queue for method ${data.typeName}: ${queueData.size}`) - scannerQueue[data.typeName] = { queue: queueData.size, timestamp: Date.now() } + console.log( + `[scannerApi] Returning received queue for method ${data.typeName}: ${queueData.size}`, + ) + scannerQueue[data.typeName] = { + queue: queueData.size, + timestamp: Date.now(), + } return { status: 'ok', message: queueData.size } } switch (scannerResponse.status) { case 200: - console.log(`[scannerApi] Request from ${data.username}${data.userId ? ` (${data.userId})` : ''} successful`) + console.log( + `[scannerApi] Request from ${data.username}${ + data.userId ? ` (${data.userId})` : '' + } successful`, + ) return { status: 'ok', message: 'scanner_ok' } case 401: - console.log('[scannerApi] Wrong credentials - check your scanner API settings in config') + console.log( + '[scannerApi] Wrong credentials - check your scanner API settings in config', + ) return { status: 'error', message: 'scanner_wrong_credentials' } case 404: - console.log(`[scannerApi] Error: instance ${config.scanner[category][`${category}Instance`]} does not exist`) + console.log( + `[scannerApi] Error: instance ${ + config.scanner[category][`${category}Instance`] + } does not exist`, + ) return { status: 'error', message: 'scanner_no_instance' } case 416: - console.log(`[scannerApi] Error: instance ${config.scanner[category][`${category}Instance`]} has no device assigned`) + console.log( + `[scannerApi] Error: instance ${ + config.scanner[category][`${category}Instance`] + } has no device assigned`, + ) return { status: 'error', message: 'scanner_no_device_assigned' } case 500: - console.log(`[scannerApi] Error: device ${config.scanner[category][`${category}Device`]} does not exist`) + console.log( + `[scannerApi] Error: device ${ + config.scanner[category][`${category}Device`] + } does not exist`, + ) return { status: 'error', message: 'scanner_no_device' } default: return { status: 'error', message: 'scanner_error' } @@ -99,7 +188,9 @@ module.exports = async function scannerApi(category, method, data = null) { if (e instanceof AbortError) { console.log('Request to the scanner timed out and was aborted') } else { - console.log('[scannerApi] There was a problem processing that scanner request') + console.log( + '[scannerApi] There was a problem processing that scanner request', + ) } return { status: 'error', message: 'scanner_error' } } finally { diff --git a/server/src/services/api/webhookApi.js b/server/src/services/api/webhookApi.js index 421c9c712..16985ce77 100644 --- a/server/src/services/api/webhookApi.js +++ b/server/src/services/api/webhookApi.js @@ -4,7 +4,13 @@ const resolveQuickHook = require('./resolveQuickHook') const fetchJson = require('./fetchJson') const { Event } = require('../initialization') -module.exports = async function webhookApi(category, discordId, method, webhookName, data = null) { +module.exports = async function webhookApi( + category, + discordId, + method, + webhookName, + data = null, +) { try { const webhook = Event.webhookObj[webhookName]?.server if (!webhook) { @@ -12,8 +18,11 @@ module.exports = async function webhookApi(category, discordId, method, webhookN } const headers = {} switch (webhook.provider) { - case 'poracle': Object.assign(headers, { 'X-Poracle-Secret': webhook.poracleSecret }); break - default: break + case 'poracle': + Object.assign(headers, { 'X-Poracle-Secret': webhook.poracleSecret }) + break + default: + break } const payloadObj = {} switch (category) { @@ -21,53 +30,74 @@ module.exports = async function webhookApi(category, discordId, method, webhookN case 'stop': case 'switchProfile': Object.assign(payloadObj, { - url: `${webhook.host}:${webhook.port}/api/humans/${discordId}/${category}${data ? `/${data}` : ''}`, + url: `${webhook.host}:${ + webhook.port + }/api/humans/${discordId}/${category}${data ? `/${data}` : ''}`, options: { method, headers }, get: 'human', - }); break + }) + break case 'setLocation': Object.assign(payloadObj, { url: `${webhook.host}:${webhook.port}/api/humans/${discordId}/${category}/${data[0]}/${data[1]}`, options: { method, headers }, get: 'human', - }); break + }) + break case 'setAreas': Object.assign(payloadObj, { url: `${webhook.host}:${webhook.port}/api/humans/${discordId}/${category}`, options: { - method, headers, body: JSON.stringify(data), + method, + headers, + body: JSON.stringify(data), }, get: 'human', - }); break + }) + break case 'geojson': Object.assign(payloadObj, { url: `${webhook.host}:${webhook.port}/api/geofence/all/${category}`, options: { method, headers }, - }); break + }) + break case 'areaSecurity': Object.assign(payloadObj, { url: `${webhook.host}:${webhook.port}/api/geofence/${discordId}`, options: { method, headers }, - }); break + }) + break case 'humans': Object.assign(payloadObj, { url: `${webhook.host}:${webhook.port}/api/humans/${discordId}`, options: { method, headers }, - }); break + }) + break case 'profiles-add': case 'profiles-byProfileNo': case 'profiles-update': case 'profiles-copy': - case 'profiles': { - const [main, sub] = category.split('-') - Object.assign(payloadObj, { - url: `${webhook.host}:${webhook.port}/api/${main}/${discordId}/${sub}${sub === 'copy' ? `/${data.from}/${data.to}` : ''}${method === 'DELETE' ? `/${data}` : ''}`, - options: { - method, headers, body: method === 'POST' && category !== 'profiles-copy' ? JSON.stringify(data) : undefined, - }, - get: main, - }) - } break + case 'profiles': + { + const [main, sub] = category.split('-') + Object.assign(payloadObj, { + url: `${webhook.host}:${ + webhook.port + }/api/${main}/${discordId}/${sub}${ + sub === 'copy' ? `/${data.from}/${data.to}` : '' + }${method === 'DELETE' ? `/${data}` : ''}`, + options: { + method, + headers, + body: + method === 'POST' && category !== 'profiles-copy' + ? JSON.stringify(data) + : undefined, + }, + get: main, + }) + } + break case 'egg-delete': case 'invasion-delete': case 'lure-delete': @@ -75,16 +105,20 @@ module.exports = async function webhookApi(category, discordId, method, webhookN case 'pokemon-delete': case 'quest-delete': case 'raid-delete': - case 'gym-delete': { - const [main, sub] = category.split('-') - Object.assign(payloadObj, { - url: `${webhook.host}:${webhook.port}/api/tracking/${main}/${discordId}/${sub}`, - options: { - method, headers, body: method === 'POST' ? JSON.stringify(data) : undefined, - }, - get: main, - }) - } break + case 'gym-delete': + { + const [main, sub] = category.split('-') + Object.assign(payloadObj, { + url: `${webhook.host}:${webhook.port}/api/tracking/${main}/${discordId}/${sub}`, + options: { + method, + headers, + body: method === 'POST' ? JSON.stringify(data) : undefined, + }, + get: main, + }) + } + break case 'egg': case 'invasion': case 'lure': @@ -94,26 +128,48 @@ module.exports = async function webhookApi(category, discordId, method, webhookN case 'raid': case 'gym': Object.assign(payloadObj, { - url: `${webhook.host}:${webhook.port}/api/tracking/${category}/${discordId}${method === 'DELETE' ? `/byUid/${data.uid}` : ''}`, + url: `${webhook.host}:${ + webhook.port + }/api/tracking/${category}/${discordId}${ + method === 'DELETE' ? `/byUid/${data.uid}` : '' + }`, options: { - method, headers, body: method === 'POST' ? JSON.stringify(data) : undefined, + method, + headers, + body: method === 'POST' ? JSON.stringify(data) : undefined, }, get: method === 'DELETE' ? undefined : category, - }); break - case 'quickGym': return resolveQuickHook(category, discordId, webhookName, data) + }) + break + case 'quickGym': + return resolveQuickHook(category, discordId, webhookName, data) default: Object.assign(payloadObj, { - url: `${webhook.host}:${webhook.port}/api/tracking/${category}/${discordId}${method === 'DELETE' ? `/byUid/${data.uid}` : ''}`, + url: `${webhook.host}:${ + webhook.port + }/api/tracking/${category}/${discordId}${ + method === 'DELETE' ? `/byUid/${data.uid}` : '' + }`, options: { - method, headers, body: data ? JSON.stringify(data) : null, + method, + headers, + body: data ? JSON.stringify(data) : null, }, - }); break + }) + break } if (payloadObj.options.body) { - Object.assign(payloadObj.options.headers, { Accept: 'application/json', 'Content-Type': 'application/json' }) + Object.assign(payloadObj.options.headers, { + Accept: 'application/json', + 'Content-Type': 'application/json', + }) } - const post = await fetchJson(payloadObj.url, payloadObj.options, config.devOptions.enabled) + const post = await fetchJson( + payloadObj.url, + payloadObj.options, + config.devOptions.enabled, + ) if (!post) { throw new Error('No data returned from server') @@ -128,13 +184,20 @@ module.exports = async function webhookApi(category, discordId, method, webhookN default: return `${webhook.host}:${webhook.port}/api/tracking/${payloadObj.get}/${discordId}` } - }()) - const get = await fetchJson(getUrl, { method: 'GET', headers }, config.devOptions.enabled) + })() + const get = await fetchJson( + getUrl, + { method: 'GET', headers }, + config.devOptions.enabled, + ) return { ...post, ...get } } return post } catch (e) { - console.log(e.message, 'There was a problem processing that webhook request') + console.log( + e.message, + 'There was a problem processing that webhook request', + ) return { status: 'error', message: 'webhook_error' } } } diff --git a/server/src/services/areas.js b/server/src/services/areas.js index 901bd47d4..b988c9a3b 100644 --- a/server/src/services/areas.js +++ b/server/src/services/areas.js @@ -4,15 +4,19 @@ const config = require('./config') const loadAreas = () => { try { const normalized = { type: 'FeatureCollection', features: [] } - Object.values(config.scanAreas).forEach(area => { + Object.values(config.scanAreas).forEach((area) => { if (area?.features.length) { normalized.features.push(...area.features) } }) return normalized } catch (err) { - if (config.authentication.areaRestrictions.some(rule => rule.roles.length)) { - console.warn('[Area Restrictions] Disabled - `areas.json` file is missing or broken.') + if ( + config.authentication.areaRestrictions.some((rule) => rule.roles.length) + ) { + console.warn( + '[Area Restrictions] Disabled - `areas.json` file is missing or broken.', + ) } } } @@ -24,11 +28,11 @@ const parseAreas = (areasObj) => { if (!areasObj) { return { names, polygons } } - areasObj.features.forEach(feature => { + areasObj.features.forEach((feature) => { const { name } = feature.properties if (feature.geometry.type == 'Polygon' && name) { polygons[name] = [] - feature.geometry.coordinates.forEach(coordPair => { + feature.geometry.coordinates.forEach((coordPair) => { polygons[name].push(...coordPair) }) names.push(name) diff --git a/server/src/services/checkForUpdates.js b/server/src/services/checkForUpdates.js index 081ec7e25..448190c57 100644 --- a/server/src/services/checkForUpdates.js +++ b/server/src/services/checkForUpdates.js @@ -8,7 +8,10 @@ let isDocker = false try { exec('git branch --show-current', (err, stdout) => { try { - const gitRef = fs.readFileSync(path.resolve(`${__dirname}/../../../.gitref`), 'utf8') + const gitRef = fs.readFileSync( + path.resolve(`${__dirname}/../../../.gitref`), + 'utf8', + ) if (!gitRef && (err || typeof stdout !== 'string' || !stdout.trim())) { throw new Error(err) @@ -16,41 +19,79 @@ try { if (typeof gitRef === 'string' && gitRef.trim()) { isDocker = true } - const branch = typeof gitRef === 'string' && gitRef.trim() - ? gitRef.split('/')[2].trim() - : stdout.trim() + const branch = + typeof gitRef === 'string' && gitRef.trim() + ? gitRef.split('/')[2].trim() + : stdout.trim() exec('git rev-parse HEAD', (err2, stdout2) => { try { - const gitSha = fs.readFileSync(path.resolve(`${__dirname}/../../../.gitsha`), 'utf8') + const gitSha = fs.readFileSync( + path.resolve(`${__dirname}/../../../.gitsha`), + 'utf8', + ) - if (!gitSha && (err2 || typeof stdout2 !== 'string' || !stdout2.trim())) { + if ( + !gitSha && + (err2 || typeof stdout2 !== 'string' || !stdout2.trim()) + ) { throw new Error(err2) } - const sha = typeof gitSha === 'string' && gitSha.trim() - ? gitSha.trim() - : stdout2.trim() + const sha = + typeof gitSha === 'string' && gitSha.trim() + ? gitSha.trim() + : stdout2.trim() - exec(`git ls-remote https://github.com/WatWowMap/ReactMap/ refs/heads/${branch}`, (err3, stdout3) => { - try { - if (err3 || typeof stdout3 !== 'string' || !stdout3?.split('\t')?.[0]) { - throw new Error(err3) - } - const remoteSha = stdout3.split('\t')[0] + exec( + `git ls-remote https://github.com/WatWowMap/ReactMap/ refs/heads/${branch}`, + (err3, stdout3) => { + try { + if ( + err3 || + typeof stdout3 !== 'string' || + !stdout3?.split('\t')?.[0] + ) { + throw new Error(err3) + } + const remoteSha = stdout3.split('\t')[0] - if (remoteSha !== sha) { - console.log('[UPDATE] There is a new version available: ', remoteSha, isDocker ? 'docker-compose pull' : 'git pull', ' to update') + if (remoteSha !== sha) { + console.log( + '[UPDATE] There is a new version available: ', + remoteSha, + isDocker ? 'docker-compose pull' : 'git pull', + ' to update', + ) + } + } catch (e) { + console.log( + '[UPDATE] Unable to get remote SHA:', + e.message, + '\nBranch:', + branch, + 'Local SHA:', + sha, + '\nProceeding normally...', + ) } - } catch (e) { - console.log('[UPDATE] Unable to get remote SHA:', e.message, '\nBranch:', branch, 'Local SHA:', sha, '\nProceeding normally...') - } - }) + }, + ) } catch (e) { - console.log('[UPDATE] Unable to get current SHA:', e.message, '\nBranch:', branch, '\nProceeding normally...') + console.log( + '[UPDATE] Unable to get current SHA:', + e.message, + '\nBranch:', + branch, + '\nProceeding normally...', + ) } }) } catch (e) { - console.log('[UPDATE] Unable to determine the local git branch:', e.message, '\nProceeding normally...') + console.log( + '[UPDATE] Unable to determine the local git branch:', + e.message, + '\nProceeding normally...', + ) } }) } catch (e) { diff --git a/server/src/services/config.js b/server/src/services/config.js index 2808cf486..bd88fb8d3 100644 --- a/server/src/services/config.js +++ b/server/src/services/config.js @@ -14,12 +14,27 @@ const config = require('config') if (!fs.existsSync(path.resolve(`${__dirname}/../configs/local.json`))) { // add database env variables from .env or docker-compose const { - SCANNER_DB_HOST, SCANNER_DB_PORT, SCANNER_DB_NAME, SCANNER_DB_USERNAME, SCANNER_DB_PASSWORD, - MANUAL_DB_HOST, MANUAL_DB_PORT, MANUAL_DB_NAME, MANUAL_DB_USERNAME, MANUAL_DB_PASSWORD, - MAP_GENERAL_START_LAT, MAP_GENERAL_START_LON, + SCANNER_DB_HOST, + SCANNER_DB_PORT, + SCANNER_DB_NAME, + SCANNER_DB_USERNAME, + SCANNER_DB_PASSWORD, + MANUAL_DB_HOST, + MANUAL_DB_PORT, + MANUAL_DB_NAME, + MANUAL_DB_USERNAME, + MANUAL_DB_PASSWORD, + MAP_GENERAL_START_LAT, + MAP_GENERAL_START_LON, } = process.env - if (SCANNER_DB_HOST && SCANNER_DB_PORT && SCANNER_DB_NAME && SCANNER_DB_USERNAME && SCANNER_DB_PASSWORD) { + if ( + SCANNER_DB_HOST && + SCANNER_DB_PORT && + SCANNER_DB_NAME && + SCANNER_DB_USERNAME && + SCANNER_DB_PASSWORD + ) { config.database.schemas.push({ host: SCANNER_DB_HOST, port: +SCANNER_DB_PORT, @@ -37,47 +52,65 @@ if (!fs.existsSync(path.resolve(`${__dirname}/../configs/local.json`))) { ], }) } else { - throw new Error('Missing scanner database config! \nCheck to make sure you have SCANNER_DB_HOST,SCANNER_DB_PORT, SCANNER_DB_NAME, SCANNER_DB_USERNAME, and SCANNER_DB_PASSWORD') + throw new Error( + 'Missing scanner database config! \nCheck to make sure you have SCANNER_DB_HOST,SCANNER_DB_PORT, SCANNER_DB_NAME, SCANNER_DB_USERNAME, and SCANNER_DB_PASSWORD', + ) } - if (MANUAL_DB_HOST && MANUAL_DB_PORT && MANUAL_DB_NAME && MANUAL_DB_USERNAME && MANUAL_DB_PASSWORD) { + if ( + MANUAL_DB_HOST && + MANUAL_DB_PORT && + MANUAL_DB_NAME && + MANUAL_DB_USERNAME && + MANUAL_DB_PASSWORD + ) { config.database.schemas.push({ host: MANUAL_DB_HOST, port: +MANUAL_DB_PORT, database: MANUAL_DB_NAME, username: MANUAL_DB_USERNAME, password: MANUAL_DB_PASSWORD, - useFor: [ - 'session', - 'user', - 'nest', - 'portal', - ], + useFor: ['session', 'user', 'nest', 'portal'], }) } else { - throw new Error('Missing manual database config! \nCheck to make sure you have MANUAL_DB_HOST,MANUAL_DB_PORT, MANUAL_DB_NAME, MANUAL_DB_USERNAME, and MANUAL_DB_PASSWORD') + throw new Error( + 'Missing manual database config! \nCheck to make sure you have MANUAL_DB_HOST,MANUAL_DB_PORT, MANUAL_DB_NAME, MANUAL_DB_USERNAME, and MANUAL_DB_PASSWORD', + ) } if (!MAP_GENERAL_START_LAT || !MAP_GENERAL_START_LON) { - console.warn('Missing, MAP_GENERAL_START_LAT OR MAP_GENERAL_START_LON\nYou will be able to proceed but you should add these values to your docker-compose file') + console.warn( + 'Missing, MAP_GENERAL_START_LAT OR MAP_GENERAL_START_LON\nYou will be able to proceed but you should add these values to your docker-compose file', + ) } } if (fs.existsSync(path.resolve(`${__dirname}/../configs/config.json`))) { - console.log('[CONFIG] Config v1 (config.json) found, it is fine to leave it but make sure you are using and updating local.json instead.') + console.log( + '[CONFIG] Config v1 (config.json) found, it is fine to leave it but make sure you are using and updating local.json instead.', + ) } const mergeMapConfig = (obj) => { if (process.env.TELEGRAM_BOT_NAME && !obj?.customRoutes?.telegramBotName) { - if (obj.customRoutes) obj.customRoutes.telegramBotName = process.env.TELEGRAM_BOT_NAME - console.warn('[CONFIG] TELEGRAM_BOT_NAME has been moved from the .env file to your config, telegramBotEnvRef is now deprecated.\nplease use customRoutes.telegramBotName instead\n(Move them from your .env file to your config file)') + if (obj.customRoutes) + obj.customRoutes.telegramBotName = process.env.TELEGRAM_BOT_NAME + console.warn( + '[CONFIG] TELEGRAM_BOT_NAME has been moved from the .env file to your config, telegramBotEnvRef is now deprecated.\nplease use customRoutes.telegramBotName instead\n(Move them from your .env file to your config file)', + ) } if (obj?.customRoutes?.telegramBotEnvRef) { - console.warn('[CONFIG] TELEGRAM_BOT_NAME has been moved from the .env file to your config, telegramBotEnvRef is now deprecated.\nplease use customRoutes.telegramBotName instead\n(Move them from your .env file to your config file)') - obj.customRoutes.telegramBotName = process.env[obj.customRoutes.telegramBotEnvRef] + console.warn( + '[CONFIG] TELEGRAM_BOT_NAME has been moved from the .env file to your config, telegramBotEnvRef is now deprecated.\nplease use customRoutes.telegramBotName instead\n(Move them from your .env file to your config file)', + ) + obj.customRoutes.telegramBotName = + process.env[obj.customRoutes.telegramBotEnvRef] } - ['messageOfTheDay', 'donationPage', 'loginPage'].forEach(category => { + ;['messageOfTheDay', 'donationPage', 'loginPage'].forEach((category) => { if (obj?.[category]?.components) { - obj[category].components.forEach(component => { + obj[category].components.forEach((component) => { if (component.type === 'telegram' && component.telegramBotEnvRef) { - console.warn('[CONFIG] telegramBotEnvRef is deprecated, please use telegramBotName instead\n', category) + console.warn( + '[CONFIG] telegramBotEnvRef is deprecated, please use telegramBotName instead\n', + category, + ) console.warn('OLD:\n', component) component.telegramBotName = process.env[component.telegramBotEnvRef] delete component.telegramBotEnvRef @@ -107,50 +140,79 @@ config.map = mergeMapConfig(config.map) // Create multiDomain Objects config.multiDomainsObj = Object.fromEntries( - config.multiDomains.map(d => [d.domain, mergeMapConfig(d)]), + config.multiDomains.map((d) => [d.domain, mergeMapConfig(d)]), ) // Consolidate Auth Methods // Create Authentication Objects -config.authMethods = [...new Set(config.authentication.strategies - .filter(strategy => strategy.enabled) - .map(strategy => { - config.authentication[strategy.name] = strategy - return strategy.type - })), -]; +config.authMethods = [ + ...new Set( + config.authentication.strategies + .filter((strategy) => strategy.enabled) + .map((strategy) => { + config.authentication[strategy.name] = strategy + return strategy.type + }), + ), +] // Check if empty -['tileServers', 'navigation'].forEach(opt => { - if (!config[opt].length) console.warn(`[${opt}] is empty, you need to add options to it or remove the empty array from your config.`) +;['tileServers', 'navigation'].forEach((opt) => { + if (!config[opt].length) { + console.warn( + `[${opt}] is empty, you need to add options to it or remove the empty array from your config.`, + ) + } }) // Load each areas.json -const loadScanPolygons = (fileName) => fs.existsSync(path.resolve(`${__dirname}/../configs/${fileName}`)) - ? require(`../configs/${fileName}`) - : { features: [] } +const loadScanPolygons = (fileName) => + fs.existsSync(path.resolve(`${__dirname}/../configs/${fileName}`)) + ? require(`../configs/${fileName}`) + : { features: [] } // Check if an areas.json exists config.scanAreas = { main: loadScanPolygons(config.map.geoJsonFileName), ...Object.fromEntries( - config.multiDomains.map(d => [d.general?.geoJsonFileName ? d.domain : 'main', loadScanPolygons(d.general?.geoJsonFileName || config.map.geoJsonFileName)]), + config.multiDomains.map((d) => [ + d.general?.geoJsonFileName ? d.domain : 'main', + loadScanPolygons( + d.general?.geoJsonFileName || config.map.geoJsonFileName, + ), + ]), ), } -config.api.pvp.leagueObj = Object.fromEntries(config.api.pvp.leagues.map(league => [league.name, league.cp])) -const hasLittle = config.api.pvp.leagues.find(league => league.name === 'little') +config.api.pvp.leagueObj = Object.fromEntries( + config.api.pvp.leagues.map((league) => [league.name, league.cp]), +) +const hasLittle = config.api.pvp.leagues.find( + (league) => league.name === 'little', +) if (hasLittle) { - config.api.pvp.leagueObj.little = hasLittle.littleCupRules ? 500 : { little: false, cap: 500 } + config.api.pvp.leagueObj.little = hasLittle.littleCupRules + ? 500 + : { little: false, cap: 500 } } -if (!config.authentication.strategies.length || !config.authentication.strategies.find(strategy => strategy.enabled)) { - const enabled = Object.keys(config.authentication.perms).filter(perm => config.authentication.perms[perm].enabled) - console.warn('[CONFIG] No authentication strategies enabled, adding the following perms to alwaysEnabledPerms array:\n', enabled) +if ( + !config.authentication.strategies.length || + !config.authentication.strategies.find((strategy) => strategy.enabled) +) { + const enabled = Object.keys(config.authentication.perms).filter( + (perm) => config.authentication.perms[perm].enabled, + ) + console.warn( + '[CONFIG] No authentication strategies enabled, adding the following perms to alwaysEnabledPerms array:\n', + enabled, + ) config.authentication.alwaysEnabledPerms = enabled } // Map manual areas -config.manualAreas = Object.fromEntries(config.manualAreas.map(area => [area.name, area])) +config.manualAreas = Object.fromEntries( + config.manualAreas.map((area) => [area.name, area]), +) module.exports = config diff --git a/server/src/services/defaultFilters/buildDefaultFilters.js b/server/src/services/defaultFilters/buildDefaultFilters.js index 03d4d256d..b8684c20c 100644 --- a/server/src/services/defaultFilters/buildDefaultFilters.js +++ b/server/src/services/defaultFilters/buildDefaultFilters.js @@ -8,102 +8,138 @@ const buildGyms = require('./buildGyms') const { GenericFilter, PokemonFilter } = require('../../models/index') const base = new PokemonFilter(defaultFilters.pokemon.allPokemon) -const custom = new PokemonFilter(defaultFilters.pokemon.allPokemon, 'md', ...Object.values(defaultFilters.pokemon.globalValues)) +const custom = new PokemonFilter( + defaultFilters.pokemon.allPokemon, + 'md', + ...Object.values(defaultFilters.pokemon.globalValues), +) module.exports = function buildDefault(perms, available) { - const stopReducer = perms.pokestops || perms.lures || perms.quests || perms.invasions + const stopReducer = + perms.pokestops || perms.lures || perms.quests || perms.invasions const gymReducer = perms.gyms || perms.raids const pokemonReducer = perms.iv || perms.pvp const pokemon = buildPokemon(defaultFilters, base, custom, available) return { - gyms: gymReducer ? { - enabled: defaultFilters.gyms.enabled, - allGyms: perms.gyms ? defaultFilters.gyms.enabled : undefined, - raids: perms.raids ? defaultFilters.gyms.raids : undefined, - exEligible: perms.gyms ? defaultFilters.gyms.exEligible : undefined, - inBattle: perms.gyms ? defaultFilters.gyms.exEligible : undefined, - arEligible: perms.gyms ? false : undefined, - gymBadges: perms.gymBadges ? defaultFilters.gyms.gymBadges : undefined, - badge: perms.gymBadges ? 'all' : undefined, - raidTier: perms.raids ? 'all' : undefined, - filter: { - ...buildGyms(perms, defaultFilters.gyms, available), - ...pokemon.raids, - }, - } : undefined, - nests: perms.nests ? { - enabled: defaultFilters.nests.enabled, - pokemon: defaultFilters.nests.pokemon, - polygons: defaultFilters.nests.polygons, - avgFilter: defaultFilters.nests.avgFilter, - filter: pokemon.nests, - } : undefined, - pokestops: stopReducer ? { - enabled: defaultFilters.pokestops.enabled, - allPokestops: perms.pokestops ? defaultFilters.pokestops.enabled : undefined, - lures: perms.lures ? defaultFilters.pokestops.lures : undefined, - quests: perms.quests ? defaultFilters.pokestops.quests : undefined, - showQuestSet: defaultFilters.pokestops.questSet, - invasions: perms.invasions ? defaultFilters.pokestops.invasions : undefined, - arEligible: perms.pokestops ? false : undefined, - filter: { - ...buildPokestops(perms, defaultFilters.pokestops, available), - ...pokemon.quests, - }, - } : undefined, - pokemon: perms.pokemon ? { - enabled: defaultFilters.pokemon.enabled, - legacy: (pokemonReducer && enableMapJsFilter) ? defaultFilters.pokemon.legacyFilter : undefined, - iv: perms.iv ? true : undefined, - pvp: perms.pvp ? true : undefined, - standard: base, - ivOr: custom, - xsRat: false, - xlKarp: false, - zeroIv: perms.iv ? false : undefined, - hundoIv: perms.iv ? true : undefined, - filter: pokemon.full, - } : undefined, - portals: perms.portals ? { - enabled: defaultFilters.portals.enabled, - filter: { - global: new GenericFilter(), - old: new GenericFilter(), - new: new GenericFilter(), - }, - } : undefined, - scanAreas: perms.scanAreas ? { - enabled: defaultFilters.scanAreas.enabled, - filter: {}, - } : undefined, - submissionCells: perms.submissionCells ? { - enabled: defaultFilters.submissionCells.enabled, - filter: { global: new GenericFilter() }, - } : undefined, - weather: perms.weather ? { - enabled: defaultFilters.weather.enabled, - filter: { global: new GenericFilter() }, - } : undefined, - spawnpoints: perms.spawnpoints ? { - enabled: defaultFilters.spawnpoints.enabled, - filter: { - global: new GenericFilter(), - confirmed: new GenericFilter(), - unconfirmed: new GenericFilter(), - }, - } : undefined, - scanCells: perms.scanCells ? { - enabled: defaultFilters.scanCells.enabled, - filter: { global: new GenericFilter() }, - } : undefined, - devices: perms.devices ? { - enabled: defaultFilters.devices.enabled, - filter: { - online: new GenericFilter(), - offline: new GenericFilter(), - global: new GenericFilter(), - }, - } : undefined, + gyms: gymReducer + ? { + enabled: defaultFilters.gyms.enabled, + allGyms: perms.gyms ? defaultFilters.gyms.enabled : undefined, + raids: perms.raids ? defaultFilters.gyms.raids : undefined, + exEligible: perms.gyms ? defaultFilters.gyms.exEligible : undefined, + inBattle: perms.gyms ? defaultFilters.gyms.exEligible : undefined, + arEligible: perms.gyms ? false : undefined, + gymBadges: perms.gymBadges + ? defaultFilters.gyms.gymBadges + : undefined, + badge: perms.gymBadges ? 'all' : undefined, + raidTier: perms.raids ? 'all' : undefined, + filter: { + ...buildGyms(perms, defaultFilters.gyms, available), + ...pokemon.raids, + }, + } + : undefined, + nests: perms.nests + ? { + enabled: defaultFilters.nests.enabled, + pokemon: defaultFilters.nests.pokemon, + polygons: defaultFilters.nests.polygons, + avgFilter: defaultFilters.nests.avgFilter, + filter: pokemon.nests, + } + : undefined, + pokestops: stopReducer + ? { + enabled: defaultFilters.pokestops.enabled, + allPokestops: perms.pokestops + ? defaultFilters.pokestops.enabled + : undefined, + lures: perms.lures ? defaultFilters.pokestops.lures : undefined, + quests: perms.quests ? defaultFilters.pokestops.quests : undefined, + showQuestSet: defaultFilters.pokestops.questSet, + invasions: perms.invasions + ? defaultFilters.pokestops.invasions + : undefined, + arEligible: perms.pokestops ? false : undefined, + filter: { + ...buildPokestops(perms, defaultFilters.pokestops, available), + ...pokemon.quests, + }, + } + : undefined, + pokemon: perms.pokemon + ? { + enabled: defaultFilters.pokemon.enabled, + legacy: + pokemonReducer && enableMapJsFilter + ? defaultFilters.pokemon.legacyFilter + : undefined, + iv: perms.iv ? true : undefined, + pvp: perms.pvp ? true : undefined, + standard: base, + ivOr: custom, + xsRat: false, + xlKarp: false, + zeroIv: perms.iv ? false : undefined, + hundoIv: perms.iv ? true : undefined, + filter: pokemon.full, + } + : undefined, + portals: perms.portals + ? { + enabled: defaultFilters.portals.enabled, + filter: { + global: new GenericFilter(), + old: new GenericFilter(), + new: new GenericFilter(), + }, + } + : undefined, + scanAreas: perms.scanAreas + ? { + enabled: defaultFilters.scanAreas.enabled, + filter: {}, + } + : undefined, + submissionCells: perms.submissionCells + ? { + enabled: defaultFilters.submissionCells.enabled, + filter: { global: new GenericFilter() }, + } + : undefined, + weather: perms.weather + ? { + enabled: defaultFilters.weather.enabled, + filter: { global: new GenericFilter() }, + } + : undefined, + spawnpoints: perms.spawnpoints + ? { + enabled: defaultFilters.spawnpoints.enabled, + filter: { + global: new GenericFilter(), + confirmed: new GenericFilter(), + unconfirmed: new GenericFilter(), + }, + } + : undefined, + scanCells: perms.scanCells + ? { + enabled: defaultFilters.scanCells.enabled, + filter: { global: new GenericFilter() }, + } + : undefined, + devices: perms.devices + ? { + enabled: defaultFilters.devices.enabled, + filter: { + online: new GenericFilter(), + offline: new GenericFilter(), + global: new GenericFilter(), + }, + } + : undefined, } } diff --git a/server/src/services/defaultFilters/buildGyms.js b/server/src/services/defaultFilters/buildGyms.js index abf8b9455..a4535acd5 100644 --- a/server/src/services/defaultFilters/buildGyms.js +++ b/server/src/services/defaultFilters/buildGyms.js @@ -7,19 +7,19 @@ module.exports = function buildGyms(perms, defaults, available) { defaults.baseTeamIds.forEach((team, i) => { gymFilters[`t${team}-0`] = new GenericFilter(defaults.allGyms) if (i) { - defaults.baseGymSlotAmounts.forEach(slot => { + defaults.baseGymSlotAmounts.forEach((slot) => { gymFilters[`g${team}-${slot}`] = new GenericFilter(defaults.allGyms) }) } }) } if (perms.raids) { - defaults.baseRaidTiers.forEach(tier => { + defaults.baseRaidTiers.forEach((tier) => { gymFilters[`e${tier}`] = new GenericFilter(defaults.eggs) gymFilters[`r${tier}`] = new GenericFilter(defaults.raids) }) } - available.gyms.forEach(avail => { + available.gyms.forEach((avail) => { if (perms.gyms && (avail.startsWith('t') || avail.startsWith('g'))) { gymFilters[avail] = new GenericFilter(defaults.allGyms) } diff --git a/server/src/services/defaultFilters/buildPokemon.js b/server/src/services/defaultFilters/buildPokemon.js index 98fea8c80..2650bf6a3 100644 --- a/server/src/services/defaultFilters/buildPokemon.js +++ b/server/src/services/defaultFilters/buildPokemon.js @@ -9,24 +9,35 @@ module.exports = function buildPokemon(defaults, base, custom, available) { quests: { global: new GenericFilter() }, nests: { global: new GenericFilter() }, } - const energyAmounts = new Set([...defaults.pokestops.baseMegaEnergyAmounts, ...available.pokestops - .filter((e) => e.startsWith('m')) - .map((e) => e.split('-')[1])]) + const energyAmounts = new Set([ + ...defaults.pokestops.baseMegaEnergyAmounts, + ...available.pokestops + .filter((e) => e.startsWith('m')) + .map((e) => e.split('-')[1]), + ]) for (const [i, pkmn] of Object.entries(Event.masterfile.pokemon)) { for (const j of Object.keys(pkmn.forms)) { pokemon.full[`${i}-${j}`] = base pokemon.raids[`${i}-${j}`] = new GenericFilter(defaults.gyms.pokemon) - pokemon.quests[`${i}-${j}`] = new GenericFilter(defaults.pokestops.pokemon) + pokemon.quests[`${i}-${j}`] = new GenericFilter( + defaults.pokestops.pokemon, + ) pokemon.nests[`${i}-${j}`] = new GenericFilter(defaults.nests.allPokemon) } if (pkmn.family == i) { - pokemon.quests[`c${pkmn.family}`] = new GenericFilter(defaults.pokestops.candy) - pokemon.quests[`x${pkmn.family}`] = new GenericFilter(defaults.pokestops.candy) + pokemon.quests[`c${pkmn.family}`] = new GenericFilter( + defaults.pokestops.candy, + ) + pokemon.quests[`x${pkmn.family}`] = new GenericFilter( + defaults.pokestops.candy, + ) } if (pkmn.tempEvolutions) { energyAmounts.forEach((a) => { - pokemon.quests[`m${i}-${a}`] = new GenericFilter(defaults.pokestops.megaEnergy) + pokemon.quests[`m${i}-${a}`] = new GenericFilter( + defaults.pokestops.megaEnergy, + ) }) } } diff --git a/server/src/services/defaultFilters/buildPokestops.js b/server/src/services/defaultFilters/buildPokestops.js index a22fdc8f4..d5731bf37 100644 --- a/server/src/services/defaultFilters/buildPokestops.js +++ b/server/src/services/defaultFilters/buildPokestops.js @@ -4,31 +4,35 @@ const { Event } = require('../initialization') module.exports = function buildPokestops(perms, defaults, available) { const quests = { s0: new GenericFilter() } if (perms.lures) { - defaults.baseLureIds.forEach(lure => { + defaults.baseLureIds.forEach((lure) => { quests[`l${lure}`] = new GenericFilter(defaults.lures) }) } if (perms.quests) { - Object.keys(Event.masterfile.items).forEach(item => { + Object.keys(Event.masterfile.items).forEach((item) => { quests[`q${item}`] = new GenericFilter(defaults.items) }) - for (let i = defaults.stardust.min; i <= defaults.stardust.max; i += defaults.stardust.interval) { + for ( + let i = defaults.stardust.min; + i <= defaults.stardust.max; + i += defaults.stardust.interval + ) { quests[`d${i}`] = new GenericFilter(defaults.stardust.enabled) } - Object.keys(Event.masterfile.questRewardTypes).forEach(type => { + Object.keys(Event.masterfile.questRewardTypes).forEach((type) => { if (type !== '0') { quests[`u${type}`] = new GenericFilter(defaults.rewardTypes) } }) } if (perms.invasions) { - Object.keys(Event.invasions).forEach(type => { + Object.keys(Event.invasions).forEach((type) => { if (type !== '0') { quests[`i${type}`] = new GenericFilter(defaults.allInvasions) } }) } - available.pokestops.forEach(avail => { + available.pokestops.forEach((avail) => { if (perms.lures && avail.startsWith('l')) { quests[avail] = new GenericFilter(defaults.lures) } diff --git a/server/src/services/events/guildMemberUpdate.js b/server/src/services/events/guildMemberUpdate.js index 5d393691b..fc9c2e633 100644 --- a/server/src/services/events/guildMemberUpdate.js +++ b/server/src/services/events/guildMemberUpdate.js @@ -5,26 +5,33 @@ const { User } = require('../../models/index') module.exports = async (client, oldPresence, newPresence) => { const rolesBefore = oldPresence.roles.cache - .filter(x => BigInt(x.id).toString()) + .filter((x) => BigInt(x.id).toString()) .keyArray() const rolesAfter = newPresence.roles.cache - .filter(x => BigInt(x.id).toString()) + .filter((x) => BigInt(x.id).toString()) .keyArray() - const perms = [...new Set( - Object.values(client.config.perms) - .map(x => x.roles) - .flat(), - )] + const perms = [ + ...new Set( + Object.values(client.config.perms) + .map((x) => x.roles) + .flat(), + ), + ] const roleDiff = rolesBefore - .filter(x => !rolesAfter.includes(x)) - .concat(rolesAfter - .filter(x => !rolesBefore.includes(x))) + .filter((x) => !rolesAfter.includes(x)) + .concat(rolesAfter.filter((x) => !rolesBefore.includes(x))) try { if (perms.includes(roleDiff[0])) { await clearDiscordSessions(oldPresence.user.id, client.user.username) - await User.clearPerms(oldPresence.user.id, 'discord', client.user.username) + await User.clearPerms( + oldPresence.user.id, + 'discord', + client.user.username, + ) } } catch (e) { - console.error(`Could not clear sessions for ${oldPresence.user.username}#${oldPresence.user.discriminator}`) + console.error( + `Could not clear sessions for ${oldPresence.user.username}#${oldPresence.user.discriminator}`, + ) } } diff --git a/server/src/services/functions/areaPerms.js b/server/src/services/functions/areaPerms.js index 3dd2cfad3..fd93d6cce 100644 --- a/server/src/services/functions/areaPerms.js +++ b/server/src/services/functions/areaPerms.js @@ -4,11 +4,11 @@ const config = require('../config') module.exports = function areaPerms(roles) { let perms = [] if (areas.names.length) { - roles.forEach(group => { - config.authentication.areaRestrictions.forEach(rule => { + roles.forEach((group) => { + config.authentication.areaRestrictions.forEach((rule) => { if (rule.roles.includes(group)) { if (rule.areas.length) { - rule.areas.forEach(areaName => { + rule.areas.forEach((areaName) => { if (areas.names.includes(areaName)) { perms.push(areaName) } diff --git a/server/src/services/functions/dbSelection.js b/server/src/services/functions/dbSelection.js index bd9106f6a..3d8e8d4f3 100644 --- a/server/src/services/functions/dbSelection.js +++ b/server/src/services/functions/dbSelection.js @@ -1,7 +1,10 @@ -const { database: { schemas } } = require('../config') +const { + database: { schemas }, +} = require('../config') module.exports = function dbSelection(category) { - if (category === 'quest' || category === 'invasion' || category === 'lure') category = 'pokestop' + if (category === 'quest' || category === 'invasion' || category === 'lure') + category = 'pokestop' if (category === 'raid') category = 'gym' return schemas.find(({ useFor }) => useFor.includes(category)) } diff --git a/server/src/services/functions/evalWebhookId.js b/server/src/services/functions/evalWebhookId.js index 620ab6359..ab3540afe 100644 --- a/server/src/services/functions/evalWebhookId.js +++ b/server/src/services/functions/evalWebhookId.js @@ -4,8 +4,11 @@ module.exports = function evalWebhookId(user) { } const { strategy, webhookStrategy, discordId, telegramId } = user switch (strategy) { - case 'discord': return discordId - case 'telegram': return telegramId - default: return webhookStrategy === 'discord' ? discordId : telegramId + case 'discord': + return discordId + case 'telegram': + return telegramId + default: + return webhookStrategy === 'discord' ? discordId : telegramId } } diff --git a/server/src/services/functions/getAreaSql.js b/server/src/services/functions/getAreaSql.js index da20db5a3..35b36d89c 100644 --- a/server/src/services/functions/getAreaSql.js +++ b/server/src/services/functions/getAreaSql.js @@ -1,6 +1,11 @@ const areas = require('../areas') -module.exports = function getAreaRestrictionSql(query, areaRestrictions, isMad, category) { +module.exports = function getAreaRestrictionSql( + query, + areaRestrictions, + isMad, + category, +) { let columns = ['lat', 'lon'] if (isMad) { if (category === 'device') { @@ -9,19 +14,21 @@ module.exports = function getAreaRestrictionSql(query, areaRestrictions, isMad, columns = ['latitude', 'longitude'] } if (category === 'pokemon') { - columns = columns.map(each => `pokemon.${each}`) + columns = columns.map((each) => `pokemon.${each}`) } } else if (category === 'device') { - columns = columns.map(each => `last_${each}`) + columns = columns.map((each) => `last_${each}`) } if (category === 's2cell') { - columns = columns.map(each => `center_${each}`) + columns = columns.map((each) => `center_${each}`) } - query.andWhere(restrictions => { - areaRestrictions.forEach(area => { - const polygon = areas.polygons[area].map(e => e.join(' ')).join() - restrictions.orWhereRaw(`ST_CONTAINS(ST_GeomFromText("POLYGON((${polygon}))"), POINT(${columns[1]}, ${columns[0]}))`) + query.andWhere((restrictions) => { + areaRestrictions.forEach((area) => { + const polygon = areas.polygons[area].map((e) => e.join(' ')).join() + restrictions.orWhereRaw( + `ST_CONTAINS(ST_GeomFromText("POLYGON((${polygon}))"), POINT(${columns[1]}, ${columns[0]}))`, + ) }) }) } diff --git a/server/src/services/functions/getPlacementCells.js b/server/src/services/functions/getPlacementCells.js index d5744f7bc..4030dc29f 100644 --- a/server/src/services/functions/getPlacementCells.js +++ b/server/src/services/functions/getPlacementCells.js @@ -1,14 +1,19 @@ /* global BigInt */ const { - S2LatLng, S2RegionCoverer, S2CellId, S2LatLngRect, + S2LatLng, + S2RegionCoverer, + S2CellId, + S2LatLngRect, } = require('nodes2ts') const getPolyVector = require('./getPolyVector') const { Ring } = require('../../models/index') module.exports = function getPlacementCells(bounds, pokestops, gyms) { // dedupe poi entries - const allCoords = Object.values(Object.fromEntries([...pokestops, ...gyms].map(poi => [poi.id, poi]))) + const allCoords = Object.values( + Object.fromEntries([...pokestops, ...gyms].map((poi) => [poi.id, poi])), + ) const regionCoverer = new S2RegionCoverer() regionCoverer.minLevel = 17 @@ -32,14 +37,16 @@ module.exports = function getPlacementCells(bounds, pokestops, gyms) { } for (let i = 0; i < allCoords.length; i += 1) { const coords = allCoords[i] - const level17Cell = S2CellId.fromPoint(S2LatLng.fromDegrees(coords.lat, coords.lon).toPoint()).parentL(17) + const level17Cell = S2CellId.fromPoint( + S2LatLng.fromDegrees(coords.lat, coords.lon).toPoint(), + ).parentL(17) const cellId = BigInt(level17Cell.id).toString() const cell = indexedCells[cellId] if (cell) { cell.blocked = true } } - const rings = allCoords.map(poi => new Ring(poi.id, poi.lat, poi.lon)) + const rings = allCoords.map((poi) => new Ring(poi.id, poi.lat, poi.lon)) return { cells: Object.values(indexedCells), diff --git a/server/src/services/functions/getPolyVector.js b/server/src/services/functions/getPolyVector.js index f11352151..195a01077 100644 --- a/server/src/services/functions/getPolyVector.js +++ b/server/src/services/functions/getPolyVector.js @@ -1,7 +1,5 @@ /* global BigInt */ -const { - S2LatLng, S2Cell, S2CellId, S2Point, -} = require('nodes2ts') +const { S2LatLng, S2Cell, S2CellId, S2Point } = require('nodes2ts') module.exports = function getPolyVector(s2cellId, polyline) { const s2cell = new S2Cell(new S2CellId(BigInt(s2cellId).toString())) @@ -10,10 +8,7 @@ module.exports = function getPolyVector(s2cellId, polyline) { const coordinate = s2cell.getVertex(i) const point = new S2Point(coordinate.x, coordinate.y, coordinate.z) const latLng = S2LatLng.fromPoint(point) - polygon.push([ - latLng.latDegrees, - latLng.lngDegrees, - ]) + polygon.push([latLng.latDegrees, latLng.lngDegrees]) } if (polyline) { polygon.push(polygon[0]) diff --git a/server/src/services/functions/getTypeCells.js b/server/src/services/functions/getTypeCells.js index e4ddcbdfc..9fd34c32b 100644 --- a/server/src/services/functions/getTypeCells.js +++ b/server/src/services/functions/getTypeCells.js @@ -1,6 +1,9 @@ /* global BigInt */ const { - S2LatLng, S2RegionCoverer, S2CellId, S2LatLngRect, + S2LatLng, + S2RegionCoverer, + S2CellId, + S2LatLngRect, } = require('nodes2ts') const getPolyVector = require('./getPolyVector') @@ -29,7 +32,9 @@ module.exports = function getTypeCells(bounds, pokestops, gyms) { } for (let i = 0; i < gyms.length; i += 1) { const coords = gyms[i] - const level14Cell = S2CellId.fromPoint(S2LatLng.fromDegrees(coords.lat, coords.lon).toPoint()).parentL(14) + const level14Cell = S2CellId.fromPoint( + S2LatLng.fromDegrees(coords.lat, coords.lon).toPoint(), + ).parentL(14) const cellId = BigInt(level14Cell.id).toString() const cell = indexedCells[cellId] if (cell) { @@ -39,7 +44,9 @@ module.exports = function getTypeCells(bounds, pokestops, gyms) { } for (let i = 0; i < pokestops.length; i += 1) { const coords = pokestops[i] - const level14Cell = S2CellId.fromPoint(S2LatLng.fromDegrees(coords.lat, coords.lon).toPoint()).parentL(14) + const level14Cell = S2CellId.fromPoint( + S2LatLng.fromDegrees(coords.lat, coords.lon).toPoint(), + ).parentL(14) const cellId = BigInt(level14Cell.id).toString() const cell = indexedCells[cellId] if (cell) { diff --git a/server/src/services/functions/mergePerms.js b/server/src/services/functions/mergePerms.js index 516709436..ced53a368 100644 --- a/server/src/services/functions/mergePerms.js +++ b/server/src/services/functions/mergePerms.js @@ -1,7 +1,10 @@ module.exports = function mergePerms(existingPerms, incomingPerms) { return Object.fromEntries( - Object.keys(existingPerms).map(key => [key, Array.isArray(existingPerms[key]) - ? [...new Set([...existingPerms[key], ...incomingPerms[key]])] - : existingPerms[key] || incomingPerms[key]]), + Object.keys(existingPerms).map((key) => [ + key, + Array.isArray(existingPerms[key]) + ? [...new Set([...existingPerms[key], ...incomingPerms[key]])] + : existingPerms[key] || incomingPerms[key], + ]), ) } diff --git a/server/src/services/functions/permissions.js b/server/src/services/functions/permissions.js index d93cdfcdf..78e876b8e 100644 --- a/server/src/services/functions/permissions.js +++ b/server/src/services/functions/permissions.js @@ -3,42 +3,57 @@ module.exports = function permissionManager(permToCheck, perms) { permToCheck = permToCheck.replace('quick', '').toLowerCase() } switch (permToCheck) { - case 'map': return perms.map + case 'map': + return perms.map case 'team': case 'teams': case 'gym': - case 'gyms': return perms.gyms + case 'gyms': + return perms.gyms case 'egg': case 'eggs': case 'raid': - case 'raids': return perms.raids + case 'raids': + return perms.raids case 'monster': case 'monsters': case 'pokemon': - case 'pokemons': return perms.pokemon + case 'pokemons': + return perms.pokemon case 'iv': - case 'ivs': return perms.iv + case 'ivs': + return perms.iv case 'pvp': - case 'pvps': return perms.pvp + case 'pvps': + return perms.pvp case 'nest': - case 'nests': return perms.nests + case 'nests': + return perms.nests case 'pokestop': - case 'pokestops': return perms.pokestops + case 'pokestops': + return perms.pokestops case 'quest': - case 'quests': return perms.quests + case 'quests': + return perms.quests case 'lure': - case 'lures': return perms.lures + case 'lures': + return perms.lures case 'invasion': - case 'invasions': return perms.invasions + case 'invasions': + return perms.invasions case 'scanArea': - case 'scanAreas': return perms.scanAreas + case 'scanAreas': + return perms.scanAreas case 'spawnpoint': - case 'spawnpoints': return perms.spawnpoints + case 'spawnpoints': + return perms.spawnpoints case 'webhook': case 'setLocation': case 'setAreas': case 'switchProfile': - case 'webhooks': return perms.webhooks - default: return false + case 'webhooks': + return perms.webhooks + default: + return false } } diff --git a/server/src/services/functions/scannerPerms.js b/server/src/services/functions/scannerPerms.js index 212f9bb3a..39c8ffb38 100644 --- a/server/src/services/functions/scannerPerms.js +++ b/server/src/services/functions/scannerPerms.js @@ -3,8 +3,8 @@ const { scanner } = require('../config') module.exports = function scannerPerms(roles, provider) { let perms = [] if (Object.keys(scanner).length) { - roles.forEach(role => { - Object.keys(scanner).forEach(mode => { + roles.forEach((role) => { + Object.keys(scanner).forEach((mode) => { if (scanner[mode][provider]?.includes(role)) { perms.push(mode) } diff --git a/server/src/services/functions/webhookPerms.js b/server/src/services/functions/webhookPerms.js index f691958b7..3f6574594 100644 --- a/server/src/services/functions/webhookPerms.js +++ b/server/src/services/functions/webhookPerms.js @@ -3,8 +3,8 @@ const { webhooks } = require('../config') module.exports = function webhookPerms(roles, provider) { let perms = [] if (webhooks.length) { - roles.forEach(role => { - webhooks.forEach(webhook => { + roles.forEach((role) => { + webhooks.forEach((webhook) => { if (webhook?.[provider]?.includes(role)) { perms.push(webhook.name) } diff --git a/server/src/services/geocoder.js b/server/src/services/geocoder.js index 592e82c2d..de3bda289 100644 --- a/server/src/services/geocoder.js +++ b/server/src/services/geocoder.js @@ -17,7 +17,9 @@ module.exports = async function geocoder(nominatimUrl, search, reverse) { town: result.address.town || '', village: result.address.village || '', }))(stockGeocoder._geocoder._formatResult) - const results = reverse ? await stockGeocoder.reverse(search) : await stockGeocoder.geocode(search) + const results = reverse + ? await stockGeocoder.reverse(search) + : await stockGeocoder.geocode(search) return reverse ? results[0] : results } catch (e) { console.warn('[GEOCODER] Unable to geocode', search) diff --git a/server/src/services/initWebhooks.js b/server/src/services/initWebhooks.js index 2702ba5fc..69e4714fd 100644 --- a/server/src/services/initWebhooks.js +++ b/server/src/services/initWebhooks.js @@ -8,21 +8,39 @@ module.exports = async function initWebhooks(webhook, config) { throw new Error('Webhook name property is required and must be unique') } if (webhook.enabled) { - const options = { method: 'GET', headers: { 'X-Poracle-Secret': webhook.poracleSecret } } - webhook.areasToSkip = webhook.areasToSkip?.map(x => x.toLowerCase()) || [] + const options = { + method: 'GET', + headers: { 'X-Poracle-Secret': webhook.poracleSecret }, + } + webhook.areasToSkip = + webhook.areasToSkip?.map((x) => x.toLowerCase()) || [] - const hookConfig = await fetchJson(`${webhook.host}:${webhook.port}/api/config/poracleWeb`, options, config.devOptions.enabled) + const hookConfig = await fetchJson( + `${webhook.host}:${webhook.port}/api/config/poracleWeb`, + options, + config.devOptions.enabled, + ) if (!hookConfig) { throw new Error(`Webhook [${webhook.name}] is not configured correctly`) } if (!hookConfig.version) { - throw new Error(`No version found, webhook [${webhook.name}] is not configured correctly`) + throw new Error( + `No version found, webhook [${webhook.name}] is not configured correctly`, + ) } - const [major, minor, patch] = hookConfig.version.split('.').map(x => parseInt(x)) + const [major, minor, patch] = hookConfig.version + .split('.') + .map((x) => parseInt(x)) - if (major < 4 || (major === 4 && minor < 5) || (major === 4 && minor === 5 && patch < 1)) { - throw new Error(`Poracle must be at least version 4.5.1, current version is ${hookConfig.version}`) + if ( + major < 4 || + (major === 4 && minor < 5) || + (major === 4 && minor === 5 && patch < 1) + ) { + throw new Error( + `Poracle must be at least version 4.5.1, current version is ${hookConfig.version}`, + ) } const baseSettings = { @@ -30,29 +48,46 @@ module.exports = async function initWebhooks(webhook, config) { platform: webhook.platform, addressFormat: webhook.addressFormat || hookConfig.addressFormat, fetched: Date.now(), - leagues: [{ name: 'great', cp: 1500, min: hookConfig.pvpFilterGreatMinCP }, { name: 'ultra', cp: 2500, min: hookConfig.pvpFilterUltraMinCP }], + leagues: [ + { name: 'great', cp: 1500, min: hookConfig.pvpFilterGreatMinCP }, + { name: 'ultra', cp: 2500, min: hookConfig.pvpFilterUltraMinCP }, + ], valid: Boolean(hookConfig), pvp: 'rdm', everything: hookConfig.everythingFlagPermissions === 'allow-any', gymBattles: hookConfig.gymBattles, } if (hookConfig?.pvpLittleLeagueAllowed) { - baseSettings.leagues.push({ name: 'little', cp: 500, min: hookConfig.pvpFilterLittleMinCP }) + baseSettings.leagues.push({ + name: 'little', + cp: 500, + min: hookConfig.pvpFilterLittleMinCP, + }) baseSettings.pvp = 'ohbem' } - const templates = await fetchJson(`${webhook.host}:${webhook.port}/api/config/templates?names=true`, options, config.devOptions.enabled) - const areas = await fetchJson(`${webhook.host}:${webhook.port}/api/geofence/all/geojson`, options, config.devOptions.enabled) || {} + const templates = await fetchJson( + `${webhook.host}:${webhook.port}/api/config/templates?names=true`, + options, + config.devOptions.enabled, + ) + const areas = + (await fetchJson( + `${webhook.host}:${webhook.port}/api/geofence/all/geojson`, + options, + config.devOptions.enabled, + )) || {} if (areas.geoJSON?.features) { - areas.geoJSON.features = areas.geoJSON.features - .filter(x => !webhook.areasToSkip.includes(x.properties.name.toLowerCase())) + areas.geoJSON.features = areas.geoJSON.features.filter( + (x) => !webhook.areasToSkip.includes(x.properties.name.toLowerCase()), + ) } else { console.warn('No geofences found') } if (templates) { - ['discord', 'telegram'].forEach(platform => { + ;['discord', 'telegram'].forEach((platform) => { if (templates[platform].monster) { templates[platform].pokemon = templates[platform].monster delete templates[platform].monster @@ -74,19 +109,29 @@ module.exports = async function initWebhooks(webhook, config) { nominatimUrl: hookConfig ? hookConfig.providerURL : null, areasToSkip: webhook.areasToSkip, }, - client: hookConfig ? { - ...baseSettings, - prefix: hookConfig.prefix, - locale: hookConfig.locale, - info: webhookUi(webhook.provider, hookConfig, baseSettings.pvp, baseSettings.leagues), - areas: areas.geoJSON || [], - templates, - } : baseSettings, + client: hookConfig + ? { + ...baseSettings, + prefix: hookConfig.prefix, + locale: hookConfig.locale, + info: webhookUi( + webhook.provider, + hookConfig, + baseSettings.pvp, + baseSettings.leagues, + ), + areas: areas.geoJSON || [], + templates, + } + : baseSettings, } } console.log(`[EVENT] ${webhook.name} webhook initialized`) } catch (e) { - console.log(config.devOptions.enabled ? e : e.message, 'An error has occurred during webhook initialization') + console.log( + config.devOptions.enabled ? e : e.message, + 'An error has occurred during webhook initialization', + ) } return {} } diff --git a/server/src/services/initialization.js b/server/src/services/initialization.js index bc1166c8a..382101509 100644 --- a/server/src/services/initialization.js +++ b/server/src/services/initialization.js @@ -1,15 +1,29 @@ /* eslint-disable no-console */ +const fs = require('fs') +const { resolve } = require('path') const { database: { schemas: exampleSchemas }, } = require('../configs/local.example.json') const config = require('./config') -const staticMf = require('../data/masterfile.json') + +const staticMf = JSON.parse( + fs.readFileSync(resolve(__dirname, '../data/masterfile.json')), +) const DbCheck = require('./DbCheck') const EventManager = require('./EventManager') const PvpWrapper = require('./PvpWrapper') -const Db = new DbCheck(exampleSchemas, config.database, config.devOptions.queryDebug, config.api, config.map.distanceUnit) -const Pvp = config.api.pvp.reactMapHandlesPvp ? new PvpWrapper(config.api.pvp) : null + +const Db = new DbCheck( + exampleSchemas, + config.database, + config.devOptions.queryDebug, + config.api, + config.map.distanceUnit, +) +const Pvp = config.api.pvp.reactMapHandlesPvp + ? new PvpWrapper(config.api.pvp) + : null const Event = new EventManager(staticMf) Event.setTimers(config, Db, Pvp) diff --git a/server/src/services/legacyFilter.js b/server/src/services/legacyFilter.js index 592fe3360..05b6e7ca4 100644 --- a/server/src/services/legacyFilter.js +++ b/server/src/services/legacyFilter.js @@ -5,13 +5,16 @@ /* eslint-disable default-case */ const requireFromString = require('require-from-string') const { - api: { pvp: { minCp: pvpMinCp, reactMapHandlesPvp } }, + api: { + pvp: { minCp: pvpMinCp, reactMapHandlesPvp }, + }, } = require('./config') const { Pvp, Event } = require('./initialization') const jsifyIvFilter = (filter) => { const input = filter.toUpperCase() - const tokenizer = /\s*([()|&!,]|([ADSL]?|CP|LC|[GU]L)\s*([0-9]+(?:\.[0-9]*)?)(?:\s*-\s*([0-9]+(?:\.[0-9]*)?))?)/g + const tokenizer = + /\s*([()|&!,]|([ADSL]?|CP|LC|[GU]L)\s*([0-9]+(?:\.[0-9]*)?)(?:\s*-\s*([0-9]+(?:\.[0-9]*)?))?)/g let result = '' let expectClause = true // expect a clause or '(' let stack = 0 @@ -27,20 +30,33 @@ const jsifyIvFilter = (filter) => { let column = 'iv' let subColumn switch (match[2]) { - case 'A': column = 'atk_iv'; break - case 'D': column = 'def_iv'; break - case 'S': column = 'sta_iv'; break - case 'L': column = 'level'; break - case 'CP': column = 'cp'; break + case 'A': + column = 'atk_iv' + break + case 'D': + column = 'def_iv' + break + case 'S': + column = 'sta_iv' + break + case 'L': + column = 'level' + break + case 'CP': + column = 'cp' + break case 'GL': column = 'cleanPvp' - subColumn = 'great'; break + subColumn = 'great' + break case 'UL': column = 'cleanPvp' - subColumn = 'ultra'; break + subColumn = 'ultra' + break case 'LC': column = 'cleanPvp' - subColumn = 'little'; break + subColumn = 'little' + break } let upper = lower if (match[4] !== undefined) { @@ -103,16 +119,18 @@ const getLegacy = (results, args, perms, ts) => { const pokemonLookup = {} const formLookup = {} const pokemonFilterIV = { or: args.filters.onlyIvOr.adv } - Object.keys(args.filters).forEach(pkmn => { + Object.keys(args.filters).forEach((pkmn) => { if (pkmn.charAt(0) !== 'o') { pokemonFilterIV[pkmn] = args.filters[pkmn].adv } }) const interestedLevelCaps = Object.keys(args.filters) - .filter(x => x.startsWith('onlyPvp') && args.filters[x]) - .map(y => parseInt(y.substring(7))) - const interestedMegas = args.filters.pvpMega ? [1, 2, 3, 'experimental_stats'] : [] + .filter((x) => x.startsWith('onlyPvp') && args.filters[x]) + .map((y) => parseInt(y.substring(7))) + const interestedMegas = args.filters.pvpMega + ? [1, 2, 3, 'experimental_stats'] + : [] for (const key of args.filters.onlyLegacyExclude || []) { if (key === 'global') continue @@ -120,7 +138,9 @@ const getLegacy = (results, args, perms, ts) => { if (split.length === 2) { const pokemonId = parseInt(split[0]) const formId = parseInt(split[1]) - if ((Event.masterfile.pokemon[pokemonId] || {}).defaultFormId === formId) { + if ( + (Event.masterfile.pokemon[pokemonId] || {}).defaultFormId === formId + ) { pokemonLookup[pokemonId] = false } formLookup[formId] = false @@ -145,7 +165,8 @@ const getLegacy = (results, args, perms, ts) => { console.warn('Unrecognized key', key) } else { pokemonLookup[pokemonId] = false - const defaultForm = (Event.masterfile.pokemon[pokemonId] || {}).defaultFormId + const defaultForm = (Event.masterfile.pokemon[pokemonId] || {}) + .defaultFormId if (defaultForm) { formLookup[defaultForm] = false } @@ -167,7 +188,9 @@ const getLegacy = (results, args, perms, ts) => { if (split.length === 2) { const pokemonId = parseInt(split[0]) const formId = parseInt(split[1]) - if ((Event.masterfile.pokemon[pokemonId] || {}).defaultFormId === formId) { + if ( + (Event.masterfile.pokemon[pokemonId] || {}).defaultFormId === formId + ) { pokemonLookup[pokemonId] = jsFilter } formLookup[formId] = jsFilter @@ -182,7 +205,8 @@ const getLegacy = (results, args, perms, ts) => { console.warn('Unrecognized key', key) } else { pokemonLookup[pokemonId] = jsFilter - const defaultForm = (Event.masterfile.pokemon[pokemonId] || {}).defaultFormId + const defaultForm = (Event.masterfile.pokemon[pokemonId] || {}) + .defaultFormId if (defaultForm) { formLookup[defaultForm] = jsFilter } @@ -194,22 +218,37 @@ const getLegacy = (results, args, perms, ts) => { let bestPvp = 4096 const filterLeagueStats = (pvpResult, target, minCp) => { let last - for (const entry of typeof pvpResult === 'string' ? JSON.parse(pvpResult) : pvpResult) { - if ((minCp && entry.cp < minCp) || (entry.cap !== undefined && (entry.capped - ? interestedLevelCaps[interestedLevelCaps.length - 1] < entry.cap - : !interestedLevelCaps.includes(entry.cap)))) { + for (const entry of typeof pvpResult === 'string' + ? JSON.parse(pvpResult) + : pvpResult) { + if ( + (minCp && entry.cp < minCp) || + (entry.cap !== undefined && + (entry.capped + ? interestedLevelCaps[interestedLevelCaps.length - 1] < entry.cap + : !interestedLevelCaps.includes(entry.cap))) + ) { continue } if (entry.evolution) { - if (Event.masterfile.pokemon[entry.pokemon].tempEvolutions[entry.evolution].unreleased - ? !interestedMegas.includes('experimental') - : !interestedMegas.includes(entry.evolution)) { + if ( + Event.masterfile.pokemon[entry.pokemon].tempEvolutions[ + entry.evolution + ].unreleased + ? !interestedMegas.includes('experimental') + : !interestedMegas.includes(entry.evolution) + ) { continue } } - if (last !== undefined && last.pokemon === entry.pokemon - && last.form === entry.form && last.evolution === entry.evolution - && last.level === entry.level && last.rank === entry.rank) { + if ( + last !== undefined && + last.pokemon === entry.pokemon && + last.form === entry.form && + last.evolution === entry.evolution && + last.level === entry.level && + last.rank === entry.rank + ) { last.cap = entry.cap if (entry.capped) { last.capped = true @@ -232,7 +271,8 @@ const getLegacy = (results, args, perms, ts) => { const filtered = {} if (result.pokemon_id === 132) { filtered.ditto_form = result.form - result.form = Event.masterfile.pokemon[result.pokemon_id]?.defaultFormId || 0 + result.form = + Event.masterfile.pokemon[result.pokemon_id]?.defaultFormId || 0 } if (!result.seen_type) { if (result.spawn_id === null) { @@ -253,21 +293,37 @@ const getLegacy = (results, args, perms, ts) => { const { great, ultra } = pvpMinCp filtered.cleanPvp = {} if (result.pvp || (reactMapHandlesPvp && result.cp)) { - const pvpResults = reactMapHandlesPvp ? Pvp.resultWithCache(result, ts) : JSON.parse(result.pvp) - Object.keys(pvpResults).forEach(league => { - filterLeagueStats(pvpResults[league], filtered.cleanPvp[league] = []) + const pvpResults = reactMapHandlesPvp + ? Pvp.resultWithCache(result, ts) + : JSON.parse(result.pvp) + Object.keys(pvpResults).forEach((league) => { + filterLeagueStats( + pvpResults[league], + (filtered.cleanPvp[league] = []), + ) }) } else { if (result.pvp_rankings_great_league) { - filterLeagueStats(result.pvp_rankings_great_league, filtered.cleanPvp.great = [], great) + filterLeagueStats( + result.pvp_rankings_great_league, + (filtered.cleanPvp.great = []), + great, + ) } if (result.pvp_rankings_ultra_league) { - filterLeagueStats(result.pvp_rankings_ultra_league, filtered.cleanPvp.ultra = [], ultra) + filterLeagueStats( + result.pvp_rankings_ultra_league, + (filtered.cleanPvp.ultra = []), + ultra, + ) } } filtered.bestPvp = bestPvp } - let pokemonFilter = result.form === 0 ? pokemonLookup[result.pokemon_id] : formLookup[result.form] + let pokemonFilter = + result.form === 0 + ? pokemonLookup[result.pokemon_id] + : formLookup[result.form] if (pokemonFilter === undefined) { pokemonFilter = andIv(filtered) || orIv(filtered) } else if (pokemonFilter === false) { @@ -280,7 +336,9 @@ const getLegacy = (results, args, perms, ts) => { } if (!result.seen_type) { if (result.spawn_id === null) { - filtered.seen_type = result.pokestop_id ? 'nearby_stop' : 'nearby_cell' + filtered.seen_type = result.pokestop_id + ? 'nearby_stop' + : 'nearby_cell' } else { filtered.seen_type = 'encounter' } diff --git a/server/src/services/logUserAuth.js b/server/src/services/logUserAuth.js index bb620d6b7..12f33e906 100644 --- a/server/src/services/logUserAuth.js +++ b/server/src/services/logUserAuth.js @@ -2,13 +2,18 @@ const Fetch = require('./Fetch') module.exports = async function getAuthInfo(req, user, strategy) { - const ip = req.headers['cf-connecting-ip'] - || ((req.headers['x-forwarded-for'] || '').split(', ')[0]) - || (req.connection.remoteAddress || req.connection.localAddress).match('[0-9]+.[0-9].+[0-9]+.[0-9]+$')[0] + const ip = + req.headers['cf-connecting-ip'] || + (req.headers['x-forwarded-for'] || '').split(', ')[0] || + (req.connection.remoteAddress || req.connection.localAddress).match( + '[0-9]+.[0-9].+[0-9]+.[0-9]+$', + )[0] - const geo = await Fetch.json(`http://ip-api.com/json/${ip}?fields=66846719&lang=en`) + const geo = await Fetch.json( + `http://ip-api.com/json/${ip}?fields=66846719&lang=en`, + ) const embed = { - color: 0xFF0000, + color: 0xff0000, title: 'Authentication', author: { name: `${user.username}`, @@ -62,13 +67,18 @@ module.exports = async function getAuthInfo(req, user, strategy) { timestamp: new Date(), } if (user.valid) { - console.log('[DISCORD]', user.username, `(${user.id})`, 'Authenticated successfully.') + console.log( + '[DISCORD]', + user.username, + `(${user.id})`, + 'Authenticated successfully.', + ) embed.description = `${user.username} Successfully Authenticated` - embed.color = 0x00FF00 + embed.color = 0x00ff00 } else if (user.blocked) { console.warn('[DISCORD]', user.id, 'Blocked due to', user.blocked) embed.description = `User Blocked Due to ${user.blocked}` - embed.color = 0xFF0000 + embed.color = 0xff0000 } else { console.warn('[DISCORD]', user.id, 'Not authorized to access map') } diff --git a/server/src/services/sessionStore.js b/server/src/services/sessionStore.js index 5992c4445..2e7759cff 100644 --- a/server/src/services/sessionStore.js +++ b/server/src/services/sessionStore.js @@ -4,7 +4,9 @@ const session = require('express-session') const MySQLStore = require('express-mysql-session')(session) const { api: { maxSessions }, - database: { settings: { sessionTableName } }, + database: { + settings: { sessionTableName }, + }, } = require('./config') const Utility = require('./Utility') const { Session } = require('../models/index') @@ -36,7 +38,7 @@ const sessionStore = new MySQLStore({ }) const isValidSession = async (userId) => { - const ts = Math.floor((new Date()).getTime() / 1000) + const ts = Math.floor(new Date().getTime() / 1000) const results = await Session.query() .select('session_id') .whereRaw(`json_extract(data, '$.passport.user.id') = ${userId}`) @@ -54,7 +56,9 @@ const clearOtherSessions = async (userId, currentSessionId) => { const clearDiscordSessions = async (discordId, botName) => { const results = await Session.query() - .whereRaw(`json_extract(data, '$.passport.user.discordId') = '${discordId}'`) + .whereRaw( + `json_extract(data, '$.passport.user.discordId') = '${discordId}'`, + ) .orWhereRaw(`json_extract(data, '$.passport.user.id') = '${discordId}'`) .delete() console.log(`[Session${botName && ` - ${botName}`}] Clear Result:`, results) diff --git a/server/src/services/ui/advMenus.js b/server/src/services/ui/advMenus.js index 9fe24c476..798835950 100644 --- a/server/src/services/ui/advMenus.js +++ b/server/src/services/ui/advMenus.js @@ -3,7 +3,16 @@ const { map } = require('../config') const categories = { gyms: ['teams', 'eggs', 'raids', 'pokemon'], - pokestops: ['lures', 'items', 'quest_reward_12', 'invasions', 'pokemon', 'quest_reward_4', 'quest_reward_9', 'quest_reward_3'], + pokestops: [ + 'lures', + 'items', + 'quest_reward_12', + 'invasions', + 'pokemon', + 'quest_reward_4', + 'quest_reward_9', + 'quest_reward_3', + ], pokemon: ['pokemon'], nests: ['pokemon'], } @@ -13,17 +22,21 @@ if (map.enableQuestRewardTypeFilters) { } const pokemonFilters = { - generations: [...new Set( - Object.values(Event.masterfile.pokemon) - .map(val => `generation_${val.genId}`), - )].filter(val => val !== undefined), + generations: [ + ...new Set( + Object.values(Event.masterfile.pokemon).map( + (val) => `generation_${val.genId}`, + ), + ), + ].filter((val) => val !== undefined), types: Object.keys(Event.masterfile.types) - .map(key => `poke_type_${key}`) - .filter(val => val !== 'poke_type_0'), - rarity: [...new Set( - Object.values(Event.masterfile.pokemon) - .map(val => val.rarity), - )].filter(val => val !== undefined), + .map((key) => `poke_type_${key}`) + .filter((val) => val !== 'poke_type_0'), + rarity: [ + ...new Set( + Object.values(Event.masterfile.pokemon).map((val) => val.rarity), + ), + ].filter((val) => val !== undefined), forms: ['normalForms', 'altForms', 'Alola', 'Galarian'], others: ['reverse', 'selected', 'unselected', 'onlyAvailable'], } @@ -33,7 +46,7 @@ module.exports = function buildMenus() { const returnedItems = {} Object.entries(pokemonFilters).forEach(([key, items]) => { - menuFilters[key] = Object.fromEntries(items.map(item => [item, false])) + menuFilters[key] = Object.fromEntries(items.map((item) => [item, false])) }) Object.entries(categories).forEach(([key, items]) => { @@ -45,7 +58,7 @@ module.exports = function buildMenus() { ...menuFilters.others, onlyAvailable: true, }, - categories: Object.fromEntries(items.map(item => [item, false])), + categories: Object.fromEntries(items.map((item) => [item, false])), }, } }) diff --git a/server/src/services/ui/clientOptions.js b/server/src/services/ui/clientOptions.js index 7ffc9f5b5..88ce30657 100644 --- a/server/src/services/ui/clientOptions.js +++ b/server/src/services/ui/clientOptions.js @@ -1,7 +1,9 @@ const { clientSideOptions, map: { enableMapJsFilter }, - api: { pvp: { levels } }, + api: { + pvp: { levels }, + }, } = require('../config') const dbSelection = require('../functions/dbSelection') @@ -58,9 +60,11 @@ module.exports = function clientOptions(perms) { }, } - levels.forEach(level => { + levels.forEach((level) => { clientMenus.pokemon[`pvp${level}`] = { - type: 'bool', perm: ['pvp'], value: true, + type: 'bool', + perm: ['pvp'], + value: true, } }) @@ -78,13 +82,14 @@ module.exports = function clientOptions(perms) { // only the keys & values are stored locally const clientValues = {} - Object.entries(clientMenus).forEach(category => { + Object.entries(clientMenus).forEach((category) => { const [key, options] = category clientValues[key] = {} - Object.entries(options).forEach(option => { + Object.entries(options).forEach((option) => { const [name, meta] = option - clientMenus[key][name].value = clientSideOptions[key][name] || meta.value || false - clientMenus[key][name].disabled = !meta.perm.some(x => perms[x]) + clientMenus[key][name].value = + clientSideOptions[key][name] || meta.value || false + clientMenus[key][name].disabled = !meta.perm.some((x) => perms[x]) clientValues[key][name] = meta.value if (meta.sub) clientMenus[key][name].sub = {} delete clientMenus[key][name].perm @@ -93,7 +98,7 @@ module.exports = function clientOptions(perms) { clientMenus.pokemon.glow.value = true clientValues.pokemon.glow = true - clientSideOptions.pokemon.glow.forEach(option => { + clientSideOptions.pokemon.glow.forEach((option) => { clientMenus.pokemon.glow.sub[option.name] = { ...option } clientMenus.pokemon.glow.sub[option.name].disabled = !perms[option.perm] clientMenus.pokemon.glow.sub[option.name].type = 'color' diff --git a/server/src/services/ui/primary.js b/server/src/services/ui/primary.js index 2967225af..10d327e18 100644 --- a/server/src/services/ui/primary.js +++ b/server/src/services/ui/primary.js @@ -1,12 +1,23 @@ /* eslint-disable no-restricted-syntax */ const { - api: { pvp: { leagues } }, - defaultFilters: { nests: { avgSliderStep } }, + api: { + pvp: { leagues }, + }, + defaultFilters: { + nests: { avgSliderStep }, + }, } = require('../config') module.exports = function generateUi(filters, perms) { const ui = {} - const ignoredKeys = ['enabled', 'filter', 'showQuestSet', 'badge', 'avgFilter', 'raidTier'] + const ignoredKeys = [ + 'enabled', + 'filter', + 'showQuestSet', + 'badge', + 'avgFilter', + 'raidTier', + ] // builds the initial categories for (const [key, value] of Object.entries(filters)) { @@ -18,68 +29,119 @@ module.exports = function generateUi(filters, perms) { sliders = { secondary: [ { - name: 'avgFilter', i18nKey: 'spawns_per_hour', label: '', min: filters.nests.avgFilter[0], max: filters.nests.avgFilter[1], perm: 'nests', step: avgSliderStep, + name: 'avgFilter', + i18nKey: 'spawns_per_hour', + label: '', + min: filters.nests.avgFilter[0], + max: filters.nests.avgFilter[1], + perm: 'nests', + step: avgSliderStep, }, ], - }; break + } + break case 'pokemon': ui[key] = {} sliders = { primary: [ { - name: 'iv', label: '%', min: 0, max: 100, perm: 'iv', color: 'secondary', + name: 'iv', + label: '%', + min: 0, + max: 100, + perm: 'iv', + color: 'secondary', }, ], secondary: [ { - name: 'level', label: '', min: 1, max: 35, perm: 'iv', + name: 'level', + label: '', + min: 1, + max: 35, + perm: 'iv', }, { - name: 'atk_iv', label: '', min: 0, max: 15, perm: 'iv', + name: 'atk_iv', + label: '', + min: 0, + max: 15, + perm: 'iv', }, { - name: 'def_iv', label: '', min: 0, max: 15, perm: 'iv', + name: 'def_iv', + label: '', + min: 0, + max: 15, + perm: 'iv', }, { - name: 'sta_iv', label: '', min: 0, max: 15, perm: 'iv', + name: 'sta_iv', + label: '', + min: 0, + max: 15, + perm: 'iv', }, ], } - leagues.forEach(league => sliders.primary.push({ - name: league.name, label: 'rank', min: (league.minRank || 1), max: (league.maxRank || 100), perm: 'pvp', color: 'primary', - })); break + leagues.forEach((league) => + sliders.primary.push({ + name: league.name, + label: 'rank', + min: league.minRank || 1, + max: league.maxRank || 100, + perm: 'pvp', + color: 'primary', + }), + ) + break case 'submissionCells': case 'portals': if (!ui.wayfarer) ui.wayfarer = {} - ui.wayfarer[key] = true; break + ui.wayfarer[key] = true + break case 'spawnpoints': case 'scanCells': case 'devices': if (!ui.admin) ui.admin = {} - ui.admin[key] = true; break - default: ui[key] = {}; break + ui.admin[key] = true + break + default: + ui[key] = {} + break } // builds each subcategory for (const [subKey, subValue] of Object.entries(value)) { - if ((!ignoredKeys.includes(subKey) && subValue !== undefined) - || key === 'weather' || key === 'scanAreas') { + if ( + (!ignoredKeys.includes(subKey) && subValue !== undefined) || + key === 'weather' || + key === 'scanAreas' + ) { switch (key) { case 'submissionCells': - case 'portals': ui.wayfarer[key] = true; break + case 'portals': + ui.wayfarer[key] = true + break case 'spawnpoints': case 'scanCells': - case 'devices': ui.admin[key] = true; break + case 'devices': + ui.admin[key] = true + break case 'scanAreas': - case 'weather': ui[key].enabled = true; break - default: ui[key][subKey] = true; break + case 'weather': + ui[key].enabled = true + break + default: + ui[key][subKey] = true + break } } } // adds any sliders present if (sliders) { ui[key].sliders = sliders - Object.keys(sliders).forEach(category => { - sliders[category].forEach(slider => { + Object.keys(sliders).forEach((category) => { + sliders[category].forEach((slider) => { slider.disabled = !perms[slider.perm] if (!slider.color) { slider.color = category @@ -91,7 +153,7 @@ module.exports = function generateUi(filters, perms) { } // deletes any menus that do not have any items/perms - Object.keys(ui).forEach(category => { + Object.keys(ui).forEach((category) => { if (Object.keys(ui[category]).length === 0) { delete ui[category] } diff --git a/server/src/services/ui/webhook.js b/server/src/services/ui/webhook.js index 95cafe9c1..b408ec2f9 100644 --- a/server/src/services/ui/webhook.js +++ b/server/src/services/ui/webhook.js @@ -41,24 +41,84 @@ module.exports = function webhookUi(provider, hookConfig, pvp, leagues) { byDistance: false, xs: false, xl: false, - everything_individually: hookConfig.everythingFlagPermissions === 'allow-and-always-individually' - || hookConfig.everythingFlagPermissions === 'deny', + everything_individually: + hookConfig.everythingFlagPermissions === + 'allow-and-always-individually' || + hookConfig.everythingFlagPermissions === 'deny', }, ui: { primary: { sliders: [ - { name: 'iv', label: '', min: -1, max: 100, perm: 'iv', low: 'min_iv', high: 'max_iv' }, - { name: 'level', label: '', min: 0, max: 40, perm: 'iv', low: 'min_level', high: 'max_level' }, + { + name: 'iv', + label: '', + min: -1, + max: 100, + perm: 'iv', + low: 'min_iv', + high: 'max_iv', + }, + { + name: 'level', + label: '', + min: 0, + max: 40, + perm: 'iv', + low: 'min_level', + high: 'max_level', + }, ], }, advanced: { sliders: [ - { name: 'cp', label: '', min: 0, max: 9000, perm: 'iv', low: 'min_cp', high: 'max_cp' }, - { name: 'atk_iv', label: '', min: 0, max: 15, perm: 'iv', low: 'atk', high: 'max_atk' }, - { name: 'def_iv', label: '', min: 0, max: 15, perm: 'iv', low: 'def', high: 'max_def' }, - { name: 'sta_iv', label: '', min: 0, max: 15, perm: 'iv', low: 'sta', high: 'max_sta' }, + { + name: 'cp', + label: '', + min: 0, + max: 9000, + perm: 'iv', + low: 'min_cp', + high: 'max_cp', + }, + { + name: 'atk_iv', + label: '', + min: 0, + max: 15, + perm: 'iv', + low: 'atk', + high: 'max_atk', + }, + { + name: 'def_iv', + label: '', + min: 0, + max: 15, + perm: 'iv', + low: 'def', + high: 'max_def', + }, + { + name: 'sta_iv', + label: '', + min: 0, + max: 15, + perm: 'iv', + low: 'sta', + high: 'max_sta', + }, + ], + texts: [ + { + name: 'min_time', + type: 'number', + max: 60, + adornment: 's', + xs: 4, + sm: 4, + width: 100, + }, ], - texts: [{ name: 'min_time', type: 'number', max: 60, adornment: 's', xs: 4, sm: 4, width: 100 }], booleans: [ { name: 'xs', xs: 4, sm: 4, override: true }, { name: 'xl', xs: 4, sm: 4, override: true }, @@ -66,13 +126,46 @@ module.exports = function webhookUi(provider, hookConfig, pvp, leagues) { }, pvp: { selects: [ - { name: 'pvp_ranking_league', options: [{ name: 'none', cp: 0 }, ...leagues], xs: 6, sm: 3 }, - ...(isOhbem ? [{ name: 'pvp_ranking_cap', options: [0, ...(hookConfig.pvpCaps || [])], xs: 6, sm: 3 }] : []), + { + name: 'pvp_ranking_league', + options: [{ name: 'none', cp: 0 }, ...leagues], + xs: 6, + sm: 3, + }, + ...(isOhbem + ? [ + { + name: 'pvp_ranking_cap', + options: [0, ...(hookConfig.pvpCaps || [])], + xs: 6, + sm: 3, + }, + ] + : []), ], texts: isOhbem ? [] - : [{ name: 'pvp_ranking_min_cp', type: 'number', adornment: 'cp', width: 110, xs: 6, sm: 3 }], - sliders: [{ name: 'pvp', label: 'rank', min: 1, max: hookConfig.pvpFilterMaxRank, perm: 'pvp', low: 'pvp_ranking_best', high: 'pvp_ranking_worst' }], + : [ + { + name: 'pvp_ranking_min_cp', + type: 'number', + adornment: 'cp', + width: 110, + xs: 6, + sm: 3, + }, + ], + sliders: [ + { + name: 'pvp', + label: 'rank', + min: 1, + max: hookConfig.pvpFilterMaxRank, + perm: 'pvp', + low: 'pvp_ranking_best', + high: 'pvp_ranking_worst', + }, + ], }, general: { selects: [ @@ -87,8 +180,24 @@ module.exports = function webhookUi(provider, hookConfig, pvp, leagues) { { name: 'noIv', xs: 6, sm: 3 }, ], distanceOrArea: { - booleans: [{ name: 'byDistance', max: hookConfig.maxDistance, xs: 6, sm: 8, override: true }], - texts: [{ name: 'distance', type: 'number', adornment: 'm', xs: 6, sm: 4 }], + booleans: [ + { + name: 'byDistance', + max: hookConfig.maxDistance, + xs: 6, + sm: 8, + override: true, + }, + ], + texts: [ + { + name: 'distance', + type: 'number', + adornment: 'm', + xs: 6, + sm: 4, + }, + ], }, }, global: { @@ -112,8 +221,10 @@ module.exports = function webhookUi(provider, hookConfig, pvp, leagues) { byDistance: false, allMoves: true, allForms: true, - everything_individually: hookConfig.everythingFlagPermissions === 'allow-and-always-individually' - || hookConfig.everythingFlagPermissions === 'deny', + everything_individually: + hookConfig.everythingFlagPermissions === + 'allow-and-always-individually' || + hookConfig.everythingFlagPermissions === 'deny', }, ui: { general: { @@ -129,10 +240,34 @@ module.exports = function webhookUi(provider, hookConfig, pvp, leagues) { { name: 'allForms', disabled: ['r'], xs: 6, sm: 3 }, { name: 'allMoves', disabled: ['r'], xs: 6, sm: 3 }, ], - autoComplete: [{ name: 'gymName', label: 'gym', searchCategory: 'gyms', xs: 12, sm: 12 }], + autoComplete: [ + { + name: 'gymName', + label: 'gym', + searchCategory: 'gyms', + xs: 12, + sm: 12, + }, + ], distanceOrArea: { - booleans: [{ name: 'byDistance', max: hookConfig.maxDistance, xs: 6, sm: 8, override: true }], - texts: [{ name: 'distance', type: 'number', adornment: 'm', xs: 6, sm: 4 }], + booleans: [ + { + name: 'byDistance', + max: hookConfig.maxDistance, + xs: 6, + sm: 8, + override: true, + }, + ], + texts: [ + { + name: 'distance', + type: 'number', + adornment: 'm', + xs: 6, + sm: 4, + }, + ], }, }, global: { @@ -150,8 +285,10 @@ module.exports = function webhookUi(provider, hookConfig, pvp, leagues) { team: 4, gym_id: null, byDistance: false, - everything_individually: hookConfig.everythingFlagPermissions === 'allow-and-always-individually' - || hookConfig.everythingFlagPermissions === 'deny', + everything_individually: + hookConfig.everythingFlagPermissions === + 'allow-and-always-individually' || + hookConfig.everythingFlagPermissions === 'deny', }, ui: { general: { @@ -164,10 +301,34 @@ module.exports = function webhookUi(provider, hookConfig, pvp, leagues) { { name: 'clean', xs: 6, sm: 6 }, { name: 'exclusive', xs: 6, sm: 6 }, ], - autoComplete: [{ name: 'gymName', label: 'gym', searchCategory: 'gyms', xs: 12, sm: 12 }], + autoComplete: [ + { + name: 'gymName', + label: 'gym', + searchCategory: 'gyms', + xs: 12, + sm: 12, + }, + ], distanceOrArea: { - booleans: [{ name: 'byDistance', max: hookConfig.maxDistance, xs: 6, sm: 8, override: true }], - texts: [{ name: 'distance', type: 'number', adornment: 'm', xs: 6, sm: 4 }], + booleans: [ + { + name: 'byDistance', + max: hookConfig.maxDistance, + xs: 6, + sm: 8, + override: true, + }, + ], + texts: [ + { + name: 'distance', + type: 'number', + adornment: 'm', + xs: 6, + sm: 4, + }, + ], }, }, global: { @@ -185,8 +346,10 @@ module.exports = function webhookUi(provider, hookConfig, pvp, leagues) { battle_changes: false, gym_id: null, byDistance: false, - everything_individually: hookConfig.everythingFlagPermissions === 'allow-and-always-individually' - || hookConfig.everythingFlagPermissions === 'deny', + everything_individually: + hookConfig.everythingFlagPermissions === + 'allow-and-always-individually' || + hookConfig.everythingFlagPermissions === 'deny', }, ui: { general: { @@ -196,13 +359,39 @@ module.exports = function webhookUi(provider, hookConfig, pvp, leagues) { ], booleans: [ { name: 'clean', xs: 4, sm: 4 }, - ...(hookConfig.gymBattles ? [{ name: 'battle_changes', xs: 6, sm: 4 }] : []), + ...(hookConfig.gymBattles + ? [{ name: 'battle_changes', xs: 6, sm: 4 }] + : []), { name: 'slot_changes', xs: 6, sm: 4 }, ], - autoComplete: [{ name: 'gymName', label: 'gym', searchCategory: 'gyms', xs: 12, sm: 12 }], + autoComplete: [ + { + name: 'gymName', + label: 'gym', + searchCategory: 'gyms', + xs: 12, + sm: 12, + }, + ], distanceOrArea: { - booleans: [{ name: 'byDistance', max: hookConfig.maxDistance, xs: 6, sm: 8, override: true }], - texts: [{ name: 'distance', type: 'number', adornment: 'm', xs: 6, sm: 4 }], + booleans: [ + { + name: 'byDistance', + max: hookConfig.maxDistance, + xs: 6, + sm: 8, + override: true, + }, + ], + texts: [ + { + name: 'distance', + type: 'number', + adornment: 'm', + xs: 6, + sm: 4, + }, + ], }, }, global: { @@ -218,8 +407,10 @@ module.exports = function webhookUi(provider, hookConfig, pvp, leagues) { grunt_type: null, gender: 0, byDistance: false, - everything_individually: hookConfig.everythingFlagPermissions === 'allow-and-always-individually' - || hookConfig.everythingFlagPermissions === 'deny', + everything_individually: + hookConfig.everythingFlagPermissions === + 'allow-and-always-individually' || + hookConfig.everythingFlagPermissions === 'deny', }, ui: { general: { @@ -227,12 +418,26 @@ module.exports = function webhookUi(provider, hookConfig, pvp, leagues) { { name: 'profile_no', options: [], xs: 4, sm: 4 }, { name: 'template', options: [], xs: 4, sm: 4 }, ], - booleans: [ - { name: 'clean', xs: 4, sm: 4 }, - ], + booleans: [{ name: 'clean', xs: 4, sm: 4 }], distanceOrArea: { - booleans: [{ name: 'byDistance', max: hookConfig.maxDistance, xs: 6, sm: 8, override: true }], - texts: [{ name: 'distance', type: 'number', adornment: 'm', xs: 6, sm: 4 }], + booleans: [ + { + name: 'byDistance', + max: hookConfig.maxDistance, + xs: 6, + sm: 8, + override: true, + }, + ], + texts: [ + { + name: 'distance', + type: 'number', + adornment: 'm', + xs: 6, + sm: 4, + }, + ], }, }, global: { @@ -254,12 +459,26 @@ module.exports = function webhookUi(provider, hookConfig, pvp, leagues) { { name: 'profile_no', options: [], xs: 4, sm: 4 }, { name: 'template', options: [], xs: 4, sm: 4 }, ], - booleans: [ - { name: 'clean', xs: 4, sm: 4 }, - ], + booleans: [{ name: 'clean', xs: 4, sm: 4 }], distanceOrArea: { - booleans: [{ name: 'byDistance', max: hookConfig.maxDistance, xs: 6, sm: 8, override: true }], - texts: [{ name: 'distance', type: 'number', adornment: 'm', xs: 6, sm: 4 }], + booleans: [ + { + name: 'byDistance', + max: hookConfig.maxDistance, + xs: 6, + sm: 8, + override: true, + }, + ], + texts: [ + { + name: 'distance', + type: 'number', + adornment: 'm', + xs: 6, + sm: 4, + }, + ], }, }, }, @@ -285,12 +504,41 @@ module.exports = function webhookUi(provider, hookConfig, pvp, leagues) { ], booleans: [ { name: 'clean', xs: 4, sm: 4 }, - { name: 'allForms', xs: 6, sm: 6, disabled: ['m', 'x', 'd', 'c', 'q'] }, + { + name: 'allForms', + xs: 6, + sm: 6, + disabled: ['m', 'x', 'd', 'c', 'q'], + }, + ], + texts: [ + { + name: 'amount', + type: 'number', + disabled: ['m', 'd', 'g'], + xs: 6, + sm: 6, + }, ], - texts: [{ name: 'amount', type: 'number', disabled: ['m', 'd', 'g'], xs: 6, sm: 6 }], distanceOrArea: { - booleans: [{ name: 'byDistance', max: hookConfig.maxDistance, xs: 6, sm: 8, override: true }], - texts: [{ name: 'distance', type: 'number', adornment: 'm', xs: 6, sm: 4 }], + booleans: [ + { + name: 'byDistance', + max: hookConfig.maxDistance, + xs: 6, + sm: 8, + override: true, + }, + ], + texts: [ + { + name: 'distance', + type: 'number', + adornment: 'm', + xs: 6, + sm: 4, + }, + ], }, }, }, @@ -318,21 +566,46 @@ module.exports = function webhookUi(provider, hookConfig, pvp, leagues) { ], texts: [{ name: 'min_spawn_avg', type: 'number', xs: 6, sm: 6 }], distanceOrArea: { - booleans: [{ name: 'byDistance', max: hookConfig.maxDistance, xs: 6, sm: 8, override: true }], - texts: [{ name: 'distance', type: 'number', adornment: 'm', xs: 6, sm: 4 }], + booleans: [ + { + name: 'byDistance', + max: hookConfig.maxDistance, + xs: 6, + sm: 8, + override: true, + }, + ], + texts: [ + { + name: 'distance', + type: 'number', + adornment: 'm', + xs: 6, + sm: 4, + }, + ], }, }, }, }, } - Object.values(poracleUiObj).forEach(category => { - if (typeof category === 'object' && category?.ui?.global - && hookConfig.everythingFlagPermissions === 'allow-any') { - category.ui.global.booleans.push({ name: 'everything_individually', xs: 12, sm: 12, override: true }) + Object.values(poracleUiObj).forEach((category) => { + if ( + typeof category === 'object' && + category?.ui?.global && + hookConfig.everythingFlagPermissions === 'allow-any' + ) { + category.ui.global.booleans.push({ + name: 'everything_individually', + xs: 12, + sm: 12, + override: true, + }) } }) return poracleUiObj } - default: return {} + default: + return {} } } diff --git a/server/src/strategies/discord.js b/server/src/strategies/discord.js index 46a34a9b4..96331aad1 100644 --- a/server/src/strategies/discord.js +++ b/server/src/strategies/discord.js @@ -53,7 +53,11 @@ const authHandler = async (req, accessToken, refreshToken, profile, done) => { .then(async (userExists) => { if (req.user && userExists?.strategy === 'local') { await User.query() - .update({ discordId: user.id, discordPerms: JSON.stringify(user.perms), webhookStrategy: 'discord' }) + .update({ + discordId: user.id, + discordPerms: JSON.stringify(user.perms), + webhookStrategy: 'discord', + }) .where('id', req.user.id) await User.query() .where('discordId', user.id) @@ -68,8 +72,11 @@ const authHandler = async (req, accessToken, refreshToken, profile, done) => { }) } if (!userExists) { - userExists = await User.query() - .insertAndFetch({ discordId: user.id, strategy: 'discord', tutorial: !forceTutorial }) + userExists = await User.query().insertAndFetch({ + discordId: user.id, + strategy: 'discord', + tutorial: !forceTutorial, + }) } if (userExists.strategy !== 'discord') { await User.query() @@ -78,19 +85,31 @@ const authHandler = async (req, accessToken, refreshToken, profile, done) => { userExists.strategy = 'discord' } if (userExists.id >= 25000) { - console.warn('[USER] User ID is higher than 25,000! This may indicate that a Discord ID was saved as the User ID\nYou should rerun the migrations with "yarn migrate:rollback && yarn migrate:latest"') + console.warn( + '[USER] User ID is higher than 25,000! This may indicate that a Discord ID was saved as the User ID\nYou should rerun the migrations with "yarn migrate:rollback && yarn migrate:latest"', + ) } - return done(null, { ...user, ...userExists, username: userExists.username || user.username }) + return done(null, { + ...user, + ...userExists, + username: userExists.username || user.username, + }) }) } catch (e) { console.error('[AUTH] User has failed Discord auth.', e) } } -passport.use(path.parse(__filename).name, new DiscordStrategy({ - clientID: strategyConfig.clientId, - clientSecret: strategyConfig.clientSecret, - callbackURL: strategyConfig.redirectUri, - scope: ['identify', 'guilds'], - passReqToCallback: true, -}, authHandler)) +passport.use( + path.parse(__filename).name, + new DiscordStrategy( + { + clientID: strategyConfig.clientId, + clientSecret: strategyConfig.clientSecret, + callbackURL: strategyConfig.redirectUri, + scope: ['identify', 'guilds'], + passReqToCallback: true, + }, + authHandler, + ), +) diff --git a/server/src/strategies/local.js b/server/src/strategies/local.js index 95f4a9975..48d46b77d 100644 --- a/server/src/strategies/local.js +++ b/server/src/strategies/local.js @@ -6,7 +6,11 @@ const path = require('path') const { map: { forceTutorial }, - authentication: { [path.parse(__filename).name]: strategyConfig, alwaysEnabledPerms, perms }, + authentication: { + [path.parse(__filename).name]: strategyConfig, + alwaysEnabledPerms, + perms, + }, } = require('../services/config') const { User } = require('../models/index') const Utility = require('../services/Utility') @@ -16,12 +20,16 @@ if (strategyConfig.doNothing) { } const authHandler = async (req, username, password, done) => { - const localPerms = Object.keys(perms).filter(key => perms[key].roles.includes('local')) + const localPerms = Object.keys(perms).filter((key) => + perms[key].roles.includes('local'), + ) const user = { perms: { ...Object.fromEntries( - Object.keys(perms) - .map(perm => [perm, localPerms.includes(perm) || alwaysEnabledPerms.includes(perm)]), + Object.keys(perms).map((perm) => [ + perm, + localPerms.includes(perm) || alwaysEnabledPerms.includes(perm), + ]), ), areaRestrictions: Utility.areaPerms(localPerms, 'local'), webhooks: [], @@ -35,22 +43,26 @@ const authHandler = async (req, username, password, done) => { .then(async (userExists) => { if (!userExists) { try { - const newUser = await User.query() - .insertAndFetch({ - username, - password: await bcrypt.hash(password, 10), - strategy: 'local', - tutorial: !forceTutorial, - }) + const newUser = await User.query().insertAndFetch({ + username, + password: await bcrypt.hash(password, 10), + strategy: 'local', + tutorial: !forceTutorial, + }) user.id = newUser.id - console.log('[LOCAL]', user.username, `(${user.id})`, 'Authenticated successfully.') + console.log( + '[LOCAL]', + user.username, + `(${user.id})`, + 'Authenticated successfully.', + ) return done(null, user) } catch (e) { return done(null, user, { message: 'error_creating_user' }) } } if (bcrypt.compareSync(password, userExists.password)) { - ['discordPerms', 'telegramPerms'].forEach((permSet) => { + ;['discordPerms', 'telegramPerms'].forEach((permSet) => { if (userExists[permSet]) { user.perms = Utility.mergePerms(user.perms, userExists[permSet]) } @@ -62,7 +74,12 @@ const authHandler = async (req, username, password, done) => { userExists.strategy = 'local' } user.id = userExists.id - console.log('[LOCAL]', user.username, `(${user.id})`, 'Authenticated successfully.') + console.log( + '[LOCAL]', + user.username, + `(${user.id})`, + 'Authenticated successfully.', + ) return done(null, user) } return done(null, false, { message: 'invalid_credentials' }) @@ -72,8 +89,14 @@ const authHandler = async (req, username, password, done) => { } } -passport.use(path.parse(__filename).name, new Strategy({ - usernameField: 'username', - passwordField: 'password', - passReqToCallback: true, -}, authHandler)) +passport.use( + path.parse(__filename).name, + new Strategy( + { + usernameField: 'username', + passwordField: 'password', + passReqToCallback: true, + }, + authHandler, + ), +) diff --git a/server/src/strategies/telegram.js b/server/src/strategies/telegram.js index 604325528..38846624e 100644 --- a/server/src/strategies/telegram.js +++ b/server/src/strategies/telegram.js @@ -5,7 +5,11 @@ const path = require('path') const { map: { forceTutorial }, - authentication: { [path.parse(__filename).name]: strategyConfig, perms, alwaysEnabledPerms }, + authentication: { + [path.parse(__filename).name]: strategyConfig, + perms, + alwaysEnabledPerms, + }, } = require('../services/config') const { User } = require('../models/index') const Fetch = require('../services/Fetch') @@ -15,34 +19,50 @@ const authHandler = async (req, profile, done) => { const user = { ...profile, perms: { - ...Object.fromEntries(Object.keys(perms).map(x => [x, false])), + ...Object.fromEntries(Object.keys(perms).map((x) => [x, false])), areaRestrictions: [], webhooks: [], }, } const chatInfo = [user.id] - await Promise.all(strategyConfig.groups.map(async (group) => { - try { - const response = await Fetch.json(`https://api.telegram.org/bot${strategyConfig.botToken}/getChatMember?chat_id=${group}&user_id=${user.id}`) - if (!response) { - throw new Error('Unable to query TG API or User is not in the group') - } - if (!response.ok) { - throw new Error(`Telegram API error: ${response.status} ${response.statusText}`) - } - if (response.result.status !== 'left' && response.result.status !== 'kicked') { - chatInfo.push(group) + await Promise.all( + strategyConfig.groups.map(async (group) => { + try { + const response = await Fetch.json( + `https://api.telegram.org/bot${strategyConfig.botToken}/getChatMember?chat_id=${group}&user_id=${user.id}`, + ) + if (!response) { + throw new Error('Unable to query TG API or User is not in the group') + } + if (!response.ok) { + throw new Error( + `Telegram API error: ${response.status} ${response.statusText}`, + ) + } + if ( + response.result.status !== 'left' && + response.result.status !== 'kicked' + ) { + chatInfo.push(group) + } + } catch (e) { + console.error( + e.message, + `Telegram Group: ${group}`, + `User: ${user.id} (${user.username})`, + ) + return null } - } catch (e) { - console.error(e.message, `Telegram Group: ${group}`, `User: ${user.id} (${user.username})`) - return null - } - })) + }), + ) Object.entries(perms).forEach(([perm, info]) => { - if (info.enabled && (alwaysEnabledPerms.includes(perm) - || info.roles.some(role => chatInfo.includes(role)))) { + if ( + info.enabled && + (alwaysEnabledPerms.includes(perm) || + info.roles.some((role) => chatInfo.includes(role))) + ) { user.perms[perm] = true } }) @@ -57,13 +77,22 @@ const authHandler = async (req, profile, done) => { .then(async (userExists) => { if (req.user && userExists?.strategy === 'local') { await User.query() - .update({ telegramId: user.id, telegramPerms: JSON.stringify(user.perms), webhookStrategy: 'telegram' }) + .update({ + telegramId: user.id, + telegramPerms: JSON.stringify(user.perms), + webhookStrategy: 'telegram', + }) .where('id', req.user.id) await User.query() .where('telegramId', user.id) .whereNot('id', req.user.id) .delete() - console.log('[TELEGRAM]', user.username, `(${user.id})`, 'Authenticated successfully.') + console.log( + '[TELEGRAM]', + user.username, + `(${user.id})`, + 'Authenticated successfully.', + ) return done(null, { ...user, ...req.user, @@ -73,8 +102,11 @@ const authHandler = async (req, profile, done) => { }) } if (!userExists) { - userExists = await User.query() - .insertAndFetch({ telegramId: user.id, strategy: user.provider, tutorial: !forceTutorial }) + userExists = await User.query().insertAndFetch({ + telegramId: user.id, + strategy: user.provider, + tutorial: !forceTutorial, + }) } if (userExists.strategy !== 'telegram') { await User.query() @@ -83,17 +115,34 @@ const authHandler = async (req, profile, done) => { userExists.strategy = 'telegram' } if (userExists.id >= 25000) { - console.warn('[USER] User ID is higher than 25,000! This may indicate that a Telegram ID was saved as the User ID\nYou should rerun the migrations with "yarn migrate:rollback && yarn migrate:latest"') + console.warn( + '[USER] User ID is higher than 25,000! This may indicate that a Telegram ID was saved as the User ID\nYou should rerun the migrations with "yarn migrate:rollback && yarn migrate:latest"', + ) } - console.log('[TELEGRAM]', user.username, `(${user.id})`, 'Authenticated successfully.') - return done(null, { ...user, ...userExists, username: userExists.username || user.username }) + console.log( + '[TELEGRAM]', + user.username, + `(${user.id})`, + 'Authenticated successfully.', + ) + return done(null, { + ...user, + ...userExists, + username: userExists.username || user.username, + }) }) } catch (e) { console.error('[TELEGRAM] User has failed Telegram auth.', e) } } -passport.use(path.parse(__filename).name, new TelegramStrategy({ - botToken: strategyConfig.botToken, - passReqToCallback: true, -}, authHandler)) +passport.use( + path.parse(__filename).name, + new TelegramStrategy( + { + botToken: strategyConfig.botToken, + passReqToCallback: true, + }, + authHandler, + ), +) diff --git a/src/assets/mui/theme.js b/src/assets/mui/theme.js index 5ac2a01e8..1d114f344 100644 --- a/src/assets/mui/theme.js +++ b/src/assets/mui/theme.js @@ -2,80 +2,82 @@ import { responsiveFontSizes } from '@material-ui/core' import { createTheme } from '@material-ui/core/styles' export default function setTheme(theme) { - return responsiveFontSizes(createTheme({ - palette: { - type: 'dark', - primary: { - light: '#ff784e', - main: theme?.primary || '#ff5722', - dark: '#b23c17', - contrastText: '#fff', - }, - secondary: { - light: '#33bfff', - main: theme?.secondary || '#00b0ff', - dark: '#007bb2', - contrastText: '#fff', - }, - action: { - main: '#00e676', - contrastText: '#fff', - active: '#00e676', - }, - grey: { - light: '#bdbdbd', - main: '#333333', - dark: '#424242', - contrastText: '#fff', - }, - background: { - paper: '#333333', - default: '#333333', - }, - text: { - primary: '#f5f5f5', - secondary: 'white', - hint: '#a0a0a0', - }, - }, - props: { - MuiButtonBase: { - disableRipple: true, - }, - }, - overrides: { - MuiDialogTitle: { - root: { - padding: '12px 24px', + return responsiveFontSizes( + createTheme({ + palette: { + type: 'dark', + primary: { + light: '#ff784e', + main: theme?.primary || '#ff5722', + dark: '#b23c17', + contrastText: '#fff', + }, + secondary: { + light: '#33bfff', + main: theme?.secondary || '#00b0ff', + dark: '#007bb2', + contrastText: '#fff', + }, + action: { + main: '#00e676', + contrastText: '#fff', + active: '#00e676', + }, + grey: { + light: '#bdbdbd', + main: '#333333', + dark: '#424242', + contrastText: '#fff', + }, + background: { + paper: '#333333', + default: '#333333', + }, + text: { + primary: '#f5f5f5', + secondary: 'white', + hint: '#a0a0a0', }, }, - MuiAccordion: { - root: { - '&$expanded': { - margin: '1px 0', - }, + props: { + MuiButtonBase: { + disableRipple: true, }, }, - MuiAccordionSummary: { - root: { - '&$expanded': { - minHeight: 10, + overrides: { + MuiDialogTitle: { + root: { + padding: '12px 24px', }, }, - content: { - '&$expanded': { - margin: '10px 0', + MuiAccordion: { + root: { + '&$expanded': { + margin: '1px 0', + }, }, }, - }, - MuiSelect: { - icon: { - color: 'white', + MuiAccordionSummary: { + root: { + '&$expanded': { + minHeight: 10, + }, + }, + content: { + '&$expanded': { + margin: '10px 0', + }, + }, }, - iconOpen: { - color: 'white', + MuiSelect: { + icon: { + color: 'white', + }, + iconOpen: { + color: 'white', + }, }, }, - }, - })) + }), + ) } diff --git a/src/components/Clustering.jsx b/src/components/Clustering.jsx index 3e38a4d20..0ecfafbbe 100644 --- a/src/components/Clustering.jsx +++ b/src/components/Clustering.jsx @@ -7,18 +7,32 @@ import Notification from './layout/general/Notification' const ignoredClustering = ['devices', 'submissionCells', 'scanCells', 'weather'] export default function Clustering({ - category, renderedData, userSettings, clusteringRules, staticUserSettings, params, - filters, map, Icons, perms, tileStyle, config, userIcons, setParams, isNight, + category, + renderedData, + userSettings, + clusteringRules, + staticUserSettings, + params, + filters, + map, + Icons, + perms, + tileStyle, + config, + userIcons, + setParams, + isNight, }) { const Component = index[category] - const hideList = useStatic(state => state.hideList) - const excludeList = useStatic(state => state.excludeList) - const timerList = useStatic(state => state.timerList) + const hideList = useStatic((state) => state.hideList) + const excludeList = useStatic((state) => state.excludeList) + const timerList = useStatic((state) => state.timerList) const ts = Math.floor(Date.now() / 1000) const currentZoom = map.getZoom() - const showCircles = userSettings.interactionRanges && currentZoom >= config.interactionRangeZoom + const showCircles = + userSettings.interactionRanges && currentZoom >= config.interactionRangeZoom const finalData = renderedData.map((each) => { if (!each) return null @@ -51,8 +65,9 @@ export default function Clustering({ return null }) - const limitHit = finalData.length > clusteringRules.forcedLimit - && !ignoredClustering.includes(category) + const limitHit = + finalData.length > clusteringRules.forcedLimit && + !ignoredClustering.includes(category) return limitHit || (clusteringRules.zoomLevel && userSettings.clustering) ? ( <> @@ -80,5 +95,7 @@ export default function Clustering({ /> )} - ) : finalData + ) : ( + finalData + ) } diff --git a/src/components/Config.jsx b/src/components/Config.jsx index 1d27f925b..c21c44381 100644 --- a/src/components/Config.jsx +++ b/src/components/Config.jsx @@ -25,9 +25,17 @@ export default function Config() { const data = await Fetch.getSettings() if (data?.config && data?.masterfile) { if (data.masterfile?.questRewardTypes) { - localStorage.setItem('questRewardTypes', JSON.stringify(data.masterfile.questRewardTypes)) + localStorage.setItem( + 'questRewardTypes', + JSON.stringify(data.masterfile.questRewardTypes), + ) } - const Icons = new UIcons(data.config.icons, data.masterfile ? data.masterfile.questRewardTypes : JSON.parse(localStorage.getItem('questRewardTypes'))) + const Icons = new UIcons( + data.config.icons, + data.masterfile + ? data.masterfile.questRewardTypes + : JSON.parse(localStorage.getItem('questRewardTypes')), + ) if (Icons) { Icons.build(data.config.icons.styles) if (data.config.icons.defaultIcons) { @@ -53,9 +61,16 @@ export default function Config() { return ( - + - + ) } diff --git a/src/components/Container.jsx b/src/components/Container.jsx index 46dbfbfa9..2f9040d24 100644 --- a/src/components/Container.jsx +++ b/src/components/Container.jsx @@ -18,11 +18,8 @@ export default function Container({ serverSettings, params, location, zoom }) { zoomControl={false} preferCanvas > - {(serverSettings.user && serverSettings.user.perms.map) && ( - + {serverSettings.user && serverSettings.user.perms.map && ( + )} ) diff --git a/src/components/ErrorBoundary.jsx b/src/components/ErrorBoundary.jsx index 5374d57c1..956032ead 100644 --- a/src/components/ErrorBoundary.jsx +++ b/src/components/ErrorBoundary.jsx @@ -22,18 +22,27 @@ class ErrorBoundary extends Component { render() { return this.state.hasError ? ( - + {this.props.t('react_error')} - + {this.state.message}

- ) : this.props.children + ) : ( + this.props.children + ) } } diff --git a/src/components/Errors.jsx b/src/components/Errors.jsx index 51b7ae6b7..f267c955f 100644 --- a/src/components/Errors.jsx +++ b/src/components/Errors.jsx @@ -25,7 +25,11 @@ export default function Errors() {
- diff --git a/src/components/HolidayEffects.jsx b/src/components/HolidayEffects.jsx index 483b66ae7..826b72f3f 100644 --- a/src/components/HolidayEffects.jsx +++ b/src/components/HolidayEffects.jsx @@ -4,20 +4,36 @@ import HolidayAnimations from '@services/HolidayAnimations' export default function HolidayEffects({ mapSettings }) { const date = new Date() - if (mapSettings.valentinesDay && date.getMonth() === 1 && date.getDate() === 14) { - const heart = new HolidayAnimations('https://upload.wikimedia.org/wikipedia/commons/thumb/8/86/A_perfect_SVG_heart.svg/20px-A_perfect_SVG_heart.svg.png') + if ( + mapSettings.valentinesDay && + date.getMonth() === 1 && + date.getDate() === 14 + ) { + const heart = new HolidayAnimations( + 'https://upload.wikimedia.org/wikipedia/commons/thumb/8/86/A_perfect_SVG_heart.svg/20px-A_perfect_SVG_heart.svg.png', + ) heart.initialize() return null } - if (mapSettings.internationalWomensDay && date.getMonth() === 2 && date.getDate() === 8) { - const flower = new HolidayAnimations('https://upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Emoji_u1f338.svg/20px-Emoji_u1f338.svg.png') + if ( + mapSettings.internationalWomensDay && + date.getMonth() === 2 && + date.getDate() === 8 + ) { + const flower = new HolidayAnimations( + 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Emoji_u1f338.svg/20px-Emoji_u1f338.svg.png', + ) flower.initialize() return null } - if (mapSettings.christmasSnow - && date.getMonth() === 11 && date.getDate() >= 24 && date.getDate() <= 30) { + if ( + mapSettings.christmasSnow && + date.getMonth() === 11 && + date.getDate() >= 24 && + date.getDate() <= 30 + ) { return (
@@ -29,8 +45,11 @@ export default function HolidayEffects({ mapSettings }) {
) } - if (mapSettings.newYearsFireworks - && ((date.getMonth() === 11 && date.getDate() === 31) || (date.getMonth() === 0 && date.getDate() === 1))) { + if ( + mapSettings.newYearsFireworks && + ((date.getMonth() === 11 && date.getDate() === 31) || + (date.getMonth() === 0 && date.getDate() === 1)) + ) { return (
diff --git a/src/components/Map.jsx b/src/components/Map.jsx index 114259bc0..ba4617b6a 100644 --- a/src/components/Map.jsx +++ b/src/components/Map.jsx @@ -14,30 +14,41 @@ import ScanNext from './layout/dialogs/scanner/ScanNext' import ScanZone from './layout/dialogs/scanner/ScanZone' import ClientError from './layout/dialogs/ClientError' -const userSettingsCategory = category => { +const userSettingsCategory = (category) => { switch (category) { case 'devices': case 'spawnpoints': - case 'scanCells': return 'admin' + case 'scanCells': + return 'admin' case 'submissionCells': - case 'portals': return 'wayfarer' - default: return category + case 'portals': + return 'wayfarer' + default: + return category } } const getTileServer = (tileServers, settings, isNight) => { - const fallbackTs = Object.values(tileServers).find(server => server.name !== 'auto') + const fallbackTs = Object.values(tileServers).find( + (server) => server.name !== 'auto', + ) if (tileServers?.[settings.tileServers]?.name === 'auto') { const autoTile = isNight - ? Object.values(tileServers).find(server => server.style === 'dark') - : Object.values(tileServers).find(server => server.style === 'light') + ? Object.values(tileServers).find((server) => server.style === 'dark') + : Object.values(tileServers).find((server) => server.style === 'light') return autoTile || fallbackTs } return tileServers[settings.tileServers] || fallbackTs } -export default function Map({ serverSettings: - { config: { map: config, tileServers, scanner }, Icons, webhooks }, params }) { +export default function Map({ + serverSettings: { + config: { map: config, tileServers, scanner }, + Icons, + webhooks, + }, + params, +}) { Utility.analytics(window.location.pathname) const map = useMap() @@ -47,21 +58,21 @@ export default function Map({ serverSettings: const isMobile = useMediaQuery(theme.breakpoints.only('xs')) const isTablet = useMediaQuery(theme.breakpoints.only('sm')) - const staticUserSettings = useStatic(state => state.userSettings) - const ui = useStatic(state => state.ui) - const staticFilters = useStatic(state => state.filters) - const setExcludeList = useStatic(state => state.setExcludeList) - const active = useStatic(state => state.active) - const setActive = useStatic(state => state.setActive) - - const filters = useStore(state => state.filters) - const settings = useStore(state => state.settings) - const icons = useStore(state => state.icons) - const setLocation = useStore(s => s.setLocation) - const isNight = useStatic(state => state.isNight) - const setIsNight = useStatic(state => state.setIsNight) - const setZoom = useStore(state => state.setZoom) - const userSettings = useStore(state => state.userSettings) + const staticUserSettings = useStatic((state) => state.userSettings) + const ui = useStatic((state) => state.ui) + const staticFilters = useStatic((state) => state.filters) + const setExcludeList = useStatic((state) => state.setExcludeList) + const active = useStatic((state) => state.active) + const setActive = useStatic((state) => state.setActive) + + const filters = useStore((state) => state.filters) + const settings = useStore((state) => state.settings) + const icons = useStore((state) => state.icons) + const setLocation = useStore((s) => s.setLocation) + const isNight = useStatic((state) => state.isNight) + const setIsNight = useStatic((state) => state.setIsNight) + const setZoom = useStore((state) => state.setZoom) + const userSettings = useStore((state) => state.userSettings) const [webhookMode, setWebhookMode] = useState(false) const [scanNextMode, setScanNextMode] = useState(false) @@ -69,21 +80,29 @@ export default function Map({ serverSettings: const [manualParams, setManualParams] = useState(params) const [error, setError] = useState('') const [windowState, setWindowState] = useState(true) - const [lc] = useState(L.control.locate({ - position: 'bottomright', - icon: 'fas fa-location-arrow', - keepCurrentZoomLevel: true, - setView: 'untilPan', - })) - - const onMove = useCallback((latLon) => { - const newCenter = latLon || map.getCenter() - setLocation([newCenter.lat, newCenter.lng]) - setZoom(Math.floor(map.getZoom())) - setIsNight(Utility.nightCheck(newCenter.lat, newCenter.lng)) - }, [map]) - - const tileServer = useMemo(() => getTileServer(tileServers, settings, isNight), [isNight, settings.tileServers]) + const [lc] = useState( + L.control.locate({ + position: 'bottomright', + icon: 'fas fa-location-arrow', + keepCurrentZoomLevel: true, + setView: 'untilPan', + }), + ) + + const onMove = useCallback( + (latLon) => { + const newCenter = latLon || map.getCenter() + setLocation([newCenter.lat, newCenter.lng]) + setZoom(Math.floor(map.getZoom())) + setIsNight(Utility.nightCheck(newCenter.lat, newCenter.lng)) + }, + [map], + ) + + const tileServer = useMemo( + () => getTileServer(tileServers, settings, isNight), + [isNight, settings.tileServers], + ) const onFocus = () => setWindowState(true) @@ -99,7 +118,10 @@ export default function Map({ serverSettings: }, []) useEffect(() => { - const timer = setTimeout(() => setActive(windowState), 1000 * 60 * config.clientTimeoutMinutes) + const timer = setTimeout( + () => setActive(windowState), + 1000 * 60 * config.clientTimeoutMinutes, + ) if (windowState) { clearTimeout(timer) setActive(windowState) @@ -120,13 +142,18 @@ export default function Map({ serverSettings: - {settings.navigationControls === 'leaflet' && } - {(webhooks && webhookMode) ? ( + {settings.navigationControls === 'leaflet' && ( + + )} + {webhooks && webhookMode ? ( ) : ( - Object.entries({ ...ui, ...ui.wayfarer, ...ui.admin }).map(([category, value]) => { - let enabled = false - - switch (category) { - case 'scanAreas': - if ((filters[category] && filters[category].enabled) - || webhookMode === 'areas') { - enabled = true - } break - case 'gyms': - if (((filters[category].allGyms && value.allGyms) - || (filters[category].raids && value.raids) - || (filters[category].exEligible && value.exEligible) - || (filters[category].inBattle && value.inBattle) - || (filters[category].arEligible && value.arEligible) - || (filters[category].gymBadges && value.gymBadges)) - && !webhookMode) { - enabled = true - } break - case 'nests': - if (((filters[category].pokemon && value.pokemon) - || (filters[category].polygons && value.polygons)) - && !webhookMode) { - enabled = true - } break - case 'pokestops': - if (((filters[category].allPokestops && value.allPokestops) - || (filters[category].lures && value.lures) - || (filters[category].invasions && value.invasions) - || (filters[category].quests && value.quests) - || (filters[category].arEligible && value.arEligible)) - && !webhookMode) { - enabled = true - } break - default: - if (filters[category] - && filters[category].enabled - && value && !webhookMode) { - enabled = true - } break - } - if (enabled && !error) { - Utility.analytics('Data', `${category} being fetched`, category, true) - return ( - x ? x.size : 'md').join(',') : 'md'} - bounds={Utility.getQueryArgs(map)} - setExcludeList={setExcludeList} - onMove={onMove} - perms={value} - map={map} - category={category} - config={config} - Icons={Icons} - staticFilters={staticFilters[category].filter} - userIcons={icons} - userSettings={userSettings[userSettingsCategory(category)] || {}} - filters={filters[category]} - tileStyle={tileServer?.style || 'light'} - clusteringRules={config?.clustering?.[category] || { zoomLimit: config.minZoom, forcedLimit: 10000 }} - staticUserSettings={staticUserSettings[category]} - params={manualParams} - setParams={setManualParams} - isNight={isNight} - isMobile={isMobile} - setError={setError} - active={active} - /> - ) - } - return null - }) + Object.entries({ ...ui, ...ui.wayfarer, ...ui.admin }).map( + ([category, value]) => { + let enabled = false + + switch (category) { + case 'scanAreas': + if ( + (filters[category] && filters[category].enabled) || + webhookMode === 'areas' + ) { + enabled = true + } + break + case 'gyms': + if ( + ((filters[category].allGyms && value.allGyms) || + (filters[category].raids && value.raids) || + (filters[category].exEligible && value.exEligible) || + (filters[category].inBattle && value.inBattle) || + (filters[category].arEligible && value.arEligible) || + (filters[category].gymBadges && value.gymBadges)) && + !webhookMode + ) { + enabled = true + } + break + case 'nests': + if ( + ((filters[category].pokemon && value.pokemon) || + (filters[category].polygons && value.polygons)) && + !webhookMode + ) { + enabled = true + } + break + case 'pokestops': + if ( + ((filters[category].allPokestops && value.allPokestops) || + (filters[category].lures && value.lures) || + (filters[category].invasions && value.invasions) || + (filters[category].quests && value.quests) || + (filters[category].arEligible && value.arEligible)) && + !webhookMode + ) { + enabled = true + } + break + default: + if ( + filters[category] && + filters[category].enabled && + value && + !webhookMode + ) { + enabled = true + } + break + } + if (enabled && !error) { + Utility.analytics( + 'Data', + `${category} being fetched`, + category, + true, + ) + return ( + (x ? x.size : 'md')) + .join(',') + : 'md' + } + bounds={Utility.getQueryArgs(map)} + setExcludeList={setExcludeList} + onMove={onMove} + perms={value} + map={map} + category={category} + config={config} + Icons={Icons} + staticFilters={staticFilters[category].filter} + userIcons={icons} + userSettings={ + userSettings[userSettingsCategory(category)] || {} + } + filters={filters[category]} + tileStyle={tileServer?.style || 'light'} + clusteringRules={ + config?.clustering?.[category] || { + zoomLimit: config.minZoom, + forcedLimit: 10000, + } + } + staticUserSettings={staticUserSettings[category]} + params={manualParams} + setParams={setManualParams} + isNight={isNight} + isMobile={isMobile} + setError={setError} + active={active} + /> + ) + } + return null + }, + ) )} {scanNextMode && ( { - const trimmed = { - onlyLegacyExclude: [], - onlyLegacy: userSettings.legacyFilter, - onlyLinkGlobal: userSettings.linkGlobalAndAdvanced, - } - Object.entries(requestedFilters).forEach(topLevelFilter => { - const [id, specifics] = topLevelFilter - - if (!filterSkipList.includes(id)) { - trimmed[`only${id.charAt(0).toUpperCase()}${id.slice(1)}`] = specifics - } - }) - Object.entries(userSettings).forEach(([entryK, entryV]) => { - if (entryK.startsWith('pvp')) { - trimmed[`only${entryK.charAt(0).toUpperCase()}${entryK.slice(1)}`] = entryV + const trimFilters = useCallback( + (requestedFilters) => { + const trimmed = { + onlyLegacyExclude: [], + onlyLegacy: userSettings.legacyFilter, + onlyLinkGlobal: userSettings.linkGlobalAndAdvanced, } - }) - Object.entries(requestedFilters.filter).forEach(filter => { - const [id, specifics] = filter + Object.entries(requestedFilters).forEach((topLevelFilter) => { + const [id, specifics] = topLevelFilter - if (specifics && specifics.enabled && staticFilters[id]) { - trimmed[id] = specifics - } else if (userSettings.legacyFilter) { - trimmed.onlyLegacyExclude.push(id) - } - }) - return trimmed - }, [userSettings, filters]) + if (!filterSkipList.includes(id)) { + trimmed[`only${id.charAt(0).toUpperCase()}${id.slice(1)}`] = specifics + } + }) + Object.entries(userSettings).forEach(([entryK, entryV]) => { + if (entryK.startsWith('pvp')) { + trimmed[`only${entryK.charAt(0).toUpperCase()}${entryK.slice(1)}`] = + entryV + } + }) + Object.entries(requestedFilters.filter).forEach((filter) => { + const [id, specifics] = filter + + if (specifics && specifics.enabled && staticFilters[id]) { + trimmed[id] = specifics + } else if (userSettings.legacyFilter) { + trimmed.onlyLegacyExclude.push(id) + } + }) + return trimmed + }, + [userSettings, filters], + ) const refetchData = () => { onMove() - if (category !== 'weather' - && category !== 'device' - && category !== 'scanAreas') { + if ( + category !== 'weather' && + category !== 'device' && + category !== 'scanAreas' + ) { refetch({ ...Utility.getQueryArgs(map), filters: trimFilters(filters), @@ -98,8 +122,10 @@ export default function QueryData({ /> ) } - const message = error?.networkError?.result?.errors?.find(x => x?.message === 'old_client')?.message - || error?.message + const message = + error?.networkError?.result?.errors?.find( + (x) => x?.message === 'old_client', + )?.message || error?.message if (message === 'session_expired' || message === 'old_client') { setError(message) return null diff --git a/src/components/ReactRouter.jsx b/src/components/ReactRouter.jsx index 36013cd5e..4aed36075 100644 --- a/src/components/ReactRouter.jsx +++ b/src/components/ReactRouter.jsx @@ -20,13 +20,13 @@ export default function ReactRouter({ serverSettings, getServerSettings }) { } /> - )} + } /> diff --git a/src/components/WebhookQuery.jsx b/src/components/WebhookQuery.jsx index 170ff42c4..06c130506 100644 --- a/src/components/WebhookQuery.jsx +++ b/src/components/WebhookQuery.jsx @@ -4,11 +4,18 @@ import { useQuery } from '@apollo/client' import Query from '@services/Query' import Container from './Container' -export default function WebhookQuery({ params, serverSettings, location, zoom }) { +export default function WebhookQuery({ + params, + serverSettings, + location, + zoom, +}) { let lowercase = params.category.toLowerCase() - if (lowercase === 'invasions' - || lowercase === 'lures' - || lowercase === 'quests') { + if ( + lowercase === 'invasions' || + lowercase === 'lures' || + lowercase === 'quests' + ) { lowercase = 'pokestops' } if (lowercase === 'raids') { @@ -23,9 +30,11 @@ export default function WebhookQuery({ params, serverSettings, location, zoom }) }) return data ? ( state.config) - const { loggedIn } = useStatic(state => state.auth) + const { + map: { enableFloatingProfileButton }, + scanner: { scannerType, enableScanNext, enableScanZone }, + } = useStatic((state) => state.config) + const { loggedIn } = useStatic((state) => state.auth) const map = useMap() const ref = useRef(null) const classes = useStyles() const { lc, color } = useLocation(map) - const selectedWebhook = useStore(s => s.selectedWebhook) + const selectedWebhook = useStore((s) => s.selectedWebhook) const fabSize = isMobile ? 'small' : 'large' const iconSize = isMobile ? 'small' : 'medium' @@ -43,10 +67,14 @@ export default function FloatingButtons({ L.DomEvent.disableClickPropagation(ref.current) }, []) - const showDonorPage = (perms.donor ? donationPage.showToDonors : true) - && donationPage.showOnMap && donationPage.components.length + const showDonorPage = + (perms.donor ? donationPage.showToDonors : true) && + donationPage.showOnMap && + donationPage.components.length - const DonorIcon = showDonorPage ? DonationIcons[donationPage.fabIcon || 'card'] : null + const DonorIcon = showDonorPage + ? DonationIcons[donationPage.fabIcon || 'card'] + : null return ( - + {enableFloatingProfileButton && loggedIn && ( - setUserProfile(true)} title={t('user_profile')} disabled={Boolean(webhookMode) || Boolean(scanNextMode) || Boolean(scanZoneMode)}> + setUserProfile(true)} + title={t('user_profile')} + disabled={ + Boolean(webhookMode) || + Boolean(scanNextMode) || + Boolean(scanZoneMode) + } + > )} {safeSearch.length ? ( - + ) : null} - {(perms?.webhooks?.length && webhooks && selectedWebhook) ? ( + {perms?.webhooks?.length && webhooks && selectedWebhook ? ( setWebhookMode('open')} title={selectedWebhook} - disabled={Boolean(webhookMode) || Boolean(scanNextMode) || Boolean(scanZoneMode)} + disabled={ + Boolean(webhookMode) || + Boolean(scanNextMode) || + Boolean(scanZoneMode) + } > ) : null} - {(perms?.scanner?.includes('scanNext') && enableScanNext) ? ( + {perms?.scanner?.includes('scanNext') && enableScanNext ? ( - scanNextMode === 'setLocation' ? setScanNextMode(false) : setScanNextMode('setLocation')} title={t('scan_next')} disabled={Boolean(webhookMode) || Boolean(scanZoneMode)}> + + scanNextMode === 'setLocation' + ? setScanNextMode(false) + : setScanNextMode('setLocation') + } + title={t('scan_next')} + disabled={Boolean(webhookMode) || Boolean(scanZoneMode)} + > ) : null} - {(perms?.scanner?.includes('scanZone') && enableScanZone && scannerType === 'rdm') ? ( + {perms?.scanner?.includes('scanZone') && + enableScanZone && + scannerType === 'rdm' ? ( - scanZoneMode === 'setLocation' ? setScanZoneMode(false) : setScanZoneMode('setLocation')} title={t('scan_zone')} disabled={Boolean(webhookMode) || Boolean(scanNextMode)}> + + scanZoneMode === 'setLocation' + ? setScanZoneMode(false) + : setScanZoneMode('setLocation') + } + title={t('scan_zone')} + disabled={Boolean(webhookMode) || Boolean(scanNextMode)} + > ) : null} {showDonorPage ? ( - setDonorPage(true)} title={t('donor_menu')} disabled={Boolean(webhookMode) || Boolean(scanNextMode) || Boolean(scanZoneMode)}> + setDonorPage(true)} + title={t('donor_menu')} + disabled={ + Boolean(webhookMode) || + Boolean(scanNextMode) || + Boolean(scanZoneMode) + } + > @@ -114,17 +210,32 @@ export default function FloatingButtons({ {settings.navigationControls === 'react' ? ( <> - lc._onClick()} title={t('use_my_location')}> + lc._onClick()} + title={t('use_my_location')} + > - map.zoomIn()} title={t('zoom_in')}> + map.zoomIn()} + title={t('zoom_in')} + > - map.zoomOut()} title={t('zoom_out')}> + map.zoomOut()} + title={t('zoom_out')} + > @@ -132,7 +243,12 @@ export default function FloatingButtons({ ) : null} {(webhookMode === 'areas' || webhookMode === 'location') && ( - setWebhookMode('open')} title={t('save')}> + setWebhookMode('open')} + title={t('save')} + > diff --git a/src/components/layout/Nav.jsx b/src/components/layout/Nav.jsx index 9b63754c1..65c98f19c 100644 --- a/src/components/layout/Nav.jsx +++ b/src/components/layout/Nav.jsx @@ -22,31 +22,43 @@ import ResetFilters from './dialogs/ResetFilters' const searchable = ['quests', 'pokestops', 'raids', 'gyms', 'portals', 'nests'] export default function Nav({ - map, setManualParams, Icons, config, - setWebhookMode, webhookMode, settings, webhooks, - setScanNextMode, scanNextMode, setScanZoneMode, scanZoneMode, - isMobile, isTablet, + map, + setManualParams, + Icons, + config, + setWebhookMode, + webhookMode, + settings, + webhooks, + setScanNextMode, + scanNextMode, + setScanZoneMode, + scanZoneMode, + isMobile, + isTablet, }) { const classes = useStyles() - const { perms } = useStatic(state => state.auth) - const webhookAlert = useStatic(state => state.webhookAlert) - const setWebhookAlert = useStatic(state => state.setWebhookAlert) - const { map: { enableTutorial, messageOfTheDay, donationPage } } = useStatic(state => state.config) - const userProfile = useStatic(state => state.userProfile) - const setUserProfile = useStatic(state => state.setUserProfile) - const feedback = useStatic(state => state.feedback) - const setFeedback = useStatic(state => state.setFeedback) - const resetFilters = useStatic(state => state.resetFilters) - const setResetFilters = useStatic(state => state.setResetFilters) + const { perms } = useStatic((state) => state.auth) + const webhookAlert = useStatic((state) => state.webhookAlert) + const setWebhookAlert = useStatic((state) => state.setWebhookAlert) + const { + map: { enableTutorial, messageOfTheDay, donationPage }, + } = useStatic((state) => state.config) + const userProfile = useStatic((state) => state.userProfile) + const setUserProfile = useStatic((state) => state.setUserProfile) + const feedback = useStatic((state) => state.feedback) + const setFeedback = useStatic((state) => state.setFeedback) + const resetFilters = useStatic((state) => state.resetFilters) + const setResetFilters = useStatic((state) => state.setResetFilters) - const filters = useStore(state => state.filters) - const setFilters = useStore(state => state.setFilters) - const userSettings = useStore(state => state.userSettings) - const setUserSettings = useStore(state => state.setUserSettings) - const tutorial = useStore(state => state.tutorial) - const setTutorial = useStore(state => state.setTutorial) - const motdIndex = useStore(state => state.motdIndex) - const setMotdIndex = useStore(s => s.setMotdIndex) + const filters = useStore((state) => state.filters) + const setFilters = useStore((state) => state.setFilters) + const userSettings = useStore((state) => state.userSettings) + const setUserSettings = useStore((state) => state.setUserSettings) + const tutorial = useStore((state) => state.tutorial) + const setTutorial = useStore((state) => state.setTutorial) + const motdIndex = useStore((state) => state.motdIndex) + const setMotdIndex = useStore((s) => s.setMotdIndex) const [drawer, setDrawer] = useState(false) const [dialog, setDialog] = useState({ @@ -55,17 +67,24 @@ export default function Nav({ type: '', }) const [motd, setMotd] = useState( - messageOfTheDay.components.length - && (messageOfTheDay.index > motdIndex || messageOfTheDay.settings.permanent) - && ((perms.donor ? messageOfTheDay.settings.donorOnly : messageOfTheDay.settings.freeloaderOnly) - || (!messageOfTheDay.settings.donorOnly && !messageOfTheDay.settings.freeloaderOnly)), + messageOfTheDay.components.length && + (messageOfTheDay.index > motdIndex || + messageOfTheDay.settings.permanent) && + ((perms.donor + ? messageOfTheDay.settings.donorOnly + : messageOfTheDay.settings.freeloaderOnly) || + (!messageOfTheDay.settings.donorOnly && + !messageOfTheDay.settings.freeloaderOnly)), ) const [donorPage, setDonorPage] = useState(false) - const safeSearch = searchable.filter(category => perms[category]) + const safeSearch = searchable.filter((category) => perms[category]) const toggleDrawer = (open) => (event) => { - if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) { + if ( + event.type === 'keydown' && + (event.key === 'Tab' || event.key === 'Shift') + ) { return } setDrawer(open) @@ -79,8 +98,15 @@ export default function Nav({ } const toggleDialog = (open, category, type, filter) => (event) => { - Utility.analytics('Menu Toggle', `Open: ${open}`, `Category: ${category} Menu: ${type}`) - if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) { + Utility.analytics( + 'Menu Toggle', + `Open: ${open}`, + `Category: ${category} Menu: ${type}`, + ) + if ( + event.type === 'keydown' && + (event.key === 'Tab' || event.key === 'Shift') + ) { return } setDialog({ open, category, type }) @@ -204,10 +230,7 @@ export default function Nav({ handleMotdClose={handleMotdClose} /> - setDonorPage(false)} - > + setDonorPage(false)}> setDonorPage(false)} @@ -229,11 +252,15 @@ export default function Nav({ setWebhookAlert({ open: false, severity: 'info', message: '' })} + onClose={() => + setWebhookAlert({ open: false, severity: 'info', message: '' }) + } TransitionComponent={SlideTransition} > setWebhookAlert({ open: false, severity: 'info', message: '' })} + onClose={() => + setWebhookAlert({ open: false, severity: 'info', message: '' }) + } severity={webhookAlert.severity} variant="filled" style={{ whiteSpace: 'pre-line', textAlign: 'center' }} diff --git a/src/components/layout/auth/Auth.jsx b/src/components/layout/auth/Auth.jsx index eac370c9b..a4324924a 100644 --- a/src/components/layout/auth/Auth.jsx +++ b/src/components/layout/auth/Auth.jsx @@ -12,23 +12,30 @@ export default function Auth({ serverSettings, getServerSettings }) { const { location, zoom } = useConfig(serverSettings, params) if (serverSettings.error) { - return ( - - ) + return } - if ((serverSettings.authMethods.length && !serverSettings.user) - || (serverSettings.user && !serverSettings.user?.perms?.map)) { + if ( + (serverSettings.authMethods.length && !serverSettings.user) || + (serverSettings.user && !serverSettings.user?.perms?.map) + ) { if (params.category || params.lat) { localStorage.setItem('params', JSON.stringify(params)) } - return + return ( + + ) } const cachedParams = JSON.parse(localStorage.getItem('params')) if (cachedParams) { localStorage.removeItem('params') const url = cachedParams.category - ? `/id/${cachedParams.category}/${cachedParams.id}/${cachedParams.zoom || 18}` + ? `/id/${cachedParams.category}/${cachedParams.id}/${ + cachedParams.zoom || 18 + }` : `/@/${cachedParams.lat}/${cachedParams.lon}/${cachedParams.zoom || 18}` return } @@ -43,6 +50,11 @@ export default function Auth({ serverSettings, getServerSettings }) { ) } return ( - + ) } diff --git a/src/components/layout/auth/Discord.jsx b/src/components/layout/auth/Discord.jsx index bdccec542..034413b9d 100644 --- a/src/components/layout/auth/Discord.jsx +++ b/src/components/layout/auth/Discord.jsx @@ -17,7 +17,8 @@ export default function DiscordLogin({ href, text, size }) { size={size || 'large'} href={href || '/auth/discord/callback'} > -   + +   {text ? t(text) : t('login')} diff --git a/src/components/layout/auth/Local.jsx b/src/components/layout/auth/Local.jsx index 999f1b665..d5c1bd17e 100644 --- a/src/components/layout/auth/Local.jsx +++ b/src/components/layout/auth/Local.jsx @@ -1,7 +1,14 @@ import React, { useState } from 'react' import { Navigate } from 'react-router-dom' import { - Grid, Typography, Button, OutlinedInput, InputLabel, FormControl, InputAdornment, IconButton, + Grid, + Typography, + Button, + OutlinedInput, + InputLabel, + FormControl, + InputAdornment, + IconButton, } from '@material-ui/core' import { Visibility, VisibilityOff } from '@material-ui/icons' import { useTranslation } from 'react-i18next' @@ -10,7 +17,11 @@ import { useMutation } from '@apollo/client' import Fetch from '@services/Fetch' import Query from '@services/Query' -export default function LocalLogin({ href, serverSettings, getServerSettings }) { +export default function LocalLogin({ + href, + serverSettings, + getServerSettings, +}) { const { t } = useTranslation() const [user, setUser] = useState({ username: '', @@ -32,18 +43,17 @@ export default function LocalLogin({ href, serverSettings, getServerSettings }) const handleSubmit = async (e) => { e.preventDefault() setSubmitted(true) - await Fetch.login(user, href) - .then(async resp => { - if (!resp.ok) { - setError(t(await resp.json())) + await Fetch.login(user, href).then(async (resp) => { + if (!resp.ok) { + setError(t(await resp.json())) + } + if (resp.redirected) { + await getServerSettings() + if (serverSettings.user.valid) { + setRedirect(true) } - if (resp.redirected) { - await getServerSettings() - if (serverSettings.user.valid) { - setRedirect(true) - } - } - }) + } + }) } if (redirect) { @@ -53,12 +63,7 @@ export default function LocalLogin({ href, serverSettings, getServerSettings }) return ( <>
- + {t('local_username')} @@ -72,7 +77,9 @@ export default function LocalLogin({ href, serverSettings, getServerSettings }) color="secondary" labelWidth={t('local_username').length * 9} style={{ width: 250 }} - onKeyDown={(e) => { if (e.key === 'Enter') handleSubmit(e) }} + onKeyDown={(e) => { + if (e.key === 'Enter') handleSubmit(e) + }} /> @@ -88,20 +95,24 @@ export default function LocalLogin({ href, serverSettings, getServerSettings }) autoComplete="current-password" color="secondary" labelWidth={t('local_password').length * 9} - onKeyDown={(e) => { if (e.key === 'Enter') handleSubmit(e) }} + onKeyDown={(e) => { + if (e.key === 'Enter') handleSubmit(e) + }} style={{ width: 250 }} - endAdornment={( + endAdornment={ setUser({ ...user, showPassword: !user.showPassword })} + onClick={() => + setUser({ ...user, showPassword: !user.showPassword }) + } onMouseDown={(e) => e.preventDefault()} > {user.showPassword ? : } - )} + } /> diff --git a/src/components/layout/auth/Login.jsx b/src/components/layout/auth/Login.jsx index d5f9cedcc..b90e412ee 100644 --- a/src/components/layout/auth/Login.jsx +++ b/src/components/layout/auth/Login.jsx @@ -11,7 +11,11 @@ import DiscordLogin from './Discord' import TelegramLogin from './Telegram' import CustomTile from '../custom/CustomTile' -export default function Login({ clickedTwice, serverSettings, getServerSettings }) { +export default function Login({ + clickedTwice, + serverSettings, + getServerSettings, +}) { const location = useLocation() const { t } = useTranslation() const theme = useTheme() @@ -50,18 +54,37 @@ export default function Login({ clickedTwice, serverSettings, getServerSettings {serverSettings?.authMethods?.includes('discord') && ( - + {serverSettings.config.map.discordInvite && ( - - + + )} @@ -90,8 +113,19 @@ export default function Login({ clickedTwice, serverSettings, getServerSettings )} - - + + ) diff --git a/src/components/layout/auth/Telegram.jsx b/src/components/layout/auth/Telegram.jsx index 0ee4c75de..b3dad6cd5 100644 --- a/src/components/layout/auth/Telegram.jsx +++ b/src/components/layout/auth/Telegram.jsx @@ -10,7 +10,10 @@ export default function Telegram({ botName, authUrl }) { script.src = 'https://telegram.org/js/telegram-widget.js?4' script.setAttribute('data-telegram-login', botName) script.setAttribute('data-auth-url', authUrl) - script.setAttribute('data-lang', (localStorage?.getItem('i18nextLng') || 'en')) + script.setAttribute( + 'data-lang', + localStorage?.getItem('i18nextLng') || 'en', + ) script.setAttribute('data-userpic', 'false') script.setAttribute('data-size', 'large') script.setAttribute('data-request-access', 'write') diff --git a/src/components/layout/custom/AdvancedAccordion.jsx b/src/components/layout/custom/AdvancedAccordion.jsx index 499752427..9274a923f 100644 --- a/src/components/layout/custom/AdvancedAccordion.jsx +++ b/src/components/layout/custom/AdvancedAccordion.jsx @@ -1,6 +1,12 @@ import React from 'react' import { - createTheme, ThemeProvider, Grid, Typography, Accordion, AccordionSummary, AccordionDetails, + createTheme, + ThemeProvider, + Grid, + Typography, + Accordion, + AccordionSummary, + AccordionDetails, } from '@material-ui/core' import { ExpandMore } from '@material-ui/icons' import { useTranslation } from 'react-i18next' @@ -57,18 +63,18 @@ export default function AdvancedAccordion({ block, theme = {} }) { return ( createTheme({ - ...theme2, - ...accordionTheme, - })} + theme={(theme2) => + createTheme({ + ...theme2, + ...accordionTheme, + }) + } > } > - - {t('advanced')} - + {t('advanced')} - {Boolean(block.icon) && }  + {Boolean(block.icon) && ( + + )} +   {Utility.getBlockContent(block.content)} diff --git a/src/components/layout/custom/CustomTile.jsx b/src/components/layout/custom/CustomTile.jsx index cb5167358..b680bad9e 100644 --- a/src/components/layout/custom/CustomTile.jsx +++ b/src/components/layout/custom/CustomTile.jsx @@ -6,7 +6,12 @@ import Utility from '@services/Utility' import Generator from './Generator' -export default function CustomTile({ block, defaultReturn, serverSettings = {}, getServerSettings = () => {} }) { +export default function CustomTile({ + block, + defaultReturn, + serverSettings = {}, + getServerSettings = () => {}, +}) { return ( s.auth) - const footerOptions = [{ name: 'close', action: handleClose, color: 'primary' }] +export default function CustomWrapper({ + configObj, + defaultTitle, + contentBody, + handleClose, +}) { + const { perms } = useStatic((s) => s.auth) + const footerOptions = [ + { name: 'close', action: handleClose, color: 'primary' }, + ] if (configObj.footerButtons.length) { footerOptions.unshift( ...configObj.footerButtons - .filter(button => ( - !button.donorOnly && !button.freeloaderOnly) - || (button.donorOnly && perms.donor) - || (button.freeloaderOnly && !perms.donor)) - .map(b => ({ ...b, name: Utility.getBlockContent(b.name) })), + .filter( + (button) => + (!button.donorOnly && !button.freeloaderOnly) || + (button.donorOnly && perms.donor) || + (button.freeloaderOnly && !perms.donor), + ) + .map((b) => ({ ...b, name: Utility.getBlockContent(b.name) })), ) } return ( <> -
Utility.getBlockContent(t)) - : [defaultTitle]} +
Utility.getBlockContent(t)) + : [defaultTitle] + } /> - case 'button': return - case 'text': return - case 'divider': return - case 'telegram': return - case 'discord': return - case 'localLogin': return ( - - ) - case 'parent': return ( - - {block.components.map((subBlock, i) => ( - - - - ))} - - ) - default: return defaultReturn || null + case 'img': + return + case 'button': + return + case 'text': + return + case 'divider': + return + case 'telegram': + return ( + + ) + case 'discord': + return + case 'localLogin': + return ( + + ) + case 'parent': + return ( + + {block.components.map((subBlock, i) => ( + + + + ))} + + ) + default: + return defaultReturn || null } } diff --git a/src/components/layout/custom/LinkWrapper.jsx b/src/components/layout/custom/LinkWrapper.jsx index 3d48e1afa..aa17b8a1c 100644 --- a/src/components/layout/custom/LinkWrapper.jsx +++ b/src/components/layout/custom/LinkWrapper.jsx @@ -14,10 +14,7 @@ export default function LinkWrapper({ block, element }) { {element} ) : ( - + {element} ) diff --git a/src/components/layout/dialogs/BadgeSelection.jsx b/src/components/layout/dialogs/BadgeSelection.jsx index 8d227850f..3ec54de97 100644 --- a/src/components/layout/dialogs/BadgeSelection.jsx +++ b/src/components/layout/dialogs/BadgeSelection.jsx @@ -19,7 +19,7 @@ export default function BadgeSelection({ gym, setBadgeMenu, badge, setBadge }) {
setBadgeMenu(false)} /> - {[0, 1, 2, 3].map(i => ( + {[0, 1, 2, 3].map((i) => ( -
setFeedback(false), color: 'primary', align: 'right' }]} role="webhook_footer" /> +
setFeedback(false), + color: 'primary', + align: 'right', + }, + ]} + role="webhook_footer" + /> ) } diff --git a/src/components/layout/dialogs/Motd.jsx b/src/components/layout/dialogs/Motd.jsx index 1459c716e..d508dfc39 100644 --- a/src/components/layout/dialogs/Motd.jsx +++ b/src/components/layout/dialogs/Motd.jsx @@ -13,43 +13,50 @@ export default function Motd({ motd, perms, handleMotdClose }) { configObj={motd} defaultTitle="message_of_the_day" handleClose={handleMotdClose} - contentBody={ - motd.components.map((block, i) => { - if (block.donorOnly && !perms.donor) return null - if (block.freeloaderOnly && perms.donor) return null - return ( - } - /> - ) - }) - } + contentBody={motd.components.map((block, i) => { + if (block.donorOnly && !perms.donor) return null + if (block.freeloaderOnly && perms.donor) return null + return ( + } + /> + ) + })} /> ) } -const DefaultMotD = ({ block }) => typeof block === 'string' ? ( - - {block} - -) : ( -
- {block.title && ( - - {Utility.getBlockContent(block.title)} - - )} - {block.body && ( - - {Utility.getBlockContent(block.body)} - - )} - {block.footer && ( - - {Utility.getBlockContent(block.footer)} - - )} -
-) +const DefaultMotD = ({ block }) => + typeof block === 'string' ? ( + + {block} + + ) : ( +
+ {block.title && ( + + {Utility.getBlockContent(block.title)} + + )} + {block.body && ( + + {Utility.getBlockContent(block.body)} + + )} + {block.footer && ( + + {Utility.getBlockContent(block.footer)} + + )} +
+ ) diff --git a/src/components/layout/dialogs/ResetFilters.jsx b/src/components/layout/dialogs/ResetFilters.jsx index e51207bd0..07f402f45 100644 --- a/src/components/layout/dialogs/ResetFilters.jsx +++ b/src/components/layout/dialogs/ResetFilters.jsx @@ -1,7 +1,5 @@ import React, { useState } from 'react' -import { - Button, Typography, DialogContent, -} from '@material-ui/core' +import { Button, Typography, DialogContent } from '@material-ui/core' import { Navigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' @@ -13,7 +11,7 @@ import Footer from '../general/Footer' export default function ResetFilters() { const { t } = useTranslation() const [redirect, setRedirect] = useState(false) - const setResetFilters = useStatic(state => state.setResetFilters) + const setResetFilters = useStatic((state) => state.setResetFilters) if (redirect) { return @@ -42,7 +40,17 @@ export default function ResetFilters() {
-
setResetFilters(false), color: 'primary', align: 'right' }]} role="webhook_footer" /> +
setResetFilters(false), + color: 'primary', + align: 'right', + }, + ]} + role="webhook_footer" + /> ) } diff --git a/src/components/layout/dialogs/Search.jsx b/src/components/layout/dialogs/Search.jsx index d52ceb0a8..7bcd844d3 100644 --- a/src/components/layout/dialogs/Search.jsx +++ b/src/components/layout/dialogs/Search.jsx @@ -1,6 +1,11 @@ import React from 'react' import { - Tabs, AppBar, Tab, TextField, Typography, Grid, + Tabs, + AppBar, + Tab, + TextField, + Typography, + Grid, } from '@material-ui/core' import { useTranslation } from 'react-i18next' import { useQuery } from '@apollo/client' @@ -11,23 +16,25 @@ import Query from '@services/Query' import Header from '../general/Header' import QuestTitle from '../general/QuestTitle' -export default function Search({ - safeSearch, toggleDialog, isMobile, Icons, -}) { +export default function Search({ safeSearch, toggleDialog, isMobile, Icons }) { Utility.analytics('/search') const { t } = useTranslation() - const location = useStore(state => state.location) - const search = useStore(state => state.search) - const setSearch = useStore(state => state.setSearch) - const searchTab = useStore(state => state.searchTab) - const setSearchTab = useStore(state => state.setSearchTab) - const { map } = useStatic(state => state.config) + const location = useStore((state) => state.location) + const search = useStore((state) => state.search) + const setSearch = useStore((state) => state.setSearch) + const searchTab = useStore((state) => state.searchTab) + const setSearchTab = useStore((state) => state.setSearchTab) + const { map } = useStatic((state) => state.config) const handleTabChange = (event, newValue) => { setSearchTab(newValue) } - Utility.analytics('Global Search', `Search Value: ${search}`, safeSearch[searchTab]) + Utility.analytics( + 'Global Search', + `Search Value: ${search}`, + safeSearch[searchTab], + ) const { data, previousData } = useQuery(Query.search(safeSearch[searchTab]), { variables: { @@ -44,53 +51,93 @@ export default function Search({ const getUrl = (option) => { const { - quest_reward_type, nest_pokemon_id, nest_pokemon_form, raid_pokemon_id, + quest_reward_type, + nest_pokemon_id, + nest_pokemon_form, + raid_pokemon_id, } = option if (quest_reward_type) { const { - quest_pokemon_id, quest_form_id, quest_gender_id, quest_costume_id, quest_shiny, - quest_item_id, item_amount, stardust_amount, candy_amount, xl_candy_amount, - mega_pokemon_id, mega_amount, candy_pokemon_id, xl_candy_pokemon_id, + quest_pokemon_id, + quest_form_id, + quest_gender_id, + quest_costume_id, + quest_shiny, + quest_item_id, + item_amount, + stardust_amount, + candy_amount, + xl_candy_amount, + mega_pokemon_id, + mega_amount, + candy_pokemon_id, + xl_candy_pokemon_id, } = option let main let amount = 0 switch (quest_reward_type) { case 2: main = Icons.getRewards(quest_reward_type, quest_item_id, item_amount) - amount = main.includes('_a') || item_amount <= 1 ? 0 : item_amount; break + amount = main.includes('_a') || item_amount <= 1 ? 0 : item_amount + break case 3: main = Icons.getRewards(quest_reward_type, stardust_amount) - amount = main.includes('_a') ? 0 : stardust_amount; break + amount = main.includes('_a') ? 0 : stardust_amount + break case 4: main = Icons.getRewards(quest_reward_type, candy_pokemon_id) - amount = main.includes('_a') ? 0 : candy_amount; break + amount = main.includes('_a') ? 0 : candy_amount + break case 7: - main = Icons.getPokemon(quest_pokemon_id, quest_form_id, 0, quest_gender_id, quest_costume_id, quest_shiny) + main = Icons.getPokemon( + quest_pokemon_id, + quest_form_id, + 0, + quest_gender_id, + quest_costume_id, + quest_shiny, + ) break case 9: main = Icons.getRewards(quest_reward_type, xl_candy_pokemon_id) - amount = main.includes('_a') ? 0 : xl_candy_amount; break + amount = main.includes('_a') ? 0 : xl_candy_amount + break case 12: - main = Icons.getRewards(quest_reward_type, mega_pokemon_id, mega_amount) - amount = main.includes('_a') ? 0 : mega_amount; break + main = Icons.getRewards( + quest_reward_type, + mega_pokemon_id, + mega_amount, + ) + amount = main.includes('_a') ? 0 : mega_amount + break default: main = Icons.getRewards(quest_reward_type) } return ( -
{main} - {Boolean(main.includes('stardust') ? !main.endsWith('0.png') : !main.includes('_a') && amount) - &&
x{amount}
} + {Boolean( + main.includes('stardust') + ? !main.endsWith('0.png') + : !main.includes('_a') && amount, + ) &&
x{amount}
}
) } if (raid_pokemon_id) { const { - raid_pokemon_form, raid_pokemon_gender, raid_pokemon_costume, raid_pokemon_evolution, + raid_pokemon_form, + raid_pokemon_gender, + raid_pokemon_costume, + raid_pokemon_evolution, } = option return ( { switch (safeSearch[searchTab]) { case 'quests': - case 'pokestops': return t('unknown_pokestop') - default: return t('unknown_gym') + case 'pokestops': + return t('unknown_pokestop') + default: + return t('unknown_gym') } } @@ -135,10 +184,16 @@ export default function Search({ variant="fullWidth" style={{ backgroundColor: '#424242', width: '100%' }} > - {safeSearch.map(each => ( + {safeSearch.map((each) => ( } + icon={ + {each} + } style={{ width: 40, minWidth: 40 }} /> ))} @@ -150,12 +205,15 @@ export default function Search({ label={t(`global_search_${safeSearch[searchTab]}`)} value={search} onChange={({ target: { value } }) => { - if (/^[0-9\s\p{L}]+$/u.test(value) || value === '') setSearch(value.toLowerCase()) + if (/^[0-9\s\p{L}]+$/u.test(value) || value === '') + setSearch(value.toLowerCase()) }} variant="outlined" /> - {fetchedData?.[safeSearch[searchTab] === 'quests' ? 'searchQuest' : 'search']?.map((option, index) => ( + {fetchedData?.[ + safeSearch[searchTab] === 'quests' ? 'searchQuest' : 'search' + ]?.map((option, index) => ( - {option.url - ? ( - {option.url} - ) - : getUrl(option)} + : Icons.getMisc(safeSearch[searchTab]) + } + style={{ height: 40, width: 45, objectFit: 'fill' }} + alt={option.url} + /> + ) : ( + getUrl(option) + )} {option.name || getBackupName()}
- {(option.quest_title && option.quest_target) && ( + {option.quest_title && option.quest_target && ( - {option.distance} {map.distanceUnit === 'mi' ? t('mi') : t('km')} + + {option.distance}{' '} + {map.distanceUnit === 'mi' ? t('mi') : t('km')} +
{safeSearch[searchTab] === 'quests' && ( diff --git a/src/components/layout/dialogs/UserOptions.jsx b/src/components/layout/dialogs/UserOptions.jsx index 55b9df4b0..1c151d62f 100644 --- a/src/components/layout/dialogs/UserOptions.jsx +++ b/src/components/layout/dialogs/UserOptions.jsx @@ -19,23 +19,34 @@ import Footer from '../general/Footer' export default function UserOptions({ category, toggleDialog, isMobile }) { const { t } = useTranslation() - const { [category]: staticUserSettings } = useStatic(state => state.userSettings) - const userSettings = useStore(state => state.userSettings) + const { [category]: staticUserSettings } = useStatic( + (state) => state.userSettings, + ) + const userSettings = useStore((state) => state.userSettings) const [localState, setLocalState] = useState(userSettings[category]) const [tab, setTab] = useState(0) - const [tabPages] = useState(Array.from({ - length: Math.ceil(Object.keys(staticUserSettings).length / 10), - }, (v, i) => i)) + const [tabPages] = useState( + Array.from( + { + length: Math.ceil(Object.keys(staticUserSettings).length / 10), + }, + (v, i) => i, + ), + ) - const handleChange = event => { + const handleChange = (event) => { const { name, value } = event.target if (value) { setLocalState({ ...localState, [name]: value }) } else { setLocalState({ ...localState, [name]: !localState[name] }) } - Utility.analytics('User Options', `Name: ${name} New Value: ${value || !localState[name]}`, category) + Utility.analytics( + 'User Options', + `Name: ${name} New Value: ${value || !localState[name]}`, + category, + ) } const handleTabChange = (event, newValue) => { @@ -44,53 +55,52 @@ export default function UserOptions({ category, toggleDialog, isMobile }) { const getLabel = (label) => { if (label.startsWith('pvp') && !label.includes('Mega')) { - return ( - - {{ level: label.substring(3) }} - - ) + return {{ level: label.substring(3) }} } - return (t(Utility.camelToSnake(label), Utility.getProperName(label))) + return t(Utility.camelToSnake(label), Utility.getProperName(label)) } const getInputType = (option, subOption) => { const fullOption = subOption - ? staticUserSettings[option].sub[subOption] : staticUserSettings[option] + ? staticUserSettings[option].sub[subOption] + : staticUserSettings[option] switch (fullOption.type) { - case 'bool': return ( - - - - ) - default: return ( - - - - ) + case 'bool': + return ( + + + + ) + default: + return ( + + + + ) } } @@ -110,7 +120,7 @@ export default function UserOptions({ category, toggleDialog, isMobile }) { variant="fullWidth" style={{ backgroundColor: '#424242', width: '100%' }} > - {tabPages.map(each => ( + {tabPages.map((each) => ( {{ page: each + 1 }}} @@ -120,7 +130,7 @@ export default function UserOptions({ category, toggleDialog, isMobile }) { )} - {tabPages.map(each => ( + {tabPages.map((each) => ( {Object.entries(staticUserSettings).map(([key, values], j) => { const start = each * 10 @@ -138,13 +148,11 @@ export default function UserOptions({ category, toggleDialog, isMobile }) { spacing={2} > - - {getLabel(key)} - + {getLabel(key)} {getInputType(key)} - {values.sub - && Object.keys(values.sub).map(subOption => ( + {values.sub && + Object.keys(values.sub).map((subOption) => ( @@ -160,10 +168,21 @@ export default function UserOptions({ category, toggleDialog, isMobile }) { ))} -
setLocalState(userSettings[category]), icon: 'Replay', color: 'primary' }, - { name: 'save', action: toggleDialog(false, category, 'options', localState), icon: 'Save', color: 'secondary' }, - ]} +
setLocalState(userSettings[category]), + icon: 'Replay', + color: 'primary', + }, + { + name: 'save', + action: toggleDialog(false, category, 'options', localState), + icon: 'Save', + color: 'secondary', + }, + ]} /> ) diff --git a/src/components/layout/dialogs/UserProfile.jsx b/src/components/layout/dialogs/UserProfile.jsx index b6cda806b..07b5a93b8 100644 --- a/src/components/layout/dialogs/UserProfile.jsx +++ b/src/components/layout/dialogs/UserProfile.jsx @@ -37,8 +37,10 @@ import ReactWindow from '../general/ReactWindow' export default function UserProfile({ setUserProfile, isMobile, isTablet }) { Utility.analytics('/user-profile') const { t } = useTranslation() - const auth = useStatic(state => state.auth) - const { map: { excludeList, rolesLinkName, rolesLink } } = useStatic(state => state.config) + const auth = useStatic((state) => state.auth) + const { + map: { excludeList, rolesLinkName, rolesLink }, + } = useStatic((state) => state.config) const [tab, setTab] = useState(0) @@ -58,7 +60,7 @@ export default function UserProfile({ setUserProfile, isMobile, isTablet }) { variant="fullWidth" style={{ backgroundColor: '#424242', width: '100%' }} > - {['profile', 'access'].map(each => ( + {['profile', 'access'].map((each) => ( -
setUserProfile(false) }, - ]} +
setUserProfile(false), + }, + ]} /> ) } const LinkProfiles = ({ auth, t }) => { - const setAuth = useStatic(state => state.setAuth) - const { map: { discordAuthUrl, telegramAuthUrl, telegramBotName } } = useStatic(state => state.config) + const setAuth = useStatic((state) => state.setAuth) + const { + map: { discordAuthUrl, telegramAuthUrl, telegramBotName }, + } = useStatic((state) => state.config) const [refreshing, setRefreshing] = useState(false) @@ -109,30 +118,40 @@ const LinkProfiles = ({ auth, t }) => { return ( <> - + {['discord', 'telegram'].map((method, i) => { if (!auth.methods.includes(method)) return null - const Component = i - ? - : + const Component = i ? ( + + ) : ( + + ) return ( - {auth[`${method}Id`] - ? {t(`${method}_linked`)}! ({auth.username}) - : Component} + {auth[`${method}Id`] ? ( + + {t(`${method}_linked`)}! ({auth.username}) + + ) : ( + Component + )} ) })} - {(auth.discordId && auth.telegramId) && ( + {auth.discordId && auth.telegramId && ( - - - {t('select_webhook_strategy')} - + + {t('select_webhook_strategy')} )} - {refreshing && } + {refreshing && ( + + )} ) } const ProfilePermissions = ({ perms, excludeList, t }) => { - const { map: { permImageDir, permArrayImages } } = useStatic(state => state.config) + const { + map: { permImageDir, permArrayImages }, + } = useStatic((state) => state.config) return ( { spacing={2} style={{ padding: 5 }} > - {Object.keys(perms).map(perm => { + {Object.keys(perms).map((perm) => { if (excludeList.includes(perm) || perm === 'donor') { return null } return ( - + ) })} @@ -211,11 +244,9 @@ const PermCard = ({ perms, perm, t, permImageDir, permArrayImages }) => ( borderRadius: 4, }} > - {perms[perm].map(area => ( + {perms[perm].map((area) => ( - - {Utility.getProperName(area)} - + {Utility.getProperName(area)} ))} @@ -236,7 +267,7 @@ const GymBadges = ({ isMobile, t }) => { fetchPolicy: 'network-only', variables: { version: inject.VERSION }, }) - const Icons = useStatic(s => s.Icons) + const Icons = useStatic((s) => s.Icons) const map = useMap() let gold = 0 @@ -244,11 +275,17 @@ const GymBadges = ({ isMobile, t }) => { let bronze = 0 if (data?.badges) { - data.badges.forEach(gym => { + data.badges.forEach((gym) => { switch (gym.badge) { - case 3: gold += 1; break - case 2: silver += 1; break - case 1: bronze += 1; break + case 3: + gold += 1 + break + case 2: + silver += 1 + break + case 1: + bronze += 1 + break default: } }) @@ -264,7 +301,11 @@ const GymBadges = ({ isMobile, t }) => { {[bronze, silver, gold].map((count, i) => ( // eslint-disable-next-line react/no-array-index-key - + {t(`badge_${i + 1}`)}: {count} @@ -308,7 +349,12 @@ const BadgeTile = ({ data, rowIndex, columnIndex, style }) => { > - map.flyTo([item.lat, item.lon], 16)}> + map.flyTo([item.lat, item.lon], 16)} + > {item.url} { + const handleSearchChange = (event) => { setSearch(event.target.value?.toString()?.toLowerCase() || '') } @@ -18,7 +18,12 @@ export default function AdvSearch({ search, setSearch, category }) { } return ( - + - + diff --git a/src/components/layout/dialogs/filters/Advanced.jsx b/src/components/layout/dialogs/filters/Advanced.jsx index 92332a808..7e021a0c3 100644 --- a/src/components/layout/dialogs/filters/Advanced.jsx +++ b/src/components/layout/dialogs/filters/Advanced.jsx @@ -1,5 +1,11 @@ import React, { useState, useEffect } from 'react' -import { Select, Typography, Grid, DialogContent, MenuItem } from '@material-ui/core' +import { + Select, + Typography, + Grid, + DialogContent, + MenuItem, +} from '@material-ui/core' import { useTranslation } from 'react-i18next' import Utility from '@services/Utility' @@ -13,18 +19,25 @@ import Size from './Size' import QuestTitle from '../../general/QuestTitle' export default function AdvancedFilter({ - toggleAdvMenu, advancedFilter, type, isTutorial, + toggleAdvMenu, + advancedFilter, + type, + isTutorial, }) { Utility.analytics(`/${type}/${advancedFilter.id}`) - const ui = useStatic(state => state.ui) - const { questConditions = {} } = useStatic(state => state.available) + const ui = useStatic((state) => state.ui) + const { questConditions = {} } = useStatic((state) => state.available) const [filterValues, setFilterValues] = useState(advancedFilter.tempFilters) - const filters = useStore(state => state.filters) - const userSettings = useStore(state => state.userSettings) + const filters = useStore((state) => state.filters) + const userSettings = useStore((state) => state.userSettings) const { t } = useTranslation() - Utility.analytics('Advanced Filtering', `ID: ${advancedFilter.id} Size: ${filterValues.size}`, type) + Utility.analytics( + 'Advanced Filtering', + `ID: ${advancedFilter.id} Size: ${filterValues.size}`, + type, + ) if (isTutorial) { ui.pokemon = isTutorial } @@ -43,22 +56,36 @@ export default function AdvancedFilter({ } const footerOptions = [ - { name: 'reset', action: () => handleChange('default', advancedFilter.standard || { enabled: false, size: 'md' }), color: 'primary', size: type === 'pokemon' ? 2 : null }, - { name: 'save', action: toggleAdvMenu(false, advancedFilter.id, filterValues), color: 'secondary', size: type === 'pokemon' ? 3 : null }, + { + name: 'reset', + action: () => + handleChange( + 'default', + advancedFilter.standard || { enabled: false, size: 'md' }, + ), + color: 'primary', + size: type === 'pokemon' ? 2 : null, + }, + { + name: 'save', + action: toggleAdvMenu(false, advancedFilter.id, filterValues), + color: 'secondary', + size: type === 'pokemon' ? 3 : null, + }, ] if (type === 'pokemon') { - footerOptions.unshift( - { - key: 'size', - component: , - size: 7, - }, - ) + /> + ), + size: 7, + }) } // Provides a reset if that condition is no longer available @@ -66,7 +93,11 @@ export default function AdvancedFilter({ if (type === 'pokestops' && ui.pokestops?.quests) { if (!questConditions[advancedFilter.id] && filterValues.adv) { setFilterValues({ ...filterValues, adv: '' }) - } else if (questConditions[advancedFilter.id]?.every(cond => cond.title !== filterValues.adv)) { + } else if ( + questConditions[advancedFilter.id]?.every( + (cond) => cond.title !== filterValues.adv, + ) + ) { setFilterValues({ ...filterValues, adv: '' }) } } @@ -75,7 +106,13 @@ export default function AdvancedFilter({ return advancedFilter.id ? ( <>
@@ -88,18 +125,17 @@ export default function AdvancedFilter({ style={{ marginTop: 10 }} spacing={1} > - {(userSettings[type].legacyFilter && ui[type].legacy) - ? ( - - - - ) - : Object.entries(ui[type].sliders).map(([category, sliders]) => ( + {userSettings[type].legacyFilter && ui[type].legacy ? ( + + + + ) : ( + Object.entries(ui[type].sliders).map(([category, sliders]) => ( - {sliders.map(each => ( + {sliders.map((each) => ( ))} - ))} + )) + )} ) : ( @@ -119,20 +156,35 @@ export default function AdvancedFilter({ /> )} - {(type === 'pokestops' && ui.pokestops?.quests && questConditions?.[advancedFilter.id]) && ( - - {t('quest_condition')} - - - )} + {type === 'pokestops' && + ui.pokestops?.quests && + questConditions?.[advancedFilter.id] && ( + + {t('quest_condition')} + + + )}
diff --git a/src/components/layout/dialogs/filters/FilterMenu.jsx b/src/components/layout/dialogs/filters/FilterMenu.jsx index 697b9ecb0..b1b734800 100644 --- a/src/components/layout/dialogs/filters/FilterMenu.jsx +++ b/src/components/layout/dialogs/filters/FilterMenu.jsx @@ -3,7 +3,11 @@ import Menu from '@components/layout/general/Menu' import Tile from '@components/layout/dialogs/filters/MenuTile' export default function FilterMenu({ - toggleDialog, category, isMobile, isTablet, filters, + toggleDialog, + category, + isMobile, + isTablet, + filters, }) { const [tempFilters, setTempFilters] = useState(filters.filter) return ( @@ -18,7 +22,12 @@ export default function FilterMenu({ tempFilters={tempFilters} setTempFilters={setTempFilters} extraButtons={[ - { name: 'save', action: toggleDialog(false, category, 'filters', tempFilters), icon: 'Save', color: 'secondary' }, + { + name: 'save', + action: toggleDialog(false, category, 'filters', tempFilters), + icon: 'Save', + color: 'secondary', + }, ]} /> ) diff --git a/src/components/layout/dialogs/filters/MenuTile.jsx b/src/components/layout/dialogs/filters/MenuTile.jsx index 1358b8ae8..674b1a821 100644 --- a/src/components/layout/dialogs/filters/MenuTile.jsx +++ b/src/components/layout/dialogs/filters/MenuTile.jsx @@ -1,16 +1,20 @@ import React, { useState } from 'react' import { Grid, IconButton, Typography } from '@material-ui/core' -import { - Check, Clear, Tune, FormatSize, Settings, -} from '@material-ui/icons' +import { Check, Clear, Tune, FormatSize, Settings } from '@material-ui/icons' -export default function MenuTile({ - data, rowIndex, columnIndex, style, -}) { +export default function MenuTile({ data, rowIndex, columnIndex, style }) { const [name, setName] = useState(true) const { - tileItem, columnCount, tempFilters, setTempFilters, toggleAdvMenu, - isMobile, type, toggleSlotsMenu, Utility, standard, + tileItem, + columnCount, + tempFilters, + setTempFilters, + toggleAdvMenu, + isMobile, + type, + toggleSlotsMenu, + Utility, + standard, } = data const item = tileItem[rowIndex * columnCount + columnIndex] @@ -27,7 +31,11 @@ export default function MenuTile({ ...tempFilters, [item.id]: newFilter, }) - Utility.analytics('Filtering', `${item.name} Status: ${!tempFilters[item.id]?.enabled}`, type) + Utility.analytics( + 'Filtering', + `${item.name} Status: ${!tempFilters[item.id]?.enabled}`, + type, + ) } const image = ( @@ -44,9 +52,11 @@ export default function MenuTile({ ) const selection = ( - {tempFilters[item.id]?.enabled - ? - : } + {tempFilters[item.id]?.enabled ? ( + + ) : ( + + )} ) @@ -54,16 +64,23 @@ export default function MenuTile({ if (type === 'pokemon') { return } - if ((type === 'pokestops' && !item.id.startsWith('l') && !item.id.startsWith('i')) - || (item.id.startsWith('t') && parseInt(item.id.charAt(1)) > 0)) { + if ( + (type === 'pokestops' && + !item.id.startsWith('l') && + !item.id.startsWith('i')) || + (item.id.startsWith('t') && parseInt(item.id.charAt(1)) > 0) + ) { return } return } const advMenu = ( 0) - ? toggleSlotsMenu(true, item.id.charAt(1)) : toggleAdvMenu(true, item.id)} + onClick={ + item.id.startsWith('t') && parseInt(item.id.charAt(1)) > 0 + ? toggleSlotsMenu(true, item.id.charAt(1)) + : toggleAdvMenu(true, item.id) + } > {getAdvMenuIcon()} diff --git a/src/components/layout/dialogs/filters/Options.jsx b/src/components/layout/dialogs/filters/Options.jsx index b8d1080b2..49d482c8a 100644 --- a/src/components/layout/dialogs/filters/Options.jsx +++ b/src/components/layout/dialogs/filters/Options.jsx @@ -16,15 +16,18 @@ import Utility from '@services/Utility' import useStyles from '@hooks/useStyles' export default function FilterOptions({ - name, options, handleChange, expanded, handleAccordion, userSelection, + name, + options, + handleChange, + expanded, + handleAccordion, + userSelection, }) { const { t } = useTranslation() const classes = useStyles() return ( - } - > + }> {t(Utility.camelToSnake(name))} @@ -32,16 +35,16 @@ export default function FilterOptions({ - {Object.keys(options).map(key => ( + {Object.keys(options).map((key) => ( handleChange(name, e)} name={key} /> - )} + } value={key} label={t(Utility.camelToSnake(key))} /> diff --git a/src/components/layout/dialogs/filters/OptionsContainer.jsx b/src/components/layout/dialogs/filters/OptionsContainer.jsx index 25bcdad62..1ecdd0805 100644 --- a/src/components/layout/dialogs/filters/OptionsContainer.jsx +++ b/src/components/layout/dialogs/filters/OptionsContainer.jsx @@ -1,7 +1,5 @@ import React from 'react' -import { - Grid, Typography, Button, Chip, IconButton, -} from '@material-ui/core' +import { Grid, Typography, Button, Chip, IconButton } from '@material-ui/core' import { Clear } from '@material-ui/icons' import { useTranslation } from 'react-i18next' @@ -12,15 +10,27 @@ import Utility from '@services/Utility' import Options from './Options' export default function OptionsContainer({ - advMenu, setAdvMenu, menus, setMenus, categories, - category, handleReset, count, isMobile, toggleDrawer, + advMenu, + setAdvMenu, + menus, + setMenus, + categories, + category, + handleReset, + count, + isMobile, + toggleDrawer, }) { const { t } = useTranslation() const classes = useStyles() - const { [category]: staticMenus } = useStatic(state => state.menus) + const { [category]: staticMenus } = useStatic((state) => state.menus) const handleChange = (name, event) => { - Utility.analytics('Filtering Options', `New Value: ${event.target.checked}`, `Category: ${category} Name: ${name}.${event.target.name}`) + Utility.analytics( + 'Filtering Options', + `New Value: ${event.target.checked}`, + `Category: ${category} Name: ${name}.${event.target.name}`, + ) setMenus({ ...menus, [category]: { @@ -44,34 +54,48 @@ export default function OptionsContainer({ } const applied = [] - const allFilterMenus = Object.entries(staticMenus.filters).map(([cat, options]) => { - if (categories - ? categories.length > 1 || cat === 'others' || (categories.includes('pokemon') && cat !== 'categories') - : Object.keys(options).length > 1) { - if (menus[category].filters[cat]) { - Object.entries(menus[category].filters[cat]).forEach(([filter, bool]) => { - if (bool && options[filter] !== undefined) { - applied.push(filter) - } - }) + const allFilterMenus = Object.entries(staticMenus.filters).map( + ([cat, options]) => { + if ( + categories + ? categories.length > 1 || + cat === 'others' || + (categories.includes('pokemon') && cat !== 'categories') + : Object.keys(options).length > 1 + ) { + if (menus[category].filters[cat]) { + Object.entries(menus[category].filters[cat]).forEach( + ([filter, bool]) => { + if (bool && options[filter] !== undefined) { + applied.push(filter) + } + }, + ) + } + return ( + + ) } - return ( - - ) - } - return null - }) + return null + }, + ) allFilterMenus.push( - + - + {t('scan_outside_area')} @@ -158,40 +185,48 @@ export default function ScanNextTarget({ - {scanNextCoords.map(coords => ( + {scanNextCoords.map((coords) => ( ))} - {scanNextType === 'M' - ? ( - - ) - : scanNextCoords.map(coords => ( + {scanNextType === 'M' ? ( + + ) : ( + scanNextCoords.map((coords) => ( - ))} + )) + )} ) } diff --git a/src/components/layout/dialogs/scanner/ScanZone.jsx b/src/components/layout/dialogs/scanner/ScanZone.jsx index 17595546d..844c83284 100644 --- a/src/components/layout/dialogs/scanner/ScanZone.jsx +++ b/src/components/layout/dialogs/scanner/ScanZone.jsx @@ -2,7 +2,13 @@ import React, { useEffect, useState } from 'react' import { useQuery, useLazyQuery } from '@apollo/client' import { useTranslation } from 'react-i18next' import { - Dialog, DialogContent, DialogTitle, DialogActions, Button, Grid, Typography, + Dialog, + DialogContent, + DialogTitle, + DialogActions, + Button, + Grid, + Typography, } from '@material-ui/core' import { useStatic, useStore } from '@hooks/useStore' @@ -10,47 +16,64 @@ import Query from '@services/Query' import ScanZoneTarget from './ScanZoneTarget' export default function ScanZone({ - map, theme, scanZoneMode, setScanZoneMode, - scanner: { scannerType, scanZoneShowScanCount, scanZoneShowScanQueue, advancedScanZoneOptions, - scanZoneRadius, scanZoneSpacing, scanZoneMaxSize, scanZoneAreaRestriction }, + map, + theme, + scanZoneMode, + setScanZoneMode, + scanner: { + scannerType, + scanZoneShowScanCount, + scanZoneShowScanQueue, + advancedScanZoneOptions, + scanZoneRadius, + scanZoneSpacing, + scanZoneMaxSize, + scanZoneAreaRestriction, + }, }) { - const { data: scanAreas } = scanZoneAreaRestriction?.length ? useQuery(Query.scanAreas()) : { data: null } - const { loggedIn } = useStatic(state => state.auth) + const { data: scanAreas } = scanZoneAreaRestriction?.length + ? useQuery(Query.scanAreas()) + : { data: null } + const { loggedIn } = useStatic((state) => state.auth) const { t } = useTranslation() - const location = useStore(s => s.location) + const location = useStore((s) => s.location) const [queue, setQueue] = useState('init') const [scanZoneLocation, setScanZoneLocation] = useState(location) const [scanZoneCoords, setScanZoneCoords] = useState([location]) const [scanZoneSize, setScanZoneSize] = useState(1) - const [scanZone, { error: scannerError, data: scannerResponse }] = useLazyQuery(Query.scanner(), { - variables: { - version: inject.VERSION, - category: 'scanZone', - method: 'GET', - data: { - username: loggedIn?.username || 'a visitor', - userId: loggedIn?.id, - scanZoneLocation, - scanZoneCoords, - scanZoneSize, + const [scanZone, { error: scannerError, data: scannerResponse }] = + useLazyQuery(Query.scanner(), { + variables: { + version: inject.VERSION, + category: 'scanZone', + method: 'GET', + data: { + username: loggedIn?.username || 'a visitor', + userId: loggedIn?.id, + scanZoneLocation, + scanZoneCoords, + scanZoneSize, + }, }, - }, - fetchPolicy: 'no-cache', - }) - const [getQueue, { data: scannerQueueResponse }] = useLazyQuery(Query.scanner(), { - variables: { - version: inject.VERSION, - category: 'getQueue', - method: 'GET', - data: { - username: loggedIn?.username || 'a visitor', - userId: loggedIn?.id, - type: 'scan_next', - typeName: 'scanZone', + fetchPolicy: 'no-cache', + }) + const [getQueue, { data: scannerQueueResponse }] = useLazyQuery( + Query.scanner(), + { + variables: { + version: inject.VERSION, + category: 'getQueue', + method: 'GET', + data: { + username: loggedIn?.username || 'a visitor', + userId: loggedIn?.id, + type: 'scan_next', + typeName: 'scanZone', + }, }, + fetchPolicy: 'no-cache', }, - fetchPolicy: 'no-cache', - }) + ) if (scanZoneMode === 'sendCoords') { scanZone() diff --git a/src/components/layout/dialogs/scanner/ScanZoneTarget.jsx b/src/components/layout/dialogs/scanner/ScanZoneTarget.jsx index 6f55820fe..272d94ca4 100644 --- a/src/components/layout/dialogs/scanner/ScanZoneTarget.jsx +++ b/src/components/layout/dialogs/scanner/ScanZoneTarget.jsx @@ -1,6 +1,4 @@ -import React, { - useState, useRef, useMemo, useEffect, -} from 'react' +import React, { useState, useRef, useMemo, useEffect } from 'react' import { Grid, Button, Box, Slider, Typography } from '@material-ui/core' import { point, polygon } from '@turf/helpers' import destination from '@turf/destination' @@ -10,9 +8,25 @@ import { useTranslation } from 'react-i18next' import AdvancedAccordion from '@components/layout/custom/AdvancedAccordion' export default function ScanZoneTarget({ - map, theme, scannerType, queue, setScanZoneMode, scanZoneLocation, setScanZoneLocation, scanZoneCoords, - setScanZoneCoords, scanZoneSize, setScanZoneSize, scanZoneShowScanCount, scanZoneShowScanQueue, - advancedScanZoneOptions, scanZoneRadius, scanZoneSpacing, scanZoneMaxSize, scanZoneAreaRestriction, scanAreas, + map, + theme, + scannerType, + queue, + setScanZoneMode, + scanZoneLocation, + setScanZoneLocation, + scanZoneCoords, + setScanZoneCoords, + scanZoneSize, + setScanZoneSize, + scanZoneShowScanCount, + scanZoneShowScanQueue, + advancedScanZoneOptions, + scanZoneRadius, + scanZoneSpacing, + scanZoneMaxSize, + scanZoneAreaRestriction, + scanAreas, }) { const [position, setPosition] = useState(scanZoneLocation) const [spacing, setSpacing] = useState(scanZoneSpacing) @@ -33,10 +47,18 @@ export default function ScanZoneTarget({ let quadrant = 1 let step = 1 while (step < 6 * i + 1) { - currentPoint = destination(currentPoint, (distance * spacing) / 1000, step === 1 - ? 330 - : bearings[quadrant], { units: 'kilometers' }) - coords = coords.concat([[currentPoint.geometry.coordinates[1], currentPoint.geometry.coordinates[0]]]) + currentPoint = destination( + currentPoint, + (distance * spacing) / 1000, + step === 1 ? 330 : bearings[quadrant], + { units: 'kilometers' }, + ) + coords = coords.concat([ + [ + currentPoint.geometry.coordinates[1], + currentPoint.geometry.coordinates[0], + ], + ]) quadrant = Math.floor(step / i) + 1 step += 1 } @@ -49,9 +71,17 @@ export default function ScanZoneTarget({ let isValid = false if (scanZoneAreaRestriction?.length && scanAreas?.length) { const testPoint = point([center[1], center[0]]) - scanZoneAreaRestriction.map(area => { - if (scanAreas.some(scanArea => scanArea.properties.name === area - && booleanPointInPolygon(testPoint, polygon(scanArea.geometry.coordinates)))) { + scanZoneAreaRestriction.map((area) => { + if ( + scanAreas.some( + (scanArea) => + scanArea.properties.name === area && + booleanPointInPolygon( + testPoint, + polygon(scanArea.geometry.coordinates), + ), + ) + ) { isValid = true } return true @@ -105,7 +135,10 @@ export default function ScanZoneTarget({ setScanZoneCoords(calcScanZoneCoords(position)) } - const rangeMarks = [{ value: scanZoneRadius.pokemon, label: t('pokemon') }, { value: scanZoneRadius.gym, label: t('gym') }] + const rangeMarks = [ + { value: scanZoneRadius.pokemon, label: t('pokemon') }, + { value: scanZoneRadius.gym, label: t('gym') }, + ] const isInAllowedArea = checkAreaValidity(position) @@ -115,9 +148,7 @@ export default function ScanZoneTarget({ const advancedMenu = ( - - {t('scan_zone_spacing')} - + {t('scan_zone_spacing')} - - {t('scan_zone_radius')} - + {t('scan_zone_radius')} setScanZoneMode('sendCoords')} > {t('click_to_scan')} - + {t('scan_outside_area')} @@ -241,13 +276,15 @@ export default function ScanZoneTarget({ - {scanZoneCoords.map(coords => ( + {scanZoneCoords.map((coords) => ( ))} diff --git a/src/components/layout/dialogs/tutorial/Advanced.jsx b/src/components/layout/dialogs/tutorial/Advanced.jsx index 5ae84f558..e45318a4c 100644 --- a/src/components/layout/dialogs/tutorial/Advanced.jsx +++ b/src/components/layout/dialogs/tutorial/Advanced.jsx @@ -1,9 +1,20 @@ import React, { useState } from 'react' import { - Grid, DialogContent, Typography, Divider, Button, Dialog, + Grid, + DialogContent, + Typography, + Divider, + Button, + Dialog, } from '@material-ui/core' import { - Tune, Ballot, Check, Clear, Save, HelpOutline, FormatSize, + Tune, + Ballot, + Check, + Clear, + Save, + HelpOutline, + FormatSize, } from '@material-ui/icons' import { useTranslation } from 'react-i18next' @@ -41,11 +52,7 @@ export default function TutAdvanced({ isMobile, toggleHelp, category }) { iv: true, pvp: true, sliders: { - primary: [ - data.sliders[0], - data.sliders[1], - data.sliders[2], - ], + primary: [data.sliders[0], data.sliders[1], data.sliders[2]], secondary: [ data.sliders[3], data.sliders[4], @@ -57,7 +64,10 @@ export default function TutAdvanced({ isMobile, toggleHelp, category }) { const columnCount = isMobile ? 1 : 2 const toggleAdvMenu = (open, id, newFilters) => (event) => { - if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) { + if ( + event.type === 'keydown' && + (event.key === 'Tab' || event.key === 'Shift') + ) { return } if (open) { @@ -74,7 +84,10 @@ export default function TutAdvanced({ isMobile, toggleHelp, category }) { } const toggleSlotsMenu = (open, id, newFilters) => (event) => { - if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) { + if ( + event.type === 'keydown' && + (event.key === 'Tab' || event.key === 'Shift') + ) { return } if (open) { @@ -104,10 +117,7 @@ export default function TutAdvanced({ isMobile, toggleHelp, category }) { return ( <> - + - + - {isMobile - ? - : {t('help')}} + {isMobile ? ( + + ) : ( + {t('help')} + )} @@ -190,9 +199,11 @@ export default function TutAdvanced({ isMobile, toggleHelp, category }) { {isPokemon ? ( <> - {isMobile - ? - : {t('apply_to_all')}} + {isMobile ? ( + + ) : ( + {t('apply_to_all')} + )} @@ -203,9 +214,11 @@ export default function TutAdvanced({ isMobile, toggleHelp, category }) { ) : ( <> - {isMobile - ? - : {t('apply_to_all')}} + {isMobile ? ( + + ) : ( + {t('apply_to_all')} + )} @@ -215,19 +228,24 @@ export default function TutAdvanced({ isMobile, toggleHelp, category }) { )} - {isMobile - ? - : {t('disable_all')}} + {isMobile ? ( + + ) : ( + {t('disable_all')} + )} {t('tutorial_clear')} - - {isMobile - ? - : {t('enable_all')}} + + {isMobile ? : {t('enable_all')}} @@ -235,9 +253,11 @@ export default function TutAdvanced({ isMobile, toggleHelp, category }) { - {isMobile - ? - : {t('save')}} + {isMobile ? ( + + ) : ( + {t('save')} + )} @@ -252,8 +272,15 @@ export default function TutAdvanced({ isMobile, toggleHelp, category }) { ) : ( - )} diff --git a/src/components/layout/dialogs/tutorial/Closing.jsx b/src/components/layout/dialogs/tutorial/Closing.jsx index c50fd47b4..6f0d584c7 100644 --- a/src/components/layout/dialogs/tutorial/Closing.jsx +++ b/src/components/layout/dialogs/tutorial/Closing.jsx @@ -1,7 +1,5 @@ import React from 'react' -import { - DialogContent, Typography, Divider, Grid, -} from '@material-ui/core' +import { DialogContent, Typography, Divider, Grid } from '@material-ui/core' import { useTranslation } from 'react-i18next' const closing = [0, 1, 2, 3, 4] @@ -18,7 +16,7 @@ export default function TutClosing() { spacing={2} style={{ height: '100%' }} > - {closing.map(i => ( + {closing.map((i) => ( {t(`tutorial_closing_${i}`)} diff --git a/src/components/layout/dialogs/tutorial/Popups.jsx b/src/components/layout/dialogs/tutorial/Popups.jsx index dcd8a157d..730802413 100644 --- a/src/components/layout/dialogs/tutorial/Popups.jsx +++ b/src/components/layout/dialogs/tutorial/Popups.jsx @@ -1,7 +1,5 @@ import React from 'react' -import { - Grid, DialogContent, Typography, Divider, -} from '@material-ui/core' +import { Grid, DialogContent, Typography, Divider } from '@material-ui/core' import { useTranslation } from 'react-i18next' import { useStatic } from '@hooks/useStore' @@ -10,9 +8,11 @@ import data from './data.json' export default function TutPopup({ isMobile }) { const { t } = useTranslation() - const Icons = useStatic(state => state.Icons) - const { map: { startLat, startLon } } = useStatic(state => state.config) - const ts = Math.floor((new Date()).getTime() / 1000) + const Icons = useStatic((state) => state.Icons) + const { + map: { startLat, startLon }, + } = useStatic((state) => state.config) + const ts = Math.floor(new Date().getTime() / 1000) const size = isMobile ? 'subtitle2' : 'subtitle1' return ( diff --git a/src/components/layout/dialogs/tutorial/Sidebar.jsx b/src/components/layout/dialogs/tutorial/Sidebar.jsx index 066a9288c..420ae5bf5 100644 --- a/src/components/layout/dialogs/tutorial/Sidebar.jsx +++ b/src/components/layout/dialogs/tutorial/Sidebar.jsx @@ -1,6 +1,11 @@ import React, { useState } from 'react' import { - Grid, DialogContent, Typography, Fab, Divider, Button, + Grid, + DialogContent, + Typography, + Fab, + Divider, + Button, } from '@material-ui/core' import { Menu, Settings } from '@material-ui/icons' import { useTranslation } from 'react-i18next' @@ -12,9 +17,10 @@ import data from './data.json' export default function TutSidebar({ toggleDialog, isMobile }) { const { t } = useTranslation() const [tempFilters, setTempFilters] = useState(data.filters) - const { perms } = useStatic(state => state.auth) + const { perms } = useStatic((state) => state.auth) - const permCheck = perms.pokestops || perms.invasions || perms.quests || perms.lures + const permCheck = + perms.pokestops || perms.invasions || perms.quests || perms.lures return ( @@ -57,7 +63,7 @@ export default function TutSidebar({ toggleDialog, isMobile }) { margin: 10, }} > - {Object.keys(tempFilters.pokestops).map(subItem => { + {Object.keys(tempFilters.pokestops).map((subItem) => { if (subItem === 'filter') { return null } @@ -71,7 +77,11 @@ export default function TutSidebar({ toggleDialog, isMobile }) { /> ) })} - + - )} - backButton={( - - )} + } /> diff --git a/src/components/layout/dialogs/tutorial/Welcome.jsx b/src/components/layout/dialogs/tutorial/Welcome.jsx index 04fc2eb60..a432ce103 100644 --- a/src/components/layout/dialogs/tutorial/Welcome.jsx +++ b/src/components/layout/dialogs/tutorial/Welcome.jsx @@ -1,10 +1,5 @@ import React from 'react' -import { - DialogContent, - Grid, - Typography, - Fab, -} from '@material-ui/core' +import { DialogContent, Grid, Typography, Fab } from '@material-ui/core' import { Person, LockOpen } from '@material-ui/icons' import { useTranslation } from 'react-i18next' @@ -13,13 +8,16 @@ import LocaleSelection from '@components/layout/general/LocaleSelection' export default function TutWelcome({ setUserProfile }) { const { t } = useTranslation() - const { methods, loggedIn, perms } = useStatic(state => state.auth) - const { map: { enableUserProfile, excludeList }, localeSelection } = useStatic(state => state.config) + const { methods, loggedIn, perms } = useStatic((state) => state.auth) + const { + map: { enableUserProfile, excludeList }, + localeSelection, + } = useStatic((state) => state.config) const getPerms = () => { let have = 0 let total = 0 - Object.keys(perms).forEach(perm => { + Object.keys(perms).forEach((perm) => { if (!excludeList.includes(perm)) { have += perms[perm] ? 1 : 0 total += 1 @@ -52,7 +50,9 @@ export default function TutWelcome({ setUserProfile }) { {enableUserProfile && ( - {!loggedIn && methods.length ? t('login_optional') : t('view_profile')} + {!loggedIn && methods.length + ? t('login_optional') + : t('view_profile')} )} @@ -80,7 +80,9 @@ export default function TutWelcome({ setUserProfile }) { {enableUserProfile && ( - {!loggedIn && methods.length ? t('tutorial_logged_out') : t('tutorial_logged_in')} + {!loggedIn && methods.length + ? t('tutorial_logged_out') + : t('tutorial_logged_in')} )} diff --git a/src/components/layout/dialogs/webhooks/AreaSelection.jsx b/src/components/layout/dialogs/webhooks/AreaSelection.jsx index 9611e8798..9cca8cb27 100644 --- a/src/components/layout/dialogs/webhooks/AreaSelection.jsx +++ b/src/components/layout/dialogs/webhooks/AreaSelection.jsx @@ -3,18 +3,23 @@ import React from 'react' import ScanAreaTile from '@components/tiles/ScanArea' export default function AreaSelection({ - map, selectedWebhook, - webhookMode, setWebhookMode, - selectedAreas, setSelectedAreas, + map, + selectedWebhook, + webhookMode, + setWebhookMode, + selectedAreas, + setSelectedAreas, webhookData, }) { if (webhookData[selectedWebhook]) { - const lower = webhookData[selectedWebhook].available.map(a => a.toLowerCase()) + const lower = webhookData[selectedWebhook].available.map((a) => + a.toLowerCase(), + ) const filtered = { ...webhookData[selectedWebhook].areas, - features: webhookData[selectedWebhook].areas.features.filter(feature => ( - lower.includes(feature.properties.name.toLowerCase()) - )), + features: webhookData[selectedWebhook].areas.features.filter((feature) => + lower.includes(feature.properties.name.toLowerCase()), + ), } return ( { const classes = useStyles() - const handleClick = areaName => { + const handleClick = (areaName) => { areaName = areaName.toLowerCase() let newAreas = [] if (areaName === 'all') { @@ -21,7 +26,7 @@ const Areas = ({ newAreas = [] } else { newAreas = selectedAreas.includes(areaName) - ? selectedAreas.filter(a => a !== areaName) + ? selectedAreas.filter((a) => a !== areaName) : [...selectedAreas, areaName] } syncWebhook({ @@ -49,7 +54,12 @@ const Areas = ({ const ChooseOnMap = ( - @@ -66,28 +76,32 @@ const Areas = ({ style={{ height: '100%' }} > - - {t('areas')} - + {t('areas')} {isMobile && ChooseOnMap} - - {!isMobile && ChooseOnMap} - - {webhookData.available.map(area => { + + {webhookData.available.map((area) => { const included = selectedAreas.includes(area.toLowerCase()) return ( ( - prev.selectedAreas.length === next.selectedAreas.length - && prev.currentHuman.area === next.currentHuman.area - && prev.isMobile === next.isMobile -) +const areEqual = (prev, next) => + prev.selectedAreas.length === next.selectedAreas.length && + prev.currentHuman.area === next.currentHuman.area && + prev.isMobile === next.isMobile export default memo(Areas, areEqual) diff --git a/src/components/layout/dialogs/webhooks/Draggable.jsx b/src/components/layout/dialogs/webhooks/Draggable.jsx index 9faa9fdb3..2694300a9 100644 --- a/src/components/layout/dialogs/webhooks/Draggable.jsx +++ b/src/components/layout/dialogs/webhooks/Draggable.jsx @@ -1,14 +1,20 @@ -import React, { - useState, useRef, useMemo, useEffect, -} from 'react' +import React, { useState, useRef, useMemo, useEffect } from 'react' import { - Grid, Button, Typography, OutlinedInput, InputAdornment, FormControl, + Grid, + Button, + Typography, + OutlinedInput, + InputAdornment, + FormControl, } from '@material-ui/core' import { Circle, Marker, Popup } from 'react-leaflet' import { useTranslation } from 'react-i18next' export default function DraggableMarker({ - map, setWebhookMode, webhookLocation, setWebhookLocation, + map, + setWebhookMode, + webhookLocation, + setWebhookLocation, }) { const [position, setPosition] = useState(webhookLocation) const [radius, setRadius] = useState(0) @@ -65,14 +71,16 @@ export default function DraggableMarker({ setRadius(e.target.value.replace(/[^0-9.]/g, ''))} - endAdornment={{t('m')}} + onChange={(e) => + setRadius(e.target.value.replace(/[^0-9.]/g, '')) + } + endAdornment={ + {t('m')} + } labelWidth={0} /> - - {t('distance_radius')} - + {t('distance_radius')} - @@ -109,12 +131,16 @@ const Location = ({ {...params} label={t('search_location')} variant="outlined" - onChange={(e) => setSearch({ variables: { search: e.target.value } })} + onChange={(e) => + setSearch({ variables: { search: e.target.value } }) + } InputProps={{ ...params.InputProps, endAdornment: ( <> - {loading ? : null} + {loading ? ( + + ) : null} {params.InputProps.endAdornment} ), @@ -139,8 +165,7 @@ const Location = ({ ) } -const getEqual = (prev, next) => ( +const getEqual = (prev, next) => prev.webhookLocation.join('') === next.webhookLocation.join('') -) export default memo(Location, getEqual) diff --git a/src/components/layout/dialogs/webhooks/Manage.jsx b/src/components/layout/dialogs/webhooks/Manage.jsx index b0c1edfc0..3ac411ce3 100644 --- a/src/components/layout/dialogs/webhooks/Manage.jsx +++ b/src/components/layout/dialogs/webhooks/Manage.jsx @@ -1,12 +1,6 @@ /* eslint-disable max-len */ import React, { useState, useEffect, useMemo } from 'react' -import { - DialogContent, - Dialog, - AppBar, - Tabs, - Tab, -} from '@material-ui/core' +import { DialogContent, Dialog, AppBar, Tabs, Tab } from '@material-ui/core' import { Person } from '@material-ui/icons' import { useTranslation, Trans } from 'react-i18next' import { useLazyQuery } from '@apollo/client' @@ -29,12 +23,19 @@ import ProfileEditing from './ProfileEditing' import Feedback from '../Feedback' export default function Manage({ - Icons, isMobile, isTablet, - selectedWebhook, setSelectedWebhook, - setWebhookMode, webhookMode, - selectedAreas, setSelectedAreas, - webhookLocation, setWebhookLocation, - webhookData, setWebhookData, + Icons, + isMobile, + isTablet, + selectedWebhook, + setSelectedWebhook, + setWebhookMode, + webhookMode, + selectedAreas, + setSelectedAreas, + webhookLocation, + setWebhookLocation, + webhookData, + setWebhookData, handleWebhookClose, }) { const { t } = useTranslation() @@ -43,42 +44,78 @@ export default function Manage({ fetchPolicy: 'no-cache', }) - const staticFilters = useStatic(s => s.filters) - const { invasions } = useStatic(s => s.masterfile) - const { map } = useStatic(s => s.config) - const setWebhookAlert = useStatic(state => state.setWebhookAlert) - const poracleFilters = useMemo(() => Poracle.filterGenerator(webhookData[selectedWebhook], staticFilters, invasions), []) + const staticFilters = useStatic((s) => s.filters) + const { invasions } = useStatic((s) => s.masterfile) + const { map } = useStatic((s) => s.config) + const setWebhookAlert = useStatic((state) => state.setWebhookAlert) + const poracleFilters = useMemo( + () => + Poracle.filterGenerator( + webhookData[selectedWebhook], + staticFilters, + invasions, + ), + [], + ) const [tabValue, setTabValue] = useState(0) const [feedback, setFeedback] = useState(false) const [addNew, setAddNew] = useState(false) - const filteredData = Object.keys(webhookData[selectedWebhook]?.info || {}).filter(key => key - && (!webhookData[selectedWebhook]?.human?.blocked_alerts || (key === 'pokemon' - ? !webhookData[selectedWebhook].human.blocked_alerts.includes('monster') - : !webhookData[selectedWebhook].human.blocked_alerts.includes(key)))) + const filteredData = Object.keys( + webhookData[selectedWebhook]?.info || {}, + ).filter( + (key) => + key && + (!webhookData[selectedWebhook]?.human?.blocked_alerts || + (key === 'pokemon' + ? !webhookData[selectedWebhook].human.blocked_alerts.includes( + 'monster', + ) + : !webhookData[selectedWebhook].human.blocked_alerts.includes(key))), + ) const webhookCategory = filteredData[tabValue] - Utility.analytics('Webhook', `${webhookCategory} Webhook Page`, webhookCategory, true) + Utility.analytics( + 'Webhook', + `${webhookCategory} Webhook Page`, + webhookCategory, + true, + ) - const [tempFilters, setTempFilters] = useState(poracleFilters[webhookCategory]) + const [tempFilters, setTempFilters] = useState( + poracleFilters[webhookCategory], + ) const [send, setSend] = useState(false) const footerButtons = [ { - name: tabValue - ? {{ category: t(filteredData[tabValue]) }} - : t('manage_profiles'), + name: tabValue ? ( + + {{ category: t(filteredData[tabValue]) }} + + ) : ( + t('manage_profiles') + ), action: () => setAddNew(true), icon: tabValue ? 'Add' : 'People', key: 'addNew', disabled: !webhookData[selectedWebhook]?.human, }, - { name: 'close', action: handleWebhookClose, icon: 'Close', color: 'primary' }, + { + name: 'close', + action: handleWebhookClose, + icon: 'Close', + color: 'primary', + }, ] if (map.feedbackLink) { - footerButtons.unshift( - { name: 'feedback', action: () => setFeedback(true), icon: 'BugReport', disabled: !webhookData[selectedWebhook].human, color: '#00e676' }, - ) + footerButtons.unshift({ + name: 'feedback', + action: () => setFeedback(true), + icon: 'BugReport', + disabled: !webhookData[selectedWebhook].human, + color: '#00e676', + }) } const handleClose = (save) => { @@ -130,7 +167,11 @@ export default function Manage({ return ( <> -
+
( - : {each}} + icon={ + each === 'human' ? ( + + ) : ( + {each} + ) + } style={{ width: 40, minWidth: 40 }} /> ))} - {webhookData[selectedWebhook].human && !poracleFilters.error ? filteredData.map((key, i) => ( - - {key === 'human' ? ( - - ) : ( - - )} - - )) : } + {webhookData[selectedWebhook].human && !poracleFilters.error ? ( + filteredData.map((key, i) => ( + + {key === 'human' ? ( + + ) : ( + + )} + + )) + ) : ( + + )}
handleClose(true), icon: 'Save', color: 'secondary' }, + { + name: 'save', + action: () => handleClose(true), + icon: 'Save', + color: 'secondary', + }, ]} /> )} diff --git a/src/components/layout/dialogs/webhooks/ProfileEditing.jsx b/src/components/layout/dialogs/webhooks/ProfileEditing.jsx index 8fe1c53ba..abbdbab7a 100644 --- a/src/components/layout/dialogs/webhooks/ProfileEditing.jsx +++ b/src/components/layout/dialogs/webhooks/ProfileEditing.jsx @@ -1,10 +1,18 @@ import React, { useEffect, useState } from 'react' import { - DialogContent, Grid, Chip, Typography, Input, Select, MenuItem, Button, Divider, TextField, IconButton, + DialogContent, + Grid, + Chip, + Typography, + Input, + Select, + MenuItem, + Button, + Divider, + TextField, + IconButton, } from '@material-ui/core' -import { - Clear, Edit, DeleteForever, Save, FileCopy, -} from '@material-ui/icons' +import { Clear, Edit, DeleteForever, Save, FileCopy } from '@material-ui/icons' import { Trans, useTranslation } from 'react-i18next' import { useMutation } from '@apollo/client' @@ -13,39 +21,63 @@ import Query from '@services/Query' import Header from '@components/layout/general/Header' import Footer from '@components/layout/general/Footer' -const profilesObject = (data) => data ? Object.fromEntries(data.map(profile => { - const newProfile = { ...profile, active_hours: [] } - const parsed = Array.isArray(profile.active_hours) - ? profile.active_hours - : JSON.parse(profile.active_hours) - if (Array.isArray(parsed)) { - const sorted = parsed.sort((a, b) => a.day === a.bday ? a.hours - b.hours : a.day - b.day) - sorted.forEach((schedule, i) => { - newProfile.active_hours.push({ ...schedule, id: i }) - }) - } - return [profile.name, newProfile] -})) : {} +const profilesObject = (data) => + data + ? Object.fromEntries( + data.map((profile) => { + const newProfile = { ...profile, active_hours: [] } + const parsed = Array.isArray(profile.active_hours) + ? profile.active_hours + : JSON.parse(profile.active_hours) + if (Array.isArray(parsed)) { + const sorted = parsed.sort((a, b) => + a.day === a.bday ? a.hours - b.hours : a.day - b.day, + ) + sorted.forEach((schedule, i) => { + newProfile.active_hours.push({ ...schedule, id: i }) + }) + } + return [profile.name, newProfile] + }), + ) + : {} export default function ProfileEditing({ - webhookData, setWebhookData, selectedWebhook, handleClose, isMobile, + webhookData, + setWebhookData, + selectedWebhook, + handleClose, + isMobile, }) { const { t } = useTranslation() const [syncWebhook, { data }] = useMutation(Query.webhook('setProfile'), { fetchPolicy: 'no-cache', }) - const [profiles, setProfiles] = useState(profilesObject(webhookData[selectedWebhook].profile)) + const [profiles, setProfiles] = useState( + profilesObject(webhookData[selectedWebhook].profile), + ) const [copyTo, setCopyTo] = useState( - Object.fromEntries(webhookData[selectedWebhook].profile.map((x) => [x.name, x.name])), + Object.fromEntries( + webhookData[selectedWebhook].profile.map((x) => [x.name, x.name]), + ), ) const [views, setViews] = useState( - Object.fromEntries(webhookData[selectedWebhook].profile.map((x) => [x.name, 'profile'])), + Object.fromEntries( + webhookData[selectedWebhook].profile.map((x) => [x.name, 'profile']), + ), ) - const [newSchedule, setNewSchedule] = useState({ day: 1, hours: '00', mins: '00' }) + const [newSchedule, setNewSchedule] = useState({ + day: 1, + hours: '00', + mins: '00', + }) const [newProfile, setNewProfile] = useState('') const handleAddProfile = () => { - setProfiles({ ...profiles, [newProfile]: { name: newProfile, active_hours: [] } }) + setProfiles({ + ...profiles, + [newProfile]: { name: newProfile, active_hours: [] }, + }) setViews({ ...views, [newProfile]: 'profile' }) setNewProfile('') syncWebhook({ @@ -89,7 +121,11 @@ export default function ProfileEditing({ const handleAddSchedule = (profile) => { const active = profiles[profile] const editedProfile = { - ...active, active_hours: [...active.active_hours, { ...newSchedule, id: active.active_hours.length }], + ...active, + active_hours: [ + ...active.active_hours, + { ...newSchedule, id: active.active_hours.length }, + ], } setProfiles({ ...profiles, [profile]: editedProfile }) setViews({ ...views, [profile]: 'profile' }) @@ -108,7 +144,9 @@ export default function ProfileEditing({ ...profiles, [profile]: { ...profiles[profile], - active_hours: profiles[profile].active_hours.filter(schedule => schedule.id !== id), + active_hours: profiles[profile].active_hours.filter( + (schedule) => schedule.id !== id, + ), }, } setProfiles(newProfileObj) @@ -144,7 +182,9 @@ export default function ProfileEditing({ } const getInputs = (profile) => { - const disabled = webhookData[selectedWebhook].human.current_profile_no === profiles[profile].profile_no + const disabled = + webhookData[selectedWebhook].human.current_profile_no === + profiles[profile].profile_no return ( setViews({ ...views, [profile]: 'edit' })}> @@ -178,10 +218,7 @@ export default function ProfileEditing({ return ( <> -
handleClose(false)} - /> +
handleClose(false)} /> @@ -192,11 +229,15 @@ export default function ProfileEditing({ setNewProfile(event.target.value?.toLowerCase())} + onChange={(event) => + setNewProfile(event.target.value?.toLowerCase()) + } variant="outlined" error={Boolean(profiles[newProfile]) || newProfile === 'all'} /> @@ -206,146 +247,205 @@ export default function ProfileEditing({ variant="contained" color="primary" onClick={handleAddProfile} - disabled={Boolean(profiles[newProfile]) || !newProfile || newProfile === 'all'} + disabled={ + Boolean(profiles[newProfile]) || + !newProfile || + newProfile === 'all' + } > {t('save')} - + {Object.keys(profiles).map((profile, i) => ( - - {Boolean(i) && } - {{ - profile: ( - <> - - - {profile} - - - {isMobile && getInputs(profile)} - - {profiles[profile].active_hours.map(schedule => ( - } - size={isMobile ? 'small' : 'medium'} - color="secondary" - onDelete={() => handleRemoveSchedule(profile, schedule.id)} - style={{ margin: 3 }} - /> - ))} - - {!isMobile && getInputs(profile)} - - ), - edit: ( - <> - - - - - - - - setViews({ ...views, [profile]: 'profile' })}> - - - handleAddSchedule(profile)}> - - - - - ), - delete: ( - <> - - - {t('confirm_delete')} - - - - setViews({ ...views, [profile]: 'profile' })}> - - - handleRemoveProfile(profile)}> - - - - - ), - copy: ( - <> - - - - {{ profile }} - - - - + + {Boolean(i) && ( + + )} + { + { + profile: ( + <> + + {profile} + + {isMobile && getInputs(profile)} + {profiles[profile].active_hours.map((schedule) => ( + } + size={isMobile ? 'small' : 'medium'} + color="secondary" + onDelete={() => + handleRemoveSchedule(profile, schedule.id) + } + style={{ margin: 3 }} + /> + ))} + + {!isMobile && getInputs(profile)} + + ), + edit: ( + <> + - - setViews({ ...views, [profile]: 'profile' })}> + + + + + + setViews({ ...views, [profile]: 'profile' }) + } + > - handleCopyProfile(profile)} disabled={profile === copyTo[profile]}> - + handleAddSchedule(profile)} + > + + + + + ), + delete: ( + <> + + + {t('confirm_delete')} + + + + + setViews({ ...views, [profile]: 'profile' }) + } + > + + handleRemoveProfile(profile)} + > + + + + + ), + copy: ( + <> + + + {{ profile }} + + + + + + + + + setViews({ ...views, [profile]: 'profile' }) + } + > + + + handleCopyProfile(profile)} + disabled={profile === copyTo[profile]} + > + + + - - - ), - }[views[profile]]} + + ), + }[views[profile]] + } ))}
diff --git a/src/components/layout/dialogs/webhooks/Selecting.jsx b/src/components/layout/dialogs/webhooks/Selecting.jsx index e2b72f824..431125319 100644 --- a/src/components/layout/dialogs/webhooks/Selecting.jsx +++ b/src/components/layout/dialogs/webhooks/Selecting.jsx @@ -18,9 +18,7 @@ export default function Selecting({ setSelected, handleAll, deleteAll }) { variant="extended" onClick={() => setSelected({})} > - - {t('cancel')} - + {t('cancel')} @@ -30,9 +28,7 @@ export default function Selecting({ setSelected, handleAll, deleteAll }) { variant="extended" onClick={handleAll} > - - {t('select_all')} - + {t('select_all')} @@ -42,9 +38,7 @@ export default function Selecting({ setSelected, handleAll, deleteAll }) { variant="extended" onClick={deleteAll} > - - {t('delete_all')} - + {t('delete_all')} diff --git a/src/components/layout/dialogs/webhooks/Tracked.jsx b/src/components/layout/dialogs/webhooks/Tracked.jsx index df33eb9d2..6aa05748f 100644 --- a/src/components/layout/dialogs/webhooks/Tracked.jsx +++ b/src/components/layout/dialogs/webhooks/Tracked.jsx @@ -12,18 +12,31 @@ import PokemonTile from './tiles/TrackedTile' import Selecting from './Selecting' const Tracked = ({ - isMobile, webhookData, selectedWebhook, Icons, send, setSend, - tempFilters, setTempFilters, setWebhookData, category, Poracle, - setWebhookAlert, t, + isMobile, + webhookData, + selectedWebhook, + Icons, + send, + setSend, + tempFilters, + setTempFilters, + setWebhookData, + category, + Poracle, + setWebhookAlert, + t, }) => { - const [syncWebhook, { data: newWebhookData }] = useMutation(Query.webhook(category), { - fetchPolicy: 'no-cache', - }) + const [syncWebhook, { data: newWebhookData }] = useMutation( + Query.webhook(category), + { + fetchPolicy: 'no-cache', + }, + ) const [search, setSearch] = useState('') const [tracked, setTracked] = useState(webhookData[selectedWebhook][category]) const [selected, setSelected] = useState({}) const [staticInfo] = useState(webhookData[selectedWebhook].info) - const { invasions } = useStatic(s => s.masterfile) + const { invasions } = useStatic((s) => s.masterfile) useEffect(() => { if (newWebhookData?.webhook?.[category]) { @@ -33,7 +46,11 @@ const Tracked = ({ setWebhookAlert({ open: true, severity: newWebhookData.webhook.status, - message: {{ name: selectedWebhook }}, + message: ( + + {{ name: selectedWebhook }} + + ), }) } }, [newWebhookData]) @@ -43,7 +60,10 @@ const Tracked = ({ setSend(false) setTempFilters( Object.fromEntries( - Object.entries(tempFilters || {}).map(([key, value]) => [key, { ...value, enabled: false }]), + Object.entries(tempFilters || {}).map(([key, value]) => [ + key, + { ...value, enabled: false }, + ]), ), ) syncWebhook({ @@ -51,7 +71,7 @@ const Tracked = ({ category, data: Poracle.processor( category, - Object.values(tempFilters || {}).filter(x => x && x.enabled), + Object.values(tempFilters || {}).filter((x) => x && x.enabled), staticInfo[category].defaults, ), name: selectedWebhook, @@ -61,30 +81,51 @@ const Tracked = ({ } }, [send]) - useEffect(() => () => setWebhookData({ - ...webhookData, - [selectedWebhook]: { - ...webhookData[selectedWebhook], - [category]: tracked, - }, - })) + useEffect( + () => () => + setWebhookData({ + ...webhookData, + [selectedWebhook]: { + ...webhookData[selectedWebhook], + [category]: tracked, + }, + }), + ) - const profileFiltered = useMemo(() => tracked - .filter(x => x.profile_no === webhookData[selectedWebhook].human.current_profile_no) - .map(y => ({ - ...y, - description: Poracle.generateDescription(y, category, webhookData[selectedWebhook].leagues, t)?.replace(/\*/g, '') || '', - })) - .sort((a, b) => ( - a[staticInfo[category].sortProp] - b[staticInfo[category].sortProp] - )), [tracked, webhookData[selectedWebhook].human.current_profile_no]) + const profileFiltered = useMemo( + () => + tracked + .filter( + (x) => + x.profile_no === + webhookData[selectedWebhook].human.current_profile_no, + ) + .map((y) => ({ + ...y, + description: + Poracle.generateDescription( + y, + category, + webhookData[selectedWebhook].leagues, + t, + )?.replace(/\*/g, '') || '', + })) + .sort( + (a, b) => + a[staticInfo[category].sortProp] - b[staticInfo[category].sortProp], + ), + [tracked, webhookData[selectedWebhook].human.current_profile_no], + ) - const searchFiltered = profileFiltered.filter(x => x.description.toLowerCase().includes(search) - || (x.pokemon_id && x.pokemon_id?.toString()?.includes(search))) + const searchFiltered = profileFiltered.filter( + (x) => + x.description.toLowerCase().includes(search) || + (x.pokemon_id && x.pokemon_id?.toString()?.includes(search)), + ) const handleAll = () => { const newObj = {} - tracked.forEach(entry => { + tracked.forEach((entry) => { newObj[entry.uid] = true }) setSelected(newObj) @@ -94,7 +135,7 @@ const Tracked = ({ syncWebhook({ variables: { category: `${category}-delete`, - data: Object.keys(selected).filter(x => selected[x]), + data: Object.keys(selected).filter((x) => selected[x]), name: selectedWebhook, status: 'POST', }, @@ -104,11 +145,7 @@ const Tracked = ({ return (
- + {searchFiltered.length ? ( ) : (
- + {t('no_alerts')} @@ -145,8 +188,12 @@ const Tracked = ({
)} - {Object.values(selected).some(x => x) && ( - + {Object.values(selected).some((x) => x) && ( + )}
) @@ -155,12 +202,15 @@ const Tracked = ({ const areEqual = (prev, next) => { const prevSelected = prev.webhookData[prev.selectedWebhook] const nextSelected = next.webhookData[next.selectedWebhook] - return prevSelected[prev.category].length === nextSelected[next.category].length - && prev.addNew === next.addNew - && prevSelected.human.current_profile_no === nextSelected.human.current_profile_no - && prevSelected.fetched === nextSelected.fetched - && prev.send === next.send - && prev.isMobile === next.isMobile + return ( + prevSelected[prev.category].length === nextSelected[next.category].length && + prev.addNew === next.addNew && + prevSelected.human.current_profile_no === + nextSelected.human.current_profile_no && + prevSelected.fetched === nextSelected.fetched && + prev.send === next.send && + prev.isMobile === next.isMobile + ) } export default memo(Tracked, areEqual) diff --git a/src/components/layout/dialogs/webhooks/Webhook.jsx b/src/components/layout/dialogs/webhooks/Webhook.jsx index b395bb046..9dfbd91f5 100644 --- a/src/components/layout/dialogs/webhooks/Webhook.jsx +++ b/src/components/layout/dialogs/webhooks/Webhook.jsx @@ -1,7 +1,5 @@ import React, { useState } from 'react' -import { - useMediaQuery, Dialog, -} from '@material-ui/core' +import { useMediaQuery, Dialog } from '@material-ui/core' import { useTheme } from '@material-ui/core/styles' import useStyles from '@hooks/useStyles' @@ -11,9 +9,7 @@ import DraggableMarker from './Draggable' import Manage from './Manage' import AreaSelection from './AreaSelection' -export default function Main({ - webhookMode, setWebhookMode, Icons, map, -}) { +export default function Main({ webhookMode, setWebhookMode, Icons, map }) { const theme = useTheme() const classes = useStyles() const isMobile = useMediaQuery(theme.breakpoints.only('xs')) @@ -22,11 +18,11 @@ export default function Main({ const [selectedAreas, setSelectedAreas] = useState([]) const [webhookLocation, setWebhookLocation] = useState([]) - const webhookData = useStatic(s => s.webhookData) - const setWebhookData = useStatic(s => s.setWebhookData) + const webhookData = useStatic((s) => s.webhookData) + const setWebhookData = useStatic((s) => s.setWebhookData) - const selectedWebhook = useStore(s => s.selectedWebhook) - const setSelectedWebhook = useStore(s => s.setSelectedWebhook) + const selectedWebhook = useStore((s) => s.selectedWebhook) + const setSelectedWebhook = useStore((s) => s.setSelectedWebhook) return ( <> diff --git a/src/components/layout/dialogs/webhooks/WebhookAdv.jsx b/src/components/layout/dialogs/webhooks/WebhookAdv.jsx index 199ea03ab..e9bee5aee 100644 --- a/src/components/layout/dialogs/webhooks/WebhookAdv.jsx +++ b/src/components/layout/dialogs/webhooks/WebhookAdv.jsx @@ -34,47 +34,110 @@ import SliderTile from '@components/layout/dialogs/filters/SliderTile' import Header from '@components/layout/general/Header' import Footer from '@components/layout/general/Footer' -const skipFields = ['profile_no', 'allForms', 'pvpEntry', 'noIv', 'byDistance', 'distance', 'xs', 'xl', 'clean', 'gender', 'description', 'uid', 'id', 'ping', 'pokemon_id', 'form', '__typename', 'allMoves', 'enabled', 'level', 'exclusive', 'lure_id', 'reward', 'reward_type', 'grunt_type', 'grunt_id', 'gym_id', 'slot_changes', 'team', 'battle_changes', 'shiny', 'everything_individually'] +const skipFields = [ + 'profile_no', + 'allForms', + 'pvpEntry', + 'noIv', + 'byDistance', + 'distance', + 'xs', + 'xl', + 'clean', + 'gender', + 'description', + 'uid', + 'id', + 'ping', + 'pokemon_id', + 'form', + '__typename', + 'allMoves', + 'enabled', + 'level', + 'exclusive', + 'lure_id', + 'reward', + 'reward_type', + 'grunt_type', + 'grunt_id', + 'gym_id', + 'slot_changes', + 'team', + 'battle_changes', + 'shiny', + 'everything_individually', +] export default function WebhookAdvanced({ - category, id, toggleWebhook, tempFilters, isMobile, + category, + id, + toggleWebhook, + tempFilters, + isMobile, }) { const idObj = Poracle.getIdObj(id) const { t } = useTranslation() const classes = useStyles() - const location = useStore(state => state.location) - const selectedWebhook = useStore(s => s.selectedWebhook) - const webhookAdv = useStore(s => s.webhookAdv) - const setWebhookAdv = useStore(s => s.setWebhookAdv) - const { [selectedWebhook]: { - info: { [category]: info }, - profile, human, templates, prefix, leagues, pvp, addressFormat, hasNominatim, locale, everything, - } } = useStatic(s => s.webhookData) - const { pokemon, moves, types } = useStatic(s => s.masterfile) + const location = useStore((state) => state.location) + const selectedWebhook = useStore((s) => s.selectedWebhook) + const webhookAdv = useStore((s) => s.webhookAdv) + const setWebhookAdv = useStore((s) => s.setWebhookAdv) + const { + [selectedWebhook]: { + info: { [category]: info }, + profile, + human, + templates, + prefix, + leagues, + pvp, + addressFormat, + hasNominatim, + locale, + everything, + }, + } = useStatic((s) => s.webhookData) + const { pokemon, moves, types } = useStatic((s) => s.masterfile) Utility.analytics(`/poracle/${category}`) - const [search, { data, previousData, loading }] = useLazyQuery(Query.search('webhook'), { - variables: { - search: '', - category: '', - lat: location[0], - lon: location[1], - locale: localStorage.getItem('i18nextLng'), - webhookName: selectedWebhook, + const [search, { data, previousData, loading }] = useLazyQuery( + Query.search('webhook'), + { + variables: { + search: '', + category: '', + lat: location[0], + lon: location[1], + locale: localStorage.getItem('i18nextLng'), + webhookName: selectedWebhook, + }, }, - }) + ) const fetchedData = data || previousData - const [filterValues, setFilterValues] = useState(tempFilters?.template - ? Poracle.reactMapFriendly(tempFilters) - : { ...Poracle.reactMapFriendly(info.defaults), profile_no: human.current_profile_no }) - const [poracleValues, setPoracleValues] = useState(tempFilters?.template - ? tempFilters - : { ...info.defaults, profile_no: human.current_profile_no }) + const [filterValues, setFilterValues] = useState( + tempFilters?.template + ? Poracle.reactMapFriendly(tempFilters) + : { + ...Poracle.reactMapFriendly(info.defaults), + profile_no: human.current_profile_no, + }, + ) + const [poracleValues, setPoracleValues] = useState( + tempFilters?.template + ? tempFilters + : { ...info.defaults, profile_no: human.current_profile_no }, + ) const handleSlider = (event, values, low, high) => { setFilterValues({ ...filterValues, [event]: values }) - setPoracleValues({ ...poracleValues, [low]: values[0], [high]: values[1], pvpEntry: event.startsWith('pvp') }) + setPoracleValues({ + ...poracleValues, + [low]: values[0], + [high]: values[1], + pvpEntry: event.startsWith('pvp'), + }) } const handleSwitch = (event) => { @@ -83,44 +146,55 @@ export default function WebhookAdvanced({ case 'xl': setPoracleValues({ ...poracleValues, - min_weight: checked ? Math.ceil(pokemon[idObj.id].weight * 1.313) : info.defaults.min_weight, + min_weight: checked + ? Math.ceil(pokemon[idObj.id].weight * 1.313) + : info.defaults.min_weight, max_weight: info.defaults.max_weight, [name]: checked, xs: false, - }); break + }) + break case 'xs': setPoracleValues({ ...poracleValues, min_weight: info.defaults.min_weight, - max_weight: checked ? Math.floor(pokemon[idObj.id].weight / 1.6431924) : info.defaults.max_weight, + max_weight: checked + ? Math.floor(pokemon[idObj.id].weight / 1.6431924) + : info.defaults.max_weight, [name]: checked, xl: false, - }); break + }) + break case 'noIv': setPoracleValues({ ...poracleValues, [name]: checked, pvpEntry: false, - }); break + }) + break case 'pvpEntry': setPoracleValues({ ...poracleValues, [name]: checked, noIv: false, - }); break + }) + break case 'allMoves': setPoracleValues({ ...poracleValues, [name]: checked, move: 9000, - }); break + }) + break case 'byDistance': setPoracleValues({ ...poracleValues, [name]: checked, distance: 0, - }); break - default: setPoracleValues({ ...poracleValues, [name]: checked }) + }) + break + default: + setPoracleValues({ ...poracleValues, [name]: checked }) } } @@ -147,124 +221,252 @@ export default function WebhookAdvanced({ } const footerOptions = [ - { name: 'save', action: toggleWebhook(false, id, poracleValues), icon: 'Save' }, + { + name: 'save', + action: toggleWebhook(false, id, poracleValues), + icon: 'Save', + }, ] const getOptions = (option) => { const menuItems = [] switch (option.name) { - case 'template': templates[poracleValues.noIv ? `${category}NoIv` : category]?.[locale]?.forEach(item => ( - menuItems.push({item}) - )); break + case 'template': + templates[poracleValues.noIv ? `${category}NoIv` : category]?.[ + locale + ]?.forEach((item) => + menuItems.push( + + {item} + , + ), + ) + break case 'profile_no': if (profile.length) { - profile.forEach(pro => ( - menuItems.push({pro.name}) - )) + profile.forEach((pro) => + menuItems.push( + + {pro.name} + , + ), + ) } else { - menuItems.push(1) - } break - case 'pvp_ranking_cap': option.options.forEach(subOption => ( - menuItems.push({subOption ? t(subOption, subOption) : t('all')}) - )); break - case 'pvp_ranking_league': option.options.forEach(league => ( - menuItems.push({t(`slider_${league.name}`)}) - )); break - case 'gender': option.options.forEach(gender => ( - menuItems.push({t(`gender_${gender}`)}) - )); break - case 'team': option.options.forEach(team => ( - menuItems.push({t(`team_${team}`, t('any'))}) - )); break + menuItems.push( + + 1 + , + ) + } + break + case 'pvp_ranking_cap': + option.options.forEach((subOption) => + menuItems.push( + + {subOption ? t(subOption, subOption) : t('all')} + , + ), + ) + break + case 'pvp_ranking_league': + option.options.forEach((league) => + menuItems.push( + + {t(`slider_${league.name}`)} + , + ), + ) + break + case 'gender': + option.options.forEach((gender) => + menuItems.push( + + {t(`gender_${gender}`)} + , + ), + ) + break + case 'team': + option.options.forEach((team) => + menuItems.push( + + {t(`team_${team}`, t('any'))} + , + ), + ) + break case 'move': - menuItems.push({t('any')}) + menuItems.push( + + {t('any')} + , + ) if (id === 'global') { - Object.keys(moves).forEach(move => { + Object.keys(moves).forEach((move) => { if (moves[move].type) { - menuItems.push({t(`move_${move}`)}) + menuItems.push( + + {t(`move_${move}`)} + , + ) } }) } else if (pokemon[idObj.id]) { - ['quickMoves', 'chargedMoves'].forEach(moveType => { + ;['quickMoves', 'chargedMoves'].forEach((moveType) => { if (pokemon[idObj.id]?.forms?.[idObj.form]?.[moveType]) { - pokemon[idObj.id]?.forms?.[idObj.form]?.[moveType].forEach(move => { - menuItems.push({t(`move_${move}`)}) - }) + pokemon[idObj.id]?.forms?.[idObj.form]?.[moveType].forEach( + (move) => { + menuItems.push( + + {t(`move_${move}`)} + , + ) + }, + ) } else if (pokemon[idObj.id][moveType]) { - pokemon[idObj.id][moveType].forEach(move => { - menuItems.push({t(`move_${move}`)}) + pokemon[idObj.id][moveType].forEach((move) => { + menuItems.push( + + {t(`move_${move}`)} + , + ) }) } }) - } break - default: option.options.forEach(subOption => ( - menuItems.push({t(subOption, subOption)}) - )) + } + break + default: + option.options.forEach((subOption) => + menuItems.push( + + {t(subOption, subOption)} + , + ), + ) } return menuItems } const checkDefaults = (field) => { - if (field === 'distance' && poracleValues.byDistance && parseInt(poracleValues.distance)) return `d${poracleValues.distance}` - if (field === 'min_time' && parseInt(poracleValues.min_time)) return `t${poracleValues.min_time}` - if (field === 'exclusive' && poracleValues.exclusive) return ` ${t('exclusive')} ` + if ( + field === 'distance' && + poracleValues.byDistance && + parseInt(poracleValues.distance) + ) + return `d${poracleValues.distance}` + if (field === 'min_time' && parseInt(poracleValues.min_time)) + return `t${poracleValues.min_time}` + if (field === 'exclusive' && poracleValues.exclusive) + return ` ${t('exclusive')} ` if (field === 'clean' && poracleValues.clean) return ` ${t('clean')} ` - if (field === 'min_spawn_avg' && poracleValues.min_spawn_avg > 0) return ` ${t('minspawn')}${poracleValues.min_spawn_avg} ` - if (field === 'slot_changes' && poracleValues.slot_changes) return ` ${t('slot_changes_poracle')} ` - if (field === 'battle_changes' && poracleValues.battle_changes) return ` ${t('battle_changes_poracle')} ` - if (field === 'team' && poracleValues.team !== 4) return t(`team_${poracleValues.team}`) - if (field === 'everything_individually' && poracleValues.everything_individually) return ` ${t('individually')} ` + if (field === 'min_spawn_avg' && poracleValues.min_spawn_avg > 0) + return ` ${t('minspawn')}${poracleValues.min_spawn_avg} ` + if (field === 'slot_changes' && poracleValues.slot_changes) + return ` ${t('slot_changes_poracle')} ` + if (field === 'battle_changes' && poracleValues.battle_changes) + return ` ${t('battle_changes_poracle')} ` + if (field === 'team' && poracleValues.team !== 4) + return t(`team_${poracleValues.team}`) + if ( + field === 'everything_individually' && + poracleValues.everything_individually + ) + return ` ${t('individually')} ` if (skipFields.includes(field)) return '' if (field.startsWith('pvp')) { - if (poracleValues.pvpEntry && poracleValues.pvp_ranking_league && poracleValues[field] !== info.defaults[field]) { - const league = leagues.find(x => x.cp === poracleValues.pvp_ranking_league) || {} + if ( + poracleValues.pvpEntry && + poracleValues.pvp_ranking_league && + poracleValues[field] !== info.defaults[field] + ) { + const league = + leagues.find((x) => x.cp === poracleValues.pvp_ranking_league) || {} switch (field) { case 'pvp_ranking_min_cp': - return pvp === 'ohbem' ? '' : `${league.name}${t('cp')}${poracleValues.pvp_ranking_min_cp}` + return pvp === 'ohbem' + ? '' + : `${league.name}${t('cp')}${poracleValues.pvp_ranking_min_cp}` case 'pvp_ranking_worst': return `${league.name}${poracleValues.pvp_ranking_worst}` case 'pvp_ranking_best': return `${league.name}high${poracleValues.pvp_ranking_best}` case 'pvp_ranking_cap': - return pvp === 'ohbem' ? `${t('cap').toLowerCase()}${poracleValues.pvp_ranking_cap}` : '' - default: return '' + return pvp === 'ohbem' + ? `${t('cap').toLowerCase()}${poracleValues.pvp_ranking_cap}` + : '' + default: + return '' } } return '' } if (!poracleValues.pvpEntry) { - return poracleValues[field] === info.defaults[field] ? '' : `${field.replace(/_/g, '').replace('min', '')}${poracleValues[field]}` + return poracleValues[field] === info.defaults[field] + ? '' + : `${field.replace(/_/g, '').replace('min', '')}${poracleValues[field]}` } } const getPoracleString = () => { switch (id.charAt(0)) { - case 't': return `${prefix}${t('gym')} + case 't': + return `${prefix}${t('gym')} ${Object.keys(poracleValues).map(checkDefaults).join(' ')}` case 'r': - case 'e': return `${prefix}${id.charAt(0) === 'e' ? t('egg') : t('raid')} ${t('level')}${idObj.id} + case 'e': + return `${prefix}${id.charAt(0) === 'e' ? t('egg') : t('raid')} ${t( + 'level', + )}${idObj.id} ${Object.keys(poracleValues).map(checkDefaults).join(' ')}` case 'i': { - const invasion = Object.keys(types).find(x => types[x].toLowerCase() === poracleValues.grunt_type) - return `${prefix}${t('invasion')} ${invasion ? t(`poke_type_${invasion}`) : t(poracleValues.grunt_type.replace(' ', ''))} + const invasion = Object.keys(types).find( + (x) => types[x].toLowerCase() === poracleValues.grunt_type, + ) + return `${prefix}${t('invasion')} ${ + invasion + ? t(`poke_type_${invasion}`) + : t(poracleValues.grunt_type.replace(' ', '')) + } ${Object.keys(poracleValues).map(checkDefaults).join(' ')}` } - case 'q': return `${prefix}${t('quest')} ${t(`item_${idObj.id}`).replace(' ', '_')} + case 'q': + return `${prefix}${t('quest')} ${t(`item_${idObj.id}`).replace( + ' ', + '_', + )} ${Object.keys(poracleValues).map(checkDefaults).join(' ')}` - case 'm': return `${prefix}${t('quest')} ${t('energy')}${t(`poke_${idObj.id}`)} + case 'm': + return `${prefix}${t('quest')} ${t('energy')}${t(`poke_${idObj.id}`)} ${Object.keys(poracleValues).map(checkDefaults).join(' ')}` - case 'c': return `${prefix}${t('quest')} ${t('candy')}${t(`poke_${idObj.id}`)} + case 'c': + return `${prefix}${t('quest')} ${t('candy')}${t(`poke_${idObj.id}`)} ${Object.keys(poracleValues).map(checkDefaults).join(' ')}` - case 'x': return `${prefix}${t('quest')} ${t('xl')}${t(`poke_${idObj.id}`)} + case 'x': + return `${prefix}${t('quest')} ${t('xl')}${t(`poke_${idObj.id}`)} ${Object.keys(poracleValues).map(checkDefaults).join(' ')}` - case 'd': return `${prefix}${t('quest')} ${t('stardust')} + case 'd': + return `${prefix}${t('quest')} ${t('stardust')} ${Object.keys(poracleValues).map(checkDefaults).join(' ')}` - case 'l': return `${prefix}${t('lure')} ${t(`lure_${idObj.id}`).toLowerCase()} + case 'l': + return `${prefix}${t('lure')} ${t(`lure_${idObj.id}`).toLowerCase()} ${Object.keys(poracleValues).map(checkDefaults).join(' ')}` - default: return `${prefix}${category === 'pokemon' ? t('track') : t(category)} + default: + return `${prefix}${category === 'pokemon' ? t('track') : t(category)} ${t(`poke_${idObj.id === '0' ? 'global' : idObj.id}`)} - ${!poracleValues.allForms && +idObj.form ? `form:${t(`form_${idObj.form}`).replace(/ /g, '_')}` : ''} - ${poracleValues.noIv ? `${poracleValues.clean ? ` ${t('clean')} ` : ''}${poracleValues.byDistance && parseInt(poracleValues.distance) ? ` d${poracleValues.distance} ` : ''}` : Object.keys(poracleValues).map(checkDefaults).join(' ')} + ${ + !poracleValues.allForms && +idObj.form + ? `form:${t(`form_${idObj.form}`).replace(/ /g, '_')}` + : '' + } + ${ + poracleValues.noIv + ? `${poracleValues.clean ? ` ${t('clean')} ` : ''}${ + poracleValues.byDistance && parseInt(poracleValues.distance) + ? ` d${poracleValues.distance} ` + : '' + }` + : Object.keys(poracleValues).map(checkDefaults).join(' ') + } ${poracleValues.gender ? ` ${t(`gender_${poracleValues.gender}`)}` : ''}` } } @@ -272,185 +474,242 @@ export default function WebhookAdvanced({ const getDisabled = (option) => { switch (option.name) { case 'xl': - case 'xs': return !pokemon[idObj.id] - case 'allForms': return idObj.id === '0' - case 'distance': return !poracleValues.byDistance - case 'amount': return option?.disabled?.some(x => id.startsWith(x)) || /\d/.test(id.charAt(0)) - case 'pvpEntry': return human.blocked_alerts?.includes('pvp') - default: return option?.disabled?.some(x => id.startsWith(x)) + case 'xs': + return !pokemon[idObj.id] + case 'allForms': + return idObj.id === '0' + case 'distance': + return !poracleValues.byDistance + case 'amount': + return ( + option?.disabled?.some((x) => id.startsWith(x)) || + /\d/.test(id.charAt(0)) + ) + case 'pvpEntry': + return human.blocked_alerts?.includes('pvp') + default: + return option?.disabled?.some((x) => id.startsWith(x)) } } const getInputs = (type, options, parent) => { const size = Math.floor(12 / options.length) switch (type) { - case 'sliders': return options.map((option, i) => ( - - - - )) - case 'selects': return options.map(option => ( - - - {t(option.name)} - + {getOptions(option)} + + + + )) + case 'booleans': + return options.map((option) => ( + + + + {t(Utility.camelToSnake(option.name))} + + + + + + + )) + case 'texts': + return options.map((option) => ( + + - {getOptions(option)} - - - - )) - case 'booleans': return options.map(option => ( - - - - {t(Utility.camelToSnake(option.name))} - - - - x.cp === poracleValues.pvp_ranking_league, + )?.min || 0 + : option.min || 0, + max: + option.name === 'pvp_ranking_min_cp' && + poracleValues.pvp_ranking_league + ? poracleValues.pvp_ranking_league || 0 + : option.max || 10000, + }} + InputProps={{ + endAdornment: option.adornment ? ( + + {t(option.adornment)} + + ) : null, + }} /> - - )) - case 'texts': return options.map(option => ( - - x.cp === poracleValues.pvp_ranking_league)?.min || 0 - : option.min || 0, - max: option.name === 'pvp_ranking_min_cp' && poracleValues.pvp_ranking_league - ? poracleValues.pvp_ranking_league || 0 - : option.max || 10000, - }} - InputProps={{ - endAdornment: option.adornment - ? {t(option.adornment)} - : null, - }} - /> - - )) - case 'autoComplete': return options.map(option => ( - - - `${x.name} - ${Utility.formatter(addressFormat, x.formatted)}`} - filterOptions={(x) => x} - options={fetchedData ? fetchedData.search : []} - autoComplete - disabled={!hasNominatim} - includeInputInList - freeSolo - onChange={(event, newValue) => { - if (newValue) { - setPoracleValues({ ...poracleValues, gym_id: newValue.id }) + )) + case 'autoComplete': + return options.map((option) => ( + + + + `${x.name} - ${Utility.formatter(addressFormat, x.formatted)}` } - }} - renderInput={(params) => ( - {{ category: t(option.label) }}} - variant="outlined" - onChange={(e) => search({ - variables: { - search: e.target.value, - category: option.searchCategory, - ts: Math.floor(Date.now() / 1000), - }, - })} - InputProps={{ - ...params.InputProps, - endAdornment: ( - <> - {loading ? : null} - {params.InputProps.endAdornment} - - ), - }} - /> - )} - renderOption={(x) => ( - - - - {x.name} - - - - - {Utility.formatter(addressFormat, x.formatted)} - + filterOptions={(x) => x} + options={fetchedData ? fetchedData.search : []} + autoComplete + disabled={!hasNominatim} + includeInputInList + freeSolo + onChange={(event, newValue) => { + if (newValue) { + setPoracleValues({ ...poracleValues, gym_id: newValue.id }) + } + }} + renderInput={(params) => ( + + {{ category: t(option.label) }} + + } + variant="outlined" + onChange={(e) => + search({ + variables: { + search: e.target.value, + category: option.searchCategory, + ts: Math.floor(Date.now() / 1000), + }, + }) + } + InputProps={{ + ...params.InputProps, + endAdornment: ( + <> + {loading ? ( + + ) : null} + {params.InputProps.endAdornment} + + ), + }} + /> + )} + renderOption={(x) => ( + + + {x.name} + + + + {Utility.formatter(addressFormat, x.formatted)} + + + - - - )} - /> + )} + /> + - - )) + )) // Recursive for nested props - default: return ( - - - {Object.keys(info.ui[parent][type]).map(subType => ( - getInputs(subType, info.ui[parent][type][subType], type) - ))} - - ) + default: + return ( + + + {Object.keys(info.ui[parent][type]).map((subType) => + getInputs(subType, info.ui[parent][type][subType], type), + )} + + ) } } @@ -461,21 +720,32 @@ export default function WebhookAdvanced({ action={toggleWebhook(false, id)} /> - {Object.keys(info.ui).map(type => { - if (human.blocked_alerts && JSON.parse(human.blocked_alerts).includes(type)) return null - if (type === 'global' && (idObj.id !== 'global' || !everything)) return null + {Object.keys(info.ui).map((type) => { + if ( + human.blocked_alerts && + JSON.parse(human.blocked_alerts).includes(type) + ) + return null + if (type === 'global' && (idObj.id !== 'global' || !everything)) + return null const Items = ( - - {Object.keys(info.ui[type]).map(subType => (getInputs(subType, info.ui[type][subType], type)))} + + {Object.keys(info.ui[type]).map((subType) => + getInputs(subType, info.ui[type][subType], type), + )} ) return ( - - {(type === 'general' || type === 'distanceOrArea' || type === 'global') ? Items : ( + + {type === 'general' || + type === 'distanceOrArea' || + type === 'global' ? ( + Items + ) : ( - - {Items} - + {Items} )} ) })} - + {getPoracleString().toLowerCase()} diff --git a/src/components/layout/dialogs/webhooks/tiles/TrackedTile.jsx b/src/components/layout/dialogs/webhooks/tiles/TrackedTile.jsx index 20fbf744f..7a5a8b683 100644 --- a/src/components/layout/dialogs/webhooks/tiles/TrackedTile.jsx +++ b/src/components/layout/dialogs/webhooks/tiles/TrackedTile.jsx @@ -1,6 +1,10 @@ import React, { useState } from 'react' import { - Grid, Typography, IconButton, Dialog, Checkbox, + Grid, + Typography, + IconButton, + Dialog, + Checkbox, } from '@material-ui/core' import { DeleteForever, Edit } from '@material-ui/icons' @@ -8,19 +12,40 @@ import WebhookAdvanced from '@components/layout/dialogs/webhooks/WebhookAdv' export default function PokemonTile({ data, rowIndex, columnIndex, style }) { const { - tileItem, columnCount, Icons, syncWebhook, selectedWebhook, selected, setSelected, Utility, - tracked, setTracked, isMobile, setSend, setTempFilters, category, Poracle, invasions, + tileItem, + columnCount, + Icons, + syncWebhook, + selectedWebhook, + selected, + setSelected, + Utility, + tracked, + setTracked, + isMobile, + setSend, + setTempFilters, + category, + Poracle, + invasions, } = data const [editDialog, setEditDialog] = useState(false) const item = tileItem[rowIndex * columnCount + columnIndex] if (!item) return null const toggleWebhook = (open, id, newFilters) => (event) => { - if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) { + if ( + event.type === 'keydown' && + (event.key === 'Tab' || event.key === 'Shift') + ) { return } setEditDialog(open) - if (id && newFilters && !Object.keys(newFilters).every(key => newFilters[key] === item[key])) { + if ( + id && + newFilters && + !Object.keys(newFilters).every((key) => newFilters[key] === item[key]) + ) { // eslint-disable-next-line camelcase setTempFilters({ [id]: { ...newFilters, enabled: true } }) setSend(true) @@ -37,8 +62,9 @@ export default function PokemonTile({ data, rowIndex, columnIndex, style }) { } if (category === 'invasion') { item.grunt_id = Object.keys(invasions).find( - key => invasions[key]?.type?.toLowerCase() === item.grunt_type.toLowerCase() - && invasions[key].gender === (item.gender || 1), + (key) => + invasions[key]?.type?.toLowerCase() === item.grunt_type.toLowerCase() && + invasions[key].gender === (item.gender || 1), ) } if (category === 'pokemon') { @@ -69,9 +95,7 @@ export default function PokemonTile({ data, rowIndex, columnIndex, style }) { /> - - {item.description} - + {item.description} setEditDialog(true)}> @@ -80,7 +104,7 @@ export default function PokemonTile({ data, rowIndex, columnIndex, style }) { { - setTracked(tracked.filter(p => p.uid !== item.uid)) + setTracked(tracked.filter((p) => p.uid !== item.uid)) syncWebhook({ variables: { category, diff --git a/src/components/layout/dialogs/webhooks/tiles/WebhookTile.jsx b/src/components/layout/dialogs/webhooks/tiles/WebhookTile.jsx index ec3edaea0..9733144f7 100644 --- a/src/components/layout/dialogs/webhooks/tiles/WebhookTile.jsx +++ b/src/components/layout/dialogs/webhooks/tiles/WebhookTile.jsx @@ -1,22 +1,27 @@ import React, { useState } from 'react' import { Grid, IconButton, Typography } from '@material-ui/core' -import { - Check, Clear, Tune, -} from '@material-ui/icons' +import { Check, Clear, Tune } from '@material-ui/icons' const getOtherData = (id) => { switch (id.charAt(0)) { case 'e': - case 'r': return { level: id.slice(1) } - default: return { pokemon_id: id.split('-')[0], form: id.split('-')[1] } + case 'r': + return { level: id.slice(1) } + default: + return { pokemon_id: id.split('-')[0], form: id.split('-')[1] } } } -export default function NewPokemon({ - data, rowIndex, columnIndex, style, -}) { +export default function NewPokemon({ data, rowIndex, columnIndex, style }) { const [name, setName] = useState(true) const { - tileItem, columnCount, tempFilters, setTempFilters, isMobile, type, Utility, toggleWebhook, + tileItem, + columnCount, + tempFilters, + setTempFilters, + isMobile, + type, + Utility, + toggleWebhook, } = data const item = tileItem[rowIndex * columnCount + columnIndex] @@ -28,12 +33,18 @@ export default function NewPokemon({ const handleFilterChange = () => { setTempFilters({ ...tempFilters, - [item.id]: tempFilters[item.id] ? { - ...tempFilters[item.id], - enabled: !tempFilters[item.id]?.enabled, - } : tempFilters[item.id] = { enabled: true, ...getOtherData(item.id) }, + [item.id]: tempFilters[item.id] + ? { + ...tempFilters[item.id], + enabled: !tempFilters[item.id]?.enabled, + } + : (tempFilters[item.id] = { enabled: true, ...getOtherData(item.id) }), }) - Utility.analytics('Webhook Filtering', `${item.name} Status: ${!tempFilters[item.id]?.enabled}`, type) + Utility.analytics( + 'Webhook Filtering', + `${item.name} Status: ${!tempFilters[item.id]?.enabled}`, + type, + ) } const image = ( @@ -50,16 +61,16 @@ export default function NewPokemon({ ) const selection = ( - {tempFilters[item.id] && tempFilters[item.id]?.enabled - ? - : } + {tempFilters[item.id] && tempFilters[item.id]?.enabled ? ( + + ) : ( + + )} ) const advMenu = ( - + ) diff --git a/src/components/layout/drawer/Areas.jsx b/src/components/layout/drawer/Areas.jsx index 8250e76c9..1c0eee568 100644 --- a/src/components/layout/drawer/Areas.jsx +++ b/src/components/layout/drawer/Areas.jsx @@ -1,8 +1,6 @@ import React from 'react' import { useQuery } from '@apollo/client' -import { - Paper, MenuItem, MenuList, Typography, -} from '@material-ui/core' +import { Paper, MenuItem, MenuList, Typography } from '@material-ui/core' import center from '@turf/center' import { useMap } from 'react-leaflet' @@ -27,7 +25,7 @@ export default function AreaDropDown({ scanAreasZoom, manualAreas }) { > {Object.keys(manualAreas).length ? ( - {Object.keys(manualAreas).map(area => ( + {Object.keys(manualAreas).map((area) => ( { @@ -43,19 +41,20 @@ export default function AreaDropDown({ scanAreasZoom, manualAreas }) { ) : ( - {data && data.scanAreas[0].features.map(area => ( - { - const [lon, lat] = center(area).geometry.coordinates - map.flyTo([lat, lon], scanAreasZoom) - }} - > - - {Utility.getProperName(area.properties.name)} - - - ))} + {data && + data.scanAreas[0].features.map((area) => ( + { + const [lon, lat] = center(area).geometry.coordinates + map.flyTo([lat, lon], scanAreasZoom) + }} + > + + {Utility.getProperName(area.properties.name)} + + + ))} )} diff --git a/src/components/layout/drawer/Drawer.jsx b/src/components/layout/drawer/Drawer.jsx index b8ab29e76..da5ff7985 100644 --- a/src/components/layout/drawer/Drawer.jsx +++ b/src/components/layout/drawer/Drawer.jsx @@ -1,6 +1,13 @@ import React from 'react' import { - Drawer, Button, Typography, Accordion, AccordionSummary, AccordionDetails, Grid, IconButton, + Drawer, + Button, + Typography, + Accordion, + AccordionSummary, + AccordionDetails, + Grid, + IconButton, } from '@material-ui/core' import { ExpandMore, Clear, Settings } from '@material-ui/icons' import { useTranslation } from 'react-i18next' @@ -15,28 +22,31 @@ import { useStore, useStatic } from '../../../hooks/useStore' import Areas from './Areas' export default function Sidebar({ - drawer, toggleDrawer, filters, setFilters, toggleDialog, Icons, + drawer, + toggleDrawer, + filters, + setFilters, + toggleDialog, + Icons, }) { - const { drawer: drawerStyle } = useStore(state => state.settings) - const sidebar = useStore(state => state.sidebar) - const setSidebar = useStore(state => state.setSidebar) + const { drawer: drawerStyle } = useStore((state) => state.settings) + const sidebar = useStore((state) => state.sidebar) + const setSidebar = useStore((state) => state.setSidebar) const classes = useStyles() - const ui = useStatic(state => state.ui) - const staticUserSettings = useStatic(state => state.userSettings) + const ui = useStatic((state) => state.ui) + const staticUserSettings = useStatic((state) => state.userSettings) const { manualAreas, - map: { - title, scanAreasZoom, noScanAreaOverlay, enableQuestSetSelector, - }, - } = useStatic(state => state.config) - const available = useStatic(s => s.available) + map: { title, scanAreasZoom, noScanAreaOverlay, enableQuestSetSelector }, + } = useStatic((state) => state.config) + const available = useStatic((s) => s.available) const { t } = useTranslation() const handleChange = (panel) => (event, isExpanded) => { setSidebar(isExpanded ? panel : false) } - const drawerItems = Object.keys(ui).map(category => { + const drawerItems = Object.keys(ui).map((category) => { let content switch (category) { case 'pokemon': @@ -48,27 +58,26 @@ export default function Sidebar({ filters={filters} setFilters={setFilters} /> - ); break + ) + break case 'settings': - content = ( - - ); break + content = + break default: - content = ( - Object.keys(ui[category]).map(subItem => ( - - )) - ); break + content = Object.keys(ui[category]).map((subItem) => ( + + )) + break } return ( {content} {staticUserSettings[category] && ( - + - - )} + {(category === 'pokemon' || + category === 'gyms' || + category === 'pokestops' || + category === 'nests') && ( + + + + )} {category === 'scanAreas' && ( - + )} @@ -140,11 +153,7 @@ export default function Sidebar({ onClose={toggleDrawer(false)} classes={{ paper: classes.drawer }} > - + - {items.map(item => ( + + {items.map((item) => ( diff --git a/src/components/layout/drawer/Pokemon.jsx b/src/components/layout/drawer/Pokemon.jsx index a61daa11d..bb1140865 100644 --- a/src/components/layout/drawer/Pokemon.jsx +++ b/src/components/layout/drawer/Pokemon.jsx @@ -1,7 +1,5 @@ import React, { useEffect, useState, Fragment } from 'react' -import { - Grid, Typography, Switch, AppBar, Tab, Tabs, -} from '@material-ui/core' +import { Grid, Typography, Switch, AppBar, Tab, Tabs } from '@material-ui/core' import { useTranslation } from 'react-i18next' import { useStore, useStatic } from '@hooks/useStore' @@ -11,13 +9,19 @@ import SliderTile from '../dialogs/filters/SliderTile' import TabPanel from '../general/TabPanel' export default function WithSliders({ - category, filters, setFilters, context, specificFilter, + category, + filters, + setFilters, + context, + specificFilter, }) { - const userSettings = useStore(state => state.userSettings) + const userSettings = useStore((state) => state.userSettings) const { t } = useTranslation() - const [tempLegacy, setTempLegacy] = useState(filters[category][specificFilter]) + const [tempLegacy, setTempLegacy] = useState( + filters[category][specificFilter], + ) const [openTab, setOpenTab] = useState(0) - const Icons = useStatic(state => state.Icons) + const Icons = useStatic((state) => state.Icons) useEffect(() => { setFilters({ @@ -32,15 +36,25 @@ export default function WithSliders({ const handleChange = (event, values) => { if (values) { setTempLegacy({ - ...tempLegacy, [event]: values, + ...tempLegacy, + [event]: values, }) - Utility.analytics('Global Pokemon', `${event}: ${values}`, `${category} Text`) + Utility.analytics( + 'Global Pokemon', + `${event}: ${values}`, + `${category} Text`, + ) } else { const { name, value } = event.target setTempLegacy({ - ...tempLegacy, [name]: value, + ...tempLegacy, + [name]: value, }) - Utility.analytics('Global Pokemon', `${name}: ${value}`, `${category} Sliders`) + Utility.analytics( + 'Global Pokemon', + `${name}: ${value}`, + `${category} Sliders`, + ) } } @@ -51,9 +65,7 @@ export default function WithSliders({ return ( <> - - {t('enabled')} - + {t('enabled')} - {(userSettings[category].legacyFilter && context.legacy) ? ( + {userSettings[category].legacyFilter && context.legacy ? ( <> - - {t('iv_or_filter')} - + {t('iv_or_filter')} - {Object.keys(context.sliders).map(slider => ( - + {Object.keys(context.sliders).map((slider) => ( + ))} {Object.keys(context.sliders).map((slider, index) => ( - {Object.values(context.sliders[slider]).map(subItem => ( + {Object.values(context.sliders[slider]).map((subItem) => ( - {index ? ( - ['xsRat', 'xlKarp'].map((each, i) => ( - - - {i - - - - {i ? t('xl').toUpperCase() : t('xs').toUpperCase()} - - - - { - setFilters({ - ...filters, - [category]: { - ...filters[category], - [each]: !filters[category][each], - }, - }) - }} - /> - - - )) - ) : ( - ['zeroIv', 'hundoIv'].map(each => ( - - - - {t(Utility.camelToSnake(each))} - - - - { - setFilters({ - ...filters, - [category]: { - ...filters[category], - [each]: !filters[category][each], - }, - }) - }} - /> - - - )) - )} + {index + ? ['xsRat', 'xlKarp'].map((each, i) => ( + + + {i + + + + {i ? t('xl').toUpperCase() : t('xs').toUpperCase()} + + + + { + setFilters({ + ...filters, + [category]: { + ...filters[category], + [each]: !filters[category][each], + }, + }) + }} + /> + + + )) + : ['zeroIv', 'hundoIv'].map((each) => ( + + + + {t(Utility.camelToSnake(each))} + + + + { + setFilters({ + ...filters, + [category]: { + ...filters[category], + [each]: !filters[category][each], + }, + }) + }} + /> + + + ))} ))} diff --git a/src/components/layout/drawer/Settings.jsx b/src/components/layout/drawer/Settings.jsx index 36aa671e7..35e7dcb7b 100644 --- a/src/components/layout/drawer/Settings.jsx +++ b/src/components/layout/drawer/Settings.jsx @@ -1,6 +1,11 @@ import React from 'react' import { - FormControl, Grid, InputLabel, MenuItem, Select, Button, + FormControl, + Grid, + InputLabel, + MenuItem, + Select, + Button, } from '@material-ui/core' import { Link } from 'react-router-dom' import { useTranslation } from 'react-i18next' @@ -10,21 +15,21 @@ import Utility from '@services/Utility' export default function Settings({ Icons }) { const { t, i18n } = useTranslation() - const config = useStatic(state => state.config) - const staticSettings = useStatic(state => state.settings) - const { loggedIn, methods } = useStatic(state => state.auth) - const setStaticIcons = useStatic(state => state.setIcons) - const setUserProfile = useStatic(state => state.setUserProfile) - const setFeedback = useStatic(state => state.setFeedback) - const setResetFilters = useStatic(state => state.setResetFilters) + const config = useStatic((state) => state.config) + const staticSettings = useStatic((state) => state.settings) + const { loggedIn, methods } = useStatic((state) => state.auth) + const setStaticIcons = useStatic((state) => state.setIcons) + const setUserProfile = useStatic((state) => state.setUserProfile) + const setFeedback = useStatic((state) => state.setFeedback) + const setResetFilters = useStatic((state) => state.setResetFilters) - const setTutorial = useStore(state => state.setTutorial) - const settings = useStore(state => state.settings) - const setSettings = useStore(state => state.setSettings) - const icons = useStore(state => state.icons) - const setIcons = useStore(state => state.setIcons) + const setTutorial = useStore((state) => state.setTutorial) + const settings = useStore((state) => state.settings) + const setSettings = useStore((state) => state.setSettings) + const icons = useStore((state) => state.icons) + const setIcons = useStore((state) => state.setIcons) - const handleChange = event => { + const handleChange = (event) => { setSettings({ ...settings, [event.target.name]: config[event.target.name][event.target.value].name, @@ -34,7 +39,7 @@ export default function Settings({ Icons }) { } } - const handleIconChange = event => { + const handleIconChange = (event) => { const { name, value } = event.target Icons.setSelection(name, value) setStaticIcons(Icons) @@ -44,7 +49,10 @@ export default function Settings({ Icons }) { const exportSettings = () => { const json = localStorage.getItem('local-state') const el = document.createElement('a') - el.setAttribute('href', `data:application/json;chartset=utf-8,${encodeURIComponent(json)}`) + el.setAttribute( + 'href', + `data:application/json;chartset=utf-8,${encodeURIComponent(json)}`, + ) el.setAttribute('download', 'settings.json') el.style.display = 'none' document.body.appendChild(el) @@ -75,7 +83,7 @@ export default function Settings({ Icons }) { alignItems="center" spacing={1} > - {Object.keys(staticSettings).map(setting => ( + {Object.keys(staticSettings).map((setting) => ( {t(Utility.camelToSnake(setting))} @@ -86,22 +94,24 @@ export default function Settings({ Icons }) { onChange={handleChange} fullWidth > - {Object.keys(config[setting]).map(option => ( - - {t(`${Utility.camelToSnake(setting)}_${option.toLowerCase()}`, Utility.getProperName(option))} + {Object.keys(config[setting]).map((option) => ( + + {t( + `${Utility.camelToSnake(setting)}_${option.toLowerCase()}`, + Utility.getProperName(option), + )} ))} ))} - {Icons.customizable.map(category => ( + {Icons.customizable.map((category) => ( - {t(`${category}_icons`, `${category} Icons`)} + + {t(`${category}_icons`, `${category} Icons`)} + @@ -130,7 +140,11 @@ export default function Settings({ Icons }) { style={{ margin: '10px 0px' }} > {config.map.enableUserProfile && ( - + - - )} - {config.map.feedbackLink - && ( - - - - )} + {config.map.statsLink && ( + + + + )} + {config.map.feedbackLink && ( + + + + )} ) diff --git a/src/components/layout/drawer/WithSubItems.jsx b/src/components/layout/drawer/WithSubItems.jsx index bcf068db5..8b6780ca6 100644 --- a/src/components/layout/drawer/WithSubItems.jsx +++ b/src/components/layout/drawer/WithSubItems.jsx @@ -1,7 +1,5 @@ import React from 'react' -import { - Grid, Typography, Switch, Select, MenuItem, -} from '@material-ui/core' +import { Grid, Typography, Switch, Select, MenuItem } from '@material-ui/core' import { useTranslation } from 'react-i18next' import Utility from '@services/Utility' @@ -10,7 +8,14 @@ import MultiSelector from './MultiSelector' import SliderTile from '../dialogs/filters/SliderTile' export default function WithSubItems({ - category, filters, setFilters, subItem, noScanAreaOverlay, enableQuestSetSelector, data, available, + category, + filters, + setFilters, + subItem, + noScanAreaOverlay, + enableQuestSetSelector, + data, + available, }) { const { t } = useTranslation() @@ -18,8 +23,8 @@ export default function WithSubItems({ return null } - const filterCategory = category === 'wayfarer' || category === 'admin' - ? ( + const filterCategory = + category === 'wayfarer' || category === 'admin' ? ( { @@ -32,8 +37,7 @@ export default function WithSubItems({ }) }} /> - ) - : ( + ) : ( { @@ -53,13 +57,15 @@ export default function WithSubItems({ setFilters({ - ...filters, - [category]: { - ...filters[category], - avgFilter: values, - }, - })} + handleChange={(_, values) => + setFilters({ + ...filters, + [category]: { + ...filters[category], + avgFilter: values, + }, + }) + } filterValues={filters[category]} /> @@ -69,61 +75,79 @@ export default function WithSubItems({ return ( <> - {category === 'scanAreas' ? t('show_polygons') : t(Utility.camelToSnake(subItem))} + + {category === 'scanAreas' + ? t('show_polygons') + : t(Utility.camelToSnake(subItem))} + {filterCategory} - {(enableQuestSetSelector === true && category === 'pokestops' && subItem === 'quests' && filters[category].quests === true) && ( - - - - )} - {(category === 'gyms' && subItem === 'gymBadges' && filters[category].gymBadges === true) && ( - - - - )} - {(category === 'gyms' && subItem === 'raids' && filters[category].raids === true && available?.gyms) && ( - <> - - {t('raid_quick_select')} + {enableQuestSetSelector === true && + category === 'pokestops' && + subItem === 'quests' && + filters[category].quests === true && ( + + - - + )} + {category === 'gyms' && + subItem === 'gymBadges' && + filters[category].gymBadges === true && ( + + - - )} + )} + {category === 'gyms' && + subItem === 'raids' && + filters[category].raids === true && + available?.gyms && ( + <> + + {t('raid_quick_select')} + + + + + + )} ) } diff --git a/src/components/layout/general/ActiveWeather.jsx b/src/components/layout/general/ActiveWeather.jsx index d1e8b7b82..7c95f5329 100644 --- a/src/components/layout/general/ActiveWeather.jsx +++ b/src/components/layout/general/ActiveWeather.jsx @@ -9,13 +9,22 @@ import WeatherPopup from '@components/popups/Weather' import Header from './Header' import Footer from './Footer' -export default function ActiveWeather({ Icons, isNight, map, zoom, weather, isMobile, clickable }) { - const location = useStore(state => state.location) +export default function ActiveWeather({ + Icons, + isNight, + map, + zoom, + weather, + isMobile, + clickable, +}) { + const location = useStore((state) => state.location) const [open, setOpen] = useState(false) const { disableColorShift = false } = Icons.getModifiers('weather') const active = weather.find( - cell => cell && booleanPointInPolygon(point(location), polygon([cell.polygon])), + (cell) => + cell && booleanPointInPolygon(point(location), polygon([cell.polygon])), ) return active?.gameplay_condition && map.getZoom() > zoom ? ( @@ -48,14 +57,25 @@ export default function ActiveWeather({ Icons, isNight, map, zoom, weather, isMo
setOpen(false)} maxWidth="xs">
setOpen(false)} /> - - + + -
setOpen(false), color: 'primary' }]} /> +
setOpen(false), + color: 'primary', + }, + ]} + />
) : null diff --git a/src/components/layout/general/Footer.jsx b/src/components/layout/general/Footer.jsx index c529fcf9b..fc33f93d0 100644 --- a/src/components/layout/general/Footer.jsx +++ b/src/components/layout/general/Footer.jsx @@ -1,6 +1,10 @@ import React from 'react' import { - IconButton, Button, Typography, useMediaQuery, Grid, + IconButton, + Button, + Typography, + useMediaQuery, + Grid, } from '@material-ui/core' import { useTheme } from '@material-ui/styles' import { useTranslation } from 'react-i18next' @@ -23,7 +27,7 @@ export default function Footer({ options, role }) { alignItems="center" style={{ minHeight: 50 }} > - {options.map(button => { + {options.map((button) => { const key = button.key || button.name const actualSize = button.size || Math.floor(12 / options.length) if (button.component) { @@ -72,10 +76,10 @@ export default function Footer({ options, role }) { disabled={button.disabled} > {!button.mobileOnly && ( - - {typeof button.name === 'string' ? t(button.name) : button.name} + + {typeof button.name === 'string' + ? t(button.name) + : button.name} )} diff --git a/src/components/layout/general/Header.jsx b/src/components/layout/general/Header.jsx index 364ee7d6a..74efdd6cd 100644 --- a/src/components/layout/general/Header.jsx +++ b/src/components/layout/general/Header.jsx @@ -10,20 +10,22 @@ export default function Header({ names = [], titles, action }) { return ( - {titles.map((title, index) => ( + {titles.map((title, index) => names[index] ? ( {{ name: t(names[index]) }} - ) : `${t(title)} ` - ))} + ) : ( + `${t(title)} ` + ), + )} {Boolean(action) && ( - - - + + + )} ) diff --git a/src/components/layout/general/LocaleSelection.jsx b/src/components/layout/general/LocaleSelection.jsx index a055235ab..a56672e02 100644 --- a/src/components/layout/general/LocaleSelection.jsx +++ b/src/components/layout/general/LocaleSelection.jsx @@ -13,11 +13,8 @@ export default function LocaleSelection({ localeSelection }) { onChange={(event) => i18n.changeLanguage(event.target.value)} fullWidth > - {Object.keys(localeSelection).map(option => ( - + {Object.keys(localeSelection).map((option) => ( + {t(`locale_selection_${option}`)} ))} diff --git a/src/components/layout/general/Menu.jsx b/src/components/layout/general/Menu.jsx index c926cfd87..0d21fb545 100644 --- a/src/components/layout/general/Menu.jsx +++ b/src/components/layout/general/Menu.jsx @@ -23,16 +23,25 @@ import WebhookAdvanced from '../dialogs/webhooks/WebhookAdv' import AdvSearch from '../dialogs/filters/AdvSearch' export default function Menu({ - isTablet, isMobile, category, Tile, webhookCategory, - filters, tempFilters, setTempFilters, categories, - title, titleAction, extraButtons = [], + isTablet, + isMobile, + category, + Tile, + webhookCategory, + filters, + tempFilters, + setTempFilters, + categories, + title, + titleAction, + extraButtons = [], }) { Utility.analytics(`/advanced/${category}`) - const menus = useStore(state => state.menus) - const setMenus = useStore(state => state.setMenus) - const advMenu = useStore(state => state.advMenu) - const setAdvMenu = useStore(state => state.setAdvMenu) + const menus = useStore((state) => state.menus) + const setMenus = useStore((state) => state.setMenus) + const advMenu = useStore((state) => state.advMenu) + const setAdvMenu = useStore((state) => state.setAdvMenu) const { t } = useTranslation() let columnCount = isTablet ? 3 : 5 @@ -56,9 +65,14 @@ export default function Menu({ id: '', }) - const { - filteredObj, filteredArr, count, - } = useFilter(tempFilters, menus, search, category, webhookCategory, categories) + const { filteredObj, filteredArr, count } = useFilter( + tempFilters, + menus, + search, + category, + webhookCategory, + categories, + ) const selectAllOrNone = (show) => { const newObj = {} @@ -72,14 +86,20 @@ export default function Menu({ } const toggleDrawer = (open) => (event) => { - if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) { + if ( + event.type === 'keydown' && + (event.key === 'Tab' || event.key === 'Shift') + ) { return } setFilterDrawer(open) } const toggleAdvMenu = (open, id, newFilters) => (event) => { - if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) { + if ( + event.type === 'keydown' && + (event.key === 'Tab' || event.key === 'Shift') + ) { return } if (open) { @@ -92,13 +112,16 @@ export default function Menu({ } else if (id === 'global') { setAdvancedFilter({ open }) const newObj = tempFilters - Object.entries(filteredObj).forEach(item => { + Object.entries(filteredObj).forEach((item) => { const [key, { enabled }] = item newObj[key] = { ...newFilters, enabled } // ugly patch for also changing gym slots with the apply to all if (key.startsWith('t') && key.charAt(1) != 0) { - Object.assign(newObj, Utility.generateSlots(key, newFilters, tempFilters)) + Object.assign( + newObj, + Utility.generateSlots(key, newFilters, tempFilters), + ) } }) setTempFilters({ ...tempFilters, ...newObj, [id]: newFilters }) @@ -109,39 +132,61 @@ export default function Menu({ } const toggleWebhook = (open, id, newFilters) => (event) => { - if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) { + if ( + event.type === 'keydown' && + (event.key === 'Tab' || event.key === 'Shift') + ) { return } if (id === 'global' && !open && newFilters) { const wildCards = (() => { switch (webhookCategory) { - case 'raid': return ['r90'] - case 'egg': return ['e90'] - case 'gym': return ['t4'] - case 'invasion': return ['i0'] - default: return ['0-0'] + case 'raid': + return ['r90'] + case 'egg': + return ['e90'] + case 'gym': + return ['t4'] + case 'invasion': + return ['i0'] + default: + return ['0-0'] } })() if (newFilters.everything_individually !== false) { - Object.keys(filteredObj).forEach(item => { + Object.keys(filteredObj).forEach((item) => { if (!wildCards.includes(item)) { - filteredObj[item] = { ...tempFilters[item], ...newFilters, enabled: true } + filteredObj[item] = { + ...tempFilters[item], + ...newFilters, + enabled: true, + } } }) } else { - wildCards.forEach(item => { - filteredObj[item] = { ...tempFilters[item], ...newFilters, enabled: true } + wildCards.forEach((item) => { + filteredObj[item] = { + ...tempFilters[item], + ...newFilters, + enabled: true, + } }) } setTempFilters({ ...tempFilters, ...filteredObj, [id]: newFilters }) } else if (id && newFilters && !open) { - setTempFilters({ ...tempFilters, [id]: { ...tempFilters[id], ...newFilters, enabled: true } }) + setTempFilters({ + ...tempFilters, + [id]: { ...tempFilters[id], ...newFilters, enabled: true }, + }) } setWebhook({ open, id }) } const toggleSlotsMenu = (open, id, newFilters) => (event) => { - if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) { + if ( + event.type === 'keydown' && + (event.key === 'Tab' || event.key === 'Shift') + ) { return } if (open) { @@ -159,13 +204,16 @@ export default function Menu({ const handleReset = () => { const resetPayload = {} - Object.keys(menus[category].filters).forEach(cat => { + Object.keys(menus[category].filters).forEach((cat) => { resetPayload[cat] = {} - Object.keys(menus[category].filters[cat]).forEach(filter => { + Object.keys(menus[category].filters[cat]).forEach((filter) => { resetPayload[cat][filter] = false }) }) - setMenus({ ...menus, [category]: { ...menus[category], filters: resetPayload } }) + setMenus({ + ...menus, + [category]: { ...menus[category], filters: resetPayload }, + }) } const Options = ( @@ -187,11 +235,39 @@ export default function Menu({ ) const footerButtons = [ - { name: 'help', action: () => setHelpDialog(!helpDialog), icon: 'HelpOutline', color: 'white' }, - { name: 'openFilter', action: toggleDrawer(true), icon: 'Ballot', color: 'white', mobileOnly: true }, - { name: 'apply_to_all', action: webhookCategory ? toggleWebhook(true, 'global') : toggleAdvMenu(true, 'global'), icon: category === 'pokemon' || webhookCategory ? 'Tune' : 'FormatSize', color: 'white' }, - { name: 'disable_all', action: () => selectAllOrNone(false), icon: 'Clear', color: 'primary' }, - { name: 'enable_all', action: () => selectAllOrNone(true), icon: 'Check', color: '#00e676' }, + { + name: 'help', + action: () => setHelpDialog(!helpDialog), + icon: 'HelpOutline', + color: 'white', + }, + { + name: 'openFilter', + action: toggleDrawer(true), + icon: 'Ballot', + color: 'white', + mobileOnly: true, + }, + { + name: 'apply_to_all', + action: webhookCategory + ? toggleWebhook(true, 'global') + : toggleAdvMenu(true, 'global'), + icon: category === 'pokemon' || webhookCategory ? 'Tune' : 'FormatSize', + color: 'white', + }, + { + name: 'disable_all', + action: () => selectAllOrNone(false), + icon: 'Clear', + color: 'primary', + }, + { + name: 'enable_all', + action: () => selectAllOrNone(true), + icon: 'Check', + color: '#00e676', + }, ...extraButtons, ] @@ -209,7 +285,14 @@ export default function Menu({ {Options} )} - + ) : (
- + {t('no_filter_results')} @@ -253,11 +342,7 @@ export default function Menu({
- + {Options} - + - setHelpDialog(false)} - > + setHelpDialog(false)}> setHelpDialog(!helpDialog)} category={category} diff --git a/src/components/layout/general/Notification.jsx b/src/components/layout/general/Notification.jsx index a7aa81efa..bf76795e2 100644 --- a/src/components/layout/general/Notification.jsx +++ b/src/components/layout/general/Notification.jsx @@ -28,7 +28,9 @@ export default function Notification({ severity, i18nKey, messages }) { {messages.map((message, i) => ( - {message.variables.map((variable, j) => ({ [`variable_${j}`]: t(variable) }))} + {message.variables.map((variable, j) => ({ + [`variable_${j}`]: t(variable), + }))}
diff --git a/src/components/layout/general/QuestTitle.jsx b/src/components/layout/general/QuestTitle.jsx index da61ef41a..ac8c77226 100644 --- a/src/components/layout/general/QuestTitle.jsx +++ b/src/components/layout/general/QuestTitle.jsx @@ -9,9 +9,7 @@ export default function QuestTitle({ questTitle, questTarget }) { return i18n.exists(normalized) ? ( - - {{ amount_0: questTarget }} - + {{ amount_0: questTarget }} ) : null } diff --git a/src/components/layout/general/ReactWindow.jsx b/src/components/layout/general/ReactWindow.jsx index 5dbf99fd9..93c1795ea 100644 --- a/src/components/layout/general/ReactWindow.jsx +++ b/src/components/layout/general/ReactWindow.jsx @@ -3,7 +3,12 @@ import { FixedSizeGrid } from 'react-window' import AutoSizer from 'react-virtualized-auto-sizer' export default function ReactWindow({ - columnCount, length, Tile, data, offset, columnWidthCorrection, + columnCount, + length, + Tile, + data, + offset, + columnWidthCorrection, }) { return ( @@ -13,7 +18,9 @@ export default function ReactWindow({ width={width} height={height} columnCount={columnCount} - columnWidth={Math.floor(width / columnCount) - (columnWidthCorrection || 5)} + columnWidth={ + Math.floor(width / columnCount) - (columnWidthCorrection || 5) + } rowCount={Math.ceil(length / columnCount)} rowHeight={(columnCount > 1 ? 120 : 60) + offset} itemData={{ diff --git a/src/components/layout/general/TabPanel.jsx b/src/components/layout/general/TabPanel.jsx index d5c2774b8..893b4cba3 100644 --- a/src/components/layout/general/TabPanel.jsx +++ b/src/components/layout/general/TabPanel.jsx @@ -8,9 +8,9 @@ export default ({ children, value, index, virtual }) => ( style={virtual ? { height: '100%' } : {}} > {value === index && ( - - {children} - + + {children} + )}
) diff --git a/src/components/markers/device.js b/src/components/markers/device.js index f3ed39d0c..f55e5d1e8 100644 --- a/src/components/markers/device.js +++ b/src/components/markers/device.js @@ -2,7 +2,8 @@ import { Icon } from 'leaflet' export default function getDeviceMarkers(isOnline, Icons) { const size = Icons.getSize('device') - const { offsetX, offsetY, popupX, popupY, sizeMultiplier } = Icons.getModifiers('device') + const { offsetX, offsetY, popupX, popupY, sizeMultiplier } = + Icons.getModifiers('device') return new Icon({ iconUrl: Icons.getDevices(isOnline), iconSize: [size * sizeMultiplier, size * sizeMultiplier], diff --git a/src/components/markers/gym.jsx b/src/components/markers/gym.jsx index ddef17e1e..72a862c0b 100644 --- a/src/components/markers/gym.jsx +++ b/src/components/markers/gym.jsx @@ -5,23 +5,42 @@ import L from 'leaflet' const getBadgeColor = (raidLevel) => { switch (raidLevel) { case 1: - case 2: return '#BF05C6' + case 2: + return '#BF05C6' case 3: - case 4: return '#9E8A09' - case 5: return '#088DB6' - case 6: return '#21BD21' - default: return '#292929' + case 4: + return '#9E8A09' + case 5: + return '#088DB6' + case 6: + return '#21BD21' + default: + return '#292929' } } -export default function GymMarker(gym, hasHatched, hasRaid, filters, Icons, userSettings, badge) { +export default function GymMarker( + gym, + hasHatched, + hasRaid, + filters, + Icons, + userSettings, + badge, +) { const { - in_battle, team_id, available_slots, raid_level, ex_raid_eligible, ar_scan_eligible, + in_battle, + team_id, + available_slots, + raid_level, + ex_raid_eligible, + ar_scan_eligible, } = gym const { gym: gymMod, raid: raidMod } = Icons.modifiers const filledSlots = available_slots !== null ? 6 - available_slots : 0 - let filterId = team_id === 0 ? `t${team_id}-0` : `g${team_id}-${filledSlots || 0}` + let filterId = + team_id === 0 ? `t${team_id}-0` : `g${team_id}-${filledSlots || 0}` const gymIcon = Icons.getGyms( team_id, filledSlots, @@ -33,7 +52,8 @@ export default function GymMarker(gym, hasHatched, hasRaid, filters, Icons, user let raidIcon let raidSize = 0 const slotModifier = gymMod[filledSlots] || gymMod['0'] || gymSize * 0.5 - const showDiamond = filters.gymBadges && userSettings.gymBadgeDiamonds && badge + const showDiamond = + filters.gymBadges && userSettings.gymBadgeDiamonds && badge if (hasRaid) { const { @@ -70,7 +90,9 @@ export default function GymMarker(gym, hasHatched, hasRaid, filters, Icons, user style={{ width: 46, height: 46, - backgroundImage: `url(${gym.url ? gym.url.replace('http', 'https') : ''})`, + backgroundImage: `url(${ + gym.url ? gym.url.replace('http', 'https') : '' + })`, backgroundSize: 'cover', backgroundRepeat: 'no-repeat', clipPath: 'polygon(50% 0%, 80% 50%, 50% 100%, 20% 50%)', @@ -86,7 +108,6 @@ export default function GymMarker(gym, hasHatched, hasRaid, filters, Icons, user bottom: 2 + gymMod.offsetY, left: `${gymMod.offsetX * 50}%`, transform: 'translateX(-50%)', - }} /> @@ -103,7 +124,11 @@ export default function GymMarker(gym, hasHatched, hasRaid, filters, Icons, user transform: 'translateX(-50%)', }} /> - {Boolean(userSettings.showExBadge && ex_raid_eligible && !gymIcon.includes('_ex')) && ( + {Boolean( + userSettings.showExBadge && + ex_raid_eligible && + !gymIcon.includes('_ex'), + ) && ( ex )} - {Boolean(userSettings.showArBadge && ar_scan_eligible && !gymIcon.includes('_ar')) && ( + {Boolean( + userSettings.showArBadge && + ar_scan_eligible && + !gymIcon.includes('_ar'), + ) && ( ar { switch (badge) { case 1: return 'third'; case 2: return 'second'; default: return 'first' } })())} + src={Icons.getMisc( + (() => { + switch (badge) { + case 1: + return 'third' + case 2: + return 'second' + default: + return 'first' + } + })(), + )} alt="badge" style={{ width: gymSize / 2, @@ -180,21 +220,21 @@ export default function GymMarker(gym, hasHatched, hasRaid, filters, Icons, user transform: 'translateX(-50%)', }} > - {raid_level === 6 - ? ( - mega - ) - : raid_level} + {raid_level === 6 ? ( + mega + ) : ( + raid_level + )}
)}
@@ -203,8 +243,10 @@ export default function GymMarker(gym, hasHatched, hasRaid, filters, Icons, user return L.divIcon({ popupAnchor: [ 0 + gymMod.popupX + gymMod.offsetX, - ((-gymSize - (showDiamond ? 20 : slotModifier) - raidSize) * 0.67) + gymMod.popupY + gymMod.offsetY - + (raidIcon ? raidMod.offsetY + raidMod.popupY : 0), + (-gymSize - (showDiamond ? 20 : slotModifier) - raidSize) * 0.67 + + gymMod.popupY + + gymMod.offsetY + + (raidIcon ? raidMod.offsetY + raidMod.popupY : 0), ], className: 'gym-marker', html: renderToString(ReactIcon), diff --git a/src/components/markers/nest.jsx b/src/components/markers/nest.jsx index cffb82427..12e831e2d 100644 --- a/src/components/markers/nest.jsx +++ b/src/components/markers/nest.jsx @@ -2,12 +2,24 @@ import React from 'react' import { renderToString } from 'react-dom/server' import L from 'leaflet' -export default function nestMarker(iconUrl, nest, pokemon, filters, Icons, recent) { +export default function nestMarker( + iconUrl, + nest, + pokemon, + filters, + Icons, + recent, +) { const { types } = pokemon const filterId = `${nest.pokemon_id}-${nest.pokemon_form}` const size = Icons.getSize('nest', filters.filter[filterId]) const { - offsetX, offsetY, popupX, popupY, sizeMultiplier, nestMonSizeMulti = 1, + offsetX, + offsetY, + popupX, + popupY, + sizeMultiplier, + nestMonSizeMulti = 1, } = Icons.getModifiers('nest') const { nest: nestMod } = Icons.modifiers const opacity = recent ? 1 : 0.5 diff --git a/src/components/markers/placementCell.js b/src/components/markers/placementCell.js index fae8ce6a9..b23a472a5 100644 --- a/src/components/markers/placementCell.js +++ b/src/components/markers/placementCell.js @@ -1,7 +1,10 @@ export default function placementStyle(cellBlocked, tileStyle, userSettings) { return { fillColor: userSettings.cellBlocked, - color: tileStyle === 'dark' ? userSettings.darkMapBorder : userSettings.lightMapBorder, + color: + tileStyle === 'dark' + ? userSettings.darkMapBorder + : userSettings.lightMapBorder, opacity: 0.75, fillOpacity: cellBlocked ? 0.25 : 0, weight: 0.35, diff --git a/src/components/markers/pokemon.jsx b/src/components/markers/pokemon.jsx index dd2a56b0c..d366512a1 100644 --- a/src/components/markers/pokemon.jsx +++ b/src/components/markers/pokemon.jsx @@ -2,22 +2,39 @@ import React from 'react' import { renderToString } from 'react-dom/server' import L, { Icon } from 'leaflet' -export const basicMarker = (iconUrl, size) => new Icon({ - iconUrl, - iconSize: [size, size], - iconAnchor: [size / 2, size / 2], - popupAnchor: [0, size * -0.6], - className: 'marker', -}) +export const basicMarker = (iconUrl, size) => + new Icon({ + iconUrl, + iconSize: [size, size], + iconAnchor: [size / 2, size / 2], + popupAnchor: [0, size * -0.6], + className: 'marker', + }) -export const fancyMarker = (iconUrl, size, pkmn, glow, ivCircle, Icons, weatherCheck, isNight) => { +export const fancyMarker = ( + iconUrl, + size, + pkmn, + glow, + ivCircle, + Icons, + weatherCheck, + isNight, +) => { const { pokemon: pokemonMod, weather: weatherMod } = Icons.modifiers let badge switch (pkmn.bestPvp) { - case 1: badge = 'first'; break - case 2: badge = 'second'; break - case 3: badge = 'third'; break - default: break + case 1: + badge = 'first' + break + case 2: + badge = 'second' + break + case 3: + badge = 'third' + break + default: + break } const ReactIcon = ( @@ -26,7 +43,9 @@ export const fancyMarker = (iconUrl, size, pkmn, glow, ivCircle, Icons, weatherC src={iconUrl} alt={pkmn.pokemon_id} style={{ - WebkitFilter: glow ? `drop-shadow(0 0 10px ${glow})drop-shadow(0 0 10px ${glow})` : undefined, + WebkitFilter: glow + ? `drop-shadow(0 0 10px ${glow})drop-shadow(0 0 10px ${glow})` + : undefined, height: size, width: size, }} @@ -43,7 +62,7 @@ export const fancyMarker = (iconUrl, size, pkmn, glow, ivCircle, Icons, weatherC }} /> )} - {(ivCircle && !badge) && ( + {ivCircle && !badge && (
{ + invasions.forEach((invasion) => { filterId = `i${invasion.grunt_type}` invasionIcons.unshift(Icons.getInvasions(invasion.grunt_type)) invasionSizes.unshift(Icons.getSize('invasion', filters.filter[filterId])) @@ -41,7 +53,7 @@ export default function stopMarker(pokestop, hasQuest, hasLure, hasInvasion, fil if (hasQuest && !(hasInvasion && invasionMod?.removeQuest)) { const { quests } = pokestop - quests.forEach(quest => { + quests.forEach((quest) => { const { quest_item_id, item_amount, @@ -63,33 +75,62 @@ export default function stopMarker(pokestop, hasQuest, hasLure, hasInvasion, fil switch (quest_reward_type) { case 2: questIcons.unshift({ - url: Icons.getRewards(quest_reward_type, quest_item_id, item_amount), + url: Icons.getRewards( + quest_reward_type, + quest_item_id, + item_amount, + ), amount: item_amount > 1 && item_amount, - }); break + }) + break case 3: questIcons.unshift({ url: Icons.getRewards(quest_reward_type, stardust_amount), amount: stardust_amount, - }); break + }) + break case 4: questIcons.unshift({ - url: Icons.getRewards(quest_reward_type, candy_pokemon_id, candy_amount), + url: Icons.getRewards( + quest_reward_type, + candy_pokemon_id, + candy_amount, + ), amount: candy_amount, - }); break + }) + break case 7: questIcons.unshift({ - url: Icons.getPokemon(quest_pokemon_id, quest_form_id, 0, quest_gender_id, quest_costume_id, quest_shiny), - }); break + url: Icons.getPokemon( + quest_pokemon_id, + quest_form_id, + 0, + quest_gender_id, + quest_costume_id, + quest_shiny, + ), + }) + break case 9: questIcons.unshift({ - url: Icons.getRewards(quest_reward_type, xl_candy_pokemon_id, xl_candy_amount), + url: Icons.getRewards( + quest_reward_type, + xl_candy_pokemon_id, + xl_candy_amount, + ), amount: xl_candy_amount, - }); break + }) + break case 12: questIcons.unshift({ - url: Icons.getRewards(quest_reward_type, mega_pokemon_id, mega_amount), + url: Icons.getRewards( + quest_reward_type, + mega_pokemon_id, + mega_amount, + ), amount: mega_amount, - }); break + }) + break default: questIcons.unshift({ url: Icons.getRewards(quest_reward_type) }) } @@ -116,7 +157,11 @@ export default function stopMarker(pokestop, hasQuest, hasLure, hasInvasion, fil transform: 'translateX(-50%)', }} /> - {Boolean(userSettings.showArBadge && ar_scan_eligible && !baseIcon.includes('_ar')) && ( + {Boolean( + userSettings.showArBadge && + ar_scan_eligible && + !baseIcon.includes('_ar'), + ) && ( ar - {Boolean(icon.url.includes('stardust') ? !icon.url.endsWith('0.png') : !icon.url.includes('_a') && icon.amount) - && ( -
- x{icon.amount} -
- )} + {Boolean( + icon.url.includes('stardust') + ? !icon.url.endsWith('0.png') + : !icon.url.includes('_a') && icon.amount, + ) && ( +
+ x{icon.amount} +
+ )} ))} {invasionIcons.map((icon, i) => ( @@ -169,8 +221,7 @@ export default function stopMarker(pokestop, hasQuest, hasLure, hasInvasion, fil style={{ width: invasionSizes[i], height: invasionSizes[i], - bottom: baseSize * 0.5 * invasionMod.offsetY - + (invasionSizes[i] * i), + bottom: baseSize * 0.5 * invasionMod.offsetY + invasionSizes[i] * i, left: `${invasionMod.offsetX * 50}%`, transform: 'translateX(-50%)', }} @@ -180,9 +231,15 @@ export default function stopMarker(pokestop, hasQuest, hasLure, hasInvasion, fil ) return L.divIcon({ - popupAnchor: [popupX - 5, (pokestopMod.manualPopup - ? pokestopMod.manualPopup - totalInvasionSize * 0.25 - totalQuestSize * 0.1 - : -(baseSize + totalInvasionSize + totalQuestSize) / popupYOffset) + popupY], + popupAnchor: [ + popupX - 5, + (pokestopMod.manualPopup + ? pokestopMod.manualPopup - + totalInvasionSize * 0.25 - + totalQuestSize * 0.1 + : -(baseSize + totalInvasionSize + totalQuestSize) / popupYOffset) + + popupY, + ], className: 'pokestop-marker', html: renderToString(ReactIcon), }) diff --git a/src/components/markers/portal.js b/src/components/markers/portal.js index 26a15559b..d0000e44f 100644 --- a/src/components/markers/portal.js +++ b/src/components/markers/portal.js @@ -1,7 +1,9 @@ export default function portalMarker(portal, ts, settings) { return { - color: ts - portal.imported > 86400 ? settings.oldPortals : settings.newPortals, - fillColor: ts - portal.imported > 86400 ? settings.oldPortals : settings.newPortals, + color: + ts - portal.imported > 86400 ? settings.oldPortals : settings.newPortals, + fillColor: + ts - portal.imported > 86400 ? settings.oldPortals : settings.newPortals, fillOpacity: 0.25, } } diff --git a/src/components/markers/s2cell.js b/src/components/markers/s2cell.js index dd383d382..bb8395ad2 100644 --- a/src/components/markers/s2cell.js +++ b/src/components/markers/s2cell.js @@ -1,5 +1,5 @@ export default function s2cellMarker(cellUpdated) { - const ago = (new Date()).getTime() - (cellUpdated * 1000) + const ago = new Date().getTime() - cellUpdated * 1000 const value = ago <= 150000 ? 0 : Math.min((ago - 150000) / 750000, 1) const hue = ((1 - value) * 120).toString(10) diff --git a/src/components/markers/typeCell.js b/src/components/markers/typeCell.js index f05eacc8c..51a08aa7a 100644 --- a/src/components/markers/typeCell.js +++ b/src/components/markers/typeCell.js @@ -1,20 +1,40 @@ export default function typeStyle(cell, tileStyle, userSettings) { - const color = tileStyle === 'dark' ? userSettings.darkMapBorder : userSettings.lightMapBorder - if ((cell.count === 1 && cell.count_gyms < 1) - || (cell.count === 5 && cell.count_gyms < 2) - || (cell.count === 19 && cell.count_gyms < 3)) { + const color = + tileStyle === 'dark' + ? userSettings.darkMapBorder + : userSettings.lightMapBorder + if ( + (cell.count === 1 && cell.count_gyms < 1) || + (cell.count === 5 && cell.count_gyms < 2) || + (cell.count === 19 && cell.count_gyms < 3) + ) { return { - fillColor: userSettings.oneStopTillNext, color, opacity: 0.75, fillOpacity: 0.5, weight: 0.75, + fillColor: userSettings.oneStopTillNext, + color, + opacity: 0.75, + fillOpacity: 0.5, + weight: 0.75, } } - if ((cell.count === 4 && cell.count_gyms < 2) || (cell.count === 18 && cell.count_gyms < 3)) { + if ( + (cell.count === 4 && cell.count_gyms < 2) || + (cell.count === 18 && cell.count_gyms < 3) + ) { return { - fillColor: userSettings.twoStopsTillNext, color, opacity: 0.75, fillOpacity: 0.5, weight: 0.75, + fillColor: userSettings.twoStopsTillNext, + color, + opacity: 0.75, + fillOpacity: 0.5, + weight: 0.75, } } if (cell.count >= 20) { return { - fillColor: userSettings.noMoreGyms, color, opacity: 0.75, fillOpacity: 0.25, weight: 0.8, + fillColor: userSettings.noMoreGyms, + color, + opacity: 0.75, + fillOpacity: 0.25, + weight: 0.8, } } return { color, opacity: 0.75, fillOpacity: 0.0, weight: 0.8 } diff --git a/src/components/markers/weather.jsx b/src/components/markers/weather.jsx index fe1906157..140d53944 100644 --- a/src/components/markers/weather.jsx +++ b/src/components/markers/weather.jsx @@ -3,7 +3,14 @@ import { renderToString } from 'react-dom/server' import L from 'leaflet' export default function weatherMarker(weather, Icons, isNight) { - const { offsetX, offsetY, popupX, popupY, sizeMultiplier, disableColorShift = false } = Icons.getModifiers('weather') + const { + offsetX, + offsetY, + popupX, + popupY, + sizeMultiplier, + disableColorShift = false, + } = Icons.getModifiers('weather') return L.divIcon({ iconAnchor: [17 * offsetX, 17 * offsetY], diff --git a/src/components/popups/Device.jsx b/src/components/popups/Device.jsx index e5dac4f5a..c1807f9e5 100644 --- a/src/components/popups/Device.jsx +++ b/src/components/popups/Device.jsx @@ -45,7 +45,8 @@ const Timer = ({ device, t, ts }) => { return ( - {t('last_seen')}: {Utility.dayCheck(ts, last_seen)} ({since.str.replace('days', t('days')).replace('day', t('day'))}) + {t('last_seen')}: {Utility.dayCheck(ts, last_seen)} ( + {since.str.replace('days', t('days')).replace('day', t('day'))}) ) } diff --git a/src/components/popups/DevicePoly.jsx b/src/components/popups/DevicePoly.jsx index 01ed77af1..b3476d4fd 100644 --- a/src/components/popups/DevicePoly.jsx +++ b/src/components/popups/DevicePoly.jsx @@ -11,10 +11,7 @@ const DevicePoly = ({ device, color }) => { if (device.type === 'leveling') { return ( <> - + { if (Array.isArray(arrayRoute)) { return device?.type?.includes('circle') ? arrayRoute.map((polygon, i) => ( - [route.lat, route.lon])} - pathOptions={{ color }} - /> - )) + [route.lat, route.lon])} + pathOptions={{ color }} + /> + )) : arrayRoute.map((polygon, i) => ( - [route.lat, route.lon])} - pathOptions={{ color }} - /> - )) + [route.lat, route.lon])} + pathOptions={{ color }} + /> + )) } return null } -const areEqual = (prev, next) => ( - prev.device.type === next.device.type - && prev.color === next.color -) +const areEqual = (prev, next) => + prev.device.type === next.device.type && prev.color === next.color export default memo(DevicePoly, areEqual) diff --git a/src/components/popups/Gym.jsx b/src/components/popups/Gym.jsx index ce291e448..1fce5616a 100644 --- a/src/components/popups/Gym.jsx +++ b/src/components/popups/Gym.jsx @@ -1,8 +1,12 @@ -import React, { - Fragment, useState, useEffect, -} from 'react' +import React, { Fragment, useState, useEffect } from 'react' import { - Grid, Typography, Icon, Collapse, IconButton, Divider, Dialog, + Grid, + Typography, + Icon, + Collapse, + IconButton, + Divider, + Dialog, } from '@material-ui/core' import { ExpandMore, Map, MoreVert } from '@material-ui/icons' import { useTranslation, Trans } from 'react-i18next' @@ -19,15 +23,25 @@ import BadgeSelection from '../layout/dialogs/BadgeSelection' import PowerUp from './common/PowerUp' export default function GymPopup({ - gym, hasRaid, ts, Icons, hasHatched, badge, setBadge, + gym, + hasRaid, + ts, + Icons, + hasHatched, + badge, + setBadge, }) { const { t } = useTranslation() - const { perms } = useStatic(state => state.auth) - const popups = useStore(state => state.popups) - const setPopups = useStore(state => state.setPopups) + const { perms } = useStatic((state) => state.auth) + const popups = useStore((state) => state.popups) + const setPopups = useStore((state) => state.setPopups) useEffect(() => { - Utility.analytics('Popup', `Team ID: ${gym.team_id} Has Raid: ${hasRaid}`, 'Gym') + Utility.analytics( + 'Popup', + `Team ID: ${gym.team_id} Has Raid: ${hasRaid}`, + 'Gym', + ) }, []) return ( @@ -40,10 +54,7 @@ export default function GymPopup({ spacing={1} > - + <Title mainName={gym.name} backup={t('unknown_gym')} /> </Grid> <MenuActions gym={gym} @@ -62,16 +73,9 @@ export default function GymPopup({ justifyContent="space-evenly" spacing={1} > - <PoiImage - Icons={Icons} - gym={gym} - /> + <PoiImage Icons={Icons} gym={gym} /> <Divider orientation="vertical" flexItem /> - <GymInfo - gym={gym} - t={t} - Icons={Icons} - /> + <GymInfo gym={gym} t={t} Icons={Icons} /> </Grid> </Collapse> </Grid> @@ -85,16 +89,12 @@ export default function GymPopup({ justifyContent="center" spacing={1} > - <RaidImage - gym={gym} - ts={ts} - Icons={Icons} - t={t} - /> + <RaidImage gym={gym} ts={ts} Icons={Icons} t={t} /> <Divider orientation="vertical" flexItem /> <RaidInfo gym={gym} t={t} Icons={Icons} ts={ts} /> - {Boolean(gym.raid_pokemon_id && gym.raid_battle_timestamp >= ts) - && <Timer gym={gym} start t={t} />} + {Boolean( + gym.raid_pokemon_id && gym.raid_battle_timestamp >= ts, + ) && <Timer gym={gym} start t={t} />} <Timer gym={gym} ts={ts} t={t} hasHatched={hasHatched} /> </Grid> </Collapse> @@ -119,28 +119,31 @@ export default function GymPopup({ ) } -const MenuActions = ({ - gym, perms, hasRaid, t, badge, setBadge, -}) => { - const hideList = useStatic(state => state.hideList) - const setHideList = useStatic(state => state.setHideList) - const excludeList = useStatic(state => state.excludeList) - const setExcludeList = useStatic(state => state.setExcludeList) - const timerList = useStatic(state => state.timerList) - const setTimerList = useStatic(state => state.setTimerList) - const { gymValidDataLimit } = useStatic(state => state.config) +const MenuActions = ({ gym, perms, hasRaid, t, badge, setBadge }) => { + const hideList = useStatic((state) => state.hideList) + const setHideList = useStatic((state) => state.setHideList) + const excludeList = useStatic((state) => state.excludeList) + const setExcludeList = useStatic((state) => state.setExcludeList) + const timerList = useStatic((state) => state.timerList) + const setTimerList = useStatic((state) => state.setTimerList) + const { gymValidDataLimit } = useStatic((state) => state.config) - const selectedWebhook = useStore(state => state.selectedWebhook) + const selectedWebhook = useStore((state) => state.selectedWebhook) - const filters = useStore(state => state.filters) - const setFilters = useStore(state => state.setFilters) + const filters = useStore((state) => state.filters) + const setFilters = useStore((state) => state.setFilters) const [anchorEl, setAnchorEl] = useState(false) const [badgeMenu, setBadgeMenu] = useState(false) const addWebhook = useWebhook({ category: 'quickGym', selectedWebhook }) const { - id, team_id, raid_pokemon_id, raid_pokemon_form, raid_level, updated, + id, + team_id, + raid_pokemon_id, + raid_pokemon_form, + raid_level, + updated, } = gym const handleClick = (event) => { @@ -205,22 +208,23 @@ const MenuActions = ({ const handleTimer = () => { setAnchorEl(null) if (timerList.includes(id)) { - setTimerList(timerList.filter(x => x !== id)) + setTimerList(timerList.filter((x) => x !== id)) } else { setTimerList([...timerList, id]) } } - const options = [ - { name: 'hide', action: handleHide }, - ] + const options = [{ name: 'hide', action: handleHide }] if (perms.gyms) { if (updated > gymValidDataLimit) { options.push({ name: 'exclude_team', action: excludeTeam }) } if (perms.gymBadges && filters.gyms?.gymBadges) { - options.push({ name: 'gym_badge_menu', action: () => handleCloseBadge(true) }) + options.push({ + name: 'gym_badge_menu', + action: () => handleCloseBadge(true), + }) } } if (perms.raids && hasRaid) { @@ -229,11 +233,12 @@ const MenuActions = ({ { name: 'timer', action: handleTimer }, ) } - perms.webhooks.forEach(hook => { + perms.webhooks.forEach((hook) => { options.push({ name: ( <Trans i18nKey="webhook_entry"> - {{ category: t('gym') }}{{ name: hook }} + {{ category: t('gym') }} + {{ name: hook }} </Trans> ), action: () => addWebhook(gym), @@ -243,10 +248,7 @@ const MenuActions = ({ return ( <Grid item xs={2} style={{ textAlign: 'right' }}> - <IconButton - aria-haspopup="true" - onClick={handleClick} - > + <IconButton aria-haspopup="true" onClick={handleClick}> <MoreVert style={{ color: 'white' }} /> </IconButton> <Dropdown @@ -268,15 +270,10 @@ const MenuActions = ({ const PoiImage = ({ gym, Icons }) => { const { url, team_id, name } = gym - const src = url - ? url.replace('http://', 'https://') - : Icons.getTeams(team_id) + const src = url ? url.replace('http://', 'https://') : Icons.getTeams(team_id) return ( - <Grid - item - xs={6} - > + <Grid item xs={6}> <img src={src} alt={name || 'unknown'} @@ -290,23 +287,27 @@ const PoiImage = ({ gym, Icons }) => { ) } -const RaidImage = ({ - gym, ts, Icons, t, -}) => { +const RaidImage = ({ gym, ts, Icons, t }) => { const { - raid_level, raid_pokemon_id, raid_pokemon_form, raid_pokemon_gender, raid_pokemon_costume, raid_pokemon_evolution, - raid_battle_timestamp, raid_is_exclusive, + raid_level, + raid_pokemon_id, + raid_pokemon_form, + raid_pokemon_gender, + raid_pokemon_costume, + raid_pokemon_evolution, + raid_battle_timestamp, + raid_is_exclusive, } = gym - const { pokemon } = useStatic(state => state.masterfile) + const { pokemon } = useStatic((state) => state.masterfile) const src = raid_pokemon_id ? Icons.getPokemon( - raid_pokemon_id, - raid_pokemon_form, - raid_pokemon_evolution, - raid_pokemon_gender, - raid_pokemon_costume, - ) + raid_pokemon_id, + raid_pokemon_form, + raid_pokemon_evolution, + raid_pokemon_gender, + raid_pokemon_costume, + ) : Icons.getEggs(raid_level, raid_battle_timestamp < ts, raid_is_exclusive) const getRaidTypes = (id, form) => { @@ -317,13 +318,7 @@ const RaidImage = ({ } return ( - <Grid - container - item - xs={5} - justifyContent="center" - alignItems="center" - > + <Grid container item xs={5} justifyContent="center" alignItems="center"> <Grid item xs={12} @@ -345,20 +340,21 @@ const RaidImage = ({ {`${t('tier')} ${raid_level}`} </Typography> </Grid> - {(raid_pokemon_id > 0) && getRaidTypes(raid_pokemon_id, raid_pokemon_form).map(type => ( - <Grid - item - key={type} - xs={4} - className="grid-item" - style={{ - height: 15, - width: 15, - backgroundImage: `url(${Icons.getTypes(type)})`, - }} - /> - ))} - {(raid_pokemon_id > 0 && raid_pokemon_gender != 3) && ( + {raid_pokemon_id > 0 && + getRaidTypes(raid_pokemon_id, raid_pokemon_form).map((type) => ( + <Grid + item + key={type} + xs={4} + className="grid-item" + style={{ + height: 15, + width: 15, + backgroundImage: `url(${Icons.getTypes(type)})`, + }} + /> + ))} + {raid_pokemon_id > 0 && raid_pokemon_gender != 3 && ( <Grid item xs={4} style={{ textAlign: 'center' }}> <Icon>{raid_pokemon_gender === 1 ? 'male' : 'female'}</Icon> </Grid> @@ -369,9 +365,13 @@ const RaidImage = ({ const GymInfo = ({ gym, t, Icons }) => { const { - team_id, available_slots, ex_raid_eligible, ar_scan_eligible, updated, + team_id, + available_slots, + ex_raid_eligible, + ar_scan_eligible, + updated, } = gym - const { gymValidDataLimit } = useStatic(state => state.config) + const { gymValidDataLimit } = useStatic((state) => state.config) return ( <Grid @@ -382,19 +382,19 @@ const GymInfo = ({ gym, t, Icons }) => { justifyContent="space-around" alignItems="center" > - {(updated > gymValidDataLimit) && ( - <Grid item xs={12}> - <Typography variant="h6" align="center"> - {t(`team_${team_id}`)} - </Typography> - </Grid> && ( + {updated > gymValidDataLimit && ( + <Grid item xs={12}> + <Typography variant="h6" align="center"> + {t(`team_${team_id}`)} + </Typography> + </Grid> + ) && ( <Grid item xs={12}> <Typography variant="subtitle1" align="center"> {available_slots} {t('slots')} </Typography> </Grid> - ) - )} + )} {ex_raid_eligible && ( <Grid item @@ -421,19 +421,19 @@ const GymInfo = ({ gym, t, Icons }) => { ) } -const RaidInfo = ({ - gym, t, Icons, -}) => { - const { moves, pokemon } = useStatic(state => state.masterfile) +const RaidInfo = ({ gym, t, Icons }) => { + const { moves, pokemon } = useStatic((state) => state.masterfile) const { - raid_level, raid_pokemon_id, raid_pokemon_form, raid_pokemon_move_1, raid_pokemon_move_2, + raid_level, + raid_pokemon_id, + raid_pokemon_form, + raid_pokemon_move_1, + raid_pokemon_move_2, raid_pokemon_evolution, } = gym if (!raid_pokemon_id) { - return ( - <Timer gym={gym} start t={t} /> - ) + return <Timer gym={gym} start t={t} /> } const getRaidName = (raidLevel, id) => { @@ -471,7 +471,11 @@ const RaidInfo = ({ </Grid> <Grid item xs={12}> <Typography variant="subtitle2" align="center"> - {getRaidForm(raid_pokemon_id, raid_pokemon_form, raid_pokemon_evolution)} + {getRaidForm( + raid_pokemon_id, + raid_pokemon_form, + raid_pokemon_evolution, + )} </Typography> </Grid> {raid_pokemon_move_1 && raid_pokemon_move_1 !== 1 && ( @@ -483,7 +487,9 @@ const RaidInfo = ({ textAlign: 'center', height: 15, width: 15, - backgroundImage: `url(${Icons.getTypes(moves[raid_pokemon_move_1].type)})`, + backgroundImage: `url(${Icons.getTypes( + moves[raid_pokemon_move_1].type, + )})`, }} /> )} @@ -492,7 +498,7 @@ const RaidInfo = ({ {t(`move_${raid_pokemon_move_1}`)} </Typography> </Grid> - {(raid_pokemon_move_2 && raid_pokemon_move_2 !== 2) && ( + {raid_pokemon_move_2 && raid_pokemon_move_2 !== 2 && ( <Grid item xs={2} @@ -501,7 +507,9 @@ const RaidInfo = ({ textAlign: 'center', height: 15, width: 15, - backgroundImage: `url(${Icons.getTypes(moves[raid_pokemon_move_2].type)})`, + backgroundImage: `url(${Icons.getTypes( + moves[raid_pokemon_move_2].type, + )})`, }} /> )} @@ -514,13 +522,13 @@ const RaidInfo = ({ ) } -const Timer = ({ - gym, start, t, hasHatched, -}) => { - const target = (start ? gym.raid_battle_timestamp : gym.raid_end_timestamp) * 1000 - const update = () => start || hasHatched || gym.raid_pokemon_id - ? Utility.getTimeUntil(target, true) - : Utility.formatInterval(target - gym.raid_battle_timestamp * 1000) +const Timer = ({ gym, start, t, hasHatched }) => { + const target = + (start ? gym.raid_battle_timestamp : gym.raid_end_timestamp) * 1000 + const update = () => + start || hasHatched || gym.raid_pokemon_id + ? Utility.getTimeUntil(target, true) + : Utility.formatInterval(target - gym.raid_battle_timestamp * 1000) const [display, setDisplay] = useState(update) useEffect(() => { @@ -529,9 +537,16 @@ const Timer = ({ }) return target ? ( - <Grid item xs={start && !gym.raid_pokemon_id ? 6 : 12} style={{ textAlign: 'center' }}> + <Grid + item + xs={start && !gym.raid_pokemon_id ? 6 : 12} + style={{ textAlign: 'center' }} + > <Typography variant="subtitle1"> - {t(start ? 'starts' : 'ends')}: {new Date(target).toLocaleTimeString(localStorage.getItem('i18nextLng') || 'en')} + {t(start ? 'starts' : 'ends')}:{' '} + {new Date(target).toLocaleTimeString( + localStorage.getItem('i18nextLng') || 'en', + )} </Typography> <Typography variant="h6"> {display.str.replace('days', t('days')).replace('day', t('day'))} @@ -540,23 +555,26 @@ const Timer = ({ ) : null } -const GymFooter = ({ - gym, popups, setPopups, hasRaid, perms, Icons, -}) => { +const GymFooter = ({ gym, popups, setPopups, hasRaid, perms, Icons }) => { const classes = useStyles() - const { navigation } = useStore(state => state.settings) - const { navigation: { [navigation]: { url } } } = useStatic(state => state.config) + const { navigation } = useStore((state) => state.settings) + const { + navigation: { + [navigation]: { url }, + }, + } = useStatic((state) => state.config) const { lat, lon } = gym const handleExpandClick = (category) => { setPopups({ - ...popups, [category]: !popups[category], + ...popups, + [category]: !popups[category], }) } return ( <> - {(hasRaid && perms.raids && perms.gyms) && ( + {hasRaid && perms.raids && perms.gyms && ( <Grid item xs={4}> <IconButton className={classes.expand} @@ -597,10 +615,9 @@ const GymFooter = ({ } const ExtraInfo = ({ gym, t, ts }) => { - const { - last_modified_timestamp, updated, total_cp, guarding_pokemon_id, - } = gym - const { gymValidDataLimit } = useStatic(state => state.config) + const { last_modified_timestamp, updated, total_cp, guarding_pokemon_id } = + gym + const { gymValidDataLimit } = useStatic((state) => state.config) const extraMetaData = [ { @@ -625,26 +642,38 @@ const ExtraInfo = ({ gym, t, ts }) => { data: Utility.dayCheck(ts, last_modified_timestamp), check: last_modified_timestamp, }, - ].filter(x => Boolean(x.check)) + ].filter((x) => Boolean(x.check)) return ( <Grid container> - {extraMetaData.map(meta => ( + {extraMetaData.map((meta) => ( <Fragment key={meta.description}> - <Grid item xs={t('popup_gym_description_width')} style={{ textAlign: 'left' }}> - <Typography variant="caption"> - {t(meta.description)}: - </Typography> + <Grid + item + xs={t('popup_gym_description_width')} + style={{ textAlign: 'left' }} + > + <Typography variant="caption">{t(meta.description)}:</Typography> </Grid> {Boolean(meta.timer) && ( - <Grid item xs={t('popup_gym_seen_timer_width')} style={{ textAlign: 'right' }}> + <Grid + item + xs={t('popup_gym_seen_timer_width')} + style={{ textAlign: 'right' }} + > {meta.timer} </Grid> )} - <Grid item xs={meta.timer ? t('popup_gym_data_width') : t('popup_gym_seen_timer_width')} style={{ textAlign: 'right' }}> - <Typography variant="caption"> - {meta.data} - </Typography> + <Grid + item + xs={ + meta.timer + ? t('popup_gym_data_width') + : t('popup_gym_seen_timer_width') + } + style={{ textAlign: 'right' }} + > + <Typography variant="caption">{meta.data}</Typography> </Grid> </Fragment> ))} diff --git a/src/components/popups/Nest.jsx b/src/components/popups/Nest.jsx index 4ac42ed90..11ca97331 100644 --- a/src/components/popups/Nest.jsx +++ b/src/components/popups/Nest.jsx @@ -1,6 +1,11 @@ import React, { useState, useEffect } from 'react' import { - Grid, Typography, IconButton, Divider, Menu, MenuItem, + Grid, + Typography, + IconButton, + Divider, + Menu, + MenuItem, } from '@material-ui/core' import { MoreVert } from '@material-ui/icons' import { useTranslation } from 'react-i18next' @@ -8,23 +13,19 @@ import { useTranslation } from 'react-i18next' import { useStore, useStatic } from '@hooks/useStore' import Utility from '@services/Utility' -export default function NestPopup({ - nest, iconUrl, pokemon, recent, -}) { +export default function NestPopup({ nest, iconUrl, pokemon, recent }) { const { t } = useTranslation() - const hideList = useStatic(state => state.hideList) - const setHideList = useStatic(state => state.setHideList) - const excludeList = useStatic(state => state.excludeList) - const setExcludeList = useStatic(state => state.setExcludeList) - const filters = useStore(state => state.filters) - const setFilters = useStore(state => state.setFilters) + const hideList = useStatic((state) => state.hideList) + const setHideList = useStatic((state) => state.setHideList) + const excludeList = useStatic((state) => state.excludeList) + const setExcludeList = useStatic((state) => state.setExcludeList) + const filters = useStore((state) => state.filters) + const setFilters = useStore((state) => state.setFilters) const [parkName, setParkName] = useState(true) const [anchorEl, setAnchorEl] = useState(false) - const { - id, name, updated, pokemon_avg, - } = nest + const { id, name, updated, pokemon_avg } = nest - const lastUpdated = Utility.getTimeUntil((new Date(updated * 1000))) + const lastUpdated = Utility.getTimeUntil(new Date(updated * 1000)) const getColor = (timeSince) => { let color = '#00e676' @@ -96,10 +97,7 @@ export default function NestPopup({ </Typography> </Grid> <Grid item xs={3}> - <IconButton - aria-haspopup="true" - onClick={handleClick} - > + <IconButton aria-haspopup="true" onClick={handleClick}> <MoreVert style={{ color: 'white' }} /> </IconButton> </Grid> @@ -136,10 +134,11 @@ export default function NestPopup({ </Typography> </Grid> <Grid item xs={6} style={{ textAlign: 'center' }}> - <Typography variant="subtitle2"> - {t('last_updated')} - </Typography> - <Typography variant={lastUpdated.str.includes('D') ? 'h6' : 'subtitle2'} style={{ color: getColor(lastUpdated.diff) }}> + <Typography variant="subtitle2">{t('last_updated')}</Typography> + <Typography + variant={lastUpdated.str.includes('D') ? 'h6' : 'subtitle2'} + style={{ color: getColor(lastUpdated.diff) }} + > {lastUpdated.str.replace('days', t('days')).replace('day', t('day'))} </Typography> <Typography variant="subtitle2"> @@ -152,12 +151,14 @@ export default function NestPopup({ <Grid item xs={12} style={{ textAlign: 'center' }}> {recent ? ( <Typography variant="caption"> - {t('nest_estimated')}<br /> + {t('nest_estimated')} + <br /> {t('verify_nests')} </Typography> ) : ( <Typography variant="caption"> - {t('nest_out_of_date')}<br /> + {t('nest_out_of_date')} + <br /> {t('nest_check_current')} </Typography> )} diff --git a/src/components/popups/Pokemon.jsx b/src/components/popups/Pokemon.jsx index e6d879e53..5729696cf 100644 --- a/src/components/popups/Pokemon.jsx +++ b/src/components/popups/Pokemon.jsx @@ -1,12 +1,17 @@ -import React, { - Fragment, useCallback, useState, useEffect, -} from 'react' +import React, { Fragment, useCallback, useState, useEffect } from 'react' import { - Grid, Avatar, Typography, Icon, Collapse, IconButton, Divider, Menu, MenuItem, Tooltip, + Grid, + Avatar, + Typography, + Icon, + Collapse, + IconButton, + Divider, + Menu, + MenuItem, + Tooltip, } from '@material-ui/core' -import { - Check, Clear, ExpandMore, Map, MoreVert, -} from '@material-ui/icons' +import { Check, Clear, ExpandMore, Map, MoreVert } from '@material-ui/icons' import { useTranslation } from 'react-i18next' import { useStore, useStatic } from '@hooks/useStore' @@ -24,25 +29,37 @@ const leagueLookup = { } export default function PokemonPopup({ - pokemon, iconUrl, userSettings, isTutorial, Icons, isNight, + pokemon, + iconUrl, + userSettings, + isTutorial, + Icons, + isNight, }) { const { t } = useTranslation() const classes = useStyles() + const { pokemon_id, cleanPvp, iv, cp } = pokemon + const { perms } = useStatic((state) => state.auth) + const pokePerms = isTutorial + ? { + pvp: true, + iv: true, + } + : perms const { - pokemon_id, cleanPvp, iv, cp, - } = pokemon - const { perms } = useStatic(state => state.auth) - const pokePerms = isTutorial ? { - pvp: true, iv: true, - } : perms - const { pokemon: { [pokemon_id]: metaData } } = useStatic(state => state.masterfile) - const popups = useStore(state => state.popups) - const setPopups = useStore(state => state.setPopups) + pokemon: { [pokemon_id]: metaData }, + } = useStatic((state) => state.masterfile) + const popups = useStore((state) => state.popups) + const setPopups = useStore((state) => state.setPopups) const hasLeagues = cleanPvp ? Object.keys(cleanPvp) : [] const hasStats = iv || cp useEffect(() => { - Utility.analytics('Popup', `ID: ${pokemon.pokemon_id} IV: ${pokemon.iv}% PVP: #${pokemon.bestPvp}`, 'Pokemon') + Utility.analytics( + 'Popup', + `ID: ${pokemon.pokemon_id} IV: ${pokemon.iv}% PVP: #${pokemon.bestPvp}`, + 'Pokemon', + ) }, []) return ( @@ -64,22 +81,14 @@ export default function PokemonPopup({ isTutorial={isTutorial} /> {Boolean(pokemon.expire_timestamp) && ( - <Timer - pokemon={pokemon} - hasStats={hasStats} - t={t} - /> + <Timer pokemon={pokemon} hasStats={hasStats} t={t} /> )} {pokemon.seen_type === 'nearby_cell' && ( <Typography>{t('pokemon_cell')}</Typography> )} - {(hasStats && pokePerms.iv) && ( + {hasStats && pokePerms.iv && ( <> - <Stats - pokemon={pokemon} - metaData={metaData} - t={t} - /> + <Stats pokemon={pokemon} metaData={metaData} t={t} /> <Divider orientation="vertical" flexItem /> </> )} @@ -99,7 +108,7 @@ export default function PokemonPopup({ Icons={Icons} /> <Collapse in={popups.pvp && perms.pvp} timeout="auto" unmountOnExit> - {hasLeagues.map(league => ( + {hasLeagues.map((league) => ( <PvpInfo key={league} league={league} @@ -111,33 +120,32 @@ export default function PokemonPopup({ ))} </Collapse> <Collapse in={popups.extras} timeout="auto" unmountOnExit> - <ExtraInfo - pokemon={pokemon} - perms={pokePerms} - t={t} - Icons={Icons} - /> + <ExtraInfo pokemon={pokemon} perms={pokePerms} t={t} Icons={Icons} /> </Collapse> </Grid> ) } const Header = ({ - pokemon, metaData, t, iconUrl, userSettings, classes, isTutorial, + pokemon, + metaData, + t, + iconUrl, + userSettings, + classes, + isTutorial, }) => { - const hideList = useStatic(state => state.hideList) - const setHideList = useStatic(state => state.setHideList) - const excludeList = useStatic(state => state.excludeList) - const setExcludeList = useStatic(state => state.setExcludeList) - const timerList = useStatic(state => state.timerList) - const setTimerList = useStatic(state => state.setTimerList) - const filters = useStore(state => state.filters) - const setFilters = useStore(state => state.setFilters) + const hideList = useStatic((state) => state.hideList) + const setHideList = useStatic((state) => state.setHideList) + const excludeList = useStatic((state) => state.excludeList) + const setExcludeList = useStatic((state) => state.setExcludeList) + const timerList = useStatic((state) => state.timerList) + const setTimerList = useStatic((state) => state.setTimerList) + const filters = useStore((state) => state.filters) + const setFilters = useStore((state) => state.setFilters) const [anchorEl, setAnchorEl] = useState(false) - const { - id, pokemon_id, form, ditto_form, display_pokemon_id, - } = pokemon + const { id, pokemon_id, form, ditto_form, display_pokemon_id } = pokemon const handleClick = (event) => { setAnchorEl(event.currentTarget) @@ -174,7 +182,7 @@ const Header = ({ const handleTimer = () => { setAnchorEl(null) if (timerList.includes(id)) { - setTimerList(timerList.filter(x => x !== id)) + setTimerList(timerList.filter((x) => x !== id)) } else { setTimerList([...timerList, id]) } @@ -184,44 +192,51 @@ const Header = ({ { name: 'timer', action: handleTimer }, { name: 'hide', action: handleHide }, ] - if (isTutorial || filters?.pokemon?.filter?.[`${pokemon_id}-${form}`]?.enabled) { + if ( + isTutorial || + filters?.pokemon?.filter?.[`${pokemon_id}-${form}`]?.enabled + ) { options.push({ name: 'exclude', action: handleExclude }) } const pokeName = t(`poke_${metaData.pokedexId}`) - const formName = metaData.forms?.[form]?.name === 'Normal' || form === 0 ? '' : t(`form_${pokemon.form}`) + const formName = + metaData.forms?.[form]?.name === 'Normal' || form === 0 + ? '' + : t(`form_${pokemon.form}`) return ( <> <Grid item xs={3}> - {userSettings.showDexNumInPopup - ? ( - <Avatar classes={{ + {userSettings.showDexNumInPopup ? ( + <Avatar + classes={{ colorDefault: classes.avatar, }} - >{metaData.pokedexId} - </Avatar> - ) - : <img src={iconUrl} style={{ maxWidth: 40, maxHeight: 40 }} alt={pokemon.pokemon_id} />} + > + {metaData.pokedexId} + </Avatar> + ) : ( + <img + src={iconUrl} + style={{ maxWidth: 40, maxHeight: 40 }} + alt={pokemon.pokemon_id} + /> + )} </Grid> <Grid item xs={6} style={{ textAlign: 'center' }}> <Typography variant={pokeName.length > 8 ? 'h6' : 'h5'}> {pokeName} </Typography> - {(ditto_form !== null && display_pokemon_id) ? ( + {ditto_form !== null && display_pokemon_id ? ( <Typography variant="caption"> ({t(`poke_${display_pokemon_id}`)}) </Typography> ) : ( - <Typography variant="caption"> - {formName} - </Typography> + <Typography variant="caption">{formName}</Typography> )} </Grid> <Grid item xs={3}> - <IconButton - aria-haspopup="true" - onClick={handleClick} - > + <IconButton aria-haspopup="true" onClick={handleClick}> <MoreVert style={{ color: 'white' }} /> </IconButton> </Grid> @@ -248,20 +263,24 @@ const Header = ({ } const Stats = ({ pokemon, t }) => { - const { - cp, iv, atk_iv, def_iv, sta_iv, level, inactive_stats, - } = pokemon - - const getColor = useCallback(ivPercent => { - const ivColors = { - 0: 'red', 66: 'orange', 82: 'yellow', 100: '#00e676', - } - let color - Object.keys(ivColors).forEach(range => ( - ivPercent >= parseInt(range) ? color = ivColors[range] : '' - )) - return color - }, [iv]) + const { cp, iv, atk_iv, def_iv, sta_iv, level, inactive_stats } = pokemon + + const getColor = useCallback( + (ivPercent) => { + const ivColors = { + 0: 'red', + 66: 'orange', + 82: 'yellow', + 100: '#00e676', + } + let color + Object.keys(ivColors).forEach((range) => + ivPercent >= parseInt(range) ? (color = ivColors[range]) : '', + ) + return color + }, + [iv], + ) return ( <Grid @@ -274,8 +293,13 @@ const Stats = ({ pokemon, t }) => { > {iv !== null && ( <Grid item> - <Typography variant="h5" align="center" style={{ color: getColor(iv) }}> - {iv.toFixed(2)}{t('%')} + <Typography + variant="h5" + align="center" + style={{ color: getColor(iv) }} + > + {iv.toFixed(2)} + {t('%')} </Typography> </Grid> )} @@ -289,7 +313,8 @@ const Stats = ({ pokemon, t }) => { {level !== null && ( <Grid item> <Typography variant="subtitle1" align="center"> - {t('cp')} {cp} | {t('abbreviation_level')}{level} + {t('cp')} {cp} | {t('abbreviation_level')} + {level} </Typography> </Grid> )} @@ -297,22 +322,20 @@ const Stats = ({ pokemon, t }) => { ) } -const Info = ({ - pokemon, metaData, perms, Icons, isNight, -}) => { +const Info = ({ pokemon, metaData, perms, Icons, isNight }) => { const { gender, weather, form } = pokemon const formTypes = metaData?.forms?.[form]?.types || metaData?.types || [] return ( <Grid item - xs={(perms.iv) ? 3 : 11} + xs={perms.iv ? 3 : 11} container - direction={(perms.iv) ? 'column' : 'row'} + direction={perms.iv ? 'column' : 'row'} justifyContent="space-around" alignItems="center" > - {(weather != 0 && perms.iv) && ( + {weather != 0 && perms.iv && ( <Grid item className="grid-item" @@ -334,7 +357,7 @@ const Info = ({ </Icon> </Grid> )} - {formTypes.map(type => ( + {formTypes.map((type) => ( <Grid item key={type} @@ -370,29 +393,39 @@ const Timer = ({ pokemon, hasStats, t }) => { {timer.str} </Typography> <Typography variant="subtitle2" align="center"> - {despawnTimer.toLocaleTimeString(localStorage.getItem('i18nextLng') || 'en')} + {despawnTimer.toLocaleTimeString( + localStorage.getItem('i18nextLng') || 'en', + )} </Typography> </Grid> <Grid item xs={hasStats ? 3 : 2}> <Tooltip - title={expire_timestamp_verified ? t('timer_verified') : t('timer_unverified')} + title={ + expire_timestamp_verified + ? t('timer_verified') + : t('timer_unverified') + } arrow enterTouchDelay={0} > - {expire_timestamp_verified - ? <Check fontSize="large" style={{ color: '#00e676' }} /> - : <Clear fontSize="large" color="primary" />} + {expire_timestamp_verified ? ( + <Check fontSize="large" style={{ color: '#00e676' }} /> + ) : ( + <Clear fontSize="large" color="primary" /> + )} </Tooltip> </Grid> </> ) } -const Footer = ({ - pokemon, popups, setPopups, hasPvp, classes, Icons, -}) => { - const { navigation } = useStore(state => state.settings) - const { navigation: { [navigation]: { url } } } = useStatic(state => state.config) +const Footer = ({ pokemon, popups, setPopups, hasPvp, classes, Icons }) => { + const { navigation } = useStore((state) => state.settings) + const { + navigation: { + [navigation]: { url }, + }, + } = useStatic((state) => state.config) const { lat, lon } = pokemon @@ -426,7 +459,12 @@ const Footer = ({ )} <Grid item xs={4} style={{ textAlign: 'center' }}> <IconButton> - <a href={url.replace('{x}', lat).replace('{y}', lon)} target="_blank" rel="noreferrer" style={{ color: 'white' }}> + <a + href={url.replace('{x}', lat).replace('{y}', lon)} + target="_blank" + rel="noreferrer" + style={{ color: 'white' }} + > <Map /> </a> </IconButton> @@ -444,94 +482,123 @@ const Footer = ({ ) } -const ExtraInfo = ({ - pokemon, perms, t, Icons, -}) => { - const { moves } = useStatic(state => state.masterfile) +const ExtraInfo = ({ pokemon, perms, t, Icons }) => { + const { moves } = useStatic((state) => state.masterfile) - const { - move_1, move_2, weight, size, first_seen_timestamp, updated, iv, - } = pokemon + const { move_1, move_2, weight, size, first_seen_timestamp, updated, iv } = + pokemon return ( - <Grid - container - alignItems="center" - justifyContent="center" - > - {(perms.iv && iv !== null) && [move_1, move_2].map((move, i) => { - if (!move) return null - return ( - <Fragment key={move}> - <Grid - item - xs={2} - className="grid-item" - style={{ - height: 15, - width: 15, - backgroundImage: `url(${Icons.getTypes(moves[move].type)})`, - }} - /> - <Grid item xs={6}> - <Typography variant="caption"> - {t(`move_${move}`)} - </Typography> - </Grid> - <Grid item xs={3} style={{ textAlign: 'right' }}> - <Typography variant="caption"> - {i ? `${weight ? weight.toFixed(2) : '? '}${t('kilogram')}` : `${size ? size.toFixed(2) : '? '}${t('meter')}`} - </Typography> - </Grid> - </Fragment> - ) - })} - {[first_seen_timestamp, updated].map((time, i) => ( + <Grid container alignItems="center" justifyContent="center"> + {perms.iv && + iv !== null && + [move_1, move_2].map((move, i) => { + if (!move) return null + return ( + <Fragment key={move}> + <Grid + item + xs={2} + className="grid-item" + style={{ + height: 15, + width: 15, + backgroundImage: `url(${Icons.getTypes(moves[move].type)})`, + }} + /> + <Grid item xs={6}> + <Typography variant="caption">{t(`move_${move}`)}</Typography> + </Grid> + <Grid item xs={3} style={{ textAlign: 'right' }}> + <Typography variant="caption"> + {i + ? `${weight ? weight.toFixed(2) : '? '}${t('kilogram')}` + : `${size ? size.toFixed(2) : '? '}${t('meter')}`} + </Typography> + </Grid> + </Fragment> + ) + })} + {[first_seen_timestamp, updated].map((time, i) => time ? ( <Fragment key={time}> - <Grid item xs={t('popup_pokemon_description_width')} style={{ textAlign: 'center' }}> + <Grid + item + xs={t('popup_pokemon_description_width')} + style={{ textAlign: 'center' }} + > <Typography variant="caption"> {i ? t('last_seen') : t('first_seen')}: </Typography> </Grid> - <Grid item xs={t('popup_pokemon_seen_timer_width')} style={{ textAlign: 'right' }}> + <Grid + item + xs={t('popup_pokemon_seen_timer_width')} + style={{ textAlign: 'right' }} + > <GenericTimer expireTime={time} /> </Grid> - <Grid item xs={t('popup_pokemon_data_width')} style={{ textAlign: 'right' }}> + <Grid + item + xs={t('popup_pokemon_data_width')} + style={{ textAlign: 'right' }} + > <Typography variant="caption"> - {(new Date(time * 1000)).toLocaleTimeString(localStorage.getItem('i18nextLng') || 'en')} + {new Date(time * 1000).toLocaleTimeString( + localStorage.getItem('i18nextLng') || 'en', + )} </Typography> </Grid> </Fragment> - ) : null - ))} + ) : null, + )} </Grid> ) } -const PvpInfo = ({ - pokemon, league, data, t, Icons, -}) => { +const PvpInfo = ({ pokemon, league, data, t, Icons }) => { if (data === null) return '' - const rows = data.map(each => each.rank !== null && each.cp !== null ? { - id: `${league}-${each.pokemon}-${each.form}-${each.evolution}-${each.gender}-${each.rank}-${each.cp}-${each.lvl}-${each.cap}`, - img: <img - src={Icons.getPokemon(each.pokemon, each.form, each.evolution, each.gender, pokemon.costume)} - height={20} - alt={each.pokemon} - />, - rank: each.rank || 0, - cp: each.cp || 0, - lvl: `${each.level || ''}${each.cap && !each.capped ? `/${each.cap}` : ''}`, - percent: (each.percentage * 100).toFixed(1) || 0, - } : null).filter(Boolean) + const rows = data + .map((each) => + each.rank !== null && each.cp !== null + ? { + id: `${league}-${each.pokemon}-${each.form}-${each.evolution}-${each.gender}-${each.rank}-${each.cp}-${each.lvl}-${each.cap}`, + img: ( + <img + src={Icons.getPokemon( + each.pokemon, + each.form, + each.evolution, + each.gender, + pokemon.costume, + )} + height={20} + alt={each.pokemon} + /> + ), + rank: each.rank || 0, + cp: each.cp || 0, + lvl: `${each.level || ''}${ + each.cap && !each.capped ? `/${each.cap}` : '' + }`, + percent: (each.percentage * 100).toFixed(1) || 0, + } + : null, + ) + .filter(Boolean) return ( <table className="table-pvp"> <thead> <tr> - <td style={rowClass}><img src={Icons.getMisc(leagueLookup[league] || 500)} height={20} alt={league} /></td> + <td style={rowClass}> + <img + src={Icons.getMisc(leagueLookup[league] || 500)} + height={20} + alt={league} + /> + </td> <td style={rowClass}>{t('rank')}</td> <td style={rowClass}>{t('cp')}</td> <td style={rowClass}>{t('lvl')}</td> diff --git a/src/components/popups/Pokestop.jsx b/src/components/popups/Pokestop.jsx index 2e61bc878..e1a762278 100644 --- a/src/components/popups/Pokestop.jsx +++ b/src/components/popups/Pokestop.jsx @@ -1,8 +1,10 @@ -import React, { - Fragment, useState, useEffect, -} from 'react' +import React, { Fragment, useState, useEffect } from 'react' import { - Grid, Typography, Collapse, IconButton, Divider, + Grid, + Typography, + Collapse, + IconButton, + Divider, } from '@material-ui/core' import { ExpandMore, MoreVert } from '@material-ui/icons' import { useTranslation, Trans } from 'react-i18next' @@ -20,19 +22,28 @@ import Timer from './common/Timer' import PowerUp from './common/PowerUp' export default function PokestopPopup({ - pokestop, ts, hasLure, hasInvasion, hasQuest, Icons, userSettings, config, + pokestop, + ts, + hasLure, + hasInvasion, + hasQuest, + Icons, + userSettings, + config, }) { const { t } = useTranslation() - const { pokestops: perms } = useStatic(state => state.ui) - const popups = useStore(state => state.popups) - const setPopups = useStore(state => state.setPopups) - const { - lure_expire_timestamp, lure_id, invasions, - } = pokestop + const { pokestops: perms } = useStatic((state) => state.ui) + const popups = useStore((state) => state.popups) + const setPopups = useStore((state) => state.setPopups) + const { lure_expire_timestamp, lure_id, invasions } = pokestop useEffect(() => { const has = { hasLure, hasQuest, hasInvasion } - Utility.analytics('Popup', Object.keys(has).filter(a => Boolean(has[a])), 'Pokestop') + Utility.analytics( + 'Popup', + Object.keys(has).filter((a) => Boolean(has[a])), + 'Pokestop', + ) }, []) const plainPokestop = !hasLure && !hasQuest && !hasInvasion @@ -57,10 +68,7 @@ export default function PokestopPopup({ </Grid> )} <Grid item xs={plainPokestop ? 10 : 7}> - <Title - mainName={pokestop.name} - backup={t('unknown_pokestop')} - /> + <Title mainName={pokestop.name} backup={t('unknown_pokestop')} /> </Grid> <MenuActions pokestop={pokestop} @@ -84,33 +92,45 @@ export default function PokestopPopup({ <PowerUp {...pokestop} /> </> ) : ( - <Collapse in={!popups.invasions || !hasInvasion} timeout="auto" unmountOnExit> + <Collapse + in={!popups.invasions || !hasInvasion} + timeout="auto" + unmountOnExit + > <Grid container justifyContent="center" alignItems="center" spacing={1} > - <PowerUp {...pokestop} divider={hasInvasion || hasQuest || hasLure} /> - {hasQuest && pokestop.quests.map((quest, index) => ( - <Fragment key={quest.with_ar}> - {index ? <Divider light flexItem className="popup-divider" /> : null} - <RewardInfo - quest={quest} - Icons={Icons} - config={config} - t={t} - /> - <QuestConditions - quest={quest} - t={t} - userSettings={userSettings} - /> - </Fragment> - ))} + <PowerUp + {...pokestop} + divider={hasInvasion || hasQuest || hasLure} + /> + {hasQuest && + pokestop.quests.map((quest, index) => ( + <Fragment key={quest.with_ar}> + {index ? ( + <Divider light flexItem className="popup-divider" /> + ) : null} + <RewardInfo + quest={quest} + Icons={Icons} + config={config} + t={t} + /> + <QuestConditions + quest={quest} + t={t} + userSettings={userSettings} + /> + </Fragment> + ))} {hasLure && ( <> - {(hasQuest) && <Divider light flexItem className="popup-divider" />} + {hasQuest && ( + <Divider light flexItem className="popup-divider" /> + )} <TimeTile expireTime={lure_expire_timestamp} icon={Icons.getPokestops(lure_id)} @@ -120,10 +140,16 @@ export default function PokestopPopup({ )} {hasInvasion && ( <> - {(hasQuest || hasLure) && <Divider light flexItem className="popup-divider" />} + {(hasQuest || hasLure) && ( + <Divider light flexItem className="popup-divider" /> + )} {invasions.map((invasion, index) => ( - <Fragment key={`${invasion.grunt_type}-${invasion.incident_expire_timestamp}`}> - {index ? <Divider light flexItem className="popup-divider" /> : null} + <Fragment + key={`${invasion.grunt_type}-${invasion.incident_expire_timestamp}`} + > + {index ? ( + <Divider light flexItem className="popup-divider" /> + ) : null} <TimeTile expireTime={invasion.incident_expire_timestamp} icon={Icons.getInvasions(invasion.grunt_type)} @@ -137,7 +163,7 @@ export default function PokestopPopup({ </Collapse> )} </Grid> - {(perms.invasions && hasInvasion) && ( + {perms.invasions && hasInvasion && ( <Collapse in={popups.invasions} timeout="auto" unmountOnExit> <Invasion pokestop={pokestop} Icons={Icons} t={t} /> </Collapse> @@ -160,22 +186,25 @@ export default function PokestopPopup({ } const MenuActions = ({ - pokestop, perms, hasInvasion, hasQuest, hasLure, t, + pokestop, + perms, + hasInvasion, + hasQuest, + hasLure, + t, }) => { - const hideList = useStatic(state => state.hideList) - const setHideList = useStatic(state => state.setHideList) - const excludeList = useStatic(state => state.excludeList) - const setExcludeList = useStatic(state => state.setExcludeList) - const timerList = useStatic(state => state.timerList) - const setTimerList = useStatic(state => state.setTimerList) - const filters = useStore(state => state.filters) - const setFilters = useStore(state => state.setFilters) + const hideList = useStatic((state) => state.hideList) + const setHideList = useStatic((state) => state.setHideList) + const excludeList = useStatic((state) => state.excludeList) + const setExcludeList = useStatic((state) => state.setExcludeList) + const timerList = useStatic((state) => state.timerList) + const setTimerList = useStatic((state) => state.setTimerList) + const filters = useStore((state) => state.filters) + const setFilters = useStore((state) => state.setFilters) const [anchorEl, setAnchorEl] = useState(false) - const { - id, lure_id, quests, invasions, - } = pokestop + const { id, lure_id, quests, invasions } = pokestop const handleClick = (event) => { setAnchorEl(event.currentTarget) @@ -225,27 +254,39 @@ const MenuActions = ({ const handleTimer = () => { setAnchorEl(null) if (timerList.includes(id)) { - setTimerList(timerList.filter(x => x !== id)) + setTimerList(timerList.filter((x) => x !== id)) } else { setTimerList([...timerList, id]) } } - const options = [ - { name: 'hide', action: handleHide }, - ] + const options = [{ name: 'hide', action: handleHide }] if (perms.quests && hasQuest) { quests.forEach((quest, i) => { let reward = '' switch (quest.quest_reward_type) { - case 2: reward = t(`item_${quest.quest_item_id}`); break - case 3: reward = `${t('stardust')} x${quest.stardust_amount}`; break - case 4: reward = `${t(`poke_${quest.candy_pokemon_id} ${t('candy')}`)}`; break - case 7: reward = t(`poke_${quest.quest_pokemon_id}`); break - case 9: reward = t(`poke_${quest.quest_pokemon_id} ${t('xl')}`); break - case 12: reward = `${t(`poke_${quest.mega_pokemon_id}`)} x${quest.mega_amount}`; break - default: reward = t(`quest_reward_${quest.quest_reward_type}`); break + case 2: + reward = t(`item_${quest.quest_item_id}`) + break + case 3: + reward = `${t('stardust')} x${quest.stardust_amount}` + break + case 4: + reward = `${t(`poke_${quest.candy_pokemon_id} ${t('candy')}`)}` + break + case 7: + reward = t(`poke_${quest.quest_pokemon_id}`) + break + case 9: + reward = t(`poke_${quest.quest_pokemon_id} ${t('xl')}`) + break + case 12: + reward = `${t(`poke_${quest.mega_pokemon_id}`)} x${quest.mega_amount}` + break + default: + reward = t(`quest_reward_${quest.quest_reward_type}`) + break } options.push({ key: `${reward}-${quest.with_ar}`, @@ -255,13 +296,16 @@ const MenuActions = ({ }) } - if ((perms.invasions && hasInvasion) - || (perms.lures && hasLure)) { + if ((perms.invasions && hasInvasion) || (perms.lures && hasLure)) { if (hasInvasion) { invasions.forEach((invasion, i) => { options.push({ key: `${invasion.grunt_type}-${invasion.incident_expire_timestamp}`, - name: <Trans i18nKey="exclude_invasion_multi">{{ invasion: t(`grunt_a_${invasion.grunt_type}`) }}</Trans>, + name: ( + <Trans i18nKey="exclude_invasion_multi"> + {{ invasion: t(`grunt_a_${invasion.grunt_type}`) }} + </Trans> + ), action: () => excludeInvasion(i), }) }) @@ -269,16 +313,11 @@ const MenuActions = ({ if (hasLure) { options.push({ name: 'exclude_lure', action: excludeLure }) } - options.push( - { name: 'timer', action: handleTimer }, - ) + options.push({ name: 'timer', action: handleTimer }) } return ( <Grid item xs={2} style={{ textAlign: 'right' }}> - <IconButton - aria-haspopup="true" - onClick={handleClick} - > + <IconButton aria-haspopup="true" onClick={handleClick}> <MoreVert style={{ color: 'white' }} /> </IconButton> <Dropdown @@ -290,9 +329,7 @@ const MenuActions = ({ ) } -const RewardInfo = ({ - quest, Icons, config, t, -}) => { +const RewardInfo = ({ quest, Icons, config, t }) => { const { quest_item_id, item_amount, @@ -312,19 +349,29 @@ const RewardInfo = ({ const getImage = () => { switch (quest_reward_type) { - case 2: return Icons.getRewards(quest_reward_type, quest_item_id, item_amount) - case 3: return Icons.getRewards(quest_reward_type, stardust_amount) - case 4: return Icons.getRewards(quest_reward_type, candy_pokemon_id, candy_amount) - case 7: return Icons.getPokemon( - quest_pokemon_id, - quest_form_id, - 0, - quest_gender_id, - quest_costume_id, - quest_shiny, - ) - case 12: return Icons.getRewards(quest_reward_type, mega_pokemon_id, mega_amount) - default: return Icons.getRewards(quest_reward_type) + case 2: + return Icons.getRewards(quest_reward_type, quest_item_id, item_amount) + case 3: + return Icons.getRewards(quest_reward_type, stardust_amount) + case 4: + return Icons.getRewards( + quest_reward_type, + candy_pokemon_id, + candy_amount, + ) + case 7: + return Icons.getPokemon( + quest_pokemon_id, + quest_form_id, + 0, + quest_gender_id, + quest_costume_id, + quest_shiny, + ) + case 12: + return Icons.getRewards(quest_reward_type, mega_pokemon_id, mega_amount) + default: + return Icons.getRewards(quest_reward_type) } } @@ -332,7 +379,9 @@ const RewardInfo = ({ <Grid item xs={3} style={{ textAlign: 'center' }}> <img src={getImage()} className="quest-popup-img" alt="quest reward" /> <Typography variant="caption" className="ar-task" noWrap> - {config.questMessage ? config.questMessage : t(`ar_quest_${Boolean(with_ar)}`)} + {config.questMessage + ? config.questMessage + : t(`ar_quest_${Boolean(with_ar)}`)} </Typography> </Grid> ) @@ -351,9 +400,7 @@ const QuestConditions = ({ quest, t, userSettings }) => { if (userSettings.madQuestText && quest_task) { return ( <Grid item xs={9} style={{ textAlign: 'center' }}> - <Typography variant="caption"> - {quest_task} - </Typography> + <Typography variant="caption">{quest_task}</Typography> </Grid> ) } @@ -364,9 +411,7 @@ const QuestConditions = ({ quest, t, userSettings }) => { return ( <Grid item xs={9} style={{ textAlign: 'center' }}> <Typography variant="caption"> - <Trans i18nKey={normalized}> - {{ amount_0: quest_target }} - </Trans> + <Trans i18nKey={normalized}>{{ amount_0: quest_target }}</Trans> </Typography> </Grid> ) @@ -376,56 +421,67 @@ const QuestConditions = ({ quest, t, userSettings }) => { const [type1, type2] = Utility.parseConditions(quest_conditions) const primaryCondition = ( <Typography variant="caption"> - <Trans i18nKey={`quest_${quest_type}`}> - {{ amount: quest_target }} - </Trans> + <Trans i18nKey={`quest_${quest_type}`}>{{ amount: quest_target }}</Trans> </Typography> ) const getQuestConditions = (qType, qInfo) => { const key = `quest_condition_${qType}_formatted` switch (qType) { - case 1: return ( - <Trans i18nKey={key}> - {{ types: qInfo.pokemon_type_ids.map(id => t(`poke_type_${id}`)) }} - </Trans> - ) - case 2: return ( - <Trans i18nKey={key}> - {{ pokemon: qInfo.pokemon_ids.map(id => t(`poke_${id}`)) }} - </Trans> - ) - case 7: return ( - <Trans i18nKey={key}> - {{ levels: qInfo.raid_levels.map(id => id) }} - </Trans> - ) - case 11: return ( - <Trans i18nKey={key}> - {{ item: t(`item_${qInfo.item_id}`) }} - </Trans> - ) + case 1: + return ( + <Trans i18nKey={key}> + {{ + types: qInfo.pokemon_type_ids.map((id) => t(`poke_type_${id}`)), + }} + </Trans> + ) + case 2: + return ( + <Trans i18nKey={key}> + {{ pokemon: qInfo.pokemon_ids.map((id) => t(`poke_${id}`)) }} + </Trans> + ) + case 7: + return ( + <Trans i18nKey={key}> + {{ levels: qInfo.raid_levels.map((id) => id) }} + </Trans> + ) + case 11: + return ( + <Trans i18nKey={key}>{{ item: t(`item_${qInfo.item_id}`) }}</Trans> + ) case 8: - case 14: return qInfo.throw_type_id ? ( - <Trans i18nKey={key}> - {{ throw_type: t(`throw_type_${qInfo.throw_type_id}`) }} - </Trans> - ) : t('quest_condition_14') - case 26: return ( - <Trans i18nKey={key}> - {{ alignments: qInfo.alignment_ids.map(id => t(`alignment_${id}`)) }} - </Trans> - ) - case 27: return ( - <Trans i18nKey={key}> - {{ categories: qInfo.character_category_ids.map(id => t(`character_category_${id}`)) }} - </Trans> - ) - case 44: return ( - <Trans i18nKey={key}> - {{ time: qInfo.time }} - </Trans> - ) - default: return t(`quest_condition_${qType}`) + case 14: + return qInfo.throw_type_id ? ( + <Trans i18nKey={key}> + {{ throw_type: t(`throw_type_${qInfo.throw_type_id}`) }} + </Trans> + ) : ( + t('quest_condition_14') + ) + case 26: + return ( + <Trans i18nKey={key}> + {{ + alignments: qInfo.alignment_ids.map((id) => t(`alignment_${id}`)), + }} + </Trans> + ) + case 27: + return ( + <Trans i18nKey={key}> + {{ + categories: qInfo.character_category_ids.map((id) => + t(`character_category_${id}`), + ), + }} + </Trans> + ) + case 44: + return <Trans i18nKey={key}>{{ time: qInfo.time }}</Trans> + default: + return t(`quest_condition_${qType}`) } } return ( @@ -451,21 +507,25 @@ const QuestConditions = ({ quest, t, userSettings }) => { ) } -const Footer = ({ - pokestop, popups, setPopups, - hasInvasion, perms, Icons, -}) => { +const Footer = ({ pokestop, popups, setPopups, hasInvasion, perms, Icons }) => { const classes = useStyles() const handleExpandClick = (category) => { setPopups({ - ...popups, [category]: !popups[category], + ...popups, + [category]: !popups[category], }) } return ( - <Grid container item xs={12} justifyContent="space-evenly" alignItems="center"> - {(hasInvasion && perms.invasions) && ( + <Grid + container + item + xs={12} + justifyContent="space-evenly" + alignItems="center" + > + {hasInvasion && perms.invasions && ( <Grid item xs={3} style={{ textAlign: 'center' }}> <IconButton className={classes.expand} @@ -515,25 +575,29 @@ const ExtraInfo = ({ pokestop, t, ts }) => { ] return ( - <Grid - container - alignItems="center" - justifyContent="center" - > - {extraMetaData.map(meta => ( + <Grid container alignItems="center" justifyContent="center"> + {extraMetaData.map((meta) => ( <Fragment key={meta.description}> - <Grid item xs={t('popup_pokestop_description_width')} style={{ textAlign: 'left' }}> - <Typography variant="caption"> - {t(meta.description)}: - </Typography> + <Grid + item + xs={t('popup_pokestop_description_width')} + style={{ textAlign: 'left' }} + > + <Typography variant="caption">{t(meta.description)}:</Typography> </Grid> - <Grid item xs={t('popup_pokestop_seen_timer_width')} style={{ textAlign: 'right' }}> + <Grid + item + xs={t('popup_pokestop_seen_timer_width')} + style={{ textAlign: 'right' }} + > {meta.timer} </Grid> - <Grid item xs={t('popup_pokestop_data_width')} style={{ textAlign: 'right' }}> - <Typography variant="caption"> - {meta.data} - </Typography> + <Grid + item + xs={t('popup_pokestop_data_width')} + style={{ textAlign: 'right' }} + > + <Typography variant="caption">{meta.data}</Typography> </Grid> </Fragment> ))} @@ -543,15 +607,22 @@ const ExtraInfo = ({ pokestop, t, ts }) => { const Invasion = ({ pokestop, Icons, t }) => { const { invasions } = pokestop - const { invasions: invasionInfo } = useStatic(state => state.masterfile) + const { invasions: invasionInfo } = useStatic((state) => state.masterfile) const encounterNum = { first: '#1', second: '#2', third: '#3' } - const makeShadowPokemon = pkmn => ( + const makeShadowPokemon = (pkmn) => ( <div key={pkmn.id} className="invasion-reward"> <img className="invasion-reward" alt="invasion reward" - src={Icons.getPokemon(pkmn.id, pkmn.form, 0, pkmn.gender, pkmn.costumeId, pkmn.shiny)} + src={Icons.getPokemon( + pkmn.id, + pkmn.form, + 0, + pkmn.gender, + pkmn.costumeId, + pkmn.shiny, + )} /> <img className="invasion-reward-shadow" @@ -561,7 +632,7 @@ const Invasion = ({ pokestop, Icons, t }) => { </div> ) - const getRewardPercent = grunt => { + const getRewardPercent = (grunt) => { if (grunt.type === 'Giovanni') { return { third: '100%' } } @@ -574,8 +645,11 @@ const Invasion = ({ pokestop, Icons, t }) => { return { first: '100%' } } - return invasions.map(invasion => ( - <Grid container key={`${invasion.grunt_type}-${invasion.incident_expire_timestamp}`}> + return invasions.map((invasion) => ( + <Grid + container + key={`${invasion.grunt_type}-${invasion.incident_expire_timestamp}`} + > <Grid item xs={12}> <Typography variant="h6" align="center"> {t(`grunt_a_${invasion.grunt_type}`)} @@ -584,15 +658,23 @@ const Invasion = ({ pokestop, Icons, t }) => { <Grid item xs={12}> <table className="table-invasion"> <tbody> - {Object.keys(invasionInfo[invasion.grunt_type].encounters).map(position => ( - <tr key={position}> - <td>{encounterNum[position]}</td> - <td> - {invasionInfo[invasion.grunt_type].encounters[position].map(data => makeShadowPokemon(data))} - </td> - <td>{getRewardPercent(invasionInfo[invasion.grunt_type])[position] || ''}</td> - </tr> - ))} + {Object.keys(invasionInfo[invasion.grunt_type].encounters).map( + (position) => ( + <tr key={position}> + <td>{encounterNum[position]}</td> + <td> + {invasionInfo[invasion.grunt_type].encounters[position].map( + (data) => makeShadowPokemon(data), + )} + </td> + <td> + {getRewardPercent(invasionInfo[invasion.grunt_type])[ + position + ] || ''} + </td> + </tr> + ), + )} </tbody> </table> </Grid> diff --git a/src/components/popups/Portal.jsx b/src/components/popups/Portal.jsx index 82ba0ac05..7775d9ac2 100644 --- a/src/components/popups/Portal.jsx +++ b/src/components/popups/Portal.jsx @@ -7,13 +7,15 @@ import { useStore, useStatic } from '@hooks/useStore' import Utility from '@services/Utility' export default function PortalPopup({ portal, ts, Icons }) { - const { navigation } = useStore(state => state.settings) - const { navigation: { [navigation]: { url } } } = useStatic(state => state.config) + const { navigation } = useStore((state) => state.settings) + const { + navigation: { + [navigation]: { url }, + }, + } = useStatic((state) => state.config) const { t } = useTranslation() const [portalName, setPortalName] = useState(true) - const { - url: imageUrl, name, lat, lon, updated, imported, - } = portal + const { url: imageUrl, name, lat, lon, updated, imported } = portal const src = imageUrl ? imageUrl.replace('http://', 'https://') @@ -72,10 +74,14 @@ export default function PortalPopup({ portal, ts, Icons }) { </a> </Grid> <Grid item xs={12} style={{ textAlign: 'center' }}> - {extraMetaData.map(meta => ( + {extraMetaData.map((meta) => ( <Fragment key={meta.description}> - <Typography variant="subtitle1" style={{ textAlign: 'center' }}>{meta.description}</Typography> - <Typography variant="caption" style={{ textAlign: 'center' }}>{meta.data}</Typography> + <Typography variant="subtitle1" style={{ textAlign: 'center' }}> + {meta.description} + </Typography> + <Typography variant="caption" style={{ textAlign: 'center' }}> + {meta.data} + </Typography> </Fragment> ))} </Grid> diff --git a/src/components/popups/S2cell.jsx b/src/components/popups/S2cell.jsx index 1fc8420e7..8510753cd 100644 --- a/src/components/popups/S2cell.jsx +++ b/src/components/popups/S2cell.jsx @@ -20,9 +20,7 @@ export default function S2CellPopup({ cell, ts }) { return ( <> <Typography variant="h6" align="center"> - <Trans i18nKey="s2_cell_level"> - {{ level: 15 }} - </Trans> + <Trans i18nKey="s2_cell_level">{{ level: 15 }}</Trans> </Typography> <Typography variant="subtitle2" align="center"> {timer.str.replace('days', t('days')).replace('day', t('day'))} diff --git a/src/components/popups/Spawnpoint.jsx b/src/components/popups/Spawnpoint.jsx index 69050a0c9..5d56aecae 100644 --- a/src/components/popups/Spawnpoint.jsx +++ b/src/components/popups/Spawnpoint.jsx @@ -6,16 +6,16 @@ import Utility from '@services/Utility' export default function SpawnpointPopup({ spawnpoint, ts }) { const { t } = useTranslation() - const { - despawn_sec: despawn, lat, lon, updated, - } = spawnpoint + const { despawn_sec: despawn, lat, lon, updated } = spawnpoint const minute = despawn > 60 ? Math.round(despawn / 60) : despawn const minuteFixed = minute < 10 ? `0${minute}` : minute return ( <> - <Typography variant="h5" align="center">{t('spawnpoint')}</Typography> + <Typography variant="h5" align="center"> + {t('spawnpoint')} + </Typography> <Typography variant="h6" align="center"> {despawn ? `00:${minuteFixed}` : '?'} </Typography> @@ -30,7 +30,8 @@ export default function SpawnpointPopup({ spawnpoint, ts }) { {t('location')} </Typography> <Typography variant="subtitle2" align="center"> - {lat},<br />{lon} + {lat},<br /> + {lon} </Typography> </> ) diff --git a/src/components/popups/SubmissionCell.jsx b/src/components/popups/SubmissionCell.jsx index 1fcef926a..f12eaf41b 100644 --- a/src/components/popups/SubmissionCell.jsx +++ b/src/components/popups/SubmissionCell.jsx @@ -11,9 +11,11 @@ export default function SubmissionCellPopup({ cell }) { if (cell.count_gyms < 3) { untilNextGym = gymThreshold[cell.count_gyms] - cell.count } - if ((cell.count === 1 && cell.count_gyms < 1) - || (cell.count === 5 && cell.count_gyms < 2) - || (cell.count === 19 && cell.count_gyms < 3)) { + if ( + (cell.count === 1 && cell.count_gyms < 1) || + (cell.count === 5 && cell.count_gyms < 2) || + (cell.count === 19 && cell.count_gyms < 3) + ) { untilNextGym = t('next_submission') } @@ -24,9 +26,7 @@ export default function SubmissionCellPopup({ cell }) { return ( <> <Typography variant="h6" align="center"> - <Trans i18nKey="s2_cell_level"> - {{ level: cell.level }} - </Trans> + <Trans i18nKey="s2_cell_level">{{ level: cell.level }}</Trans> </Typography> <Typography variant="subtitle2" align="center"> {t('total_count')}: {cell.count} diff --git a/src/components/popups/Weather.jsx b/src/components/popups/Weather.jsx index 2a4a33e48..59ad7cb4f 100644 --- a/src/components/popups/Weather.jsx +++ b/src/components/popups/Weather.jsx @@ -7,11 +7,15 @@ import Utility from '@services/Utility' export default function WeatherPopup({ weather, ts, Icons }) { const { t } = useTranslation() - const { weather: weatherTypes } = useStatic(state => state.masterfile) + const { weather: weatherTypes } = useStatic((state) => state.masterfile) const { gameplay_condition, updated } = weather useEffect(() => { - Utility.analytics('Popup', `Type: ${t(`weather_${gameplay_condition}`)}`, 'Weather') + Utility.analytics( + 'Popup', + `Type: ${t(`weather_${gameplay_condition}`)}`, + 'Weather', + ) }, []) return ( @@ -38,11 +42,9 @@ export default function WeatherPopup({ weather, ts, Icons }) { {t('boosted_types')}: </Typography> </Grid> - {weatherTypes[gameplay_condition].types.map(type => ( + {weatherTypes[gameplay_condition].types.map((type) => ( <Grid item xs={4} key={type} style={{ textAlign: 'center' }}> - <Typography variant="caption"> - {t(`poke_type_${type}`)} - </Typography> + <Typography variant="caption">{t(`poke_type_${type}`)}</Typography> <img src={Icons.getTypes(type)} alt={type} diff --git a/src/components/popups/common/HeaderImage.jsx b/src/components/popups/common/HeaderImage.jsx index 898bac9ec..6701e74c9 100644 --- a/src/components/popups/common/HeaderImage.jsx +++ b/src/components/popups/common/HeaderImage.jsx @@ -2,11 +2,14 @@ import React from 'react' import { Avatar, Link } from '@material-ui/core' export default function HeaderImage({ - url, exEligible, arScanEligible, alt, Icons, large, + url, + exEligible, + arScanEligible, + alt, + Icons, + large, }) { - const src = url - ? url.replace('http://', 'https://') - : Icons.getPokestops(0) + const src = url ? url.replace('http://', 'https://') : Icons.getPokestops(0) const Image = ( <Avatar @@ -25,7 +28,9 @@ export default function HeaderImage({ <Link href={src} target="_blank" rel="noreferrer"> {Image} </Link> - ) : Image} + ) : ( + Image + )} {Boolean(arScanEligible) && ( <img className="ar-logo" diff --git a/src/components/popups/common/Navigation.jsx b/src/components/popups/common/Navigation.jsx index 346d65227..37ca6105f 100644 --- a/src/components/popups/common/Navigation.jsx +++ b/src/components/popups/common/Navigation.jsx @@ -5,8 +5,12 @@ import { Map } from '@material-ui/icons' import { useStore, useStatic } from '@hooks/useStore' export default function Navigation({ lat, lon }) { - const { navigation } = useStore(state => state.settings) - const { navigation: { [navigation]: { url } } } = useStatic(state => state.config) + const { navigation } = useStore((state) => state.settings) + const { + navigation: { + [navigation]: { url }, + }, + } = useStatic((state) => state.config) return ( <IconButton href={url.replace('{x}', lat).replace('{y}', lon)} diff --git a/src/components/popups/common/PowerUp.jsx b/src/components/popups/common/PowerUp.jsx index e149306db..679144d2d 100644 --- a/src/components/popups/common/PowerUp.jsx +++ b/src/components/popups/common/PowerUp.jsx @@ -7,7 +7,10 @@ import Utility from '@services/Utility' import TimeTile from './TimeTile' export default function PowerUp({ - power_up_level, power_up_points, power_up_end_timestamp, divider, + power_up_level, + power_up_points, + power_up_end_timestamp, + divider, }) { const { t } = useTranslation() if (!power_up_level) return null @@ -17,7 +20,7 @@ export default function PowerUp({ expireTime={power_up_end_timestamp} until size={5} - icon={( + icon={ <> <Typography align="center" variant="subtitle2"> {Utility.capitalize(t('level'))} {power_up_level} @@ -26,7 +29,7 @@ export default function PowerUp({ {power_up_points} {t('points')} </Typography> </> - )} + } /> {divider && <Divider light flexItem className="popup-divider" />} </Grid> diff --git a/src/components/popups/common/TimeTile.jsx b/src/components/popups/common/TimeTile.jsx index 42a79efe9..1ccc29603 100644 --- a/src/components/popups/common/TimeTile.jsx +++ b/src/components/popups/common/TimeTile.jsx @@ -10,15 +10,20 @@ export default function TimeTile({ expireTime, icon, until, size = 3 }) { <> {icon && ( <Grid item xs={size} style={{ textAlign: 'center' }}> - {typeof icon === 'string' - ? <img src={icon} className="quest-popup-img" alt={icon} /> : icon} + {typeof icon === 'string' ? ( + <img src={icon} className="quest-popup-img" alt={icon} /> + ) : ( + icon + )} </Grid> )} {endTime && ( <Grid item xs={icon ? 12 - size : 12} style={{ textAlign: 'center' }}> <Timer expireTime={expireTime} until={until} /> <Typography variant="caption"> - {new Date(endTime).toLocaleTimeString(localStorage.getItem('i18nextLng') || 'en')} + {new Date(endTime).toLocaleTimeString( + localStorage.getItem('i18nextLng') || 'en', + )} </Typography> </Grid> )} diff --git a/src/components/popups/common/Title.jsx b/src/components/popups/common/Title.jsx index 8f880ae28..b3f011419 100644 --- a/src/components/popups/common/Title.jsx +++ b/src/components/popups/common/Title.jsx @@ -4,12 +4,13 @@ import { Typography } from '@material-ui/core' import { useStore } from '@hooks/useStore' export default function Title({ mainName, backup }) { - const popups = useStore(state => state.popups) - const setPopups = useStore(state => state.setPopups) + const popups = useStore((state) => state.popups) + const setPopups = useStore((state) => state.setPopups) const handleClick = () => { setPopups({ - ...popups, names: !popups.names, + ...popups, + names: !popups.names, }) } return ( diff --git a/src/components/tiles/Device.jsx b/src/components/tiles/Device.jsx index f76a736c7..4c7a9912d 100644 --- a/src/components/tiles/Device.jsx +++ b/src/components/tiles/Device.jsx @@ -1,15 +1,11 @@ -import React, { - memo, useRef, useEffect, useState, -} from 'react' +import React, { memo, useRef, useEffect, useState } from 'react' import { Marker, Popup } from 'react-leaflet' import deviceMarker from '../markers/device' import PopupContent from '../popups/Device' import DevicePoly from '../popups/DevicePoly' -const DeviceTile = ({ - item, ts, Icons, userSettings, -}) => { +const DeviceTile = ({ item, ts, Icons, userSettings }) => { const [poly, setPoly] = useState(false) const markerRef = useRef(null) const isOnline = ts - item.last_seen < 900 @@ -31,22 +27,19 @@ const DeviceTile = ({ onOpen={() => setPoly(true)} onClose={() => setPoly(false)} > - <PopupContent - device={item} - isOnline={isOnline} - ts={ts} - /> + <PopupContent device={item} isOnline={isOnline} ts={ts} /> </Popup> - {(poly && !item.isMad) && <DevicePoly device={item} color={userSettings.devicePathColor} />} + {poly && !item.isMad && ( + <DevicePoly device={item} color={userSettings.devicePathColor} /> + )} </Marker> ) } -const areEqual = (prev, next) => ( - prev.item.type === next.item.type - && prev.item.last_lat === next.item.last_lat - && prev.item.last_lon === next.item.last_lon - && prev.item.last_seen === next.item.last_seen -) +const areEqual = (prev, next) => + prev.item.type === next.item.type && + prev.item.last_lat === next.item.last_lat && + prev.item.last_lon === next.item.last_lon && + prev.item.last_seen === next.item.last_seen export default memo(DeviceTile, areEqual) diff --git a/src/components/tiles/Gym.jsx b/src/components/tiles/Gym.jsx index 784799b61..1f40adf18 100644 --- a/src/components/tiles/Gym.jsx +++ b/src/components/tiles/Gym.jsx @@ -8,18 +8,30 @@ import gymMarker from '../markers/gym' import PopupContent from '../popups/Gym' import ToolTipWrapper from './Timer' -const getColor = team => { +const getColor = (team) => { switch (team) { - case 1: return '#0030C8' - case 2: return '#D83C22' - case 3: return '#F1F642' - default: return '#A9A9A9' + case 1: + return '#0030C8' + case 2: + return '#D83C22' + case 3: + return '#F1F642' + default: + return '#A9A9A9' } } const GymTile = ({ - item, ts, showTimer, filters, Icons, excludeList, userSettings, params, - showCircles, setParams, + item, + ts, + showTimer, + filters, + Icons, + excludeList, + userSettings, + params, + showCircles, + setParams, }) => { const markerRef = useRef({}) const [done, setDone] = useState(false) @@ -27,20 +39,32 @@ const GymTile = ({ const [badge, setBadge] = useState(item.badge || 0) const { - raid_battle_timestamp, raid_end_timestamp, raid_level, raid_pokemon_id, raid_pokemon_form, team_id, + raid_battle_timestamp, + raid_end_timestamp, + raid_level, + raid_pokemon_id, + raid_pokemon_form, + team_id, } = item const newTs = Date.now() / 1000 - const hasRaid = raid_end_timestamp >= newTs - && raid_level > 0 - && (raid_battle_timestamp >= newTs + const hasRaid = + raid_end_timestamp >= newTs && + raid_level > 0 && + (raid_battle_timestamp >= newTs ? !excludeList.includes(`e${raid_level}`) : !excludeList.includes(`${raid_pokemon_id}-${raid_pokemon_form}`)) - const hasHatched = raid_end_timestamp >= newTs && raid_battle_timestamp <= newTs + const hasHatched = + raid_end_timestamp >= newTs && raid_battle_timestamp <= newTs - const timerToDisplay = item.raid_pokemon_id || hasHatched ? raid_end_timestamp : raid_battle_timestamp + const timerToDisplay = + item.raid_pokemon_id || hasHatched + ? raid_end_timestamp + : raid_battle_timestamp - useMarkerTimer(timerToDisplay, item.id, markerRef, '', ts, () => setStateChange(!stateChange)) + useMarkerTimer(timerToDisplay, item.id, markerRef, '', ts, () => + setStateChange(!stateChange), + ) useForcePopup(item.id, markerRef, params, setParams, done) useEffect(() => { @@ -51,71 +75,86 @@ const GymTile = ({ } }, [filters.gymBadges, item.badge]) - return !excludeList.includes(`t${team_id}-0`) && ( - <Marker - ref={(m) => { - markerRef.current[item.id] = m - if (!done && item.id === params.id) { - setDone(true) - } - }} - position={[item.lat, item.lon]} - icon={gymMarker(item, hasHatched, hasRaid, filters, Icons, userSettings, badge)} - > - <Popup position={[item.lat, item.lon]}> - <PopupContent - gym={item} - hasRaid={hasRaid} - hasHatched={hasHatched} - ts={ts} - Icons={Icons} - badge={badge} - setBadge={setBadge} - /> - </Popup> - {((showTimer || userSettings.raidTimers) && hasRaid) && ( - <ToolTipWrapper - timers={[timerToDisplay]} - offset={[0, 5]} - /> - )} - {showCircles && ( - <Circle - center={[item.lat, item.lon]} - radius={70} - pathOptions={{ color: getColor(item.team_id), weight: 1 }} - /> - )} - </Marker> + return ( + !excludeList.includes(`t${team_id}-0`) && ( + <Marker + ref={(m) => { + markerRef.current[item.id] = m + if (!done && item.id === params.id) { + setDone(true) + } + }} + position={[item.lat, item.lon]} + icon={gymMarker( + item, + hasHatched, + hasRaid, + filters, + Icons, + userSettings, + badge, + )} + > + <Popup position={[item.lat, item.lon]}> + <PopupContent + gym={item} + hasRaid={hasRaid} + hasHatched={hasHatched} + ts={ts} + Icons={Icons} + badge={badge} + setBadge={setBadge} + /> + </Popup> + {(showTimer || userSettings.raidTimers) && hasRaid && ( + <ToolTipWrapper timers={[timerToDisplay]} offset={[0, 5]} /> + )} + {showCircles && ( + <Circle + center={[item.lat, item.lon]} + radius={70} + pathOptions={{ color: getColor(item.team_id), weight: 1 }} + /> + )} + </Marker> + ) ) } const areEqual = (prev, next) => { const raidLogic = () => { - if (prev.item.raid_battle_timestamp <= next.ts - && prev.item.raid_battle_timestamp > prev.ts) { + if ( + prev.item.raid_battle_timestamp <= next.ts && + prev.item.raid_battle_timestamp > prev.ts + ) { return false } - if (prev.item.raid_end_timestamp <= next.ts - && prev.item.raid_end_timestamp > prev.ts) { + if ( + prev.item.raid_end_timestamp <= next.ts && + prev.item.raid_end_timestamp > prev.ts + ) { return false } return true } - return prev.item.id === next.item.id - && prev.item.raid_pokemon_id === next.item.raid_pokemon_id - && prev.item.raid_level === next.item.raid_level - && prev.item.in_battle === next.item.in_battle - && prev.item.badge === next.item.badge - && prev.item.team_id === next.item.team_id - && prev.item.available_slots === next.item.available_slots - && raidLogic() - && prev.showTimer === next.showTimer - && prev.showCircles === next.showCircles - && !next.excludeList.includes(`${prev.item.raid_pokemon_id}-${prev.item.raid_pokemon_form}`) - && !next.excludeList.includes(`t${prev.item.team_id}-0`) - && !next.excludeList.includes(`e${prev.item.raid_level}`) + return ( + prev.item.id === next.item.id && + prev.item.raid_pokemon_id === next.item.raid_pokemon_id && + prev.item.raid_level === next.item.raid_level && + prev.item.in_battle === next.item.in_battle && + prev.item.badge === next.item.badge && + prev.item.team_id === next.item.team_id && + prev.item.available_slots === next.item.available_slots && + raidLogic() && + prev.showTimer === next.showTimer && + prev.showCircles === next.showCircles && + !next.excludeList.includes( + `${prev.item.raid_pokemon_id}-${prev.item.raid_pokemon_form}`, + ) && + !next.excludeList.includes(`t${prev.item.team_id}-0`) && + !next.excludeList.includes(`e${prev.item.raid_level}`) + ) } export default memo(GymTile, areEqual) diff --git a/src/components/tiles/Nest.jsx b/src/components/tiles/Nest.jsx index 93ceeeb24..ae0c3b443 100644 --- a/src/components/tiles/Nest.jsx +++ b/src/components/tiles/Nest.jsx @@ -7,12 +7,10 @@ import { useStatic } from '@hooks/useStore' import nestMarker from '../markers/nest' import PopupContent from '../popups/Nest' -const NestTile = ({ - item, filters, Icons, ts, params, setParams, -}) => { +const NestTile = ({ item, filters, Icons, ts, params, setParams }) => { const markerRef = useRef({}) const [done, setDone] = useState(false) - const { pokemon } = useStatic(state => state.masterfile) + const { pokemon } = useStatic((state) => state.masterfile) const iconUrl = Icons.getPokemon(item.pokemon_id, item.pokemon_form) const parsedJson = JSON.parse(item.polygon_path) @@ -31,7 +29,14 @@ const NestTile = ({ } }} position={[item.lat, item.lon]} - icon={nestMarker(iconUrl, item, pokemon[item.pokemon_id], filters, Icons, recent)} + icon={nestMarker( + iconUrl, + item, + pokemon[item.pokemon_id], + filters, + Icons, + recent, + )} > <Popup position={[item.lat, item.lon]}> <PopupContent @@ -43,18 +48,19 @@ const NestTile = ({ </Popup> </Marker> )} - {parsedJson && filters.polygons && parsedJson.map(polygon => ( - <Polygon positions={polygon} key={polygon} /> - ))} + {parsedJson && + filters.polygons && + parsedJson.map((polygon) => ( + <Polygon positions={polygon} key={polygon} /> + ))} </> ) } -const areEqual = (prev, next) => ( - prev.item.id === next.item.id - && prev.item.updated === next.item.updated - && prev.filters.pokemon === next.filters.pokemon - && prev.filters.polygons === next.filters.polygons -) +const areEqual = (prev, next) => + prev.item.id === next.item.id && + prev.item.updated === next.item.updated && + prev.filters.pokemon === next.filters.pokemon && + prev.filters.polygons === next.filters.polygons export default memo(NestTile, areEqual) diff --git a/src/components/tiles/Pokemon.jsx b/src/components/tiles/Pokemon.jsx index b38035383..024680c21 100644 --- a/src/components/tiles/Pokemon.jsx +++ b/src/components/tiles/Pokemon.jsx @@ -25,29 +25,36 @@ const cyrb53 = (str, seed = 0) => { h1 = Math.imul(h1 ^ ch, 2654435761) h2 = Math.imul(h2 ^ ch, 1597334677) } - h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909) - h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909) + h1 = + Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ + Math.imul(h2 ^ (h2 >>> 13), 3266489909) + h2 = + Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ + Math.imul(h1 ^ (h1 >>> 13), 3266489909) return [h1, h2] } const getOffset = (coords, type, seed) => { const offOffset = type === 'nearby_cell' ? 0.0002 : 0.00015 const rand = cyrb53(seed) - return [0, 1].map(i => { + return [0, 1].map((i) => { let offset = rand[i] * (0.0002 / 4294967296) - 0.0001 offset += offset >= 0 ? -offOffset : offOffset - return (coords[i] + offset) + return coords[i] + offset }) } const getGlowStatus = (item, userSettings, staticUserSettings) => { let glowCount = 0 let glowValue - Object.entries(staticUserSettings.glow.sub).forEach(rule => { + Object.entries(staticUserSettings.glow.sub).forEach((rule) => { const [ruleKey, ruleValue] = rule const statKey = ruleValue.perm === 'iv' ? 'iv' : 'bestPvp' if (ruleValue.op) { - if (operator[ruleValue.op](item[statKey], ruleValue.num) && item[statKey] !== null) { + if ( + operator[ruleValue.op](item[statKey], ruleValue.num) && + item[statKey] !== null + ) { glowCount += 1 glowValue = userSettings[ruleKey] } @@ -60,17 +67,42 @@ const getGlowStatus = (item, userSettings, staticUserSettings) => { } const PokemonTile = ({ - item, showTimer, filters, Icons, excludeList, ts, map, isNight, - userSettings, staticUserSettings, params, showCircles, setParams, + item, + showTimer, + filters, + Icons, + excludeList, + ts, + map, + isNight, + userSettings, + staticUserSettings, + params, + showCircles, + setParams, }) => { const markerRef = useRef({ [item.id]: null }) const [done, setDone] = useState(false) useMarkerTimer(item.expire_timestamp, item.id, markerRef, map, ts) - const url = Icons.getPokemon(item.pokemon_id, item.form, 0, item.gender, item.costume) - const size = Icons.getSize('pokemon', filters.filter[`${item.pokemon_id}-${item.form}`]) - const glowStatus = userSettings.glow ? getGlowStatus(item, userSettings, staticUserSettings) : undefined - const ivCircle = userSettings.ivCircles && item.iv !== null && item.iv >= userSettings.minIvCircle + const url = Icons.getPokemon( + item.pokemon_id, + item.form, + 0, + item.gender, + item.costume, + ) + const size = Icons.getSize( + 'pokemon', + filters.filter[`${item.pokemon_id}-${item.form}`], + ) + const glowStatus = userSettings.glow + ? getGlowStatus(item, userSettings, staticUserSettings) + : undefined + const ivCircle = + userSettings.ivCircles && + item.iv !== null && + item.iv >= userSettings.minIvCircle const pvpCheck = item.bestPvp !== null && item.bestPvp < 4 const weatherCheck = item.weather && userSettings.weatherIndicator @@ -80,53 +112,63 @@ const PokemonTile = ({ useForcePopup(item.id, markerRef, params, setParams, done) - return (!excludeList.includes(`${item.pokemon_id}-${item.form}`) && item.expire_timestamp > ts) && ( - <Marker - ref={(m) => { - markerRef.current[item.id] = m - if (!done && item.id === params.id) { - setDone(true) + return ( + !excludeList.includes(`${item.pokemon_id}-${item.form}`) && + item.expire_timestamp > ts && ( + <Marker + ref={(m) => { + markerRef.current[item.id] = m + if (!done && item.id === params.id) { + setDone(true) + } + }} + zIndexOffset={item.iv * 100} + position={finalLocation} + icon={ + pvpCheck || glowStatus || ivCircle || weatherCheck + ? fancyMarker( + url, + size, + item, + glowStatus, + ivCircle, + Icons, + weatherCheck, + isNight, + ) + : basicMarker(url, size) } - }} - zIndexOffset={item.iv * 100} - position={finalLocation} - icon={(pvpCheck || glowStatus || ivCircle || weatherCheck) - ? fancyMarker(url, size, item, glowStatus, ivCircle, Icons, weatherCheck, isNight) - : basicMarker(url, size)} - > - <Popup position={finalLocation}> - <PopupContent - pokemon={item} - iconUrl={url} - userSettings={userSettings} - Icons={Icons} - isNight={isNight} - /> - </Popup> - {(showTimer || userSettings.pokemonTimers) && ( - <ToolTipWrapper - timers={[item.expire_timestamp]} - offset={[0, 18]} - /> - )} - {showCircles && ( - <Circle - center={finalLocation} - radius={35} - pathOptions={{ color: '#BA42F6', weight: 1 }} - /> - )} - </Marker> + > + <Popup position={finalLocation}> + <PopupContent + pokemon={item} + iconUrl={url} + userSettings={userSettings} + Icons={Icons} + isNight={isNight} + /> + </Popup> + {(showTimer || userSettings.pokemonTimers) && ( + <ToolTipWrapper timers={[item.expire_timestamp]} offset={[0, 18]} /> + )} + {showCircles && ( + <Circle + center={finalLocation} + radius={35} + pathOptions={{ color: '#BA42F6', weight: 1 }} + /> + )} + </Marker> + ) ) } -const areEqual = (prev, next) => ( - prev.item.id === next.item.id - && prev.item.updated === next.item.updated - && prev.showTimer === next.showTimer - && !next.excludeList.includes(`${prev.item.pokemon_id}-${prev.item.form}`) - && prev.userIcons.pokemon === next.userIcons.pokemon - && prev.showCircles === next.showCircles -) +const areEqual = (prev, next) => + prev.item.id === next.item.id && + prev.item.updated === next.item.updated && + prev.showTimer === next.showTimer && + !next.excludeList.includes(`${prev.item.pokemon_id}-${prev.item.form}`) && + prev.userIcons.pokemon === next.userIcons.pokemon && + prev.showCircles === next.showCircles export default memo(PokemonTile, areEqual) diff --git a/src/components/tiles/Pokestop.jsx b/src/components/tiles/Pokestop.jsx index bf262e6a0..0130ccf20 100644 --- a/src/components/tiles/Pokestop.jsx +++ b/src/components/tiles/Pokestop.jsx @@ -9,8 +9,18 @@ import stopMarker from '../markers/pokestop' import ToolTipWrapper from './Timer' const PokestopTile = ({ - item, ts, showTimer, filters, Icons, perms, excludeList, userSettings, - params, showCircles, config, setParams, + item, + ts, + showTimer, + filters, + Icons, + perms, + excludeList, + userSettings, + params, + showCircles, + config, + setParams, }) => { const markerRef = useRef({}) const [done, setDone] = useState(false) @@ -19,28 +29,44 @@ const PokestopTile = ({ const hasLure = item.lure_expire_timestamp > newTs - const hasInvasion = item.invasions && item.invasions.some(invasion => !excludeList.includes(`i${invasion.grunt_type}`) && invasion.incident_expire_timestamp > newTs) + const hasInvasion = + item.invasions && + item.invasions.some( + (invasion) => + !excludeList.includes(`i${invasion.grunt_type}`) && + invasion.incident_expire_timestamp > newTs, + ) - const hasQuest = item.quests && item.quests.some(quest => !excludeList.includes(quest.key)) + const hasQuest = + item.quests && item.quests.some((quest) => !excludeList.includes(quest.key)) const timers = [] if ((showTimer || userSettings.invasionTimers) && hasInvasion) { - item.invasions.forEach(invasion => ( - timers.push(invasion.incident_expire_timestamp) - )) + item.invasions.forEach((invasion) => + timers.push(invasion.incident_expire_timestamp), + ) } if ((showTimer || userSettings.lureTimers) && hasLure) { timers.push(item.lure_expire_timestamp) } - useMarkerTimer(timers.length ? Math.min(...timers) : null, item.id, markerRef, '', ts, () => setStateChange(!stateChange)) + useMarkerTimer( + timers.length ? Math.min(...timers) : null, + item.id, + markerRef, + '', + ts, + () => setStateChange(!stateChange), + ) useForcePopup(item.id, markerRef, params, setParams, done) - return Boolean(((hasQuest && perms.quests) - || (hasLure && perms.lures) - || (hasInvasion && perms.invasions)) - || ((filters.allPokestops || item.ar_scan_eligible) && perms.allPokestops)) - && ( + return ( + Boolean( + (hasQuest && perms.quests) || + (hasLure && perms.lures) || + (hasInvasion && perms.invasions) || + ((filters.allPokestops || item.ar_scan_eligible) && perms.allPokestops), + ) && ( <Marker ref={(m) => { markerRef.current[item.id] = m @@ -49,7 +75,15 @@ const PokestopTile = ({ } }} position={[item.lat, item.lon]} - icon={stopMarker(item, hasQuest, hasLure, hasInvasion, filters, Icons, userSettings)} + icon={stopMarker( + item, + hasQuest, + hasLure, + hasInvasion, + filters, + Icons, + userSettings, + )} > <Popup position={[item.lat, item.lon]}> <PopupContent @@ -75,25 +109,29 @@ const PokestopTile = ({ )} </Marker> ) + ) } -const areEqual = (prev, next) => ( - prev.item.id === next.item.id - && prev.item.lure_expire_timestamp === next.item.lure_expire_timestamp - && prev.item.quests?.length === next.item.quests?.length - && prev.item.invasions?.length === next.item.invasions?.length - && prev.item.updated === next.item.updated - && prev.showTimer === next.showTimer - && (prev.item.quests && next.item.quests - ? prev.item.quests.every((q, i) => q.with_ar === next.item.quests[i]?.with_ar) - : true) - && (prev.item.quests - ? !prev.item.quests.some(quest => next.excludeList.includes(quest.key)) - : true) - && (prev.item.invasions - ? !prev.item.invasions.some(invasion => next.excludeList.includes(invasion.grunt_type)) - : true) - && prev.showCircles === next.showCircles -) +const areEqual = (prev, next) => + prev.item.id === next.item.id && + prev.item.lure_expire_timestamp === next.item.lure_expire_timestamp && + prev.item.quests?.length === next.item.quests?.length && + prev.item.invasions?.length === next.item.invasions?.length && + prev.item.updated === next.item.updated && + prev.showTimer === next.showTimer && + (prev.item.quests && next.item.quests + ? prev.item.quests.every( + (q, i) => q.with_ar === next.item.quests[i]?.with_ar, + ) + : true) && + (prev.item.quests + ? !prev.item.quests.some((quest) => next.excludeList.includes(quest.key)) + : true) && + (prev.item.invasions + ? !prev.item.invasions.some((invasion) => + next.excludeList.includes(invasion.grunt_type), + ) + : true) && + prev.showCircles === next.showCircles export default memo(PokestopTile, areEqual) diff --git a/src/components/tiles/Portal.jsx b/src/components/tiles/Portal.jsx index 7154ae362..f1b93637b 100644 --- a/src/components/tiles/Portal.jsx +++ b/src/components/tiles/Portal.jsx @@ -6,9 +6,7 @@ import useForcePopup from '@hooks/useForcePopup' import PopupContent from '../popups/Portal' import marker from '../markers/portal' -const PortalTile = ({ - item, userSettings, ts, params, Icons, setParams, -}) => { +const PortalTile = ({ item, userSettings, ts, params, Icons, setParams }) => { const [done, setDone] = useState(false) const markerRef = useRef({}) @@ -34,11 +32,10 @@ const PortalTile = ({ ) } -const areEqual = (prev, next) => ( - prev.item.id === next.item.id - && prev.userSettings.clustering === next.userSettings.clustering - && prev.userSettings.oldPortals === next.userSettings.oldPortals - && prev.userSettings.newPortals === next.userSettings.newPortals -) +const areEqual = (prev, next) => + prev.item.id === next.item.id && + prev.userSettings.clustering === next.userSettings.clustering && + prev.userSettings.oldPortals === next.userSettings.oldPortals && + prev.userSettings.newPortals === next.userSettings.newPortals export default memo(PortalTile, areEqual) diff --git a/src/components/tiles/ScanArea.jsx b/src/components/tiles/ScanArea.jsx index bd709fa23..721974595 100644 --- a/src/components/tiles/ScanArea.jsx +++ b/src/components/tiles/ScanArea.jsx @@ -3,11 +3,14 @@ import { GeoJSON } from 'react-leaflet' import Utility from '@services/Utility' export default function ScanAreaTile({ - item, webhookMode, selectedAreas, setSelectedAreas, + item, + webhookMode, + selectedAreas, + setSelectedAreas, }) { const handleClick = (name) => { if (selectedAreas.includes(name)) { - setSelectedAreas(selectedAreas.filter(h => h !== name)) + setSelectedAreas(selectedAreas.filter((h) => h !== name)) } else { setSelectedAreas([...selectedAreas, name]) } @@ -21,13 +24,21 @@ export default function ScanAreaTile({ weight: feature.properties['stroke-width'] || 3, opacity: feature.properties['stroke-opacity'] || 1, fillColor: feature.properties.fill || '#3388ff', - fillOpacity: selectedAreas && selectedAreas.includes(name) && webhookMode === 'areas' ? 0.8 : 0.2, + fillOpacity: + selectedAreas && + selectedAreas.includes(name) && + webhookMode === 'areas' + ? 0.8 + : 0.2, }) if (webhookMode) { layer.on('click', () => handleClick(name)) - layer.bindTooltip(popupContent, { - permanent: true, direction: 'top', - }).openTooltip() + layer + .bindTooltip(popupContent, { + permanent: true, + direction: 'top', + }) + .openTooltip() } else { layer.bindPopup(popupContent) } @@ -35,10 +46,6 @@ export default function ScanAreaTile({ } return ( - <GeoJSON - key={selectedAreas} - data={item} - onEachFeature={onEachFeature} - /> + <GeoJSON key={selectedAreas} data={item} onEachFeature={onEachFeature} /> ) } diff --git a/src/components/tiles/ScanCell.jsx b/src/components/tiles/ScanCell.jsx index e54ea42b0..c21c1e624 100644 --- a/src/components/tiles/ScanCell.jsx +++ b/src/components/tiles/ScanCell.jsx @@ -4,23 +4,18 @@ import { Polygon, Popup } from 'react-leaflet' import PopupContent from '../popups/S2cell' import marker from '../markers/s2cell' -const S2cellTile = ({ - item, config, zoom, ts, -}) => (zoom >= config.scanCellsZoom && ( - <Polygon - positions={item.polygon} - pathOptions={marker(item.updated)} - > - <Popup position={[item.center_lat, item.center_lon]}> - <PopupContent cell={item} ts={ts} /> - </Popup> - </Polygon> -)) +const S2cellTile = ({ item, config, zoom, ts }) => + zoom >= config.scanCellsZoom && ( + <Polygon positions={item.polygon} pathOptions={marker(item.updated)}> + <Popup position={[item.center_lat, item.center_lon]}> + <PopupContent cell={item} ts={ts} /> + </Popup> + </Polygon> + ) -const areEqual = (prev, next) => ( - prev.item.id === next.item.id - && prev.item.updated === next.item.updated - && prev.zoom === next.zoom -) +const areEqual = (prev, next) => + prev.item.id === next.item.id && + prev.item.updated === next.item.updated && + prev.zoom === next.zoom export default memo(S2cellTile, areEqual) diff --git a/src/components/tiles/Spawnpoint.jsx b/src/components/tiles/Spawnpoint.jsx index c01dbb4ff..fcfc30b43 100644 --- a/src/components/tiles/Spawnpoint.jsx +++ b/src/components/tiles/Spawnpoint.jsx @@ -15,7 +15,11 @@ const SpawnpointTile = ({ item, Icons, ts }) => { return modifiers.useImage ? ( <Marker position={[item.lat, item.lon]} - icon={spawnpointMarker(Icons.getSpawnpoints(item.despawn_sec), size * 6, modifiers)} + icon={spawnpointMarker( + Icons.getSpawnpoints(item.despawn_sec), + size * 6, + modifiers, + )} > {popup} </Marker> @@ -29,9 +33,7 @@ const SpawnpointTile = ({ item, Icons, ts }) => { </Circle> ) } -const areEqual = (prev, next) => ( - prev.item.id === next.item.id - && prev.item.updated === next.item.updated -) +const areEqual = (prev, next) => + prev.item.id === next.item.id && prev.item.updated === next.item.updated export default memo(SpawnpointTile, areEqual) diff --git a/src/components/tiles/Timer.jsx b/src/components/tiles/Timer.jsx index d912f6a47..138363e7c 100644 --- a/src/components/tiles/Timer.jsx +++ b/src/components/tiles/Timer.jsx @@ -5,7 +5,9 @@ import Utility from '@services/Utility' const Timer = ({ timestamp }) => { const { t } = useTranslation() - const [timer, setTimer] = useState(Utility.getTimeUntil(new Date(timestamp * 1000), true)) + const [timer, setTimer] = useState( + Utility.getTimeUntil(new Date(timestamp * 1000), true), + ) useEffect(() => { const timer2 = setTimeout(() => { @@ -15,9 +17,7 @@ const Timer = ({ timestamp }) => { }) return ( - <div> - {timer.str.replace('days', t('days')).replace('day', t('day'))} - </div> + <div>{timer.str.replace('days', t('days')).replace('day', t('day'))}</div> ) } @@ -25,8 +25,12 @@ export default function TooltipWrapper({ timers, offset }) { return ( <Tooltip direction="bottom" permanent offset={offset}> {[...new Set(timers)].map((timer, i) => ( - // eslint-disable-next-line react/no-array-index-key - <Timer key={timer + i * 123} timestamp={timer} multi={timers.length > 1} /> + <Timer + // eslint-disable-next-line react/no-array-index-key + key={timer + i * 123} + timestamp={timer} + multi={timers.length > 1} + /> ))} </Tooltip> ) diff --git a/src/components/tiles/Weather.jsx b/src/components/tiles/Weather.jsx index 21d9671f3..b7657d182 100644 --- a/src/components/tiles/Weather.jsx +++ b/src/components/tiles/Weather.jsx @@ -18,7 +18,13 @@ const WeatherTile = ({ item, ts, Icons, isNight, tileStyle, userSettings }) => { <Polyline key={item.id} positions={item.polygon} - pathOptions={{ color: tileStyle === 'dark' ? userSettings.darkMapBorder : userSettings.lightMapBorder, opacity: 0.25 }} + pathOptions={{ + color: + tileStyle === 'dark' + ? userSettings.darkMapBorder + : userSettings.lightMapBorder, + opacity: 0.25, + }} > <Marker icon={weatherMarker(item, Icons, isNight, userSettings)} @@ -38,10 +44,9 @@ const WeatherTile = ({ item, ts, Icons, isNight, tileStyle, userSettings }) => { ) } -const areEqual = (prev, next) => ( - prev.item.gameplay_condition === next.item.gameplay_condition - && prev.item.updated === next.item.updated - && prev.tileStyle === next.tileStyle -) +const areEqual = (prev, next) => + prev.item.gameplay_condition === next.item.gameplay_condition && + prev.item.updated === next.item.updated && + prev.tileStyle === next.tileStyle export default memo(WeatherTile, areEqual) diff --git a/src/components/tiles/submissionCells/Placement.jsx b/src/components/tiles/submissionCells/Placement.jsx index 193757745..b3db9fafc 100644 --- a/src/components/tiles/submissionCells/Placement.jsx +++ b/src/components/tiles/submissionCells/Placement.jsx @@ -11,10 +11,9 @@ const PlacementTile = ({ cell, tileStyle, userSettings }) => ( /> ) -const areEqual = (prev, next) => ( - prev.cell.id === next.cell.id - && prev.zoom === next.zoom - && prev.tileStyle === next.tileStyle -) +const areEqual = (prev, next) => + prev.cell.id === next.cell.id && + prev.zoom === next.zoom && + prev.tileStyle === next.tileStyle export default memo(PlacementTile, areEqual) diff --git a/src/components/tiles/submissionCells/Ring.jsx b/src/components/tiles/submissionCells/Ring.jsx index b19f3a9d9..6fc5937ff 100644 --- a/src/components/tiles/submissionCells/Ring.jsx +++ b/src/components/tiles/submissionCells/Ring.jsx @@ -6,13 +6,14 @@ const RingTile = ({ ring, userSettings }) => ( center={[ring.lat, ring.lon]} radius={20} interactive={false} - pathOptions={{ fillColor: userSettings.poiColor, color: userSettings.poiColor }} + pathOptions={{ + fillColor: userSettings.poiColor, + color: userSettings.poiColor, + }} /> ) -const areEqual = (prev, next) => ( - prev.ring.id === next.ring.id - && prev.zoom === next.zoom -) +const areEqual = (prev, next) => + prev.ring.id === next.ring.id && prev.zoom === next.zoom export default memo(RingTile, areEqual) diff --git a/src/components/tiles/submissionCells/SubmissionCell.jsx b/src/components/tiles/submissionCells/SubmissionCell.jsx index 8fa31f1cc..6a50c39b9 100644 --- a/src/components/tiles/submissionCells/SubmissionCell.jsx +++ b/src/components/tiles/submissionCells/SubmissionCell.jsx @@ -4,39 +4,48 @@ import PlacementTile from './Placement' import RingTile from './Ring' export default function SubmissionCellTile({ - item, tileStyle, config, zoom, userSettings, + item, + tileStyle, + config, + zoom, + userSettings, }) { const zoomLimit = zoom >= config.submissionZoom - return zoom >= (config.submissionZoom - 1) && ( - <> - {(item?.placementCells?.rings && zoomLimit) - && item.placementCells.rings.map(ring => ( - <RingTile - key={ring.id} - ring={ring} - zoom={zoomLimit} - userSettings={userSettings} - /> - ))} - {(item?.placementCells?.cells && zoomLimit) - && item.placementCells.cells.map(cell => ( - <PlacementTile - key={`pc${cell.id}-${cell.polygon[0]}-${cell.polygon[1]}-${cell.polygon[2]}-${cell.polygon[3]}`} - cell={cell} - tileStyle={tileStyle} - zoom={zoomLimit} - userSettings={userSettings} - /> - ))} - {item?.typeCells && item.typeCells.map(cell => ( - <TypeTile - key={`tc${cell.id}-${cell.polygon[0]}-${cell.polygon[1]}-${cell.polygon[2]}-${cell.polygon[3]}`} - cell={cell} - tileStyle={tileStyle} - zoom={zoom >= (config.submissionZoom - 1)} - userSettings={userSettings} - /> - ))} - </> + return ( + zoom >= config.submissionZoom - 1 && ( + <> + {item?.placementCells?.rings && + zoomLimit && + item.placementCells.rings.map((ring) => ( + <RingTile + key={ring.id} + ring={ring} + zoom={zoomLimit} + userSettings={userSettings} + /> + ))} + {item?.placementCells?.cells && + zoomLimit && + item.placementCells.cells.map((cell) => ( + <PlacementTile + key={`pc${cell.id}-${cell.polygon[0]}-${cell.polygon[1]}-${cell.polygon[2]}-${cell.polygon[3]}`} + cell={cell} + tileStyle={tileStyle} + zoom={zoomLimit} + userSettings={userSettings} + /> + ))} + {item?.typeCells && + item.typeCells.map((cell) => ( + <TypeTile + key={`tc${cell.id}-${cell.polygon[0]}-${cell.polygon[1]}-${cell.polygon[2]}-${cell.polygon[3]}`} + cell={cell} + tileStyle={tileStyle} + zoom={zoom >= config.submissionZoom - 1} + userSettings={userSettings} + /> + ))} + </> + ) ) } diff --git a/src/components/tiles/submissionCells/Type.jsx b/src/components/tiles/submissionCells/Type.jsx index 3a2ed2012..cde481eb7 100644 --- a/src/components/tiles/submissionCells/Type.jsx +++ b/src/components/tiles/submissionCells/Type.jsx @@ -9,26 +9,19 @@ const TypeTile = ({ cell, tileStyle, userSettings }) => ( positions={cell.polygon} pathOptions={typeStyle(cell, tileStyle, userSettings)} > - <Popup - position={[cell.lat, cell.lon]} - > + <Popup position={[cell.lat, cell.lon]}> <PopupContent cell={cell} /> </Popup> - <Tooltip - position={[cell.lat, cell.lon]} - direction="center" - permanent - > + <Tooltip position={[cell.lat, cell.lon]} direction="center" permanent> {cell.count} </Tooltip> </Polygon> ) -const areEqual = (prev, next) => ( - prev.cell.id === next.cell.id - && prev.cell.count === next.cell.count - && prev.zoom === next.zoom - && prev.tileStyle === next.tileStyle -) +const areEqual = (prev, next) => + prev.cell.id === next.cell.id && + prev.cell.count === next.cell.count && + prev.zoom === next.zoom && + prev.tileStyle === next.tileStyle export default memo(TypeTile, areEqual) diff --git a/src/hooks/useConfig.js b/src/hooks/useConfig.js index f99477524..ef0fd4a10 100644 --- a/src/hooks/useConfig.js +++ b/src/hooks/useConfig.js @@ -5,32 +5,39 @@ import Utility from '@services/Utility' import { useStore, useStatic } from '@hooks/useStore' export default function useConfig(serverSettings, params) { - Utility.analytics('User', serverSettings.user ? `${serverSettings.user.username} (${serverSettings.user.id})` : 'Not Logged In', 'Permissions', true) + Utility.analytics( + 'User', + serverSettings.user + ? `${serverSettings.user.username} (${serverSettings.user.id})` + : 'Not Logged In', + 'Permissions', + true, + ) document.title = serverSettings.config?.map?.headerTitle - const setUserSettings = useStore(state => state.setUserSettings) - const setSettings = useStore(state => state.setSettings) - const setFilters = useStore(state => state.setFilters) - const setLocation = useStore(state => state.setLocation) - const setZoom = useStore(state => state.setZoom) - const setMenus = useStore(state => state.setMenus) - const setIcons = useStore(state => state.setIcons) - const setSelectedWebhook = useStore(state => state.setSelectedWebhook) - const setTutorial = useStore(state => state.setTutorial) - - const setAuth = useStatic(state => state.setAuth) - const setStaticUserSettings = useStatic(state => state.setUserSettings) - const setStaticSettings = useStatic(state => state.setSettings) - const setStaticMenus = useStatic(state => state.setMenus) - const setAvailable = useStatic(state => state.setAvailable) - const setConfig = useStatic(state => state.setConfig) - const setStaticIcons = useStatic(state => state.setIcons) - const setMasterfile = useStatic(state => state.setMasterfile) - const setUi = useStatic(state => state.setUi) - const setStaticFilters = useStatic(state => state.setFilters) - const setWebhookData = useStatic(state => state.setWebhookData) - const setIsNight = useStatic(state => state.setIsNight) + const setUserSettings = useStore((state) => state.setUserSettings) + const setSettings = useStore((state) => state.setSettings) + const setFilters = useStore((state) => state.setFilters) + const setLocation = useStore((state) => state.setLocation) + const setZoom = useStore((state) => state.setZoom) + const setMenus = useStore((state) => state.setMenus) + const setIcons = useStore((state) => state.setIcons) + const setSelectedWebhook = useStore((state) => state.setSelectedWebhook) + const setTutorial = useStore((state) => state.setTutorial) + + const setAuth = useStatic((state) => state.setAuth) + const setStaticUserSettings = useStatic((state) => state.setUserSettings) + const setStaticSettings = useStatic((state) => state.setSettings) + const setStaticMenus = useStatic((state) => state.setMenus) + const setAvailable = useStatic((state) => state.setAvailable) + const setConfig = useStatic((state) => state.setConfig) + const setStaticIcons = useStatic((state) => state.setIcons) + const setMasterfile = useStatic((state) => state.setMasterfile) + const setUi = useStatic((state) => state.setUi) + const setStaticFilters = useStatic((state) => state.setFilters) + const setWebhookData = useStatic((state) => state.setWebhookData) + const setIsNight = useStatic((state) => state.setIsNight) const localState = JSON.parse(localStorage.getItem('local-state')) @@ -62,14 +69,17 @@ export default function useConfig(serverSettings, params) { }) Sentry.setUser({ username: serverSettings.user.username, - id: serverSettings.user.discordId - || serverSettings.user.telegramId - || serverSettings.user.id, + id: + serverSettings.user.discordId || + serverSettings.user.telegramId || + serverSettings.user.id, }) - setTutorial(serverSettings.user.tutorial === undefined - ? Boolean(localState?.state?.tutorial) - : !serverSettings.user.tutorial) + setTutorial( + serverSettings.user.tutorial === undefined + ? Boolean(localState?.state?.tutorial) + : !serverSettings.user.tutorial, + ) setUi(serverSettings.ui) setMasterfile(serverSettings.masterfile) @@ -90,19 +100,26 @@ export default function useConfig(serverSettings, params) { if (localState?.state?.settings) { const cached = localState.state.settings.localeSelection const i18cached = localStorage.getItem('i18nextLng') - localState.state.settings.localeSelection = cached !== i18cached ? i18cached : cached + localState.state.settings.localeSelection = + cached !== i18cached ? i18cached : cached const validNav = Object.keys(serverSettings.config.navigation) - localState.state.settings.navigation = validNav.includes(localState.state.settings.navigation) + localState.state.settings.navigation = validNav.includes( + localState.state.settings.navigation, + ) ? localState.state.settings.navigation : serverSettings.config.navigation[validNav[0]]?.name const validTs = Object.keys(serverSettings.config.tileServers) - localState.state.settings.tileServers = validTs.includes(localState.state.settings.tileServers) + localState.state.settings.tileServers = validTs.includes( + localState.state.settings.tileServers, + ) ? localState.state.settings.tileServers : serverSettings.config.tileServers[validTs[0]]?.name } else { - serverSettings.settings.localeSelection = localStorage.getItem('i18nextLng') || serverSettings.settings.localeSelection + serverSettings.settings.localeSelection = + localStorage.getItem('i18nextLng') || + serverSettings.settings.localeSelection } setSettings(updateObjState(serverSettings.settings, 'settings')) @@ -119,17 +136,29 @@ export default function useConfig(serverSettings, params) { setConfig(serverSettings.config) setWebhookData(serverSettings.webhooks) - if (localState?.state && serverSettings?.webhooks?.[localState.state?.selectedWebhook]) { + if ( + localState?.state && + serverSettings?.webhooks?.[localState.state?.selectedWebhook] + ) { setSelectedWebhook(localState.state.selectedWebhook) } else if (serverSettings?.webhooks) { setSelectedWebhook(Object.keys(serverSettings.webhooks)[0]) } - const location = params.lat && params.lon - ? [params.lat, params.lon] - : updatePositionState([serverSettings.config.map.startLat, serverSettings.config.map.startLon], 'location') - - const zoom = params.zoom || updatePositionState(serverSettings.config.map.startZoom, 'zoom') + const location = + params.lat && params.lon + ? [params.lat, params.lon] + : updatePositionState( + [ + serverSettings.config.map.startLat, + serverSettings.config.map.startLon, + ], + 'location', + ) + + const zoom = + params.zoom || + updatePositionState(serverSettings.config.map.startZoom, 'zoom') setZoom(zoom) setLocation(location) diff --git a/src/hooks/useFilter.js b/src/hooks/useFilter.js index 3b59feee5..a2a480ad5 100644 --- a/src/hooks/useFilter.js +++ b/src/hooks/useFilter.js @@ -3,21 +3,31 @@ import { useTranslation } from 'react-i18next' import { useStatic } from '@hooks/useStore' -const filteringPokemon = ['pokemon', 'quest_reward_4', 'quest_reward_9', 'quest_reward_12'] +const filteringPokemon = [ + 'pokemon', + 'quest_reward_4', + 'quest_reward_9', + 'quest_reward_12', +] -export default function useFilter(tempFilters, menus, search, category, webhookCategory, reqCategories) { +export default function useFilter( + tempFilters, + menus, + search, + category, + webhookCategory, + reqCategories, +) { const { t } = useTranslation() - const available = useStatic(useCallback(s => s.available, [])) - const Icons = useStatic(useCallback(s => s.Icons, [])) - const { perms } = useStatic(useCallback(s => s.auth, [])) - const { pokemon } = useStatic(useCallback(s => s.masterfile, [])) - const setExcludeList = useStatic(useCallback(s => s.setExcludeList, [])) - const menuFilters = useStatic(useCallback(s => s.menuFilters, [])) + const available = useStatic(useCallback((s) => s.available, [])) + const Icons = useStatic(useCallback((s) => s.Icons, [])) + const { perms } = useStatic(useCallback((s) => s.auth, [])) + const { pokemon } = useStatic(useCallback((s) => s.masterfile, [])) + const setExcludeList = useStatic(useCallback((s) => s.setExcludeList, [])) + const menuFilters = useStatic(useCallback((s) => s.menuFilters, [])) const { - filters: { - generations, types, rarity, forms, others, categories, - }, + filters: { generations, types, rarity, forms, others, categories }, } = menus[category] const tempAdvFilter = {} const filteredArr = [] @@ -26,10 +36,12 @@ export default function useFilter(tempFilters, menus, search, category, webhookC const count = { total: 0, show: 0 } let switchKey - Object.keys(menus[category].filters).forEach(subCategory => { - tempAdvFilter[subCategory] = Object.values(menus[category].filters[subCategory]).every(val => val === false) + Object.keys(menus[category].filters).forEach((subCategory) => { + tempAdvFilter[subCategory] = Object.values( + menus[category].filters[subCategory], + ).every((val) => val === false) }) - tempAdvFilter.all = Object.values(tempAdvFilter).every(val => val === true) + tempAdvFilter.all = Object.values(tempAdvFilter).every((val) => val === true) if ((others.selected && others.unselected) || tempAdvFilter.all) { switchKey = 'all' @@ -50,27 +62,27 @@ export default function useFilter(tempFilters, menus, search, category, webhookC filteredArr.push(item) } - const evalSearchTerms = term => { + const evalSearchTerms = (term) => { if (term.includes('&')) { searchTerms.push(term.split('&')) } if (term.includes('+')) { const cleaned = term.slice(1) - const families = Object.keys(pokemon).filter(id => { + const families = Object.keys(pokemon).filter((id) => { const name = t(`poke_${id}`) - return (name.toLowerCase().includes(cleaned)) + return name.toLowerCase().includes(cleaned) }) if (families && term.slice(1)) { - const familyIds = families.map(item => +pokemon[item].family) + const familyIds = families.map((item) => +pokemon[item].family) searchTerms.push(...new Set(familyIds)) } } searchTerms.push(term) } - const typeResolver = pkmnTypes => { + const typeResolver = (pkmnTypes) => { let typeCount = 0 - Object.values(types).forEach(pkmnType => { + Object.values(types).forEach((pkmnType) => { if (pkmnType) typeCount += 1 }) if (typeCount === 2) { @@ -85,8 +97,8 @@ export default function useFilter(tempFilters, menus, search, category, webhookC switchKey = 'search' search = search.replace(/,/g, '|') if (search.includes('|')) { - const orSplit = search.split('|').map(term => term.trim()) - orSplit.forEach(term => { + const orSplit = search.split('|').map((term) => term.trim()) + orSplit.forEach((term) => { evalSearchTerms(term) }) } else { @@ -98,83 +110,119 @@ export default function useFilter(tempFilters, menus, search, category, webhookC reqCategories = Object.keys(categories) } - reqCategories.forEach(subCategory => { + reqCategories.forEach((subCategory) => { Object.entries(menuFilters[subCategory] || {}).forEach(([id, item]) => { - if (item.perms.some(perm => perms[perm]) - && (item.webhookOnly - ? webhookCategory && tempFilters[id] - : true)) { - if (!item.name.endsWith('*') || (item.name.endsWith('*') && category === item.category)) { + if ( + item.perms.some((perm) => perms[perm]) && + (item.webhookOnly ? webhookCategory && tempFilters[id] : true) + ) { + if ( + !item.name.endsWith('*') || + (item.name.endsWith('*') && category === item.category) + ) { count.total += 1 item.id = id switch (switchKey) { - case 'all': addItem(id, item); break - case 'selected': if (tempFilters[id]?.enabled) addItem(id, item); break - case 'unselected': if (!tempFilters[id]?.enabled) addItem(id, item); break + case 'all': + addItem(id, item) + break + case 'selected': + if (tempFilters[id]?.enabled) addItem(id, item) + break + case 'unselected': + if (!tempFilters[id]?.enabled) addItem(id, item) + break case 'reverse': if (filteringPokemon.includes(subCategory) || item.webhookOnly) { - if (((tempAdvFilter.generations || generations[item.genId]) - && (tempAdvFilter.types || typeResolver(item.formTypes)) - && (tempAdvFilter.rarity || rarity[item.rarity]) - && (tempAdvFilter.categories || categories[subCategory]) - && (tempAdvFilter.forms - || forms[item.formName] - || (forms.altForms && item.formId != item.defaultFormId) - || (forms.normalForms && item.formId === item.defaultFormId) - )) || item.webhookOnly) { + if ( + ((tempAdvFilter.generations || generations[item.genId]) && + (tempAdvFilter.types || typeResolver(item.formTypes)) && + (tempAdvFilter.rarity || rarity[item.rarity]) && + (tempAdvFilter.categories || categories[subCategory]) && + (tempAdvFilter.forms || + forms[item.formName] || + (forms.altForms && item.formId != item.defaultFormId) || + (forms.normalForms && + item.formId === item.defaultFormId))) || + item.webhookOnly + ) { addItem(id, item) } - } else if ((tempAdvFilter.categories || categories[subCategory]) || item.webhookOnly) { + } else if ( + tempAdvFilter.categories || + categories[subCategory] || + item.webhookOnly + ) { addItem(id, item) - } break + } + break case 'available': - if ((available?.[category]?.includes(id) || id.startsWith('t')) || item.webhookOnly) { + if ( + available?.[category]?.includes(id) || + id.startsWith('t') || + item.webhookOnly + ) { if (filteringPokemon.includes(subCategory)) { - if (((tempAdvFilter.generations || generations[item.genId]) - && (tempAdvFilter.types || typeResolver(item.formTypes)) - && (tempAdvFilter.rarity || rarity[item.rarity]) - && (tempAdvFilter.categories || categories[subCategory]) - && (tempAdvFilter.forms - || forms[item.formName] - || (forms.altForms && item.formId != item.defaultFormId) - || (forms.normalForms && item.formId === item.defaultFormId) - )) || item.webhookOnly) { + if ( + ((tempAdvFilter.generations || generations[item.genId]) && + (tempAdvFilter.types || typeResolver(item.formTypes)) && + (tempAdvFilter.rarity || rarity[item.rarity]) && + (tempAdvFilter.categories || categories[subCategory]) && + (tempAdvFilter.forms || + forms[item.formName] || + (forms.altForms && item.formId != item.defaultFormId) || + (forms.normalForms && + item.formId === item.defaultFormId))) || + item.webhookOnly + ) { addItem(id, item) } - } else if (tempAdvFilter.categories || categories[subCategory] || item.webhookOnly) { + } else if ( + tempAdvFilter.categories || + categories[subCategory] || + item.webhookOnly + ) { addItem(id, item) } - } break + } + break case 'search': - searchTerms.forEach(term => { + searchTerms.forEach((term) => { const meta = item.searchMeta || item.name switch (typeof term) { case 'string': term = term.trim() - if ((meta.includes(term)) || item.pokedexId == term) { + if (meta.includes(term) || item.pokedexId == term) { addItem(id, item) - } break + } + break case 'number': - if (item.family === term) addItem(id, item); break + if (item.family === term) addItem(id, item) + break default: - if (term.every(subTerm => meta.includes(subTerm))) addItem(id, item) + if (term.every((subTerm) => meta.includes(subTerm))) + addItem(id, item) } - }); break + }) + break default: if (filteringPokemon.includes(subCategory)) { - if (generations[item.genId] - || item.formTypes.some(x => types[x]) - || rarity[item.rarity] - || (forms[item.name] - || (forms.altForms && item.formId != item.defaultFormId) - || (forms.normalForms && item.formId === item.defaultFormId)) - || categories[subCategory] - || item.webhookOnly) { + if ( + generations[item.genId] || + item.formTypes.some((x) => types[x]) || + rarity[item.rarity] || + forms[item.name] || + (forms.altForms && item.formId != item.defaultFormId) || + (forms.normalForms && item.formId === item.defaultFormId) || + categories[subCategory] || + item.webhookOnly + ) { addItem(id, item) } } else if (categories[subCategory] || item.webhookOnly) { addItem(id, item) - } break + } + break } } } diff --git a/src/hooks/useGenerate.js b/src/hooks/useGenerate.js index 4012c8cd9..80830cd51 100644 --- a/src/hooks/useGenerate.js +++ b/src/hooks/useGenerate.js @@ -9,15 +9,20 @@ import { useStatic } from '@hooks/useStore' export default function useGenerate() { const { t } = useTranslation() - const { pokemon } = useStatic(s => s.masterfile) - const { gyms, pokestops } = useStatic(s => s.filters) - const staticMenus = useStatic(s => s.menus) - const setMenuFilters = useStatic(s => s.setMenuFilters) + const { pokemon } = useStatic((s) => s.masterfile) + const { gyms, pokestops } = useStatic((s) => s.filters) + const staticMenus = useStatic((s) => s.menus) + const setMenuFilters = useStatic((s) => s.setMenuFilters) 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) + const stopFilters = genPokestops( + t, + pokemon, + pokestops, + staticMenus.pokestops.categories, + ) setMenuFilters({ ...gymFilters, ...stopFilters, ...pokeFilters }) }, [localStorage.getItem('i18nextLng'), pokemon]) diff --git a/src/hooks/useLocation.js b/src/hooks/useLocation.js index 7c92bd38b..5778eadc9 100644 --- a/src/hooks/useLocation.js +++ b/src/hooks/useLocation.js @@ -18,7 +18,10 @@ export default function useLocation(map) { setColor('inherit') }, onAdd() { - const container = L.DomUtil.create('div', 'react-locate-control leaflet-bar leaflet-control') + const container = L.DomUtil.create( + 'div', + 'react-locate-control leaflet-bar leaflet-control', + ) this._container = container this._map = map this._layer = this.options.layer || new L.LayerGroup() @@ -27,7 +30,10 @@ export default function useLocation(map) { this._compassHeading = null this._prevBounds = null - const linkAndIcon = this.options.createButtonCallback(container, this.options) + const linkAndIcon = this.options.createButtonCallback( + container, + this.options, + ) this._link = linkAndIcon.link this._icon = linkAndIcon.icon diff --git a/src/hooks/useMarkerTimer.js b/src/hooks/useMarkerTimer.js index d43834d4e..da442a064 100644 --- a/src/hooks/useMarkerTimer.js +++ b/src/hooks/useMarkerTimer.js @@ -1,6 +1,13 @@ import { useEffect } from 'react' -export default function useMarkerTimer(itemExpire, itemId, ref, map, ts, callback) { +export default function useMarkerTimer( + itemExpire, + itemId, + ref, + map, + ts, + callback, +) { useEffect(() => { if (itemExpire > ts && itemExpire !== Infinity) { const timeout = setTimeout(() => { diff --git a/src/hooks/useRefresh.js b/src/hooks/useRefresh.js index 493ee7f2c..7ab735529 100644 --- a/src/hooks/useRefresh.js +++ b/src/hooks/useRefresh.js @@ -5,10 +5,10 @@ import { useEffect } from 'react' import { useStatic } from './useStore' export default function useRefresh() { - const setAvailable = useStatic(s => s.setAvailable) - const setMasterfile = useStatic(s => s.setMasterfile) - const setStaticFilters = useStatic(s => s.setFilters) - const active = useStatic(s => s.active) + const setAvailable = useStatic((s) => s.setAvailable) + const setMasterfile = useStatic((s) => s.setMasterfile) + const setStaticFilters = useStatic((s) => s.setFilters) + const active = useStatic((s) => s.active) const { data, stopPolling, startPolling } = useQuery(getAvailable, { variables: { version: inject.VERSION }, diff --git a/src/hooks/useStore.js b/src/hooks/useStore.js index 7f1520062..57b61f90d 100644 --- a/src/hooks/useStore.js +++ b/src/hooks/useStore.js @@ -1,59 +1,67 @@ import create from 'zustand' import { persist } from 'zustand/middleware' -export const useStore = create(persist( - set => ({ - location: undefined, - setLocation: (location) => set({ location }), - zoom: undefined, - setZoom: (zoom) => set({ zoom }), - filters: undefined, - setFilters: (filters) => set({ filters }), - settings: undefined, - setSettings: (settings) => set({ settings }), - userSettings: undefined, - setUserSettings: (userSettings) => set({ userSettings }), - icons: undefined, - setIcons: (icons) => set({ icons }), - menus: undefined, - setMenus: (menus) => set({ menus }), - tutorial: true, - setTutorial: (tutorial) => set({ tutorial }), - sidebar: undefined, - setSidebar: (sidebar) => set({ sidebar }), - advMenu: { - pokemon: 'others', - gyms: 'categories', - pokestops: 'categories', - nests: 'others', +export const useStore = create( + persist( + (set) => ({ + location: undefined, + setLocation: (location) => set({ location }), + zoom: undefined, + setZoom: (zoom) => set({ zoom }), + filters: undefined, + setFilters: (filters) => set({ filters }), + settings: undefined, + setSettings: (settings) => set({ settings }), + userSettings: undefined, + setUserSettings: (userSettings) => set({ userSettings }), + icons: undefined, + setIcons: (icons) => set({ icons }), + menus: undefined, + setMenus: (menus) => set({ menus }), + tutorial: true, + setTutorial: (tutorial) => set({ tutorial }), + sidebar: undefined, + setSidebar: (sidebar) => set({ sidebar }), + advMenu: { + pokemon: 'others', + gyms: 'categories', + pokestops: 'categories', + nests: 'others', + }, + setAdvMenu: (advMenu) => set({ advMenu }), + search: '', + setSearch: (search) => set({ search }), + searchTab: 0, + setSearchTab: (searchTab) => set({ searchTab }), + selectedWebhook: undefined, + setSelectedWebhook: (selectedWebhook) => set({ selectedWebhook }), + webhookAdv: { + primary: true, + advanced: false, + pvp: false, + distance: true, + global: true, + }, + setWebhookAdv: (webhookAdv) => set({ webhookAdv }), + popups: { + invasions: false, + extras: false, + raids: true, + pvp: false, + names: true, + }, + setPopups: (popups) => set({ popups }), + motdIndex: 0, + setMotdIndex: (motdIndex) => set({ motdIndex }), + }), + { + name: 'local-state', + getStorage: () => localStorage, }, - setAdvMenu: (advMenu) => set({ advMenu }), - search: '', - setSearch: (search) => set({ search }), - searchTab: 0, - setSearchTab: (searchTab) => set({ searchTab }), - selectedWebhook: undefined, - setSelectedWebhook: (selectedWebhook) => set({ selectedWebhook }), - webhookAdv: { primary: true, advanced: false, pvp: false, distance: true, global: true }, - setWebhookAdv: (webhookAdv) => set({ webhookAdv }), - popups: { - invasions: false, - extras: false, - raids: true, - pvp: false, - names: true, - }, - setPopups: (popups) => set({ popups }), - motdIndex: 0, - setMotdIndex: (motdIndex) => set({ motdIndex }), - }), - { - name: 'local-state', - getStorage: () => localStorage, - }, -)) + ), +) -export const useStatic = create(set => ({ +export const useStatic = create((set) => ({ active: true, setActive: (active) => set({ active }), auth: { discord: true, loggedIn: false, perms: {} }, @@ -85,7 +93,9 @@ export const useStatic = create(set => ({ timerList: [], setTimerList: (timerList) => set({ timerList }), webhookAlert: { - open: false, severity: 'info', message: '', + open: false, + severity: 'info', + message: '', }, setWebhookAlert: (webhookAlert) => set({ webhookAlert }), webhookData: undefined, diff --git a/src/hooks/useStyles.js b/src/hooks/useStyles.js index 456b94296..f81573467 100644 --- a/src/hooks/useStyles.js +++ b/src/hooks/useStyles.js @@ -1,7 +1,7 @@ import { makeStyles } from '@material-ui/styles' import { purple } from '@material-ui/core/colors' -export default makeStyles(theme => ({ +export default makeStyles((theme) => ({ gridItem: { height: 75, width: 'auto', diff --git a/src/hooks/useWebhook.js b/src/hooks/useWebhook.js index 8c6312c5e..c5a4f4daf 100644 --- a/src/hooks/useWebhook.js +++ b/src/hooks/useWebhook.js @@ -7,16 +7,22 @@ import { useStatic } from '@hooks/useStore' export default function useWebhook({ category, selectedWebhook }) { const [syncWebhook, { data }] = useMutation(Query.webhook('quickAdd')) const { t } = useTranslation() - const webhookData = useStatic(state => state.webhookData) - const setWebhookData = useStatic(state => state.setWebhookData) - const setWebhookAlert = useStatic(state => state.setWebhookAlert) + const webhookData = useStatic((state) => state.webhookData) + const setWebhookData = useStatic((state) => state.setWebhookData) + const setWebhookAlert = useStatic((state) => state.setWebhookAlert) useEffect(() => { if (data?.webhook) { if (data.webhook.status === 'success') { - data.webhook.message = t(`webhook_success_${category.replace('quick', '').toLowerCase()}`) + data.webhook.message = t( + `webhook_success_${category.replace('quick', '').toLowerCase()}`, + ) } - setWebhookAlert({ open: true, severity: data.webhook.status, message: data.webhook.message }) + setWebhookAlert({ + open: true, + severity: data.webhook.status, + message: data.webhook.message, + }) if (webhookData?.[selectedWebhook]) { return setWebhookData({ ...webhookData, diff --git a/src/index.jsx b/src/index.jsx index b903e21a6..dcb545536 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -9,8 +9,15 @@ import './services/i18n' if (inject) { const { - GOOGLE_ANALYTICS_ID, ANALYTICS_DEBUG_MODE, TITLE, VERSION, CUSTOM, - SENTRY_DSN, SENTRY_TRACES_SAMPLE_RATE, DEVELOPMENT, SENTRY_DEBUG, + GOOGLE_ANALYTICS_ID, + ANALYTICS_DEBUG_MODE, + TITLE, + VERSION, + CUSTOM, + SENTRY_DSN, + SENTRY_TRACES_SAMPLE_RATE, + DEVELOPMENT, + SENTRY_DEBUG, } = inject if (GOOGLE_ANALYTICS_ID) { ReactGA.initialize(GOOGLE_ANALYTICS_ID, { debug: ANALYTICS_DEBUG_MODE }) @@ -19,19 +26,25 @@ if (inject) { document.title = TITLE } Sentry.init({ - dsn: SENTRY_DSN || 'https://c40dad799323428f83aee04391639345@o1096501.ingest.sentry.io/6117162', + dsn: + SENTRY_DSN || + 'https://c40dad799323428f83aee04391639345@o1096501.ingest.sentry.io/6117162', integrations: [new Integrations.BrowserTracing()], - tracesSampleRate: SENTRY_TRACES_SAMPLE_RATE ? +SENTRY_TRACES_SAMPLE_RATE : 0.1, + tracesSampleRate: SENTRY_TRACES_SAMPLE_RATE + ? +SENTRY_TRACES_SAMPLE_RATE + : 0.1, release: VERSION, environment: DEVELOPMENT ? 'development' : 'production', debug: SENTRY_DEBUG, beforeSend: async (event) => { const errors = event.exception.values - const isLibrary = errors.find(e => e?.value?.includes('_')) - const fetchError = errors.find(e => e?.value?.includes('<')) + const isLibrary = errors.find((e) => e?.value?.includes('_')) + const fetchError = errors.find((e) => e?.value?.includes('<')) if (!isLibrary) { - const error = errors[0] ? `${errors[0].type}: ${errors[0].value}` : 'Unknown error' + const error = errors[0] + ? `${errors[0].type}: ${errors[0].value}` + : 'Unknown error' await fetch('/clientError', { method: 'POST', headers: { diff --git a/src/services/Fetch.js b/src/services/Fetch.js index 79061f0d0..972f8df50 100644 --- a/src/services/Fetch.js +++ b/src/services/Fetch.js @@ -10,7 +10,10 @@ export default class Fetch { const body = await response.json() return body.serverSettings } catch (error) { - console.error(error.message, '\nUnable to fetch settings at this time, please try again later.') + console.error( + error.message, + '\nUnable to fetch settings at this time, please try again later.', + ) return { error: true, status: 500 } } } @@ -25,7 +28,10 @@ export default class Fetch { body: JSON.stringify(user), }) } catch (error) { - console.error(error.message, '\nUnable to login at this time, please try again later.') + console.error( + error.message, + '\nUnable to login at this time, please try again later.', + ) return { error: true, status: 500 } } } diff --git a/src/services/HolidayAnimations.js b/src/services/HolidayAnimations.js index 191b9b395..45c49d612 100644 --- a/src/services/HolidayAnimations.js +++ b/src/services/HolidayAnimations.js @@ -17,9 +17,9 @@ export default class HolidayAnimations { } move() { - this.images.forEach(item => { + this.images.forEach((item) => { item.y += item.ys - item.x += item.x > (this.h / 2) ? item.xs : -item.xs + item.x += item.x > this.h / 2 ? item.xs : -item.xs if (item.y > this.h) { item.x = Math.random() * this.w item.y = -1 * this.imageHeight @@ -30,7 +30,7 @@ export default class HolidayAnimations { draw() { this.setCanvasSize() this.ctx.clearRect(0, 0, this.w, this.h) - this.images.forEach(item => { + this.images.forEach((item) => { item.image = new Image() item.image.style.height = item.height item.image.src = this.image @@ -46,7 +46,7 @@ export default class HolidayAnimations { } this.setCanvasSize() for (let a = 0; a < 30; a += 1) { - const scale = (Math.random() * (1 - this.minScale)) + this.minScale + const scale = Math.random() * (1 - this.minScale) + this.minScale this.images.push({ x: Math.random() * this.w, xs: Math.random() * 2 - 1, diff --git a/src/services/Icons.js b/src/services/Icons.js index dae970373..f885bd3a4 100644 --- a/src/services/Icons.js +++ b/src/services/Icons.js @@ -14,15 +14,17 @@ export default class UIcons { }, } this.cacheMs = cacheHrs * 60 * 60 * 1000 - Object.entries(questRewardTypes).forEach(([id, category]) => ( - this.questRewardTypes[id] = category.toLowerCase().replace(' ', '_') - )) + Object.entries(questRewardTypes).forEach( + ([id, category]) => + (this.questRewardTypes[id] = category.toLowerCase().replace(' ', '_')), + ) } build(icons) { - const baseUrl = 'https://raw.githubusercontent.com/WatWowMap/wwm-uicons/main/' + const baseUrl = + 'https://raw.githubusercontent.com/WatWowMap/wwm-uicons/main/' - icons.forEach(icon => { + icons.forEach((icon) => { try { const { data } = icon if (data) { @@ -34,16 +36,22 @@ export default class UIcons { if (!this[icon.name].modifiers) { this[icon.name].modifiers = {} } - this[icon.name].indexes.forEach(category => { + this[icon.name].indexes.forEach((category) => { let isValid = false - if (!parseInt(category) && category !== '0' && category !== 'lastFetched') { + if ( + !parseInt(category) && + category !== '0' && + category !== 'lastFetched' + ) { if (Array.isArray(data[category])) { this[icon.name][category] = new Set(data[category]) isValid = true } else { - Object.keys(data[category]).forEach(subCategory => { + Object.keys(data[category]).forEach((subCategory) => { if (Array.isArray(data[category][subCategory])) { - this[icon.name][subCategory] = new Set(data[category][subCategory]) + this[icon.name][subCategory] = new Set( + data[category][subCategory], + ) isValid = true } }) @@ -84,12 +92,12 @@ export default class UIcons { } checkValid(localIconObj) { - return Object.values(localIconObj).every(icon => this[icon]) + return Object.values(localIconObj).every((icon) => this[icon]) } setSelection(categories, value) { if (typeof categories === 'object') { - Object.keys(categories).forEach(category => { + Object.keys(categories).forEach((category) => { if (category !== 'misc') { this.selected[category] = categories[category] this.modifiers[category] = this[categories[category]] @@ -121,24 +129,45 @@ export default class UIcons { getIconById(id) { switch (id.charAt(0)) { - case 'c': return this.getRewards(4, ...id.slice(1).split('-')) - case 'd': return this.getRewards(3, id.slice(1)) - case 'e': return this.getEggs(id.slice(1), false) - case 'g': return this.getGyms(...id.slice(1).split('-')) - case 'i': return this.getInvasions(id.slice(1)) - case 'l': return this.getPokestops(id.slice(1)) - case 'm': return this.getPokemon(id.slice(1).split('-')[0], 0, 1) - case 'q': return this.getRewards(2, ...id.slice(1).split('-')) - case 'r': return this.getEggs(id.slice(1), true) - case 's': return this.getPokestops(0) - case 't': return this.getGyms(...id.slice(1).split('-')) - case 'u': return this.getRewards(id.slice(1)) - case 'x': return this.getRewards(9, ...id.slice(1).split('-')) - default: return this.getPokemon(...id.split('-')) + case 'c': + return this.getRewards(4, ...id.slice(1).split('-')) + case 'd': + return this.getRewards(3, id.slice(1)) + case 'e': + return this.getEggs(id.slice(1), false) + case 'g': + return this.getGyms(...id.slice(1).split('-')) + case 'i': + return this.getInvasions(id.slice(1)) + case 'l': + return this.getPokestops(id.slice(1)) + case 'm': + return this.getPokemon(id.slice(1).split('-')[0], 0, 1) + case 'q': + return this.getRewards(2, ...id.slice(1).split('-')) + case 'r': + return this.getEggs(id.slice(1), true) + case 's': + return this.getPokestops(0) + case 't': + return this.getGyms(...id.slice(1).split('-')) + case 'u': + return this.getRewards(id.slice(1)) + case 'x': + return this.getRewards(9, ...id.slice(1).split('-')) + default: + return this.getPokemon(...id.split('-')) } } - getPokemon(pokemonId, form = 0, evolution = 0, gender = 0, costume = 0, shiny = false) { + getPokemon( + pokemonId, + form = 0, + evolution = 0, + gender = 0, + costume = 0, + shiny = false, + ) { const baseUrl = `${this[this.selected.pokemon].path}/pokemon` const evolutionSuffixes = evolution ? [`_e${evolution}`, ''] : [''] const formSuffixes = form ? [`_f${form}`, ''] : [''] @@ -171,7 +200,12 @@ export default class UIcons { return `${baseUrl}/0.png` } - getPokestops(lureId, invasionActive = false, questActive = false, ar = false) { + getPokestops( + lureId, + invasionActive = false, + questActive = false, + ar = false, + ) { const baseUrl = `${this[this.selected.pokestop].path}/pokestop` const invasionSuffixes = invasionActive ? ['_i', ''] : [''] const questSuffixes = questActive ? ['_q', ''] : [''] @@ -213,7 +247,13 @@ export default class UIcons { return `${baseUrl}/0.png` } - getGyms(teamId = 0, trainerCount = 0, inBattle = false, ex = false, ar = false) { + getGyms( + teamId = 0, + trainerCount = 0, + inBattle = false, + ex = false, + ar = false, + ) { const baseUrl = `${this[this.selected.gym].path}/gym` const trainerSuffixes = trainerCount ? [`_t${trainerCount}`, ''] : [''] const inBattleSuffixes = inBattle ? ['_b', ''] : [''] @@ -241,7 +281,10 @@ export default class UIcons { for (let h = 0; h < hatchedSuffixes.length; h += 1) { for (let e = 0; e < exSuffixes.length; e += 1) { const result = `${level}${hatchedSuffixes[h]}${exSuffixes[e]}.png` - if (this[this.selected.raid].egg && this[this.selected.raid].egg.has(result)) { + if ( + this[this.selected.raid].egg && + this[this.selected.raid].egg.has(result) + ) { return `${baseUrl}/${result}` } } @@ -284,11 +327,14 @@ export default class UIcons { switch (true) { case this[this.selected.misc].misc.has(`${fileName}.png`): return `${baseUrl}/${fileName}.png` - case fileName.endsWith('s') && this[this.selected.misc].misc.has(`${fileName.slice(0, -1)}.png`): + case fileName.endsWith('s') && + this[this.selected.misc].misc.has(`${fileName.slice(0, -1)}.png`): return `${baseUrl}/${fileName.slice(0, -1)}.png` - case !fileName.endsWith('s') && this[this.selected.misc].misc.has(`${fileName}s.png`): + case !fileName.endsWith('s') && + this[this.selected.misc].misc.has(`${fileName}s.png`): return `${baseUrl}/${fileName}s.png` - default: return `${baseUrl}/0.png` + default: + return `${baseUrl}/0.png` } } diff --git a/src/services/Poracle.js b/src/services/Poracle.js index eec428040..cd52e5da4 100644 --- a/src/services/Poracle.js +++ b/src/services/Poracle.js @@ -1,7 +1,10 @@ export default class Poracle { static filterGenerator = (poracleInfo, reactMapFilters, invasions) => { try { - const { info: { pokemon, raid, egg, invasion, lure, nest, quest, gym }, human } = poracleInfo + const { + info: { pokemon, raid, egg, invasion, lure, nest, quest, gym }, + human, + } = poracleInfo const filters = { pokemon: { global: { ...pokemon.defaults, profile_no: human.current_profile_no }, @@ -9,19 +12,34 @@ export default class Poracle { }, raid: { global: { ...raid.defaults, profile_no: human.current_profile_no }, - r90: { ...raid.defaults, level: 90, profile_no: human.current_profile_no }, + r90: { + ...raid.defaults, + level: 90, + profile_no: human.current_profile_no, + }, }, egg: { global: { ...egg.defaults, profile_no: human.current_profile_no }, - e90: { ...egg.defaults, level: 90, profile_no: human.current_profile_no }, + e90: { + ...egg.defaults, + level: 90, + profile_no: human.current_profile_no, + }, }, gym: { global: { ...gym.defaults, profile_no: human.current_profile_no }, t4: { ...gym.defaults, profile_no: human.current_profile_no }, }, invasion: { - global: { ...invasion.defaults, profile_no: human.current_profile_no }, - i0: { ...invasion.defaults, grunt_type: 'everything', profile_no: human.current_profile_no }, + global: { + ...invasion.defaults, + profile_no: human.current_profile_no, + }, + i0: { + ...invasion.defaults, + grunt_type: 'everything', + profile_no: human.current_profile_no, + }, }, lure: { global: { ...lure.defaults, profile_no: human.current_profile_no }, @@ -33,7 +51,7 @@ export default class Poracle { global: { ...quest.defaults, profile_no: human.current_profile_no }, }, } - Object.keys(reactMapFilters.pokemon.filter).forEach(key => { + Object.keys(reactMapFilters.pokemon.filter).forEach((key) => { filters.pokemon[key] = { ...pokemon.defaults, pokemon_id: +key.split('-')[0], @@ -74,7 +92,7 @@ export default class Poracle { delete filters.quest[key].form } }) - Object.keys(reactMapFilters.pokestops.filter).forEach(key => { + Object.keys(reactMapFilters.pokestops.filter).forEach((key) => { if (key.startsWith('i')) { filters.invasion[key] = { ...invasion.defaults, @@ -147,7 +165,7 @@ export default class Poracle { delete filters.quest[key].amount } }) - Object.keys(reactMapFilters.gyms.filter).forEach(key => { + Object.keys(reactMapFilters.gyms.filter).forEach((key) => { if (key.startsWith('r')) { filters.raid[key] = { ...raid.defaults, @@ -188,94 +206,138 @@ export default class Poracle { switch (poracleCategory) { case 'gym': case 'egg': - case 'raid': return 'gyms' + case 'raid': + return 'gyms' case 'invasion': case 'lure': - case 'quest': return 'pokestops' - case 'nest': return 'nests' - default: return poracleCategory + case 'quest': + return 'pokestops' + case 'nest': + return 'nests' + default: + return poracleCategory } } static getFilterCategories(poracleCategory) { switch (poracleCategory) { - case 'egg': return ['eggs'] - case 'invasion': return ['invasions'] - case 'gym': return ['teams'] - case 'lure': return ['lures'] - case 'nest': return ['pokemon'] - case 'raid': return ['raids', 'pokemon'] - case 'quest': return ['items', 'quest_reward_12', 'pokemon', 'quest_reward_4', 'quest_reward_3'] - default: return [poracleCategory] + case 'egg': + return ['eggs'] + case 'invasion': + return ['invasions'] + case 'gym': + return ['teams'] + case 'lure': + return ['lures'] + case 'nest': + return ['pokemon'] + case 'raid': + return ['raids', 'pokemon'] + case 'quest': + return [ + 'items', + 'quest_reward_12', + 'pokemon', + 'quest_reward_4', + 'quest_reward_3', + ] + default: + return [poracleCategory] } } static getId(item, category, invasions) { switch (category) { - case 'egg': return `e${item.level}` - case 'invasion': return `i${Object.keys(invasions) - .find(x => invasions[x].type?.toLowerCase() === item.grunt_type.toLowerCase() - && invasions[x].gender === (item.gender || 1))}` - case 'lure': return `l${item.lure_id}` - case 'gym': return `t${item.team}-0` - case 'raid': return item.pokemon_id === 9000 - ? `r${item.level}` - : `${item.pokemon_id}-${item.form}` - case 'quest': return (() => { - switch (item.reward_type) { - case 2: return `q${item.reward}` - case 3: return `d${item.amount}` - case 4: return `c${item.reward}` - case 9: return `x${item.reward}` - case 12: return `m${item.reward}-${item.amount}` - default: return `${item.reward}-${item.form}` - } - })() - default: return `${item.pokemon_id}-${item.form}` + case 'egg': + return `e${item.level}` + case 'invasion': + return `i${Object.keys(invasions).find( + (x) => + invasions[x].type?.toLowerCase() === + item.grunt_type.toLowerCase() && + invasions[x].gender === (item.gender || 1), + )}` + case 'lure': + return `l${item.lure_id}` + case 'gym': + return `t${item.team}-0` + case 'raid': + return item.pokemon_id === 9000 + ? `r${item.level}` + : `${item.pokemon_id}-${item.form}` + case 'quest': + return (() => { + switch (item.reward_type) { + case 2: + return `q${item.reward}` + case 3: + return `d${item.amount}` + case 4: + return `c${item.reward}` + case 9: + return `x${item.reward}` + case 12: + return `m${item.reward}-${item.amount}` + default: + return `${item.reward}-${item.form}` + } + })() + default: + return `${item.pokemon_id}-${item.form}` } } static getIdObj(id) { switch (id.charAt(0)) { - case 'e': return { id: id.replace('e', ''), type: 'egg' } - case 'i': return { id: id.replace('i', ''), type: 'invasion' } - case 'l': return { id: id.replace('l', ''), type: 'lure' } - case 'r': return { id: id.replace('r', ''), type: 'raid' } - case 'q': return { id: id.replace('q', ''), type: 'item' } - case 'm': return { id: id.split('-')[0].replace('m', ''), type: 'pokemon' } - case 'c': return { id: id.replace('c', ''), type: 'pokemon' } - case 'x': return { id: id.replace('x', ''), type: 'pokemon' } - case 'd': return { id: 3, type: 'quest_reward' } - case 't': return { id: id.split('-')[0].replace('t', ''), type: 'gym' } - default: return { id: id.split('-')[0], form: id.split('-')[1], type: 'pokemon' } + case 'e': + return { id: id.replace('e', ''), type: 'egg' } + case 'i': + return { id: id.replace('i', ''), type: 'invasion' } + case 'l': + return { id: id.replace('l', ''), type: 'lure' } + case 'r': + return { id: id.replace('r', ''), type: 'raid' } + case 'q': + return { id: id.replace('q', ''), type: 'item' } + case 'm': + return { id: id.split('-')[0].replace('m', ''), type: 'pokemon' } + case 'c': + return { id: id.replace('c', ''), type: 'pokemon' } + case 'x': + return { id: id.replace('x', ''), type: 'pokemon' } + case 'd': + return { id: 3, type: 'quest_reward' } + case 't': + return { id: id.split('-')[0].replace('t', ''), type: 'gym' } + default: + return { id: id.split('-')[0], form: id.split('-')[1], type: 'pokemon' } } } static getTitles(idObj) { switch (idObj.type) { - case 'egg': return idObj.id === '90' - ? ['poke_global'] - : [`egg_${idObj.id}_plural`] - case 'invasion': return idObj.id === '0' - ? ['poke_global'] - : [`grunt_a_${idObj.id}`] - case 'lure': return [`lure_${idObj.id}`] - case 'raid': return idObj.id === '90' - ? ['poke_global'] - : [`raid_${idObj.id}_plural`] - case 'pokemon': return idObj.id === '0' - ? ['poke_global'] - : [`poke_${idObj.id}`, +idObj.form ? `form_${idObj.form}` : ''] - case 'gym': return idObj.id === '4' - ? ['poke_global'] - : [`team_${idObj.id}`] - default: return [`${idObj.type}_${idObj.id}`] + case 'egg': + return idObj.id === '90' ? ['poke_global'] : [`egg_${idObj.id}_plural`] + case 'invasion': + return idObj.id === '0' ? ['poke_global'] : [`grunt_a_${idObj.id}`] + case 'lure': + return [`lure_${idObj.id}`] + case 'raid': + return idObj.id === '90' ? ['poke_global'] : [`raid_${idObj.id}_plural`] + case 'pokemon': + return idObj.id === '0' + ? ['poke_global'] + : [`poke_${idObj.id}`, +idObj.form ? `form_${idObj.form}` : ''] + case 'gym': + return idObj.id === '4' ? ['poke_global'] : [`team_${idObj.id}`] + default: + return [`${idObj.type}_${idObj.id}`] } } static reactMapFriendly(values) { const reactMapFriendly = {} - Object.keys(values).forEach(key => { + Object.keys(values).forEach((key) => { if (key === 'min_time') { reactMapFriendly[key] = values[key] } else if (key.startsWith('min')) { @@ -284,7 +346,10 @@ export default class Poracle { } else if (key.startsWith('max')) { // do nothing, handled above } else if (key.startsWith('pvp')) { - reactMapFriendly.pvp = [values.pvp_ranking_best, values.pvp_ranking_worst] + reactMapFriendly.pvp = [ + values.pvp_ranking_best, + values.pvp_ranking_worst, + ] } else if (key === 'atk' || key === 'def' || key === 'sta') { reactMapFriendly[`${key}_iv`] = [values[key], values[`max_${key}`]] } else if (key.startsWith('rarity')) { @@ -297,55 +362,123 @@ export default class Poracle { } static processor(type, entries, defaults) { - const pvpFields = ['pvp_ranking_league', 'pvp_ranking_best', 'pvp_ranking_worst', 'pvp_ranking_min_cp', 'pvp_ranking_cap'] - const ignoredFields = ['noIv', 'byDistance', 'xs', 'xl', 'allForms', 'pvpEntry'] + const pvpFields = [ + 'pvp_ranking_league', + 'pvp_ranking_best', + 'pvp_ranking_worst', + 'pvp_ranking_min_cp', + 'pvp_ranking_cap', + ] + const ignoredFields = [ + 'noIv', + 'byDistance', + 'xs', + 'xl', + 'allForms', + 'pvpEntry', + ] const dupes = {} switch (type) { - case 'egg': return entries.map(egg => ({ ...defaults, ...egg, byDistance: undefined })) - case 'invasion': return entries.map(invasion => ({ ...defaults, ...invasion, byDistance: undefined })) - case 'lure': return entries.map(lure => ({ ...defaults, ...lure, lure_id: +lure.lure_id, byDistance: undefined })) - case 'gym': return entries.map(gym => ({ ...defaults, ...gym, byDistance: undefined })) - case 'raid': return entries.map(boss => { - if (boss.allForms) { - boss.form = defaults.form - if (dupes[boss.pokemon_id]) { - return null - } - dupes[boss.pokemon_id] = true - } - if (boss.byDistance === false) { - boss.distance = 0 - } - return { ...defaults, ...boss } - }).filter(boss => boss) - case 'quest': return entries.map(quest => { - if (quest.allForms) { - quest.form = defaults.form - if (dupes[quest.reward]) { - return null - } - dupes[quest.reward] = true - } - return { ...defaults, ...quest, byDistance: undefined, allForms: undefined } - }).filter(quest => quest) - default: return entries.map(pkmn => { - const fields = ['pokemon_id', 'form', 'clean', 'distance', 'min_time', 'template', 'profile_no', 'gender', 'rarity', 'max_rarity'] - const newPokemon = {} - if (pkmn.allForms) { - pkmn.form = 0 - if (dupes[pkmn.pokemon_id]) { - return null - } - dupes[pkmn.pokemon_id] = true - } - if (pkmn.pvpEntry) { - fields.push(...pvpFields) - } else { - fields.push(...Object.keys(pkmn).filter(key => !pvpFields.includes(key) && !ignoredFields.includes(key))) - } - fields.forEach(field => newPokemon[field] = pkmn[field] === undefined ? defaults[field] : pkmn[field]) - return newPokemon - }).filter(pokemon => pokemon) + case 'egg': + return entries.map((egg) => ({ + ...defaults, + ...egg, + byDistance: undefined, + })) + case 'invasion': + return entries.map((invasion) => ({ + ...defaults, + ...invasion, + byDistance: undefined, + })) + case 'lure': + return entries.map((lure) => ({ + ...defaults, + ...lure, + lure_id: +lure.lure_id, + byDistance: undefined, + })) + case 'gym': + return entries.map((gym) => ({ + ...defaults, + ...gym, + byDistance: undefined, + })) + case 'raid': + return entries + .map((boss) => { + if (boss.allForms) { + boss.form = defaults.form + if (dupes[boss.pokemon_id]) { + return null + } + dupes[boss.pokemon_id] = true + } + if (boss.byDistance === false) { + boss.distance = 0 + } + return { ...defaults, ...boss } + }) + .filter((boss) => boss) + case 'quest': + return entries + .map((quest) => { + if (quest.allForms) { + quest.form = defaults.form + if (dupes[quest.reward]) { + return null + } + dupes[quest.reward] = true + } + return { + ...defaults, + ...quest, + byDistance: undefined, + allForms: undefined, + } + }) + .filter((quest) => quest) + default: + return entries + .map((pkmn) => { + const fields = [ + 'pokemon_id', + 'form', + 'clean', + 'distance', + 'min_time', + 'template', + 'profile_no', + 'gender', + 'rarity', + 'max_rarity', + ] + const newPokemon = {} + if (pkmn.allForms) { + pkmn.form = 0 + if (dupes[pkmn.pokemon_id]) { + return null + } + dupes[pkmn.pokemon_id] = true + } + if (pkmn.pvpEntry) { + fields.push(...pvpFields) + } else { + fields.push( + ...Object.keys(pkmn).filter( + (key) => + !pvpFields.includes(key) && !ignoredFields.includes(key), + ), + ) + } + fields.forEach( + (field) => + (newPokemon[field] = + pkmn[field] === undefined ? defaults[field] : pkmn[field]), + ) + return newPokemon + }) + .filter((pokemon) => pokemon) } } @@ -354,28 +487,82 @@ export default class Poracle { case 'invasion': { let name = t(item.grunt_id ? `grunt_${item.grunt_id}` : 'poke_global') if (!item.gender) name = name.replace(/\(.+?\)/g, `(${t('all')})`) - return `${name}${item.clean ? ` | ${t('clean')} ` : ''}${item.distance ? ` | d${item.distance}` : ''}` + return `${name}${item.clean ? ` | ${t('clean')} ` : ''}${ + item.distance ? ` | d${item.distance}` : '' + }` } - case 'lure': return `${t(`lure_${item.lure_id}`)}${item.clean ? ` | ${t('clean')} ` : ''}${item.distance ? ` | d${item.distance}` : ''}` - case 'quest': return `${t(`quest_reward_${item.reward_type}`)} | ${(function getReward() { - switch (item.reward_type) { - case 2: return `${t(`item_${item.reward}`)}${item.amount ? ` | x${item.amount}` : ''}` - case 3: return `x${item.amount}` - case 4: return `${t(`poke_${item.reward}`)}${item.amount ? ` | x${item.amount}` : ''}` - case 7: return `${t(`poke_${item.reward}`)} ${t('form')}: ${t(`form_${item.form}`)}` - case 12: return `${t(`poke_${item.reward}`)}${item.amount ? ` | x${item.amount}` : ''}` - default: return '' - } - }())}${item.clean ? ` | ${t('clean')} ` : ''}${item.distance ? ` | d${item.distance}` : ''}` + case 'lure': + return `${t(`lure_${item.lure_id}`)}${ + item.clean ? ` | ${t('clean')} ` : '' + }${item.distance ? ` | d${item.distance}` : ''}` + case 'quest': + return `${t( + `quest_reward_${item.reward_type}`, + )} | ${(function getReward() { + switch (item.reward_type) { + case 2: + return `${t(`item_${item.reward}`)}${ + item.amount ? ` | x${item.amount}` : '' + }` + case 3: + return `x${item.amount}` + case 4: + return `${t(`poke_${item.reward}`)}${ + item.amount ? ` | x${item.amount}` : '' + }` + case 7: + return `${t(`poke_${item.reward}`)} ${t('form')}: ${t( + `form_${item.form}`, + )}` + case 12: + return `${t(`poke_${item.reward}`)}${ + item.amount ? ` | x${item.amount}` : '' + }` + default: + return '' + } + })()}${item.clean ? ` | ${t('clean')} ` : ''}${ + item.distance ? ` | d${item.distance}` : '' + }` // case 'gym': return `${t(`team_${item.team}`)} ${item.gym_id ? item.name : ''}` // case 'raid': // case 'egg': return `Level ${item.level} ${item.exclusive ? 'Exclusive Only' : ''} ${item.clean ? 'clean' : ''} Template: ${item.template} ${item.team === 4 ? '' : item.team} ${item.gym_id ? 'Gym:' : ''}${item.distance ? ` | d${item.distance}` : ''}` - case 'nest': return `${t(`poke_${item.pokemon_id}`)} | Min Spawn: ${item.min_spawn_avg}${item.clean ? ` | ${t('clean')} ` : ''}${item.distance ? ` | d${item.distance}` : ''}` - case 'pokemon': return `${item.pokemon_id ? ` ${t(`poke_${item.pokemon_id}`)} | ` : ` ${t('poke_global')} | `}${item.form ? ` ${t(`form_${item.form}`)} | ` : ''}${item.pvp_ranking_league - ? `${t('pvp')} ${t(leagues.find(league => league.cp === item.pvp_ranking_league).name)} ${item.pvp_ranking_best}-${item.pvp_ranking_worst} ${item.pvp_ranking_min_cp ? `${item.pvp_ranking_min_cp}${t('cp')}` : ''} ${item.pvp_ranking_cap ? `${t('cap')}${item.pvp_ranking_cap}` : ''}${item.clean ? ` | ${t('clean')} ` : ''}${item.distance ? ` | d${item.distance}` : ''}` - : `${item.min_iv}-${item.max_iv}% | L${item.min_level}-${item.max_level} - A${item.atk}-${item.max_atk} | D${item.def}-${item.max_def} | S${item.sta}-${item.max_sta}${item.clean ? ` | ${t('clean')} ` : ''}${item.distance ? ` | d${item.distance}` : ''}`}` - default: return item.description + case 'nest': + return `${t(`poke_${item.pokemon_id}`)} | Min Spawn: ${ + item.min_spawn_avg + }${item.clean ? ` | ${t('clean')} ` : ''}${ + item.distance ? ` | d${item.distance}` : '' + }` + case 'pokemon': + return `${ + item.pokemon_id + ? ` ${t(`poke_${item.pokemon_id}`)} | ` + : ` ${t('poke_global')} | ` + }${item.form ? ` ${t(`form_${item.form}`)} | ` : ''}${ + item.pvp_ranking_league + ? `${t('pvp')} ${t( + leagues.find((league) => league.cp === item.pvp_ranking_league) + .name, + )} ${item.pvp_ranking_best}-${item.pvp_ranking_worst} ${ + item.pvp_ranking_min_cp + ? `${item.pvp_ranking_min_cp}${t('cp')}` + : '' + } ${ + item.pvp_ranking_cap ? `${t('cap')}${item.pvp_ranking_cap}` : '' + }${item.clean ? ` | ${t('clean')} ` : ''}${ + item.distance ? ` | d${item.distance}` : '' + }` + : `${item.min_iv}-${item.max_iv}% | L${item.min_level}-${ + item.max_level + } + A${item.atk}-${item.max_atk} | D${item.def}-${item.max_def} | S${ + item.sta + }-${item.max_sta}${item.clean ? ` | ${t('clean')} ` : ''}${ + item.distance ? ` | d${item.distance}` : '' + }` + }` + default: + return item.description } } } diff --git a/src/services/Query.js b/src/services/Query.js index b4f375bc9..57233a313 100644 --- a/src/services/Query.js +++ b/src/services/Query.js @@ -28,15 +28,22 @@ export default class Query { return gymIndex.getBadges } const permObj = { - Gyms: filters.raids ? filters.allGyms || perms.allGyms : filters.allGyms && perms.allGyms, + Gyms: filters.raids + ? filters.allGyms || perms.allGyms + : filters.allGyms && perms.allGyms, Raids: filters.raids && perms.raids, } let query = 'get' - Object.keys(permObj).forEach(keyPerm => { + Object.keys(permObj).forEach((keyPerm) => { if (permObj[keyPerm]) query += keyPerm }) - if (query === 'get' - && (filters.exEligible || filters.inBattle || filters.arEligible || filters.gymBadges)) { + if ( + query === 'get' && + (filters.exEligible || + filters.inBattle || + filters.arEligible || + filters.gymBadges) + ) { query += 'Gyms' } @@ -61,7 +68,7 @@ export default class Query { } let query = 'get' - Object.keys(permObj).forEach(keyPerm => { + Object.keys(permObj).forEach((keyPerm) => { if (permObj[keyPerm]) query += keyPerm }) @@ -79,7 +86,7 @@ export default class Query { } let query = 'get' - Object.keys(permObj).forEach(keyPerm => { + Object.keys(permObj).forEach((keyPerm) => { if (permObj[keyPerm]) query += keyPerm }) if (query === 'get') query += 'Pokemon' @@ -119,9 +126,12 @@ export default class Query { switch (category) { case 'raids': case 'nests': - case 'quests': return searchIndex[category] - case 'webhook': return searchIndex.poiWebhook - default: return searchIndex.poi + case 'quests': + return searchIndex[category] + case 'webhook': + return searchIndex.poiWebhook + default: + return searchIndex.poi } } diff --git a/src/services/Utility.js b/src/services/Utility.js index 26b76f93c..fba923eb8 100644 --- a/src/services/Utility.js +++ b/src/services/Utility.js @@ -52,17 +52,18 @@ export default class Utility { ? 'rgba(1, 1, 1, 0.01)' : 'rgba(240, 240, 240, 0.01)' : rowIndex % 2 - ? 'rgba(1, 1, 1, 0.01)' - : 'rgba(240, 240, 240, 0.01)' + ? 'rgba(1, 1, 1, 0.01)' + : 'rgba(240, 240, 240, 0.01)' } static generateSlots = (teamId, show, tempFilters) => { const slotObj = {} for (let i = 1; i <= 6; i += 1) { const slotKey = `g${teamId.charAt(1)}-${i}` - slotObj[slotKey] = typeof show === 'boolean' - ? { ...tempFilters[slotKey], enabled: show } - : { ...tempFilters[slotKey], size: show.size } + slotObj[slotKey] = + typeof show === 'boolean' + ? { ...tempFilters[slotKey], enabled: show } + : { ...tempFilters[slotKey], size: show.size } } return slotObj } @@ -76,15 +77,31 @@ export default class Utility { static getMidnight() { const date = new Date() return Math.floor( - new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 1, 0).getTime() / 1000, + new Date( + date.getFullYear(), + date.getMonth(), + date.getDate(), + 0, + 0, + 1, + 0, + ).getTime() / 1000, ) } - static analytics(category, action = false, label = false, nonInteraction = false) { + static analytics( + category, + action = false, + label = false, + nonInteraction = false, + ) { if (inject?.GOOGLE_ANALYTICS_ID) { if (action) { ReactGA.event({ - category, action, label, nonInteraction, + category, + action, + label, + nonInteraction, }) } else { ReactGA.pageview(category) @@ -97,7 +114,13 @@ export default class Utility { sm: sizeObj?.sm || sizeObj?.xs || 12, md: sizeObj?.md || sizeObj?.sm || sizeObj?.xs || 12, lg: sizeObj?.lg || sizeObj?.md || sizeObj?.sm || sizeObj?.xs || 12, - xl: sizeObj?.xl || sizeObj?.lg || sizeObj?.md || sizeObj?.sm || sizeObj?.xs || 12, + xl: + sizeObj?.xl || + sizeObj?.lg || + sizeObj?.md || + sizeObj?.sm || + sizeObj?.xs || + 12, }) static getQueryArgs(map) { @@ -118,8 +141,7 @@ export default class Utility { if (!content) return '' if (typeof content === 'string') return content return typeof content === 'object' - ? content[localStorage.getItem('i18nextLng')] - || Object.values(content)[0] + ? content[localStorage.getItem('i18nextLng')] || Object.values(content)[0] : '' } } diff --git a/src/services/filtering/genGyms.js b/src/services/filtering/genGyms.js index 78f045021..f31cf1142 100644 --- a/src/services/filtering/genGyms.js +++ b/src/services/filtering/genGyms.js @@ -1,41 +1,60 @@ export default function genGyms(t, gyms, categories) { - const tempObj = Object.fromEntries(categories.map(x => [x, {}])) + const tempObj = Object.fromEntries(categories.map((x) => [x, {}])) if (!gyms?.filter) return {} if (tempObj.eggs) { - tempObj.eggs.e90 = { name: t('poke_global'), perms: ['raids'], webhookOnly: true } + tempObj.eggs.e90 = { + name: t('poke_global'), + perms: ['raids'], + webhookOnly: true, + } } if (tempObj.raids) { - tempObj.raids.r90 = { name: t('poke_global'), perms: ['raids'], webhookOnly: true } + tempObj.raids.r90 = { + name: t('poke_global'), + perms: ['raids'], + webhookOnly: true, + } } if (tempObj.teams) { - tempObj.teams.t4 = { name: t('poke_global'), perms: ['gyms'], webhookOnly: true } + tempObj.teams.t4 = { + name: t('poke_global'), + perms: ['gyms'], + webhookOnly: true, + } } - Object.keys(gyms.filter).forEach(id => { - if (id !== 'global' - && !/\d/.test(id.charAt(0)) - && !id.startsWith('g')) { + Object.keys(gyms.filter).forEach((id) => { + if (id !== 'global' && !/\d/.test(id.charAt(0)) && !id.startsWith('g')) { switch (id.charAt(0)) { case 'e': tempObj.eggs[id] = { name: t(`egg_${id.slice(1)}_plural`), perms: ['raids'], - searchMeta: `${t(`egg_${id.slice(1)}_plural`)} ${t('eggs').toLowerCase()}`, - }; break + searchMeta: `${t(`egg_${id.slice(1)}_plural`)} ${t( + 'eggs', + ).toLowerCase()}`, + } + break case 'r': tempObj.raids[id] = { name: t(`raid_${id.slice(1).split('-')[0]}_plural`), perms: ['raids'], - searchMeta: `${t(`raid_${id.slice(1)}_plural`)} ${t('raids').toLowerCase()}`, + searchMeta: `${t(`raid_${id.slice(1)}_plural`)} ${t( + 'raids', + ).toLowerCase()}`, webhookOnly: true, - }; break + } + break default: tempObj.teams[id] = { name: t(`team_${id.slice(1).split('-')[0]}`), perms: ['gyms'], - searchMeta: `${t(`team_${id.slice(1)}`)} ${t('teams').toLowerCase()}`, - }; break + searchMeta: `${t(`team_${id.slice(1)}`)} ${t( + 'teams', + ).toLowerCase()}`, + } + break } } }) diff --git a/src/services/filtering/genPokemon.js b/src/services/filtering/genPokemon.js index b65d576dd..4dfbb77f3 100644 --- a/src/services/filtering/genPokemon.js +++ b/src/services/filtering/genPokemon.js @@ -1,17 +1,30 @@ export default function genPokemon(t, pokemon, categories) { - const tempObj = Object.fromEntries(categories.map(x => ( - [x, { '0-0': { webhookOnly: true, name: t('poke_global'), perms: ['pokemon', 'raids', 'quests', 'nests'], formTypes: [] } }] - ))) + const tempObj = Object.fromEntries( + categories.map((x) => [ + x, + { + '0-0': { + webhookOnly: true, + name: t('poke_global'), + perms: ['pokemon', 'raids', 'quests', 'nests'], + formTypes: [], + }, + }, + ]), + ) Object.entries(pokemon).forEach(([i, pkmn]) => { const pokeName = t(`poke_${i}`) Object.entries(pkmn.forms).forEach(([j, form]) => { const formName = t(`form_${j}`) const id = `${i}-${j}` - const formTypes = (form.types || pkmn.types || []).map(x => `poke_type_${x}`) - const name = form.name && form.name !== 'Normal' && j != 0 && j != pkmn.defaultFormId - ? formName - : pokeName + const formTypes = (form.types || pkmn.types || []).map( + (x) => `poke_type_${x}`, + ) + const name = + form.name && form.name !== 'Normal' && j != 0 && j != pkmn.defaultFormId + ? formName + : pokeName tempObj.pokemon[id] = { name: form.name === '*' ? `${name}*` : name, category: form.name === '*' ? form.category : undefined, @@ -27,7 +40,7 @@ export default function genPokemon(t, pokemon, categories) { family: pkmn.family, } tempObj.pokemon[id].searchMeta = `${Object.values(tempObj.pokemon[id]) - .flatMap(x => Array.isArray(x) ? x.map(y => t(y)) : t(x)) + .flatMap((x) => (Array.isArray(x) ? x.map((y) => t(y)) : t(x))) .join(' ') .toLowerCase()} ${t('pokemon').toLowerCase()}` }) diff --git a/src/services/filtering/genPokestops.js b/src/services/filtering/genPokestops.js index 25ea5a8ed..3dd82697c 100644 --- a/src/services/filtering/genPokestops.js +++ b/src/services/filtering/genPokestops.js @@ -1,12 +1,16 @@ export default function genPokestops(t, pokemon, pokestops, categories) { - const tempObj = Object.fromEntries(categories.map(x => [x, {}])) + const tempObj = Object.fromEntries(categories.map((x) => [x, {}])) if (!pokestops?.filter) return {} if (tempObj.invasions) { - tempObj.invasions.i0 = { name: t('poke_global'), perms: ['invasions'], webhookOnly: true } + tempObj.invasions.i0 = { + name: t('poke_global'), + perms: ['invasions'], + webhookOnly: true, + } } - Object.keys(pokestops.filter).forEach(id => { + Object.keys(pokestops.filter).forEach((id) => { if (id !== 'global' && !/\d/.test(id.charAt(0))) { switch (id.charAt(0)) { case 'i': @@ -15,76 +19,107 @@ export default function genPokestops(t, pokemon, pokestops, categories) { name: t(`grunt_a_${id.slice(1)}`, `grunt_${id.slice(1)}`), perms: ['invasions'], } - tempObj.invasions[id].searchMeta = `${t('invasions').toLowerCase()} ${t(`grunt_${id.slice(1)}`).toLowerCase()}` - } break + tempObj.invasions[id].searchMeta = `${t( + 'invasions', + ).toLowerCase()} ${t(`grunt_${id.slice(1)}`).toLowerCase()}` + } + break case 'd': if (tempObj.quest_reward_3) { tempObj.quest_reward_3[id] = { name: `x${id.slice(1)}`, perms: ['quests'], } - tempObj.quest_reward_3[id].searchMeta = `${t('quest_reward_3').toLowerCase()} ${tempObj.quest_reward_3[id].name.toLowerCase()}` - } break - case 'm': { - const monId = id && id.slice(1).split('-')[0] - if (tempObj.quest_reward_12 && pokemon[monId]) { - tempObj.quest_reward_12[id] = { - name: `${t(`poke_${monId}`)} x${id.split('-')[1]}`, - perms: ['quests'], - genId: `generation_${pokemon[monId].genId}`, - formTypes: pokemon[monId].types.map(x => `poke_type_${x}`), - rarity: pokemon[monId].rarity, - family: pokemon[monId].family, + tempObj.quest_reward_3[id].searchMeta = `${t( + 'quest_reward_3', + ).toLowerCase()} ${tempObj.quest_reward_3[id].name.toLowerCase()}` + } + break + case 'm': + { + const monId = id && id.slice(1).split('-')[0] + if (tempObj.quest_reward_12 && pokemon[monId]) { + tempObj.quest_reward_12[id] = { + name: `${t(`poke_${monId}`)} x${id.split('-')[1]}`, + perms: ['quests'], + genId: `generation_${pokemon[monId].genId}`, + formTypes: pokemon[monId].types.map((x) => `poke_type_${x}`), + rarity: pokemon[monId].rarity, + family: pokemon[monId].family, + } + tempObj.quest_reward_12[id].searchMeta = `${Object.values( + tempObj.quest_reward_12[id], + ) + .flatMap((x) => t(x)) + .join(' ') + .toLowerCase()} ${t('quest_reward_12').toLowerCase()}` } - tempObj.quest_reward_12[id].searchMeta = `${Object.values(tempObj.quest_reward_12[id]) - .flatMap(x => t(x)) - .join(' ') - .toLowerCase()} ${t('quest_reward_12').toLowerCase()}` } - } break + break case 'q': if (tempObj.items) { tempObj.items[id] = { name: t(`item_${id.slice(1)}`), perms: ['quests'], } - tempObj.items[id].searchMeta = `${t('items').toLowerCase()} ${tempObj.items[id].name.toLowerCase()}` - } break + tempObj.items[id].searchMeta = `${t( + 'items', + ).toLowerCase()} ${tempObj.items[id].name.toLowerCase()}` + } + break case 'l': if (tempObj.lures) { tempObj.lures[id] = { name: t(`lure_${id.slice(1)}`), perms: ['lures'], } - tempObj.lures[id].searchMeta = `${t('lures').toLowerCase()} ${tempObj.lures[id].name.toLowerCase()}` - } break + tempObj.lures[id].searchMeta = `${t( + 'lures', + ).toLowerCase()} ${tempObj.lures[id].name.toLowerCase()}` + } + break case 'x': - case 'c': { - const monId = id && id.slice(1) - if (tempObj.quest_reward_4 && tempObj.quest_reward_9 && pokemon[monId]) { - const category = [id.charAt(0) === 'c' ? 'quest_reward_4' : 'quest_reward_9'] - tempObj[category][id] = { - name: `${t(`poke_${monId}`)} ${id.charAt(0) === 'c' ? t('candy') : t('xl')}`, - perms: ['quests'], - genId: `generation_${pokemon[monId].genId}`, - formTypes: pokemon[monId].types.map(x => `poke_type_${x}`), - rarity: pokemon[monId].rarity, - family: pokemon[monId].family, + case 'c': + { + const monId = id && id.slice(1) + if ( + tempObj.quest_reward_4 && + tempObj.quest_reward_9 && + pokemon[monId] + ) { + const category = [ + id.charAt(0) === 'c' ? 'quest_reward_4' : 'quest_reward_9', + ] + tempObj[category][id] = { + name: `${t(`poke_${monId}`)} ${ + id.charAt(0) === 'c' ? t('candy') : t('xl') + }`, + perms: ['quests'], + genId: `generation_${pokemon[monId].genId}`, + formTypes: pokemon[monId].types.map((x) => `poke_type_${x}`), + rarity: pokemon[monId].rarity, + family: pokemon[monId].family, + } + tempObj[category][id].searchMeta = `${Object.values( + tempObj[category][id], + ) + .flatMap((x) => t(x)) + .join(' ') + .toLowerCase()} ${t(category).toLowerCase()}` } - tempObj[category][id].searchMeta = `${Object.values(tempObj[category][id]) - .flatMap(x => t(x)) - .join(' ') - .toLowerCase()} ${t(category).toLowerCase()}` } - } break + break case 'u': if (tempObj.general) { tempObj.general[id] = { name: t(`quest_reward_${id.slice(1)}`), perms: ['quests'], } - tempObj.general[id].searchMeta = `${t('general').toLowerCase()} ${tempObj.general[id].name.toLowerCase()}` - } break + tempObj.general[id].searchMeta = `${t( + 'general', + ).toLowerCase()} ${tempObj.general[id].name.toLowerCase()}` + } + break default: if (tempObj.pokestops) { tempObj.pokestops[id] = { diff --git a/src/services/functions/checkAdvFilter.js b/src/services/functions/checkAdvFilter.js index 2af63125d..5fbe59bf3 100644 --- a/src/services/functions/checkAdvFilter.js +++ b/src/services/functions/checkAdvFilter.js @@ -3,7 +3,8 @@ /* eslint-disable default-case */ export default function checkIVFilterValid(filter) { const input = filter.toUpperCase() - const tokenizer = /\s*([()|&!,]|([ADSL]?|CP|[GU]L|LC)\s*([0-9]+(?:\.[0-9]*)?)(?:\s*-\s*([0-9]+(?:\.[0-9]*)?))?)/g + const tokenizer = + /\s*([()|&!,]|([ADSL]?|CP|[GU]L|LC)\s*([0-9]+(?:\.[0-9]*)?)(?:\s*-\s*([0-9]+(?:\.[0-9]*)?))?)/g let expectClause = true let stack = 0 let lastIndex = 0 diff --git a/src/services/functions/dayCheck.js b/src/services/functions/dayCheck.js index 2f4d43c34..8fd940b0c 100644 --- a/src/services/functions/dayCheck.js +++ b/src/services/functions/dayCheck.js @@ -1,7 +1,7 @@ export default function dayCheck(currentStamp, desiredStamp) { const locale = localStorage.getItem('i18nextLng') || 'en' if (currentStamp - desiredStamp < 86400) { - return (new Date(desiredStamp * 1000)).toLocaleTimeString(locale) + return new Date(desiredStamp * 1000).toLocaleTimeString(locale) } - return (new Date(desiredStamp * 1000)).toLocaleString(locale) + return new Date(desiredStamp * 1000).toLocaleString(locale) } diff --git a/src/services/functions/formatInterval.js b/src/services/functions/formatInterval.js index 89ad9275c..7bcc0b8f9 100644 --- a/src/services/functions/formatInterval.js +++ b/src/services/functions/formatInterval.js @@ -3,7 +3,7 @@ export default function formatInterval(intervalMs) { const d = Math.floor(diff / 86400) const h = Math.floor(diff / 3600) const m = Math.floor((diff % 3600) / 60) - const s = Math.floor(diff % 3600 % 60) + const s = Math.floor((diff % 3600) % 60) const str = [] if (d > 0) { diff --git a/src/services/functions/parseConditions.js b/src/services/functions/parseConditions.js index b32c55647..1e80b7987 100644 --- a/src/services/functions/parseConditions.js +++ b/src/services/functions/parseConditions.js @@ -1,22 +1,43 @@ export default function parseQuestConditions(conditions) { const [type1, type2] = JSON.parse(conditions) const conditionsToReturn = [] - const parseMadRewards = specifics => { + const parseMadRewards = (specifics) => { const normalized = { type: specifics.type, info: {}, } switch (specifics.type) { - case 1: normalized.info.pokemon_type_ids = specifics.with_pokemon_type.pokemon_type; break - case 2: normalized.info.pokemon_ids = specifics.with_pokemon_category.pokemon_ids; break - case 7: normalized.info.raid_levels = specifics.with_raid_level.raid_level; break - case 11: normalized.info.item_id = specifics.with_item.item; break + case 1: + normalized.info.pokemon_type_ids = + specifics.with_pokemon_type.pokemon_type + break + case 2: + normalized.info.pokemon_ids = + specifics.with_pokemon_category.pokemon_ids + break + case 7: + normalized.info.raid_levels = specifics.with_raid_level.raid_level + break + case 11: + normalized.info.item_id = specifics.with_item.item + break case 8: - case 14: normalized.info.throw_type_id = specifics.with_throw_type.throw_type; break - case 26: normalized.info.alignment_ids = specifics.with_pokemon_alignment.alignment; break - case 27: normalized.info.character_category_ids = specifics.with_invasion_character.category; break - case 44: normalized.info.time = specifics.with_elapsed_time.elapsed_time / 1000; break - default: break + case 14: + normalized.info.throw_type_id = specifics.with_throw_type.throw_type + break + case 26: + normalized.info.alignment_ids = + specifics.with_pokemon_alignment.alignment + break + case 27: + normalized.info.character_category_ids = + specifics.with_invasion_character.category + break + case 44: + normalized.info.time = specifics.with_elapsed_time.elapsed_time / 1000 + break + default: + break } return normalized } diff --git a/src/services/queries/geocoder.js b/src/services/queries/geocoder.js index 5d95b5295..482ab87f8 100644 --- a/src/services/queries/geocoder.js +++ b/src/services/queries/geocoder.js @@ -3,16 +3,16 @@ import { gql } from '@apollo/client' export const Nominatim = gql` fragment Nominatim on Geocoder { latitude - longitude - streetNumber - streetName - neighborhood - suburb - city - state - zipcode - country - countryCode + longitude + streetNumber + streetName + neighborhood + suburb + city + state + zipcode + country + countryCode } ` diff --git a/src/services/queries/gym.js b/src/services/queries/gym.js index 805600b21..5871b793d 100644 --- a/src/services/queries/gym.js +++ b/src/services/queries/gym.js @@ -46,8 +46,24 @@ const raid = gql` export const getGyms = gql` ${core} ${gym} - query Gyms($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $filters: JSON!, $ts: Int!, $version: String) { - gyms(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, filters: $filters, ts: $ts, version: $version) { + query Gyms( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $filters: JSON! + $ts: Int! + $version: String + ) { + gyms( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + filters: $filters + ts: $ts + version: $version + ) { ...CoreGym ...Gym } @@ -57,8 +73,24 @@ export const getGyms = gql` export const getRaids = gql` ${core} ${raid} - query Raids($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $filters: JSON!, $ts: Int!, $version: String) { - gyms(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, filters: $filters, ts: $ts, version: $version) { + query Raids( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $filters: JSON! + $ts: Int! + $version: String + ) { + gyms( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + filters: $filters + ts: $ts + version: $version + ) { ...CoreGym ...Raid } @@ -69,8 +101,24 @@ export const getGymsRaids = gql` ${core} ${gym} ${raid} - query GymsRaids($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $filters: JSON!, $ts: Int!, $version: String) { - gyms(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, filters: $filters, ts: $ts, version: $version) { + query GymsRaids( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $filters: JSON! + $ts: Int! + $version: String + ) { + gyms( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + filters: $filters + ts: $ts + version: $version + ) { ...CoreGym ...Gym ...Raid diff --git a/src/services/queries/nest.js b/src/services/queries/nest.js index 830d62f6f..25e7ae10e 100644 --- a/src/services/queries/nest.js +++ b/src/services/queries/nest.js @@ -10,8 +10,22 @@ const core = gql` export const getAllNests = gql` ${core} - query Nests($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $filters: JSON!, $version: String) { - nests(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, filters: $filters, version: $version) { + query Nests( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $filters: JSON! + $version: String + ) { + nests( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + filters: $filters + version: $version + ) { ...CoreNest name pokemon_id diff --git a/src/services/queries/pokemon.js b/src/services/queries/pokemon.js index 608d5a356..f5a6ae548 100644 --- a/src/services/queries/pokemon.js +++ b/src/services/queries/pokemon.js @@ -44,8 +44,22 @@ const pvp = gql` export const getPokemon = gql` ${core} - query Pokemon($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $filters: JSON!, $ts: Int) { - pokemon(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, filters: $filters, ts: $ts) { + query Pokemon( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $filters: JSON! + $ts: Int + ) { + pokemon( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + filters: $filters + ts: $ts + ) { ...CorePokemon } } @@ -54,8 +68,22 @@ export const getPokemon = gql` export const getIvs = gql` ${core} ${ivs} - query PokemonIVs($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $filters: JSON!, $ts: Int) { - pokemon(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, filters: $filters, ts: $ts) { + query PokemonIVs( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $filters: JSON! + $ts: Int + ) { + pokemon( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + filters: $filters + ts: $ts + ) { ...CorePokemon ...Iv } @@ -65,8 +93,24 @@ export const getIvs = gql` export const getPvp = gql` ${core} ${pvp} - query PokemonPVP($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $filters: JSON!, $ts: Int, $version: String) { - pokemon(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, filters: $filters, ts: $ts, version: $version) { + query PokemonPVP( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $filters: JSON! + $ts: Int + $version: String + ) { + pokemon( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + filters: $filters + ts: $ts + version: $version + ) { ...CorePokemon ...Pvp } @@ -77,8 +121,24 @@ export const getIvsPvp = gql` ${core} ${ivs} ${pvp} - query PokemonIVsPVP($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $filters: JSON!, $ts: Int, $version: String) { - pokemon(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, filters: $filters, ts: $ts, version: $version) { + query PokemonIVsPVP( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $filters: JSON! + $ts: Int + $version: String + ) { + pokemon( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + filters: $filters + ts: $ts + version: $version + ) { ...CorePokemon ...Iv ...Pvp diff --git a/src/services/queries/pokestop.js b/src/services/queries/pokestop.js index a92a5c733..8139c7c07 100644 --- a/src/services/queries/pokestop.js +++ b/src/services/queries/pokestop.js @@ -63,8 +63,26 @@ const invasion = gql` export const getPokestops = gql` ${core} - query Pokestops($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $filters: JSON!, $ts: Int!, $midnight: Int!, $version: String) { - pokestops(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, filters: $filters, ts: $ts, midnight: $midnight, version: $version) { + query Pokestops( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $filters: JSON! + $ts: Int! + $midnight: Int! + $version: String + ) { + pokestops( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + filters: $filters + ts: $ts + midnight: $midnight + version: $version + ) { ...CorePokestop } } @@ -73,8 +91,26 @@ export const getPokestops = gql` export const getLures = gql` ${core} ${lure} - query Lures($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $filters: JSON!, $ts: Int!, $midnight: Int!, $version: String) { - pokestops(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, filters: $filters, ts: $ts, midnight: $midnight, version: $version) { + query Lures( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $filters: JSON! + $ts: Int! + $midnight: Int! + $version: String + ) { + pokestops( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + filters: $filters + ts: $ts + midnight: $midnight + version: $version + ) { ...CorePokestop ...Lure } @@ -84,8 +120,26 @@ export const getLures = gql` export const getQuests = gql` ${core} ${quest} - query Quests($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $filters: JSON!, $ts: Int!, $midnight: Int!, $version: String) { - pokestops(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, filters: $filters, ts: $ts, midnight: $midnight, version: $version) { + query Quests( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $filters: JSON! + $ts: Int! + $midnight: Int! + $version: String + ) { + pokestops( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + filters: $filters + ts: $ts + midnight: $midnight + version: $version + ) { ...CorePokestop ...Quest } @@ -95,8 +149,26 @@ export const getQuests = gql` export const getInvasions = gql` ${core} ${invasion} - query Invasions($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $filters: JSON!, $ts: Int!, $midnight: Int!, $version: String) { - pokestops(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, filters: $filters, ts: $ts, midnight: $midnight, version: $version) { + query Invasions( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $filters: JSON! + $ts: Int! + $midnight: Int! + $version: String + ) { + pokestops( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + filters: $filters + ts: $ts + midnight: $midnight + version: $version + ) { ...CorePokestop ...Invasion } @@ -107,8 +179,26 @@ export const getLuresQuests = gql` ${core} ${lure} ${quest} - query LuresQuests($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $filters: JSON!, $ts: Int!, $midnight: Int!, $version: String) { - pokestops(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, filters: $filters, ts: $ts, midnight: $midnight, version: $version) { + query LuresQuests( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $filters: JSON! + $ts: Int! + $midnight: Int! + $version: String + ) { + pokestops( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + filters: $filters + ts: $ts + midnight: $midnight + version: $version + ) { ...CorePokestop ...Lure ...Quest @@ -120,8 +210,26 @@ export const getLuresInvasions = gql` ${core} ${lure} ${invasion} - query LuresInvasion($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $filters: JSON!, $ts: Int!, $midnight: Int!, $version: String) { - pokestops(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, filters: $filters, ts: $ts, midnight: $midnight, version: $version) { + query LuresInvasion( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $filters: JSON! + $ts: Int! + $midnight: Int! + $version: String + ) { + pokestops( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + filters: $filters + ts: $ts + midnight: $midnight + version: $version + ) { ...CorePokestop ...Lure ...Invasion @@ -133,8 +241,26 @@ export const getQuestsInvasions = gql` ${core} ${quest} ${invasion} - query QuestsInvasions($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $filters: JSON!, $ts: Int!, $midnight: Int!, $version: String) { - pokestops(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, filters: $filters, ts: $ts, midnight: $midnight, version: $version) { + query QuestsInvasions( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $filters: JSON! + $ts: Int! + $midnight: Int! + $version: String + ) { + pokestops( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + filters: $filters + ts: $ts + midnight: $midnight + version: $version + ) { ...CorePokestop ...Quest ...Invasion @@ -147,8 +273,26 @@ export const getLuresQuestsInvasions = gql` ${lure} ${quest} ${invasion} - query LuresQuestInvasions($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $filters: JSON!, $ts: Int!, $midnight: Int!, $version: String) { - pokestops(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, filters: $filters, ts: $ts, midnight: $midnight, version: $version) { + query LuresQuestInvasions( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $filters: JSON! + $ts: Int! + $midnight: Int! + $version: String + ) { + pokestops( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + filters: $filters + ts: $ts + midnight: $midnight + version: $version + ) { ...CorePokestop ...Lure ...Quest diff --git a/src/services/queries/portal.js b/src/services/queries/portal.js index 0da5ff15a..53a89cbdd 100644 --- a/src/services/queries/portal.js +++ b/src/services/queries/portal.js @@ -1,8 +1,20 @@ import { gql } from '@apollo/client' export const getAllPortals = gql` - query Portals($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $version: String) { - portals(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, version: $version) { + query Portals( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $version: String + ) { + portals( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + version: $version + ) { id lat lon diff --git a/src/services/queries/scanAreas.js b/src/services/queries/scanAreas.js index bab4d9526..73092dc1a 100644 --- a/src/services/queries/scanAreas.js +++ b/src/services/queries/scanAreas.js @@ -1,7 +1,7 @@ import { gql } from '@apollo/client' const getAllScanAreas = gql` -query ScanAreas($version: String) { + query ScanAreas($version: String) { scanAreas(version: $version) { type features { diff --git a/src/services/queries/scanCell.js b/src/services/queries/scanCell.js index afe239624..de8761457 100644 --- a/src/services/queries/scanCell.js +++ b/src/services/queries/scanCell.js @@ -1,8 +1,22 @@ import { gql } from '@apollo/client' const getAllScanCells = gql` - query ScanCells($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $zoom: Int!, $version: String) { - scanCells(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, zoom: $zoom, version: $version) { + query ScanCells( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $zoom: Int! + $version: String + ) { + scanCells( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + zoom: $zoom + version: $version + ) { id center_lat center_lon diff --git a/src/services/queries/scanner.js b/src/services/queries/scanner.js index 9ea582e8a..2fed5175b 100644 --- a/src/services/queries/scanner.js +++ b/src/services/queries/scanner.js @@ -1,8 +1,18 @@ import { gql } from '@apollo/client' const scanner = gql` - query Scanner($category: String!, $method: String!, $data: JSON!, $version: String) { - scanner(category: $category, method: $method, data: $data, version: $version) { + query Scanner( + $category: String! + $method: String! + $data: JSON! + $version: String + ) { + scanner( + category: $category + method: $method + data: $data + version: $version + ) { status message } diff --git a/src/services/queries/search.js b/src/services/queries/search.js index 993021c7b..64f76eb26 100644 --- a/src/services/queries/search.js +++ b/src/services/queries/search.js @@ -14,8 +14,22 @@ const core = gql` export const poi = gql` ${core} - query SearchPoi($search: String!, $category: String!, $lat: Float!, $lon: Float!, $locale: String!, $version: String) { - search(search: $search, category: $category, lat: $lat, lon: $lon, locale: $locale, version: $version) { + query SearchPoi( + $search: String! + $category: String! + $lat: Float! + $lon: Float! + $locale: String! + $version: String + ) { + search( + search: $search + category: $category + lat: $lat + lon: $lon + locale: $locale + version: $version + ) { ...CoreSearch } } @@ -23,8 +37,24 @@ export const poi = gql` export const poiWebhook = gql` ${Nominatim} - query SearchWebhook($search: String!, $category: String!, $lat: Float!, $lon: Float!, $locale: String!, $webhookName: String, $version: String) { - search(search: $search, category: $category, lat: $lat, lon: $lon, locale: $locale, webhookName: $webhookName, version: $version) { + query SearchWebhook( + $search: String! + $category: String! + $lat: Float! + $lon: Float! + $locale: String! + $webhookName: String + $version: String + ) { + search( + search: $search + category: $category + lat: $lat + lon: $lon + locale: $locale + webhookName: $webhookName + version: $version + ) { id name formatted { @@ -36,8 +66,22 @@ export const poiWebhook = gql` export const nests = gql` ${core} - query SearchNests($search: String!, $category: String!, $lat: Float!, $lon: Float!, $locale: String!, $version: String) { - search(search: $search, category: $category, lat: $lat, lon: $lon, locale: $locale, version: $version) { + query SearchNests( + $search: String! + $category: String! + $lat: Float! + $lon: Float! + $locale: String! + $version: String + ) { + search( + search: $search + category: $category + lat: $lat + lon: $lon + locale: $locale + version: $version + ) { ...CoreSearch nest_pokemon_id nest_pokemon_form @@ -46,8 +90,24 @@ export const nests = gql` ` export const quests = gql` - query SearchQuests($search: String!, $category: String!, $lat: Float!, $lon: Float!, $locale: String!, $midnight: Int, $version: String) { - searchQuest(search: $search, category: $category, lat: $lat, lon: $lon, locale: $locale, midnight: $midnight, version: $version) { + query SearchQuests( + $search: String! + $category: String! + $lat: Float! + $lon: Float! + $locale: String! + $midnight: Int + $version: String + ) { + searchQuest( + search: $search + category: $category + lat: $lat + lon: $lon + locale: $locale + midnight: $midnight + version: $version + ) { id name lat @@ -75,8 +135,24 @@ export const quests = gql` export const raids = gql` ${core} - query SearchRaids($search: String!, $category: String!, $lat: Float!, $lon: Float!, $locale: String!, $ts: Int, $version: String) { - search(search: $search, category: $category, lat: $lat, lon: $lon, locale: $locale, ts: $ts, version: $version) { + query SearchRaids( + $search: String! + $category: String! + $lat: Float! + $lon: Float! + $locale: String! + $ts: Int + $version: String + ) { + search( + search: $search + category: $category + lat: $lat + lon: $lon + locale: $locale + ts: $ts + version: $version + ) { ...CoreSearch raid_pokemon_id raid_pokemon_form diff --git a/src/services/queries/spawnpoint.js b/src/services/queries/spawnpoint.js index d1ff16d57..dad726341 100644 --- a/src/services/queries/spawnpoint.js +++ b/src/services/queries/spawnpoint.js @@ -1,15 +1,27 @@ import { gql } from '@apollo/client' const getAllSpawnpoints = gql` -query Spawnpoints($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $version: String) { - spawnpoints(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, version: $version) { - id - lat - lon - despawn_sec - updated + query Spawnpoints( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $version: String + ) { + spawnpoints( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + version: $version + ) { + id + lat + lon + despawn_sec + updated + } } -} ` export default getAllSpawnpoints diff --git a/src/services/queries/submissionCells.js b/src/services/queries/submissionCells.js index 1a9cdd060..2def301fb 100644 --- a/src/services/queries/submissionCells.js +++ b/src/services/queries/submissionCells.js @@ -1,8 +1,22 @@ import { gql } from '@apollo/client' const getAllSubmissionCells = gql` - query SubmissionCells($minLat: Float!, $minLon: Float!, $maxLat: Float!, $maxLon: Float!, $zoom: Int!, $version: String) { - submissionCells(minLat: $minLat, minLon: $minLon, maxLat: $maxLat, maxLon: $maxLon, zoom: $zoom, version: $version) { + query SubmissionCells( + $minLat: Float! + $minLon: Float! + $maxLat: Float! + $maxLon: Float! + $zoom: Int! + $version: String + ) { + submissionCells( + minLat: $minLat + minLon: $minLon + maxLat: $maxLat + maxLon: $maxLon + zoom: $zoom + version: $version + ) { placementCells { cells { id diff --git a/src/services/queries/user.js b/src/services/queries/user.js index ee0d58d29..47f71ea4d 100644 --- a/src/services/queries/user.js +++ b/src/services/queries/user.js @@ -1,25 +1,25 @@ import { gql } from '@apollo/client' export const setTutorial = gql` -mutation SetTutorial($tutorial: Boolean!) { + mutation SetTutorial($tutorial: Boolean!) { tutorial(tutorial: $tutorial) } ` export const setWebhookStrategy = gql` -mutation SetStrategy($strategy: String!) { + mutation SetStrategy($strategy: String!) { strategy(strategy: $strategy) } ` export const checkUsername = gql` -mutation SetUsername($username: String!) { + mutation SetUsername($username: String!) { checkUsername(username: $username) } ` export const setGymBadge = gql` -mutation SetGymBadge($gymId: String!, $badge: Int!) { + mutation SetGymBadge($gymId: String!, $badge: Int!) { setGymBadge(gymId: $gymId, badge: $badge) } ` diff --git a/src/services/queries/weather.js b/src/services/queries/weather.js index fa482a40f..731842427 100644 --- a/src/services/queries/weather.js +++ b/src/services/queries/weather.js @@ -1,16 +1,16 @@ import { gql } from '@apollo/client' const getAllWeather = gql` -query Weather($version: String) { - weather(version: $version) { - id - latitude - longitude - gameplay_condition - updated - polygon + query Weather($version: String) { + weather(version: $version) { + id + latitude + longitude + gameplay_condition + updated + polygon + } } -} ` export default getAllWeather diff --git a/src/services/queries/webhook.js b/src/services/queries/webhook.js index 59dbaa781..e2f2a0191 100644 --- a/src/services/queries/webhook.js +++ b/src/services/queries/webhook.js @@ -245,8 +245,18 @@ export const allProfiles = gql` ${Quest} ${Raid} ${Weather} - query Webhook($category: String!, $status: String!, $name: String!, $version: String) { - webhook(category: $category, status: $status, name: $name, version: $version) { + query Webhook( + $category: String! + $status: String! + $name: String! + $version: String + ) { + webhook( + category: $category + status: $status + name: $name + version: $version + ) { ...PoracleHuman ...PoracleEgg ...PoracleGym @@ -274,7 +284,12 @@ export const quickAdd = gql` ${Quest} ${Raid} ${Weather} - mutation Webhook($data: JSON!, $category: String!, $status: String!, $name: String!) { + mutation Webhook( + $data: JSON! + $category: String! + $status: String! + $name: String! + ) { webhook(data: $data, category: $category, status: $status, name: $name) { ...PoracleHuman ...PoracleEgg @@ -296,7 +311,12 @@ export const quickAdd = gql` export const setHuman = gql` ${base} ${Human} - mutation Webhook($data: JSON!, $category: String!, $status: String!, $name: String!) { + mutation Webhook( + $data: JSON! + $category: String! + $status: String! + $name: String! + ) { webhook(data: $data, category: $category, status: $status, name: $name) { ...Base ...PoracleHuman @@ -307,7 +327,12 @@ export const setHuman = gql` export const setProfile = gql` ${base} ${Profile} - mutation Webhook($data: JSON!, $category: String!, $status: String!, $name: String!) { + mutation Webhook( + $data: JSON! + $category: String! + $status: String! + $name: String! + ) { webhook(data: $data, category: $category, status: $status, name: $name) { ...Base ...PoracleProfile @@ -318,7 +343,12 @@ export const setProfile = gql` export const pokemon = gql` ${base} ${Pokemon} - mutation Webhook($data: JSON!, $category: String!, $status: String!, $name: String!) { + mutation Webhook( + $data: JSON! + $category: String! + $status: String! + $name: String! + ) { webhook(data: $data, category: $category, status: $status, name: $name) { ...Base ...PoraclePokemon @@ -329,7 +359,12 @@ export const pokemon = gql` export const raid = gql` ${base} ${Raid} - mutation Webhook($data: JSON!, $category: String!, $status: String!, $name: String!) { + mutation Webhook( + $data: JSON! + $category: String! + $status: String! + $name: String! + ) { webhook(data: $data, category: $category, status: $status, name: $name) { ...Base ...PoracleRaid @@ -340,7 +375,12 @@ export const raid = gql` export const egg = gql` ${base} ${Egg} - mutation Webhook($data: JSON!, $category: String!, $status: String!, $name: String!) { + mutation Webhook( + $data: JSON! + $category: String! + $status: String! + $name: String! + ) { webhook(data: $data, category: $category, status: $status, name: $name) { ...Base ...PoracleEgg @@ -351,7 +391,12 @@ export const egg = gql` export const gym = gql` ${base} ${Gym} - mutation Webhook($data: JSON!, $category: String!, $status: String!, $name: String!) { + mutation Webhook( + $data: JSON! + $category: String! + $status: String! + $name: String! + ) { webhook(data: $data, category: $category, status: $status, name: $name) { ...Base ...PoracleGym @@ -362,7 +407,12 @@ export const gym = gql` export const invasion = gql` ${base} ${Invasion} - mutation Webhook($data: JSON!, $category: String!, $status: String!, $name: String!) { + mutation Webhook( + $data: JSON! + $category: String! + $status: String! + $name: String! + ) { webhook(data: $data, category: $category, status: $status, name: $name) { ...Base ...PoracleInvasion @@ -373,7 +423,12 @@ export const invasion = gql` export const lure = gql` ${base} ${Lure} - mutation Webhook($data: JSON!, $category: String!, $status: String!, $name: String!) { + mutation Webhook( + $data: JSON! + $category: String! + $status: String! + $name: String! + ) { webhook(data: $data, category: $category, status: $status, name: $name) { ...Base ...PoracleLure @@ -384,7 +439,12 @@ export const lure = gql` export const nest = gql` ${base} ${Nest} - mutation Webhook($data: JSON!, $category: String!, $status: String!, $name: String!) { + mutation Webhook( + $data: JSON! + $category: String! + $status: String! + $name: String! + ) { webhook(data: $data, category: $category, status: $status, name: $name) { ...Base ...PoracleNest @@ -395,7 +455,12 @@ export const nest = gql` export const quest = gql` ${base} ${Quest} - mutation Webhook($data: JSON!, $category: String!, $status: String!, $name: String!) { + mutation Webhook( + $data: JSON! + $category: String! + $status: String! + $name: String! + ) { webhook(data: $data, category: $category, status: $status, name: $name) { ...Base ...PoracleQuest diff --git a/yarn.lock b/yarn.lock index c18082961..5b3e56fbe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1844,6 +1844,11 @@ eslint-config-airbnb@^19.0.4: object.assign "^4.1.2" object.entries "^1.1.5" +eslint-config-prettier@^8.3.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" + integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== + eslint-import-resolver-alias@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/eslint-import-resolver-alias/-/eslint-import-resolver-alias-1.1.2.tgz#297062890e31e4d6651eb5eba9534e1f6e68fc97" @@ -3749,6 +3754,11 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= +prettier@^2.6.2: + version "2.7.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" + integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== + prism-media@^1.2.9: version "1.3.2" resolved "https://registry.yarnpkg.com/prism-media/-/prism-media-1.3.2.tgz#a1f04423ec15d22f3d62b1987b6a25dc49aad13b"