feat: onboarding course type

This commit is contained in:
Reto Aebersold 2023-11-09 17:04:24 +01:00 committed by Christian Cueni
parent 4ac735c3be
commit 607789d599
10 changed files with 255 additions and 45 deletions

View File

@ -4,14 +4,15 @@ import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/vue";
import type { AvailableLanguages } from "@/stores/user";
import { useUserStore } from "@/stores/user";
const props = defineProps({
courseName: String,
});
const props = defineProps<{
courseName: string;
imageUrl: string;
}>();
const userStore = useUserStore();
async function changeLocale(language: AvailableLanguages) {
userStore.setUserLanguages(language);
await userStore.setUserLanguages(language);
}
</script>
<template>
@ -70,12 +71,9 @@ async function changeLocale(language: AvailableLanguages) {
</div>
<div class="max-w-xs text-white">
<img
src="/static/images/mood_uk.jpg"
class="aspect-square rounded-full object-cover"
alt=""
/>
<h3 class="mt-8 text-center">{{ props.courseName }}</h3>
<img :src="imageUrl" class="aspect-square rounded-full object-cover" alt="" />
<!-- eslint-disable vue/no-v-html -->
<h3 class="mt-8 text-center" v-html="props.courseName"></h3>
</div>
<div class="flex items-center gap-x-2 text-sm text-white">

View File

@ -17,7 +17,7 @@ const props = withDefaults(
<div class="relative">
<img
v-if="props?.imageUrl"
class="aspect-square h-[172px] w-[172px] rounded-full object-cover"
class="aspect-square w-[172px] rounded-full object-cover"
:class="{ 'opacity-30': props.loading }"
:src="props.imageUrl"
alt="avatar"

View File

@ -1,14 +1,15 @@
<script setup lang="ts">
import WizardPage from "@/components/onboarding/WizardPage.vue";
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
import { ref, watch } from "vue";
import { computed, ref, watch } from "vue";
import { useUserStore } from "@/stores/user";
import AvatarImage from "@/components/ui/AvatarImage.vue";
import { useFileUpload } from "@/composables";
import { companies } from "@/pages/onboarding/companies";
import { useRoute } from "vue-router";
const user = useUserStore();
const route = useRoute();
const selectedCompany = ref(companies[0]);
const {
@ -25,6 +26,16 @@ watch(avatarFileInfo, (info) => {
watch(selectedCompany, (company) => {
console.log("company changed", company);
});
const nextRoute = computed(() => {
if (route.params.courseType === "uk") {
return "setupComplete";
}
if (route.params.courseType === "vv") {
return "checkoutAddress";
}
return "";
});
</script>
<template>
@ -69,7 +80,7 @@ watch(selectedCompany, (company) => {
</template>
<template #footer>
<router-link :to="{ name: 'setupComplete' }" class="btn-blue flex items-center">
<router-link :to="{ name: nextRoute }" class="btn-blue flex items-center">
Weiter
<it-icon-arrow-right class="it-icon ml-2 h-6 w-6" />
</router-link>

View File

@ -12,12 +12,5 @@ import WizardPage from "@/components/onboarding/WizardPage.vue";
<p class="mb-4 mt-12">Hast du schon ein Konto?</p>
<a href="/sso/login/" class="btn-secondary">Anmelden</a>
</template>
<template #footer>
<button disabled class="btn-blue flex items-center">
Weiter
<it-icon-arrow-right class="it-icon ml-2 h-6 w-6" />
</button>
</template>
</WizardPage>
</template>

View File

@ -0,0 +1,40 @@
<script setup lang="ts">
import WizardSidePanel from "@/components/onboarding/WizardSidePanel.vue";
import { computed } from "vue";
const props = defineProps({
courseType: {
type: String,
required: true,
},
});
type CourseMetaType = {
[key: string]: {
name: string;
imageUrl: string;
};
};
const courseMeta: CourseMetaType = {
uk: {
name: "Überbetriebliche Kurse",
imageUrl: "/static/images/mood_uk.jpg",
},
vv: {
name: "Versicherungs&shy;vermittler/&#8209;in",
imageUrl: "/static/images/mood_vv.jpg",
},
};
const courseData = computed(() => {
return courseMeta[props.courseType];
});
</script>
<template>
<div class="flex flex-col lg:flex-row">
<WizardSidePanel :image-url="courseData.imageUrl" :course-name="courseData.name" />
<router-view />
</div>
</template>

View File

@ -1,10 +0,0 @@
<script setup lang="ts">
import WizardSidePanel from "@/components/onboarding/WizardSidePanel.vue";
</script>
<template>
<div class="flex flex-col lg:flex-row">
<WizardSidePanel course-name="Überbetriebliche Kurse" />
<router-view />
</div>
</template>

View File

@ -0,0 +1,177 @@
<script setup lang="ts">
import WizardPage from "@/components/onboarding/WizardPage.vue";
</script>
<template>
<WizardPage :step="2">
<template #content>
<h2 class="my-10">Lehrgang kaufen</h2>
<p class="mb-4">
Der Preis für diesen Lehrgang beträgt
<b>300 CHF.</b>
Mit dem Kauf erhältst du Zugang auf den gesamten Kurs (inkl. Prüfung).
</p>
<p>Hier kannst du ausschliesslich mit einer Kreditkarte bezahlen.</p>
<h3 class="mb-4 mt-10">Adresse</h3>
<p>
Um die Zahlung vornehmen zu können, benötigen wir deine Privatadresse. Optional
kannst du die Rechnungsadresse deiner Gesellschaft hinzufügen.
</p>
<div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-6 sm:grid-cols-6">
<div class="sm:col-span-3">
<label
for="first-name"
class="block text-sm font-medium leading-6 text-gray-900"
>
Vorname
</label>
<div class="mt-2">
<input
id="first-name"
type="text"
name="first-name"
autocomplete="given-name"
class="block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div class="sm:col-span-3">
<label
for="last-name"
class="block text-sm font-medium leading-6 text-gray-900"
>
Last name
</label>
<div class="mt-2">
<input
id="last-name"
type="text"
name="last-name"
autocomplete="family-name"
class="block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div class="sm:col-span-4">
<label for="email" class="block text-sm font-medium leading-6 text-gray-900">
Email address
</label>
<div class="mt-2">
<input
id="email"
name="email"
type="email"
autocomplete="email"
class="block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div class="sm:col-span-3">
<label
for="country"
class="block text-sm font-medium leading-6 text-gray-900"
>
Country
</label>
<div class="mt-2">
<select
id="country"
name="country"
autocomplete="country-name"
class="block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:max-w-xs sm:text-sm sm:leading-6"
>
<option>United States</option>
<option>Canada</option>
<option>Mexico</option>
</select>
</div>
</div>
<div class="col-span-full">
<label
for="street-address"
class="block text-sm font-medium leading-6 text-gray-900"
>
Street address
</label>
<div class="mt-2">
<input
id="street-address"
type="text"
name="street-address"
autocomplete="street-address"
class="block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div class="sm:col-span-2 sm:col-start-1">
<label for="city" class="block text-sm font-medium leading-6 text-gray-900">
City
</label>
<div class="mt-2">
<input
id="city"
type="text"
name="city"
autocomplete="address-level2"
class="block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div class="sm:col-span-2">
<label for="region" class="block text-sm font-medium leading-6 text-gray-900">
State / Province
</label>
<div class="mt-2">
<input
id="region"
type="text"
name="region"
autocomplete="address-level1"
class="block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6"
/>
</div>
</div>
<div class="sm:col-span-2">
<label
for="postal-code"
class="block text-sm font-medium leading-6 text-gray-900"
>
ZIP / Postal code
</label>
<div class="mt-2">
<input
id="postal-code"
type="text"
name="postal-code"
autocomplete="postal-code"
class="block w-full border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6"
/>
</div>
</div>
</div>
</template>
<template #footer>
<router-link
:to="{ name: 'accountProfile' }"
class="btn-secondary flex items-center"
>
<it-icon-arrow-left class="it-icon mr-2 h-6 w-6" />
Zurück
</router-link>
<router-link to="/" class="btn-blue flex items-center">
Mit Kreditkarte bezahlen
<it-icon-arrow-right class="it-icon ml-2 h-6 w-6" />
</router-link>
</template>
</WizardPage>
</template>

View File

@ -7,7 +7,7 @@ import {
updateLoggedIn,
} from "@/router/guards";
import { addToHistory } from "@/router/history";
import { checkUKProcess } from "@/router/onboarding";
import { onboardingRedirect } from "@/router/onboarding";
import { createRouter, createWebHistory } from "vue-router";
const router = createRouter({
@ -231,39 +231,40 @@ const router = createRouter({
component: () => import("@/pages/AppointmentsPage.vue"),
},
{
path: "/onboarding/uk",
path: "/onboarding/:courseType",
props: true,
component: () => import("@/pages/onboarding/uk/WizardBase.vue"),
component: () => import("@/pages/onboarding/WizardBase.vue"),
meta: {
public: true,
hideChrome: true,
},
beforeEnter: checkUKProcess,
beforeEnter: onboardingRedirect,
children: [
{
path: "account/create",
props: true,
component: () => import("@/pages/onboarding/uk/AccountSetup.vue"),
component: () => import("@/pages/onboarding/AccountSetup.vue"),
name: "accountCreate",
},
{
path: "account/confirm",
props: true,
component: () => import("@/pages/onboarding/uk/AccountConfirm.vue"),
component: () => import("@/pages/onboarding/AccountConfirm.vue"),
name: "accountConfirm",
},
{
path: "account/profile",
props: true,
component: () => import("@/pages/onboarding/uk/AccountProfile.vue"),
component: () => import("@/pages/onboarding/AccountProfile.vue"),
name: "accountProfile",
},
{
path: "account/complete",
props: true,
component: () => import("@/pages/onboarding/uk/SetupComplete.vue"),
name: "setupComplete",
},
{
path: "checkout/address",
component: () => import("@/pages/onboarding/vv/CheckoutAddress.vue"),
name: "checkoutAddress",
},
],
},
{

View File

@ -1,7 +1,7 @@
import { useUserStore } from "@/stores/user";
import type { NavigationGuardNext, RouteLocationNormalized } from "vue-router";
export async function checkUKProcess(
export async function onboardingRedirect(
to: RouteLocationNormalized,
from: RouteLocationNormalized,
next: NavigationGuardNext
@ -11,14 +11,14 @@ export async function checkUKProcess(
// Guest
if (!userStore.loggedIn) {
if (to.name !== "accountCreate") {
return next({ name: "accountCreate" });
return next({ name: "accountCreate", params: to.params });
}
return next();
}
// Logged in
if (to.name === "accountCreate") {
return next({ name: "accountConfirm" });
return next({ name: "accountConfirm", params: to.params });
}
return next();