feat: show game info on gamemaster page
This commit is contained in:
parent
cab1a91cc2
commit
9a5c647523
@ -18,7 +18,7 @@ defineProps<{
|
|||||||
|
|
||||||
.admin-tile {
|
.admin-tile {
|
||||||
&__container {
|
&__container {
|
||||||
width: 300px;
|
min-width: 300px;
|
||||||
margin: 40px;
|
margin: 40px;
|
||||||
padding: 16px 30px;
|
padding: 16px 30px;
|
||||||
background-color: $admin-tile-background-color;
|
background-color: $admin-tile-background-color;
|
||||||
|
@ -3,36 +3,65 @@
|
|||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ $t('name') }}:</td>
|
<td>{{ $t('name') }}:</td>
|
||||||
<td>{{ game.name }}</td>
|
<td>{{ gameinfo.name }}</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="gameinfo-tile__edit-game-name" @click="editName"></div>
|
<div class="gameinfo-tile__edit-game-name" @click="editName"></div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ $t('language') }}:</td>
|
<td>{{ $t('language') }}:</td>
|
||||||
<td>{{ user.lang }}</td>
|
<td>{{ gameinfo.lang }}</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="gameinfo-tile__edit-lang" @click="editLang"></div>
|
<div class="gameinfo-tile__edit-lang" @click="editLang"></div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</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>
|
</table>
|
||||||
</AdminTile>
|
</AdminTile>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
import useI18n from '@/composables/useI18n'
|
import useI18n from '@/composables/useI18n'
|
||||||
import { useUserinfoStore } from "@/stores/UserinfoStore"
|
import useDateFormatter from '@/composables/useDateFormatter';
|
||||||
import { useGameinfoStore } from "@/stores/GameinfoStore"
|
import type { GameInfo } from '@/composables/engine.d'
|
||||||
|
|
||||||
|
const { date } = useDateFormatter()
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
gameinfo: GameInfo
|
||||||
|
}>()
|
||||||
|
|
||||||
const { $t } = useI18n({
|
const { $t } = useI18n({
|
||||||
|
id: { en: 'Id', de: 'Id' },
|
||||||
name: { en: 'Name', de: 'Name' },
|
name: { en: 'Name', de: 'Name' },
|
||||||
language: { en: 'Language', de: 'Sprache' },
|
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 editName = () => { alert('not yet implemented') }
|
||||||
const editLang = () => { alert('not yet implemented') }
|
const editLang = () => { alert('not yet implemented') }
|
||||||
|
|
||||||
|
const showId = ref(false)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -13,6 +13,11 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import useI18n from '@/composables/useI18n'
|
import useI18n from '@/composables/useI18n'
|
||||||
|
import type { GameInfo } from '@/composables/engine.d'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
gameinfo: GameInfo
|
||||||
|
}>()
|
||||||
|
|
||||||
const { $t } = useI18n({
|
const { $t } = useI18n({
|
||||||
name: { en: 'Name', de: 'Name' },
|
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 = {
|
export type Player = {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
@ -5,6 +7,14 @@ export type Player = {
|
|||||||
score: number
|
score: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PlayerInfo = Player & {
|
||||||
|
created: number
|
||||||
|
lastLoggedIn: number
|
||||||
|
isPlaying: boolean
|
||||||
|
numQuotes: number
|
||||||
|
role: Role
|
||||||
|
}
|
||||||
|
|
||||||
export type Players = Array<Player>
|
export type Players = Array<Player>
|
||||||
|
|
||||||
export type Quote = {
|
export type Quote = {
|
||||||
@ -46,3 +56,18 @@ export type Round = {
|
|||||||
selections: Selections
|
selections: Selections
|
||||||
revelation: Revelation
|
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 { EngineContext } from '@/composables/useEngine'
|
||||||
|
import type { GameInfo } from '@/composables/engine.d'
|
||||||
|
import { useUserinfoStore } from "@/stores/UserinfoStore"
|
||||||
|
|
||||||
export async function collectQuotes(this: EngineContext): Promise<void> {
|
export async function collectQuotes(this: EngineContext): Promise<void> {
|
||||||
const userInfoStore = useUserinfoStore()
|
const userInfoStore = useUserinfoStore()
|
||||||
@ -35,3 +36,10 @@ export async function finishGame(this: EngineContext): Promise<void> {
|
|||||||
g: userInfoStore.gameId,
|
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 { start, stop } from '@/composables/engine/startStop'
|
||||||
import { fetchUpdate } from '@/composables/engine/fetchUpdate'
|
import { fetchUpdate } from '@/composables/engine/fetchUpdate'
|
||||||
import { loadQuotes, getQuotesRef, deleteQuote, saveQuote } from '@/composables/engine/quotes'
|
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 { saveSelection } from '@/composables/engine/play'
|
||||||
import type { Quotes } from '@/composables/engine.d'
|
import type { Quotes, GameInfo } from '@/composables/engine.d'
|
||||||
|
|
||||||
export interface EngineContext {
|
export interface EngineContext {
|
||||||
isActive: boolean
|
isActive: boolean
|
||||||
@ -36,6 +36,7 @@ export interface useEngine {
|
|||||||
resetGame: () => Promise<void>
|
resetGame: () => Promise<void>
|
||||||
finishGame: () => Promise<void>
|
finishGame: () => Promise<void>
|
||||||
saveSelection: (selection: string) => Promise<void>
|
saveSelection: (selection: string) => Promise<void>
|
||||||
|
fetchGameInfo: () => Promise<GameInfo>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (): useEngine => {
|
export default (): useEngine => {
|
||||||
@ -69,5 +70,6 @@ export default (): useEngine => {
|
|||||||
resetGame: () => resetGame.apply(context),
|
resetGame: () => resetGame.apply(context),
|
||||||
finishGame: () => finishGame.apply(context),
|
finishGame: () => finishGame.apply(context),
|
||||||
saveSelection: (selection: string) => saveSelection.apply(context, [selection]),
|
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 = {
|
export type i18nMap = {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
en: 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 browserLang = navigator.language ? navigator.language.substring(0, 2) : 'en'
|
||||||
const defaultLang: Lang = browserLang === 'de' ? 'de' : 'en'
|
const defaultLang: Lang = browserLang === 'de' ? 'de' : 'en'
|
||||||
let lang: Lang = defaultLang
|
let lang: Lang = defaultLang
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="gamemaster__container">
|
<div class="gamemaster__container">
|
||||||
<TopBar />
|
<TopBar />
|
||||||
<AdminGameInfoTile />
|
<div class="gamemaster__tiles">
|
||||||
|
<AdminGameInfoTile :gameinfo="gameinfo" />
|
||||||
|
<div class="gamemaster__tiles-spacer" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -19,9 +22,8 @@ try {
|
|||||||
navigateTo('/', { replace: true })
|
navigateTo('/', { replace: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
const { start: startEngine, stop: stopEngine } = useEngine()
|
const { fetchGameInfo } = useEngine()
|
||||||
onMounted(() => startEngine())
|
const gameinfo = await fetchGameInfo()
|
||||||
onBeforeUnmount(() => stopEngine())
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@ -30,5 +32,13 @@ onBeforeUnmount(() => stopEngine())
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__tiles {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__tiles-spacer {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
Loading…
Reference in New Issue
Block a user