Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,8 @@
"battles": false,
"gmaxStationed": false,
"interactionRanges": false,
"customRange": 0
"customRange": 0,
"inactiveStations": false
},
"s2cells": {
"enabled": false,
Expand Down
2 changes: 2 additions & 0 deletions packages/locales/lib/human/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@
"total_cp": "Total CP",
"first_seen": "First Seen",
"last_seen": "Last Seen",
"last_active": "Last active: {{time}}",
"last_modified": "Last Modified",
"last_updated": "Last Updated",
"imported": "Imported",
Expand Down Expand Up @@ -815,6 +816,7 @@
"global_search_stations": "Enter Power Spot Name or Dynamax Pokémon...",
"station_timers": "Power Spot Timers",
"stations_opacity": "Dynamic Power Spot Opacity",
"inactive_power_spots": "Inactive Power Spots",
"max_battles": "Max Battles",
"dynamax": "Dynamax",
"stations_subtitle": "Displays Power Spots on the map",
Expand Down
3 changes: 3 additions & 0 deletions server/src/filters/builder/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ function buildDefaultFilters(perms) {
gmaxStationed: perms.dynamax
? defaultFilters.stations.gmaxStationed
: undefined,
inactiveStations: perms.stations
? defaultFilters.stations.inactiveStations
: undefined,
}
: undefined,
pokemon:
Expand Down
123 changes: 84 additions & 39 deletions server/src/models/Station.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Station extends Model {
onlyMaxBattles,
onlyBattleTier,
onlyGmaxStationed,
onlyInactiveStations,
} = args.filters
const ts = getEpoch()
const select = [
Expand Down Expand Up @@ -132,47 +133,91 @@ class Station extends Model {
if (!getAreaSql(query, areaRestrictions, onlyAreas, isMad)) {
return []
}
/** @type {import("@rm/types").FullStation[]} */
const results = await query.select(select)

return results
.map((station) => {
if (station.is_battle_available && station.battle_pokemon_id === null) {
station.is_battle_available = false
}
if (station.total_stationed_pokemon === null) {
station.total_stationed_pokemon = 0
}
if (
station.stationed_pokemon &&
(station.total_stationed_gmax === undefined ||
station.total_stationed_gmax === null)
) {
const list =
typeof station.stationed_pokemon === 'string'
? JSON.parse(station.stationed_pokemon)
: station.stationed_pokemon || []
let count = 0
if (list)
for (let i = 0; i < list.length; ++i)
if (list[i].bread_mode === 2 || list[i].bread_mode === 3) ++count
station.total_stationed_gmax = count
}
return station
})
.filter(
(station) =>
onlyAllStations ||
(perms.dynamax &&
((onlyMaxBattles &&
(onlyBattleTier === 'all'
? args.filters[`j${station.battle_level}`] ||
args.filters[
`${station.battle_pokemon_id}-${station.battle_pokemon_form}`
]
: onlyBattleTier === station.battle_level)) ||
(onlyGmaxStationed && station.total_stationed_gmax))),
const normalizeStation = (station) => {
if (station.is_battle_available && station.battle_pokemon_id === null) {
station.is_battle_available = false
}
if (station.total_stationed_pokemon === null) {
station.total_stationed_pokemon = 0
}
if (
station.stationed_pokemon &&
(station.total_stationed_gmax === undefined ||
station.total_stationed_gmax === null)
) {
const list =
typeof station.stationed_pokemon === 'string'
? JSON.parse(station.stationed_pokemon)
: station.stationed_pokemon || []
let count = 0
if (list)
for (let i = 0; i < list.length; ++i)
if (list[i].bread_mode === 2 || list[i].bread_mode === 3) ++count
station.total_stationed_gmax = count
}
return station
}

const shouldInclude = (station) => {
const isInactive =
Number.isFinite(station.end_time) && station.end_time <= ts
if (onlyInactiveStations && isInactive) {
return true
}
if (onlyAllStations) {
return true
}
return (
perms.dynamax &&
((onlyMaxBattles &&
(onlyBattleTier === 'all'
? args.filters[`j${station.battle_level}`] ||
args.filters[
`${station.battle_pokemon_id}-${station.battle_pokemon_form}`
]
: onlyBattleTier === station.battle_level)) ||
(onlyGmaxStationed && station.total_stationed_gmax))
Comment thread
Mygod marked this conversation as resolved.
Outdated
)
}

/** @type {import("@rm/types").FullStation[]} */
const activeResults = (await query.select(select))
.map(normalizeStation)
.filter(shouldInclude)

if (!onlyInactiveStations) {
return activeResults
}

const inactiveQuery = this.query()
applyManualIdFilter(inactiveQuery, {
manualId: args.filters.onlyManualId,
latColumn: 'lat',
lonColumn: 'lon',
idColumn: 'id',
bounds: {
minLat: args.minLat,
maxLat: args.maxLat,
minLon: args.minLon,
maxLon: args.maxLon,
},
})
inactiveQuery.andWhere('end_time', '<=', ts)

if (!getAreaSql(inactiveQuery, areaRestrictions, onlyAreas, isMad)) {
return activeResults
}

const inactiveResults = (await inactiveQuery.select(select))
.map(normalizeStation)
.filter(shouldInclude)

const combined = new Map()
activeResults.forEach((station) => combined.set(station.id, station))
inactiveResults.forEach((station) => combined.set(station.id, station))
Comment thread
Mygod marked this conversation as resolved.
Outdated

return [...combined.values()]
}

/**
Expand Down
1 change: 1 addition & 0 deletions server/src/ui/drawer.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ function drawer(req, perms) {
allStations: perms.stations || BLOCKED,
maxBattles: perms.dynamax || BLOCKED,
gmaxStationed: perms.dynamax || BLOCKED,
inactiveStations: perms.stations || BLOCKED,
}
: BLOCKED,
pokemon:
Expand Down
37 changes: 30 additions & 7 deletions src/features/station/StationPopup.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -355,17 +355,40 @@ function StationAttackBonus({ total_stationed_pokemon, total_stationed_gmax }) {

/** @param {import('@rm/types').Station} station */
function StationContent({ start_time, end_time, battle_end, id }) {
const { t } = useTranslation()
const dateFormatter = useFormatStore((s) => s.dateFormat)
const now = Date.now() / 1000
const isFutureStart = start_time > now
const hasEndTime = Number.isFinite(end_time)
const endEpoch = hasEndTime ? end_time : 0
const isInactive = hasEndTime && endEpoch < now

if (isInactive) {
const formatted = hasEndTime
? dateFormatter.format(new Date(endEpoch * 1000))
: '—'
Comment thread
Mygod marked this conversation as resolved.
Outdated
return (
<CardContent sx={{ p: 0 }}>
<Stack alignItems="center" justifyContent="center">
<Typography variant="subtitle2">{t('inactive')}</Typography>
<Typography variant="caption">
{t('last_active', { time: formatted })}
</Typography>
</Stack>
</CardContent>
)
}

const hasStartTime = Number.isFinite(start_time)
const startEpoch = hasStartTime ? start_time : 0
const isFutureStart = hasStartTime && startEpoch > now
const displayInactiveOnly =
Number.isFinite(battle_end) &&
Number.isFinite(end_time) &&
battle_end === end_time
Number.isFinite(battle_end) && hasEndTime && battle_end === endEpoch
const epoch = displayInactiveOnly
? (end_time ?? 0)
? endEpoch || 0
: isFutureStart
? (start_time ?? 0)
: (end_time ?? 0)
? startEpoch || 0
: endEpoch || 0
Comment thread
Mygod marked this conversation as resolved.
Outdated
Comment thread
Mygod marked this conversation as resolved.
Outdated

return (
<CardContent sx={{ p: 0 }}>
<Stack alignItems="center" justifyContent="center">
Expand Down
14 changes: 11 additions & 3 deletions src/features/station/useStationMarker.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ export function useStationMarker({
start_time,
end_time,
}) {
const now = Date.now() / 1000
const isInactive = Number.isFinite(end_time) && end_time < now
const hasStarted = Number.isFinite(start_time) && start_time < now
Comment thread
Mygod marked this conversation as resolved.
const [, Icons] = useStorage(
(s) => [s.icons, useMemory.getState().Icons],
(a, b) => Object.entries(a[0]).every(([k, v]) => b[0][k] === v),
)
const [baseIcon, baseSize, battleIcon, battleSize] = useStorage((s) => {
const { filter } = s.filters.stations
return [
Icons.getStation(start_time < Date.now() / 1000),
Icons.getStation(isInactive ? false : hasStarted),
Icons.getSize('station', filter[`j${battle_level}`]?.size),
Icons.getPokemon(
battle_pokemon_id,
Expand All @@ -47,8 +50,13 @@ export function useStationMarker({
]
}, basicEqualFn)
const [stationMod, battleMod] = Icons.getModifiers('station', 'dynamax')
const opacity = useOpacity('stations')(end_time)
const isActive = !!battle_pokemon_id && start_time < Date.now() / 1000
const dynamicOpacity = useOpacity('stations')(end_time)
const opacity = isInactive ? 0.3 : dynamicOpacity
const isActive =
!isInactive &&
!!battle_pokemon_id &&
Number.isFinite(start_time) &&
start_time < now
Comment thread
Mygod marked this conversation as resolved.

return divIcon({
popupAnchor: [
Expand Down
3 changes: 3 additions & 0 deletions src/pages/map/components/QueryData.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ const trimFilters = (requestedFilters, userSettings, category, onlyAreas) => {
entryV
}
})
if (category === 'stations' && requestedFilters?.inactiveStations) {
trimmed.onlyInactiveStations = true
}
Object.entries(requestedFilters?.filter || {}).forEach(([id, specifics]) => {
// eslint-disable-next-line no-unused-vars
const { enabled, size, ...rest } = (easyMode
Expand Down
1 change: 1 addition & 0 deletions src/pages/map/hooks/usePermCheck.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export function usePermCheck(category) {
case 'stations':
if (
(filters?.allStations && perms?.stations) ||
(filters?.inactiveStations && perms?.stations) ||
(filters?.maxBattles && perms?.dynamax) ||
(filters?.gmaxStationed && perms?.dynamax)
) {
Expand Down
Loading