From df2c9d478830e8c9c13d087cedfb7bbbc078de78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20CHOMAZ?= Date: Sun, 1 Feb 2026 16:20:49 +0100 Subject: [PATCH] (new) track the new quizstore.js for manage the current Vulture Session --- VApp/src/store/quizStore.js | 166 ++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 VApp/src/store/quizStore.js diff --git a/VApp/src/store/quizStore.js b/VApp/src/store/quizStore.js new file mode 100644 index 00000000..ae5d0c5d --- /dev/null +++ b/VApp/src/store/quizStore.js @@ -0,0 +1,166 @@ +import { reactive, computed } from 'vue'; +import mqtt from 'mqtt'; +import config from '@/config.js'; +import sessionConfig from '@/quizz/vulture-session-2026-01/session-configuration.json'; + +// Reactive state +const state = reactive({ + currentQuestionIndex: 0, + questions: [], + isMediaHidden: true, + packTitle: '', + timer: 0 // Timer in seconds +}); + +// MQTT Client +let client = null; +let timerInterval = null; +let initialized = false; + +// Initialize Store +function init() { + if (initialized) { + console.log('QuizStore: Already initialized'); + return; + } + initialized = true; + + // Load local config immediately + state.questions = sessionConfig.Questions || []; + state.packTitle = sessionConfig.PackTitle || ''; + + // Connect MQTT + client = mqtt.connect(config.mqttBrokerUrl); + + client.on('connect', () => { + console.log('QuizStore: MQTT Connected'); + client.subscribe('game/quiz/control'); + client.subscribe('/display/control'); + }); + + client.on('message', (topic, message) => { + const msgStr = message.toString(); + console.log('QuizStore: MQTT Message Received', topic, msgStr); + if (topic === 'game/quiz/control') { + try { + const payload = JSON.parse(msgStr); + handleRemoteCommand(payload); + } catch (e) { + console.error('QuizStore: JSON Parse Error', e); + } + } else if (topic === '/display/control') { + // Handle raw string commands from MqttButtons + if (msgStr === 'next') { + _nextQuestion(true); + } else if (msgStr === 'previous') { + _prevQuestion(true); + } else if (msgStr === 'play') { + // Start timer for picture questions + const currentQ = state.questions[state.currentQuestionIndex]; + if (currentQ?.Type === 'picture') { + const playTime = currentQ.Settings?.PlayTime; + if (playTime && playTime > 0) { + console.log('QuizStore: Starting timer for picture', playTime); + actions.startTimer(playTime); + } + } + } else if (msgStr === 'pause') { + stopTimer(); + } + } + }); +} + +function handleRemoteCommand(cmd) { + if (cmd.action === 'next') { + _nextQuestion(false); + } else if (cmd.action === 'prev') { + _prevQuestion(false); + } else if (cmd.action === 'setIndex') { + state.currentQuestionIndex = cmd.index; + } +} + +// Internal actions (boolean publish determines if we send MQTT) +function _nextQuestion(publish = true) { + if (state.currentQuestionIndex < state.questions.length - 1) { + state.currentQuestionIndex++; + if (publish && client) { + client.publish('game/quiz/control', JSON.stringify({ action: 'setIndex', index: state.currentQuestionIndex })); + } + } +} + +function _prevQuestion(publish = true) { + if (state.currentQuestionIndex > 0) { + state.currentQuestionIndex--; + if (publish && client) { + client.publish('game/quiz/control', JSON.stringify({ action: 'setIndex', index: state.currentQuestionIndex })); + } + } +} + +// Public Actions +const actions = { + init, + nextQuestion: () => _nextQuestion(true), + prevQuestion: () => _prevQuestion(true), + setQuestion: (index) => { + if (index >= 0 && index < state.questions.length) { + state.currentQuestionIndex = index; + if (client) { + client.publish('game/quiz/control', JSON.stringify({ action: 'setIndex', index: index })); + } + } + }, + startTimer: (seconds) => { + stopTimer(); + state.timer = seconds; + publishTimer(); + timerInterval = setInterval(() => { + if (state.timer > 0) { + state.timer--; + publishTimer(); + } else { + stopTimer(); + // Auto-hide by publishing pause + if (client) { + client.publish('/display/control', 'pause'); + } + } + }, 1000); + }, + stopTimer +}; + +function stopTimer() { + if (timerInterval) { + clearInterval(timerInterval); + timerInterval = null; + } + state.timer = 0; + publishTimer(); +} + +function publishTimer() { + if (client) { + client.publish('game/timer', JSON.stringify({ time: state.timer })); + } +} + +// Getters +const getters = { + currentQuestion: computed(() => state.questions[state.currentQuestionIndex]), + isFirstQuestion: computed(() => state.currentQuestionIndex === 0), + isLastQuestion: computed(() => state.currentQuestionIndex === state.questions.length - 1), + totalQuestions: computed(() => state.questions.length), + packTitle: computed(() => state.packTitle), + currentQuestionIndex: computed(() => state.currentQuestionIndex), + timer: computed(() => state.timer) +}; + +export default { + state, + actions, + getters +};