Add query url and clickable navigation

This commit is contained in:
Daniel Egger 2023-05-09 18:13:09 +02:00
parent 6534cbf8df
commit 04b179aa52
4 changed files with 138 additions and 133 deletions

View File

@ -1,106 +1,3 @@
<template>
<LearningContentMultiLayout
:title="title"
subtitle="Feedback"
:learning-content-type="'feedback'"
:show-start-button="stepNo === 0"
:show-next-button="stepNo > 0 && stepNo + 1 < numSteps"
:show-previous-button="stepNo > 0"
:show-exit-button="stepNo + 1 === numSteps"
:current-step="stepNo"
:steps-count="numSteps"
:start-badge-text="$t('general.introduction')"
:end-badge-text="$t('general.submission')"
@previous="previousStep()"
@next="nextStep()"
>
<div>
<p v-if="stepNo === 0" class="mt-10">
{{
$t("feedback.intro", {
name: `${courseSessionsStore.circleExperts[0].first_name} ${courseSessionsStore.circleExperts[0].last_name}`,
})
}}
</p>
<p v-if="stepNo > 0 && stepNo + 1 < numSteps" class="pb-2">
{{ stepLabels[stepNo] }}
</p>
<ItRadioGroup
v-if="stepNo === 1"
v-model="satisfaction"
class="mb-8"
:items="RATINGS"
/>
<ItRadioGroup
v-if="stepNo === 2"
v-model="goalAttainment"
class="mb-8"
:items="RATINGS"
/>
<ItRadioGroup
v-if="stepNo === 3"
v-model="proficiency"
class="mb-8"
:items="PERCENTAGES"
/>
<ItRadioGroup
v-if="stepNo === 4"
v-model="preparationTaskClarity"
class="mb-8"
:items="YES_NO"
/>
<ItRadioGroup
v-if="stepNo === 5"
v-model="instructorCompetence"
class="mb-8"
:items="RATINGS"
/>
<ItRadioGroup
v-if="stepNo === 6"
v-model="instructorRespect"
class="mb-8"
:items="RATINGS"
/>
<ItTextarea v-if="stepNo === 7" v-model="instructorOpenFeedback" class="mb-8" />
<ItRadioGroup
v-if="stepNo === 8"
v-model="wouldRecommend"
class="mb-8"
:items="YES_NO"
/>
<ItTextarea v-if="stepNo === 9" v-model="courseNegativeFeedback" class="mb-8" />
<ItTextarea v-if="stepNo === 10" v-model="coursePositiveFeedback" class="mb-8" />
<FeedbackCompletition
v-if="stepNo === 11"
:avatar-url="courseSessionsStore.circleExperts[0].avatar_url"
:title="
$t('feedback.completionTitle', {
name: `${courseSessionsStore.circleExperts[0].first_name} ${courseSessionsStore.circleExperts[0].last_name}`,
})
"
:description="$t('feedback.completionDescription')"
:feedback-sent="mutationResult != null"
@send-feedback="sendFeedback"
/>
</div>
</LearningContentMultiLayout>
<!--
<pre>
satisfaction {{ satisfaction }}
goalAttainment {{ goalAttainment }}
proficiency {{ proficiency }}
receivedMaterials {{ receivedMaterials }}
materialsRating {{ materialsRating }}
instructorCompetence {{ instructorCompetence }}
instructorRespect {{ instructorRespect }}
instructorOpenFeedback {{ instructorOpenFeedback }}
wouldRecommend {{ wouldRecommend }}
coursePositiveFeedback {{ coursePositiveFeedback }}
courseNegativeFeedback {{ courseNegativeFeedback }}
mutationResult: {{ mutationResult }}
</pre> -->
</template>
<script setup lang="ts"> <script setup lang="ts">
import ItRadioGroup from "@/components/ui/ItRadioGroup.vue"; import ItRadioGroup from "@/components/ui/ItRadioGroup.vue";
import ItTextarea from "@/components/ui/ItTextarea.vue"; import ItTextarea from "@/components/ui/ItTextarea.vue";
@ -117,6 +14,7 @@ import { useCircleStore } from "@/stores/circle";
import { useCourseSessionsStore } from "@/stores/courseSessions"; import { useCourseSessionsStore } from "@/stores/courseSessions";
import type { LearningContent } from "@/types"; import type { LearningContent } from "@/types";
import { useMutation } from "@urql/vue"; import { useMutation } from "@urql/vue";
import { useRouteQuery } from "@vueuse/router";
import log from "loglevel"; import log from "loglevel";
import { computed, onMounted, reactive, ref } from "vue"; import { computed, onMounted, reactive, ref } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
@ -130,7 +28,7 @@ onMounted(async () => {
log.debug("Feedback mounted"); log.debug("Feedback mounted");
}); });
const stepNo = ref(0); const stepNo = useRouteQuery("step", "0", { transform: Number, mode: "push" });
const title = computed( const title = computed(
() => `«${circleStore.circle?.title}»: ${t("feedback.areYouSatisfied")}` () => `«${circleStore.circle?.title}»: ${t("feedback.areYouSatisfied")}`
@ -229,3 +127,107 @@ const sendFeedback = () => {
.catch((e) => log.error(e)); .catch((e) => log.error(e));
}; };
</script> </script>
<template>
<LearningContentMultiLayout
:title="title"
subtitle="Feedback"
:learning-content-type="'feedback'"
:show-start-button="stepNo === 0"
:show-next-button="stepNo > 0 && stepNo + 1 < numSteps"
:show-previous-button="stepNo > 0"
:show-exit-button="stepNo + 1 === numSteps"
:current-step="stepNo"
:steps-count="numSteps"
:start-badge-text="$t('general.introduction')"
:end-badge-text="$t('general.submission')"
:base-url="props.page.frontend_url"
@previous="previousStep()"
@next="nextStep()"
>
<div>
<p v-if="stepNo === 0" class="mt-10">
{{
$t("feedback.intro", {
name: `${courseSessionsStore.circleExperts[0].first_name} ${courseSessionsStore.circleExperts[0].last_name}`,
})
}}
</p>
<p v-if="stepNo > 0 && stepNo + 1 < numSteps" class="pb-2">
{{ stepLabels[stepNo] }}
</p>
<ItRadioGroup
v-if="stepNo === 1"
v-model="satisfaction"
class="mb-8"
:items="RATINGS"
/>
<ItRadioGroup
v-if="stepNo === 2"
v-model="goalAttainment"
class="mb-8"
:items="RATINGS"
/>
<ItRadioGroup
v-if="stepNo === 3"
v-model="proficiency"
class="mb-8"
:items="PERCENTAGES"
/>
<ItRadioGroup
v-if="stepNo === 4"
v-model="preparationTaskClarity"
class="mb-8"
:items="YES_NO"
/>
<ItRadioGroup
v-if="stepNo === 5"
v-model="instructorCompetence"
class="mb-8"
:items="RATINGS"
/>
<ItRadioGroup
v-if="stepNo === 6"
v-model="instructorRespect"
class="mb-8"
:items="RATINGS"
/>
<ItTextarea v-if="stepNo === 7" v-model="instructorOpenFeedback" class="mb-8" />
<ItRadioGroup
v-if="stepNo === 8"
v-model="wouldRecommend"
class="mb-8"
:items="YES_NO"
/>
<ItTextarea v-if="stepNo === 9" v-model="courseNegativeFeedback" class="mb-8" />
<ItTextarea v-if="stepNo === 10" v-model="coursePositiveFeedback" class="mb-8" />
<FeedbackCompletition
v-if="stepNo === 11"
:avatar-url="courseSessionsStore.circleExperts[0].avatar_url"
:title="
$t('feedback.completionTitle', {
name: `${courseSessionsStore.circleExperts[0].first_name} ${courseSessionsStore.circleExperts[0].last_name}`,
})
"
:description="$t('feedback.completionDescription')"
:feedback-sent="mutationResult != null"
@send-feedback="sendFeedback"
/>
</div>
</LearningContentMultiLayout>
<!--
<pre>
satisfaction {{ satisfaction }}
goalAttainment {{ goalAttainment }}
proficiency {{ proficiency }}
receivedMaterials {{ receivedMaterials }}
materialsRating {{ materialsRating }}
instructorCompetence {{ instructorCompetence }}
instructorRespect {{ instructorRespect }}
instructorOpenFeedback {{ instructorOpenFeedback }}
wouldRecommend {{ wouldRecommend }}
coursePositiveFeedback {{ coursePositiveFeedback }}
courseNegativeFeedback {{ courseNegativeFeedback }}
mutationResult: {{ mutationResult }}
</pre> -->
</template>

View File

@ -9,14 +9,14 @@ export interface Props {
startBadgeText?: string; startBadgeText?: string;
endBadgeText?: string; endBadgeText?: string;
baseUrl?: string; baseUrl?: string;
queryParam?: string; stepQueryParam?: string;
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
startBadgeText: undefined, startBadgeText: undefined,
endBadgeText: undefined, endBadgeText: undefined,
baseUrl: undefined, baseUrl: undefined,
queryParam: "page", stepQueryParam: "step",
}); });
const hasStartBadge = computed(() => typeof props.startBadgeText !== "undefined"); const hasStartBadge = computed(() => typeof props.startBadgeText !== "undefined");
@ -67,7 +67,10 @@ function calcStepIndex(step: number) {
:class="startBadgeClasses" :class="startBadgeClasses"
data-cy="nav-progress-step-start" data-cy="nav-progress-step-start"
> >
<router-link v-if="props.baseUrl" :to="`${props.baseUrl}?${props.queryParam}=0`"> <router-link
v-if="props.baseUrl"
:to="`${props.baseUrl}?${props.stepQueryParam}=0`"
>
{{ props.startBadgeText }} {{ props.startBadgeText }}
</router-link> </router-link>
<span v-else>{{ props.startBadgeText }}</span> <span v-else>{{ props.startBadgeText }}</span>
@ -84,7 +87,7 @@ function calcStepIndex(step: number) {
> >
<router-link <router-link
v-if="props.baseUrl" v-if="props.baseUrl"
:to="`${props.baseUrl}?${props.queryParam}=${calcStepIndex(step)}`" :to="`${props.baseUrl}?${props.stepQueryParam}=${calcStepIndex(step)}`"
> >
{{ step + 1 }} {{ step + 1 }}
</router-link> </router-link>
@ -100,7 +103,7 @@ function calcStepIndex(step: number) {
> >
<router-link <router-link
v-if="props.baseUrl" v-if="props.baseUrl"
:to="`${props.baseUrl}?${props.queryParam}=${steps - 1}`" :to="`${props.baseUrl}?${props.stepQueryParam}=${steps - 1}`"
> >
{{ props.endBadgeText }} {{ props.endBadgeText }}
</router-link> </router-link>

View File

@ -41,7 +41,7 @@ const props = defineProps<{
}>(); }>();
// 0 = introduction, 1 - n = tasks, n+1 = submission // 0 = introduction, 1 - n = tasks, n+1 = submission
const pageIndex = useRouteQuery("page", "0", { transform: Number, mode: "push" }); const stepIndex = useRouteQuery("step", "0", { transform: Number, mode: "push" });
const assignmentCompletion = computed(() => assignmentStore.assignmentCompletion); const assignmentCompletion = computed(() => assignmentStore.assignmentCompletion);
const completionStatus = computed(() => { const completionStatus = computed(() => {
@ -64,10 +64,10 @@ onMounted(async () => {
); );
if ( if (
pageIndex.value === 0 && stepIndex.value === 0 &&
(completionStatus.value ?? "in_progress") !== "in_progress" (completionStatus.value ?? "in_progress") !== "in_progress"
) { ) {
pageIndex.value = numPages.value - 1; stepIndex.value = numPages.value - 1;
} }
} catch (error) { } catch (error) {
log.error(error); log.error(error);
@ -76,9 +76,9 @@ onMounted(async () => {
const numTasks = computed(() => state.assignment?.tasks?.length ?? 0); const numTasks = computed(() => state.assignment?.tasks?.length ?? 0);
const numPages = computed(() => numTasks.value + 2); const numPages = computed(() => numTasks.value + 2);
const showPreviousButton = computed(() => pageIndex.value != 0); const showPreviousButton = computed(() => stepIndex.value != 0);
const showNextButton = computed(() => pageIndex.value + 1 < numPages.value); const showNextButton = computed(() => stepIndex.value + 1 < numPages.value);
const showExitButton = computed(() => numPages.value === pageIndex.value + 1); const showExitButton = computed(() => numPages.value === stepIndex.value + 1);
const dueDate = computed(() => const dueDate = computed(() =>
dayjs(state.courseSessionAssignmentDetails?.submissionDeadlineDateTimeUtc) dayjs(state.courseSessionAssignmentDetails?.submissionDeadlineDateTimeUtc)
); );
@ -86,41 +86,41 @@ const courseSessionId = computed(
() => courseSessionsStore.currentCourseSession?.id ?? 0 () => courseSessionsStore.currentCourseSession?.id ?? 0
); );
const currentTask = computed(() => { const currentTask = computed(() => {
if (pageIndex.value > 0 && pageIndex.value <= numTasks.value) { if (stepIndex.value > 0 && stepIndex.value <= numTasks.value) {
return state.assignment?.tasks[pageIndex.value - 1]; return state.assignment?.tasks[stepIndex.value - 1];
} }
return undefined; return undefined;
}); });
const handleBack = () => { const handleBack = () => {
log.debug("handleBack"); log.debug("handleBack");
if (pageIndex.value > 0) { if (stepIndex.value > 0) {
pageIndex.value -= 1; stepIndex.value -= 1;
} }
log.debug(`pageIndex: ${pageIndex.value}`); log.debug(`pageIndex: ${stepIndex.value}`);
}; };
const handleContinue = () => { const handleContinue = () => {
log.debug("handleContinue"); log.debug("handleContinue");
if (pageIndex.value + 1 < numPages.value) { if (stepIndex.value + 1 < numPages.value) {
pageIndex.value += 1; stepIndex.value += 1;
} }
log.debug(`pageIndex: ${pageIndex.value}`); log.debug(`pageIndex: ${stepIndex.value}`);
}; };
const jumpToTask = (task: AssignmentTask) => { const jumpToTask = (task: AssignmentTask) => {
log.debug("jumpToTask", task); log.debug("jumpToTask", task);
const index = state.assignment?.tasks.findIndex((t) => t.id === task.id); const index = state.assignment?.tasks.findIndex((t) => t.id === task.id);
if (index && index >= 0) { if (index && index >= 0) {
pageIndex.value = index + 1; stepIndex.value = index + 1;
} }
log.debug(`pageIndex: ${pageIndex.value}`); log.debug(`pageIndex: ${stepIndex.value}`);
}; };
const getTitle = () => { const getTitle = () => {
if (0 === pageIndex.value) { if (0 === stepIndex.value) {
return t("general.introduction"); return t("general.introduction");
} else if (pageIndex.value === numPages.value - 1) { } else if (stepIndex.value === numPages.value - 1) {
return t("general.submission"); return t("general.submission");
} }
return currentTask?.value?.value.title ?? "Unknown"; return currentTask?.value?.value.title ?? "Unknown";
@ -137,7 +137,7 @@ const assignmentUser = computed(() => {
<div v-if="state.assignment"> <div v-if="state.assignment">
<div class="flex"> <div class="flex">
<LearningContentMultiLayout <LearningContentMultiLayout
:current-step="pageIndex" :current-step="stepIndex"
:subtitle="state.assignment?.title ?? ''" :subtitle="state.assignment?.title ?? ''"
:title="getTitle()" :title="getTitle()"
learning-content-type="assignment" learning-content-type="assignment"
@ -147,7 +147,7 @@ const assignmentUser = computed(() => {
:show-start-button="false" :show-start-button="false"
:show-previous-button="showPreviousButton" :show-previous-button="showPreviousButton"
:base-url="props.learningContent.frontend_url" :base-url="props.learningContent.frontend_url"
query-param="page" step-query-param="step"
start-badge-text="Einleitung" start-badge-text="Einleitung"
end-badge-text="Abgabe" end-badge-text="Abgabe"
close-button-variant="close" close-button-variant="close"
@ -157,7 +157,7 @@ const assignmentUser = computed(() => {
<div class="flex"> <div class="flex">
<div> <div>
<AssignmentIntroductionView <AssignmentIntroductionView
v-if="pageIndex === 0 && state.assignment" v-if="stepIndex === 0 && state.assignment"
:due-date="dueDate" :due-date="dueDate"
:assignment="state.assignment!" :assignment="state.assignment!"
></AssignmentIntroductionView> ></AssignmentIntroductionView>
@ -167,7 +167,7 @@ const assignmentUser = computed(() => {
:assignment-id="props.assignmentId" :assignment-id="props.assignmentId"
></AssignmentTaskView> ></AssignmentTaskView>
<AssignmentSubmissionView <AssignmentSubmissionView
v-if="pageIndex + 1 === numPages && state.assignment && courseSessionId" v-if="stepIndex + 1 === numPages && state.assignment && courseSessionId"
:due-date="dueDate" :due-date="dueDate"
:assignment="state.assignment!" :assignment="state.assignment!"
:assignment-completion-data="assignmentCompletion?.completion_data ?? {}" :assignment-completion-data="assignmentCompletion?.completion_data ?? {}"

View File

@ -20,7 +20,7 @@ interface Props {
endBadgeText?: string; endBadgeText?: string;
closeButtonVariant?: ClosingButtonVariant; closeButtonVariant?: ClosingButtonVariant;
baseUrl?: string; baseUrl?: string;
queryParam?: string; stepQueryParam?: string;
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
@ -58,7 +58,7 @@ const emit = defineEmits(["previous", "next", "exit"]);
:steps="stepsCount" :steps="stepsCount"
:end-badge-text="props.endBadgeText" :end-badge-text="props.endBadgeText"
:base-url="props.baseUrl" :base-url="props.baseUrl"
:query-param="props.queryParam" :query-param="props.stepQueryParam"
class="overflow-hidden pb-12" class="overflow-hidden pb-12"
></ItNavigationProgress> ></ItNavigationProgress>
<slot></slot> <slot></slot>