refactor: updated order message component

This commit is contained in:
2025-09-27 22:16:26 +02:00
parent 73c397a1bc
commit 5a2be7b25e
7 changed files with 201 additions and 257 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
VITE_APP_API_URL=https://stacjownik.spythere.eu/api
VITE_APP_SWDR_URL=https://api.td2.info.pl
VITE_APP_ORDER_VERSION=2
VITE_APP_ORDER_VERSION=3 # 3 - NEW 2025 ORDER INSTRUCTIONS
#VITE_UPDATE_TEST='test'
+2 -4
View File
@@ -56,7 +56,7 @@ export default defineComponent({
loadSettings() {
document.title = `GeneraTOR ${this.appVersion}`;
this.store.orderDarkMode = this.getOrderSetting('dark-mode') === 'true';
this.store.orderDarkMode = StorageManager.getBooleanValue('dark-mode');
},
handleQueries() {
@@ -65,7 +65,7 @@ export default defineComponent({
const id = query.get('sceneryId');
if (id != null) {
this.store.orderMode = 'OrderTrainPicker';
this.store.panelMode = 'OrderTrainPicker';
}
},
@@ -93,8 +93,6 @@ export default defineComponent({
StorageManager.setStringValue(STORAGE_VERSION_KEY, this.appVersion);
},
loadLang() {
const storageLang = StorageManager.getStringValue('lang');
+182 -162
View File
@@ -67,179 +67,199 @@
</section>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
<script lang="ts" setup>
import { computed, onMounted, ref, watch } from 'vue';
import { useStore } from '../store/store';
import saveIcon from '../assets/icon-save.svg';
import orderStorageMixin from '../mixins/orderStorageMixin';
import orderValidationMixin from '../mixins/orderValidationMixin';
import { currentFormattedHours, currentFormattedMinutes } from '../utils/dateUtils';
import StorageManager from '../managers/storageManager';
import { LocalStorageOrder } from '../types/orderTypes';
import { useI18n } from 'vue-i18n';
export default defineComponent({
name: 'OrderMessage',
const { t } = useI18n();
const store = useStore();
mixins: [orderStorageMixin, orderValidationMixin],
const actionMonit = ref('');
const monitTimeout = ref(0);
data() {
return {
saveIcon,
actionMonit: '',
monitTimeout: undefined as number | undefined,
const incrementOnSave = ref(true);
const incrementOnCopy = ref(true);
const updateDate = ref(true);
incrementOnSave: true,
incrementOnCopy: true,
updateDate: true
};
},
onMounted(() => {
incrementOnSave.value = StorageManager.getBooleanValue('save-increment');
incrementOnCopy.value = StorageManager.getBooleanValue('copy-increment');
updateDate.value = StorageManager.getBooleanValue('update-date');
});
setup() {
return {
store: useStore()
};
},
const orderMessagePreview = computed(() => store.orderMessage);
mounted() {
this.incrementOnSave = this.getOrderSetting('save-increment') === 'true';
this.incrementOnCopy = this.getOrderSetting('copy-increment') === 'true';
this.updateDate = this.getOrderSetting('update-date') === 'true';
},
computed: {
fullOrderMessage() {
return this.store.orderMessage + this.store.footerMessage;
},
// Replace all new line tags with <br> for preview and get rid of the first one (visible only on simulator's chat)
orderMessagePreview() {
return this.fullOrderMessage.replace(/\n/g, '<br>').replace('<br>', '');
}
},
watch: {
fullOrderMessage() {
if (this.updateDate) {
this.store.orderFooter['hour'] = currentFormattedHours();
this.store.orderFooter['minutes'] = currentFormattedMinutes();
}
}
},
methods: {
onCheckboxChange(e: Event) {
const checkbox = e.target as HTMLInputElement;
this.saveOrderSetting(checkbox.id, checkbox.checked);
},
showActionMonit(text: string) {
if (this.monitTimeout) {
this.actionMonit = '';
clearTimeout(this.monitTimeout);
setTimeout(() => {
this.actionMonit = text;
this.monitTimeout = window.setTimeout(() => {
this.actionMonit = '';
}, 5000);
}, 300);
return;
}
this.actionMonit = text;
this.monitTimeout = window.setTimeout(() => {
this.actionMonit = '';
}, 5000);
},
incrementOrderNo() {
const order = this.store[this.store.chosenOrderType];
order.header.orderNo = (Number(order.header.orderNo) + 1).toString();
},
copyMessage() {
if (!navigator.clipboard)
return this.showActionMonit(this.$t('order-message.warning-outdated-clipboard'));
const hasAtLeastOneRow = /(\[ \d \])/g.test(this.fullOrderMessage);
const hasAllInputsFilled = !/_/g.test(this.store.orderMessage);
if (!hasAllInputsFilled)
return this.showActionMonit(
`<span class="text--warn">${this.$t('order-message.warning-fill-inputs')}</span>`
);
if (!hasAtLeastOneRow)
return this.showActionMonit(
`<span class="text--warn">${this.$t('order-message.warning-add-rows')}</span>`
);
const fieldsToCorrect = this.verifyOrderFields();
if (fieldsToCorrect.length > 0)
return this.showActionMonit(
`<span class="text--warn">${this.$t('order-message.warning-fill-footer')} ${fieldsToCorrect.join(
', '
)}</span>`
);
navigator.clipboard.writeText(this.fullOrderMessage);
if (this.incrementOnCopy) this.incrementOrderNo();
this.showActionMonit(this.$t('order-message.success-copy-html'));
},
saveOrder() {
const savedOrderStatus = this.saveLocalOrder();
switch (savedOrderStatus) {
case -1:
this.showActionMonit(
`<span class="text--warn">${this.$t('order-message.warning-fill-top')}</span>`
);
break;
case 0:
this.showActionMonit(
`<span class="text--warn">${this.$t('order-message.warning-order-identical')}</span>`
);
break;
case 1:
this.showActionMonit(this.$t('order-message.success-save-html'));
if (this.incrementOnSave) this.incrementOrderNo();
break;
default:
break;
}
},
updateOrder() {
const updatedOrderStatus = this.updateLocalOrder();
switch (updatedOrderStatus) {
case -1:
this.showActionMonit(
`<span class="text--warn">${this.$t('order-message.error-update')}</span>`
);
break;
case 0:
this.showActionMonit(
`<span class="text--warn">${this.$t('order-message.warning-no-order-selected')}</span>`
);
break;
case 1:
this.showActionMonit(this.$t('order-message.success-update-html'));
break;
}
}
watch(orderMessagePreview, () => {
if (updateDate.value == true) {
store.orderFooter['hour'] = currentFormattedHours();
store.orderFooter['minutes'] = currentFormattedMinutes();
}
});
function onCheckboxChange(e: Event) {
const checkbox = e.target as HTMLInputElement;
StorageManager.setBooleanValue(checkbox.id, checkbox.checked);
}
function showActionMonit(text: string) {
if (monitTimeout.value) {
actionMonit.value = '';
clearTimeout(monitTimeout.value);
// setTimeout(() => {
actionMonit.value = text;
monitTimeout.value = window.setTimeout(() => {
actionMonit.value = '';
}, 5000);
// }, 300);
return;
}
actionMonit.value = text;
monitTimeout.value = window.setTimeout(() => {
actionMonit.value = '';
}, 5000);
}
// TODO
function incrementOrderNo() {
// store.orderData.header.
// order.header.orderNo = (Number(order.header.orderNo) + 1).toString();
}
function copyMessage() {
if (!navigator.clipboard) return showActionMonit(t('order-message.warning-outdated-clipboard'));
const hasAtLeastOneRow = /(\[ \d \])/g.test(orderMessagePreview.value);
const hasAllInputsFilled = !/_/g.test(store.orderMessage);
if (!hasAllInputsFilled)
return showActionMonit(
`<span class="text--warn">${t('order-message.warning-fill-inputs')}</span>`
);
if (!hasAtLeastOneRow)
return showActionMonit(
`<span class="text--warn">${t('order-message.warning-add-rows')}</span>`
);
const fieldsToCorrect = verifyOrderFields();
if (fieldsToCorrect.length > 0)
return showActionMonit(
`<span class="text--warn">${t('order-message.warning-fill-footer')} ${fieldsToCorrect.join(
', '
)}</span>`
);
navigator.clipboard.writeText(orderMessagePreview.value);
if (incrementOnCopy) incrementOrderNo();
showActionMonit(t('order-message.success-copy-html'));
}
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() {
const orderObj: LocalStorageOrder = {
id: '',
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 (!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;
}
const nextOrderCount = Number(localOrderCount) + 1;
const orderId = `order-${nextOrderCount}`;
orderObj['id'] = orderId;
localStorage.setItem('orderCount', `${nextOrderCount}`);
localStorage.setItem(orderId, JSON.stringify(orderObj));
store.chosenLocalOrderId = orderId;
showActionMonit(t('order-message.success-save-html'));
if (incrementOnSave) incrementOrderNo();
}
function updateOrder() {
if (!store.chosenLocalOrderId) {
showActionMonit(
`<span class="text--warn">${t('order-message.warning-no-order-selected')}</span>`
);
return;
}
const localOrder = window.localStorage.getItem(store.chosenLocalOrderId);
if (!localOrder) {
showActionMonit(`<span class="text--warn">${t('order-message.error-update')}</span>`);
return;
}
const orderObj: LocalStorageOrder = {
id: store.chosenLocalOrderId,
orderType: store.chosenOrderType,
orderBody: store[store.chosenOrderType],
orderFooter: store.orderFooter,
updatedAt: Date.now(),
orderVersion: import.meta.env['VITE_APP_ORDER_VERSION'] || '1'
};
window.localStorage.setItem(store.chosenLocalOrderId, JSON.stringify(orderObj));
showActionMonit(t('order-message.success-update-html'));
}
</script>
<style lang="scss" scoped>
+2 -2
View File
@@ -261,7 +261,7 @@ export default defineComponent({
sceneryAbbrev || this.store.orderFooter.stationName.slice(0, 2);
}
this.store.orderMode = 'OrderMessage';
this.store.panelMode = 'OrderMessage';
},
handleQueries() {
@@ -283,7 +283,7 @@ export default defineComponent({
this.selectOption();
this.store.orderMode = 'OrderTrainPicker';
this.store.panelMode = 'OrderTrainPicker';
}
}
}
+1 -70
View File
@@ -15,75 +15,6 @@ export default defineComponent({
},
methods: {
saveOrderSetting(key: string, value: string | number | boolean) {
window.localStorage.setItem(key, value.toString());
},
getOrderSetting(key: string) {
return window.localStorage.getItem(key);
},
removeOrderSetting(key: string) {
window.localStorage.removeItem(key);
},
saveLocalOrder() {
const orderObj: LocalStorageOrder = {
id: '',
orderType: this.store.chosenOrderType,
orderBody: this.store[this.store.chosenOrderType],
orderFooter: this.store.orderFooter,
createdAt: Date.now(),
orderVersion: import.meta.env['VITE_APP_ORDER_VERSION'] || '1'
};
const headerInfo = orderObj['orderBody']['header'];
if (!headerInfo['orderNo']) return -1;
if (!headerInfo['trainNo']) return -1;
if (!headerInfo['date']) return -1;
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)) {
return 0;
}
const nextOrderCount = Number(localOrderCount) + 1;
const orderId = `order-${nextOrderCount}`;
orderObj['id'] = orderId;
localStorage.setItem('orderCount', `${nextOrderCount}`);
localStorage.setItem(orderId, JSON.stringify(orderObj));
this.store.chosenLocalOrderId = orderId;
return 1;
},
updateLocalOrder() {
if (!this.store.chosenLocalOrderId) return 0;
const localOrder = window.localStorage.getItem(this.store.chosenLocalOrderId);
if (!localOrder) return -1;
const orderObj: LocalStorageOrder = {
id: this.store.chosenLocalOrderId,
orderType: this.store.chosenOrderType,
orderBody: this.store[this.store.chosenOrderType],
orderFooter: this.store.orderFooter,
updatedAt: Date.now(),
orderVersion: import.meta.env['VITE_APP_ORDER_VERSION'] || '1'
};
window.localStorage.setItem(this.store.chosenLocalOrderId, JSON.stringify(orderObj));
return 1;
},
removeLocalOrder(order: LocalStorageOrder) {
localStorage.removeItem(order.id);
@@ -157,7 +88,7 @@ export default defineComponent({
this.store.chosenOrderType = localOrder.orderType;
this.store.chosenLocalOrderId = localOrder.id;
this.store.orderMode = 'OrderMessage';
this.store.panelMode = 'OrderMessage';
}
}
});
+1 -1
View File
@@ -341,7 +341,7 @@ export const useStore = defineStore('store', {
}
},
orderMode: 'OrderMessage',
panelMode: 'OrderMessage',
orderFooter: {
stationName: '',
+12 -17
View File
@@ -1,22 +1,17 @@
<template>
<div class="home">
<div class="home_container">
<div class="order_container">
<div class="home-container">
<div class="order-container">
<Order />
</div>
<div class="message_container">
<div class="message_nav">
<!-- <button class="g-button icon" @click="switchLanguages">
<LanguagesIcon :size="18" />
<span style="margin-left: 0.25em">{{ $t('locale.' + store.currentAppLocale) }}</span>
</button> -->
<div class="panel-container">
<div class="panel-nav">
<button
v-for="(action, i) in navActions"
:key="action.mode"
class="g-button option"
:data-active="store.orderMode == action.mode"
:data-active="store.panelMode == action.mode"
@click="selectOrderMode(action.mode)"
>
{{ $t(`navbar.${action.value}`) }}
@@ -68,7 +63,7 @@ export default defineComponent({
methods: {
selectOrderMode(mode: string) {
this.store.orderMode = mode;
this.store.panelMode = mode;
},
switchLanguages() {
@@ -89,7 +84,7 @@ export default defineComponent({
computed: {
orderModeComponent() {
switch (this.store.orderMode) {
switch (this.store.panelMode) {
case 'OrderMessage':
return OrderMessage;
case 'OrderList':
@@ -117,7 +112,7 @@ export default defineComponent({
width: 100%;
}
.home_container {
.home-container {
display: flex;
flex-wrap: wrap;
justify-content: center;
@@ -136,7 +131,7 @@ export default defineComponent({
}
}
.order_container {
.order-container {
max-width: 800px;
display: flex;
@@ -147,7 +142,7 @@ export default defineComponent({
}
}
.message_container {
.panel-container {
width: 500px;
padding: 2px;
@@ -155,7 +150,7 @@ export default defineComponent({
grid-template-rows: auto auto 1fr;
}
.message_nav {
.panel-nav {
display: flex;
align-items: center;
justify-content: center;
@@ -165,7 +160,7 @@ export default defineComponent({
margin-bottom: 1.5em;
}
.message_nav > button {
.panel-nav > button {
position: relative;
&::before {