updated npm versions; Refactored Question/Answer Types

This commit is contained in:
Baer 2026-03-21 22:56:02 +01:00
parent ae18ac1ccd
commit afd2345cac
47 changed files with 3564 additions and 3785 deletions

View File

@ -1,11 +1,10 @@
package at.eisibaer.jbear2.dto.board
import at.eisibaer.jbear2.dto.edit.AnswerTypeDto
import org.springframework.data.geo.Point
data class AnswerDto(
val text: String,
val answerType: AnswerTypeDto,
val answerType: Int,
val image: String?,
val location: Point?,
)

View File

@ -1,11 +1,10 @@
package at.eisibaer.jbear2.dto.board
import at.eisibaer.jbear2.dto.edit.QuestionTypeDto
import org.springframework.data.geo.Point
data class QuestionDto(
val text: String,
val questionType: QuestionTypeDto,
val questionType: Int,
val fontScaling: Int,
val image: String?,
val location: Point?,

View File

@ -1,7 +0,0 @@
package at.eisibaer.jbear2.dto.edit
data class AnswerTypeDto(
val title: String,
val description: String,
val id: Long?,
)

View File

@ -1,7 +0,0 @@
package at.eisibaer.jbear2.dto.edit
data class QuestionTypeDto(
val title: String,
val description: String,
val id: Long,
)

View File

@ -1,6 +0,0 @@
package at.eisibaer.jbear2.dto.edit
data class TypesDto(
val questionTypes: List<QuestionTypeDto>,
val answerTypes: List<AnswerTypeDto>,
)

View File

@ -1,32 +0,0 @@
package at.eisibaer.jbear2.endpoint
import at.eisibaer.jbear2.dto.edit.TypesDto
import at.eisibaer.jbear2.repository.AnswerTypeRepository
import at.eisibaer.jbear2.repository.QuestionTypeRepository
import at.eisibaer.jbear2.service.mapper.AnswerTypeMapper
import at.eisibaer.jbear2.service.mapper.QuestionTypeMapper
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
@Controller
@RequestMapping("/api/board")
class BoardEndpoint(
val answerTypeRepository: AnswerTypeRepository,
val questionTypeRepository: QuestionTypeRepository,
val questionTypeMapper: QuestionTypeMapper,
val answerTypeMapper: AnswerTypeMapper,
) {
@GetMapping("/structure")
fun getStructureForBoardEditing(): ResponseEntity<TypesDto>{
val questionTypes = questionTypeRepository.findAllByActiveTrue()
val answerTypes = answerTypeRepository.findAllByActiveTrue()
val types = TypesDto(
questionTypeMapper.toDto( questionTypes ),
answerTypeMapper.toDto( answerTypes )
);
return ResponseEntity.ok(types);
}
}

View File

@ -1,5 +1,6 @@
package at.eisibaer.jbear2.model
import at.eisibaer.jbear2.model.enums.AnswerType
import jakarta.persistence.*
@Entity
@ -11,9 +12,9 @@ data class Answer(
@Column(name = "text", nullable = false, unique = false)
val text: String,
@ManyToOne
@JoinColumn(name = "fk_answer_type", referencedColumnName = "id")
val answerType: AnswerType,
@Enumerated
@Column(name = "answer_type", nullable = false, unique = false)
val answerType: AnswerType = AnswerType.TEXT,
@OneToOne
@JoinColumn(name = "fk_image_file", referencedColumnName = "id")

View File

@ -1,21 +0,0 @@
package at.eisibaer.jbear2.model
import jakarta.persistence.*
@Entity
@Table(name = "answer_types")
data class AnswerType(
@Column(name = "title", nullable = false, unique = true)
val title: String,
@Column(name = "description", nullable = false, unique = true)
val description: String,
@Column(name = "active", nullable = false, unique = false)
val active: Boolean,
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
val id: Long? = null,
)

View File

@ -1,5 +1,6 @@
package at.eisibaer.jbear2.model
import at.eisibaer.jbear2.model.enums.QuestionType
import jakarta.persistence.*
@Entity
@ -13,9 +14,9 @@ data class Question(
@Column(name = "text", nullable = false, unique = false)
val text: String,
@ManyToOne
@JoinColumn(name = "fk_question_type", referencedColumnName = "id")
val questionType: QuestionType,
@Enumerated
@Column(name = "question_type", nullable = false, unique = false)
val questionType: QuestionType = QuestionType.TEXT,
@Column(name = "font_scaling", nullable = false, unique = false)
val fontScaling: Int,

View File

@ -1,21 +0,0 @@
package at.eisibaer.jbear2.model
import jakarta.persistence.*
@Entity
@Table(name = "question_types")
data class QuestionType(
@Column(name = "title", nullable = false, unique = true)
val title: String,
@Column(name = "description", nullable = false, unique = true)
val description: String,
@Column(name = "active", nullable = false, unique = false)
val active: Boolean,
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
val id: Long? = null,
)

View File

@ -0,0 +1,8 @@
package at.eisibaer.jbear2.model.enums
enum class AnswerType {
TEXT,
IMAGE,
AUDIO,
LOCATION;
}

View File

@ -0,0 +1,8 @@
package at.eisibaer.jbear2.model.enums
enum class QuestionType {
TEXT,
IMAGE,
AUDIO,
LOCATION;
}

View File

@ -1,11 +0,0 @@
package at.eisibaer.jbear2.repository
import at.eisibaer.jbear2.model.AnswerType
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@Repository
interface AnswerTypeRepository : JpaRepository<AnswerType, Long> {
fun findAllByActiveTrue(): List<AnswerType>;
}

View File

@ -1,11 +0,0 @@
package at.eisibaer.jbear2.repository
import at.eisibaer.jbear2.model.QuestionType
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@Repository
interface QuestionTypeRepository : JpaRepository<QuestionType, Long> {
fun findAllByActiveTrue(): List<QuestionType>;
}

View File

@ -3,6 +3,7 @@ package at.eisibaer.jbear2.service.mapper
import at.eisibaer.jbear2.dto.board.AnswerDto
import at.eisibaer.jbear2.model.Answer
import at.eisibaer.jbear2.model.File
import at.eisibaer.jbear2.model.enums.AnswerType
import at.eisibaer.jbear2.repository.FileRepository
import org.mapstruct.Context
import org.mapstruct.Mapper
@ -31,4 +32,12 @@ abstract class AnswerMapper {
}
}
}
fun map(type: AnswerType): Int {
return type.ordinal;
}
fun map(value: Int): AnswerType {
return AnswerType.entries[value];
}
}

View File

@ -1,9 +0,0 @@
package at.eisibaer.jbear2.service.mapper
import at.eisibaer.jbear2.dto.edit.AnswerTypeDto
import at.eisibaer.jbear2.model.AnswerType
import org.mapstruct.Mapper
@Mapper
interface AnswerTypeMapper : EntityMapper<AnswerTypeDto, AnswerType> {
}

View File

@ -3,6 +3,7 @@ package at.eisibaer.jbear2.service.mapper
import at.eisibaer.jbear2.dto.board.QuestionDto
import at.eisibaer.jbear2.model.File
import at.eisibaer.jbear2.model.Question
import at.eisibaer.jbear2.model.enums.QuestionType
import at.eisibaer.jbear2.repository.FileRepository
import org.mapstruct.Context
import org.mapstruct.Mapper
@ -31,4 +32,12 @@ abstract class QuestionMapper {
}
}
}
fun map(type: QuestionType): Int {
return type.ordinal;
}
fun map(value: Int): QuestionType {
return QuestionType.entries[value];
}
}

View File

@ -1,9 +0,0 @@
package at.eisibaer.jbear2.service.mapper
import at.eisibaer.jbear2.dto.edit.QuestionTypeDto
import at.eisibaer.jbear2.model.QuestionType
import org.mapstruct.Mapper
@Mapper
interface QuestionTypeMapper : EntityMapper<QuestionTypeDto, QuestionType> {
}

View File

@ -1,14 +0,0 @@
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript'
],
parserOptions: {
ecmaVersion: 'latest'
}
}

View File

@ -0,0 +1,24 @@
import { defineConfig } from "eslint/config";
import { js } from "@eslint/js";
import { FlagCompat } from "eslint/eslintrc";
import pluginVue from "eslint-plugin-vue";
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all
});
export default defineConfig([{
...pluginVue.configs['flat/essential'],
extends: compat.extends(
"plugin:vue/vue3-essential",
"eslint:recommended",
"@vue/eslint-config-typescript",
),
languageOptions: {
ecmaVersion: "latest",
parserOptions: {},
},
}]);

File diff suppressed because it is too large Load Diff

View File

@ -13,41 +13,37 @@
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/vue-fontawesome": "^3.0.8",
"@popperjs/core": "^2.11.8",
"@stomp/stompjs": "^7.0.0",
"@vuelidate/core": "^2.0.3",
"@vuelidate/validators": "^2.0.4",
"@vueuse/core": "^11.1.0",
"axios": "^1.7.2",
"bootstrap": "^5.3.3",
"pinia": "^2.1.7",
"vue": "^3.4.21",
"vue-draggable-plus": "^0.5.3",
"vue-i18n": "^9.13.1",
"vue-router": "^4.3.0"
"@fortawesome/fontawesome-svg-core": "~7.2.0",
"@fortawesome/free-solid-svg-icons": "~7.2.0",
"@fortawesome/vue-fontawesome": "~3.1.3",
"@stomp/stompjs": "~7.3.0",
"@vuelidate/core": "~2.0.3",
"@vuelidate/validators": "~2.0.4",
"@vueuse/core": "~14.2.1",
"axios": "~1.13.6",
"bootstrap": "~5.3.8",
"pinia": "~3.0.4",
"vue": "~3.5.30",
"vue-draggable-plus": "~0.6.1",
"vue-i18n": "~11.3.0",
"vue-router": "~5.0.3"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.8.0",
"@tsconfig/node20": "^20.1.4",
"@types/bootstrap": "^5.2.10",
"@types/jsdom": "^21.1.6",
"@types/node": "^20.12.5",
"@vitejs/plugin-vue": "^5.0.4",
"@vue/eslint-config-typescript": "^13.0.0",
"@vue/test-utils": "^2.4.5",
"@vue/tsconfig": "^0.5.1",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.23.0",
"jsdom": "^24.0.0",
"npm-run-all2": "^6.1.2",
"sass": "^1.77.6",
"typescript": "~5.4.0",
"vite": "^5.2.8",
"vite-plugin-vue-devtools": "^7.0.25",
"vitest": "^1.4.0",
"vue-tsc": "^2.0.11"
"@eslint/js": "~10.0.1",
"@intlify/eslint-plugin-vue-i18n": "~4.3.0",
"@tsconfig/node24": "~24.0.4",
"@types/bootstrap": "~5.2.10",
"@types/node": "~25.5.0",
"@vitejs/plugin-vue": "~6.0.5",
"@vue/eslint-config-typescript": "~14.7.0",
"@vue/test-utils": "~2.4.6",
"@vue/tsconfig": "~0.9.0",
"eslint": "~10.0.3",
"eslint-plugin-vue": "~10.8.0",
"sass": "~1.98.0",
"typescript": "~5.9.3",
"vite": "~8.0.0",
"vite-plugin-vue-devtools": "~8.1.0",
"vitest": "~4.1.0"
}
}

View File

@ -53,8 +53,10 @@ $breadcrumb-divider: quote(">");
@import "bootstrap/scss/variables-dark";
$form-file-button-bg: var(--#{$prefix}secondary-bg);
$form-file-button-hover-bg: var(--#{$prefix}tertiary-bg);
$form-file-button-hover-bg: var(--#{$prefix}tertiary-bg);
// $btn-border-radius: 0;
// $card-border-radius: 0;
/* Bootstrap Color Map adjustments */
$custom-colors: (

View File

@ -1,7 +1,6 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import type { Board } from '@/models/board/Board';
import { userService } from '@/services/UserService';
import IconJeobeardy from '../icons/IconJeobeardy.vue';
@ -78,7 +77,7 @@ userService
</template>
<div v-if="props.withNewOption" class="col-4 mb-3">
<button
class="btn btn-outline-primary w-100 h-100 d-flex flex-column justify-content-center p-3"
class="btn btn-outline-primary w-100 h-100 d-flex flex-column justify-content-center align-items-center gap-2"
@click="createNewBoard"
>
Create new Board

View File

@ -37,8 +37,12 @@ function boardEntrySelected(cIndex: number, bEIndex: number){
<template v-for="(category, categoryIndex) in props.board.categories " :key="category.name">
<div class="col pb-2">
<div class="d-flex flex-column h-100">
<button class="flex-fill board-card-max-height card bg-primary w-100 my-1" @click="categorySelected(categoryIndex)" :title="board.categories[categoryIndex].description">
<!-- TODO make color changeable?? -->
<button
class="flex-fill board-card-max-height card bg-primary w-100 my-1"
@click="categorySelected(categoryIndex)"
:title="board.categories[categoryIndex].description"
:style="[board.categories[categoryIndex].customColor ? {'background-color': `${board.categories[categoryIndex].color} !important`} : {}]"
>
<div class="card-body d-flex align-items-center justify-content-center">
{{ category.name }}
</div>

View File

@ -1,12 +1,12 @@
<script setup lang="ts">
import { computed, inject, ref } from 'vue';
import { computed, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { VueDraggable } from 'vue-draggable-plus';
import type { Board } from '@/models/board/Board';
import { Question } from '@/models/board/Question';
import { QuestionType } from '@/models/board/QuestionType';
import { answerTypesKey, questionTypesKey } from '@/services/UtilService';
import { QuestionType, type QuestionTypeType } from '@/models/board/QuestionType';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { AnswerType } from '@/models/board/AnswerType';
const { t } = useI18n();
@ -16,8 +16,6 @@ const props = defineProps<{
categoryIndex: number,
boardEntryIndex: number,
}>();
const questionTypes = inject(questionTypesKey);
const answerTypes = inject(answerTypesKey);
const emit = defineEmits<{
editBoard: [],
@ -30,9 +28,9 @@ const boardEntry = computed( () => {
});
const newQuestionText = ref( '' );
const newQuestionType = ref<QuestionType | null>( (questionTypes?.value ?? [null])[0] );
const newQuestionType = ref<QuestionTypeType>(QuestionType.TEXT);
function addQuestion() {
if( boardEntry.value.questions.length >= 10 || newQuestionType.value === null) {
if( boardEntry.value.questions.length >= 10) {
return;
}
const newQuestion = new Question(newQuestionText.value, newQuestionType.value);
@ -133,7 +131,7 @@ function openQuestion(categoryIndex: number, boardEntryIndex: number, questionIn
</div>
<div class="text-truncate">
<span class="ms-2">
{{ t(`board.question.types.title.${question.questionType.title}`) }}
<FontAwesomeIcon v-if="question.questionType === QuestionType.TEXT" :icon="['fas', 'align-center']" />
<span class="fw-light">
({{ question.text.length === 0 ? 'No Text yet' : question.text }})
</span>
@ -170,8 +168,8 @@ function openQuestion(categoryIndex: number, boardEntryIndex: number, questionIn
<div class="row mb-2">
<div class="col">
<select id="type-for-new-question" v-model="newQuestionType" class="form-select">
<template v-for="questionType in questionTypes" :key="questionType.id">
<option :value="questionType" :title="t(`board.question.types.description.${questionType.description}`)">{{ t(`board.question.types.title.${questionType.title}`) }}</option>
<template v-for="questionType in QuestionType" :key="questionType">
<option :value="questionType" :title="t(`board.question.types.description.${questionType}`)">{{ t(`board.question.types.title.${questionType}`) }}</option>
</template>
</select>
</div>
@ -186,8 +184,8 @@ function openQuestion(categoryIndex: number, boardEntryIndex: number, questionIn
<h4>{{ t('board.answer.label', 2) }}</h4>
<label class="mt-2" for="type-for-answer">{{ t( "board.answer.types.label" ) }}</label>
<select id="type-for-answer" v-model="boardEntry.answer.answerType" class="form-select">
<template v-for="answerType in answerTypes" :key="answerType.id">
<option :value="answerType" :title="t(`board.answer.types.description.${answerType.description}`)">{{ t(`board.answer.types.title.${answerType.title}`) }}</option>
<template v-for="answerType in AnswerType" :key="answerType">
<option :value="answerType" :title="t(`board.answer.types.description.${answerType}`)">{{ t(`board.answer.types.title.${answerType}`) }}</option>
</template>
</select>
<label class="mt-2" for="answer-text">{{ t( 'board.answer.text' ) }}</label>

View File

@ -4,7 +4,6 @@ import { Category } from '@/models/board/Category';
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { VueDraggable } from 'vue-draggable-plus';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
const { t } = useI18n();

View File

@ -1,12 +1,10 @@
<script setup lang="ts">
import type { Board } from '@/models/board/Board';
import { inject, ref } from 'vue';
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { VueDraggable } from 'vue-draggable-plus';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { BoardEntry } from '@/models/board/BoardEntry';
import { Answer } from '@/models/board/Answer';
import { answerTypesKey } from '@/services/UtilService';
import { AnswerType } from '@/models/board/AnswerType';
const { t } = useI18n();
@ -16,7 +14,6 @@ const board = defineModel<Board>( { required: true } );
const props = defineProps<{
categoryIndex: number,
}>();
const answerTypes = inject(answerTypesKey);
const emit = defineEmits<{
editBoardEntry: [categoryIndex: number, boardEntryIndex: number],
@ -29,7 +26,7 @@ function addBoardEntry() {
if( board.value.categories[props.categoryIndex].boardEntries.length >= 10 ) {
return;
}
const answer = new Answer('', answerTypes?.value[0] ?? new AnswerType('', '', false, 0));
const answer = new Answer('', AnswerType.TEXT);
const newBoardEntry = new BoardEntry( newBoardEntryName.value, answer, [] );
board.value.categories[props.categoryIndex].boardEntries.push( newBoardEntry );
}
@ -81,6 +78,11 @@ function openBoard() {
<label for="category-description">{{ t( 'board.category.description' ) }}</label>
<textarea id="category-description" class="form-control" v-model="board.categories[props.categoryIndex].description" :placeholder="t( 'board.category.description' )">
</textarea>
<div class="form-check mt-2">
<input id="category-color-custom" type="checkbox" class="form-check-input" v-model="board.categories[props.categoryIndex].customColor">
<label for="category-color-custom">{{ t( 'board.category.custom-color' ) }}</label>
</div>
<input v-if="board.categories[props.categoryIndex].customColor" id="category-color" type="color" class="form-control" v-model="board.categories[props.categoryIndex].color"/>
</div>
</div>
<div class="row mt-3">

View File

@ -1,12 +1,8 @@
<script setup lang="ts">
import type { Board } from '@/models/board/Board';
import { computed, inject } from 'vue';
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { questionTypesKey } from '@/services/UtilService';
const QUESTION_TYPE_IMAGE_ID = 2;
const QUESTION_TYPE_AUDIO_ID = 3;
import { QuestionType } from '@/models/board/QuestionType';
const { t } = useI18n();
@ -17,7 +13,6 @@ const props = defineProps<{
boardEntryIndex: number,
questionIndex: number;
}>();
const questionTypes = inject( questionTypesKey );
const emit = defineEmits<{
editBoard: [],
@ -85,7 +80,7 @@ function newAudioUploaded( event: Event ) {
</a>
</li>
<li class="breadcrumb-item active text-truncate" style="max-width: 6em;" aria-current="page">
{{ question.text.length !== 0 ? question.text : question.questionType.title }}
{{ question.text.length !== 0 ? question.text : t(`board.question.types.title.${question.questionType}`) }}
</li>
</ol>
</nav>
@ -107,12 +102,12 @@ function newAudioUploaded( event: Event ) {
<label for="board-entry-points">{{ t( 'board.question.type' ) }}</label>
<select id="question-type" v-model="question.questionType" class="form-select mb-2" aria-label="Question Type">
<template v-for=" questionType in questionTypes " :key="questionType.id">
<option :value="questionType" :title="t(`board.question.types.description.${questionType.description}`)">{{ t(`board.question.types.title.${questionType.title}`) }}</option>
<template v-for=" questionType in QuestionType " :key="questionType">
<option :value="questionType" :title="t(`board.question.types.description.${questionType}`)">{{ t(`board.question.types.title.${questionType}`) }}</option>
</template>
</select>
<template v-if=" question.questionType.id === QUESTION_TYPE_IMAGE_ID ">
<template v-if=" question.questionType === QuestionType.IMAGE ">
<label for="question-image-input">{{ t( 'board.question.upload.image' ) }}</label>
<input
id="question-image-input"
@ -122,7 +117,7 @@ function newAudioUploaded( event: Event ) {
accept="image/png, image/jpeg"
>
</template>
<template v-if=" question.questionType.id === QUESTION_TYPE_AUDIO_ID ">
<template v-if=" question.questionType === QuestionType.AUDIO ">
<label for="question-audio-input">{{ t( 'board.question.upload.audio' ) }}</label>
<input
id="question-audio-input"

View File

@ -1,5 +1,4 @@
<script setup lang="ts">
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';

View File

@ -1,5 +1,4 @@
<script setup lang="ts">
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { onMounted, watch } from 'vue';
import { useI18n } from 'vue-i18n';

View File

@ -8,7 +8,6 @@ import ThemeChanger from '@/components/blocks/ThemeChanger.vue';
import LocaleChanger from '@/components/blocks/LocaleChanger.vue';
import { useUserStore } from '@/stores/UserStore';
import { authService } from '@/services/AuthService';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
const navNames = {
HOME: "home",

View File

@ -1,6 +1,5 @@
<script setup lang="ts">
import { useGameStore } from '@/stores/GameStore';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
@ -10,8 +9,6 @@ const gameStore = useGameStore();
function adjustPoints(){
}
</script>
<template>
@ -32,7 +29,7 @@ function adjustPoints(){
/>
</div>
</div>
<template v-for="player in gameStore.players" :key="player.id">
<template v-for="player in gameStore.players" :key="player.uuid">
<div class="card bg-body-secondary mb-2">
<div class="card-header bg-primary p-2">
<div class="row">

View File

@ -1,16 +1,9 @@
<script setup lang="ts">
import { computed, inject, provide, ref, type Ref } from 'vue';
import { computed, inject, ref, type Ref } from 'vue';
import {
answerTypesKey,
navbarKey,
questionTypesKey,
} from '@/services/UtilService';
import { boardService } from '@/services/BoardService';
import { navbarKey } from '@/services/UtilService';
import { Board } from '@/models/board/Board';
import { BoardEntry } from '@/models/board/BoardEntry';
import { QuestionType } from '@/models/board/QuestionType';
import { AnswerType } from '@/models/board/AnswerType';
import type NavBar from '@/components/blocks/NavBar.vue';
import BoardView from '@/components/blocks/BoardView.vue';
@ -18,7 +11,6 @@ import CreatePanel from '@/components/blocks/CreatePanel.vue';
import BoardEntryView from '@/components/blocks/BoardEntryView.vue';
import { userService } from '@/services/UserService';
import { useRoute, useRouter } from 'vue-router';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
const navbar = inject<Ref<InstanceType<typeof NavBar> | null>>(navbarKey);
const navbarHeight = computed(() => {
@ -106,15 +98,6 @@ function exit() {
//TODO
}
let answerTypes = ref<Array<AnswerType>>([]);
let questionTypes = ref<Array<QuestionType>>([]);
provide(questionTypesKey, questionTypes);
provide(answerTypesKey, answerTypes);
boardService.getTypes().then((typesDto) => {
answerTypes.value = typesDto.answerTypes;
questionTypes.value = typesDto.questionTypes;
});
const boardLoading = ref(true);
const route = useRoute();
const router = useRouter();

View File

@ -1,17 +1,11 @@
<script setup lang="ts">
import { computed, inject, provide, ref, type Ref } from 'vue';
import { computed, inject, ref, type Ref } from 'vue';
import {
answerTypesKey,
navbarKey,
questionTypesKey,
} from '@/services/UtilService';
import { boardService } from '@/services/BoardService';
import { navbarKey } from '@/services/UtilService';
import { Board } from '@/models/board/Board';
import { Category } from '@/models/board/Category';
import { BoardEntry } from '@/models/board/BoardEntry';
import { Answer } from '@/models/board/Answer';
import { QuestionType } from '@/models/board/QuestionType';
import { AnswerType } from '@/models/board/AnswerType';
import type NavBar from '@/components/blocks/NavBar.vue';
@ -41,7 +35,7 @@ const board1 = ref<Board>(
);
const answer = new Answer(
'',
new AnswerType('Simple Answer', 'Simple Answer with text', true, 1)
AnswerType.TEXT
);
const newBoardEntry = new BoardEntry(
'Test Entry 1',
@ -89,15 +83,6 @@ function showAnswer() {
function hideAnswer() {
isAnswerShown.value = false;
}
let answerTypes = ref<Array<AnswerType>>([]);
let questionTypes = ref<Array<QuestionType>>([]);
provide(questionTypesKey, questionTypes);
provide(answerTypesKey, answerTypes);
boardService.getTypes().then((typesDto) => {
answerTypes.value = typesDto.answerTypes;
questionTypes.value = typesDto.questionTypes;
});
</script>
<template>

View File

@ -8,7 +8,6 @@ import { useGameStore } from '@/stores/GameStore';
import IconJeobeardy from '@/components/icons/IconJeobeardy.vue';
import { useRouter } from 'vue-router';
import type { AxiosError } from 'axios';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
const { t } = useI18n();

View File

@ -2,7 +2,6 @@
import { GAME_STATUS_CONST } from '@/services/GameService';
import { useGameStore } from '@/stores/GameStore';
import { useUserStore } from '@/stores/UserStore';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import type { AxiosError } from 'axios';
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';

View File

@ -2,7 +2,6 @@
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useClipboard } from '@vueuse/core';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { userService } from '@/services/UserService';
import { useGameStore } from '@/stores/GameStore';

View File

@ -79,6 +79,7 @@
"category": {
"infos": "Category Infos",
"label": "No Category | Category | Categories | {count} Categories",
"custom-color": "Set Custom Color",
"name": "Category Name",
"description": "Category Description",
"add": "Add Category",
@ -100,16 +101,16 @@
"fontsize": "Font Size",
"types": {
"title": {
"simple_question": "Simple Question",
"image_question": "Image Question",
"audio_question": "Audio Question",
"location_question": "Location Question"
"0": "Simple Question",
"1": "Image Question",
"2": "Audio Question",
"3": "Location Question"
},
"description": {
"simple_question_description": "A simple question with just text",
"image_question_description": "A question with text and an image",
"audio_question_description": "A question with text and audio",
"location_question_description": "A question with an image for players to guess the location on the image"
"0": "A simple question with just text",
"1": "A question with text and an image",
"2": "A question with text and audio",
"3": "A question with an image for players to guess the location on the image"
}
},
"upload": {
@ -123,14 +124,16 @@
"types": {
"label": "Answer Type",
"title": {
"simple_answer": "Simple Answer",
"image_answer": "Image Answer",
"location_answer": "Location Answer"
"0": "Simple Answer",
"1": "Image Answer",
"2": "Audio Answer",
"3": "Location Answer"
},
"description": {
"simple_answer_description": "A simple answer with just text",
"image_answer_description": "An answer with text and an image",
"location_answer_description": "An answer for a location question with the correct location shown on an image"
"0": "A simple answer with just text",
"1": "An answer with text and an image",
"2": "An answer with text and audio",
"3": "An answer for a location question with the correct location shown on an image"
}
}
}
@ -168,7 +171,7 @@
"light": {
"name": "Light"
},
"highContrast": {
"high-contrast": {
"name": "High Contrast"
}
},

View File

@ -9,7 +9,7 @@ import '@/assets/scss/customized_bootstrap.scss';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { library } from '@fortawesome/fontawesome-svg-core';
import { faSun, faMoon, faCircleHalfStroke, faEdit, faPlay, faSpinner, faLanguage, faGlobe, faPlus, faTrash, faGripLines, faAngleUp, faAngleDown, faAngleLeft, faAnglesRight, faHandPointer, faMinus, faEye, faLock, faLockOpen, faSave, faXmark, faUsers, faArrowRightToBracket, faCopy, faCheck, faArrowRight } from '@fortawesome/free-solid-svg-icons';
import { faSun, faMoon, faCircleHalfStroke, faEdit, faPlay, faSpinner, faLanguage, faGlobe, faPlus, faTrash, faGripLines, faAngleUp, faAngleDown, faAngleLeft, faAnglesRight, faHandPointer, faMinus, faEye, faLock, faLockOpen, faSave, faXmark, faUsers, faArrowRightToBracket, faCopy, faCheck, faArrowRight, faAlignCenter } from '@fortawesome/free-solid-svg-icons';
import enMessages from './locales/en.json';
import deMessages from './locales/de.json';
@ -52,10 +52,12 @@ library.add(
faCopy,
faCheck,
faArrowRight,
faAlignCenter,
)
const app = createApp( App );
app.component('FontAwesomeIcon', FontAwesomeIcon);
app.use( createPinia() );
app.use( router );
app.use( i18n );

View File

@ -1,8 +1,8 @@
export class AnswerType {
constructor(
public title: string,
public description: string,
public active: boolean,
public id: number,
){}
}
export const AnswerType = {
TEXT: 0,
IMAGE: 1,
AUDIO: 2,
LOCATION: 3,
} as const
export type AnswerTypeType = (typeof AnswerType)[keyof typeof AnswerType];

View File

@ -6,5 +6,7 @@ export class Category{
public description: string,
public boardEntries: Array<BoardEntry> = [],
public id: number | undefined = undefined,
public customColor: boolean = false,
public color: string = '#e86a92ff',
){}
}

View File

@ -1,9 +1,9 @@
import type { QuestionType } from './QuestionType';
import type { QuestionTypeType } from './QuestionType';
export class Question{
constructor(
public text: string,
public questionType: QuestionType,
public questionType: QuestionTypeType,
public fontScaling: number = 3,
public image: string | undefined = undefined,
public audio: string | undefined = undefined,

View File

@ -1,8 +1,8 @@
export class QuestionType {
constructor(
public title: string,
public description: string,
public active: boolean,
public id: number | undefined = undefined,
){}
}
export const QuestionType = {
TEXT: 0,
IMAGE: 1,
AUDIO: 2,
LOCATION: 3,
} as const
export type QuestionTypeType = (typeof QuestionType)[keyof typeof QuestionType];

View File

@ -5,6 +5,7 @@ import axios from "axios";
class BoardService {
//TODO Remove and replace with const values
getTypes(): Promise<TypesDto> {
return new Promise( ( resolve, reject ) => {
axios.get( `${ENV.API_BASE_URL}/board/structure`,

View File

@ -1,9 +1,5 @@
import type { InjectionKey, Ref } from 'vue';
import type NavBar from '@/components/blocks/NavBar.vue';
import type { QuestionType } from '@/models/board/QuestionType';
import type { AnswerType } from '@/models/board/AnswerType';
export const infoModalShowFnKey = Symbol() as InjectionKey<Function>;
export const navbarKey = Symbol() as InjectionKey<Ref<InstanceType<typeof NavBar> | undefined>>;
export const questionTypesKey = Symbol() as InjectionKey<Ref<Array<QuestionType>>>;
export const answerTypesKey = Symbol() as InjectionKey<Ref<Array<AnswerType>>>;
export const navbarKey = Symbol() as InjectionKey<Ref<InstanceType<typeof NavBar> | undefined>>;

View File

@ -1,5 +1,5 @@
{
"extends": "@tsconfig/node20/tsconfig.json",
"extends": "@tsconfig/node24/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",