feat: show game info on gamemaster page
This commit is contained in:
parent
cab1a91cc2
commit
9a5c647523
@ -18,7 +18,7 @@ defineProps<{
|
||||
|
||||
.admin-tile {
|
||||
&__container {
|
||||
width: 300px;
|
||||
min-width: 300px;
|
||||
margin: 40px;
|
||||
padding: 16px 30px;
|
||||
background-color: $admin-tile-background-color;
|
||||
|
@ -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"> </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>
|
||||
|
@ -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' },
|
||||
|
25
client/src/composables/engine.d.ts
vendored
25
client/src/composables/engine.d.ts
vendored
@ -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
|
||||
}
|
@ -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
|
||||
}
|
31
client/src/composables/useDateFormatter.ts
Normal file
31
client/src/composables/useDateFormatter.ts
Normal 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,
|
||||
}
|
||||
}
|
@ -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),
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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>
|
Loading…
Reference in New Issue
Block a user