Refactor feedback component

This commit is contained in:
Ramon Wenger 2022-12-08 17:02:59 +01:00
parent fb10799140
commit dd30010269
6 changed files with 149 additions and 182 deletions

View File

@ -1,87 +1,83 @@
<template> <template>
<div> <div>
<div> <ItRadioGroup
<p>Würden Sie den Kurs weiterempfehlen?</p> v-model="wouldRecommend"
<ItCheckbox :checked="wouldRecommend" @toggle="recommend = !recommend" /> label="Würden Sie den Kurs weiterempfehlen?"
</div> class="mb-8"
<div> :items="YES_NO"
<ItRadioGroup />
v-model="satisfaction" <ItRadioGroup
label="Zufriedenheit insgesamt" v-model="satisfaction"
:items="ratings" label="Zufriedenheit insgesamt"
/> class="mb-8"
<ItRadioGroup :items="RATINGS"
v-model="goalAttainment" />
label="Zielerreichung insgesamt" <ItRadioGroup
:items="ratings" v-model="goalAttainment"
/> label="Zielerreichung insgesamt"
<ItRadioGroup class="mb-8"
v-model="proficiency" :items="RATINGS"
label="Wie beurteilen Sie Ihre Sicherheit bezüglichen den Themen nach dem Kurs?" />
:items="percentages" <ItRadioGroup
/> v-model="proficiency"
</div> label="Wie beurteilen Sie Ihre Sicherheit bezüglichen den Themen nach dem Kurs?"
class="mb-8"
:items="PERCENTAGES"
/>
<ItRadioGroup <ItRadioGroup
v-model="receivedMaterials" v-model="receivedMaterials"
label="Haben Sie Vorbereitungsunterlagen (z.B. eLearning) erhalten?" label="Haben Sie Vorbereitungsunterlagen (z.B. eLearning) erhalten?"
:items="yesNo" class="mb-8"
:items="YES_NO"
/> />
<ItRadioGroup <ItRadioGroup
v-model="materialsRating" v-model="materialsRating"
label="Falls ja: Wie beurteilen Sie die Vorbereitungsunterlagen (z.B. label="Falls ja: Wie beurteilen Sie die Vorbereitungsunterlagen (z.B.
eLearning)?" eLearning)?"
:items="ratings" class="mb-8"
:items="RATINGS"
/> />
<ItRadioGroup <ItRadioGroup
v-model="instructorCompetence" v-model="instructorCompetence"
label="Der Kursleiter war themenstark, fachkompetent." label="Der Kursleiter war themenstark, fachkompetent."
:items="ratings" class="mb-8"
:items="RATINGS"
/> />
<ItRadioGroup <ItRadioGroup
v-model="instructorRespect" v-model="instructorRespect"
class="mb-8"
label="Fragen und Anregungen der Kursteilnehmenden wurden ernst label="Fragen und Anregungen der Kursteilnehmenden wurden ernst
genommen u. aufgegriffen." genommen u. aufgegriffen."
:items="ratings" :items="RATINGS"
/> />
<ItRadioGroup <div class="mb-8">
v-model="howDiscovered" <p class="mb-4">Was ich dem Kursleiter sonst noch sagen wollte:</p>
label="Wie sind Sie auf das Kursangebot aufmerksam geworden?" <textarea
:items="discoveryReasons" v-model="instructorOpenFeedback"
/> rows="4"
<p>Was ich dem Kursleiter sonst noch sagen wollte:</p> class="block w-full rounded-md border-gray-300 py-3 px-4 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
<textarea />
v-model="instructorOpenFeedback" </div>
rows="4" <div class="mb-8">
class="block w-96 rounded-md border-gray-300 py-3 px-4 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" <p class="mb-4">Wo sehen Sie Verbesserungspotenzial?</p>
/>
<div>
<p>Wo sehen Sie Verbesserungspotenzial?</p>
<textarea <textarea
v-model="courseNegativeFeedback" v-model="courseNegativeFeedback"
rows="4" rows="4"
class="block w-96 rounded-md border-gray-300 py-3 px-4 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" class="block w-full rounded-md border-gray-300 py-3 px-4 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
/> />
<!-- class="block w-full rounded-md border-gray-300 py-3 px-4 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"--> <!-- class="block w-full rounded-md border-gray-300 py-3 px-4 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"-->
</div> </div>
<div> <div class="mb-8">
<p>Was hat Ihnen besonders gut gefallen?</p> <p class="mb-4">Was hat Ihnen besonders gut gefallen?</p>
<textarea <textarea
v-model="coursePositiveFeedback" v-model="coursePositiveFeedback"
rows="4" rows="4"
class="block w-96 rounded-md border-gray-300 py-3 px-4 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" class="block w-full rounded-md border-gray-300 py-3 px-4 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
/> />
<!-- class="block w-full rounded-md border-gray-300 py-3 px-4 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"--> <!-- class="block w-full rounded-md border-gray-300 py-3 px-4 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"-->
</div> </div>
<h3>Motivation</h3> <button class="btn-blue" @click="sendFeedback">Senden und abschliessen</button>
<ItCheckbox /> <hr />
Persönliches Interesse
<ItCheckbox />
Berufliches Interesse
<ItCheckbox />
Pflichtkurs
<ItCheckbox />
Andere Gründe
<button @click="sendFeedback">Send!</button>
<pre> <pre>
satisfaction {{ satisfaction }} satisfaction {{ satisfaction }}
goalAttainment {{ goalAttainment }} goalAttainment {{ goalAttainment }}
@ -94,22 +90,29 @@ genommen u. aufgegriffen."
wouldRecommend {{ wouldRecommend }} wouldRecommend {{ wouldRecommend }}
coursePositiveFeedback {{ coursePositiveFeedback }} coursePositiveFeedback {{ coursePositiveFeedback }}
courseNegativeFeedback {{ courseNegativeFeedback }} courseNegativeFeedback {{ courseNegativeFeedback }}
howDiscovered {{ howDiscovered }}
motivation {{ motivation }}
mutationResult: {{ mutationResult }} mutationResult: {{ mutationResult }}
</pre> </pre>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import ItCheckbox from "@/components/ui/ItCheckbox.vue"; import {
PERCENTAGES,
RATINGS,
YES_NO,
} from "@/components/learningPath/feedback.constants";
import ItRadioGroup from "@/components/ui/ItRadioGroup.vue"; import ItRadioGroup from "@/components/ui/ItRadioGroup.vue";
import { COMPLETION_SUCCESS } from "@/constants";
import { graphql } from "@/gql/"; import { graphql } from "@/gql/";
import type { SendFeedbackInput } from "@/gql/graphql"; import type { SendFeedbackInput } from "@/gql/graphql";
import { useCircleStore } from "@/stores/circle";
import type { LearningContent } from "@/types";
import { useMutation } from "@urql/vue"; import { useMutation } from "@urql/vue";
import log from "loglevel"; import log from "loglevel";
import { reactive, ref } from "vue"; import { reactive, ref } from "vue";
const { page } = defineProps<{ page: LearningContent }>();
const sendFeedbackMutation = graphql(` const sendFeedbackMutation = graphql(`
mutation SendFeedbackMutation($input: SendFeedbackInput!) { mutation SendFeedbackMutation($input: SendFeedbackInput!) {
sendFeedback(input: $input) { sendFeedback(input: $input) {
@ -128,111 +131,14 @@ const sendFeedbackMutation = graphql(`
`); `);
const { executeMutation } = useMutation(sendFeedbackMutation); const { executeMutation } = useMutation(sendFeedbackMutation);
const discoveryReasons = [ const satisfaction = ref(null);
{ const goalAttainment = ref(null);
name: "Internet", const wouldRecommend = ref(null);
id: "I", const proficiency = ref(null);
}, const receivedMaterials = ref(null);
{
name: "Prospekt",
id: "L",
},
{
name: "Zeitung",
id: "N",
},
{
name: "Persönliche Empfehlung",
id: "R",
},
{
name: "Öffentliche Veranstaltung",
id: "E",
},
{
name: "Andere",
id: "O",
},
];
const yesNo = [
{
name: "Ja",
id: true,
},
{
name: "Nein",
id: false,
},
];
const ratings = [
{
name: "sehr unzufrieden",
id: 1,
},
{
name: "unzufrieden",
id: 2,
},
{
name: "zufrieden",
id: 3,
},
{
name: "sehr zufrieden",
id: 4,
},
];
const percentages = [
{
name: "20%",
id: 20,
},
{
name: "40%",
id: 40,
},
{
name: "60%",
id: 60,
},
{
name: "80%",
id: 80,
},
{
name: "100%",
id: 100,
},
];
const motivations = [
{
name: "Persönliches Interesse",
id: 1,
},
{
name: "Berufliches Interesse",
id: 2,
},
{
name: "Pflichtkurs",
id: 3,
},
{
name: "Andere Gründe",
id: 4,
},
];
const motivation = ref("");
const satisfaction = ref(0);
const goalAttainment = ref(0);
const wouldRecommend = ref(true);
const proficiency = ref(0);
const receivedMaterials = ref(false);
const materialsRating = ref(null); const materialsRating = ref(null);
const instructorCompetence = ref(0); const instructorCompetence = ref(null);
const instructorRespect = ref(0); const instructorRespect = ref(null);
const howDiscovered = ref("");
const coursePositiveFeedback = ref(""); const coursePositiveFeedback = ref("");
const courseNegativeFeedback = ref(""); const courseNegativeFeedback = ref("");
const instructorOpenFeedback = ref(""); const instructorOpenFeedback = ref("");
@ -240,12 +146,12 @@ const instructorOpenFeedback = ref("");
const mutationResult = ref<any>(null); const mutationResult = ref<any>(null);
const sendFeedback = () => { const sendFeedback = () => {
log.info("sending feedback");
const input: SendFeedbackInput = reactive({ const input: SendFeedbackInput = reactive({
materialsRating, materialsRating,
courseNegativeFeedback, courseNegativeFeedback,
coursePositiveFeedback, coursePositiveFeedback,
goalAttainment, goalAttainment,
howDiscovered,
instructorCompetence, instructorCompetence,
instructorRespect, instructorRespect,
instructorOpenFeedback, instructorOpenFeedback,
@ -253,14 +159,18 @@ const sendFeedback = () => {
proficiency, proficiency,
receivedMaterials, receivedMaterials,
wouldRecommend, wouldRecommend,
motivation, page: page.translation_key,
}); });
const variables = reactive({ const variables = reactive({
input, input,
}); });
executeMutation(variables).then(({ data }) => { log.debug(variables);
log.debug(data); executeMutation(variables)
mutationResult.value = data; .then(({ data, error }) => {
}); log.debug(data);
log.error(error);
mutationResult.value = data;
})
.catch((e) => log.error(e));
}; };
</script> </script>

View File

@ -4,6 +4,7 @@ import type { LearningUnit } from "@/types";
import * as log from "loglevel"; import * as log from "loglevel";
import LearningContentContainer from "@/components/learningPath/LearningContentContainer.vue"; import LearningContentContainer from "@/components/learningPath/LearningContentContainer.vue";
import {COMPLETION_FAILURE, COMPLETION_SUCCESS} from "@/constants";
import { computed, reactive } from "vue"; import { computed, reactive } from "vue";
log.debug("LearningContent.vue setup"); log.debug("LearningContent.vue setup");
@ -83,7 +84,7 @@ function handleBack() {
'border-2': currentQuestion.completion_status === 'success', 'border-2': currentQuestion.completion_status === 'success',
}" }"
data-cy="success" data-cy="success"
@click="circleStore.markCompletion(currentQuestion, 'success')" @click="circleStore.markCompletion(currentQuestion, COMPLETION_SUCCESS)"
> >
<it-icon-smiley-happy class="w-16 h-16 mr-4"></it-icon-smiley-happy> <it-icon-smiley-happy class="w-16 h-16 mr-4"></it-icon-smiley-happy>
<span class="font-bold text-large">{{ $t("selfEvaluation.yes") }}.</span> <span class="font-bold text-large">{{ $t("selfEvaluation.yes") }}.</span>
@ -91,8 +92,8 @@ function handleBack() {
<button <button
class="flex-1 inline-flex items-center text-left p-4 border" class="flex-1 inline-flex items-center text-left p-4 border"
:class="{ :class="{
'border-orange-500': currentQuestion.completion_status === 'fail', 'border-orange-500': currentQuestion.completion_status === COMPLETION_FAILURE,
'border-2': currentQuestion.completion_status === 'fail', 'border-2': currentQuestion.completion_status === COMPLETION_FAILURE,
}" }"
data-cy="fail" data-cy="fail"
@click="circleStore.markCompletion(currentQuestion, 'fail')" @click="circleStore.markCompletion(currentQuestion, 'fail')"

View File

@ -0,0 +1,52 @@
import type { RadioItem } from "@/components/learningPath/feedback.types";
export const YES_NO: RadioItem<boolean>[] = [
{
name: "Ja",
value: true,
},
{
name: "Nein",
value: false,
},
];
export const RATINGS: RadioItem<number>[] = [
{
name: "sehr unzufrieden",
value: 1,
},
{
name: "unzufrieden",
value: 2,
},
{
name: "zufrieden",
value: 3,
},
{
name: "sehr zufrieden",
value: 4,
},
];
export const PERCENTAGES: RadioItem<number>[] = [
{
name: "20%",
value: 20,
},
{
name: "40%",
value: 40,
},
{
name: "60%",
value: 60,
},
{
name: "80%",
value: 80,
},
{
name: "100%",
value: 100,
},
];

View File

@ -0,0 +1,4 @@
export interface RadioItem<T> {
value: T;
name: string;
}

3
client/src/constants.ts Normal file
View File

@ -0,0 +1,3 @@
export const COMPLETION_SUCCESS = "success";
export const COMPLETION_FAILURE = "fail";
export const COMPLETION_UNKNOWN = "unknown";

View File

@ -1679,20 +1679,19 @@ export type SecurityRequestResponseLog = {
export type SendFeedbackInput = { export type SendFeedbackInput = {
clientMutationId?: InputMaybe<Scalars['String']>; clientMutationId?: InputMaybe<Scalars['String']>;
courseNegativeFeedback: Scalars['String']; courseNegativeFeedback?: InputMaybe<Scalars['String']>;
coursePositiveFeedback: Scalars['String']; coursePositiveFeedback?: InputMaybe<Scalars['String']>;
goalAttainment: Scalars['Int']; goalAttainment?: InputMaybe<Scalars['Int']>;
howDiscovered: Scalars['String'];
id?: InputMaybe<Scalars['Int']>; id?: InputMaybe<Scalars['Int']>;
instructorCompetence: Scalars['Int']; instructorCompetence?: InputMaybe<Scalars['Int']>;
instructorOpenFeedback: Scalars['String']; instructorOpenFeedback?: InputMaybe<Scalars['String']>;
instructorRespect: Scalars['Int']; instructorRespect?: InputMaybe<Scalars['Int']>;
materialsRating?: InputMaybe<Scalars['Int']>; materialsRating?: InputMaybe<Scalars['Int']>;
motivation: Scalars['String']; page: Scalars['String'];
proficiency: Scalars['Int']; proficiency?: InputMaybe<Scalars['Int']>;
receivedMaterials: Scalars['Boolean']; receivedMaterials?: InputMaybe<Scalars['Boolean']>;
satisfaction: Scalars['Int']; satisfaction?: InputMaybe<Scalars['Int']>;
wouldRecommend: Scalars['Boolean']; wouldRecommend?: InputMaybe<Scalars['Boolean']>;
}; };
export type SendFeedbackPayload = { export type SendFeedbackPayload = {
@ -1702,13 +1701,11 @@ export type SendFeedbackPayload = {
coursePositiveFeedback?: Maybe<Scalars['String']>; coursePositiveFeedback?: Maybe<Scalars['String']>;
errors?: Maybe<Array<Maybe<ErrorType>>>; errors?: Maybe<Array<Maybe<ErrorType>>>;
goalAttainment?: Maybe<Scalars['Int']>; goalAttainment?: Maybe<Scalars['Int']>;
howDiscovered?: Maybe<Scalars['String']>;
id?: Maybe<Scalars['Int']>; id?: Maybe<Scalars['Int']>;
instructorCompetence?: Maybe<Scalars['Int']>; instructorCompetence?: Maybe<Scalars['Int']>;
instructorOpenFeedback?: Maybe<Scalars['String']>; instructorOpenFeedback?: Maybe<Scalars['String']>;
instructorRespect?: Maybe<Scalars['Int']>; instructorRespect?: Maybe<Scalars['Int']>;
materialsRating?: Maybe<Scalars['Int']>; materialsRating?: Maybe<Scalars['Int']>;
motivation?: Maybe<Scalars['String']>;
proficiency?: Maybe<Scalars['Int']>; proficiency?: Maybe<Scalars['Int']>;
receivedMaterials?: Maybe<Scalars['Boolean']>; receivedMaterials?: Maybe<Scalars['Boolean']>;
satisfaction?: Maybe<Scalars['Int']>; satisfaction?: Maybe<Scalars['Int']>;