Refactor chapter component

This commit is contained in:
Ramon Wenger 2023-02-13 14:10:00 +01:00
parent a629f6a5e6
commit 04d06b3332
4 changed files with 186 additions and 171 deletions

View File

@ -2,6 +2,11 @@ export type numberOrUndefined = number | undefined;
type types = 'task' | 'normal' | 'base_communication' | 'base_society' | 'base_interdisciplinary'; type types = 'task' | 'normal' | 'base_communication' | 'base_society' | 'base_interdisciplinary';
export interface Page {
id: string;
title: string;
}
export interface InstrumentCategory { export interface InstrumentCategory {
id: string; id: string;
name: string; name: string;
@ -10,10 +15,17 @@ export interface InstrumentCategory {
types: any[]; types: any[];
} }
export interface ContentBlock { export interface Hideable {
title: string; userCreated: boolean;
hiddenFor: any[];
visibleFor: any[];
titleHiddenFor: any[];
descriptionHiddenFor: any[];
hidden: boolean;
}
export interface ContentBlock extends Hideable, Page {
contents: any[]; contents: any[];
id: string;
isAssignment: boolean; isAssignment: boolean;
type: types; type: types;
notes: any[]; notes: any[];
@ -21,13 +33,15 @@ export interface ContentBlock {
indent?: boolean; indent?: boolean;
instrumentCategory: InstrumentCategory; instrumentCategory: InstrumentCategory;
mine: boolean; mine: boolean;
userCreated: boolean;
hiddenFor: any[];
visibleFor: any[];
root: string; root: string;
titleHiddenFor: any[]; }
descriptionHiddenFor: any[];
hidden: boolean; export interface Chapter extends Hideable, Page {
contentBlocks: ContentBlock[];
bookmark: any;
titleHidden: boolean;
descriptionHidden: boolean;
description: string;
} }
export interface ActionOptions { export interface ActionOptions {

View File

@ -32,7 +32,7 @@
data-cy="chapter-bookmark-actions" data-cy="chapter-bookmark-actions"
@add-note="addNote" @add-note="addNote"
@edit-note="editNote" @edit-note="editNote"
@bookmark="bookmark(!chapter.bookmark)" @bookmark="bookmark()"
/> />
<div <div
:class="{ 'hideable-element--greyed-out': descriptionGreyedOut }" :class="{ 'hideable-element--greyed-out': descriptionGreyedOut }"
@ -65,164 +65,154 @@
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import ContentBlock from '@/components/ContentBlock'; import { computed } from 'vue';
import AddContentButton from '@/components/AddContentButton'; import ContentBlock from '@/components/ContentBlock.vue';
import BookmarkActions from '@/components/notes/BookmarkActions'; import AddContentButton from '@/components/AddContentButton.vue';
import VisibilityAction from '@/components/visibility/VisibilityAction'; import BookmarkActions from '@/components/notes/BookmarkActions.vue';
import VisibilityAction from '@/components/visibility/VisibilityAction.vue';
import CopyLink from '@/components/CopyLink.vue'; import CopyLink from '@/components/CopyLink.vue';
import type { Chapter } from '@/@types';
import { hidden } from '@/helpers/visibility'; import { hidden } from '@/helpers/visibility';
import { CHAPTER_DESCRIPTION_TYPE, CHAPTER_TITLE_TYPE, CONTENT_TYPE } from '@/consts/types'; import { CHAPTER_DESCRIPTION_TYPE, CHAPTER_TITLE_TYPE, CONTENT_TYPE } from '@/consts/types';
import { useStore } from 'vuex';
import UPDATE_CHAPTER_BOOKMARK_MUTATION from '@/graphql/gql/mutations/updateChapterBookmark.gql'; import UPDATE_CHAPTER_BOOKMARK_MUTATION from '@/graphql/gql/mutations/updateChapterBookmark.gql';
import CHAPTER_QUERY from '@/graphql/gql/queries/chapterQuery.gql'; import CHAPTER_QUERY from '@/graphql/gql/queries/chapterQuery.gql';
import { getMe } from '@/mixins/me';
import { useMutation } from '@vue/apollo-composable';
import me from '@/mixins/me'; export interface Props {
chapter: Chapter;
index: number;
editMode: boolean;
}
export default { const { schoolClass } = getMe();
props: {
chapter: { const store = useStore();
type: Object,
default: () => ({}), const props = withDefaults(defineProps<Props>(), {
index: 0,
editMode: false,
});
const filteredContentBlocks = computed(() => {
if (!(props.chapter && props.chapter.contentBlocks)) {
return [];
}
if (props.editMode) {
return props.chapter.contentBlocks;
}
return props.chapter.contentBlocks.filter(
(contentBlock) =>
!hidden({
block: contentBlock,
schoolClass: schoolClass,
type: CONTENT_TYPE,
})
);
});
const note = computed(() => {
if (props.chapter && props.chapter.bookmark) {
return props.chapter.bookmark.note;
}
return false;
});
const titleGreyedOut = computed(() => {
return textHidden(CHAPTER_TITLE_TYPE) && props.editMode;
});
const titleHidden = computed(() => {
// never hidden when editing the module
if (props.chapter.titleHidden === true) {
return true;
}
return textHidden(CHAPTER_TITLE_TYPE) && !props.editMode;
});
const descriptionGreyedOut = computed(() => {
return textHidden(CHAPTER_DESCRIPTION_TYPE) && props.editMode;
});
const descriptionHidden = computed(() => {
// never hidden when editing the module
if (props.chapter.descriptionHidden === true) {
return true;
}
return textHidden(CHAPTER_DESCRIPTION_TYPE) && !props.editMode;
});
const { mutate: bookmark } = useMutation(UPDATE_CHAPTER_BOOKMARK_MUTATION, () => {
const bookmarked = !props.chapter.bookmark;
const id = props.chapter.id;
return {
variables: {
input: {
chapter: id,
bookmarked,
},
}, },
index: { update: (store: any) => {
type: Number, const query = CHAPTER_QUERY;
default: 0, const variables = { id };
}, const { chapter } = store.readQuery({
editMode: { query,
type: Boolean, variables,
default: false, });
},
},
mixins: [me], let bookmark;
components: { if (bookmarked) {
BookmarkActions, bookmark = {
VisibilityAction, __typename: 'ChapterBookmarkNode',
ContentBlock, note: null,
AddContentButton, };
CopyLink, } else {
}, bookmark = null;
computed: {
filteredContentBlocks() {
if (!(this.chapter && this.chapter.contentBlocks)) {
return [];
} }
if (this.editMode) {
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.editMode;
},
// never hidden when editing the module
titleHidden() {
if (this.chapter.titleHidden === true) {
return true;
}
return this.textHidden(CHAPTER_TITLE_TYPE) && !this.editMode;
},
descriptionGreyedOut() {
return this.textHidden(CHAPTER_DESCRIPTION_TYPE) && this.editMode;
},
// never hidden when editing the module
descriptionHidden() {
if (this.chapter.descriptionHidden === true) {
return true;
}
return this.textHidden(CHAPTER_DESCRIPTION_TYPE) && !this.editMode;
},
},
methods: { const data = {
bookmark(bookmarked) { chapter: {
const id = this.chapter.id; ...chapter,
this.$apollo.mutate({ bookmark,
mutation: UPDATE_CHAPTER_BOOKMARK_MUTATION,
variables: {
input: {
chapter: id,
bookmarked,
},
}, },
update: (store) => { };
const query = CHAPTER_QUERY;
const variables = { id };
const { chapter } = store.readQuery({
query,
variables,
});
let bookmark; store.writeQuery({
data,
if (bookmarked) { query,
bookmark = { variables,
__typename: 'ChapterBookmarkNode',
note: null,
};
} else {
bookmark = null;
}
const data = {
chapter: {
...chapter,
bookmark,
},
};
store.writeQuery({
data,
query,
variables,
});
},
optimisticResponse: {
__typename: 'Mutation',
updateChapterBookmark: {
__typename: 'UpdateChapterBookmarkPayload',
success: true,
},
},
}); });
}, },
addNote(id) {
this.$store.dispatch('addNote', { optimisticResponse: {
content: id, __typename: 'Mutation',
parent: this.chapter.id, updateChapterBookmark: {
}); __typename: 'UpdateChapterBookmarkPayload',
success: true,
},
}, },
editNote() { };
this.$store.dispatch('editNote', this.chapter.bookmark.note); });
},
textHidden(type) { const addNote = (id: string) => {
return hidden({ store.dispatch('addNote', {
block: this.chapter, content: id,
schoolClass: this.schoolClass, parent: props.chapter.id,
type, });
}); };
}, const editNote = () => {
}, store.dispatch('editNote', props.chapter.bookmark.note);
};
const textHidden = (type: string) => {
return hidden({
block: props.chapter,
schoolClass: schoolClass,
type,
});
}; };
</script> </script>
<script></script>
<style scoped lang="scss"> <style scoped lang="scss">
@import '~styles/helpers'; @import '~styles/helpers';

View File

@ -121,7 +121,7 @@ import type { Modal } from '@/plugins/modal.types';
export interface Props { export interface Props {
contentBlock: ContentBlock; contentBlock: ContentBlock;
parent?: any; parent?: any;
editMode: boolean; editMode?: boolean;
} }
const ContentComponent = defineAsyncComponent( const ContentComponent = defineAsyncComponent(

View File

@ -10,7 +10,7 @@ import UPDATE_OBJECTIVE_VISIBILITY_MUTATION from '@/graphql/gql/mutations/update
import UPDATE_OBJECTIVE_GROUP_VISIBILITY_MUTATION from '@/graphql/gql/mutations/updateObjectiveGroupVisibility.gql'; import UPDATE_OBJECTIVE_GROUP_VISIBILITY_MUTATION from '@/graphql/gql/mutations/updateObjectiveGroupVisibility.gql';
import UPDATE_CHAPTER_VISIBILITY_MUTATION from '@/graphql/gql/mutations/updateChapterVisibility.gql'; import UPDATE_CHAPTER_VISIBILITY_MUTATION from '@/graphql/gql/mutations/updateChapterVisibility.gql';
export const createVisibilityMutation = (type, id, visibility) => { export const createVisibilityMutation = (type: string, id: string, visibility: string) => {
let mutation, variables; let mutation, variables;
switch (type) { switch (type) {
case CONTENT_TYPE: case CONTENT_TYPE:
@ -61,32 +61,43 @@ export const createVisibilityMutation = (type, id, visibility) => {
}; };
}; };
const containsClass = (arr = [], schoolClass) => arr.map((entry) => entry.id).includes(schoolClass.id); const containsClass = (arr: any[] = [], schoolClass: any) => arr.map((entry) => entry.id).includes(schoolClass.id);
export const hidden = ({ export const hidden: (options: {
type: string;
block: {
userCreated: boolean;
visibleFor: any[];
hiddenFor: any[];
titleHiddenFor: any[];
descriptionHiddenFor: any[];
hidden: boolean;
};
schoolClass: any;
}) => boolean = ({
type, type,
block: { userCreated, visibleFor, hiddenFor, titleHiddenFor, descriptionHiddenFor, hidden }, block: { userCreated, visibleFor, hiddenFor, titleHiddenFor, descriptionHiddenFor, hidden },
schoolClass, schoolClass,
}) => { }) => {
if (hidden === true) { if (hidden === true) {
return true; return true;
} }
switch (type) { switch (type) {
case CONTENT_TYPE: case CONTENT_TYPE:
case OBJECTIVE_TYPE: case OBJECTIVE_TYPE:
// is this content block / objective group user created? // is this content block / objective group user created?
return userCreated return userCreated
? // if so, is visibility not explicitly set for this school class? ? // if so, is visibility not explicitly set for this school class?
!containsClass(visibleFor, schoolClass) !containsClass(visibleFor, schoolClass)
: // otherwise, is it explicitly hidden for this school class? : // otherwise, is it explicitly hidden for this school class?
containsClass(hiddenFor, schoolClass); containsClass(hiddenFor, schoolClass);
case OBJECTIVE_GROUP_TYPE: case OBJECTIVE_GROUP_TYPE:
return containsClass(hiddenFor, schoolClass); return containsClass(hiddenFor, schoolClass);
case CHAPTER_TITLE_TYPE: case CHAPTER_TITLE_TYPE:
return containsClass(titleHiddenFor, schoolClass); return containsClass(titleHiddenFor, schoolClass);
case CHAPTER_DESCRIPTION_TYPE: case CHAPTER_DESCRIPTION_TYPE:
return containsClass(descriptionHiddenFor, schoolClass); return containsClass(descriptionHiddenFor, schoolClass);
default: default:
return false; return false;
} }
}; };