wip: Split cockpit feedback pages

This commit is contained in:
Christian Cueni 2023-12-07 09:25:43 +01:00
parent 22cfa6ff23
commit aa5077bf3c
8 changed files with 266 additions and 126 deletions

View File

@ -0,0 +1,86 @@
<template>
<main v-if="feedbackData">
<h1 class="mb-2">{{ $t("feedback.feedbackPageTitle") }}</h1>
<p class="mb-10">
<span class="font-bold" data-cy="feedback-data-amount">
{{ feedbackData.amount }}
</span>
{{ $t("feedback.feedbackPageInfo") }}
</p>
<ol v-if="feedbackData.amount > 0">
<li
v-for="(question, i) in orderedQuestions"
:key="i"
:data-cy="`question-${i + 1}`"
>
<RatingScale
v-if="ratingKeys.includes(question.key)"
class="mb-8 bg-white"
:ratings="feedbackData.questions[question.key]"
:title="`${$t('feedback.questionTitle')} ${i + 1}`"
:text="question.question"
/>
<VerticalBarChart
v-else-if="verticalChartKeys.includes(question.key)"
class="mb-8 bg-white"
:title="`${$t('feedback.questionTitle')} ${i + 1}`"
:ratings="feedbackData.questions[question.key]"
:text="question.question"
:ratio="0.2"
/>
<OpenFeedback
v-else-if="
openKeys.includes(question.key) && feedbackData.questions[question.key]
"
class="mb-8 bg-white"
:title="`${$t('feedback.questionTitle')} ${i + 1}`"
:text="question.question"
:answers="feedbackData.questions[question.key].filter((a: string) => a !== '')"
></OpenFeedback>
<HorizontalBarChart
v-else-if="
horizontalChartKeys.includes(question.key) &&
feedbackData.questions[question.key]
"
class="mb-8 bg-white"
:title="`${$t('feedback.questionTitle')} ${i}`"
:text="question.question"
:items="feedbackData.questions[question.key].map((a: string) => `${a}%`)"
/>
</li>
</ol>
</main>
</template>
<script setup lang="ts">
import HorizontalBarChart from "@/components/ui/HorizontalBarChart.vue";
import OpenFeedback from "@/components/ui/OpenFeedback.vue";
import RatingScale from "@/components/ui/RatingScale.vue";
import VerticalBarChart from "@/components/ui/VerticalBarChart.vue";
import type { FeedbackData } from "@/types";
import * as log from "loglevel";
interface Props {
orderedQuestions?: {
key: string;
question: string;
}[];
feedbackData: FeedbackData;
ratingKeys?: string[];
verticalChartKeys?: string[];
horizontalChartKeys?: string[];
openKeys?: string[];
}
const props = withDefaults(defineProps<Props>(), {
orderedQuestions: () => [],
ratingKeys: () => [],
verticalChartKeys: () => [],
horizontalChartKeys: () => [],
openKeys: () => [],
});
log.debug("FeedbackBasePage created");
</script>
<style scoped></style>

View File

@ -10,78 +10,29 @@
<span>{{ $t("general.back") }}</span>
</router-link>
</nav>
<main v-if="feedbackData">
<h1 class="mb-2">{{ $t("feedback.feedbackPageTitle") }}</h1>
<p class="mb-10">
<span class="font-bold" data-cy="feedback-data-amount">
{{ feedbackData.amount }}
</span>
{{ $t("feedback.feedbackPageInfo") }}
</p>
<ol v-if="feedbackData.amount > 0">
<li
v-for="(question, i) in orderedQuestions"
:key="i"
:data-cy="`question-${i + 1}`"
>
<RatingScale
v-if="ratingKeys.includes(question.key)"
class="mb-8 bg-white"
:ratings="feedbackData.questions[question.key]"
:title="`${$t('feedback.questionTitle')} ${i + 1}`"
:text="question.question"
/>
<VerticalBarChart
v-else-if="verticalChartKyes.includes(question.key)"
class="mb-8 bg-white"
:title="`${$t('feedback.questionTitle')} ${i + 1}`"
:ratings="feedbackData.questions[question.key]"
:text="question.question"
:ratio="0.2"
/>
<OpenFeedback
v-else-if="
openKeys.includes(question.key) && feedbackData.questions[question.key]
"
class="mb-8 bg-white"
:title="`${$t('feedback.questionTitle')} ${i + 1}`"
:text="question.question"
:answers="feedbackData.questions[question.key].filter((a: string) => a !== '')"
></OpenFeedback>
<HorizontalBarChart
v-else-if="
horizontalChartKeys.includes(question.key) &&
feedbackData.questions[question.key]
"
class="mb-8 bg-white"
:title="`${$t('feedback.questionTitle')} ${i}`"
:text="question.question"
:items="feedbackData.questions[question.key].map((a: string) => `${a}%`)"
/>
</li>
</ol>
</main>
<FeedbackPageVV
v-if="feedbackData != undefined && feedbackType === 'vv'"
:feedback-data="feedbackData"
/>
<FeedbackPageUK
v-else-if="feedbackData != undefined && feedbackType === 'uk'"
:feedback-data="feedbackData"
/>
<div v-else class="flex justify-center">
<p>unknown FeedbackType</p>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import HorizontalBarChart from "@/components/ui/HorizontalBarChart.vue";
import OpenFeedback from "@/components/ui/OpenFeedback.vue";
import RatingScale from "@/components/ui/RatingScale.vue";
import VerticalBarChart from "@/components/ui/VerticalBarChart.vue";
import { useCurrentCourseSession } from "@/composables";
import { itGet } from "@/fetchHelpers";
import * as log from "loglevel";
import { onMounted, ref } from "vue";
import { useTranslation } from "i18next-vue";
interface FeedbackData {
amount: number;
questions: {
[key: string]: any;
};
}
import type { FeedbackData } from "@/types";
import FeedbackPageVV from "@/pages/cockpit/FeedbackPageVV.vue";
import FeedbackPageUK from "@/pages/cockpit/FeedbackPageUK.vue";
const props = defineProps<{
courseSlug: string;
@ -91,72 +42,18 @@ const props = defineProps<{
log.debug("FeedbackPage created", props.circleId);
const courseSession = useCurrentCourseSession();
const { t } = useTranslation();
const orderedQuestions = [
{
key: "satisfaction",
question: t("feedback.satisfactionLabel"),
},
{
key: "goal_attainment",
question: t("feedback.goalAttainmentLabel"),
},
{
key: "proficiency",
question: t("feedback.proficiencyLabel"),
},
{
key: "preparation_task_clarity",
question: t("feedback.preparationTaskClarityLabel"),
},
{
key: "instructor_competence",
question: t("feedback.instructorCompetenceLabel"),
},
{
key: "instructor_respect",
question: t("feedback.instructorRespectLabel"),
},
{
key: "instructor_open_feedback",
question: t("feedback.instructorOpenFeedbackLabel"),
},
{
key: "would_recommend",
question: t("feedback.recommendLabel"),
},
{
key: "course_negative_feedback",
question: t("feedback.courseNegativeFeedbackLabel"),
},
{
key: "course_positive_feedback",
question: t("feedback.coursePositiveFeedbackLabel"),
},
];
const ratingKeys = [
"satisfaction",
"goal_attainment",
"instructor_competence",
"instructor_respect",
];
const verticalChartKyes = ["preparation_task_clarity", "would_recommend"];
const horizontalChartKeys = ["proficiency"];
const openKeys = [
"course_negative_feedback",
"course_positive_feedback",
"instructor_open_feedback",
];
const feedbackData = ref<FeedbackData | undefined>(undefined);
const feedbackType = ref<"vv" | undefined>(undefined);
onMounted(async () => {
log.debug("FeedbackPage mounted");
feedbackData.value = await itGet(
`/api/core/feedback/${courseSession.value.id}/${props.circleId}`
);
log.debug("FeedbackPage feedbackData", feedbackData.value);
if (["uk", "vv"].includes(feedbackData.value?.feedbackType ?? "")) {
feedbackType.value = feedbackData.value.feedbackType;
}
});
</script>

View File

@ -0,0 +1,84 @@
<template>
<FeedbackBasePage
:ordered-questions="orderedQuestions"
:feedback-data="feedbackData"
:rating-keys="ratingKeys"
:vertical-chart-keys="verticalChartKeys"
:horizontal-chart-keys="horizontalChartKeys"
:open-keys="openKeys"
/>
</template>
<script setup lang="ts">
import FeedbackBasePage from "@/pages/cockpit/FeedbackBasePage.vue";
import type { FeedbackData } from "@/types";
import * as log from "loglevel";
import { useTranslation } from "i18next-vue";
const props = defineProps<{
feedbackData: FeedbackData;
}>();
log.debug("FeedbackPageUK created");
const { t } = useTranslation();
const orderedQuestions = [
{
key: "satisfaction",
question: t("feedback.satisfactionLabel"),
},
{
key: "goal_attainment",
question: t("feedback.goalAttainmentLabel"),
},
{
key: "proficiency",
question: t("feedback.proficiencyLabel"),
},
{
key: "preparation_task_clarity",
question: t("feedback.preparationTaskClarityLabel"),
},
{
key: "instructor_competence",
question: t("feedback.instructorCompetenceLabel"),
},
{
key: "instructor_respect",
question: t("feedback.instructorRespectLabel"),
},
{
key: "instructor_open_feedback",
question: t("feedback.instructorOpenFeedbackLabel"),
},
{
key: "would_recommend",
question: t("feedback.recommendLabel"),
},
{
key: "course_negative_feedback",
question: t("feedback.courseNegativeFeedbackLabel"),
},
{
key: "course_positive_feedback",
question: t("feedback.coursePositiveFeedbackLabel"),
},
];
const ratingKeys = [
"satisfaction",
"goal_attainment",
"instructor_competence",
"instructor_respect",
];
const verticalChartKeys = ["preparation_task_clarity", "would_recommend"];
const horizontalChartKeys = ["proficiency"];
const openKeys = [
"course_negative_feedback",
"course_positive_feedback",
"instructor_open_feedback",
];
</script>
<style scoped></style>

View File

@ -0,0 +1,63 @@
<template>
<FeedbackBasePage
:ordered-questions="orderedQuestions"
:feedback-data="feedbackData"
:rating-keys="ratingKeys"
:vertical-chart-keys="verticalChartKeys"
:horizontal-chart-keys="horizontalChartKeys"
:open-keys="openKeys"
/>
</template>
<script setup lang="ts">
import FeedbackBasePage from "@/pages/cockpit/FeedbackBasePage.vue";
import type { FeedbackData } from "@/types";
import * as log from "loglevel";
import { useTranslation } from "i18next-vue";
const props = defineProps<{
feedbackData: FeedbackData;
}>();
log.debug("FeedbackPageVV created");
const { t } = useTranslation();
const orderedQuestions = [
{
key: "satisfaction",
question: t("feedback.satisfactionLabel"),
},
{
key: "goal_attainment",
question: t("feedback.goalAttainmentLabel"),
},
{
key: "proficiency",
question: t("feedback.proficiencyLabelVV"),
},
{
key: "preparation_task_clarity",
question: t("feedback.praxisAssignmentClarity"),
},
{
key: "would_recommend",
question: t("feedback.recommendLabelVV"),
},
{
key: "course_negative_feedback",
question: t("feedback.courseNegativeFeedbackLabel"),
},
{
key: "course_positive_feedback",
question: t("feedback.coursePositiveFeedbackLabel"),
},
];
const ratingKeys = ["satisfaction", "goal_attainment"];
const verticalChartKeys = ["preparation_task_clarity", "would_recommend"];
const horizontalChartKeys = ["proficiency"];
const openKeys = ["course_negative_feedback", "course_positive_feedback"];
</script>
<style scoped></style>

View File

@ -566,3 +566,13 @@ export type DueDate = SimpleDueDate & {
course_session_id: string;
circle: CircleLight | null;
};
export type FeedbackType = "uk" | "vv";
export interface FeedbackData {
amount: number;
questions: {
[key: string]: any;
};
feedbackType: FeedbackType;
}

View File

@ -32,7 +32,8 @@ from vbv_lernwelt.course_session.services.attendance import AttendanceUserStatus
from vbv_lernwelt.feedback.models import FeedbackResponse
from vbv_lernwelt.learnpath.models import (
LearningContentAttendanceCourse,
LearningContentFeedbackUK, LearningContentFeedbackVV,
LearningContentFeedbackUK,
LearningContentFeedbackVV,
)
from vbv_lernwelt.notify.models import Notification

View File

@ -6,8 +6,8 @@ from vbv_lernwelt.feedback.models import FeedbackResponse
logger = structlog.get_logger(__name__)
FEEDBACK_TYPES = (
('uk', 'Feedback UK'),
('vv', 'Feedback VV'),
("uk", "Feedback UK"),
("vv", "Feedback VV"),
)

View File

@ -61,7 +61,6 @@ def get_feedback_for_circle(request, course_session_id, circle_id):
feedback_user__in=feedback_users(course_session_id),
).order_by("created_at")
# I guess this is ok for the üK case
feedback_data = {"amount": len(feedbacks), "questions": {}, "feedbackType": None}
if feedback_data["amount"] == 0: