Files
pichunt/app/components/admin/Answer.vue
T
2025-08-09 14:58:38 +02:00

138 lines
4.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
const { d } = useI18n();
const props = defineProps<{
answer: {
id: number;
text: string | null;
updatedAt: string;
team: { id: number; name: string };
score: number | null;
review: string | null;
reviewer: { name: string; id: number } | null;
member: { name: string; id: number } | null;
internalNote: string | null;
rankingValue: number | null;
showcase: boolean;
picture: {
url: string;
createdAt: string;
} | null;
};
quest: {
title: string;
pictureRequired: boolean;
textRequired: boolean;
points: number;
extraPoints: number | null;
extraText: string | null;
textSolution: string | null;
};
}>();
const header = computed(() => {
const parts = [
props.answer.team.name,
props.answer.picture?.url ? '📸✅' : '📷❌',
props.answer.text ? '📝✅' : '📝❌',
props.answer.review ? '🔍✅' : '🔍❌',
props.answer.score ?? 'No points',
d(props.answer.updatedAt, {
dateStyle: 'medium',
timeStyle: 'medium'
}),
props.answer.rankingValue,
props.answer.showcase ? '★' : null
];
return parts.filter((s) => !!s).join(' ');
});
const style = computed<[string, string]>(() => {
if (props.answer.review && props.answer.score !== null) {
return ['success', 'check'];
}
if (props.answer.review || props.answer.score !== null) {
return ['danger', 'priority_high'];
}
if (
(props.quest.pictureRequired ? !!props.answer.picture?.url : true) &&
(props.quest.textRequired ? !!props.answer.text : true)
) {
return ['primary', 'info'];
}
return ['', ''];
});
</script>
<template>
<VaCollapse :header="header" :icon="style[1]" :color="style[0]">
<template #content>
<div class="flex flex-col gap-2">
<div
class="mb-2 grid grid-cols-3 justify-between gap-8 rounded-lg bg-gray-200 p-4 font-bold md:grid-cols-6"
>
<p>
{{
answer.picture?.url ? '📸✅ Picture done' : '📷❌ Picture missing'
}}
</p>
<p>{{ answer.text ? '📝✅ Answer done' : '📝❌ Answer missing' }}</p>
<p>
{{ answer.review ? '🔍✅ Review done' : '🔍❌ Review missing' }}
</p>
<p v-if="answer.rankingValue">
<VaIcon name="leaderboard" color="primary" />
{{ answer.rankingValue }}
</p>
<p v-if="answer.showcase">
<VaIcon name="auto_awesome" color="warning" /> Showcase
</p>
<p>{{ answer.score ?? 'No' }} points</p>
</div>
<ClickableImage
v-if="answer.picture?.url"
:src="answer.picture.url"
:title="`${quest.title} ${answer.team.name}`"
class="h-48"
/>
<h3 v-if="quest.textSolution">Solution:</h3>
<p v-if="quest.textSolution" class="bg-green-300 p-2 font-mono text-xl">
{{ quest.textSolution }}
</p>
<h3>Teams Answer:</h3>
<p class="bg-gray-300 p-2 font-mono text-xl">{{ answer.text }}</p>
<VaDivider />
<div
class="flex flex-col justify-between gap-4 md:flex-row md:items-center"
>
<VaInput
label="Score"
type="number"
:min="0"
messages="Including extra points"
/>
<VaInput
label="Ranking value"
type="number"
:min="0"
messages="Useful for sorting metric-based answers (e.g. distance, time), sorted descending"
/>
<VaCheckbox
label="Showcase"
messages="Special showcase at the end, before the final leaderboard"
/>
</div>
<VaTextarea label="Review" messages="Will be shown publicly!" />
<VaDivider />
<VaTextarea
label="Internal note"
messages="Only internal, the team won't see this!"
/>
<VaButton>Save</VaButton>
</div>
</template>
</VaCollapse>
</template>
<style scoped></style>