Add Course Profile selection step to checkout flow
This commit is contained in:
parent
493b3197cf
commit
ca4ba26005
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from "vue";
|
|
||||||
import type { LearningContentWithCompletion, LearningPathType } from "@/types";
|
import type { LearningContentWithCompletion, LearningPathType } from "@/types";
|
||||||
|
import { computed } from "vue";
|
||||||
import LearningPathListTopic from "./LearningPathListTopic.vue";
|
import LearningPathListTopic from "./LearningPathListTopic.vue";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -391,6 +391,12 @@ const router = createRouter({
|
||||||
component: () => import("@/pages/onboarding/uk/SetupComplete.vue"),
|
component: () => import("@/pages/onboarding/uk/SetupComplete.vue"),
|
||||||
name: "setupComplete",
|
name: "setupComplete",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "account/course-profile",
|
||||||
|
component: () => import("@/pages/onboarding/vv/AccountCourseProfile.vue"),
|
||||||
|
name: "accountCourseProfile",
|
||||||
|
props: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "checkout/address",
|
path: "checkout/address",
|
||||||
component: () => import("@/pages/onboarding/vv/CheckoutAddress.vue"),
|
component: () => import("@/pages/onboarding/vv/CheckoutAddress.vue"),
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,21 @@ export type Country = {
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CourseProfile = {
|
||||||
|
id: number;
|
||||||
|
code: string;
|
||||||
|
};
|
||||||
|
|
||||||
export function useEntities() {
|
export function useEntities() {
|
||||||
const countries: Ref<Country[]> = ref([]);
|
const countries: Ref<Country[]> = ref([]);
|
||||||
const organisations: Ref<Organisation[]> = ref([]);
|
const organisations: Ref<Organisation[]> = ref([]);
|
||||||
|
const courseProfiles: Ref<CourseProfile[]> = ref([]);
|
||||||
|
|
||||||
itGetCached("/api/core/entities/").then((res: any) => {
|
itGetCached("/api/core/entities/").then((res: any) => {
|
||||||
countries.value = res.countries;
|
countries.value = res.countries;
|
||||||
organisations.value = res.organisations;
|
organisations.value = res.organisations;
|
||||||
|
courseProfiles.value = res.courseProfiles;
|
||||||
});
|
});
|
||||||
|
|
||||||
return { organisations, countries };
|
return { organisations, countries, courseProfiles };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ export function profileNextRoute(courseType: string | string[]) {
|
||||||
}
|
}
|
||||||
// vv- -> vv-de, vv-fr or vv-it
|
// vv- -> vv-de, vv-fr or vv-it
|
||||||
if (isString(courseType) && startsWith(courseType, "vv-")) {
|
if (isString(courseType) && startsWith(courseType, "vv-")) {
|
||||||
return "checkoutAddress";
|
return "accountCourseProfile";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ from rest_framework.response import Response
|
||||||
|
|
||||||
from vbv_lernwelt.core.models import Country, Organisation
|
from vbv_lernwelt.core.models import Country, Organisation
|
||||||
from vbv_lernwelt.core.serializers import CountrySerializer, OrganisationSerializer
|
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"])
|
@api_view(["GET"])
|
||||||
|
|
@ -26,4 +28,13 @@ def list_entities(request):
|
||||||
countries = CountrySerializer(
|
countries = CountrySerializer(
|
||||||
Country.objects.all(), many=True, context=context
|
Country.objects.all(), many=True, context=context
|
||||||
).data
|
).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,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from rest_framework.decorators import api_view, permission_classes
|
from rest_framework.decorators import api_view, permission_classes
|
||||||
from rest_framework.generics import get_object_or_404
|
from rest_framework.generics import get_object_or_404
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
from rest_framework import serializers
|
||||||
from rest_framework.fields import SerializerMethodField
|
from rest_framework.fields import SerializerMethodField
|
||||||
|
|
||||||
from vbv_lernwelt.competence.serializers import (
|
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.core.utils import get_django_content_type
|
||||||
from vbv_lernwelt.course.serializer_helpers import get_course_serializer_class
|
from vbv_lernwelt.course.serializer_helpers import get_course_serializer_class
|
||||||
from vbv_lernwelt.learnpath.models import (
|
from vbv_lernwelt.learnpath.models import (
|
||||||
|
CourseProfile,
|
||||||
LearningContentAssignment,
|
LearningContentAssignment,
|
||||||
LearningContentEdoniqTest,
|
LearningContentEdoniqTest,
|
||||||
LearningUnit,
|
LearningUnit,
|
||||||
|
|
@ -98,3 +100,9 @@ class LearningContentAssignmentSerializer(
|
||||||
}
|
}
|
||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class CourseProfileSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = CourseProfile
|
||||||
|
fields = ["id", "code"]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue