updated npm versions; Refactored Question/Answer Types
This commit is contained in:
parent
ae18ac1ccd
commit
afd2345cac
|
|
@ -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?,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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?,
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
package at.eisibaer.jbear2.dto.edit
|
||||
|
||||
data class AnswerTypeDto(
|
||||
val title: String,
|
||||
val description: String,
|
||||
val id: Long?,
|
||||
)
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package at.eisibaer.jbear2.dto.edit
|
||||
|
||||
data class QuestionTypeDto(
|
||||
val title: String,
|
||||
val description: String,
|
||||
val id: Long,
|
||||
)
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
package at.eisibaer.jbear2.dto.edit
|
||||
|
||||
data class TypesDto(
|
||||
val questionTypes: List<QuestionTypeDto>,
|
||||
val answerTypes: List<AnswerTypeDto>,
|
||||
)
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package at.eisibaer.jbear2.model.enums
|
||||
|
||||
enum class AnswerType {
|
||||
TEXT,
|
||||
IMAGE,
|
||||
AUDIO,
|
||||
LOCATION;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package at.eisibaer.jbear2.model.enums
|
||||
|
||||
enum class QuestionType {
|
||||
TEXT,
|
||||
IMAGE,
|
||||
AUDIO,
|
||||
LOCATION;
|
||||
}
|
||||
|
|
@ -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>;
|
||||
}
|
||||
|
|
@ -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>;
|
||||
}
|
||||
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
@ -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> {
|
||||
}
|
||||
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
@ -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> {
|
||||
}
|
||||
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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: (
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script setup lang="ts">
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script setup lang="ts">
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
||||
import { onMounted, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
@ -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',
|
||||
){}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
@ -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`,
|
||||
|
|
|
|||
|
|
@ -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>>>;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"extends": "@tsconfig/node20/tsconfig.json",
|
||||
"extends": "@tsconfig/node24/tsconfig.json",
|
||||
"include": [
|
||||
"vite.config.*",
|
||||
"vitest.config.*",
|
||||
|
|
|
|||
Loading…
Reference in New Issue