Refactor ContentComponent

This commit is contained in:
Ramon Wenger 2024-01-11 10:00:37 +01:00
parent f3dc0e9b09
commit a6974853ef
7 changed files with 496 additions and 924 deletions

View File

@ -2,16 +2,16 @@ import { CodegenConfig } from '@graphql-codegen/cli';
const config: CodegenConfig = {
schema: ['../server/schema.graphql', './local.graphql'],
documents: ['src/**/*.vue'],
documents: ['src/**/*.vue', 'src/**/*.ts'],
generates: {
'src/__generated__/': {
preset: 'client',
plugins: [],
presetConfig: {
useTypeImports: true
useTypeImports: true,
},
},
},
ignoreNoDocuments: true
ignoreNoDocuments: true,
};
export default config;

View File

@ -24,6 +24,8 @@ const documents = {
"\n fragment SnapshotTitleFragment on SnapshotNode {\n title\n }\n": types.SnapshotTitleFragmentFragmentDoc,
"\n fragment SnapshotDetailsFragment on SnapshotNode {\n id\n title\n shared\n created\n creator\n mine\n }\n": types.SnapshotDetailsFragmentFragmentDoc,
"\n query ModuleEditModeQuery($slug: String) {\n module(slug: $slug) {\n inEditMode @client\n slug\n }\n }\n": types.ModuleEditModeQueryDocument,
"\n mutation UpdateInstrumentBookmark($input: UpdateInstrumentBookmarkInput!) {\n updateInstrumentBookmark(input: $input) {\n success\n }\n }\n ": types.UpdateInstrumentBookmarkDocument,
"\n mutation UpdateContentBookmark($input: UpdateContentBookmarkInput!) {\n updateContentBookmark(input: $input) {\n success\n }\n }\n ": types.UpdateContentBookmarkDocument,
"\n query ChapterQuery($id: ID!) {\n chapter(id: $id) {\n path\n }\n }\n ": types.ChapterQueryDocument,
"\n query ContentBlockQuery($id: ID!) {\n contentBlock(id: $id) {\n path\n }\n }\n ": types.ContentBlockQueryDocument,
"\n query MeLanguage {\n me {\n language @client\n }\n }\n ": types.MeLanguageDocument,
@ -89,6 +91,14 @@ export function graphql(source: "\n fragment SnapshotDetailsFragment on Snapsho
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query ModuleEditModeQuery($slug: String) {\n module(slug: $slug) {\n inEditMode @client\n slug\n }\n }\n"): (typeof documents)["\n query ModuleEditModeQuery($slug: String) {\n module(slug: $slug) {\n inEditMode @client\n slug\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n mutation UpdateInstrumentBookmark($input: UpdateInstrumentBookmarkInput!) {\n updateInstrumentBookmark(input: $input) {\n success\n }\n }\n "): (typeof documents)["\n mutation UpdateInstrumentBookmark($input: UpdateInstrumentBookmarkInput!) {\n updateInstrumentBookmark(input: $input) {\n success\n }\n }\n "];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n mutation UpdateContentBookmark($input: UpdateContentBookmarkInput!) {\n updateContentBookmark(input: $input) {\n success\n }\n }\n "): (typeof documents)["\n mutation UpdateContentBookmark($input: UpdateContentBookmarkInput!) {\n updateContentBookmark(input: $input) {\n success\n }\n }\n "];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/

File diff suppressed because it is too large Load Diff

View File

@ -12,70 +12,121 @@
v-if="showBookmarkActions"
@add-note="addNote(component.id)"
@edit-note="editNote"
@bookmark="bookmarkContent(component.id, !bookmarked)"
/>
<component
v-bind="component"
:parent="parent"
:is="component.type"
@bookmark="bookmarkContent(!bookmarked)"
/>
<component v-bind="component" :parent="parent" :is="componentType" />
</div>
</template>
<script>
import { constructContentComponentBookmarkMutation } from '@/helpers/update-content-bookmark-mutation';
import { defineAsyncComponent } from 'vue';
<script setup lang="ts">
import { defineAsyncComponent, ref, computed, onMounted } from "vue";
import { useStore } from "vuex";
import { constructContentComponentBookmarkMutation } from "@/helpers/update-content-bookmark-mutation";
import { useMutation } from "@vue/apollo-composable";
const TextBlock = defineAsyncComponent(() => import('@/components/content-blocks/TextBlock.vue'));
const InstrumentWidget = defineAsyncComponent(() => import('@/components/content-blocks/InstrumentWidget.vue'));
const ImageBlock = defineAsyncComponent(() => import('@/components/content-blocks/ImageBlock.vue'));
const ImageUrlBlock = defineAsyncComponent(() => import('@/components/content-blocks/ImageUrlBlock.vue'));
const VideoBlock = defineAsyncComponent(() => import('@/components/content-blocks/VideoBlock.vue'));
const LinkBlock = defineAsyncComponent(() => import('@/components/content-blocks/LinkBlock.vue'));
const DocumentBlock = defineAsyncComponent(() => import('@/components/content-blocks/DocumentBlock.vue'));
const CmsDocumentBlock = defineAsyncComponent(() => import('@/components/content-blocks/CmsDocumentBlock.vue'));
const InfogramBlock = defineAsyncComponent(() => import('@/components/content-blocks/InfogramBlock.vue'));
const ThinglinkBlock = defineAsyncComponent(() => import('@/components/content-blocks/ThinglinkBlock.vue'));
const GeniallyBlock = defineAsyncComponent(() => import('@/components/content-blocks/GeniallyBlock.vue'));
const SubtitleBlock = defineAsyncComponent(() => import('@/components/content-blocks/SubtitleBlock.vue'));
const SectionTitleBlock = defineAsyncComponent(() => import('@/components/content-blocks/SectionTitleBlock.vue'));
const ContentListBlock = defineAsyncComponent(() => import('@/components/content-blocks/ContentListBlock.vue'));
const ModuleRoomSlug = defineAsyncComponent(() => import('@/components/content-blocks/ModuleRoomSlug.vue'));
const Assignment = defineAsyncComponent(() => import('@/components/content-blocks/assignment/Assignment.vue'));
const Survey = defineAsyncComponent(() => import('@/components/content-blocks/SurveyBlock.vue'));
const Solution = defineAsyncComponent(() => import('@/components/content-blocks/Solution.vue'));
const Instruction = defineAsyncComponent(() => import('@/components/content-blocks/Instruction.vue'));
const BookmarkActions = defineAsyncComponent(() => import('@/components/notes/BookmarkActions.vue'));
export interface Props {
component: any;
parent: any;
bookmarks: any[];
notes: any[];
root: string;
editMode: boolean;
}
const TextBlock = defineAsyncComponent(
() => import("@/components/content-blocks/TextBlock.vue")
);
const InstrumentWidget = defineAsyncComponent(
() => import("@/components/content-blocks/InstrumentWidget.vue")
);
const ImageBlock = defineAsyncComponent(
() => import("@/components/content-blocks/ImageBlock.vue")
);
const ImageUrlBlock = defineAsyncComponent(
() => import("@/components/content-blocks/ImageUrlBlock.vue")
);
const VideoBlock = defineAsyncComponent(
() => import("@/components/content-blocks/VideoBlock.vue")
);
const LinkBlock = defineAsyncComponent(
() => import("@/components/content-blocks/LinkBlock.vue")
);
const DocumentBlock = defineAsyncComponent(
() => import("@/components/content-blocks/DocumentBlock.vue")
);
const CmsDocumentBlock = defineAsyncComponent(
() => import("@/components/content-blocks/CmsDocumentBlock.vue")
);
const InfogramBlock = defineAsyncComponent(
() => import("@/components/content-blocks/InfogramBlock.vue")
);
const ThinglinkBlock = defineAsyncComponent(
() => import("@/components/content-blocks/ThinglinkBlock.vue")
);
const GeniallyBlock = defineAsyncComponent(
() => import("@/components/content-blocks/GeniallyBlock.vue")
);
const SubtitleBlock = defineAsyncComponent(
() => import("@/components/content-blocks/SubtitleBlock.vue")
);
const SectionTitleBlock = defineAsyncComponent(
() => import("@/components/content-blocks/SectionTitleBlock.vue")
);
const ContentListBlock = defineAsyncComponent(
() => import("@/components/content-blocks/ContentListBlock.vue")
);
const ModuleRoomSlug = defineAsyncComponent(
() => import("@/components/content-blocks/ModuleRoomSlug.vue")
);
const Assignment = defineAsyncComponent(
() => import("@/components/content-blocks/assignment/Assignment.vue")
);
const Survey = defineAsyncComponent(
() => import("@/components/content-blocks/SurveyBlock.vue")
);
const Solution = defineAsyncComponent(
() => import("@/components/content-blocks/Solution.vue")
);
const Instruction = defineAsyncComponent(
() => import("@/components/content-blocks/Instruction.vue")
);
const BookmarkActions = defineAsyncComponent(
() => import("@/components/notes/BookmarkActions.vue")
);
export default {
props: {
component: {
type: Object,
default: () => ({}),
},
parent: {
type: Object,
default: () => ({}),
},
bookmarks: {
type: Array,
default: () => [],
},
notes: {
type: Array,
default: () => [],
},
root: {
type: String,
default: '',
},
editMode: {
type: Boolean,
default: false,
},
},
type ContentComponentType =
| typeof TextBlock
| typeof InstrumentWidget
| typeof InstrumentWidget
| typeof ImageBlock
| typeof ImageUrlBlock
| typeof VideoBlock
| typeof LinkBlock
| typeof DocumentBlock
| typeof InfogramBlock
| typeof GeniallyBlock
| typeof SubtitleBlock
| typeof SectionTitleBlock
| typeof ContentListBlock
| typeof ModuleRoomSlug
| typeof ThinglinkBlock
| typeof CmsDocumentBlock
| typeof Survey
| typeof Solution
| typeof Instruction
| typeof Assignment;
components: {
const props = withDefaults(defineProps<Props>(), {
component: () => ({}),
parent: () => ({}),
bookmarks: () => [],
notes: () => [],
root: "",
editMode: false,
});
const store = useStore();
const components: Record<string, ContentComponentType> = {
text_block: TextBlock,
basic_knowledge: InstrumentWidget, // for legacy
instrument: InstrumentWidget,
@ -92,63 +143,92 @@ export default {
module_room_slug: ModuleRoomSlug,
thinglink_block: ThinglinkBlock,
cms_document_block: CmsDocumentBlock,
Survey,
Solution,
Instruction,
Assignment,
BookmarkActions,
},
survey: Survey,
solution: Solution,
instruction: Instruction,
assignment: Assignment,
};
computed: {
bookmarked() {
return this.bookmarks && !!this.bookmarks.find((bookmark) => bookmark.uuid === this.component.id);
},
note() {
const bookmark = this.bookmarks && this.bookmarks.find((bookmark) => bookmark.uuid === this.component.id);
const componentType = computed(() => {
return components[props.component.type] || "";
});
const bookmarked = computed(
() =>
props.bookmarks &&
!!props.bookmarks.find((bookmark) => bookmark.uuid === props.component.id)
);
const note = computed(() => {
const bookmark =
props.bookmarks &&
props.bookmarks.find((bookmark) => bookmark.uuid === props.component.id);
return bookmark && bookmark.note;
},
showBookmarkActions() {
return this.component.type !== 'content_list' && this.component.type !== 'basic_knowledge' && !this.editMode;
},
componentClass() {
let classes = ['content-component', `content-component--${this.component.type}`];
if (this.bookmarked) {
classes.push('content-component--bookmarked');
});
const showBookmarkActions = computed(
() =>
props.component.type !== "content_list" &&
props.component.type !== "basic_knowledge" &&
!props.editMode
);
const componentClass = computed(() => {
let classes = [
"content-component",
`content-component--${props.component.type}`,
];
if (bookmarked.value) {
classes.push("content-component--bookmarked");
}
return classes;
},
},
});
methods: {
addNote(id) {
const type = Object.prototype.hasOwnProperty.call(this.parent, '__typename')
? this.parent.__typename
: 'ContentBlockNode';
const addNote = (id: string) => {
const type = Object.prototype.hasOwnProperty.call(props.parent, "__typename")
? props.parent.__typename
: "ContentBlockNode";
this.$store.dispatch('addNote', {
store.dispatch("addNote", {
content: id,
type,
block: this.root,
block: props.root,
});
};
const editNote = () => {
store.dispatch("editNote", note);
};
const { mutation, variables, update, optimisticResponse } =
constructContentComponentBookmarkMutation(
props.component.id,
bookmarked.value,
props.parent,
props.root
);
const { mutate: mutateBookmarkContent } = useMutation(mutation, {
update,
optimisticResponse,
});
const bookmarkContent = (bookmarked: boolean) => {
const newVars = {
input: {
...variables.input,
bookmarked,
},
editNote() {
this.$store.dispatch('editNote', this.note);
},
bookmarkContent(uuid, bookmarked) {
this.$apollo.mutate(constructContentComponentBookmarkMutation(uuid, bookmarked, this.parent, this.root));
},
},
};
console.log(newVars);
mutateBookmarkContent(newVars);
};
</script>
<style lang="scss" scoped>
@import 'styles/helpers';
@import "styles/helpers";
.content-component {
position: relative;
&--bookmarked {
}
// &--bookmarked {
// }
&--subtitle {
margin-top: 2 * $medium-spacing;

View File

@ -1,5 +0,0 @@
mutation UpdateContentBookmark($input: UpdateContentBookmarkInput!) {
updateContentBookmark(input: $input) {
success
}
}

View File

@ -1,5 +0,0 @@
mutation UpdateInstrumentBookmark($input: UpdateInstrumentBookmarkInput!) {
updateInstrumentBookmark(input: $input) {
success
}
}

View File

@ -1,17 +1,34 @@
import UPDATE_CONTENT_BOOKMARK from '@/graphql/gql/mutations/updateContentBookmark.gql';
import UPDATE_INSTRUMENT_BOOKMARK from '@/graphql/gql/mutations/updateInstrumentBookmark.gql';
import CONTENT_BLOCK_QUERY from '@/graphql/gql/queries/contentBlockQuery.gql';
import INSTRUMENT_FRAGMENT from '@/graphql/gql/fragments/instrumentParts.gql';
import { pushToArray, removeAtIndex } from '@/graphql/immutable-operations';
import { graphql } from '@/__generated__';
const compareUuid = (uuid) => (element) => element.uuid === uuid;
const compareUuid = (uuid: string) => (element) => element.uuid === uuid;
export const constructContentComponentBookmarkMutation = (uuid, bookmarked, parent, root) => {
let mutation = {};
interface Mutation {
mutation: any;
variables: any;
update: (store: any) => void;
optimisticResponse: any;
}
export const constructContentComponentBookmarkMutation: (
uuid: string,
bookmarked: boolean,
parent: any,
root: any
) => Mutation = (uuid, bookmarked, parent, root) => {
let mutation: Mutation;
if (parent.__typename === 'InstrumentNode') {
mutation = {
mutation: UPDATE_INSTRUMENT_BOOKMARK,
mutation: graphql(`
mutation UpdateInstrumentBookmark($input: UpdateInstrumentBookmarkInput!) {
updateInstrumentBookmark(input: $input) {
success
}
}
`),
variables: {
input: {
uuid,
@ -30,7 +47,7 @@ export const constructContentComponentBookmarkMutation = (uuid, bookmarked, pare
id,
});
let bookmarks;
let bookmarks: any[];
if (bookmarked) {
const element = {
@ -40,7 +57,7 @@ export const constructContentComponentBookmarkMutation = (uuid, bookmarked, pare
};
bookmarks = pushToArray(instrument.bookmarks, element);
} else {
let index = instrument.bookmarks.findIndex(compareUuid(uuid));
const index = instrument.bookmarks.findIndex(compareUuid(uuid));
if (index > -1) {
bookmarks = removeAtIndex(instrument.bookmarks, index);
} else {
@ -69,7 +86,13 @@ export const constructContentComponentBookmarkMutation = (uuid, bookmarked, pare
};
} else {
mutation = {
mutation: UPDATE_CONTENT_BOOKMARK,
mutation: graphql(`
mutation UpdateContentBookmark($input: UpdateContentBookmarkInput!) {
updateContentBookmark(input: $input) {
success
}
}
`),
variables: {
input: {
uuid,
@ -86,17 +109,17 @@ export const constructContentComponentBookmarkMutation = (uuid, bookmarked, pare
});
// const bookmarks = data.contentBlock.bookmarks;
let bookmarks;
let bookmarks: any[];
if (bookmarked) {
let element = {
const element = {
note: null,
uuid,
__typename: 'ContentBlockBookmarkNode',
};
bookmarks = pushToArray(contentBlock.bookmarks, element);
} else {
let index = contentBlock.bookmarks.findIndex(compareUuid(uuid));
const index = contentBlock.bookmarks.findIndex(compareUuid(uuid));
if (index > -1) {
bookmarks = removeAtIndex(contentBlock.bookmarks, index);
} else {