Move review to separate model

This commit is contained in:
2025-08-13 23:53:36 +02:00
parent befc678bdb
commit 900414727f
17 changed files with 403 additions and 155 deletions
+78 -24
View File
@@ -33,6 +33,7 @@ useHead({
});
const answer = ref(data.value?.answer?.text);
const final = ref(data.value?.answer?.final || false);
const textType = {
TEXT: 'text',
@@ -44,8 +45,10 @@ const textType = {
const newImage = ref<File>();
const uploading = ref(false);
const submitError = ref('');
async function submit() {
uploading.value = true;
submitError.value = '';
const body = new FormData();
@@ -55,21 +58,38 @@ async function submit() {
if (answer.value) {
body.set('answer', answer.value);
}
if (final.value) {
body.set('final', 'true');
}
if (newImage.value) {
body.set('image', newImage.value);
}
const result = await $fetch(`/api/quest/${questSlug?.id}/submit`, {
method: 'POST',
body
});
try {
await $fetch(`/api/quest/${questSlug?.id}/submit`, {
method: 'POST',
body
});
console.log(result);
await refresh();
await refresh();
answer.value = data.value?.answer?.text;
newImage.value = undefined;
} catch (e) {
if (e instanceof Error && 'statusCode' in e && e.statusCode === 418) {
submitError.value = 'Answer is already finalized, no update allowed!';
await refresh();
} else if (
e instanceof Error &&
'statusCode' in e &&
e.statusCode === 409
) {
submitError.value = 'Conflict: Please refresh';
} else {
submitError.value = parseError(e);
}
}
uploading.value = false;
answer.value = data.value?.answer?.text;
newImage.value = undefined;
}
const createImageURL = (file: File) => URL.createObjectURL(file);
@@ -83,7 +103,10 @@ const createImageURL = (file: File) => URL.createObjectURL(file);
>Back to Hunt</VaButton
>
<VaButton
@click="refresh"
@click="
submitError = '';
refresh();
"
icon="refresh"
:loading="pending"
color="success"
@@ -105,7 +128,9 @@ const createImageURL = (file: File) => URL.createObjectURL(file);
<VaCard
:stripe="data.answer !== null"
:stripe-color="
data.answer?.score && data.answer?.score > 0 ? 'success' : 'primary'
data.answer?.review?.score && data.answer?.review?.score > 0
? 'success'
: 'primary'
"
>
<VaCardTitle><QuestTags :quest="data" /></VaCardTitle>
@@ -132,26 +157,34 @@ const createImageURL = (file: File) => URL.createObjectURL(file);
<VaCard color="info" v-if="data.answer?.review">
<VaCardTitle>Review</VaCardTitle>
<VaCardContent>
<p v-if="data.answer.score" class="mb-2">
<VaChip color="success"
>Answer type: {{ data.answer.score }}</VaChip
>
<span v-if="data.answer.reviewer" class="text-sm">
by {{ data.answer.reviewer.name }}</span
<p v-if="data.answer.review?.score" class="mb-2">
Score:
<VaChip color="success">{{ data.answer.review.score }}</VaChip>
<span v-if="data.answer.review.reviewer" class="text-sm">
by {{ data.answer.review.reviewer.name }} at
{{
$d(data.answer.updatedAt, {
dateStyle: 'medium',
timeStyle: 'medium'
})
}}</span
>
</p>
<p>{{ data.answer.review }}</p>
<p class="italic">{{ data.answer.review.review }}</p>
</VaCardContent>
</VaCard>
<VaCard color="primary" v-if="user && user.role !== 'ADMIN'">
<VaCard
stripe
:stripe-color="data.answer?.final ? 'success' : 'primary'"
v-if="user && user.role !== 'ADMIN'"
>
<VaCardTitle>Submission</VaCardTitle>
<VaCardContent>
<div class="flex flex-col gap-4">
<VaInput
:label="data.question"
:disabled="uploading"
:disabled="uploading || data.answer?.final"
v-if="data.question"
color="onPrimary"
placeholder="Your answer"
:required-mark="data.textRequired"
v-model="answer"
@@ -187,8 +220,7 @@ const createImageURL = (file: File) => URL.createObjectURL(file);
></VaImage>
<VaFileUpload
v-model="newImage"
:disabled="uploading"
color="onPrimary"
:disabled="uploading || data.answer?.final"
type="single"
file-types="jpg,png,jpeg"
/>
@@ -206,13 +238,35 @@ const createImageURL = (file: File) => URL.createObjectURL(file);
}}
by {{ data.answer.member.name }}
</p>
<VaCheckbox
:disabled="data.answer?.final"
label="Finalize answer"
messages="This allows the admins to review your answer and give you points. You cannot change your answer afterwards!"
v-model="final"
/>
<VaAlert
v-if="submitError.length > 0"
color="danger"
class="w-full text-center"
>{{ $t(submitError) }}</VaAlert
>
<VaButton
:disabled="!(newImage || data.answer?.text !== answer)"
color="onPrimary"
v-if="!data.answer?.final"
:disabled="
!(
newImage ||
data.answer?.text !== answer ||
data.answer?.final !== final
)
"
:loading="uploading"
@click="submit"
>Update</VaButton
>
<p v-else class="font-bold">
Your final answer has already been submitted!
</p>
</div>
</VaCardContent>
</VaCard>
+1 -1
View File
@@ -55,7 +55,7 @@ const newUser = ref<User>();
watchDebounced(
search,
(newSearch) => {
if (newSearch && newSearch.length >= 3) {
if (newSearch) {
safeSearch.value = newSearch;
}
},
+8 -3
View File
@@ -143,9 +143,14 @@ async function invite() {
v-for="quest in data.quests"
:key="`q-${quest.id}`"
:to="$localePath(`/hunt/${sluggy(data)}/${sluggy(quest)}`)"
:stripe="quest.answer !== null"
stripe
:stripe-color="
quest.answer?.score && quest.answer?.score > 0 ? 'success' : 'primary'
(quest.answer?.review?.score && quest.answer?.review?.score > 0) ||
quest.answer?.final
? 'success'
: !!quest.answer
? 'warning'
: 'primary'
"
>
<VaCardTitle><QuestTags :quest="quest" /></VaCardTitle>
@@ -172,7 +177,7 @@ async function invite() {
<VaButton
color="danger"
:to="$localePath(`/hunt/${sluggy(data)}/${sluggy(quest)}/admin`)"
>Admin</VaButton
>Admin ({{ quest.unreviewed || 0 }} unreviewed)</VaButton
>
</VaCardActions>
</VaCard>