General problem…
Using Vue, firebase functions and realtime database. The ‘isPlayerTurn.value’ returns false only, it never changes. I have tried changing the values/ parameters many times, have tried using AI to suggest problems, it mostly says that the code works. It does allow the creation of matchmaking and the turn does shift between users. However the button color is never changed as the ‘isPlayerTurn.value’ doesn’t change.
Vue code…
<script setup>
import { ref, watchEffect, computed } from 'vue';
import { httpsCallable } from 'firebase/functions';
import { functions, realTime, auth } from '@/firebase';
import { ref as dbRef, onValue, off } from 'firebase/database';
import { onAuthStateChanged } from 'firebase/auth';
const gameId = ref('');
const playerId = ref('');
const gameTurnRef = ref('');
const isPlayerTurn = ref('');
onAuthStateChanged(auth, (user) => {
if (user) {
playerId.value = user.uid;
console.log('player id:', playerId.value)
} else {
// Handle the case when the user is not authenticated
}
});
const updateGameTurnRef = () => {
if (gameId.value) {
gameTurnRef.value = dbRef(realTime, `games/${gameId.value}/turn`);
}
};
watchEffect(() => {
console.log('gameId:', gameId.value);
updateGameTurnRef();
});
watchEffect(() => {
if (!gameTurnRef.value) return;
const gameTurnRefListener = onValue(gameTurnRef.value, (snapshot) => {
const turn = snapshot.val();
console.log('turn:', turn);
if (turn !== null) {
isPlayerTurn.value = turn; // === playerId.value;
} else {
console.error('Invalid turn data:', turn);
}
}, (error) => {
console.error('Error fetching turn data:', error);
});
return () => {
off(gameTurnRefListener);
};
});
const endTurn = async () => {
try {
const makeMove = httpsCallable(functions, "makeMove");
const response = await makeMove(playerId.value);
if (response.data && response.data.turn !== undefined) {
isPlayerTurn.value = response.data.turn === playerId.value;
console.log('is player turn:', isPlayerTurn.value);
console.log('is response turn:', response.data.turn);
console.log('is player :', response.data);
}
} catch (error) {
console.error('Error making move:', error);
}
};
const buttonBackgroundColor = computed(() => {
return isPlayerTurn.value ? 'red' : 'blue';
});
</script>
<template>
<button @click="endTurn" :style="{ backgroundColor: buttonBackgroundColor}">End Turn</button>
</template>
<style scoped>
button {
width: 100px;
}
</style>
Firebase Function…
exports.makeMove = functions.https.onCall((data, context) => {
return new Promise((resolve, reject) => {
try {
assertAuth(context);
const playerId = context.auth.uid;
const move = data; // Expecting a string directly
assertValidMove(move); // Validate the move
// Check player is in a game
RTDB.ref("matchmaking/" + playerId + "/gameId")
.once("value")
.then((gameIdSnapshot) => {
const gameId = gameIdSnapshot.val();
if (!gameId) {
throw new functions.https
.HttpsError("failed-precondition", "Player is not in a game");
}
const gameRef = RTDB.ref("games/" + gameId);
const playersRef = gameRef.child("gameInfo/playersInfo");
const movesRef = gameRef.child(playerId + "/moves");
const turnRef = gameRef.child("turn");
// Check if it's the player's turn
gameRef.once("value")
.then((gameSnapshot) => {
const isPlayerTurn = gameSnapshot
.child("turn").val() === playerId;
if (!isPlayerTurn) {
throw new functions.https
.HttpsError("failed-precondition"
, "It's not your turn");
}
// Enact the player move
return movesRef.push().set(move)
.then(() => {
return playersRef.once("value")
.then((snapshot) => {
const players = snapshot.val();
const playerIds = Object.keys(players);
const nextTurnPlayer =
playerIds
.find((id) => id !== playerId) ||
playerIds[0];
// Update turn
return turnRef.set(nextTurnPlayer)
.then(() => {
// Resolve with the updated turn status
resolve({turn: nextTurnPlayer ===
playerId ? true : false});
})
.catch((error) => {
reject(error);
});
})
.catch((error) => {
reject(error);
});
})
.catch((error) => {
reject(error);
});
})
.catch((error) => {
reject(error);
});
})
.catch((error) => {
reject(error);
});
} catch (error) {
console.error("ERROR:", error);
reject(new functions.https.HttpsError("internal", error.message));
}
});
});
function assertValidMove(move) {
// Assuming `move` is a string representing the move
if (typeof move !== "string" || move.trim() === "") {
throw new functions.https.HttpsError(
"invalid-argument",
"Move is not a valid string",
);
}
}
enter image description here realtime structure
enter image description here realtime structure ctd
I have tried switching variables properties multiple times. Thinking about the logical structure.
But I still cannot work out why it is not working. It could be something very simple which is why I am asking for help on here.
Expecting. When one player clicks on the button then the button should change to red and for the other player it should then turn to blue and vice-versa. Initially, I expect both players to have the button to be set to blue. Ideally they should both be neutral until the sequence starts… the login stages set initial player turn. But that is something that I am not concerned with (if anyone could solve that issue as well though then that would be amazing)
nserves is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.