feat: add create team dialog

This commit is contained in:
Settel 2022-09-09 12:50:05 +02:00
parent 2fb3833dd8
commit c6f09831e3
7 changed files with 119 additions and 42 deletions

View File

@ -1,28 +1,41 @@
<template> <template>
<ModalDialog @close="closeModalDialog" :title="$t('create-team')"> <template v-if="authcode">
<div class="create-team-dialog__description">{{ $t('description') }}</div> <ModalDialog :no-close-button="true" @close="closeModalDialog">
<div class="create-team-dialog__form"> <div class="create-team-dialog__auth-message">{{ $t('pin') }}</div>
<label class="create-team-dialog__label">{{ $t('your-name') }}</label> <div class="create-team-dialog__pin">{{ authcode }}</div>
<input id="create-team-dialog-name" class="create-team-dialog__input" v-model="playerName" size="40"/> <div class="create-team-dialog__auth-message">{{ $t('remember-and-log-in') }}</div>
<label class="create-team-dialog__label">{{ $t('team-name') }}</label> <div class="create-team-dialog__login-box">
<input class="create-team-dialog__input" v-model="teamName" size="40"/> <LoginBox />
<label class="create-team-dialog__label">{{ $t('language') }}</label> </div>
<select class="create-team-dialog__select" v-model="lang"> </ModalDialog>
<option value="en">EN</option> </template>
<option value="de">DE</option> <template v-else>
</select> <ModalDialog @close="closeModalDialog" :title="$t('create-team')">
<div class="create-team-dialog__description">{{ $t('description') }}</div>
</div> <div class="create-team-dialog__form">
<template v-slot:footer> <label class="create-team-dialog__label">{{ $t('your-name') }}</label>
<Button class="create-team-dialog__button" :border="true" @click="createTeam">{{ $t('create-team') }}</Button> <input id="create-team-dialog-name" class="create-team-dialog__input" v-model="playerName" size="40" />
<Button class="create-team-dialog__button" :border="false" @click="closeModalDialog">{{ $t('cancel') }}</Button> <label class="create-team-dialog__label">{{ $t('team-name') }}</label>
</template> <input class="create-team-dialog__input" v-model="teamName" size="40" />
</ModalDialog> <label class="create-team-dialog__label">{{ $t('language') }}</label>
<select class="create-team-dialog__select" v-model="lang">
<option value="en">EN</option>
<option value="de">DE</option>
</select>
</div>
<template v-slot:footer>
<Button class="create-team-dialog__button" :border="true" @click="createTeam">{{ $t('create-team') }}</Button>
<Button class="create-team-dialog__button" :border="false" @click="closeModalDialog">{{ $t('cancel') }}</Button>
</template>
</ModalDialog>
</template>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import useI18n from '@/composables/useI18n' import useI18n from '@/composables/useI18n'
import useEngine from '../composables/useEngine';
import LoginBox from './LoginBox.vue';
const emit = defineEmits(['close']) const emit = defineEmits(['close'])
@ -34,19 +47,35 @@ const { $t, getLang } = useI18n({
'team-name': { en: 'Team name', de: 'Teamname' }, 'team-name': { en: 'Team name', de: 'Teamname' },
'language': { en: 'Language', de: 'Sprache' }, 'language': { en: 'Language', de: 'Sprache' },
'names-missing': { en: 'Please enter a user name and a team name.', de: 'Bitte wähle einen Benutzernamen und Teamnamen.' }, 'names-missing': { en: 'Please enter a user name and a team name.', de: 'Bitte wähle einen Benutzernamen und Teamnamen.' },
'failed-to-create': { en: 'Failed to create team, sorry. Please contact Settel to investigate.', de: 'Team konnte nicht angelegt werden. Bitte kontaktiere Settel zur genaueren Untersuchung.' },
'pin': { en: 'Your pin code is:', de: 'Deine PIN lautet:' },
'remember-and-log-in': { en: 'Write it down now, then log in with your pin code.', de: 'Schreibe sie Dir gleich auf und logge dich anschließend damit ein.' },
}) })
const closeModalDialog = () => { emit('close') } const closeModalDialog = () => { emit('close') }
const playerName = ref('') const playerName = ref('')
const teamName = ref('') const teamName = ref('')
const lang = ref(getLang()) const lang = ref(getLang())
const authcode = ref('')
const createTeam = () => { const createTeam = async (): Promise<void> => {
if (playerName.value.length == 0 || teamName.value.length == 0) { if (playerName.value.length == 0 || teamName.value.length == 0) {
alert($t('names-missing')) alert($t('names-missing'))
return return
} }
alert('not yet implemented')
const status = await useEngine().createGame(
playerName.value,
teamName.value,
lang.value,
)
if (status.status !== 'ok') {
alert($t('failed-to-create'))
return
}
authcode.value = status.authcode
} }
onMounted(() => { onMounted(() => {
@ -90,5 +119,25 @@ onMounted(() => {
&__button~&__button { &__button~&__button {
margin-left: 16px; margin-left: 16px;
} }
&__auth-message {
font-family: $font-secondary;
font-size: 24px;
text-align: center;
margin: 32px;
}
&__pin {
font-family: $font-secondary;
font-size: 32px;
font-weight: 800;
text-align: center;
}
&__login-box {
display: flex;
margin-top: 96px;
justify-content: center;
}
} }
</style> </style>

View File

@ -3,7 +3,7 @@
<div class="modal-dialog__box"> <div class="modal-dialog__box">
<div class="modal-dialog__header"> <div class="modal-dialog__header">
<div class="modal-dialog__title">{{ title }}</div> <div class="modal-dialog__title">{{ title }}</div>
<Button :border="false" @click="emit('close')">x</Button> <Button v-if="!noCloseButton" :border="false" @click="emit('close')">x</Button>
</div> </div>
<div class="modal-dialog__body"> <div class="modal-dialog__body">
<slot /> <slot />
@ -19,6 +19,7 @@
<script setup lang="ts"> <script setup lang="ts">
defineProps<{ defineProps<{
title?: string title?: string
noCloseButton?: boolean
}>() }>()
const emit = defineEmits(['close']) const emit = defineEmits(['close'])
</script> </script>
@ -55,21 +56,21 @@ const emit = defineEmits(['close'])
&__title { &__title {
flex-grow: 1; flex-grow: 1;
margin: 16px 16px 8px 16px; margin: 36px 36px 8px 36px;
font-family: $font-primary; font-family: $font-primary;
font-size: 24px; font-size: 24px;
} }
&__body { &__body {
flex-grow: 1; flex-grow: 1;
margin: 16px; margin: 36px;
font-family: $font-secondary; font-family: $font-secondary;
} }
&__footer { &__footer {
display: flex; display: flex;
// justify-content: end; // justify-content: end;
margin: 24px 16px; margin: 24px 36px;
} }
&__backdrop { &__backdrop {

View File

@ -1,21 +1,21 @@
<template> <template>
<ModalDialog :title="title" @close="emit('close')"> <ModalDialog :title="title" @close="emit('close')">
<label class="player-dialog__label">Name</label> <label class="player-dialog__label">Name</label>
<input id="player-dialog-name" class="player-dialog__input" v-model="player.name" size="40"/> <input id="player-dialog-name" class="player-dialog__input" v-model="player.name" size="60" />
<label class="player-dialog__label">Score</label> <label class="player-dialog__label">Score</label>
<input class="player-dialog__input" v-model="player.score" size="40" maxlength="4" /> <input class="player-dialog__input" v-model="player.score" size="60" maxlength="4" />
<label class="player-dialog__label">Authcode</label> <label class="player-dialog__label">Authcode</label>
<div class="player-dialog__input-box"> <div class="player-dialog__input-box">
<input class="player-dialog__input" v-model="player.authcode" size="10" maxlength="6" /> <input class="player-dialog__input" v-model="player.authcode" size="40" maxlength="6" />
<Button :border="false" css-class="mini" @click="generate">generate</Button> <Button class="player-dialog__generate" :border="false" css-class="mini" @click="generate">generate</Button>
</div> </div>
<div class="player-dialog__id-container" @click="showId = true"> <div class="player-dialog__id-container" @click="showId = true">
<span class="player-dialog__id" :class="{ 'player-dialog__id__show': showId }">{{ player.id }}</span> <span class="player-dialog__id" :class="{ 'player-dialog__id__show': showId }">{{ player.id }}</span>
</div> </div>
<template v-slot:footer> <template v-slot:footer>
<Button v-for="button in buttons" :key="button.id" class="player-dialog__button" <Button v-for="button in buttons" :key="button.id" class="player-dialog__button"
:css-class="button.type === 'caution' ? button.type : ''" :border="['primary', 'caution'].indexOf(button.type) >= 0" :css-class="button.type === 'caution' ? button.type : ''"
@click="emit('submit', button.id)">{{ button.name :border="['primary', 'caution'].indexOf(button.type) >= 0" @click="emit('submit', button.id)">{{ button.name
}}</Button> }}</Button>
</template> </template>
</ModalDialog> </ModalDialog>
@ -34,7 +34,7 @@ const props = defineProps<{
const emit = defineEmits(['close', 'submit']) const emit = defineEmits(['close', 'submit'])
const showId = ref(false) const showId = ref(false)
onMounted(() => { onMounted(() => {
window.setTimeout(() => { window.setTimeout(() => {
document.getElementById('player-dialog-name')?.focus() document.getElementById('player-dialog-name')?.focus()
}, 0) }, 0)
@ -76,6 +76,14 @@ const generate = () => {
} }
} }
&__input-box {
display: flex;
}
&__generate {
margin-left: auto;
}
&__button~&__button { &__button~&__button {
margin-left: 16px; margin-left: 16px;
} }

View File

@ -29,8 +29,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import useI18n from '@/composables/useI18n' import useI18n from '@/composables/useI18n'
import useDateFormatter from '@/composables/useDateFormatter'; import useDateFormatter from '@/composables/useDateFormatter'
import useEngine from '@/composables/useEngine'; import useEngine from '@/composables/useEngine'
import { useUserinfoStore } from "@/stores/UserinfoStore"
import type { GameInfo, PlayerEdit } from '@/composables/engine.d' import type { GameInfo, PlayerEdit } from '@/composables/engine.d'
import type { Button, ButtonAction } from '@/components/admin/PlayerModal' import type { Button, ButtonAction } from '@/components/admin/PlayerModal'
@ -70,13 +71,17 @@ const addPlayer = () => {
} }
} }
const user = useUserinfoStore()
const editPlayer = async (player: PlayerEdit): Promise<void> => { const editPlayer = async (player: PlayerEdit): Promise<void> => {
showPlayerDialog.value = true showPlayerDialog.value = true
playerDialogTitle.value = 'Edit player' playerDialogTitle.value = 'Edit player'
playerDialogButtons.value =[ playerDialogButtons.value = [
{ id: 'edit', name: 'Save', type: 'primary' }, { id: 'edit', name: 'Save', type: 'primary' },
{ id: 'delete', name: 'Delete', type: 'caution' },
] ]
if (player.id != user.id) {
playerDialogButtons.value.push({ id: 'delete', name: 'Delete', type: 'caution' })
}
playerDialogPlayer.value = { playerDialogPlayer.value = {
...player, ...player,
} }

View File

@ -74,4 +74,9 @@ export type GameInfo = {
players: Array<PlayersExtended> players: Array<PlayersExtended>
numQuotesLeft: number numQuotesLeft: number
numQuotesTotal: number numQuotesTotal: number
} }
export type CreateGameStatus = {
status: string
authcode: string
}

View File

@ -1,6 +1,6 @@
import { EngineContext } from '@/composables/useEngine' import { EngineContext } from '@/composables/useEngine'
import type { GameInfo, PlayerEdit } from '@/composables/engine.d'
import { useUserinfoStore } from "@/stores/UserinfoStore" import { useUserinfoStore } from "@/stores/UserinfoStore"
import type { GameInfo, PlayerEdit, Lang, CreateGameStatus } from '@/composables/engine.d'
export async function fetchGameInfo(this: EngineContext): Promise<GameInfo> { export async function fetchGameInfo(this: EngineContext): Promise<GameInfo> {
const userInfoStore = useUserinfoStore() const userInfoStore = useUserinfoStore()
@ -44,3 +44,10 @@ export async function deletePlayer(this: EngineContext, id: string): Promise<voi
}) })
} }
export async function createGame(this: EngineContext, name: string, teamname: string, lang: Lang): Promise<CreateGameStatus> {
return await this.callApi('/api/createGame', {
name,
teamname,
lang,
}) as CreateGameStatus
}

View File

@ -3,10 +3,10 @@ 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 { fetchGameInfo, setGameLang, setGameName, savePlayer, deletePlayer } from '@/composables/engine/gamemaster' import { fetchGameInfo, setGameLang, setGameName, savePlayer, deletePlayer, createGame } from '@/composables/engine/gameManagement'
import { collectQuotes, startGame, continueGame, resetGame, finishGame } from '@/composables/engine/gameState' import { collectQuotes, startGame, continueGame, resetGame, finishGame } from '@/composables/engine/gameState'
import { saveSelection } from '@/composables/engine/play' import { saveSelection } from '@/composables/engine/play'
import type { Quotes, GameInfo, PlayerEdit } from '@/composables/engine.d' import type { Quotes, GameInfo, PlayerEdit, Lang, CreateGameStatus } from '@/composables/engine.d'
export interface EngineContext { export interface EngineContext {
isActive: boolean isActive: boolean
@ -42,6 +42,7 @@ export interface useEngine {
setGameName: (name: string) => Promise<void> setGameName: (name: string) => Promise<void>
savePlayer: (player: PlayerEdit) => Promise<void> savePlayer: (player: PlayerEdit) => Promise<void>
deletePlayer: (id: string) => Promise<void> deletePlayer: (id: string) => Promise<void>
createGame: (name: string, teamname: string, lang: Lang) => Promise<CreateGameStatus>
} }
export default (): useEngine => { export default (): useEngine => {
@ -80,5 +81,6 @@ export default (): useEngine => {
setGameName: (name: string) => setGameName.apply(context, [name]), setGameName: (name: string) => setGameName.apply(context, [name]),
savePlayer: (player: PlayerEdit) => savePlayer.apply(context, [player]), savePlayer: (player: PlayerEdit) => savePlayer.apply(context, [player]),
deletePlayer: (id: string) => deletePlayer.apply(context, [id]), deletePlayer: (id: string) => deletePlayer.apply(context, [id]),
createGame: (name: string, teamname: string, lang: Lang) => createGame.apply(context, [name, teamname, lang]),
} }
} }