mirror of
https://github.com/Spythere/srjp-td2.git
synced 2026-05-04 14:08:12 +00:00
chore: fetching data
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<select
|
||||
v-model="globalStore.selectedTrainId"
|
||||
@change="selectTrain"
|
||||
name="trains"
|
||||
id="trains-select"
|
||||
class="bg-zinc-800 p-1 rounded-md print:hidden w-full"
|
||||
:disabled="apiStore.activeDataStatus != DataStatus.SUCCESS"
|
||||
>
|
||||
<option :value="null" disabled>
|
||||
{{
|
||||
apiStore.activeDataStatus == DataStatus.LOADING
|
||||
? $t('data-loading-text')
|
||||
: $t('train-select-placeholder')
|
||||
}}
|
||||
</option>
|
||||
<option :value="train.id" v-for="train in globalStore.activeTimetableTrains">
|
||||
{{ train.driverName }} | {{ train.timetable?.category }} {{ train.trainNo }} [{{
|
||||
getRegionNameById(train.region)
|
||||
}}]
|
||||
</option>
|
||||
</select>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useApiStore } from '../../stores/api.store';
|
||||
import { useGlobalStore } from '../../stores/global.store';
|
||||
import { DataStatus } from '../../types/api.types';
|
||||
import { getRegionNameById } from '../../utils/trainUtils';
|
||||
|
||||
const apiStore = useApiStore();
|
||||
const globalStore = useGlobalStore();
|
||||
|
||||
function selectTrain() {
|
||||
if (!apiStore.activeData) return;
|
||||
|
||||
globalStore.selectedActiveTrain =
|
||||
globalStore.activeTimetableTrains.find((train) => train.id == globalStore.selectedTrainId) ??
|
||||
null;
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<div class="flex gap-2 items-center">
|
||||
<div class="flex gap-2 w-full">
|
||||
<input
|
||||
v-model="globalStore.journalTimetableSearch.driverName"
|
||||
type="text"
|
||||
@keydown.enter="fetchJournalTimetables"
|
||||
:class="`bg-zinc-800 p-1 rounded-md print:hidden w-full ${
|
||||
apiStore.connectionMode == 'offline' ? 'opacity-35' : ''
|
||||
}`"
|
||||
:disabled="
|
||||
apiStore.journalDataStatus == DataStatus.LOADING || apiStore.connectionMode == 'offline'
|
||||
"
|
||||
:placeholder="$t('journal-driver-search-placeholder')"
|
||||
/>
|
||||
|
||||
<input
|
||||
v-model="globalStore.journalTimetableSearch.route"
|
||||
type="text"
|
||||
@keydown.enter="fetchJournalTimetables"
|
||||
:class="`bg-zinc-800 p-1 rounded-md print:hidden w-full ${
|
||||
apiStore.connectionMode == 'offline' ? 'opacity-35' : ''
|
||||
}`"
|
||||
:disabled="
|
||||
apiStore.journalDataStatus == DataStatus.LOADING || apiStore.connectionMode == 'offline'
|
||||
"
|
||||
:placeholder="$t('journal-route-search-placeholder')"
|
||||
/>
|
||||
|
||||
<input
|
||||
v-model="globalStore.journalTimetableSearch.date"
|
||||
type="date"
|
||||
@keydown.enter="fetchJournalTimetables"
|
||||
:class="`bg-zinc-800 p-1 rounded-md print:hidden w-full ${
|
||||
apiStore.connectionMode == 'offline' ? 'opacity-35' : ''
|
||||
}`"
|
||||
:disabled="
|
||||
apiStore.journalDataStatus == DataStatus.LOADING || apiStore.connectionMode == 'offline'
|
||||
"
|
||||
:placeholder="$t('journal-date-search-placeholder')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="bg-zinc-800 hover:bg-zinc-700 p-1 rounded-md"
|
||||
v-if="globalStore.viewMode == 'journal'"
|
||||
@click="clearSearch"
|
||||
>
|
||||
<TrashIcon class="size-6" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="bg-zinc-800 hover:bg-zinc-700 p-1 rounded-md"
|
||||
v-if="globalStore.viewMode == 'journal'"
|
||||
@click="fetchJournalTimetables"
|
||||
>
|
||||
<ArrowRightCircleIcon class="size-6" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ArrowRightCircleIcon, TrashIcon } from '@heroicons/vue/16/solid';
|
||||
import { useApiStore } from '../../stores/api.store';
|
||||
import { useGlobalStore } from '../../stores/global.store';
|
||||
import { DataStatus, type JournalTimetablesShortResponse } from '../../types/api.types';
|
||||
|
||||
const globalStore = useGlobalStore();
|
||||
const apiStore = useApiStore();
|
||||
|
||||
async function fetchJournalTimetables() {
|
||||
const searchValues = globalStore.journalTimetableSearch;
|
||||
|
||||
let fetchParams: Record<string, any> = {};
|
||||
|
||||
if (searchValues['driverName']) {
|
||||
fetchParams['driverName'] = searchValues['driverName'].trim();
|
||||
}
|
||||
|
||||
if (searchValues['date']) {
|
||||
let dateFromStr = new Date(searchValues['date']).toISOString();
|
||||
|
||||
let dateTo = new Date(dateFromStr);
|
||||
dateTo.setDate(dateTo.getDate() + 1);
|
||||
|
||||
fetchParams['dateFrom'] = dateFromStr;
|
||||
fetchParams['dateTo'] = dateTo.toISOString();
|
||||
}
|
||||
|
||||
if (searchValues['route']) {
|
||||
const [routeFrom, routeTo] = searchValues['route'].split('-');
|
||||
|
||||
if (routeFrom) {
|
||||
fetchParams['issuedFrom'] = routeFrom.trim();
|
||||
}
|
||||
|
||||
if (routeTo) {
|
||||
fetchParams['terminatingAt'] = routeTo.trim();
|
||||
}
|
||||
}
|
||||
|
||||
fetchParams['hasStopsDetails'] = 1;
|
||||
fetchParams['returnType'] = 'short';
|
||||
|
||||
try {
|
||||
apiStore.journalDataStatus = DataStatus.LOADING;
|
||||
|
||||
const response = (
|
||||
await apiStore.client!.get<JournalTimetablesShortResponse>('/api/getTimetables', {
|
||||
params: fetchParams
|
||||
})
|
||||
).data;
|
||||
|
||||
apiStore.journalDataStatus = DataStatus.SUCCESS;
|
||||
apiStore.journalTimetablesData = response;
|
||||
} catch (error) {
|
||||
apiStore.journalDataStatus = DataStatus.ERROR;
|
||||
apiStore.journalTimetablesData = null;
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
function clearSearch() {
|
||||
Object.keys(globalStore.journalTimetableSearch).forEach(
|
||||
(k) => ((globalStore.journalTimetableSearch as any)[k] = '')
|
||||
);
|
||||
|
||||
apiStore.journalTimetablesData = null;
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div class="flex gap-2">
|
||||
<div class="w-full">
|
||||
<input
|
||||
v-model="globalStore.localTimetableSearch"
|
||||
type="text"
|
||||
class="bg-zinc-800 p-1 rounded-md print:hidden w-full"
|
||||
:placeholder="$t('train-search-placeholder')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
class="bg-zinc-800 hover:bg-zinc-700 p-1 rounded-md"
|
||||
v-if="globalStore.viewMode == 'storage'"
|
||||
@click="clearSearch"
|
||||
>
|
||||
<TrashIcon class="size-6" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { TrashIcon } from '@heroicons/vue/16/solid';
|
||||
import { useGlobalStore } from '../../stores/global.store';
|
||||
|
||||
const globalStore = useGlobalStore();
|
||||
|
||||
function clearSearch() {
|
||||
globalStore.localTimetableSearch = '';
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<div class="flex gap-2 flex-col mb-2 print:hidden">
|
||||
<!-- Top Actions & Modes -->
|
||||
<SearchModeActions />
|
||||
|
||||
<!-- Active Data Search -->
|
||||
<ActiveSearchInput v-if="globalStore.viewMode == 'active'" />
|
||||
|
||||
<!-- Local Storage Search -->
|
||||
<LocalSearchInput v-else-if="globalStore.viewMode == 'storage'" />
|
||||
|
||||
<!-- Journal Serach -->
|
||||
<JournalSearchInput v-else />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useGlobalStore } from '../../stores/global.store';
|
||||
|
||||
import ActiveSearchInput from './ActiveSearchInput.vue';
|
||||
import JournalSearchInput from './JournalSearchInput.vue';
|
||||
import LocalSearchInput from './LocalSearchInput.vue';
|
||||
import SearchModeActions from './SearchModeActions.vue';
|
||||
|
||||
const globalStore = useGlobalStore();
|
||||
</script>
|
||||
@@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<div class="flex justify-between gap-2">
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
:class="`p-1 rounded-md ${
|
||||
globalStore.viewMode == 'active'
|
||||
? 'bg-green-600 hover:bg-green-500'
|
||||
: 'bg-zinc-800 hover:bg-zinc-700'
|
||||
}`"
|
||||
@click="toggleViewMode('active')"
|
||||
>
|
||||
<WifiIcon class="size-6" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
:class="`p-1 rounded-md ${
|
||||
globalStore.viewMode == 'storage'
|
||||
? 'bg-green-600 hover:bg-green-500'
|
||||
: 'bg-zinc-800 hover:bg-zinc-700'
|
||||
}`"
|
||||
@click="toggleViewMode('storage')"
|
||||
>
|
||||
<ArchiveBoxArrowDownIcon class="size-6" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
:class="`p-1 rounded-md ${
|
||||
globalStore.viewMode == 'journal'
|
||||
? 'bg-green-600 hover:bg-green-500'
|
||||
: 'bg-zinc-800 hover:bg-zinc-700'
|
||||
}`"
|
||||
@click="toggleViewMode('journal')"
|
||||
>
|
||||
<CloudIcon class="size-6" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<button class="bg-zinc-800 p-1 rounded-md hover:bg-zinc-700 self-end" @click="toggleDarkMode">
|
||||
<MoonIcon v-if="globalStore.darkMode" class="text-white size-6" />
|
||||
<SunIcon v-else class="text-white size-6" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="bg-zinc-800 p-1 rounded-md hover:bg-zinc-700 disabled:opacity-60 disabled:hover:bg-zinc-800"
|
||||
:disabled="globalStore.currentTimetableData == null"
|
||||
@click="openPrintingWindow"
|
||||
>
|
||||
<PrinterIcon class="text-white size-6" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="p-1 rounded-md disabled:opacity-60 disabled:hover:bg-zinc-800"
|
||||
:disabled="globalStore.currentTimetableData == null"
|
||||
:class="{
|
||||
'bg-green-600 hover:bg-green-700': isTimetableSaved,
|
||||
'bg-zinc-800 hover:bg-zinc-700': !isTimetableSaved
|
||||
}"
|
||||
@click="saveToStorage"
|
||||
>
|
||||
<ArrowDownTrayIcon class="text-white size-6" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
PrinterIcon,
|
||||
MoonIcon,
|
||||
SunIcon,
|
||||
ArchiveBoxArrowDownIcon,
|
||||
ArrowDownTrayIcon,
|
||||
CloudIcon,
|
||||
WifiIcon
|
||||
} from '@heroicons/vue/16/solid';
|
||||
import { computed, watch } from 'vue';
|
||||
import { useGlobalStore } from '../../stores/global.store';
|
||||
import type { ViewMode, TimetableData } from '../../types/common.types';
|
||||
|
||||
const globalStore = useGlobalStore();
|
||||
|
||||
// Computed
|
||||
const isTimetableSaved = computed(() => {
|
||||
if (!globalStore.currentTimetableData) return false;
|
||||
|
||||
return Object.keys(globalStore.storageTimetables).includes(
|
||||
`${globalStore.currentTimetableData.timetableId}`
|
||||
);
|
||||
});
|
||||
|
||||
// Watchers
|
||||
watch(
|
||||
() => globalStore.selectedActiveTrain,
|
||||
(curr) => {
|
||||
if (curr != null) {
|
||||
globalStore.generatedDate = new Date();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Methods
|
||||
function toggleViewMode(viewMode: ViewMode) {
|
||||
globalStore.viewMode = viewMode;
|
||||
}
|
||||
|
||||
function toggleDarkMode() {
|
||||
globalStore.darkMode = !globalStore.darkMode;
|
||||
|
||||
window.localStorage.setItem('currentTheme', globalStore.darkMode ? 'dark' : 'light');
|
||||
}
|
||||
|
||||
function saveToStorage() {
|
||||
if (globalStore.currentTimetableData == null) return;
|
||||
|
||||
try {
|
||||
const savedTimetablesStorage = localStorage.getItem('savedTimetables');
|
||||
let savedTimetablesJSON: Record<number, TimetableData> = savedTimetablesStorage
|
||||
? JSON.parse(savedTimetablesStorage)
|
||||
: {};
|
||||
|
||||
if (savedTimetablesJSON[globalStore.currentTimetableData.timetableId] !== undefined) {
|
||||
globalStore.selectedStorageTimetable =
|
||||
savedTimetablesJSON[globalStore.currentTimetableData.timetableId];
|
||||
globalStore.viewMode = 'storage';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
savedTimetablesJSON[globalStore.currentTimetableData.timetableId] = {
|
||||
...globalStore.currentTimetableData,
|
||||
savedTimestamp: Date.now()
|
||||
};
|
||||
|
||||
localStorage.setItem('savedTimetables', JSON.stringify(savedTimetablesJSON));
|
||||
globalStore.storageTimetables = savedTimetablesJSON;
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
function openPrintingWindow() {
|
||||
if (globalStore.selectedActiveTrain != null) {
|
||||
const date = `${globalStore
|
||||
.generatedDate!.toLocaleDateString('pl-PL')
|
||||
.replace(/\./g, '-')}--${globalStore
|
||||
.generatedDate!.toLocaleTimeString('pl-PL')
|
||||
.replace(/:/g, '-')}`;
|
||||
|
||||
document.title = `${globalStore.selectedActiveTrain.driverName} ; ${
|
||||
globalStore.selectedActiveTrain.timetable!.category
|
||||
} ${globalStore.selectedActiveTrain.trainNo}
|
||||
${globalStore.selectedActiveTrain.timetable?.route.replace('|', ' - ')} ; ${date}`;
|
||||
}
|
||||
|
||||
window.print();
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user