feat: add gamemaster page (WIP)
This commit is contained in:
parent
6b1316d3ef
commit
cab1a91cc2
@ -6,9 +6,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '~/assets/css/components';
|
@import '~/assets/css/components';
|
||||||
|
|
||||||
@ -31,6 +28,7 @@
|
|||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background-color: $alert-background-color;
|
background-color: $alert-background-color;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
|
color: $text-primary-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -18,7 +18,7 @@ defineProps<{
|
|||||||
|
|
||||||
.admin-tile {
|
.admin-tile {
|
||||||
&__container {
|
&__container {
|
||||||
width: 360px;
|
width: 300px;
|
||||||
margin: 40px;
|
margin: 40px;
|
||||||
padding: 16px 30px;
|
padding: 16px 30px;
|
||||||
background-color: $admin-tile-background-color;
|
background-color: $admin-tile-background-color;
|
45
client/src/components/admin/GameInfoTile.vue
Normal file
45
client/src/components/admin/GameInfoTile.vue
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<template>
|
||||||
|
<AdminTile title="Game">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>{{ $t('name') }}:</td>
|
||||||
|
<td>{{ game.name }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="gameinfo-tile__edit-game-name" @click="editName"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ $t('language') }}:</td>
|
||||||
|
<td>{{ user.lang }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="gameinfo-tile__edit-lang" @click="editLang"></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</AdminTile>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import useI18n from '@/composables/useI18n'
|
||||||
|
import { useUserinfoStore } from "@/stores/UserinfoStore"
|
||||||
|
import { useGameinfoStore } from "@/stores/GameinfoStore"
|
||||||
|
|
||||||
|
const { $t } = useI18n({
|
||||||
|
name: { en: 'Name', de: 'Name' },
|
||||||
|
language: { en: 'Language', de: 'Sprache' },
|
||||||
|
})
|
||||||
|
|
||||||
|
const game = useGameinfoStore()
|
||||||
|
const user = useUserinfoStore()
|
||||||
|
const editName = () => { alert('not yet implemented') }
|
||||||
|
const editLang = () => { alert('not yet implemented') }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.gameinfo-tile {
|
||||||
|
&__container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
33
client/src/components/admin/PlayersTile.vue
Normal file
33
client/src/components/admin/PlayersTile.vue
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<template>
|
||||||
|
<AdminTile title="Players">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>{{ $t('name') }}:</th>
|
||||||
|
<th>{{ $t('num-quotes') }}</th>
|
||||||
|
<th>{{ $t('score') }}</th>
|
||||||
|
<th>{{ $t('last-logged-in') }}</th>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</AdminTile>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import useI18n from '@/composables/useI18n'
|
||||||
|
|
||||||
|
const { $t } = useI18n({
|
||||||
|
name: { en: 'Name', de: 'Name' },
|
||||||
|
'num-quotes': { en: '# quotes', de: '# Quotes' },
|
||||||
|
'score': { en: 'Score', de: 'Score' },
|
||||||
|
'last-logged-in': { en: 'last logged in', de: 'zuletzt eingeloggt' },
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.gameinfo-tile {
|
||||||
|
&__container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -4,6 +4,8 @@ import { useGameinfoStore } from "@/stores/GameinfoStore"
|
|||||||
import { useRoundStore } from "@/stores/RoundStore"
|
import { useRoundStore } from "@/stores/RoundStore"
|
||||||
import { usePlayersStore } from "@/stores/PlayersStore"
|
import { usePlayersStore } from "@/stores/PlayersStore"
|
||||||
import { EngineContext } from '@/composables/useEngine'
|
import { EngineContext } from '@/composables/useEngine'
|
||||||
|
import useAlert from '@/composables/useAlert'
|
||||||
|
import useI18n from '@/composables/useI18n'
|
||||||
|
|
||||||
type EngineResponse = {
|
type EngineResponse = {
|
||||||
version: string,
|
version: string,
|
||||||
@ -17,8 +19,14 @@ type EngineResponse = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { $t } = useI18n({
|
||||||
|
'connection-broken': { en: 'connection to server broken.', de: 'Verbindung zum Server ist unterbrochen.' },
|
||||||
|
'retrying': { en: 'retrying', de: 'verbinde erneut'},
|
||||||
|
})
|
||||||
|
|
||||||
export async function fetchUpdate(this: EngineContext) {
|
export async function fetchUpdate(this: EngineContext) {
|
||||||
if (this.shouldStop || !this.isActive) {
|
if (this.shouldStop || !this.isActive) {
|
||||||
|
useAlert().clearAlert()
|
||||||
this.isActive = false
|
this.isActive = false
|
||||||
this.shouldStop = false
|
this.shouldStop = false
|
||||||
console.debug('engine stopped')
|
console.debug('engine stopped')
|
||||||
@ -41,6 +49,7 @@ export async function fetchUpdate(this: EngineContext) {
|
|||||||
this.isConnected.value = true
|
this.isConnected.value = true
|
||||||
this.retry.value = 0
|
this.retry.value = 0
|
||||||
|
|
||||||
|
useAlert().clearAlert()
|
||||||
useEngineStore().setJson(response)
|
useEngineStore().setJson(response)
|
||||||
useGameinfoStore().setGameinfo(response.game)
|
useGameinfoStore().setGameinfo(response.game)
|
||||||
useRoundStore().setRound(response.game.round)
|
useRoundStore().setRound(response.game.round)
|
||||||
@ -57,6 +66,10 @@ export async function fetchUpdate(this: EngineContext) {
|
|||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
this.isConnected.value = false
|
this.isConnected.value = false
|
||||||
this.retry.value++
|
this.retry.value++
|
||||||
|
useAlert().setAlert([
|
||||||
|
$t('connection-broken'),
|
||||||
|
this.retry.value > 0 ? $t('retrying') + '...'.slice(0, this.retry.value % 4) : ''
|
||||||
|
])
|
||||||
|
|
||||||
if (e.response) {
|
if (e.response) {
|
||||||
// callApi() threw an exception
|
// callApi() threw an exception
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { useUserinfoStore } from "@/stores/UserinfoStore"
|
import { useUserinfoStore } from "@/stores/UserinfoStore"
|
||||||
import { EngineContext } from '@/composables/useEngine'
|
import { EngineContext } from '@/composables/useEngine'
|
||||||
|
import useAlert from '@/composables/useAlert'
|
||||||
|
|
||||||
export function start(this: EngineContext): void {
|
export function start(this: EngineContext): void {
|
||||||
if (this.isActive && !this.shouldStop) {
|
if (this.isActive && !this.shouldStop) {
|
||||||
@ -11,16 +12,18 @@ export function start(this: EngineContext): void {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useAlert().clearAlert()
|
||||||
this.isActive = true
|
this.isActive = true
|
||||||
this.shouldStop = false
|
this.shouldStop = false
|
||||||
this.isConnected.value = true
|
this.isConnected.value = true
|
||||||
|
|
||||||
this.fetchUpdate()
|
this.fetchUpdate()
|
||||||
console.log('start engine')
|
console.log('start engine')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stop(this: EngineContext): void {
|
export function stop(this: EngineContext): void {
|
||||||
if (this.isActive) {
|
if (this.isActive) {
|
||||||
|
useAlert().clearAlert()
|
||||||
this.shouldStop = true
|
this.shouldStop = true
|
||||||
this.isConnected.value = true
|
this.isConnected.value = true
|
||||||
console.log('shut down engine')
|
console.log('shut down engine')
|
||||||
|
23
client/src/composables/useAlert.ts
Normal file
23
client/src/composables/useAlert.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { Ref, ref } from 'vue'
|
||||||
|
|
||||||
|
export type AlertMessages = Array<string>
|
||||||
|
|
||||||
|
export interface useAlert {
|
||||||
|
setAlert(message: AlertMessages): void
|
||||||
|
clearAlert(): void
|
||||||
|
getAlertMessagesRef(): Ref<AlertMessages>
|
||||||
|
}
|
||||||
|
|
||||||
|
const alertMessages = ref([] as AlertMessages)
|
||||||
|
|
||||||
|
export default (): useAlert => {
|
||||||
|
return {
|
||||||
|
setAlert: (message: AlertMessages): void => {
|
||||||
|
alertMessages.value = message
|
||||||
|
},
|
||||||
|
clearAlert: ():void => {
|
||||||
|
alertMessages.value = []
|
||||||
|
},
|
||||||
|
getAlertMessagesRef: (): Ref<AlertMessages> => alertMessages
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-default">
|
<div class="layout-default">
|
||||||
|
<AlertBox v-if="alertMessages.length > 0">
|
||||||
|
<div v-for="msg in alertMessages" :key="msg">{{ msg }}</div>
|
||||||
|
</AlertBox>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useHead } from '#app'
|
import { useHead } from '#app'
|
||||||
|
import useAlert from '@/composables/useAlert'
|
||||||
|
|
||||||
useHead({
|
useHead({
|
||||||
title: 'Know Your Teammates!',
|
title: 'Know Your Teammates!',
|
||||||
charset: 'utf-8',
|
charset: 'utf-8',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const alertMessages = useAlert().getAlertMessagesRef()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="gamemaster__container">
|
<div class="gamemaster__container">
|
||||||
<TopBar />
|
<TopBar />
|
||||||
<AdminTile title="Info">
|
<AdminGameInfoTile />
|
||||||
<div class="gamemaster__info">... info ...</div>
|
</div>
|
||||||
</AdminTile>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { navigateTo } from '#app'
|
import { navigateTo } from '#app'
|
||||||
import useAuth from '@/composables/useAuth';
|
import { onMounted, onBeforeUnmount } from 'vue'
|
||||||
import TopBar from '../components/TopBar.vue';
|
import useAuth from '@/composables/useAuth'
|
||||||
|
import useEngine from '@/composables/useEngine'
|
||||||
|
|
||||||
// ensure user is authenticated
|
// ensure user is authenticated
|
||||||
const { authenticateAndLoadUserInfo } = useAuth()
|
const { authenticateAndLoadUserInfo } = useAuth()
|
||||||
@ -19,6 +18,10 @@ try {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
navigateTo('/', { replace: true })
|
navigateTo('/', { replace: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { start: startEngine, stop: stopEngine } = useEngine()
|
||||||
|
onMounted(() => startEngine())
|
||||||
|
onBeforeUnmount(() => stopEngine())
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page-play__container">
|
<div class="page-play__container">
|
||||||
<TopBar />
|
<TopBar />
|
||||||
<AlertBox v-if="!isConnected" mode="alert">
|
|
||||||
{{ $t('connection-broken') }}
|
|
||||||
<div v-if="retry >= 0">{{ $t('retrying') }} {{ '...'.slice(0, retry % 4) }}</div>
|
|
||||||
</AlertBox>
|
|
||||||
<div class="page-play__playfield-container">
|
<div class="page-play__playfield-container">
|
||||||
<div class="page-play__playfield-content">
|
<div class="page-play__playfield-content">
|
||||||
<Lobby v-if="game.state === 'idle'" />
|
<Lobby v-if="game.state === 'idle'" />
|
||||||
@ -20,17 +16,11 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { navigateTo, useRoute } from '#app'
|
import { navigateTo, useRoute } from '#app'
|
||||||
import { computed, onMounted, onBeforeUnmount } from 'vue';
|
import { computed, onMounted, onBeforeUnmount, watch } from 'vue';
|
||||||
import useAuth from '@/composables/useAuth';
|
import useAuth from '@/composables/useAuth';
|
||||||
import useEngine from '@/composables/useEngine';
|
import useEngine from '@/composables/useEngine';
|
||||||
import { useGameinfoStore } from "@/stores/GameinfoStore"
|
|
||||||
import useI18n from '@/composables/useI18n'
|
import useI18n from '@/composables/useI18n'
|
||||||
|
import { useGameinfoStore } from "@/stores/GameinfoStore"
|
||||||
const { $t } = useI18n({
|
|
||||||
'connection-broken': { en: 'connection to server broken.', de: 'Verbindung zum Server ist unterbrochen.' },
|
|
||||||
'retrying': { en: 'retrying', de: 'verbinde erneut'},
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
// ensure user is authenticated
|
// ensure user is authenticated
|
||||||
const { authenticateAndLoadUserInfo } = useAuth()
|
const { authenticateAndLoadUserInfo } = useAuth()
|
||||||
@ -40,7 +30,7 @@ try {
|
|||||||
navigateTo('/', { replace: true })
|
navigateTo('/', { replace: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
const { start: startEngine, stop: stopEngine, isConnected, retry } = useEngine()
|
const { start: startEngine, stop: stopEngine } = useEngine()
|
||||||
onMounted(() => startEngine())
|
onMounted(() => startEngine())
|
||||||
onBeforeUnmount(() => stopEngine())
|
onBeforeUnmount(() => stopEngine())
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user