skillbox/client/src/components/Chapter.vue

223 lines
5.3 KiB
Vue

<template>
<div
:data-scrollto="chapter.id"
class="chapter"
>
<div
:class="{'hideable-element--greyed-out': titleGreyedOut}"
class="hideable-element"
v-if="!titleHidden"
>
<h3
:id="'chapter-' + index"
>
{{ chapter.title }}
</h3>
</div>
<visibility-action
:block="chapter"
type="chapter-title"
v-if="editModule"
/>
<bookmark-actions
:bookmarked="chapter.bookmark"
:note="note"
class="chapter__bookmark-actions"
@add-note="addNote"
@edit-note="editNote"
@bookmark="bookmark(!chapter.bookmark)"
/>
<div
:class="{'hideable-element--greyed-out': descriptionGreyedOut}"
class="chapter__intro intro hideable-element"
v-if="!descriptionHidden"
>
<visibility-action
:block="chapter"
:chapter="true"
type="chapter-description"
v-if="editModule"
/>
<p
class="chapter__description"
>
{{ chapter.description }}
</p>
</div>
<add-content-button
:parent="chapter"
v-if="editModule"
/>
<content-block
:content-block="contentBlock"
:parent="chapter.id"
v-for="contentBlock in filteredContentBlocks"
:key="contentBlock.id"
/>
</div>
</template>
<script>
import ContentBlock from '@/components/ContentBlock';
import AddContentButton from '@/components/AddContentButton';
import BookmarkActions from '@/components/notes/BookmarkActions';
import VisibilityAction from '@/components/visibility/VisibilityAction';
import {mapState} from 'vuex';
import {hidden} from '@/helpers/visibility';
import {CHAPTER_DESCRIPTION_TYPE, CHAPTER_TITLE_TYPE, CONTENT_TYPE} from '@/consts/types';
import UPDATE_CHAPTER_BOOKMARK_MUTATION from '@/graphql/gql/mutations/updateChapterBookmark.gql';
import CHAPTER_QUERY from '@/graphql/gql/queries/chapterQuery.gql';
import me from '@/mixins/me';
export default {
props: ['chapter', 'index'],
mixins: [me],
components: {
BookmarkActions,
VisibilityAction,
ContentBlock,
AddContentButton,
},
computed: {
...mapState(['editModule']),
filteredContentBlocks() {
if (!(this.chapter && this.chapter.contentBlocks)) {
return [];
}
if (this.editModule) {
return this.chapter.contentBlocks;
}
return this.chapter.contentBlocks.filter(contentBlock => !hidden({
block: contentBlock,
schoolClass: this.schoolClass,
type: CONTENT_TYPE,
}));
},
note() {
if (this.chapter && this.chapter.bookmark) {
return this.chapter.bookmark.note;
}
return false;
},
titleGreyedOut() {
return this.textHidden(CHAPTER_TITLE_TYPE) && this.editModule;
},
// never hidden when editing the module
titleHidden() {
if (this.chapter.titleHidden === true) {
return true;
}
return this.textHidden(CHAPTER_TITLE_TYPE) && !this.editModule;
},
descriptionGreyedOut() {
return this.textHidden(CHAPTER_DESCRIPTION_TYPE) && this.editModule;
},
// never hidden when editing the module
descriptionHidden() {
if (this.chapter.descriptionHidden === true) {
return true;
}
return this.textHidden(CHAPTER_DESCRIPTION_TYPE) && !this.editModule;
},
},
methods: {
bookmark(bookmarked) {
const id = this.chapter.id;
this.$apollo.mutate({
mutation: UPDATE_CHAPTER_BOOKMARK_MUTATION,
variables: {
input: {
chapter: id,
bookmarked,
},
},
update: (store) => {
const query = CHAPTER_QUERY;
const variables = {id};
const data = store.readQuery({
query,
variables,
});
const chapter = data.chapter;
if (bookmarked) {
chapter.bookmark = {
__typename: 'ChapterBookmarkNode',
note: null,
};
} else {
chapter.bookmark = null;
}
data.chapter = chapter;
store.writeQuery({
data,
query,
variables,
});
},
optimisticResponse: {
__typename: 'Mutation',
updateChapterBookmark: {
__typename: 'UpdateChapterBookmarkPayload',
success: true,
},
},
});
},
addNote(id) {
this.$store.dispatch('addNote', {
content: id,
parent: this.chapter.id,
});
},
editNote() {
this.$store.dispatch('editNote', this.chapter.bookmark.note);
},
textHidden(type) {
return hidden({
block: this.chapter,
schoolClass: this.schoolClass,
type,
});
},
},
};
</script>
<style scoped lang="scss">
@import "~styles/helpers";
.chapter {
position: relative;
&__bookmark-actions {
margin-top: 3px;
}
&__intro {
position: relative;
}
&__description {
@include lead-paragraph;
margin-bottom: $large-spacing;
}
}
</style>