mirror of
https://github.com/Spythere/stacjownik.git
synced 2026-05-03 13:28:11 +00:00
lokalne fonty; poprawki offline i cachingu pwa
This commit is contained in:
+34
-34
@@ -37,7 +37,6 @@ import { defineComponent, watch } from 'vue';
|
||||
import Clock from './components/App/Clock.vue';
|
||||
|
||||
import packageInfo from '.././package.json';
|
||||
import { regions } from './data/options.json';
|
||||
|
||||
import { useMainStore } from './store/mainStore';
|
||||
import StatusIndicator from './components/App/StatusIndicator.vue';
|
||||
@@ -46,6 +45,7 @@ import AppHeader from './components/App/AppHeader.vue';
|
||||
import axios from 'axios';
|
||||
import StorageManager from './managers/storageManager';
|
||||
import { useApiStore } from './store/apiStore';
|
||||
import { Status } from './typings/common';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
@@ -66,26 +66,10 @@ export default defineComponent({
|
||||
}),
|
||||
|
||||
created() {
|
||||
this.loadLang();
|
||||
this.apiStore.setupAPI();
|
||||
|
||||
this.store.isOffline = !window.navigator.onLine;
|
||||
|
||||
window.addEventListener('offline', () => {
|
||||
this.store.isOffline = true;
|
||||
this.apiStore.activeData = undefined;
|
||||
|
||||
this.apiStore.setDataStatuses();
|
||||
});
|
||||
|
||||
window.addEventListener('online', () => {
|
||||
this.store.isOffline = false;
|
||||
});
|
||||
this.init();
|
||||
},
|
||||
|
||||
async mounted() {
|
||||
this.setReleaseURL();
|
||||
|
||||
watch(
|
||||
() => this.store.blockScroll,
|
||||
(value) => {
|
||||
@@ -95,23 +79,39 @@ export default defineComponent({
|
||||
);
|
||||
},
|
||||
|
||||
watch: {
|
||||
'$route.query.region': {
|
||||
immediate: true,
|
||||
handler(regionQuery: string) {
|
||||
if (regionQuery) {
|
||||
this.store.region.id =
|
||||
regions.find(
|
||||
(reg) =>
|
||||
reg.id == regionQuery.toLocaleLowerCase() ||
|
||||
reg.value.toLocaleLowerCase() == regionQuery.toLocaleLowerCase()
|
||||
)?.id || 'eu';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
init() {
|
||||
this.loadLang();
|
||||
this.setReleaseURL();
|
||||
this.setupOfflineHandling();
|
||||
|
||||
this.apiStore.setupAPI();
|
||||
},
|
||||
|
||||
setupOfflineHandling() {
|
||||
this.store.isOffline = !window.navigator.onLine;
|
||||
|
||||
if (this.store.isOffline) this.handleOfflineMode();
|
||||
|
||||
window.addEventListener('offline', this.handleOfflineMode);
|
||||
window.addEventListener('online', this.handleOnlineMode);
|
||||
},
|
||||
|
||||
handleOfflineMode() {
|
||||
this.store.isOffline = true;
|
||||
|
||||
this.apiStore.stopActiveDataScheduler();
|
||||
this.apiStore.activeData = undefined;
|
||||
|
||||
this.apiStore.dataStatuses.connection = Status.Data.Offline;
|
||||
},
|
||||
|
||||
handleOnlineMode() {
|
||||
this.store.isOffline = false;
|
||||
|
||||
this.apiStore.setupAPI();
|
||||
},
|
||||
|
||||
changeLang(lang: string) {
|
||||
this.$i18n.locale = lang;
|
||||
this.currentLang = lang;
|
||||
|
||||
@@ -240,9 +240,9 @@ export default defineComponent({
|
||||
const trainsDataStatus = statuses.trains;
|
||||
const dispatcherDataStatus = statuses.dispatchers;
|
||||
|
||||
if (this.store.isOffline) {
|
||||
this.setSignalStatus(Status.Data.Initialized);
|
||||
this.indicator.status = Status.Data.Initialized;
|
||||
if (connectionStatus == Status.Data.Offline) {
|
||||
this.setSignalStatus(Status.Data.Offline);
|
||||
this.indicator.status = Status.Data.Offline;
|
||||
this.indicator.message = 'data-status.S1-offline';
|
||||
return;
|
||||
}
|
||||
@@ -293,7 +293,7 @@ export default defineComponent({
|
||||
this.orangeLight = false;
|
||||
this.redBottomLight = false;
|
||||
|
||||
if (status == Status.Data.Initialized) {
|
||||
if (status == Status.Data.Initialized || status == Status.Data.Offline) {
|
||||
this.redTopLight = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,21 @@ export default defineComponent({
|
||||
'store.region.id': {
|
||||
handler(regionId) {
|
||||
this.selectedItemIndex = this.regionList.findIndex((reg) => reg.id == regionId);
|
||||
|
||||
console.log('region id', regionId);
|
||||
}
|
||||
},
|
||||
'$route.query.region': {
|
||||
immediate: true,
|
||||
handler(regionQuery: string) {
|
||||
if (regionQuery) {
|
||||
this.store.region.id =
|
||||
regionsJSON.find(
|
||||
(reg) =>
|
||||
reg.id == regionQuery.toLocaleLowerCase() ||
|
||||
reg.value.toLocaleLowerCase() == regionQuery.toLocaleLowerCase()
|
||||
)?.id || 'eu';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -279,7 +279,7 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<Loading v-if="!isDataLoaded && stations.length == 0" />
|
||||
<Loading v-if="apiStore.dataStatuses.sceneries == Status.Loading" />
|
||||
|
||||
<div class="no-stations" v-else-if="stations.length == 0">
|
||||
{{ $t('sceneries.no-stations') }}
|
||||
@@ -288,7 +288,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, PropType } from 'vue';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import dateMixin from '../../mixins/dateMixin';
|
||||
import stationInfoMixin from '../../mixins/stationInfoMixin';
|
||||
import styleMixin from '../../mixins/styleMixin';
|
||||
@@ -330,12 +330,8 @@ export default defineComponent({
|
||||
const apiStore = useApiStore();
|
||||
const stationFiltersStore = useStationFiltersStore();
|
||||
|
||||
const isDataLoaded = computed(() => {
|
||||
return apiStore.dataStatuses.sceneries != Status.Data.Loading;
|
||||
});
|
||||
|
||||
return {
|
||||
isDataLoaded,
|
||||
Status: Status.Data,
|
||||
stationFiltersStore,
|
||||
mainStore,
|
||||
apiStore
|
||||
|
||||
@@ -5,13 +5,12 @@
|
||||
{{ $t('app.offline') }}
|
||||
</div>
|
||||
|
||||
<Loading v-else-if="trains.length == 0 && apiStore.dataStatuses.trains == 0" key="loading" />
|
||||
<Loading
|
||||
v-else-if="trains.length == 0 && apiStore.dataStatuses.connection == 0"
|
||||
key="loading"
|
||||
/>
|
||||
|
||||
<div
|
||||
class="table-info"
|
||||
key="no-trains"
|
||||
v-else-if="trains.length == 0 && apiStore.dataStatuses.trains != 0"
|
||||
>
|
||||
<div class="table-info" key="no-trains" v-else-if="trains.length == 0">
|
||||
{{ $t('trains.no-trains') }}
|
||||
</div>
|
||||
|
||||
|
||||
+10
-3
@@ -18,7 +18,8 @@ const routes: Array<RouteRecordRaw> = [
|
||||
props: (route) => ({
|
||||
train: route.query.train,
|
||||
driver: route.query.driver,
|
||||
trainId: route.query.trainId
|
||||
trainId: route.query.trainId,
|
||||
region: route.query.region
|
||||
})
|
||||
},
|
||||
{
|
||||
@@ -37,12 +38,18 @@ const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/journal/timetables',
|
||||
name: 'JournalTimetables',
|
||||
component: JournalTimetablesVue
|
||||
component: JournalTimetablesVue,
|
||||
props: (route) => ({
|
||||
region: route.query.region
|
||||
})
|
||||
},
|
||||
{
|
||||
path: '/journal/dispatchers',
|
||||
name: 'JournalDispatchers',
|
||||
component: JournalDispatchersVue
|
||||
component: JournalDispatchersVue,
|
||||
props: (route) => ({
|
||||
region: route.query.region
|
||||
})
|
||||
},
|
||||
{
|
||||
path: '/:catchAll(.*)',
|
||||
|
||||
+39
-19
@@ -18,7 +18,9 @@ export const useApiStore = defineStore('apiStore', {
|
||||
activeData: undefined as API.ActiveData.Response | undefined,
|
||||
rollingStockData: undefined as API.RollingStock.Response | undefined,
|
||||
donatorsData: [] as API.Donators.Response,
|
||||
sceneryData: [] as StationJSONData[]
|
||||
sceneryData: [] as StationJSONData[],
|
||||
|
||||
activeDataTimeout: undefined as number | undefined
|
||||
}),
|
||||
|
||||
actions: {
|
||||
@@ -28,22 +30,32 @@ export const useApiStore = defineStore('apiStore', {
|
||||
this.fetchDonatorsData();
|
||||
this.fetchStationsGeneralInfo();
|
||||
|
||||
this.scheduleFetchActiveData();
|
||||
if (this.activeDataTimeout === undefined) this.startActiveDataScheduler();
|
||||
},
|
||||
|
||||
async setDataStatuses() {
|
||||
if (!this.activeData?.activeSceneries) {
|
||||
this.dataStatuses.sceneries = Status.Data.Error;
|
||||
this.dataStatuses.trains = Status.Data.Error;
|
||||
this.dataStatuses.dispatchers = Status.Data.Error;
|
||||
// async setDataStatuses() {
|
||||
// if (!window.navigator.onLine) {
|
||||
// this.dataStatuses.connection = Status.Data.Offline;
|
||||
// this.dataStatuses.sceneries = Status.Data.Offline;
|
||||
// this.dataStatuses.trains = Status.Data.Offline;
|
||||
// this.dataStatuses.dispatchers = Status.Data.Offline;
|
||||
// this.dataStatuses.timetables = Status.Data.Offline;
|
||||
// }
|
||||
|
||||
return;
|
||||
}
|
||||
// if (!this.activeData?.activeSceneries) {
|
||||
// this.dataStatuses.connection = Status.Data.Loaded;
|
||||
// this.dataStatuses.sceneries = Status.Data.Error;
|
||||
// this.dataStatuses.trains = Status.Data.Error;
|
||||
// this.dataStatuses.dispatchers = Status.Data.Error;
|
||||
|
||||
this.dataStatuses.sceneries = Status.Data.Loaded;
|
||||
this.dataStatuses.trains = !this.activeData.trains ? Status.Data.Warning : Status.Data.Loaded;
|
||||
this.dataStatuses.dispatchers = Status.Data.Loaded;
|
||||
},
|
||||
// return;
|
||||
// }
|
||||
|
||||
// this.dataStatuses.connection = Status.Data.Loaded;
|
||||
// this.dataStatuses.sceneries = Status.Data.Loaded;
|
||||
// this.dataStatuses.trains = !this.activeData.trains ? Status.Data.Warning : Status.Data.Loaded;
|
||||
// this.dataStatuses.dispatchers = Status.Data.Loaded;
|
||||
// },
|
||||
|
||||
async fetchDonatorsData() {
|
||||
try {
|
||||
@@ -67,12 +79,16 @@ export const useApiStore = defineStore('apiStore', {
|
||||
}
|
||||
},
|
||||
|
||||
async scheduleFetchActiveData() {
|
||||
async startActiveDataScheduler() {
|
||||
if (!window.navigator.onLine) {
|
||||
this.dataStatuses.connection = Status.Data.Offline;
|
||||
return;
|
||||
}
|
||||
|
||||
if (import.meta.env.VITE_API_MODE === 'mock') {
|
||||
const mockActiveData = await import('../data/mockActiveData.json');
|
||||
this.dataStatuses.connection = Status.Data.Loaded;
|
||||
this.activeData = mockActiveData;
|
||||
this.setDataStatuses();
|
||||
|
||||
console.warn('Stacjownik działa w trybie mockowania danych z WS');
|
||||
|
||||
@@ -84,21 +100,24 @@ export const useApiStore = defineStore('apiStore', {
|
||||
|
||||
this.activeData = data;
|
||||
this.dataStatuses.connection = Status.Data.Loaded;
|
||||
|
||||
this.setDataStatuses();
|
||||
} catch (error) {
|
||||
this.dataStatuses.connection = Status.Data.Error;
|
||||
console.error('Wystąpił błąd podczas pobierania danych online z API!');
|
||||
} finally {
|
||||
setTimeout(
|
||||
this.activeDataTimeout = window.setTimeout(
|
||||
() => {
|
||||
this.scheduleFetchActiveData();
|
||||
this.startActiveDataScheduler();
|
||||
},
|
||||
~~(1000 * (Math.random() * (25 - 20) + 25))
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
async stopActiveDataScheduler() {
|
||||
window.clearTimeout(this.activeDataTimeout);
|
||||
this.activeDataTimeout = undefined;
|
||||
},
|
||||
|
||||
async fetchStationsGeneralInfo() {
|
||||
const sceneryData: StationJSONData[] = (await http.get<StationJSONData[]>('api/getSceneries'))
|
||||
.data;
|
||||
@@ -108,6 +127,7 @@ export const useApiStore = defineStore('apiStore', {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dataStatuses.sceneries = Status.Data.Loaded;
|
||||
this.sceneryData = sceneryData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
overflow-y: auto;
|
||||
height: 90vh;
|
||||
min-height: 550px;
|
||||
margin-top: 0.5em;
|
||||
|
||||
padding-right: 0.2em;
|
||||
}
|
||||
@@ -24,7 +25,7 @@
|
||||
text-align: end;
|
||||
|
||||
padding: 0.25em;
|
||||
margin: 0.5em 0;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.journal_warning {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
@font-face {
|
||||
font-family: 'Quicksand';
|
||||
src:
|
||||
url('/fonts/Quicksand-Bold.woff2') format('woff2'),
|
||||
url('/fonts/Quicksand-Bold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Quicksand';
|
||||
src:
|
||||
url('/fonts/Quicksand-SemiBold.woff2') format('woff2'),
|
||||
url('/fonts/Quicksand-SemiBold.woff') format('woff');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Quicksand';
|
||||
src:
|
||||
url('/fonts/Quicksand-Medium.woff2') format('woff2'),
|
||||
url('/fonts/Quicksand-Medium.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Quicksand';
|
||||
src:
|
||||
url('/fonts/Quicksand-Regular.woff2') format('woff2'),
|
||||
url('/fonts/Quicksand-Regular.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Quicksand';
|
||||
src:
|
||||
url('/fonts/Quicksand-Light.woff2') format('woff2'),
|
||||
url('/fonts/Quicksand-Light.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
@import 'fonts.scss';
|
||||
|
||||
:root {
|
||||
--clr-primary: #ffc014;
|
||||
--clr-secondary: #2f2f2f;
|
||||
|
||||
@@ -11,7 +11,7 @@ export namespace Status {
|
||||
}
|
||||
|
||||
export enum Data {
|
||||
Offline = 2,
|
||||
Offline = -2,
|
||||
Initialized = -1,
|
||||
Loading = 0,
|
||||
Error = 1,
|
||||
|
||||
Reference in New Issue
Block a user