Add Course Profile selection step to checkout flow

This commit is contained in:
Ramon Wenger 2024-07-18 17:42:07 +02:00 committed by Christian Cueni
parent 493b3197cf
commit ca4ba26005
8 changed files with 130 additions and 5 deletions

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import { computed } from "vue";
import type { LearningContentWithCompletion, LearningPathType } from "@/types";
import { computed } from "vue";
import LearningPathListTopic from "./LearningPathListTopic.vue";
const props = defineProps<{

View File

@ -0,0 +1,94 @@
<script setup lang="ts">
import WizardPage from "@/components/onboarding/WizardPage.vue";
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
import { useEntities, type CourseProfile } from "@/services/entities";
import { profileNextRoute } from "@/services/onboarding";
import { useUserStore } from "@/stores/user";
import { useTranslation } from "i18next-vue";
import { computed, ref, watch } from "vue";
import { useRoute } from "vue-router";
const { t } = useTranslation();
const user = useUserStore();
const route = useRoute();
const { courseProfiles } = useEntities();
const selectedCourseProfile = ref({
id: 0,
name: t("a.Auswählen"),
});
// watch(
// organisations,
// (newOrganisations) => {
// if (newOrganisations) {
// const userOrganisation = newOrganisations.find((c) => c.id === user.organisation);
// if (userOrganisation) {
// selectedOrganisation.value = userOrganisation;
// }
// }
// },
// { immediate: true }
// );
//
const validCourseProfile = computed(() => {
return selectedCourseProfile.value.id !== 0;
});
watch(selectedCourseProfile, async (courseProfile: CourseProfile) => {
user.updateChosenCourseProfile(courseProfile);
});
const nextRoute = computed(() => {
return profileNextRoute(route.params.courseType);
});
const courseProfilesToDropdown = computed(() => {
return courseProfiles.value.map((profile) => ({
...profile,
name: t(`profile.${profile.code}`),
}));
});
</script>
<template>
<WizardPage :step="2">
<template #content>
<h2 class="my-10" data-cy="account-profile-title">
{{ $t("a.Zulassungsprofil auswählen") }}
</h2>
<p class="mb-6 max-w-md hyphens-none">
{{
$t(
"a.Wähle ein Zulassungsprofil, damit du deinen Lehrgang an der richtigen Stelle beginnen kannst. Du kannst ihn später jederzeit ändern."
)
}}
</p>
<pre>{{ courseProfilesToDropdown }}</pre>
<pre>{{ user.chosen_profile }}</pre>
<ItDropdownSelect
v-model="selectedCourseProfile"
:items="courseProfilesToDropdown"
/>
</template>
<template #footer>
<router-link v-slot="{ navigate }" :to="{ name: nextRoute }" custom>
<button
:disabled="!validCourseProfile"
class="btn-blue flex items-center"
role="link"
data-cy="continue-button"
@click="navigate"
>
{{ $t("general.next") }}
<it-icon-arrow-right class="it-icon ml-2 h-6 w-6" />
</button>
</router-link>
</template>
</WizardPage>
</template>

View File

@ -391,6 +391,12 @@ const router = createRouter({
component: () => import("@/pages/onboarding/uk/SetupComplete.vue"),
name: "setupComplete",
},
{
path: "account/course-profile",
component: () => import("@/pages/onboarding/vv/AccountCourseProfile.vue"),
name: "accountCourseProfile",
props: true,
},
{
path: "checkout/address",
component: () => import("@/pages/onboarding/vv/CheckoutAddress.vue"),

View File

@ -13,14 +13,21 @@ export type Country = {
name: string;
};
export type CourseProfile = {
id: number;
code: string;
};
export function useEntities() {
const countries: Ref<Country[]> = ref([]);
const organisations: Ref<Organisation[]> = ref([]);
const courseProfiles: Ref<CourseProfile[]> = ref([]);
itGetCached("/api/core/entities/").then((res: any) => {
countries.value = res.countries;
organisations.value = res.organisations;
courseProfiles.value = res.courseProfiles;
});
return { organisations, countries };
return { organisations, countries, courseProfiles };
}

View File

@ -11,7 +11,7 @@ export function profileNextRoute(courseType: string | string[]) {
}
// vv- -> vv-de, vv-fr or vv-it
if (isString(courseType) && startsWith(courseType, "vv-")) {
return "checkoutAddress";
return "accountCourseProfile";
}
return "";
}

View File

@ -4,6 +4,8 @@ from rest_framework.response import Response
from vbv_lernwelt.core.models import Country, Organisation
from vbv_lernwelt.core.serializers import CountrySerializer, OrganisationSerializer
from vbv_lernwelt.learnpath.models import CourseProfile
from vbv_lernwelt.learnpath.serializers import CourseProfileSerializer
@api_view(["GET"])
@ -26,4 +28,13 @@ def list_entities(request):
countries = CountrySerializer(
Country.objects.all(), many=True, context=context
).data
return Response({"organisations": organisations, "countries": countries})
course_profiles = CourseProfileSerializer(
CourseProfile.objects.all(), many=True, context=context
).data
return Response(
{
"organisations": organisations,
"countries": countries,
"courseProfiles": course_profiles,
}
)

View File

@ -1,4 +1,3 @@
from django.shortcuts import get_object_or_404
from rest_framework.decorators import api_view, permission_classes
from rest_framework.generics import get_object_or_404
from rest_framework.permissions import IsAuthenticated

View File

@ -1,3 +1,4 @@
from rest_framework import serializers
from rest_framework.fields import SerializerMethodField
from vbv_lernwelt.competence.serializers import (
@ -6,6 +7,7 @@ from vbv_lernwelt.competence.serializers import (
from vbv_lernwelt.core.utils import get_django_content_type
from vbv_lernwelt.course.serializer_helpers import get_course_serializer_class
from vbv_lernwelt.learnpath.models import (
CourseProfile,
LearningContentAssignment,
LearningContentEdoniqTest,
LearningUnit,
@ -98,3 +100,9 @@ class LearningContentAssignmentSerializer(
}
except Exception:
return None
class CourseProfileSerializer(serializers.ModelSerializer):
class Meta:
model = CourseProfile
fields = ["id", "code"]