diff --git a/backend/models/trigger.js b/backend/models/trigger.js index 295ec73..cd87394 100644 --- a/backend/models/trigger.js +++ b/backend/models/trigger.js @@ -350,15 +350,16 @@ export async function createTriggers() { SELECT * FROM random_fill ), - -- 8) Neue Ämter anlegen und sofort zurückliefern + -- 8) Neue Ämter anlegen – created_at = Wahldatum (Amtsbeginn), nicht NOW() + -- damit termEnds = Amtsbeginn + termLength korrekt berechnet werden kann created_offices AS ( INSERT INTO falukant_data.political_office (office_type_id, character_id, created_at, updated_at, region_id) SELECT tp.tp_office_type_id, fw.character_id, - NOW() AS created_at, - NOW() AS updated_at, + tp.tp_election_date AS created_at, + tp.tp_election_date AS updated_at, tp.tp_region_id FROM final_winners fw JOIN to_process tp diff --git a/backend/services/falukantService.js b/backend/services/falukantService.js index 6ff6623..a790f17 100644 --- a/backend/services/falukantService.js +++ b/backend/services/falukantService.js @@ -3535,8 +3535,9 @@ class FalukantService extends BaseService { firstName: firstNameObject.id, }); updateFalukantUserMoney(falukantUser.id, -50, 'Baptism', falukantUser.id); - // Trigger status bar refresh for the user after baptism - notifyUser(hashedUserId, 'falukantUpdateStatus', {}); + // Trigger status bar refresh (children count) and family view update + await notifyUser(hashedUserId, 'falukantUpdateStatus', {}); + await notifyUser(hashedUserId, 'familychanged', {}); return { success: true }; } catch (error) { throw new Error(error.message); diff --git a/frontend/src/components/falukant/StatusBar.vue b/frontend/src/components/falukant/StatusBar.vue index e3bb0be..73b2a67 100644 --- a/frontend/src/components/falukant/StatusBar.vue +++ b/frontend/src/components/falukant/StatusBar.vue @@ -64,6 +64,17 @@ export default { this.preloadQuickAccessImages(); }, deep: true + }, + socket(newVal, oldVal) { + if (oldVal) this.teardownSocketListeners(); + if (newVal) this.setupSocketListeners(); + }, + daemonSocket(newVal, oldVal) { + if (oldVal && this._daemonHandler) { + oldVal.removeEventListener('message', this._daemonHandler); + this._daemonHandler = null; + } + if (newVal) this.setupDaemonListeners(); } }, async mounted() { @@ -72,24 +83,13 @@ export default { // Bilder für Schnellzugriff vorladen und cachen this.preloadQuickAccessImages(); - // Live-Socket-Events - ["falukantUpdateStatus", "stock_change", "familychanged"].forEach(eventName => { - if (this.daemonSocket) { - this.daemonSocket.addEventListener('message', (event) => { - try { - const data = JSON.parse(event.data); - if (data.event === eventName) { - this.handleEvent(data); - } - } catch (error) { - // Ignore non-JSON messages like ping/pong - } - }); - } - }); + // Socket.IO (Backend notifyUser) – Hauptkanal für Falukant-Events + this.setupSocketListeners(); + this.setupDaemonListeners(); }, beforeUnmount() { - // Daemon WebSocket wird automatisch beim Logout geschlossen + this.teardownSocketListeners(); + this.teardownDaemonListeners(); }, methods: { preloadQuickAccessImages() { @@ -155,6 +155,40 @@ export default { // Error fetching status } }, + setupSocketListeners() { + this.teardownSocketListeners(); + if (!this.socket) return; + this.socket.on('falukantUpdateStatus', (data) => this.handleEvent({ event: 'falukantUpdateStatus', ...data })); + this.socket.on('stock_change', (data) => this.handleEvent({ event: 'stock_change', ...data })); + this.socket.on('familychanged', (data) => this.handleEvent({ event: 'familychanged', ...data })); + }, + teardownSocketListeners() { + if (this.socket) { + this.socket.off('falukantUpdateStatus'); + this.socket.off('stock_change'); + this.socket.off('familychanged'); + } + }, + setupDaemonListeners() { + this.teardownDaemonListeners(); + if (!this.daemonSocket) return; + this._daemonHandler = (event) => { + try { + const data = JSON.parse(event.data); + if (['falukantUpdateStatus', 'stock_change', 'familychanged'].includes(data.event)) { + this.handleEvent(data); + } + } catch (_) {} + }; + this.daemonSocket.addEventListener('message', this._daemonHandler); + }, + teardownDaemonListeners() { + const sock = this.daemonSocket; + if (sock && this._daemonHandler) { + sock.removeEventListener('message', this._daemonHandler); + this._daemonHandler = null; + } + }, handleEvent(eventData) { switch (eventData.event) { case 'falukantUpdateStatus':