use activity data in frontent

This commit is contained in:
Christian Cueni 2019-04-11 17:00:59 +02:00
parent fa98141f3c
commit 59d88d5143
12 changed files with 183 additions and 56 deletions

View File

@ -1,5 +1,5 @@
<template>
<div :class="{'no-scroll': showModal || showMobileNavigation}" class="app">
<div :class="{'no-scroll': showModal || showMobileNavigation}" class="app" id="app">
<component :is="showModal" v-if="showModal"></component>
<component :is="layout"></component>
<mobile-navigation v-if="showMobileNavigation"></mobile-navigation>

View File

@ -1,5 +1,5 @@
<template>
<router-link to="/me">
<router-link to="/me/activity">
<div class="user-widget" :class="{'user-widget--is-profile': isProfile}">
<user-icon class="user-widget__avatar" :src="avatar"></user-icon>
<span class="user-widget__name">{{firstName}} {{lastName}}</span>

View File

@ -1,6 +1,6 @@
<template>
<div class="assignment">
<h3 class="assignment__title">{{assignment.title}}</h3>
<h3 class="assignment__title" :id="assignment.id.replace(/=/g, '')">{{assignment.title}}</h3>
<p class="assignment__assignment-text">
{{assignment.assignment}}
</p>
@ -67,6 +67,7 @@
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
import ASSIGNMENT_QUERY from '@/graphql/gql/assignmentQuery.gql';
import ME_QUERY from '@/graphql/gql/meQuery.gql';
import UPDATE_ASSIGNMENT_MUTATION from '@/graphql/gql/mutations/updateAssignmentMutation.gql';
@ -92,6 +93,7 @@
},
computed: {
...mapGetters(['scrollToAssignmentId']),
final() {
return !!this.submission && this.submission.final
},
@ -109,6 +111,7 @@
},
methods: {
...mapActions(['scrollToAssignmentReady']),
_save: debounce(function (submission) {
this.saving++;
this.$apollo.mutate({
@ -196,6 +199,9 @@
result({data}) {
this.assignment = cloneDeep(data.assignment);
this.assignment.submission = Object.assign(this.initialSubmission(), this.assignment.submission);
if (this.assignment.id === this.scrollToAssignmentId) {
this.$nextTick(() => this.scrollToAssignmentReady(true));
}
}
},
me: {

View File

@ -1,34 +1,14 @@
<template>
<div class="module-activity">
<h3 class="module-activity__module-name">Geld und Kauf - Modul 9</h3>
<h2 class="module-activity__title">Ökololololologie</h2>
<h3 class="module-activity__module-name">{{moduleTitle}}</h3>
<h2 class="module-activity__title">{{title}}</h2>
<div class="module-activity__tasks activity-tasks">
<h4 class="activity-tasks__title">Aufträge</h4>
<ol class="activity-tasks__task-list task-list">
<li class="task-list__item task-item">
<h5 class="task-item__title">Auftrag x, Begründung</h5>
<p class="task-item__submission">"eine Antwrotasdfasdfasdf"</p>
</li>
<li class="task-list__item task-item">
<h5 class="task-item__title">Auftrag x, Begründung</h5>
<p class="task-item__submission">"eine Antwrotasdfasdfasdf"</p>
</li>
<li class="task-list__item task-item">
<h5 class="task-item__title">Auftrag x, Begründung</h5>
<p class="task-item__submission">"eine Antwrotasdfasdfasdf"</p>
</li>
<li class="task-list__item task-item">
<h5 class="task-item__title">Auftrag x, Begründung</h5>
<p class="task-item__submission">"eine Antwrotasdfasdfasdf"</p>
</li>
</ol>
</div>
<div class="module-activity__tasks activity-tasks">
<h4 class="activity-tasks__title activity-tasks__title--alternative">Basiswissen</h4>
<ol class="activity-tasks__task-list task-list">
<li class="task-list__item task-item">
<h5 class="task-item__title">Auftrag x, Begründung</h5>:
<p class="task-item__submission">"eine Antwrotasdfasdfasdf"</p>
<li v-for="activity in activities" :key="activity.key" class="task-list__item task-item">
<h5 class="task-item__title">{{activity.assignmentTitle}}</h5>
<p class="task-item__submission">{{activity.answer}}</p>
<a href="#" @click="goToAssignment(activity)"><chevron-right class="task-item__chevron"></chevron-right></a>
</li>
</ol>
</div>
@ -37,7 +17,25 @@
<script>
import { mapActions } from 'vuex'
import ChevronRight from '@/components/icons/ChevronRight';
export default {
props: ['metaTitle', 'title', 'activities', 'topic', 'slug'],
components: {ChevronRight},
computed: {
moduleTitle () {
return `${this.topic.title} - ${this.metaTitle}`
}
},
methods: {
...mapActions(['scrollToAssignmentId']),
goToAssignment (activity) {
const url = `/module/${this.slug}/`;
this.scrollToAssignmentId(activity.assignmentId);
this.$router.push(url);
}
}
}
</script>
@ -70,7 +68,9 @@
.task-item {
display: flex;
flex-direction: row;
margin-left: $medium-spacing;
justify-content: space-between;
$line-height: 50px;
&__title {
&::after {
@ -79,9 +79,23 @@
margin-right: $medium-spacing;
}
&__submission {
width: 100%;
}
&__title, &__submission {
line-height: 50px;
height: 50px;
line-height: $line-height;
height: $line-height;
}
&__chevron {
line-height: $line-height;
height: $medium-spacing;
vertical-align: middle;
position: relative;
top: ($line-height - $medium-spacing) / 2;
fill: $color-brand;
width: 30px;
}
}

View File

@ -0,0 +1,23 @@
query {
myActivity {
edges {
node {
id
text
assignment {
id
title
module {
title
metaTitle
slug
id
topic {
title
}
}
}
}
}
}
}

View File

@ -1,37 +1,59 @@
<template>
<div class="activity">
<h1 class="activity__header">Meine Aktivität</h1>
<module-activity class="activity"></module-activity>
<module-activity class="activity"></module-activity>
<module-activity class="activity"></module-activity>
<div class="modules">
<module-activity v-for="moduleId in Object.keys(modules)" v-bind="modules[moduleId]" :key="moduleId" class="activity"></module-activity>
</div>
</div>
</template>
<script>
import ModuleActivity from '@/components/profile/ModuleActivity';
import MY_ACTIVITY_QUERY from '@/graphql/gql/myActivity.gql'
export default {
components: {
ModuleActivity
},
// apollo: {
// schoolClasses: {
// query: MY_SCHOOL_CLASSES_QUERY,
// update(data) {
// return this.$getRidOfEdges(data).me.schoolClasses
// }
// }
// },
apollo: {
submissions: {
query: MY_ACTIVITY_QUERY,
update(data) {
return this.$getRidOfEdges(data).myActivity;
}
}
},
data() {
return {
activities: []
submissions: []
}
},
methods: {
computed: {
modules () {
let modules = {};
this.submissions.map((submission) => {
let activity = {
assignmentId: submission.assignment.id,
assignmentTitle: submission.assignment.title,
answer: submission.text
};
const module = submission.assignment.module
if (!(module.id in modules)) {
modules[module.id] = {
...module,
activities: []
}
}
modules[module.id].activities = [...modules[module.id].activities, activity];
});
return modules
}
}
}
</script>

View File

@ -3,6 +3,7 @@
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import ASSIGNMENTS_QUERY from '@/graphql/gql/assignmentsQuery.gql';
import {moduleQuery} from '@/graphql/queries';
@ -13,18 +14,60 @@
Module
},
methods: {
...mapActions(['scrollToAssignmentReady']),
},
computed: {
...mapGetters(['scrollToAssignmentId']),
},
apollo: {
module: moduleQuery,
assignments: {
query: ASSIGNMENTS_QUERY
assignments() {
return {
query: ASSIGNMENTS_QUERY
}
}
},
data() {
return {
module: {},
assignments: []
assignments: [],
isScrolling: false
}
},
mounted () {
this.$store.subscribe((mutation, state) => {
if (mutation.type === 'setScrollToAssignmentReady' && state.scrollToAssignmentReady && !this.isScrolling) {
this.isScrolling = true;
// this.$nextTick(() => {
let options = {
container: '#app',
easing: 'ease-in',
offset: -60,
force: true,
cancelable: true,
onStart: (element) => {
},
onDone: (element) => {
this.scrollToAssignmentReady(false);
this.isScrolling = false;
},
onCancel: function() {
// scrolling has been interrupted
},
x: false,
y: true
};
this.$scrollTo(`#${this.scrollToAssignmentId.replace(/=/g, '')}`, 1000, options);
// })
}
})
},
beforeDestroy () {
this.scrollToAssignmentReady(false);
}
}
</script>

View File

@ -79,15 +79,12 @@ const routes = [
},
{
path: '/me',
name: 'profile',
component: profilePage,
meta: {
isProfile: true
},
children: [
{path: 'password-change', name: 'pw-change', component: passwordChange, meta: {isProfile: true}},
{path: 'myclasses', name: 'my-classes', component: myClasses, meta: {isProfile: true}},
{path: 'activity', name: 'activity', component: activity, meta: {isProfile: true}},
{path: '', name: 'profile-activity', component: activity, meta: {isProfile: true}},
]
},
{path: '*', component: p404}

View File

@ -25,7 +25,9 @@ export default new Vuex.Store({
id: 0,
type: ''
},
vimeoId: null
vimeoId: null,
scrollToAssignmentId: '',
scrollToAssignmentReady: false
},
getters: {
@ -34,7 +36,9 @@ export default new Vuex.Store({
},
showMobileNavigation: state => {
return state.showMobileNavigation
}
},
scrollToAssignmentId: state => state.scrollToAssignmentId,
scrollToAssignmentReady: state => state.scrollToAssignmentReady,
},
actions: {
@ -118,6 +122,12 @@ export default new Vuex.Store({
},
showMobileNavigation({commit}, payload) {
commit('setShowMobileNavigation', payload);
},
scrollToAssignmentId({commit}, payload) {
commit('setScrollToAssignmentId', payload);
},
scrollToAssignmentReady({commit}, payload) {
commit('setScrollToAssignmentReady', payload);
}
},
@ -172,6 +182,12 @@ export default new Vuex.Store({
},
setShowMobileNavigation(state, payload) {
state.showMobileNavigation = payload;
},
setScrollToAssignmentId(state, payload) {
state.scrollToAssignmentId = payload;
},
setScrollToAssignmentReady(state, payload) {
state.scrollToAssignmentReady = payload;
}
}
})

View File

@ -15,7 +15,6 @@ class StudentSubmissionQuery(object):
class MyActivityQuery(object):
# my_activity = relay.Node.Field(StudentSubmissionNode)
my_activity = DjangoFilterConnectionField(StudentSubmissionNode)
def resolve_my_activity(self, info, **kwargs):

View File

@ -43,8 +43,10 @@ class MyAssignemntsText(DefaultUserTestCase):
myActivity {
edges {
node {
id
text
assignment {
id
title
}
}

View File

@ -67,13 +67,14 @@ class ChapterNode(DjangoObjectType):
class ModuleNode(DjangoObjectType):
pk = graphene.Int()
chapters = DjangoFilterConnectionField(ChapterNode)
topic = graphene.Field('books.schema.queries.TopicNode')
hero_image = graphene.String()
solutions_enabled = graphene.Boolean()
class Meta:
model = Module
only_fields = [
'slug', 'title', 'meta_title', 'teaser', 'intro', 'objective_groups', 'assignments', 'hero_image'
'slug', 'title', 'meta_title', 'teaser', 'intro', 'objective_groups', 'assignments', 'hero_image', 'topic'
]
filter_fields = {
'slug': ['exact', 'icontains', 'in'],
@ -91,6 +92,10 @@ class ModuleNode(DjangoObjectType):
def resolve_chapters(self, info, **kwargs):
return Chapter.get_by_parent(self)
def resolve_topic(self, info, **kwargs):
some = self.get_parent().specific
return self.get_parent().specific
def resolve_solutions_enabled(self, info, **kwargs):
return self.solutions_enabled_by.filter(pk=info.context.user.pk).exists()