Add onboarding visited flag to user

This commit is contained in:
Ramon Wenger 2020-07-07 22:31:25 +02:00
parent 5778f98448
commit f588abee43
10 changed files with 127 additions and 15 deletions

View File

@ -5,5 +5,6 @@ query MeQuery {
...UserParts ...UserParts
isTeacher isTeacher
permissions permissions
onboardingVisited
} }
} }

View File

@ -0,0 +1,5 @@
mutation UpdateOnboardingProgress {
updateOnboardingProgress {
success
}
}

View File

@ -127,6 +127,12 @@ function redirectStudentsWithoutClass() {
}).then(({data}) => data.me.schoolClasses.edges.length === 0 && data.me.permissions.length === 0); }).then(({data}) => data.me.schoolClasses.edges.length === 0 && data.me.permissions.length === 0);
} }
function redirectUsersToOnboarding(to) {
return privateApolloClient.query({
query: ME_QUERY,
}).then(({data}) => !data.me.onboardingVisited);
}
function networkErrorCallback(statusCode) { function networkErrorCallback(statusCode) {
if (statusCode === 402) { if (statusCode === 402) {
router.push({name: 'licenseActivation'}, 0); router.push({name: 'licenseActivation'}, 0);
@ -156,6 +162,11 @@ router.beforeEach(async (to, from, next) => {
return return
} }
if ((to.name.indexOf('onboarding') === -1) && await redirectUsersToOnboarding()) {
next({name: 'onboarding-start'})
return
}
next(); next();
}); });

View File

@ -1,17 +1,17 @@
<template> <template>
<div :class="['onboarding', {'onboarding--illustration': illustration}]" > <div :class="['onboarding', {'onboarding--illustration': illustration}]">
<div class="onboarding__illustration"> <div class="onboarding__illustration">
<component :is="illustration" /> <component :is="illustration"/>
</div> </div>
<div class="onboarding__content"> <div class="onboarding__content">
<router-view/> <router-view/>
<router-link <a
:to="next" class="onboarding__button button button--primary button--big"
class="onboarding__button button button--primary button--big">{{ nextLabel }} @click="next">{{ nextLabel }}
</router-link> </a>
<router-link <a
:to="{name:'home'}" class="onboarding__secondary-link"
class="onboarding__secondary-link">Einführung überspringen</router-link> @click.prevent="completeOnboarding">Einführung überspringen</a>
</div> </div>
</div> </div>
</template> </template>
@ -21,6 +21,9 @@
import PortfolioIllustration from '@/components/illustrations/PortfolioIllustration'; import PortfolioIllustration from '@/components/illustrations/PortfolioIllustration';
import RoomsIllustration from '@/components/illustrations/RoomsIllustration'; import RoomsIllustration from '@/components/illustrations/RoomsIllustration';
import UPDATE_ONBOARDING_PROGRESS from '@/graphql/gql/mutations/updateOnboardingProgress.gql';
import ME_QUERY from '@/graphql/gql/meQuery';
export default { export default {
components: { components: {
contents: ContentsIllustration, contents: ContentsIllustration,
@ -29,17 +32,37 @@
}, },
computed: { computed: {
next() {
return {
name: this.$route.meta.next
}
},
nextLabel() { nextLabel() {
return this.$route.name === 'onboarding-start' ? 'Einführung starten' : 'Weiter' return this.$route.name === 'onboarding-start' ? 'Einführung starten' : 'Weiter'
}, },
illustration() { illustration() {
return this.$route.meta.illustration return this.$route.meta.illustration
} }
},
methods: {
next() {
const next = this.$route.meta.next;
if (next === 'home') {
this.completeOnboarding();
}
this.$router.push({name: next});
},
completeOnboarding() {
const router = this.$router;
this.$apollo.mutate({
mutation: UPDATE_ONBOARDING_PROGRESS,
update(store, {data: {updateOnboardingProgress: {success}}}) {
const query = ME_QUERY;
const data = store.readQuery({query});
if (data) {
data.me.onboardingVisited = success;
store.writeQuery({query, data})
}
router.push({name: 'home'});
}
});
}
} }
} }
</script> </script>
@ -142,10 +165,12 @@
box-sizing: border-box; box-sizing: border-box;
justify-content: center; justify-content: center;
margin-bottom: $large-spacing; margin-bottom: $large-spacing;
cursor: pointer;
} }
&__secondary-link { &__secondary-link {
@include inline-title; @include inline-title;
cursor: pointer;
@include desktop { @include desktop {
margin-top: auto; margin-top: auto;

View File

@ -40,6 +40,15 @@
class="button">Alle News anzeigen class="button">Alle News anzeigen
</router-link> </router-link>
</div> </div>
<div class="start-page__onboarding">
<h2 class="start-page__heading">Kennen Sie schon alle Bereiche von mySkillbox?</h2>
<p class="start-page__paragraph">Schauen Sie sich jetzt die Einführung zu mySkillbox an.</p>
<router-link
:to="{name: 'onboarding-start'}"
class="button button--primary">Los geht's
</router-link>
</div>
</div> </div>
</div> </div>
@ -130,6 +139,11 @@
@include meta-title; @include meta-title;
} }
&__paragraph {
@include regular-text;
margin-bottom: $large-spacing;
}
&__content { &__content {
padding-top: 2*$large-spacing; padding-top: 2*$large-spacing;
box-sizing: border-box; box-sizing: border-box;

View File

@ -0,0 +1,23 @@
# Generated by Django 2.2.12 on 2020-07-07 15:01
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('books', '0022_recentmodule'),
]
operations = [
migrations.AlterModelOptions(
name='recentmodule',
options={'get_latest_by': 'visited'},
),
migrations.AlterField(
model_name='recentmodule',
name='module',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='recent_modules', to='books.Module'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.12 on 2020-07-07 15:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0020_user_recent_modules'),
]
operations = [
migrations.AddField(
model_name='user',
name='onboarding_visited',
field=models.BooleanField(default=False),
),
]

View File

@ -24,6 +24,7 @@ class User(AbstractUser):
hep_id = models.PositiveIntegerField(null=True, blank=False) hep_id = models.PositiveIntegerField(null=True, blank=False)
hep_group_id = models.PositiveIntegerField(null=True, blank=False) hep_group_id = models.PositiveIntegerField(null=True, blank=False)
license_expiry_date = models.DateField(blank=False, null=True, default=None) license_expiry_date = models.DateField(blank=False, null=True, default=None)
onboarding_visited = models.BooleanField(default=False)
objects = UserManager() objects = UserManager()

View File

@ -209,6 +209,19 @@ class CreateSchoolClass(relay.ClientIDMutation):
return cls(success=True, school_class=school_class) return cls(success=True, school_class=school_class)
class UpdateOnboardingProgress(graphene.Mutation):
success = graphene.Boolean()
@classmethod
def mutate(cls, root, info, **kwargs):
user = info.context.user
if not user.onboarding_visited:
user.onboarding_visited = True
user.save()
return cls(success=True)
class ProfileMutations: class ProfileMutations:
update_password = UpdatePassword.Field() update_password = UpdatePassword.Field()
update_avatar = UpdateAvatar.Field() update_avatar = UpdateAvatar.Field()
@ -217,3 +230,4 @@ class ProfileMutations:
add_remove_member = AddRemoveMember.Field() add_remove_member = AddRemoveMember.Field()
update_school_class = UpdateSchoolClass.Field() update_school_class = UpdateSchoolClass.Field()
create_school_class = CreateSchoolClass.Field() create_school_class = CreateSchoolClass.Field()
update_onboarding_progress = UpdateOnboardingProgress.Field()

View File

@ -66,7 +66,7 @@ class UserNode(DjangoObjectType):
filter_fields = ['username', 'email'] filter_fields = ['username', 'email']
only_fields = ['username', 'email', 'first_name', 'last_name', 'school_classes', 'last_module', only_fields = ['username', 'email', 'first_name', 'last_name', 'school_classes', 'last_module',
'last_topic', 'avatar_url', 'last_topic', 'avatar_url',
'selected_class', 'expiry_date'] 'selected_class', 'expiry_date', 'onboarding_visited']
interfaces = (relay.Node,) interfaces = (relay.Node,)
def resolve_pk(self, info, **kwargs): def resolve_pk(self, info, **kwargs):