refactor: order list & order message logic for new data

This commit is contained in:
2025-09-29 19:30:30 +02:00
parent 7784e08f03
commit a0a5e72701
6 changed files with 184 additions and 185 deletions
+56 -57
View File
@@ -1,10 +1,10 @@
<template> <template>
<section class="order-list"> <section class="order-list">
<h3>{{ $t('order-list.title') }} ({{ localOrderList.length }})</h3> <h3>{{ t('order-list.title') }} ({{ storageOrderList.length }})</h3>
<transition-group name="list" tag="ul"> <transition-group name="list" tag="ul">
<li class="no-orders-warning" v-if="sortedOrderList.length == 0" :key="-1"> <li class="no-orders-warning" v-if="sortedOrderList.length == 0" :key="-1">
{{ $t('order-list.no-saved-orders') }} {{ t('order-list.no-saved-orders') }}
</li> </li>
<li <li
@@ -15,10 +15,9 @@
<b class="text--accent">#{{ order.id.split('-')[1] }}&nbsp;</b> <b class="text--accent">#{{ order.id.split('-')[1] }}&nbsp;</b>
<b> <b>
{{ {{
$t('order-list.order-title', { t('order-list.order-title', {
orderName: getOrderName(order.orderType), id: order.id,
orderNo: order.orderBody['header']['orderNo'], trainNo: order.orderData.header.A
trainNo: order.orderBody['header']['trainNo']
}) })
}} }}
</b> </b>
@@ -26,21 +25,21 @@
v-if="!order.orderVersion || order.orderVersion != ORDER_VERSION" v-if="!order.orderVersion || order.orderVersion != ORDER_VERSION"
class="wrong-order-indicator" class="wrong-order-indicator"
tabindex="0" tabindex="0"
data-tooltip="Przestarzała wersja rozkazu! Może generować złe informacje!" :data-tooltip="t('order-list.warning-deprecated-version')"
>&#9888; >&#9888;
</span> </span>
<br /> <br />
{{ $t(`order-list.order-${order.createdAt ? 'added' : 'updated'}`) }} {{ t(`order-list.order-${order.createdAt ? 'added' : 'updated'}`) }}
{{ new Date(order.createdAt || order.updatedAt || 0).toLocaleString('pl-PL') }} {{ new Date(order.createdAt || order.updatedAt || 0).toLocaleString('pl-PL') }}
<hr /> <hr />
<div class="buttons"> <div class="buttons">
<button class="g-button" @click="selectLocalOrder(order)"> <button class="g-button" @click="selectLocalOrder(order)">
{{ $t('order-list.button-order-select') }} {{ t('order-list.button-order-select') }}
</button> </button>
<button class="g-button" @click="removeOrder(order)"> <button class="g-button" @click="removeOrder(order.id)">
{{ $t('order-list.button-order-remove') }} {{ t('order-list.button-order-remove') }}
</button> </button>
</div> </div>
</li> </li>
@@ -48,68 +47,68 @@
</section> </section>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent } from 'vue'; import { computed, onActivated, Reactive, reactive } from 'vue';
import orderStorageMixin from '../mixins/orderStorageMixin';
import { useStore } from '../store/store'; import { useStore } from '../store/store';
import { LocalStorageOrderLegacy } from '../types/orderTypes'; import { IStorageOrderData, LocalStorageOrderLegacy } from '../types/orderTypes';
import StorageManager from '../managers/storageManager';
import { useI18n } from 'vue-i18n';
export default defineComponent({ const { t } = useI18n();
name: 'OrderList', const store = useStore();
mixins: [orderStorageMixin], const storageOrderList = reactive<Reactive<IStorageOrderData[]>>([]);
data() { const ORDER_VERSION = import.meta.env['VITE_APP_ORDER_VERSION'];
return {
localOrderList: [] as LocalStorageOrderLegacy[],
ORDER_VERSION: import.meta.env['VITE_APP_ORDER_VERSION']
};
},
setup() { function removeOrder(orderId: string) {
return { StorageManager.removeValue(orderId);
store: useStore(),
localStorage: window.localStorage
};
},
methods: { if (store.chosenLocalOrderId == orderId) store.chosenLocalOrderId = '';
getOrderName(orderType: string) { storageOrderList.splice(storageOrderList.findIndex((o) => o.id == orderId));
return orderType.split('order')[1];
},
removeOrder(order: LocalStorageOrderLegacy) { if (storageOrderList.length == 0) StorageManager.setNumericValue('orderCount', 0);
if (!order) return; }
this.removeLocalOrder(order); function selectLocalOrder(order: IStorageOrderData) {
this.localOrderList = this.localOrderList.filter((o) => o.id != order.id); store.orderData = order.orderData;
}
if (this.localOrderList.length == 0) this.saveOrderSetting('orderCount', 0); function isOrderDeprecated(
} order: IStorageOrderData | LocalStorageOrderLegacy
}, ): order is LocalStorageOrderLegacy {
return 'orderType' in order;
}
computed: { const sortedOrderList = computed(() => {
sortedOrderList() { return storageOrderList
return this.localOrderList .slice()
.slice() .sort((a, b) => (b.createdAt || b.updatedAt || 0) - (a.createdAt || a.updatedAt || 0));
.sort((a, b) => (b.createdAt || b.updatedAt!) - (a.createdAt || a.updatedAt!)); });
}
},
activated() { onActivated(() => {
const localStorage = window.localStorage; const localStorage = window.localStorage;
const orderList = []; const orderList = [];
for (let key in localStorage) { let deprecatedOrders = 0;
if (!/^order-/g.test(key)) continue;
const orderObj: LocalStorageOrderLegacy = JSON.parse(localStorage[key]); for (let key in localStorage) {
if (!orderObj) continue; if (!/^order-/g.test(key)) continue;
orderList.push(orderObj); const orderObj: IStorageOrderData | LocalStorageOrderLegacy = JSON.parse(localStorage[key]);
if (!orderObj) continue;
if (isOrderDeprecated(orderObj)) {
console.warn(`Deprecated order found with ID: ${orderObj.id}`);
continue;
} }
this.localOrderList = orderList; orderList.push(orderObj);
} }
if (deprecatedOrders != 0) {
}
storageOrderList.push(...orderList);
}); });
</script> </script>
+118 -103
View File
@@ -62,25 +62,44 @@
</div> </div>
<transition name="monit-anim"> <transition name="monit-anim">
<div class="action_monit" v-if="actionMonit" v-html="actionMonit"></div> <div
class="action_monit"
v-if="actionMonit.content"
v-html="actionMonit.content"
:class="{
'text--warn': actionMonit.type == 'warning'
}"
></div>
</transition> </transition>
</section> </section>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, onMounted, ref, watch } from 'vue'; import { computed, onMounted, Reactive, reactive, ref, watch } from 'vue';
import { useStore } from '../store/store'; import { useStore } from '../store/store';
import { currentFormattedHours, currentFormattedMinutes } from '../utils/dateUtils';
import StorageManager from '../managers/storageManager';
import { LocalStorageOrderLegacy } from '../types/orderTypes';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import StorageManager from '../managers/storageManager';
import { currentFormattedHours, currentFormattedMinutes } from '../utils/dateUtils';
import { IStorageOrderData } from '../types/orderTypes';
type TActionMonitType = 'warning' | 'info' | 'success';
interface IActionMonit {
type: TActionMonitType;
content: string;
timeoutId: number | null;
}
const { t } = useI18n(); const { t } = useI18n();
const store = useStore(); const store = useStore();
const actionMonit = ref(''); const actionMonit: Reactive<IActionMonit> = reactive({
const monitTimeout = ref(0); visible: false,
type: 'info',
content: '',
timeoutId: null
});
const incrementOnSave = ref(true); const incrementOnSave = ref(true);
const incrementOnCopy = ref(true); const incrementOnCopy = ref(true);
@@ -106,137 +125,135 @@ function onCheckboxChange(e: Event) {
StorageManager.setBooleanValue(checkbox.id, checkbox.checked); StorageManager.setBooleanValue(checkbox.id, checkbox.checked);
} }
function showActionMonit(text: string) { function showActionMonit(content: string, type: TActionMonitType) {
if (monitTimeout.value) { if (actionMonit.timeoutId != null) {
actionMonit.value = ''; actionMonit.content = '';
clearTimeout(monitTimeout.value);
// setTimeout(() => { clearTimeout(actionMonit.timeoutId);
actionMonit.value = text;
monitTimeout.value = window.setTimeout(() => { setTimeout(() => {
actionMonit.value = ''; actionMonit.content = content;
}, 5000); actionMonit.type = type;
// }, 300);
actionMonit.timeoutId = window.setTimeout(() => {
actionMonit.content = '';
actionMonit.timeoutId = null;
}, 5000);
}, 100);
return; return;
} }
actionMonit.value = text; actionMonit.content = content;
actionMonit.type = type;
monitTimeout.value = window.setTimeout(() => { actionMonit.timeoutId = window.setTimeout(() => {
actionMonit.value = ''; actionMonit.content = '';
actionMonit.timeoutId = null;
}, 5000); }, 5000);
} }
function verifyOrderFields() {
const { header, footer } = store.orderData;
const fieldsToCorrect: string[] = [];
Object.entries(header).forEach(([k, v]) => {
if (v.trim().length == 0) {
fieldsToCorrect.push(`order.header.${k}`);
}
});
Object.entries(footer).forEach(([k, v]) => {
if (v.trim().length == 0) {
fieldsToCorrect.push(`order.footer.${k}`);
}
});
return fieldsToCorrect;
}
// TODO // TODO
function incrementOrderNo() { function incrementOrderNo() {
// store.orderData.header. // store.orderData. = (Number(order.header.orderNo) + 1).toString();
// order.header.orderNo = (Number(order.header.orderNo) + 1).toString();
} }
function copyMessage() { function copyMessage() {
if (!navigator.clipboard) return showActionMonit(t('order-message.warning-outdated-clipboard')); if (!navigator.clipboard)
return showActionMonit(t('order-message.warning-outdated-clipboard'), 'warning');
const hasAtLeastOneRow = /(\[ \d \])/g.test(orderMessagePreview.value); // const hasAtLeastOneRow = /(\[ \d \])/g.test(orderMessagePreview.value);
const hasAllInputsFilled = !/_/g.test(store.orderMessage); // const hasAllInputsFilled = !/_/g.test(store.orderMessage);
if (!hasAllInputsFilled) // if (!hasAllInputsFilled)
return showActionMonit( // return showActionMonit(
`<span class="text--warn">${t('order-message.warning-fill-inputs')}</span>` // `${t('order-message.warning-fill-inputs')}`
); // );
if (!hasAtLeastOneRow) // if (!hasAtLeastOneRow)
return showActionMonit( // return showActionMonit(
`<span class="text--warn">${t('order-message.warning-add-rows')}</span>` // `${t('order-message.warning-add-rows')}`
); // );
const fieldsToCorrect = verifyOrderFields(); const fieldsToCorrect = verifyOrderFields();
if (fieldsToCorrect.length > 0) if (fieldsToCorrect.length > 0)
return showActionMonit( return showActionMonit(
`<span class="text--warn">${t('order-message.warning-fill-footer')} ${fieldsToCorrect.join( `${t('order-message.warning-fill-footer')} ${fieldsToCorrect.join(', ')}`,
', ' 'warning'
)}</span>`
); );
navigator.clipboard.writeText(orderMessagePreview.value); navigator.clipboard.writeText(orderMessagePreview.value);
if (incrementOnCopy) incrementOrderNo(); if (incrementOnCopy) incrementOrderNo();
showActionMonit(t('order-message.success-copy-html')); showActionMonit(t('order-message.success-copy-html'), 'success');
}
function verifyOrderFields() {
// const header = this.store[this.store.chosenOrderType].header;
const footer = store.orderFooter;
const fieldsToCorrect = [];
// if (!header.orderNo) fieldsToCorrect.push('numer rozkazu');
// if (!header.trainNo) fieldsToCorrect.push('numer pociągu / manewru');
// if (!header.date) fieldsToCorrect.push('data');
if (!footer.stationName) fieldsToCorrect.push('stacja');
if (!footer.checkpointName) fieldsToCorrect.push('posterunek');
if (!footer.hour) fieldsToCorrect.push('godzina');
if (!footer.minutes) fieldsToCorrect.push('minuta');
if (!footer.dispatcherName && !footer.secondaryDispatcherName)
fieldsToCorrect.push('dyżurny ruchu (lub z polecenia dyżurnego ruchu)');
return fieldsToCorrect;
} }
function saveOrder() { function saveOrder() {
const orderObj: LocalStorageOrderLegacy = { const noHeaderInfo = Object.values(store.orderData.header).some((v) => {
id: '', return v.trim().length == 0;
orderType: store.chosenOrderType, });
orderBody: store[store.chosenOrderType],
orderFooter: store.orderFooter,
createdAt: Date.now(),
orderVersion: import.meta.env['VITE_APP_ORDER_VERSION'] || '3'
};
// const headerInfo = orderObj['orderBody']['header']; if (noHeaderInfo) {
showActionMonit(`${t('order-message.warning-fill-top')}`, 'warning');
// if (!headerInfo['orderNo']) return -1;
// if (!headerInfo['trainNo']) return -1;
// if (!headerInfo['date']) return -1;
// No header info: -1
// showActionMonit(`<span class="text--warn">${t('order-message.warning-fill-top')}</span>`)
const localStorage = window.localStorage;
const localOrderCount = localStorage.getItem('orderCount') || '0';
if (localOrderCount == '0') localStorage.setItem('orderCount', '0');
const prevLocalOrder = localStorage.getItem(`order-${Number(localOrderCount)}`);
if (prevLocalOrder && prevLocalOrder == JSON.stringify(orderObj)) {
showActionMonit(
`<span class="text--warn">${t('order-message.warning-order-identical')}</span>`
);
return; return;
} }
const nextOrderCount = Number(localOrderCount) + 1; const orderDataToSave: IStorageOrderData = {
const orderId = `order-${nextOrderCount}`; id: '',
orderObj['id'] = orderId; createdAt: Date.now(),
orderVersion: import.meta.env['VITE_APP_ORDER_VERSION'] || '3',
orderData: store.orderData
};
const localStorage = window.localStorage;
const localOrderCount = StorageManager.getNumericValue('orderCount') || 0;
if (localOrderCount == 0) StorageManager.setNumericValue('orderCount', 0);
const prevLocalOrder = StorageManager.getValue(`order-${Number(localOrderCount)}`);
if (prevLocalOrder && prevLocalOrder == JSON.stringify(orderDataToSave)) {
showActionMonit(`${t('order-message.warning-order-identical')}`, 'warning');
return;
}
const nextOrderCount = localOrderCount + 1;
const nextOrderId = `order-${nextOrderCount}`;
orderDataToSave['id'] = nextOrderId;
localStorage.setItem('orderCount', `${nextOrderCount}`); localStorage.setItem('orderCount', `${nextOrderCount}`);
localStorage.setItem(orderId, JSON.stringify(orderObj)); localStorage.setItem(nextOrderId, JSON.stringify(orderDataToSave));
store.chosenLocalOrderId = orderId; store.chosenLocalOrderId = nextOrderId;
showActionMonit(t('order-message.success-save-html')); showActionMonit(t('order-message.success-save-html'), 'success');
if (incrementOnSave) incrementOrderNo(); if (incrementOnSave) incrementOrderNo();
} }
function updateOrder() { function updateOrder() {
if (!store.chosenLocalOrderId) { if (!store.chosenLocalOrderId) {
showActionMonit( showActionMonit(`${t('order-message.warning-no-order-selected')}`, 'warning');
`<span class="text--warn">${t('order-message.warning-no-order-selected')}</span>`
);
return; return;
} }
@@ -244,21 +261,19 @@ function updateOrder() {
const localOrder = window.localStorage.getItem(store.chosenLocalOrderId); const localOrder = window.localStorage.getItem(store.chosenLocalOrderId);
if (!localOrder) { if (!localOrder) {
showActionMonit(`<span class="text--warn">${t('order-message.error-update')}</span>`); showActionMonit(`${t('order-message.error-update')}`, 'warning');
return; return;
} }
const orderObj: LocalStorageOrderLegacy = { const orderDataToUpdate: IStorageOrderData = {
id: store.chosenLocalOrderId, id: store.chosenLocalOrderId,
orderType: store.chosenOrderType, orderData: store.orderData,
orderBody: store[store.chosenOrderType],
orderFooter: store.orderFooter,
updatedAt: Date.now(), updatedAt: Date.now(),
orderVersion: import.meta.env['VITE_APP_ORDER_VERSION'] || '1' orderVersion: import.meta.env['VITE_APP_ORDER_VERSION'] || '3'
}; };
window.localStorage.setItem(store.chosenLocalOrderId, JSON.stringify(orderObj)); window.localStorage.setItem(store.chosenLocalOrderId, JSON.stringify(orderDataToUpdate));
showActionMonit(t('order-message.success-update-html')); showActionMonit(t('order-message.success-update-html'), 'warning');
} }
</script> </script>
+4 -3
View File
@@ -27,7 +27,7 @@
"warning-fill-inputs": "Fill all the empty fields before copying the order!", "warning-fill-inputs": "Fill all the empty fields before copying the order!",
"warning-add-rows": "Add at least one row before copying the order!", "warning-add-rows": "Add at least one row before copying the order!",
"warning-fill-footer": "Fill the following rows in the order's footer before copying it:", "warning-fill-footer": "Fill the following rows in the order's footer before copying it:",
"warning-fill-top": "Fill the order number, train number and date before saving it!", "warning-fill-top": "Fill at least fields A, B, C and D in the order's header before saving it!",
"warning-order-identical": "Last saved order is identical as the current one!", "warning-order-identical": "Last saved order is identical as the current one!",
"warning-no-order-selected": "Choose the already saved order first!", "warning-no-order-selected": "Choose the already saved order first!",
"error-update": "An error occurred while saving this order! :/", "error-update": "An error occurred while saving this order! :/",
@@ -52,12 +52,13 @@
}, },
"order-list": { "order-list": {
"title": "Saved train orders", "title": "Saved train orders",
"order-title": "Order \"{orderName}\" no. {orderNo} for train no. {trainNo}", "order-title": "Order #{id} for train no. {trainNo}",
"no-saved-orders": "No saved orders!", "no-saved-orders": "No saved orders!",
"order-added": "Added:", "order-added": "Added:",
"order-updated": "Updated:", "order-updated": "Updated:",
"button-order-select": "Select", "button-order-select": "Select",
"button-order-remove": "Remove" "button-order-remove": "Remove",
"warning-deprecated-version": "Deprecated version of the order - may generate incorrect information!"
}, },
"order-train-picker": { "order-train-picker": {
"placeholder-scenery-name": "Scenery name", "placeholder-scenery-name": "Scenery name",
+4 -3
View File
@@ -27,7 +27,7 @@
"warning-fill-inputs": "Wypełnij puste rubryki rozkazu przed jego skopiowaniem!", "warning-fill-inputs": "Wypełnij puste rubryki rozkazu przed jego skopiowaniem!",
"warning-add-rows": "Dodaj co najmniej jedną działkę rozkazu przed jego skopiowaniem!", "warning-add-rows": "Dodaj co najmniej jedną działkę rozkazu przed jego skopiowaniem!",
"warning-fill-footer": "Uzupełnij następujące rubryki na dole rozkazu przed jego skopiowaniem:", "warning-fill-footer": "Uzupełnij następujące rubryki na dole rozkazu przed jego skopiowaniem:",
"warning-fill-top": "Wypełnij numer rozkazu, numer pociągu i datę zanim dodasz rozkaz!", "warning-fill-top": "Wypełnij co najmniej rubryki A, B, C i D w nagłówku rozkazu przed jego zapisaniem!",
"warning-order-identical": "Ostatni zapisany rozkaz jest identyczny z obecnym!", "warning-order-identical": "Ostatni zapisany rozkaz jest identyczny z obecnym!",
"warning-no-order-selected": "Wybierz rozkaz, który chcesz zaktualizować!", "warning-no-order-selected": "Wybierz rozkaz, który chcesz zaktualizować!",
"error-update": "Wystąpił błąd podczas aktualizowania tego rozkazu! :/", "error-update": "Wystąpił błąd podczas aktualizowania tego rozkazu! :/",
@@ -53,11 +53,12 @@
"order-list": { "order-list": {
"title": "Zapisane rozkazy pisemne", "title": "Zapisane rozkazy pisemne",
"no-saved-orders": "Brak zapisanych rozkazów!", "no-saved-orders": "Brak zapisanych rozkazów!",
"order-title": "Rozkaz \"{orderName}\" nr {orderNo} dla pociągu nr {trainNo}", "order-title": "Rozkaz pisemny #{id} dla pociągu nr {trainNo}",
"order-added": "Dodano:", "order-added": "Dodano:",
"order-updated": "Zaktualizowano:", "order-updated": "Zaktualizowano:",
"button-order-select": "Wybierz", "button-order-select": "Wybierz",
"button-order-remove": "Usuń" "button-order-remove": "Usuń",
"warning-deprecated-version": "Przestarzała wersja rozkazu! Może generować złe informacje!"
}, },
"order-train-picker": { "order-train-picker": {
"placeholder-scenery-name": "Sceneria", "placeholder-scenery-name": "Sceneria",
+1 -18
View File
@@ -32,21 +32,4 @@ export interface ISceneryData {
routes: string; routes: string;
signalType: string; signalType: string;
url: string; url: string;
} }
// export interface ITrainData {
// trainNo: number;
// driverId: number;
// driverName: string;
// driverIsSupporter: boolean;
// dataSignal: string;
// dataSceneryConnection: string;
// dataDistance: number;
// dataCon: string;
// dataSpeed: number;
// dataMass: number;
// dataLength: number;
// region: string;
// isOnline: number;
// lastSeen: number;
// station?: ISceneryData;
// }
+1 -1
View File
@@ -13,7 +13,7 @@ export interface LocalStorageOrderLegacy {
export interface IStorageOrderData { export interface IStorageOrderData {
id: string; id: string;
orderVersion: string; orderVersion: string;
createdAt: number; createdAt?: number;
updatedAt?: number; updatedAt?: number;
orderData: IOrderData; orderData: IOrderData;
} }