mirror of
https://github.com/Spythere/srjp-td2.git
synced 2026-05-04 05:58:12 +00:00
feat: journal timetable view mode
This commit is contained in:
@@ -1,16 +1,68 @@
|
||||
<template>
|
||||
<div class="flex gap-2 mb-2 print:hidden">
|
||||
<button
|
||||
class="p-1 rounded-md"
|
||||
:class="{
|
||||
'bg-zinc-800 hover:bg-zinc-700': globalStore.viewMode == 'active',
|
||||
'bg-green-600 hover:bg-green-500': globalStore.viewMode == 'storage',
|
||||
}"
|
||||
@click="toggleViewMode"
|
||||
>
|
||||
<ArchiveBoxArrowDownIcon class="size-6" />
|
||||
</button>
|
||||
<div class="flex gap-2 justify-between flex-wrap mb-2 print:hidden">
|
||||
<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>
|
||||
|
||||
<!-- Active Data Search -->
|
||||
<select
|
||||
name="trains"
|
||||
id="trains-select"
|
||||
@@ -21,45 +73,37 @@
|
||||
@change="selectTrain"
|
||||
>
|
||||
<option :value="null" disabled>
|
||||
{{ apiStore.activeDataStatus == DataStatus.LOADING ? $t('data-loading-text') : $t('train-select-placeholder') }}
|
||||
{{
|
||||
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) }}]
|
||||
{{ train.driverName }} | {{ train.timetable?.category }} {{ train.trainNo }} [{{
|
||||
getRegionNameById(train.region)
|
||||
}}]
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<!-- Local Storage Search -->
|
||||
<input
|
||||
type="text"
|
||||
v-if="globalStore.viewMode == 'storage'"
|
||||
v-model="globalStore.timetableSearch"
|
||||
v-model="globalStore.localTimetableSearch"
|
||||
class="bg-zinc-800 p-1 rounded-md print:hidden w-full"
|
||||
:placeholder="$t('train-search-placeholder')"
|
||||
/>
|
||||
|
||||
<button class="bg-zinc-800 p-1 rounded-md hover:bg-zinc-700" @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>
|
||||
<!-- Journal Serach -->
|
||||
<input
|
||||
type="text"
|
||||
v-else-if="globalStore.viewMode == 'journal'"
|
||||
v-model="globalStore.journalTimetableSearch"
|
||||
@change="fetchJournalTimetables"
|
||||
class="bg-zinc-800 p-1 rounded-md print:hidden w-full"
|
||||
:placeholder="$t('journal-search-placeholder')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -68,9 +112,17 @@ import { computed } from 'vue';
|
||||
import { useApiStore } from '../../stores/api.store';
|
||||
import { DataStatus } from '../../types/api.types';
|
||||
import { useGlobalStore } from '../../stores/global.store';
|
||||
import { PrinterIcon, MoonIcon, SunIcon, ArchiveBoxArrowDownIcon, ArrowDownTrayIcon } from '@heroicons/vue/16/solid';
|
||||
import {
|
||||
PrinterIcon,
|
||||
MoonIcon,
|
||||
SunIcon,
|
||||
ArchiveBoxArrowDownIcon,
|
||||
ArrowDownTrayIcon,
|
||||
CloudIcon,
|
||||
WifiIcon
|
||||
} from '@heroicons/vue/16/solid';
|
||||
import { getRegionNameById } from '../../utils/trainUtils';
|
||||
import type { TimetableData } from '../../types/common.types';
|
||||
import type { TimetableData, ViewMode } from '../../types/common.types';
|
||||
|
||||
// Stores
|
||||
const apiStore = useApiStore();
|
||||
@@ -80,22 +132,26 @@ const globalStore = useGlobalStore();
|
||||
const isTimetableSaved = computed(() => {
|
||||
if (!globalStore.currentTimetableData) return false;
|
||||
|
||||
return Object.keys(globalStore.storageTimetables).includes(`${globalStore.currentTimetableData.timetableId}`);
|
||||
return Object.keys(globalStore.storageTimetables).includes(
|
||||
`${globalStore.currentTimetableData.timetableId}`
|
||||
);
|
||||
});
|
||||
|
||||
// Methods
|
||||
function selectTrain() {
|
||||
if (!apiStore.activeData) return;
|
||||
|
||||
globalStore.selectedActiveTrain = globalStore.activeTimetableTrains.find((train) => train.id == globalStore.selectedTrainId) ?? null;
|
||||
globalStore.selectedActiveTrain =
|
||||
globalStore.activeTimetableTrains.find((train) => train.id == globalStore.selectedTrainId) ??
|
||||
null;
|
||||
|
||||
if (globalStore.selectedActiveTrain != null) {
|
||||
globalStore.generatedDate = new Date();
|
||||
}
|
||||
}
|
||||
|
||||
function toggleViewMode() {
|
||||
globalStore.viewMode = globalStore.viewMode == 'active' ? 'storage' : 'active';
|
||||
function toggleViewMode(viewMode: ViewMode) {
|
||||
globalStore.viewMode = viewMode;
|
||||
}
|
||||
|
||||
function toggleDarkMode() {
|
||||
@@ -109,16 +165,22 @@ function saveToStorage() {
|
||||
|
||||
try {
|
||||
const savedTimetablesStorage = localStorage.getItem('savedTimetables');
|
||||
let savedTimetablesJSON: Record<number, TimetableData> = savedTimetablesStorage ? JSON.parse(savedTimetablesStorage) : {};
|
||||
let savedTimetablesJSON: Record<number, TimetableData> = savedTimetablesStorage
|
||||
? JSON.parse(savedTimetablesStorage)
|
||||
: {};
|
||||
|
||||
if (savedTimetablesJSON[globalStore.currentTimetableData.timetableId] !== undefined) {
|
||||
globalStore.selectedStorageTimetable = savedTimetablesJSON[globalStore.currentTimetableData.timetableId];
|
||||
globalStore.selectedStorageTimetable =
|
||||
savedTimetablesJSON[globalStore.currentTimetableData.timetableId];
|
||||
globalStore.viewMode = 'storage';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
savedTimetablesJSON[globalStore.currentTimetableData.timetableId] = { ...globalStore.currentTimetableData, savedTimestamp: Date.now() };
|
||||
savedTimetablesJSON[globalStore.currentTimetableData.timetableId] = {
|
||||
...globalStore.currentTimetableData,
|
||||
savedTimestamp: Date.now()
|
||||
};
|
||||
|
||||
localStorage.setItem('savedTimetables', JSON.stringify(savedTimetablesJSON));
|
||||
globalStore.storageTimetables = savedTimetablesJSON;
|
||||
@@ -127,21 +189,22 @@ function saveToStorage() {
|
||||
|
||||
function openPrintingWindow() {
|
||||
if (globalStore.selectedActiveTrain != null) {
|
||||
const date = `${globalStore.generatedDate!.toLocaleDateString('pl-PL').replace(/\./g, '-')}--${globalStore
|
||||
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
|
||||
}
|
||||
document.title = `${globalStore.selectedActiveTrain.driverName} ; ${
|
||||
globalStore.selectedActiveTrain.timetable!.category
|
||||
} ${globalStore.selectedActiveTrain.trainNo}
|
||||
${globalStore.selectedActiveTrain.timetable?.route.replace('|', ' - ')} ; ${date}`;
|
||||
}
|
||||
|
||||
window.print();
|
||||
}
|
||||
|
||||
// function refreshData() {
|
||||
// apiStore.fetchActiveData();
|
||||
// selectTrain();
|
||||
// }
|
||||
async function fetchJournalTimetables() {
|
||||
apiStore.fetchJournalTimetables(globalStore.journalTimetableSearch);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<template>
|
||||
<!-- Local -->
|
||||
<div class="my-2 print:hidden" v-if="globalStore.currentTimetableData?.savedTimestamp">
|
||||
<div class="flex gap-2">
|
||||
<div class="flex items-center gap-2 bg-zinc-900 p-1 w-full">
|
||||
@@ -18,11 +19,49 @@
|
||||
</i18n-t>
|
||||
</div>
|
||||
|
||||
<button class="font-bold bg-zinc-900 p-1 hover:bg-zinc-800" @click="removeTimetable(globalStore.currentTimetableData.timetableId)">
|
||||
<button
|
||||
class="font-bold bg-zinc-900 p-1 hover:bg-zinc-800"
|
||||
@click="removeTimetable(globalStore.currentTimetableData.timetableId)"
|
||||
>
|
||||
<TrashIcon class="text-white size-6" />
|
||||
</button>
|
||||
|
||||
<button class="font-bold bg-zinc-900 p-1 hover:bg-zinc-800" @click="globalStore.selectedStorageTimetable = null">
|
||||
<button
|
||||
class="font-bold bg-zinc-900 p-1 hover:bg-zinc-800"
|
||||
@click="globalStore.selectedStorageTimetable = null"
|
||||
>
|
||||
<ArrowUturnLeftIcon class="text-white size-6" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Journal -->
|
||||
<div class="my-2 print:hidden" v-if="globalStore.currentTimetableData?.journalCreatedAt">
|
||||
<div class="flex gap-2">
|
||||
<div class="flex items-center gap-2 bg-zinc-900 p-1 w-full">
|
||||
<div>
|
||||
<InformationCircleIcon class="size-5" />
|
||||
</div>
|
||||
|
||||
<i18n-t keypath="journal-preview-info" tag="span">
|
||||
<template v-slot:id>
|
||||
<b>#{{ globalStore.currentTimetableData.timetableId }}</b>
|
||||
</template>
|
||||
<template v-slot:driverName>
|
||||
<b>{{ globalStore.currentTimetableData.driverName }}</b>
|
||||
</template>
|
||||
<template v-slot:date>
|
||||
<b>{{
|
||||
new Date(globalStore.currentTimetableData.journalCreatedAt).toLocaleString()
|
||||
}}</b>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="font-bold bg-zinc-900 p-1 hover:bg-zinc-800"
|
||||
@click="globalStore.selectedJournalTimetable = null"
|
||||
>
|
||||
<ArrowUturnLeftIcon class="text-white size-6" />
|
||||
</button>
|
||||
</div>
|
||||
@@ -45,12 +84,14 @@ function removeTimetable(timetableId: number) {
|
||||
|
||||
try {
|
||||
const savedTimetablesStorage = localStorage.getItem('savedTimetables');
|
||||
let savedTimetablesJSON: Record<number, TimetableData> = savedTimetablesStorage ? JSON.parse(savedTimetablesStorage) : {};
|
||||
let savedTimetablesJSON: Record<number, TimetableData> = savedTimetablesStorage
|
||||
? JSON.parse(savedTimetablesStorage)
|
||||
: {};
|
||||
delete savedTimetablesJSON[timetableId];
|
||||
|
||||
localStorage.setItem('savedTimetables', JSON.stringify(savedTimetablesJSON));
|
||||
globalStore.storageTimetables = savedTimetablesJSON;
|
||||
|
||||
|
||||
globalStore.selectedStorageTimetable = null;
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<template>
|
||||
<div
|
||||
:class="{ dark: globalStore.darkMode }"
|
||||
v-if="globalStore.currentTimetableData != null"
|
||||
class="overflow-auto p-1 bg-white print:bg-white dark:bg-zinc-950 print:text-black text-black dark:text-white min-h-full"
|
||||
>
|
||||
<!-- Timetable render based on current view mode -->
|
||||
<div :class="{ dark: globalStore.darkMode }" v-if="globalStore.currentTimetableData != null"
|
||||
class="overflow-auto p-1 bg-white print:bg-white dark:bg-zinc-950 print:text-black text-black dark:text-white min-h-full">
|
||||
<div>
|
||||
<div class="p-1 font-bold w-max">
|
||||
{{ globalStore.currentTimetableData.category }} {{ globalStore.currentTimetableData.trainNo }} {{ $t('headers.relation') }}
|
||||
{{ globalStore.currentTimetableData.category }} {{ globalStore.currentTimetableData.trainNo }} {{
|
||||
$t('headers.relation') }}
|
||||
{{ globalStore.currentTimetableData.route.replace('|', ' - ') }}
|
||||
</div>
|
||||
|
||||
@@ -22,9 +21,8 @@
|
||||
<div>{{ $t('train-select-info') }}</div>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<StorageView />
|
||||
</div>
|
||||
<LocalStorageView v-else-if="globalStore.viewMode == 'storage'" />
|
||||
<JournalStorageView v-else />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -35,8 +33,9 @@ import { useApiStore } from '../../stores/api.store';
|
||||
import { useGlobalStore } from '../../stores/global.store';
|
||||
import TimetableBody from './TimetableBody.vue';
|
||||
import TimetableHeader from './TimetableHeader.vue';
|
||||
import type { SceneryRoute, StopRow, TimetablePathData } from '../../types/common.types';
|
||||
import StorageView from '../TimetableStorage/StorageView.vue';
|
||||
import { type SceneryRoute, type StopRow, type TimetablePathData } from '../../types/common.types';
|
||||
import LocalStorageView from '../TimetableViews/LocalStorageView.vue';
|
||||
import JournalStorageView from '../TimetableViews/JournalStorageView.vue';
|
||||
|
||||
const globalStore = useGlobalStore();
|
||||
const apiStore = useApiStore();
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<template>
|
||||
<div>API STORAGE</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
@@ -1,56 +0,0 @@
|
||||
<template>
|
||||
<div class="text-white">
|
||||
<div v-if="globalStore.selectedStorageTimetable == null && Object.keys(globalStore.storageTimetables).length == 0">
|
||||
<div class="font-bold text-xl">{{ $t('storage-empty-header') }}</div>
|
||||
<div>{{ $t('storage-empty-info') }}</div>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<div class="font-bold p-2 bg-zinc-700 mb-3">
|
||||
<div class="text-2xl">{{ $t('storage-preview-title') }}</div>
|
||||
<div class="flex gap-2 justify-center">
|
||||
<template v-for="(mode, i) in storageModeList">
|
||||
<span v-if="i != 0">•</span>
|
||||
<button class="hover:text-green-300" :class="{ 'underline text-green-300': currentStorageModeIndex == i }" @click="selectStorageMode(i)">
|
||||
{{ $t(`storage-mode.${mode.key}`) }}
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Current storage mode component -->
|
||||
<component :is="storageModeList[currentStorageModeIndex].component" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useGlobalStore } from '../../stores/global.store';
|
||||
import { StorageMode } from '../../types/common.types';
|
||||
import { ref, type Component, type Ref } from 'vue';
|
||||
import LocalStorage from '../TimetableStorage/LocalStorage.vue';
|
||||
import ApiStorage from '../TimetableStorage/ApiStorage.vue';
|
||||
|
||||
interface CurrentStorageMode {
|
||||
key: StorageMode;
|
||||
component: Component;
|
||||
}
|
||||
|
||||
const globalStore = useGlobalStore();
|
||||
const currentStorageModeIndex: Ref<number> = ref(0);
|
||||
|
||||
const storageModeList: CurrentStorageMode[] = [
|
||||
{
|
||||
key: StorageMode.LOCAL,
|
||||
component: LocalStorage,
|
||||
},
|
||||
{
|
||||
key: StorageMode.API,
|
||||
component: ApiStorage,
|
||||
},
|
||||
];
|
||||
|
||||
function selectStorageMode(index: number) {
|
||||
currentStorageModeIndex.value = index;
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<div class="text-white">
|
||||
<h2 class="font-bold p-2 bg-zinc-700 mb-3 text-2xl">
|
||||
{{ $t('journal-preview-title') }}
|
||||
</h2>
|
||||
|
||||
<div v-if="apiStore.journalDataStatus == DataStatus.LOADING" class="bg-zinc-900 p-2">
|
||||
{{ $t('data-loading-text') }}
|
||||
</div>
|
||||
|
||||
<div v-else-if="apiStore.journalDataStatus == DataStatus.ERROR" class="bg-red-500 p-2">
|
||||
{{ $t('data-loading-error-text') }}
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else-if="!apiStore.journalTimetablesData"
|
||||
class="text-zinc-400 mt-2"
|
||||
v-html="$t('journal-empty-info')"
|
||||
></div>
|
||||
|
||||
<div v-else-if="apiStore.journalTimetablesData.length == 0">
|
||||
<p class="text-zinc-300 mb-2">
|
||||
{{ $t('journal-no-data') }}
|
||||
</p>
|
||||
|
||||
<b class="text-red-300">
|
||||
{{ $t('journal-reminder-text') }}
|
||||
</b>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<ul>
|
||||
<li
|
||||
v-for="timetable in apiStore.journalTimetablesData"
|
||||
class="flex gap-1 w-full my-2"
|
||||
@click="fetchTimetableDetails(timetable.id)"
|
||||
>
|
||||
<button class="bg-zinc-900 p-2 w-full cursor-pointer hover:bg-zinc-800 text-left">
|
||||
<div class="text-zinc-300">
|
||||
#{{ timetable.id }} •
|
||||
{{ new Date(timetable.createdAt!).toLocaleString() }}
|
||||
</div>
|
||||
<b>
|
||||
{{ timetable.driverName }} | {{ timetable.trainCategoryCode }}
|
||||
{{ timetable.trainNo }}
|
||||
</b>
|
||||
{{ timetable.route.replace('|', ' > ') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div v-if="apiStore.journalTimetablesData.length > 0">
|
||||
<hr class="border-t-2 border-t-gray-500" />
|
||||
|
||||
<p class="text-zinc-400 text-sm">
|
||||
{{ $t('journal-footer-text') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useApiStore } from '../../stores/api.store';
|
||||
import { DataStatus } from '../../types/api.types';
|
||||
|
||||
const apiStore = useApiStore();
|
||||
|
||||
function fetchTimetableDetails(id: number) {
|
||||
apiStore.fetchJournalTimetableDetails(id);
|
||||
}
|
||||
</script>
|
||||
+45
-14
@@ -1,16 +1,42 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="font-bold p-2 bg-zinc-800 mb-3" v-if="filteredTimetables.length == 0">{{ $t('storage-preview-empty') }}</div>
|
||||
<div class="text-white">
|
||||
<div class="font-bold p-2 bg-zinc-700 mb-3">
|
||||
<div class="text-2xl">{{ $t('storage-preview-title') }}</div>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
<div
|
||||
v-if="
|
||||
globalStore.selectedStorageTimetable == null &&
|
||||
Object.keys(globalStore.storageTimetables).length == 0
|
||||
"
|
||||
class="text-zinc-400"
|
||||
>
|
||||
{{ $t('storage-empty-info') }}
|
||||
</div>
|
||||
|
||||
<div class="font-bold p-2 bg-zinc-800 mb-3" v-else-if="filteredTimetables.length == 0">
|
||||
{{ $t('storage-preview-empty') }}
|
||||
</div>
|
||||
|
||||
<ul v-else>
|
||||
<li v-for="timetable in filteredTimetables" class="flex gap-1 w-full my-2">
|
||||
<button class="bg-zinc-900 p-2 w-full cursor-pointer hover:bg-zinc-800 text-left" @click="selectTimetable(timetable)">
|
||||
<div class="text-zinc-300">#{{ timetable.timetableId }} • {{ new Date(timetable.savedTimestamp!).toLocaleString() }}</div>
|
||||
<b>{{ timetable.driverName }} | {{ timetable.category }} {{ timetable.trainNo }}</b> {{ timetable.route.replace('|', ' > ') }}
|
||||
<button
|
||||
class="bg-zinc-900 p-2 w-full cursor-pointer hover:bg-zinc-800 text-left"
|
||||
@click="selectTimetable(timetable)"
|
||||
>
|
||||
<div class="text-zinc-300">
|
||||
#{{ timetable.timetableId }} •
|
||||
{{ new Date(timetable.savedTimestamp!).toLocaleString() }}
|
||||
</div>
|
||||
<b>{{ timetable.driverName }} | {{ timetable.category }} {{ timetable.trainNo }}</b>
|
||||
{{ timetable.route.replace('|', ' > ') }}
|
||||
</button>
|
||||
|
||||
<button class="bg-zinc-900 p-2 hover:bg-zinc-800" @click="removeTimetable(timetable.timetableId)">
|
||||
<TrashIcon class="size-5 text-white" />
|
||||
<button
|
||||
class="bg-zinc-900 p-2 hover:bg-zinc-800"
|
||||
@click="removeTimetable(timetable.timetableId)"
|
||||
>
|
||||
<TrashIcon class="size-6 text-white" />
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -18,11 +44,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useGlobalStore } from '../../stores/global.store';
|
||||
import { computed } from 'vue';
|
||||
import { TrashIcon } from '@heroicons/vue/16/solid';
|
||||
import type { TimetableData } from '../../types/common.types';
|
||||
import { TrashIcon } from '@heroicons/vue/16/solid';
|
||||
|
||||
const globalStore = useGlobalStore();
|
||||
const i18n = useI18n();
|
||||
@@ -30,11 +56,11 @@ const i18n = useI18n();
|
||||
const filteredTimetables = computed(() => {
|
||||
let timetables = Object.values(globalStore.storageTimetables);
|
||||
|
||||
if (globalStore.timetableSearch.length != 0)
|
||||
if (globalStore.localTimetableSearch.length != 0)
|
||||
timetables = timetables.filter((st) =>
|
||||
`${st.timetableId} ${st.driverName} ${st.route} ${st.category} ${st.trainNo}`
|
||||
.toLocaleLowerCase()
|
||||
.includes(globalStore.timetableSearch.toLocaleLowerCase())
|
||||
.includes(globalStore.localTimetableSearch.toLocaleLowerCase())
|
||||
);
|
||||
|
||||
timetables.sort((a, b) => {
|
||||
@@ -55,11 +81,16 @@ function removeTimetable(timetableId: number) {
|
||||
|
||||
try {
|
||||
const savedTimetablesStorage = localStorage.getItem('savedTimetables');
|
||||
let savedTimetablesJSON: Record<number, TimetableData> = savedTimetablesStorage ? JSON.parse(savedTimetablesStorage) : {};
|
||||
let savedTimetablesJSON: Record<number, TimetableData> = savedTimetablesStorage
|
||||
? JSON.parse(savedTimetablesStorage)
|
||||
: {};
|
||||
delete savedTimetablesJSON[timetableId];
|
||||
|
||||
localStorage.setItem('savedTimetables', JSON.stringify(savedTimetablesJSON));
|
||||
|
||||
globalStore.storageTimetables = savedTimetablesJSON;
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user