PWA: tryb offline

This commit is contained in:
2022-12-26 18:43:15 +01:00
parent f93c1fbfec
commit 2e721fb8bf
17 changed files with 2531 additions and 2366 deletions
+27 -3
View File
@@ -29,7 +29,7 @@
</template>
<script lang="ts">
import { computed, defineComponent, provide, ref, watch } from 'vue';
import { computed, defineComponent, KeepAlive, provide, ref, watch } from 'vue';
import Clock from './components/App/Clock.vue';
@@ -44,6 +44,9 @@ import imageMixin from './mixins/imageMixin';
import AppHeader from './components/App/AppHeader.vue';
import axios from 'axios';
import UpdatePrompt from './components/App/UpdatePrompt.vue';
import { VERSION } from 'vue-i18n';
import { RouterView } from 'vue-router';
import useCustomSW from './mixins/useCustomSW';
export default defineComponent({
components: {
@@ -52,8 +55,8 @@ export default defineComponent({
SelectBox,
TrainModal,
AppHeader,
UpdatePrompt
},
UpdatePrompt,
},
mixins: [imageMixin],
@@ -61,6 +64,8 @@ export default defineComponent({
const store = useStore();
store.connectToAPI();
const { offlineReady } = useCustomSW();
const isFilterCardVisible = ref(false);
provide('isFilterCardVisible', isFilterCardVisible);
@@ -85,6 +90,25 @@ export default defineComponent({
created() {
this.loadLang();
this.store.isOffline = !window.navigator.onLine;
window.addEventListener('offline', () => {
this.store.isOffline = true;
this.store.apiData = {
stations: [],
dispatchers: [],
trains: [],
connectedSocketCount: 0,
};
this.store.setOnlineData();
});
window.addEventListener('online', () => {
this.store.isOffline = false;
});
},
async mounted() {
+13 -1
View File
@@ -161,7 +161,6 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { DataStatus } from '../../scripts/enums/DataStatus';
import { useStore } from '../../store/store';
@@ -172,6 +171,7 @@ export default defineComponent({
return {
tooltipActive: false,
indicator: {
offline: false,
status: DataStatus.Loading,
message: 'data-status.S3',
},
@@ -193,6 +193,7 @@ export default defineComponent({
return {
dataStatus: store.dataStatuses,
store,
};
},
@@ -206,6 +207,13 @@ export default defineComponent({
const trainsDataStatus = statuses.trains;
const dispatcherDataStatus = statuses.dispatchers;
if (this.store.isOffline) {
this.setSignalStatus(DataStatus.Initialized);
this.indicator.status = DataStatus.Initialized;
this.indicator.message = 'data-status.S1-offline';
return;
}
if (connectionStatus == DataStatus.Error) {
this.setSignalStatus(connectionStatus);
this.indicator.status = connectionStatus;
@@ -252,6 +260,10 @@ export default defineComponent({
this.orangeLight = false;
this.redBottomLight = false;
if (status == DataStatus.Initialized) {
this.redTopLight = true;
}
if (status == DataStatus.Loaded) {
this.greenLight = true;
}
+2 -9
View File
@@ -14,18 +14,11 @@
</template>
<script setup lang="ts">
import { useRegisterSW } from 'virtual:pwa-register/vue';
import { ref } from 'vue';
import useCustomSW from '../../mixins/useCustomSW';
const hidePrompt = ref(false);
const { needRefresh, updateServiceWorker } = useRegisterSW({
immediate: true,
onNeedRefresh() {
console.log('Needs refresh!');
},
});
const { needRefresh, updateServiceWorker } = useCustomSW();
</script>
<style lang="scss" scoped>
+1 -1
View File
@@ -1,5 +1,5 @@
<template>
<div class="journal-stats">
<div class="journal-stats" v-show="!store.isOffline">
<div class="tabs">
<button
v-for="tab in data.tabs"
+9 -5
View File
@@ -2,18 +2,22 @@
<div class="train-table">
<transition name="anim" mode="out-in">
<div :key="store.dataStatuses.trains">
<Loading v-if="trains.length == 0 && store.dataStatuses.trains == 0" />
<div class="table-info" v-if="store.isOffline">
{{ $t('app.offline') }}
</div>
<div class="table-info no-trains" v-if="trains.length == 0 && store.dataStatuses.trains != 0">
<Loading v-else-if="trains.length == 0 && store.dataStatuses.trains == 0" />
<div class="table-info no-trains" v-else-if="trains.length == 0 && store.dataStatuses.trains != 0">
{{ $t('trains.no-trains') }}
</div>
<div class="timeouts-warning" v-if="trainNumbersWithTimeouts.length != 0">
<div class="timeouts-warning" v-if="trainNumbersWithTimeouts.length == 0">
<b class="warning-timeout">?</b>
{{ $t('trains.timeout') }}
</div>
<ul class="train-list">
<ul class="train-list" v-else>
<li
class="train-row"
v-for="train in currentTrains"
+3 -1
View File
@@ -11,7 +11,8 @@
"error": "An error occured while loading data!",
"no-result": "No results for current search!",
"migration-warning": "Stacjownik services will be unavailable 2/06/2022 between 1-3am (CEST time) due to the migration of API hostings!",
"migration-confirm": "Roger that!"
"migration-confirm": "Roger that!",
"offline": "App is in the offline mode!"
},
"update": {
"title": "New Stacjownik version is available!",
@@ -20,6 +21,7 @@
"confirm-button": "Understood!"
},
"data-status": {
"S1-offline": "<b>S1 signal</b> <br> The app is working in offline mode!",
"S1a-connection": "<b>S1a signal</b> <br> Cannot connect with Stacjownik API service!",
"S1a-sceneries": "<b>S1a signal</b> <br> Cannot load online stations data!",
"S2": "<b>S2 signal</b> <br> All data loaded successfully!",
+3 -1
View File
@@ -11,7 +11,8 @@
"error": "Wystąpił problem z załadowaniem danych!",
"no-result": "Brak wyników o podanych kryteriach!",
"migration-warning": "Usługi Stacjownika będą niedostępne w godzinach 1:00-3:00 2 czerwca 2022r. z powodu migracji hostingów API!",
"migration-confirm": "Przyjąłem!"
"migration-confirm": "Przyjąłem!",
"offline": "Aplikacja w trybie offline!"
},
"update": {
@@ -22,6 +23,7 @@
},
"data-status": {
"S1-offline": "<b>Sygnał S1</b> <br> Aplikacja działa w trybie offline!",
"S1a-connection": "<b>Sygnał S1a</b> <br> Błąd podczas próby połączenia się z API Stacjownika!",
"S1a-sceneries": "<b>Sygnał S1a</b> <br> Błąd podczas pobierania danych o sceneriach online!",
"S2": "<b>Sygnał S2</b> <br> Pomyślnie załadowano dane!",
+13
View File
@@ -0,0 +1,13 @@
import { useRegisterSW } from 'virtual:pwa-register/vue';
export default () => {
const { needRefresh, updateServiceWorker, offlineReady } = useRegisterSW({
immediate: true,
});
return {
needRefresh,
updateServiceWorker,
offlineReady,
};
};
+5 -2
View File
@@ -3,6 +3,7 @@ import inputData from '../data/options.json';
import Filter from '../scripts/interfaces/Filter';
import Station from '../scripts/interfaces/Station';
import StorageManager from '../scripts/managers/storageManager';
import { useStore } from './store';
const sortStations = (a: Station, b: Station, sorter: { index: number; dir: number }) => {
switch (sorter.index) {
@@ -58,7 +59,7 @@ const sortStations = (a: Station, b: Station, sorter: { index: number; dir: numb
return a.name.localeCompare(b.name);
};
const filterStations = (station: Station, filters: Filter) => {
const filterStations = (station: Station, filters: Filter, isOffline = false) => {
const returnMode = false;
if ((station.generalInfo?.availability == 'nonPublic' || !station.generalInfo) && filters['nonPublic'])
@@ -236,6 +237,7 @@ export const useStationFiltersStore = defineStore('stationFiltersStore', {
inputs: inputData,
filters: { ...filterInitStates },
sorterActive: { index: 0, dir: 1 },
store: useStore(),
};
},
@@ -249,7 +251,7 @@ export const useStationFiltersStore = defineStore('stationFiltersStore', {
return station;
})
.filter((station) => filterStations(station, this.filters))
.filter((station) => filterStations(station, this.filters, this.store.isOffline))
.sort((a, b) => sortStations(a, b, this.sorterActive));
},
@@ -303,3 +305,4 @@ export const useStationFiltersStore = defineStore('stationFiltersStore', {
},
},
});
+11 -4
View File
@@ -17,7 +17,6 @@ import {
} from '../scripts/utils/storeUtils';
import { APIData, StationJSONData, StoreState } from './storeTypes';
export const useStore = defineStore('store', {
state: () =>
({
@@ -35,6 +34,7 @@ export const useStore = defineStore('store', {
stationCount: 0,
webSocket: undefined,
isOffline: false,
dispatcherStatsName: '',
dispatcherStatsData: undefined,
@@ -57,7 +57,6 @@ export const useStore = defineStore('store', {
blockScroll: false,
listenerLaunched: false,
} as StoreState),
actions: {
@@ -225,6 +224,14 @@ export const useStore = defineStore('store', {
const onlineStationNames: string[] = [];
const prevDispatcherStatuses: StoreState['lastDispatcherStatuses'] = [];
if (this.isOffline) {
this.stationList.forEach((station) => {
station.onlineInfo = undefined;
});
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);
@@ -352,12 +359,11 @@ export const useStore = defineStore('store', {
transports: ['websocket', 'polling'],
rememberUpgrade: true,
reconnection: true,
timeout: 10000,
timeout: 2000,
});
socket.on('connect_error', (err) => {
this.dataStatuses.connection = DataStatus.Error;
this.webSocket = undefined;
});
socket.on('UPDATE', (data: APIData) => {
@@ -368,6 +374,7 @@ export const useStore = defineStore('store', {
socket.emit('FETCH_DATA', {}, (data: APIData) => {
this.apiData = data;
this.dataStatuses.connection = DataStatus.Loaded;
this.setOnlineData();
});
+1
View File
@@ -23,6 +23,7 @@ export interface StoreState {
stationCount: number;
webSocket?: Socket;
isOffline: boolean;
dispatcherStatsName: string;
dispatcherStatsData?: DispatcherStatsAPIData;
+5 -1
View File
@@ -14,7 +14,11 @@
<div class="list_wrapper" @scroll="handleScroll">
<!-- <transition name="warning" mode="out-in"> -->
<!-- <div :key="dataStatus"> -->
<Loading v-if="dataStatus == DataStatus.Initialized || dataStatus == DataStatus.Loading" />
<div class="journal_warning" v-if="store.isOffline">
{{ $t('app.offline') }}
</div>
<Loading v-else-if="dataStatus == DataStatus.Initialized || dataStatus == DataStatus.Loading" />
<div v-else-if="dataStatus == DataStatus.Error" class="journal_warning error">
{{ $t('app.error') }}
+5 -1
View File
@@ -17,7 +17,11 @@
<div class="list_wrapper" @scroll="handleScroll">
<!-- <transition name="warning" mode="out-in"> -->
<!-- <div :key="dataStatus"> -->
<Loading v-if="dataStatus == DataStatus.Initialized || dataStatus == DataStatus.Loading" />
<div class="journal_warning" v-if="store.isOffline">
{{ $t('app.offline') }}
</div>
<Loading v-else-if="dataStatus == DataStatus.Initialized || dataStatus == DataStatus.Loading" />
<div v-else-if="dataStatus == DataStatus.Error" class="journal_warning error">
{{ $t('app.error') }}