feat: show game info on gamemaster page

This commit is contained in:
Settel 2022-09-04 09:45:30 +02:00
parent cab1a91cc2
commit 9a5c647523
9 changed files with 127 additions and 17 deletions

View File

@ -18,7 +18,7 @@ defineProps<{
.admin-tile {
&__container {
width: 300px;
min-width: 300px;
margin: 40px;
padding: 16px 30px;
background-color: $admin-tile-background-color;

View File

@ -3,36 +3,65 @@
<table>
<tr>
<td>{{ $t('name') }}:</td>
<td>{{ game.name }}</td>
<td>{{ gameinfo.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>{{ gameinfo.lang }}</td>
<td>
<div class="gameinfo-tile__edit-lang" @click="editLang"></div>
</td>
</tr>
<tr>
<td>{{ $t('created') }}:</td>
<td colspan="2">{{ date(gameinfo.created) }}</td>
</tr>
<tr>
<td>{{ $t('num-players') }}:</td>
<td colspan="2">{{ gameinfo.players.length }}</td>
</tr>
<tr>
<td>{{ $t('num-quotes-played') }}:</td>
<td colspan="2">{{ gameinfo.numQuotesLeft - gameinfo.numQuotesLeft }} / {{ gameinfo.numQuotesTotal }}</td>
</tr>
<tr v-if="!showId" @click="showId = true">
<td colspan="3">&nbsp;</td>
</tr>
<tr v-if="showId">
<td colspan="3">{{ gameinfo.id }}</td>
</tr>
</table>
</AdminTile>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import useI18n from '@/composables/useI18n'
import { useUserinfoStore } from "@/stores/UserinfoStore"
import { useGameinfoStore } from "@/stores/GameinfoStore"
import useDateFormatter from '@/composables/useDateFormatter';
import type { GameInfo } from '@/composables/engine.d'
const { date } = useDateFormatter()
defineProps<{
gameinfo: GameInfo
}>()
const { $t } = useI18n({
id: { en: 'Id', de: 'Id' },
name: { en: 'Name', de: 'Name' },
language: { en: 'Language', de: 'Sprache' },
created: { en: 'Created', de: 'Erstellt' },
'num-players': { en: '# Players', de: '# Spieler' },
'num-quotes-played': { en: '# Quotes played', de: '# Aussagen gespielt'}
})
const game = useGameinfoStore()
const user = useUserinfoStore()
const editName = () => { alert('not yet implemented') }
const editLang = () => { alert('not yet implemented') }
const showId = ref(false)
</script>
<style lang="scss">
@ -42,4 +71,4 @@ const editLang = () => { alert('not yet implemented') }
height: 100%;
}
}
</style>
</style>

View File

@ -13,6 +13,11 @@
<script setup lang="ts">
import useI18n from '@/composables/useI18n'
import type { GameInfo } from '@/composables/engine.d'
defineProps<{
gameinfo: GameInfo
}>()
const { $t } = useI18n({
name: { en: 'Name', de: 'Name' },

View File

@ -1,3 +1,5 @@
export type Role = 'player' | 'gamemaster' | 'admin'
export type Player = {
id: string
name: string
@ -5,6 +7,14 @@ export type Player = {
score: number
}
export type PlayerInfo = Player & {
created: number
lastLoggedIn: number
isPlaying: boolean
numQuotes: number
role: Role
}
export type Players = Array<Player>
export type Quote = {
@ -46,3 +56,18 @@ export type Round = {
selections: Selections
revelation: Revelation
}
export type Lang = 'de' | 'en'
export type State = 'idle' | 'collect' | 'ready-set' | 'play' | 'finish'
export type GameInfo = {
id: string
name: string
lang: Lang
created: number
state: State
players: Array<PlayersExtended>
numQuotesLeft: number
numQuotesTotal: number
}

View File

@ -1,5 +1,6 @@
import { useUserinfoStore } from "@/stores/UserinfoStore"
import { EngineContext } from '@/composables/useEngine'
import type { GameInfo } from '@/composables/engine.d'
import { useUserinfoStore } from "@/stores/UserinfoStore"
export async function collectQuotes(this: EngineContext): Promise<void> {
const userInfoStore = useUserinfoStore()
@ -35,3 +36,10 @@ export async function finishGame(this: EngineContext): Promise<void> {
g: userInfoStore.gameId,
})
}
export async function fetchGameInfo(this: EngineContext): Promise<GameInfo> {
const userInfoStore = useUserinfoStore()
return await this.callApi('/api/gameinfo', {
g: userInfoStore.gameId,
}) as GameInfo
}

View File

@ -0,0 +1,31 @@
export interface useDateFormatter {
date: (timestamp: number) => string | undefined
datetime: (timestamp: number) => string | undefined
}
export default (): useDateFormatter => {
const leftPad2Digits = (val: number) => val < 10 ? '0' + val : '' + val
const date = (time: number): string | undefined => {
if (!time) return
const d = new Date(time * 1000)
return `${d.getFullYear()}-` +
`${leftPad2Digits(d.getMonth() + 1)}-` +
`${leftPad2Digits(d.getDate())}`
}
const datetime = (time: number): string | undefined => {
if (!time) return
const d = new Date(time * 1000)
return `${date(time)}, ` +
`${leftPad2Digits(d.getHours())}:` +
`${leftPad2Digits(d.getMinutes())}:` +
`${leftPad2Digits(d.getSeconds())}`
}
return {
date,
datetime,
}
}

View File

@ -3,9 +3,9 @@ import { callApi, QueryParams } from '@/composables/engine/callApi'
import { start, stop } from '@/composables/engine/startStop'
import { fetchUpdate } from '@/composables/engine/fetchUpdate'
import { loadQuotes, getQuotesRef, deleteQuote, saveQuote } from '@/composables/engine/quotes'
import { collectQuotes, startGame, continueGame, resetGame, finishGame } from '@/composables/engine/gamemaster'
import { collectQuotes, startGame, continueGame, resetGame, finishGame, fetchGameInfo } from '@/composables/engine/gamemaster'
import { saveSelection } from '@/composables/engine/play'
import type { Quotes } from '@/composables/engine.d'
import type { Quotes, GameInfo } from '@/composables/engine.d'
export interface EngineContext {
isActive: boolean
@ -36,6 +36,7 @@ export interface useEngine {
resetGame: () => Promise<void>
finishGame: () => Promise<void>
saveSelection: (selection: string) => Promise<void>
fetchGameInfo: () => Promise<GameInfo>
}
export default (): useEngine => {
@ -69,5 +70,6 @@ export default (): useEngine => {
resetGame: () => resetGame.apply(context),
finishGame: () => finishGame.apply(context),
saveSelection: (selection: string) => saveSelection.apply(context, [selection]),
fetchGameInfo: () => fetchGameInfo.apply(context),
}
}

View File

@ -1,3 +1,5 @@
import type { Lang } from '@/composables/engine.d'
export type i18nMap = {
[key: string]: {
en: string,
@ -5,8 +7,6 @@ export type i18nMap = {
},
}
export type Lang = 'de' | 'en'
const browserLang = navigator.language ? navigator.language.substring(0, 2) : 'en'
const defaultLang: Lang = browserLang === 'de' ? 'de' : 'en'
let lang: Lang = defaultLang

View File

@ -1,7 +1,10 @@
<template>
<div class="gamemaster__container">
<TopBar />
<AdminGameInfoTile />
<div class="gamemaster__tiles">
<AdminGameInfoTile :gameinfo="gameinfo" />
<div class="gamemaster__tiles-spacer" />
</div>
</div>
</template>
@ -19,9 +22,8 @@ try {
navigateTo('/', { replace: true })
}
const { start: startEngine, stop: stopEngine } = useEngine()
onMounted(() => startEngine())
onBeforeUnmount(() => stopEngine())
const { fetchGameInfo } = useEngine()
const gameinfo = await fetchGameInfo()
</script>
<style lang="scss">
@ -30,5 +32,13 @@ onBeforeUnmount(() => stopEngine())
width: 100%;
height: 100%;
}
&__tiles {
display: flex;
}
&__tiles-spacer {
flex-grow: 1;
}
}
</style>