Save last topic and go there on topic navigation

This commit is contained in:
Ramon Wenger 2020-06-16 16:29:41 +02:00
parent a9b3dddd8b
commit c6bdae3fd3
12 changed files with 142 additions and 32 deletions

View File

@ -6,7 +6,7 @@
<div class="content-navigation__item">
<router-link
:class="{'content-navigation__link--active': isActive('book')}"
to="/book/topic/berufliche-grundbildung"
:to="topicRoute"
active-class="content-navigation__link--active"
class="content-navigation__link"
@click.native="close">Themen
@ -73,6 +73,7 @@
import BookTopicNavigation from '@/components/book-navigation/BookTopicNavigation';
import sidebarMixin from '@/mixins/sidebar';
import meMixin from '@/mixins/me';
export default {
props: {
@ -81,13 +82,27 @@
}
},
mixins: [sidebarMixin],
mixins: [sidebarMixin, meMixin],
components: {
BookTopicNavigation,
Logo
},
computed: {
topicRoute() {
if (this.me.lastTopic && this.me.lastTopic.slug) {
return {
name: 'topic',
params: {
topicSlug: this.me.lastTopic.slug
}
}
}
return '/book/topic/berufliche-grundbildung'
}
},
methods: {
isActive(linkName) {
return linkName === 'book' && this.$route.path.indexOf('module') > -1;

View File

@ -0,0 +1,17 @@
#import "./moduleParts.gql"
fragment TopicParts on TopicNode {
id
title
teaser
slug
description
vimeoId
instructions
modules {
edges {
node {
...ModuleParts
}
}
}
}

View File

@ -12,6 +12,10 @@ fragment UserParts on UserNode {
id
slug
}
lastTopic {
id
slug
}
selectedClass {
id
}

View File

@ -0,0 +1,8 @@
#import "../fragments/topicParts.gql"
mutation UpdateLastTopic($input: UpdateLastTopicInput!) {
updateLastTopic(input: $input) {
topic {
...TopicParts
}
}
}

View File

@ -1,18 +1,6 @@
#import "./fragments/moduleParts.gql"
#import "./fragments/topicParts.gql"
query Topic($slug: String!){
topic(slug: $slug) {
id
title
teaser
description
vimeoId
instructions
modules {
edges {
node {
...ModuleParts
}
}
}
...TopicParts
}
}

View File

@ -63,10 +63,13 @@
import PortfolioIllustration from '@/components/illustrations/PortfolioIllustration';
import RoomsIllustration from '@/components/illustrations/RoomsIllustration';
import {meQuery} from '@/graphql/queries';
import MobileHeader from '@/components/MobileHeader';
import meMixin from '@/mixins/me';
export default {
mixins: [meMixin],
components: {
MobileHeader,
HeaderBar,
@ -77,12 +80,6 @@
RoomsIllustration
},
data() {
return {
me: {}
}
},
computed: {
moduleRoute() {
if (this.me.lastModule && this.me.lastModule.slug) {
@ -98,9 +95,6 @@
}
},
apollo: {
me: meQuery
},
}
</script>

View File

@ -45,6 +45,9 @@
import me from '@/mixins/me';
import BookTopicNavigation from '@/components/book-navigation/BookTopicNavigation';
import UPDATE_LAST_TOPIC_MUTATION from '@/graphql/gql/mutations/updateLastTopic.gql';
import ME_QUERY from '@/graphql/gql/meQuery.gql';
export default {
mixins: [me],
@ -64,6 +67,12 @@
},
update(data) {
return this.$getRidOfEdges(data).topic || {};
},
result(r, key) {
if (this.saveMe) {
this.saveMe = false;
this.updateLastVisitedTopic(this.topic.id);
}
}
}
}
@ -75,7 +84,8 @@
modules: {
edges: []
}
}
},
saveMe: false
}
},
@ -85,9 +95,37 @@
}
},
mounted() {
if (!this.topic.id) { // component was loaded before topic, apollo not ready yet
this.saveMe = true; // needs saving, apollo will do this
} else {
this.updateLastVisitedTopic(this.topic.id);
}
},
methods: {
openVideo() {
this.$store.dispatch('showFullscreenVideo', this.topic.vimeoId);
},
updateLastVisitedTopic(topicId) {
this.$apollo.mutate({
mutation: UPDATE_LAST_TOPIC_MUTATION,
variables: {
input: {
id: topicId
}
},
update(store, {data: {updateLastTopic: {topic}}}) {
if (topic) {
let query = ME_QUERY;
const data = store.readQuery({query});
if (data) {
data.me.lastTopic = topic;
store.writeQuery({query, data})
}
}
}
});
}
},
}

View File

@ -1,5 +1,5 @@
from books.schema.mutations.contentblock import MutateContentBlock, AddContentBlock, DeleteContentBlock
from books.schema.mutations.module import UpdateSolutionVisibility, UpdateLastModule
from books.schema.mutations.module import UpdateSolutionVisibility, UpdateLastModule, UpdateLastTopic
class BookMutations(object):
@ -8,3 +8,4 @@ class BookMutations(object):
delete_content_block = DeleteContentBlock.Field()
update_solution_visibility = UpdateSolutionVisibility.Field()
update_last_module = UpdateLastModule.Field()
update_last_topic = UpdateLastTopic.Field()

View File

@ -2,8 +2,8 @@ import graphene
from graphene import relay
from api.utils import get_errors, get_object
from books.models import Module
from books.schema.queries import ModuleNode
from books.models import Module, Topic
from books.schema.queries import ModuleNode, TopicNode
class UpdateSolutionVisibility(relay.ClientIDMutation):
@ -71,3 +71,26 @@ class UpdateLastModule(relay.ClientIDMutation):
except Exception as e:
errors = ['Error: {}'.format(e)]
return cls(errors=errors)
class UpdateLastTopic(relay.ClientIDMutation):
class Input:
# todo: use slug here too
id = graphene.ID()
topic = graphene.Field(TopicNode)
@classmethod
def mutate_and_get_payload(cls, root, info, **args):
user = info.context.user
id = args.get('id')
topic = get_object(Topic, id)
if not topic:
raise Topic.DoesNotExist
user.last_topic = topic
user.save()
return cls(topic=topic)

View File

@ -0,0 +1,20 @@
# Generated by Django 2.1.15 on 2020-06-15 14:24
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('books', '0021_auto_20200525_1447'),
('users', '0017_auto_20200430_1251'),
]
operations = [
migrations.AddField(
model_name='user',
name='last_topic',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='books.Topic'),
),
]

View File

@ -17,6 +17,7 @@ DEFAULT_SCHOOL_ID = 1
class User(AbstractUser):
last_module = models.ForeignKey('books.Module', related_name='+', on_delete=models.SET_NULL, null=True)
last_topic = models.ForeignKey('books.Topic', related_name='+', on_delete=models.SET_NULL, null=True)
avatar_url = models.CharField(max_length=254, blank=True, default='')
email = models.EmailField(_('email address'), unique=True)
hep_id = models.PositiveIntegerField(null=True, blank=False)

View File

@ -50,7 +50,8 @@ class UserNode(DjangoObjectType):
class Meta:
model = User
filter_fields = ['username', 'email']
only_fields = ['username', 'email', 'first_name', 'last_name', 'school_classes', 'last_module', 'avatar_url',
only_fields = ['username', 'email', 'first_name', 'last_name', 'school_classes', 'last_module',
'last_topic', 'avatar_url',
'selected_class', 'expiry_date']
interfaces = (relay.Node,)
@ -64,7 +65,7 @@ class UserNode(DjangoObjectType):
return self.selected_class()
def resolve_expiry_date(self, info):
if not self.hep_id: # concerns users that already have an (old) account
if not self.hep_id: # concerns users that already have an (old) account
return format(datetime(2020, 7, 31), 'U') # just set some expiry date
else:
return self.license_expiry_date