wip: Split cockpit feedback pages
This commit is contained in:
parent
22cfa6ff23
commit
aa5077bf3c
|
|
@ -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>
|
||||||
|
|
@ -10,78 +10,29 @@
|
||||||
<span>{{ $t("general.back") }}</span>
|
<span>{{ $t("general.back") }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</nav>
|
</nav>
|
||||||
<main v-if="feedbackData">
|
<FeedbackPageVV
|
||||||
<h1 class="mb-2">{{ $t("feedback.feedbackPageTitle") }}</h1>
|
v-if="feedbackData != undefined && feedbackType === 'vv'"
|
||||||
<p class="mb-10">
|
:feedback-data="feedbackData"
|
||||||
<span class="font-bold" data-cy="feedback-data-amount">
|
/>
|
||||||
{{ feedbackData.amount }}
|
<FeedbackPageUK
|
||||||
</span>
|
v-else-if="feedbackData != undefined && feedbackType === 'uk'"
|
||||||
{{ $t("feedback.feedbackPageInfo") }}
|
:feedback-data="feedbackData"
|
||||||
</p>
|
/>
|
||||||
<ol v-if="feedbackData.amount > 0">
|
<div v-else class="flex justify-center">
|
||||||
<li
|
<p>unknown FeedbackType</p>
|
||||||
v-for="(question, i) in orderedQuestions"
|
</div>
|
||||||
: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>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<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 { useCurrentCourseSession } from "@/composables";
|
||||||
import { itGet } from "@/fetchHelpers";
|
import { itGet } from "@/fetchHelpers";
|
||||||
import * as log from "loglevel";
|
import * as log from "loglevel";
|
||||||
import { onMounted, ref } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
import { useTranslation } from "i18next-vue";
|
import type { FeedbackData } from "@/types";
|
||||||
|
import FeedbackPageVV from "@/pages/cockpit/FeedbackPageVV.vue";
|
||||||
interface FeedbackData {
|
import FeedbackPageUK from "@/pages/cockpit/FeedbackPageUK.vue";
|
||||||
amount: number;
|
|
||||||
questions: {
|
|
||||||
[key: string]: any;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
courseSlug: string;
|
courseSlug: string;
|
||||||
|
|
@ -91,72 +42,18 @@ const props = defineProps<{
|
||||||
log.debug("FeedbackPage created", props.circleId);
|
log.debug("FeedbackPage created", props.circleId);
|
||||||
|
|
||||||
const courseSession = useCurrentCourseSession();
|
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 feedbackData = ref<FeedbackData | undefined>(undefined);
|
||||||
|
const feedbackType = ref<"vv" | undefined>(undefined);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
log.debug("FeedbackPage mounted");
|
log.debug("FeedbackPage mounted");
|
||||||
feedbackData.value = await itGet(
|
feedbackData.value = await itGet(
|
||||||
`/api/core/feedback/${courseSession.value.id}/${props.circleId}`
|
`/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>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -566,3 +566,13 @@ export type DueDate = SimpleDueDate & {
|
||||||
course_session_id: string;
|
course_session_id: string;
|
||||||
circle: CircleLight | null;
|
circle: CircleLight | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type FeedbackType = "uk" | "vv";
|
||||||
|
|
||||||
|
export interface FeedbackData {
|
||||||
|
amount: number;
|
||||||
|
questions: {
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
feedbackType: FeedbackType;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,8 @@ from vbv_lernwelt.course_session.services.attendance import AttendanceUserStatus
|
||||||
from vbv_lernwelt.feedback.models import FeedbackResponse
|
from vbv_lernwelt.feedback.models import FeedbackResponse
|
||||||
from vbv_lernwelt.learnpath.models import (
|
from vbv_lernwelt.learnpath.models import (
|
||||||
LearningContentAttendanceCourse,
|
LearningContentAttendanceCourse,
|
||||||
LearningContentFeedbackUK, LearningContentFeedbackVV,
|
LearningContentFeedbackUK,
|
||||||
|
LearningContentFeedbackVV,
|
||||||
)
|
)
|
||||||
from vbv_lernwelt.notify.models import Notification
|
from vbv_lernwelt.notify.models import Notification
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ from vbv_lernwelt.feedback.models import FeedbackResponse
|
||||||
logger = structlog.get_logger(__name__)
|
logger = structlog.get_logger(__name__)
|
||||||
|
|
||||||
FEEDBACK_TYPES = (
|
FEEDBACK_TYPES = (
|
||||||
('uk', 'Feedback UK'),
|
("uk", "Feedback UK"),
|
||||||
('vv', 'Feedback VV'),
|
("vv", "Feedback VV"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,6 @@ def get_feedback_for_circle(request, course_session_id, circle_id):
|
||||||
feedback_user__in=feedback_users(course_session_id),
|
feedback_user__in=feedback_users(course_session_id),
|
||||||
).order_by("created_at")
|
).order_by("created_at")
|
||||||
|
|
||||||
# I guess this is ok for the üK case
|
|
||||||
feedback_data = {"amount": len(feedbacks), "questions": {}, "feedbackType": None}
|
feedback_data = {"amount": len(feedbacks), "questions": {}, "feedbackType": None}
|
||||||
|
|
||||||
if feedback_data["amount"] == 0:
|
if feedback_data["amount"] == 0:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue