This commit is contained in:
2025-09-14 03:56:04 +02:00
parent 2cc70cc709
commit 46a8b19a1c
7 changed files with 350 additions and 9 deletions

View File

@@ -173,6 +173,7 @@ router.get("/games", async (req, res) => {
* is_local: false * is_local: false
* current_playing_user: 1 * current_playing_user: 1
* turn_order: null * turn_order: null
* creator: 1
*/ */
router.get("/games/:id", asyncHandler(async (req, res) => { router.get("/games/:id", asyncHandler(async (req, res) => {
const gameId = parseInt(req.params.id, 10); const gameId = parseInt(req.params.id, 10);
@@ -182,7 +183,7 @@ router.get("/games/:id", asyncHandler(async (req, res) => {
if (!games.length) throw new ApiError(404, "Game not found"); if (!games.length) throw new ApiError(404, "Game not found");
const [creatorRows] = await pool.query( const [creatorRows] = await pool.query(
`SELECT u.id, u.username `SELECT u.id
FROM game_players gp FROM game_players gp
JOIN users u ON gp.user = u.id JOIN users u ON gp.user = u.id
WHERE gp.game = ? AND gp.is_creator = TRUE WHERE gp.game = ? AND gp.is_creator = TRUE
@@ -190,7 +191,7 @@ router.get("/games/:id", asyncHandler(async (req, res) => {
[gameId] [gameId]
); );
const creator = creatorRows.lenght ? creatorRows[0] : null; const creator = creatorRows.length ? creatorRows[0].id : null;
res.json({ ...games[0], creator}); res.json({ ...games[0], creator});
})); }));
@@ -388,7 +389,7 @@ router.patch("/games/:id/lock", asyncHandler(async (req, res) => {
const currentPlayingUser = turnOrder[0]; const currentPlayingUser = turnOrder[0];
await conn.query( await conn.query(
"UPDATE current_games SET is_open = FALSE, turn_order = ?, current_playing_user = ? WHERE id = ?", "UPDATE current_games SET is_open = FALSE, turn_order = ?, current_playing_user = ? WHERE id = ?",
[JSON.stringify(turnOrder), gameId, currentPlayingUser] [JSON.stringify(turnOrder), currentPlayingUser, gameId]
); );
await conn.commit(); await conn.commit();

View File

@@ -73,6 +73,12 @@
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item clickable v-ripple to="/game/online/join">
<q-item-section>
Join Online Game
</q-item-section>
</q-item>
<q-item clickable v-ripple to="/game"> <q-item clickable v-ripple to="/game">
<q-item-section> <q-item-section>
Game Game

View File

@@ -1,7 +1,168 @@
<template> <template>
CreateOnlineGame <div class="q-pa-md flex flex-center">
<q-card
class="q-pa-lg shadow-3"
style="width: 400px; max-width: 90vw; border-radius: 16px;"
>
<q-card-section>
<div class="text-h6 q-mt-md">Online Game</div>
<div class="text-subtitle2 text-black">
Game ID: {{ gameID }}
</div>
</q-card-section>
<q-separator />
<q-card-section>
<div class="text-h6 q-mt-md">Players:</div>
<li v-for="plr in gamePlayers" :key="plr.username">
<div class="text-subtitle2 text-black">{{ plr.username }}</div>
</li>
</q-card-section>
<q-separator />
<q-card-actions align="center">
<q-btn
v-if="gameCreator === user.id"
label="Start Game!"
color="primary"
@click="startGame"
rounded
unelevated
size="lg"
class="full-width"
/>
</q-card-actions>
</q-card>
</div>
</template> </template>
<script setup> <script setup>
// import { ref, onMounted, onUnmounted } from "vue";
import { useQuasar, LocalStorage } from "quasar";
import { api } from 'src/boot/axios';
import { useRouter } from 'vue-router'
const router = useRouter()
const $q = useQuasar();
const gameID = ref();
const gameCreator = ref(null);
const gamePlayers = ref([]);
const user = ref({ username:"", id:0 });
var canUpdate = false
const storedUser = LocalStorage.getItem("user")
if (storedUser) {
console.log(storedUser)
user.value = storedUser
} else {
router.push("/user/username")
}
const storedgameID = LocalStorage.getItem("gameID")
if (storedgameID) {
console.log(storedgameID)
gameID.value = storedgameID
api.get(`/api/games/${gameID.value}`)
.then(function (response) {
console.log(response);
gameCreator.value = response.data.creator
canUpdate = true
})
.catch(function (error) {
console.log(error);
$q.notify({
type: "negative",
message: error.response.data.error,
});
});
} else {
router.push("/")
}
async function update() {
if (!canUpdate) {return}
api.get(`/api/games/${gameID.value}/players`)
.then(function (response) {
gamePlayers.value = response.data
})
.catch(function (error) {
console.log(error);
$q.notify({
type: "negative",
message: error.response.data.error,
});
});
api.get(`/api/games/${gameID.value}`)
.then(function (response) {
if (!response.data.is_open) {
router.push("/game")
}
})
.catch(function (error) {
console.log(error);
$q.notify({
type: "negative",
message: error.response.data.error,
});
});
}
async function startGame() {
api.patch(`/api/games/${gameID.value}/lock`, {
user: user.value.id
})
.then(function (response) {
console.log(response);
$q.notify({
type: "positive",
message: "Success!",
});
router.push("/game")
})
.catch(function (error) {
console.log(error);
$q.notify({
type: "negative",
message: error.response.data.error,
});
});
}
let intervalId = null
onMounted(() => {
update()
intervalId = setInterval(update, 1000)
})
onUnmounted(() => {
clearInterval(intervalId)
})
</script> </script>

View File

@@ -0,0 +1,96 @@
<template>
<div class="q-pa-md flex flex-center">
<q-card
class="q-pa-lg shadow-3"
style="width: 400px; max-width: 90vw; border-radius: 16px;"
>
<q-card-section class="text-center">
<div class="text-h6 q-mt-md">Enter Game ID</div>
</q-card-section>
<q-card-section>
<q-input
v-model="gameID"
filled
label="Game ID"
type="number"
dense
style="border-radius: 6px;"
>
<template #prepend>
<q-icon name="public" />
</template>
</q-input>
</q-card-section>
<q-card-actions align="center">
<q-btn
label="Go!"
color="primary"
@click="joinGame"
rounded
unelevated
size="lg"
class="full-width"
/>
</q-card-actions>
</q-card>
</div>
</template>
<script setup>
import { ref } from "vue";
import { useQuasar, LocalStorage } from "quasar";
import { api } from 'src/boot/axios';
import { useRouter } from 'vue-router'
const router = useRouter()
const $q = useQuasar();
const gameID = ref();
const user = ref({ username:"", id:0 });
const storedUser = LocalStorage.getItem("user")
if (storedUser) {
console.log(storedUser)
user.value = storedUser
} else {
router.push("/user/username")
}
async function joinGame() {
if (!gameID.value) {
$q.notify({
type: "negative",
message: "Please enter a Game ID!",
});
return;
}
api.post(`/api/games/${gameID.value}/players`, {
user: user.value.id
})
.then(function (response) {
console.log(response);
LocalStorage.setItem("gameID", gameID.value)
$q.notify({
type: "positive",
message: "Success!",
});
router.push("/game/online/create")
})
.catch(function (error) {
console.log(error);
$q.notify({
type: "negative",
message: error.response.data.error,
});
});
}
</script>

View File

@@ -1,7 +1,83 @@
<template> <template>
Settings <div class="q-pa-lg">
<q-card flat bordered class="shadow-2" style="max-width:600px; margin: 0 auto; border-radius:12px;">
<q-card-section>
<div class="text-h6">User Settings</div>
<div class="text-subtitle2 text-black">
Username: <span class="text-subtitle2 text-grey">{{ user.username }}</span>
</div>
<div class="text-subtitle2 text-black">
ID: <span class="text-subtitle2 text-grey">{{ user.id }}</span>
</div>
</q-card-section>
<q-separator />
<q-card-section>
<div class="q-gutter-md">
<div class="text-h8">Input method</div>
<q-btn-dropdown color="primary" :label="selected">
<q-list>
<q-item
v-for="opt in options"
:key="opt"
clickable
v-close-popup
@click="selectOption(opt)"
>
<q-item-section>
<q-item-label>{{ opt }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
<div class="text-h8">Dart Picker Offset</div>
<div class="text-h8">Dart Picker Darts Colours</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn flat label="Cancel" @click="resetForm" />
<q-btn color="primary" label="Save changes" unelevated @click="onSave" />
</q-card-actions>
</q-card>
</div>
</template> </template>
<script setup> <script setup>
// import { ref } from 'vue'
import { useQuasar, LocalStorage } from 'quasar'
import { useRouter } from 'vue-router'
const router = useRouter()
const $q = useQuasar();
const options = ['Dart Picker', 'Numbers']
const selected = ref('Input method')
const user = ref({ username:"", id:0 });
const storedUser = LocalStorage.getItem("user")
if (storedUser) {
console.log(storedUser)
user.value = storedUser
} else {
router.push("/user/username")
}
function selectOption(opt) {
selected.value = opt
}
function resetForm () {
$q.notify({ message: 'Changes discarded', color: 'negative' })
}
function onSave () {
$q.notify({ message: 'Settings saved', color: 'positive' })
}
</script> </script>

View File

@@ -75,7 +75,7 @@ async function setUsername() {
message: "Success!", message: "Success!",
}); });
router.push("/game/select") router.push("/")
}) })
.catch(function (error) { .catch(function (error) {

View File

@@ -15,6 +15,7 @@ const routes = [
{ path: 'game/select', component: () => import('pages/game/gameModeSelectPage.vue') }, { path: 'game/select', component: () => import('pages/game/gameModeSelectPage.vue') },
{ path: 'game/local/create', component: () => import('pages/game/createLocalGamePage.vue') }, { path: 'game/local/create', component: () => import('pages/game/createLocalGamePage.vue') },
{ path: 'game/online/create', component: () => import('pages/game/createOnlineGamePage.vue') }, { path: 'game/online/create', component: () => import('pages/game/createOnlineGamePage.vue') },
{ path: 'game/online/join', component: () => import('pages/game/joinOnlineGamePage.vue') },
{ path: 'error', component: () => import('pages/ErrorPage.vue') } { path: 'error', component: () => import('pages/ErrorPage.vue') }
], ],