Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 67 additions & 8 deletions src/features/dashboard/components/ActiveStudies.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<v-card elevation="2" rounded="lg" class="mb-6">
<v-card elevation="2" rounded="lg" class="mb-6" min-height="480px">
<v-card-title class="d-flex align-center justify-space-between py-4">
<div class="d-flex align-center">
<v-icon icon="mdi-flask-outline" class="me-2" color="primary" />
Expand All @@ -11,9 +11,19 @@
</v-card-title>

<v-card-text class="pa-4">
<v-row>
<v-col v-for="study in studies.filter(s => s)" :key="study.id" cols="12" md="6">
<v-card variant="outlined" rounded="lg" class="study-card">
<v-row v-if="loading">
<v-col v-for="n in 4" :key="n" cols="12" md="6">
<v-skeleton-loader
type="card"
class="study-card"
elevation="2"
rounded="lg"
/>
</v-col>
</v-row>
<v-row v-else>
<v-col v-for="study in studies.filter(s => s)" :key="study.id" cols="12" md="6">
<v-card variant="outlined" rounded="lg" class="study-card" @click="goToStudy(study)" hover>
<v-card-text class="pa-4">
<div class="d-flex align-center justify-space-between mb-3">
<v-chip
Expand Down Expand Up @@ -47,9 +57,9 @@
<v-icon icon="mdi-account-group" size="16" class="me-1" color="info" />
<span>{{ study.participants }} participants</span>
</div>
<div class="d-flex align-center">
<div v-if="study.daysLeft !== null" class="d-flex align-center">
<v-icon icon="mdi-calendar-clock" size="16" class="me-1" color="warning" />
<span>{{ study.daysLeft }} days left</span>
<span>{{ `${study.daysLeft} ${study.daysLeft > 1 ? 'days left' : 'day left'}` }}</span>
</div>
</div>
</v-card-text>
Expand All @@ -62,8 +72,9 @@

<script setup>
import AnswerController from '@/shared/controllers/AnswerController';
import { STUDY_TYPES } from '@/shared/constants/methodDefinitions';
import { getMethodManagerView, STUDY_TYPES } from '@/shared/constants/methodDefinitions';
import { computed, ref, watch } from 'vue'
import { useRouter } from 'vue-router';
import { useStore } from 'vuex';
import StudyController from '@/controllers/StudyController';

Expand All @@ -75,9 +86,12 @@ const props = defineProps({
})

const store = useStore()
const router = useRouter();
const answerController = new AnswerController()
const studyController = new StudyController()

const emit = defineEmits(["update-total"]);

const loading = ref(false);
const studiesWithAnswers = ref([]);

Expand Down Expand Up @@ -154,14 +168,47 @@ const finalFour = (studyArr) => {
status: study.status,
progress: calculateProgress(study.answers),
participants: study.answers?.length || 0,
daysLeft: daysLeft(study.endDate) || 0,
daysLeft: study.endDate ? daysLeft(study.endDate) : null,
typeIcon: 'mdi-sort-variant'
}))
.filter((study, index, self) =>
index === self.findIndex(m => m.id === study.id)
);
}

async function getTotalAnswersCount(studies) {
if (!studies || !studies.length) return 0;

try {
const counts = await Promise.all(
studies.map(async (study) => {
const testDoc = await studyController.getStudy({ id: study.testDocId });
const answerDoc = await answerController.getAnswerById(testDoc.answersDocId);

const answers =
answerDoc.type === STUDY_TYPES.USER
? Object.values({ ...answerDoc.taskAnswers })
: Object.values({ ...answerDoc.heuristicAnswers });

return answers.length;
})
);

return counts.reduce((acc, len) => acc + len, 0);
} catch (err) {
console.error("Error in getTotalAnswersCount:", err);
return 0;
}
}

const goToStudy = async (study) => {
if (!study?.id) return;

const testDoc = await studyController.getStudy({ id: study.id });
const methodView = getMethodManagerView(testDoc.testType, testDoc.subType)
router.push({ name: methodView, params: { id: testDoc.id } })
}

// Default studies if none provided
const defaultStudies = [
{
Expand Down Expand Up @@ -213,6 +260,18 @@ watch(
},
{ immediate: true }
);

watch(
() => props.studies,
async (newVal) => {
if (newVal && newVal.length > 0) {
const total = await getTotalAnswersCount(newVal);
emit("update-total", total);
}
},
{ immediate: true }
);

</script>

<style scoped>
Expand Down
4 changes: 2 additions & 2 deletions src/features/dashboard/components/StatsCards.vue
Original file line number Diff line number Diff line change
Expand Up @@ -173,14 +173,14 @@ defineProps({
}

.stats-value {
font-size: 2.0rem;
font-size: 20px;
font-weight: 700;
color: rgb(var(--v-theme-on-surface));
line-height: 1.2;
}

.stats-label {
font-size: 1rem;
font-size: 16px;
font-weight: 400;
}
</style>
7 changes: 5 additions & 2 deletions src/features/dashboard/views/DashboardView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@
cols="12"
lg="8"
>
<ActiveStudies :studies="items" />
<ActiveStudies
:studies="items"
@update-total="totalParticipants = $event"
/>
</v-col>
<v-col
cols="12"
Expand Down Expand Up @@ -98,7 +101,7 @@ const store = useStore()
// Dashboard data
const totalStudies = ref(12)
const usedStorage = ref(150)
const totalParticipants = ref(347)
const totalParticipants = ref(0)

// User info
const userDisplayName = computed(() => {
Expand Down
9 changes: 6 additions & 3 deletions src/ux/Heuristic/components/AddCommentBtn.vue
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,10 @@ const updateComment = (input) => {
emit('updateComment', input)
}

const handleImageUploaded = () => {
updateComment('')
}
const handleImageUploaded = (imageUrl) => {
if (imageUrl) {
localComment.value = '';
emit('updateComment', '', props.heurisIndex, props.answerHeu.heuristicId)
}
};
</script>
8 changes: 3 additions & 5 deletions src/ux/Heuristic/components/ImportImage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,13 @@ const uploadFile = async () => {
storage,
`tests/${props.testId}/heuristic_${props.heuristicId}/${props.questionId}/${file.name}`
)

await uploadBytes(storageReference, file)
url.value = await getDownloadURL(storageReference)

store.commit('SET_CURRENT_IMAGE_URL', url.value)

store.dispatch('setCurrentImageUrl', url.value)
imageUploaded.value = true
emit('imageUploaded')
}
emit('imageUploaded', url.value)
};
</script>

<style>
Expand Down
2 changes: 1 addition & 1 deletion src/ux/Heuristic/models/HeuristicQuestionAnswer.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default class HeuristicQuestionAnswer {
heuristicId: this.heuristicId,
heuristicAnswer: this.heuristicAnswer,
heuristicComment: this.heuristicComment,
answerImageUrl: this.answerImageUrl,
answerImageUrl: this.answerImageUrl || '',
}
}
}
7 changes: 1 addition & 6 deletions src/ux/Heuristic/store/Heuristic.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ export default {
testWeights: {},
scoresPercentage: [],
currentImageUrl: '',


},
getters: {
heuristics(state, getters, rootState) {
Expand Down Expand Up @@ -63,10 +61,7 @@ export default {
},
SET_CURRENT_IMAGE_URL(state, payload) {
state.currentImageUrl = payload
},
SET_CURRENT_IMAGE_URL(state, url) {
state.currentImageUrl = url
},
}
},
actions: {
async setHeuristics({ commit }, payload) {
Expand Down
10 changes: 5 additions & 5 deletions src/ux/Heuristic/views/HeuristicTestView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,6 @@ const isUserTestAdmin = computed(() => {
});

const loading = computed(() => store.getters.loading)
const currentImageUrl = computed(() => store.state.Tests.currentImageUrl)

const startTest = async () => {
if (heuristics.value.length === 0) {
Expand All @@ -648,10 +647,11 @@ const updateComment = (comment, heurisIndex, answerIndex) => {
if (!currentUserTestAnswer.value.heuristicQuestions?.[heurisIndex]?.heuristicQuestions?.[answerIndex]) {
return;
}
if (comment != '' && comment != undefined) {
currentUserTestAnswer.value.heuristicQuestions[heurisIndex].heuristicQuestions[answerIndex].heuristicComment = comment;
} else {
currentUserTestAnswer.value.heuristicQuestions[heurisIndex].heuristicQuestions[answerIndex].answerImageUrl = currentImageUrl.value;
const question = currentUserTestAnswer.value.heuristicQuestions[heurisIndex].heuristicQuestions[answerIndex];
if (comment !== '' && comment !== undefined) {
question.heuristicComment = comment;
} else if (store.state.Heuristic.currentImageUrl) {
question.answerImageUrl = store.state.Heuristic.currentImageUrl;
}
};

Expand Down
Loading