diff --git a/src/App.vue b/src/App.vue index 12b1547..4c460c1 100644 --- a/src/App.vue +++ b/src/App.vue @@ -32,20 +32,19 @@ diff --git a/src/components/SceneryView/SceneryInfo/SceneryInfoDispatcher.vue b/src/components/SceneryView/SceneryInfo/SceneryInfoDispatcher.vue index a834a1b..bfe9659 100644 --- a/src/components/SceneryView/SceneryInfo/SceneryInfoDispatcher.vue +++ b/src/components/SceneryView/SceneryInfo/SceneryInfoDispatcher.vue @@ -1,35 +1,30 @@ - + - {{ station.onlineInfo.dispatcherExp > 1 ? station.onlineInfo.dispatcherExp : 'L' }} + {{ onlineScenery.dispatcherExp > 1 ? onlineScenery.dispatcherExp : 'L' }} - {{ station.onlineInfo.dispatcherName }} + {{ onlineScenery.dispatcherName }} - {{ station.onlineInfo?.dispatcherRate || '0' }} + {{ onlineScenery?.dispatcherRate || '0' }} @@ -39,19 +34,15 @@ import { PropType, defineComponent } from 'vue'; import dateMixin from '../../../mixins/dateMixin'; import routerMixin from '../../../mixins/routerMixin'; import styleMixin from '../../../mixins/styleMixin'; -import Station from '../../../scripts/interfaces/Station'; import StationStatusBadge from '../../Global/StationStatusBadge.vue'; +import { OnlineScenery } from '../../../scripts/interfaces/store/storeTypes'; export default defineComponent({ mixins: [styleMixin, dateMixin, routerMixin], props: { - station: { - type: Object as PropType, - required: true - }, - onlineFrom: { - type: Number, - default: -1 + onlineScenery: { + type: Object as PropType, + required: false } }, components: { StationStatusBadge } diff --git a/src/components/SceneryView/SceneryInfo/SceneryInfoSpawnList.vue b/src/components/SceneryView/SceneryInfo/SceneryInfoSpawnList.vue index 0f0a245..885918d 100644 --- a/src/components/SceneryView/SceneryInfo/SceneryInfoSpawnList.vue +++ b/src/components/SceneryView/SceneryInfo/SceneryInfoSpawnList.vue @@ -3,14 +3,14 @@ {{ $t('scenery.spawns') }} - {{ station.onlineInfo?.spawns.length || '0' }} + {{ onlineScenery?.spawns.length || '0' }} - + {{ spawn.spawnName }} @@ -18,9 +18,7 @@ - {{ $t('scenery.no-spawns') }} @@ -28,21 +26,21 @@ diff --git a/src/components/SceneryView/SceneryTimetable.vue b/src/components/SceneryView/SceneryTimetable.vue index 3579f2d..4894c79 100644 --- a/src/components/SceneryView/SceneryTimetable.vue +++ b/src/components/SceneryView/SceneryTimetable.vue @@ -6,14 +6,12 @@ {{ $t('scenery.timetables') }} - {{ - station.onlineInfo?.scheduledTrains?.length || '0' - }} + {{ onlineScenery?.scheduledTrains?.length || '0' }} / {{ - station.onlineInfo?.scheduledTrains?.filter((train) => train.stopInfo.confirmed) - .length || '0' + onlineScenery?.scheduledTrains?.filter((train) => train.stopInfo.confirmed).length || + '0' }} @@ -59,7 +57,7 @@ {{ $t('scenery.offline') }} @@ -186,6 +184,7 @@ import Station from '../../scripts/interfaces/Station'; import { useStore } from '../../store/store'; import modalTrainMixin from '../../mixins/modalTrainMixin'; import ScheduledTrainStatus from './ScheduledTrainStatus.vue'; +import { OnlineScenery } from '../../scripts/interfaces/store/storeTypes'; export default defineComponent({ name: 'SceneryTimetable', @@ -199,9 +198,9 @@ export default defineComponent({ type: Object as PropType, required: true }, - - timetableOnly: { - type: Boolean + onlineScenery: { + type: Object as PropType, + required: false } }, @@ -229,36 +228,9 @@ export default defineComponent({ : props.station?.generalInfo?.checkpoints[0].checkpointName || null ); - const computedScheduledTrains = computed(() => { - if (!props.station) return []; - - const station = props.station as Station; - - let scheduledTrains = - station.generalInfo?.checkpoints.find((cp) => cp.checkpointName === chosenCheckpoint.value) - ?.scheduledTrains || - station.onlineInfo?.scheduledTrains || - []; - - if (!scheduledTrains) return []; - - return ( - scheduledTrains.sort((a, b) => { - if (a.stopStatusID > b.stopStatusID) return 1; - if (a.stopStatusID < b.stopStatusID) return -1; - - if (a.stopInfo.arrivalTimestamp > b.stopInfo.arrivalTimestamp) return 1; - if (a.stopInfo.arrivalTimestamp < b.stopInfo.arrivalTimestamp) return -1; - - return a.stopInfo.departureTimestamp > b.stopInfo.departureTimestamp ? 1 : -1; - }) || [] - ); - }); - return { currentURL, chosenCheckpoint, - computedScheduledTrains, store }; }, @@ -269,27 +241,37 @@ export default defineComponent({ if (this.chosenCheckpoint) url += `&checkpoint=${this.chosenCheckpoint}`; return url; + }, + + computedScheduledTrains() { + return ( + this.onlineScenery?.scheduledTrains + ?.filter( + (train) => + train.checkpointName.toLocaleLowerCase() == + (this.chosenCheckpoint || this.station.name).toLocaleLowerCase() + ) + .sort((a, b) => { + if (a.stopStatusID > b.stopStatusID) return 1; + if (a.stopStatusID < b.stopStatusID) return -1; + + if (a.stopInfo.arrivalTimestamp > b.stopInfo.arrivalTimestamp) return 1; + if (a.stopInfo.arrivalTimestamp < b.stopInfo.arrivalTimestamp) return -1; + + return a.stopInfo.departureTimestamp > b.stopInfo.departureTimestamp ? 1 : -1; + }) || [] + ); } }, methods: { loadSelectedOption() { - if (!this.station) return; - if (!this.station.generalInfo) return; - if (!this.station.generalInfo.checkpoints) return; - if (this.station.generalInfo.checkpoints.length == 0) return; - - if (this.chosenCheckpoint != '') return; - - this.chosenCheckpoint = this.station.generalInfo.checkpoints[0].checkpointName; + this.chosenCheckpoint = + this.station.generalInfo?.checkpoints[0]?.checkpointName || this.station.name; }, setCheckpoint(cp: { checkpointName: string }) { this.chosenCheckpoint = cp.checkpointName; - }, - - showTimetableOnlyView() { - this.$router.push(`${this.$route.fullPath}&timetableOnly=1`); } } }); diff --git a/src/components/SceneryView/SceneryTimetablesHistory.vue b/src/components/SceneryView/SceneryTimetablesHistory.vue index 14aff15..be45b1d 100644 --- a/src/components/SceneryView/SceneryTimetablesHistory.vue +++ b/src/components/SceneryView/SceneryTimetablesHistory.vue @@ -65,6 +65,7 @@ import Station from '../../scripts/interfaces/Station'; import { URLs } from '../../scripts/utils/apiURLs'; import Loading from '../Global/Loading.vue'; import listObserverMixin from '../../mixins/listObserverMixin'; +import { OnlineScenery } from '../../scripts/interfaces/store/storeTypes'; export default defineComponent({ name: 'SceneryTimetablesHistory', @@ -73,6 +74,10 @@ export default defineComponent({ station: { type: Object as PropType, required: true + }, + onlineScenery: { + type: Object as PropType, + required: false } }, diff --git a/src/components/StationsView/FilterOption.vue b/src/components/StationsView/FilterOption.vue index 7bfeb3e..5376db0 100644 --- a/src/components/StationsView/FilterOption.vue +++ b/src/components/StationsView/FilterOption.vue @@ -1,8 +1,8 @@ - + - + @@ -234,7 +242,7 @@ @@ -244,20 +252,23 @@ {{ - station.onlineInfo?.scheduledTrains?.filter((train) => !train.stopInfo.confirmed) - .length || 0 + new Set([ + ...(station.onlineInfo?.scheduledTrains + ?.filter((train) => !train.stopInfo.confirmed) + .map((train) => train.checkpointName) || []) + ]).size || 0 }} @@ -336,9 +347,13 @@ export default defineComponent({ if (!station) return; this.lastSelectedStationName = station.name; + this.$router.push({ name: 'SceneryView', - query: { station: station.name.replaceAll(' ', '_') } + query: { + station: station.name.replaceAll(' ', '_'), + region: this.$route.query.region || undefined + } }); }, diff --git a/src/main.ts b/src/main.ts index 174bf24..eec3e7f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,6 +7,7 @@ import plLang from './locales/pl.json'; import { createI18n } from 'vue-i18n'; import { createPinia } from 'pinia'; +import useCustomSW from './mixins/useCustomSW'; const i18n = createI18n({ locale: 'pl', @@ -20,6 +21,9 @@ const i18n = createI18n({ enableLegacy: false }); +// SW +useCustomSW(); + const clickOutsideDirective: Directive = { mounted(el, binding) { el.clickOutsideEvent = (event: Event) => { diff --git a/src/router/index.ts b/src/router/index.ts index 4deff23..85573f5 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -6,7 +6,10 @@ const routes: Array = [ { path: '/', name: 'StationsView', - component: () => import('../views/StationsView.vue') + component: () => import('../views/StationsView.vue'), + props: (route) => ({ + region: route.query.region + }) }, { path: '/trains', @@ -21,7 +24,11 @@ const routes: Array = [ { path: '/scenery', name: 'SceneryView', - component: () => import('../views/SceneryView.vue') + component: () => import('../views/SceneryView.vue'), + props: (route) => ({ + region: route.query.region, + station: route.query.station + }) }, { path: '/journal', @@ -53,9 +60,11 @@ const routes: Array = [ ]; const router = createRouter({ - scrollBehavior(to, from) { + scrollBehavior(to, from, savedPosition) { if (to.name == 'SceneryView' && from.name) return { el: `.app_main` }; + if (savedPosition) return savedPosition; + // if (from.name == 'SceneryView' && to.name == 'StationsView') return { el: `.last-selected`, top: 20 }; }, history: createWebHistory(), diff --git a/src/scripts/interfaces/ScheduledTrain.ts b/src/scripts/interfaces/ScheduledTrain.ts index 7d94a34..1637eb4 100644 --- a/src/scripts/interfaces/ScheduledTrain.ts +++ b/src/scripts/interfaces/ScheduledTrain.ts @@ -10,6 +10,8 @@ export enum StopStatus { } export interface ScheduledTrain { + checkpointName: string; + trainId: string; trainNo: number; diff --git a/src/scripts/interfaces/store/storeTypes.ts b/src/scripts/interfaces/store/storeTypes.ts index 09e3ffe..6a58609 100644 --- a/src/scripts/interfaces/store/storeTypes.ts +++ b/src/scripts/interfaces/store/storeTypes.ts @@ -2,17 +2,16 @@ import { Socket } from 'socket.io-client'; import { DataStatus } from '../../enums/DataStatus'; import StationAPIData from '../api/StationAPIData'; import { TrainAPIData } from '../api/TrainAPIData'; -import Station from '../Station'; -import Train from '../Train'; import { DispatcherStatsAPIData } from '../api/DispatcherStatsAPIData'; import { DriverStatsAPIData } from '../api/DriverStatsAPIData'; import { RollingStockGithubData } from '../github_api/StockInfoGithubData'; +import Station from '../Station'; +import { ScheduledTrain } from '../ScheduledTrain'; export type Availability = 'default' | 'unavailable' | 'nonPublic' | 'abandoned' | 'nonDefault'; export interface StoreState { stationList: Station[]; - trainList: Train[]; apiData: APIData; rollingStockData?: RollingStockGithubData; @@ -91,3 +90,31 @@ export interface StationJSONData { availability: Availability; } + +export interface StationTrain { + driverName: string; + driverId: number; + trainNo: number; + trainId: string; + stopStatus: string; +} + +export interface OnlineScenery { + name: string; + hash: string; + region: string; + maxUsers: number; + currentUsers: number; + spawns: { spawnName: string; spawnLength: number; isElectrified: boolean }[]; + dispatcherName: string; + dispatcherRate: number; + dispatcherId: number; + dispatcherExp: number; + dispatcherIsSupporter: boolean; + + statusTimestamp: number; + statusID: string; + + stationTrains?: StationTrain[]; + scheduledTrains?: ScheduledTrain[]; +} diff --git a/src/scripts/utils/storeUtils.ts b/src/scripts/utils/storeUtils.ts index 81d681f..e1d09c2 100644 --- a/src/scripts/utils/storeUtils.ts +++ b/src/scripts/utils/storeUtils.ts @@ -1,6 +1,9 @@ import { ScheduledTrain, StopStatus } from '../interfaces/ScheduledTrain'; +import Station from '../interfaces/Station'; import Train from '../interfaces/Train'; import TrainStop from '../interfaces/TrainStop'; +import StationAPIData from '../interfaces/api/StationAPIData'; +import { StationTrain, StoreState } from '../interfaces/store/storeTypes'; export const getLocoURL = (locoType: string): string => `https://rj.td2.info.pl/dist/img/thumbnails/${ @@ -79,7 +82,7 @@ export const getTimestamp = (date: string | null): number => (date ? new Date(da export const getTrainStopStatus = ( stopInfo: TrainStop, currentStationName: string, - stationName: string + sceneryName: string ) => { let stopStatus = StopStatus['arriving'], stopLabel = '', @@ -89,23 +92,23 @@ export const getTrainStopStatus = ( stopStatus = StopStatus['terminated']; stopLabel = 'Skończył bieg'; stopStatusID = 5; - } else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName == stationName) { + } else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName == sceneryName) { stopStatus = StopStatus['departed']; stopLabel = 'Odprawiony'; stopStatusID = 2; - } else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName != stationName) { + } else if (!stopInfo.terminatesHere && stopInfo.confirmed && currentStationName != sceneryName) { stopStatus = StopStatus['departed-away']; stopLabel = 'Odjechał'; stopStatusID = 4; - } else if (currentStationName == stationName && !stopInfo.stopped) { + } else if (currentStationName == sceneryName && !stopInfo.stopped) { stopStatus = StopStatus['online']; stopLabel = 'Na stacji'; stopStatusID = 0; - } else if (currentStationName == stationName && stopInfo.stopped) { + } else if (currentStationName == sceneryName && stopInfo.stopped) { stopStatus = StopStatus['stopped']; stopLabel = 'Postój'; stopStatusID = 1; - } else if (currentStationName != stationName) { + } else if (currentStationName != sceneryName) { stopStatus = StopStatus['arriving']; stopLabel = 'W drodze'; stopStatusID = 3; @@ -114,16 +117,16 @@ export const getTrainStopStatus = ( return { stopStatus, stopLabel, stopStatusID }; }; -export function getScheduledTrain( +export function getCheckpointTrain( train: Train, trainStopIndex: number, - stationName: string + sceneryName: string ): ScheduledTrain { const timetable = train.timetableData!; const followingStops = timetable.followingStops; const trainStop = followingStops[trainStopIndex]; - const trainStopStatus = getTrainStopStatus(trainStop, train.currentStationName, stationName); + const trainStopStatus = getTrainStopStatus(trainStop, train.currentStationName, sceneryName); let prevStationName = '', nextStationName = ''; @@ -177,6 +180,8 @@ export function getScheduledTrain( } return { + checkpointName: trainStop.stopNameRAW, + trainNo: train.trainNo, trainId: train.trainId, @@ -206,3 +211,119 @@ export function getScheduledTrain( prevDepartureLine }; } + +export function getDispatcherStatus(state: StoreState, onlineStationData: StationAPIData) { + const { dispatchers } = state.apiData; + + const prevDispatcherStatus = state.lastDispatcherStatuses.find( + (dispatcher) => dispatcher.hash === onlineStationData.stationHash + ); + + const stationStatus = !dispatchers + ? undefined + : dispatchers.find( + (status: string[]) => + status[0] == onlineStationData.stationHash && status[1] == state.region.id + ) || -1; + + const statusTimestamp = + prevDispatcherStatus && !dispatchers + ? prevDispatcherStatus.statusTimestamp + : getStatusTimestamp(stationStatus); + + const statusID = + prevDispatcherStatus && !dispatchers + ? prevDispatcherStatus.statusID + : getStatusID(stationStatus); + + return { + hash: onlineStationData.stationHash, + statusID, + statusTimestamp + }; +} + +export function getScheduledTrains( + trainList: Train[], + stationAPIData: StationAPIData, + stationGeneralInfo: Station['generalInfo'] +): ScheduledTrain[] { + const stationName = stationAPIData.stationName.toLocaleLowerCase(); + + stationGeneralInfo?.checkpoints.forEach((cp) => (cp.scheduledTrains.length = 0)); + + return trainList.reduce((acc: ScheduledTrain[], train) => { + if (!train.timetableData) return acc; + + const timetable = train.timetableData; + if (!timetable.sceneries.includes(stationAPIData.stationHash)) return acc; + + const stopInfoIndex = timetable.followingStops.findIndex((stop) => { + const stopName = stop.stopNameRAW.toLowerCase(); + + return ( + stationName == stopName || + (!/(po\.|podg\.)/.test(stationName) && stopName.includes(stationName)) || + (!/(po\.|podg\.)/.test(stopName) && stationName.includes(stopName)) || + (stopName.split(', podg.')[0] !== undefined && + stationName.startsWith(stopName.split(', podg.')[0])) + ); + }); + + const checkpointScheduledTrains: ScheduledTrain[] = []; + + if (stopInfoIndex != -1) { + checkpointScheduledTrains.push( + getCheckpointTrain(train, stopInfoIndex, stationAPIData.stationName) + ); + } + + stationGeneralInfo?.checkpoints?.forEach((checkpoint) => { + if (checkpoint.checkpointName.toLocaleLowerCase() == stationName) return; + + if ( + checkpointScheduledTrains.findIndex( + (cpTrain) => + cpTrain.checkpointName.toLocaleLowerCase() == + checkpoint.checkpointName.toLocaleLowerCase() + ) != -1 + ) + return; + + const index = timetable.followingStops.findIndex( + (stop) => stop.stopNameRAW.toLowerCase() == checkpoint.checkpointName.toLowerCase() + ); + + if (index > -1) + checkpointScheduledTrains.push( + getCheckpointTrain(train, index, stationAPIData.stationName) + ); + }); + + acc.push(...checkpointScheduledTrains); + return acc; + }, []) as ScheduledTrain[]; +} + +export function getStationTrains( + trainList: Train[], + scheduledTrainList: ScheduledTrain[], + region: string, + apiStation: StationAPIData +): StationTrain[] { + return trainList + .filter( + (train) => + train?.region === region && + train.online && + train.currentStationName === apiStation.stationName + ) + .map((train) => ({ + driverName: train.driverName, + driverId: train.driverId, + trainNo: train.trainNo, + trainId: train.trainId, + stopStatus: + scheduledTrainList.find((st) => st.trainNo === train.trainNo)?.stopStatus || 'no-timetable' + })); +} diff --git a/src/store/stationFiltersStore.ts b/src/store/stationFiltersStore.ts index 501922c..e778449 100644 --- a/src/store/stationFiltersStore.ts +++ b/src/store/stationFiltersStore.ts @@ -1,6 +1,5 @@ import { defineStore } from 'pinia'; import inputData from '../data/options.json'; -import Station from '../scripts/interfaces/Station'; import StorageManager from '../scripts/managers/storageManager'; import { useStore } from './store'; import { filterInitStates } from '../scripts/constants/stores/initFilterStates'; @@ -13,31 +12,28 @@ export const useStationFiltersStore = defineStore('stationFiltersStore', { inputs: inputData, filters: { ...filterInitStates }, sorterActive: { headerName: 'station' as HeadIdsTypes, dir: 1 }, - store: useStore(), lastClickedFilterId: '' }; }, getters: { - areFiltersAtDefault(state) { + areFiltersAtDefault: (state) => { return Object.keys(state.filters).every((f) => state.filters[f] === filterInitStates[f]); + }, + + filteredStationList: (state) => { + const store = useStore(); + return store.stationList + .map((station) => ({ + ...station, + onlineInfo: store.onlineSceneryList.find((os) => os.name == station.name) + })) + .filter((station) => filterStations(station, state.filters)) + .sort((a, b) => sortStations(a, b, state.sorterActive)); } }, actions: { - getFilteredStationList(stationList: Station[], region: string): Station[] { - return stationList - .map((station) => { - if (station.onlineInfo && station.onlineInfo.region != region) { - delete station.onlineInfo; - } - - return station; - }) - .filter((station) => filterStations(station, this.filters)) - .sort((a, b) => sortStations(a, b, this.sorterActive)); - }, - setupFilters() { if (!StorageManager.isRegistered('options_saved')) return; diff --git a/src/store/store.ts b/src/store/store.ts index 337bd35..fc7ebb9 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -9,12 +9,18 @@ import StationRoutes from '../scripts/interfaces/StationRoutes'; import Train from '../scripts/interfaces/Train'; import { URLs } from '../scripts/utils/apiURLs'; import { - getStatusTimestamp, - getStatusID, - getScheduledTrain, - parseSpawns + getDispatcherStatus, + getCheckpointTrain, + parseSpawns, + getScheduledTrains, + getStationTrains } from '../scripts/utils/storeUtils'; -import { APIData, StationJSONData, StoreState } from '../scripts/interfaces/store/storeTypes'; +import { + APIData, + OnlineScenery, + StationJSONData, + StoreState +} from '../scripts/interfaces/store/storeTypes'; import packageInfo from '../../package.json'; import { RollingStockGithubData } from '../scripts/interfaces/github_api/StockInfoGithubData'; @@ -25,7 +31,7 @@ export const useStore = defineStore('store', { rollingStockData: undefined, stationList: [], - trainList: [], + routesList: [], sceneryData: [], @@ -63,13 +69,9 @@ export const useStore = defineStore('store', { modalLastClickedTarget: null }) as StoreState, - actions: { - setTrainsOnlineData() { - const { trains } = this.apiData; - - if (!trains) return []; - - this.trainList = trains + getters: { + trainList(): Train[] { + return (this.apiData?.trains ?? []) .filter( (train) => train.region === this.region.id && @@ -123,193 +125,113 @@ export const useStore = defineStore('store', { }); }, - getDispatcherStatus(onlineStationData: StationAPIData) { - const { dispatchers } = this.apiData; + onlineSceneryList(state): OnlineScenery[] { + if (state.isOffline) return []; + if (!state.apiData?.stations) return []; - const prevDispatcherStatus = this.lastDispatcherStatuses.find( - (dispatcher) => dispatcher.hash === onlineStationData.stationHash - ); + return state.apiData?.stations + ?.filter((apiStation) => apiStation.region == state.region.id && apiStation.isOnline) + .map((apiStation) => { + const dispatcherStatus = getDispatcherStatus(state as StoreState, apiStation); + const station = this.stationList.find((s) => s.name === apiStation.stationName); - const stationStatus = !dispatchers - ? undefined - : dispatchers.find( - (status: string[]) => - status[0] == onlineStationData.stationHash && status[1] == this.region.id - ) || -1; + const scheduledTrains = getScheduledTrains( + this.trainList, + apiStation, + station?.generalInfo + ); - const statusTimestamp = - prevDispatcherStatus && !dispatchers - ? prevDispatcherStatus.statusTimestamp - : getStatusTimestamp(stationStatus); - const statusID = - prevDispatcherStatus && !dispatchers - ? prevDispatcherStatus.statusID - : getStatusID(stationStatus); + const stationTrains = getStationTrains( + this.trainList, + scheduledTrains, + this.region.id, + apiStation + ); - return { - hash: onlineStationData.stationHash, - statusID, - statusTimestamp - }; - }, - - getScheduledTrains(stationGeneralInfo: Station['generalInfo'], stationAPIData: StationAPIData) { - const stationName = stationAPIData.stationName.toLowerCase(); - - stationGeneralInfo?.checkpoints.forEach((cp) => (cp.scheduledTrains.length = 0)); - - return this.trainList.reduce((acc: ScheduledTrain[], train) => { - if (!train.timetableData) return acc; - - const timetable = train.timetableData; - if (!timetable.sceneries.includes(stationAPIData.stationHash)) return acc; - - const stopInfoIndex = timetable.followingStops.findIndex((stop) => { - const stopName = stop.stopNameRAW.toLowerCase(); - - if (stationName === stopName) return true; - if ( - stopName.includes(stationName) && - !stop.stopName.includes('po.') && - !stop.stopName.includes('podg.') - ) - return true; - - if ( - stationName.includes(stopName) && - !stop.stopName.includes('po.') && - !stop.stopName.includes('podg.') - ) - return true; - - if ( - stopName.includes('podg.') && - stopName.split(', podg.')[0] && - stationName.includes(stopName.split(', podg.')[0]) - ) - return true; - - if ( - stationGeneralInfo && - stationGeneralInfo.checkpoints && - stationGeneralInfo.checkpoints.length > 0 && - stationGeneralInfo.checkpoints.some((cp) => - cp.checkpointName.toLowerCase().includes(stop.stopNameRAW.toLowerCase()) - ) - ) - return true; - - return false; + return { + name: apiStation.stationName, + hash: apiStation.stationHash, + region: apiStation.region, + maxUsers: apiStation.maxUsers, + currentUsers: apiStation.currentUsers, + spawns: parseSpawns(apiStation.spawnString), + dispatcherName: apiStation.dispatcherName, + dispatcherRate: apiStation.dispatcherRate, + dispatcherId: apiStation.dispatcherId, + dispatcherExp: apiStation.dispatcherExp, + dispatcherIsSupporter: apiStation.dispatcherIsSupporter, + scheduledTrains: scheduledTrains, + stationTrains: stationTrains, + statusTimestamp: dispatcherStatus.statusTimestamp, + statusID: dispatcherStatus.statusID + }; }); + } + }, + actions: { + // setStationsOnlineInfo() { + // const onlineStationNames: string[] = []; + // const prevDispatcherStatuses: StoreState['lastDispatcherStatuses'] = []; - if (stopInfoIndex == -1) return acc; + // if (this.isOffline) { + // this.stationList.forEach((station) => { + // station.onlineInfo = undefined; + // }); - const scheduledStopTrain = getScheduledTrain( - train, - stopInfoIndex, - stationAPIData.stationName - ); + // return; + // } - if (stationGeneralInfo?.checkpoints) { - for (const checkpoint of stationGeneralInfo.checkpoints) { - const index = timetable.followingStops.findIndex( - (stop) => stop.stopNameRAW.toLowerCase() == checkpoint.checkpointName.toLowerCase() - ); + // this.apiData.stations?.forEach((stationAPIData) => { + // if (stationAPIData.region !== this.region.id || !stationAPIData.isOnline) return; - if (index == -1) continue; + // const station = this.stationList.find((s) => s.name === stationAPIData.stationName); - const scheduledCheckpointTrain = getScheduledTrain( - train, - index, - stationAPIData.stationName - ); - checkpoint.scheduledTrains.push(scheduledCheckpointTrain); - } - } + // onlineStationNames.push(stationAPIData.stationName); - acc.push(scheduledStopTrain); - return acc; - }, []) as ScheduledTrain[]; - }, + // const dispatcherStatus = this.getDispatcherStatus(stationAPIData); + // prevDispatcherStatuses.push(dispatcherStatus); - getStationTrains(stationAPIData: StationAPIData) { - return this.trainList - .filter( - (train) => - train?.region === this.region.id && - train.online && - train.currentStationName === stationAPIData.stationName - ) - .map((train) => ({ - driverName: train.driverName, - driverId: train.driverId, - trainNo: train.trainNo, - trainId: train.trainId - })); - }, + // const stationTrains = this.getStationTrains(stationAPIData); + // const scheduledTrains = this.getScheduledTrains(station?.generalInfo, stationAPIData); - setStationsOnlineInfo() { - const onlineStationNames: string[] = []; - const prevDispatcherStatuses: StoreState['lastDispatcherStatuses'] = []; + // const onlineInfo = { + // name: stationAPIData.stationName, + // hash: stationAPIData.stationHash, + // region: stationAPIData.region, + // maxUsers: stationAPIData.maxUsers, + // currentUsers: stationAPIData.currentUsers, + // spawns: parseSpawns(stationAPIData.spawnString), + // dispatcherName: stationAPIData.dispatcherName, + // dispatcherRate: stationAPIData.dispatcherRate, + // dispatcherId: stationAPIData.dispatcherId, + // dispatcherExp: stationAPIData.dispatcherExp, + // dispatcherIsSupporter: stationAPIData.dispatcherIsSupporter, + // stationTrains, + // statusTimestamp: dispatcherStatus.statusTimestamp, + // statusID: dispatcherStatus.statusID, + // scheduledTrains + // }; - if (this.isOffline) { - this.stationList.forEach((station) => { - station.onlineInfo = undefined; - }); + // if (!station) { + // this.stationList.push({ + // name: stationAPIData.stationName, + // onlineInfo + // }); - return; - } + // return; + // } - this.apiData.stations?.forEach((stationAPIData) => { - if (stationAPIData.region !== this.region.id || !stationAPIData.isOnline) return; - const station = this.stationList.find((s) => s.name === stationAPIData.stationName); + // station.onlineInfo = { ...onlineInfo }; + // }); - onlineStationNames.push(stationAPIData.stationName); + // this.stationList + // .filter((station) => !onlineStationNames.includes(station.name) && station.onlineInfo) + // .forEach((offlineStation) => { + // offlineStation.onlineInfo = undefined; + // }); - const dispatcherStatus = this.getDispatcherStatus(stationAPIData); - prevDispatcherStatuses.push(dispatcherStatus); - - const stationTrains = this.getStationTrains(stationAPIData); - const scheduledTrains = this.getScheduledTrains(station?.generalInfo, stationAPIData); - - const onlineInfo = { - name: stationAPIData.stationName, - hash: stationAPIData.stationHash, - region: stationAPIData.region, - maxUsers: stationAPIData.maxUsers, - currentUsers: stationAPIData.currentUsers, - spawns: parseSpawns(stationAPIData.spawnString), - dispatcherName: stationAPIData.dispatcherName, - dispatcherRate: stationAPIData.dispatcherRate, - dispatcherId: stationAPIData.dispatcherId, - dispatcherExp: stationAPIData.dispatcherExp, - dispatcherIsSupporter: stationAPIData.dispatcherIsSupporter, - stationTrains, - statusTimestamp: dispatcherStatus.statusTimestamp, - statusID: dispatcherStatus.statusID, - scheduledTrains - }; - - if (!station) { - this.stationList.push({ - name: stationAPIData.stationName, - onlineInfo - }); - - return; - } - - station.onlineInfo = { ...onlineInfo }; - - this.stationList - .filter((station) => !onlineStationNames.includes(station.name) && station.onlineInfo) - .forEach((offlineStation) => { - offlineStation.onlineInfo = undefined; - }); - }); - - if (this.apiData.dispatchers != null) this.lastDispatcherStatuses = prevDispatcherStatuses; - }, + // if (this.apiData.dispatchers != null) this.lastDispatcherStatuses = prevDispatcherStatuses; + // }, async fetchStationsGeneralInfo() { const sceneryData: StationJSONData[] = await ( @@ -385,7 +307,7 @@ export const useStore = defineStore('store', { } const socket = io(URLs.stacjownikAPI, { - // transports: ['websocket', 'polling'], + transports: ['websocket', 'polling'], rememberUpgrade: true, reconnection: true, extraHeaders: { @@ -405,7 +327,6 @@ export const useStore = defineStore('store', { socket.emit('FETCH_DATA', { version: packageInfo.version }, (data: APIData) => { this.dataStatuses.connection = DataStatus.Loaded; - this.apiData = data; this.setOnlineData(); }); @@ -414,10 +335,9 @@ export const useStore = defineStore('store', { }, async connectToAPI() { - await this.fetchStationsGeneralInfo(); - await this.fetchStockInfoData(); - this.connectToWebsocket(); + this.fetchStockInfoData(); + this.fetchStationsGeneralInfo(); }, async changeRegion(region: StoreState['region']) { @@ -453,8 +373,7 @@ export const useStore = defineStore('store', { ? DataStatus.Warning : DataStatus.Loaded; - this.setTrainsOnlineData(); - this.setStationsOnlineInfo(); + // this.setStationsOnlineInfo(); } } }); diff --git a/src/styles/global.scss b/src/styles/global.scss index ca83ca2..ec69dd7 100644 --- a/src/styles/global.scss +++ b/src/styles/global.scss @@ -35,10 +35,6 @@ } } -html { - scroll-behavior: smooth; -} - body { background: var(--clr-bg); diff --git a/src/views/SceneryView.vue b/src/views/SceneryView.vue index 6567be9..ef3e1db 100644 --- a/src/views/SceneryView.vue +++ b/src/views/SceneryView.vue @@ -1,9 +1,6 @@ - + {{ $t('scenery.no-scenery') }} @@ -11,21 +8,16 @@ - - + + - - + + @@ -44,6 +36,7 @@ @@ -82,9 +75,22 @@ export default defineComponent({ SceneryDispatchersHistory }, + props: { + region: { + type: String, + required: false + }, + + station: { + type: String, + required: true + } + }, + mixins: [routerMixin], data: () => ({ + store: useStore(), viewModes: [ { id: 'scenery.option-active-timetables', @@ -111,24 +117,28 @@ export default defineComponent({ setup() { const route = useRoute(); - const store = useStore(); - const timetableOnly = computed(() => (route.query['timetableOnly'] == '1' ? true : false)); const isComponentVisible = computed(() => route.path === '/scenery'); - const stationInfo = computed(() => { - return store.stationList.find( - (station) => station.name === route.query.station?.toString().replace(/_/g, ' ') - ); - }); - return { - timetableOnly, - isComponentVisible, - stationInfo, - store + isComponentVisible }; }, + + computed: { + stationInfo() { + return this.store.stationList.find( + (station) => station.name === this.station?.toString().replace(/_/g, ' ') + ); + }, + + onlineSceneryInfo() { + return this.store.onlineSceneryList.find( + (scenery) => scenery.name === this.station?.toString().replace(/_/g, ' ') + ); + } + }, + methods: { setViewMode(componentName: string) { this.currentViewCompontent = componentName; diff --git a/src/views/StationsView.vue b/src/views/StationsView.vue index b5cdfef..6a0c6c9 100644 --- a/src/views/StationsView.vue +++ b/src/views/StationsView.vue @@ -33,19 +33,15 @@ export default defineComponent({ filterCardOpen: false, modalHidden: true, STORAGE_KEY: 'options_saved', - focusedStationName: '' + focusedStationName: '', + filterStore: useStationFiltersStore(), + store: useStore() }), - setup() { - return { - filterStore: useStationFiltersStore(), - store: useStore() - }; - }, computed: { computedStationList() { - return this.filterStore.getFilteredStationList(this.store.stationList, this.store.region.id); + return this.filterStore.filteredStationList; } }, diff --git a/vite.config.ts b/vite.config.ts index fd3e769..c423e9f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,7 +4,7 @@ import { VitePWA } from 'vite-plugin-pwa'; export default defineConfig({ server: { - port: 5001, + port: 5001 }, plugins: [ vue(), @@ -20,13 +20,25 @@ export default defineConfig({ options: { cacheName: 'sceneries-cache', expiration: { - maxEntries: 1, - maxAgeSeconds: 60 * 60 * 24 * 7, // <== 7 days + maxAgeSeconds: 60 * 60 * 24 * 7 // <== 7 days }, cacheableResponse: { - statuses: [0, 200], + statuses: [0, 200] + } + } + }, + { + urlPattern: new RegExp('^https://raw.githubusercontent.com/Spythere/api/*', 'i'), + handler: 'NetworkFirst', + options: { + cacheName: 'github-api-cache', + expiration: { + maxAgeSeconds: 60 * 60 * 24 * 7 // <== 7 days }, - }, + cacheableResponse: { + statuses: [0, 200] + } + } }, { urlPattern: /^https:\/\/rj.td2.info.pl\/dist\/img\/thumbnails\/.*/i, @@ -35,21 +47,19 @@ export default defineConfig({ cacheName: 'images-cache', expiration: { maxEntries: 100, - maxAgeSeconds: 60 * 60 * 24 * 60, + maxAgeSeconds: 60 * 60 * 24 * 7 // <== 7 days }, cacheableResponse: { - statuses: [0, 200, 404], - }, - }, - }, - ], + statuses: [0, 200, 404] + } + } + } + ] }, devOptions: { enabled: true, - }, - }), - ], + suppressWarnings: true + } + }) + ] }); - - -