Refactor bookmark actions

This commit is contained in:
Ramon Wenger 2022-01-28 00:03:36 +01:00
parent 1462b08ecd
commit 57704d7fc2
10 changed files with 217 additions and 99 deletions

View File

@ -44,7 +44,7 @@ export default {
id: getChapterId(), id: getChapterId(),
title: 'chapter-title', title: 'chapter-title',
description: 'chapter-description', description: 'chapter-description',
bookmark: null
}), }),
ContentBlockNode: () => ({ ContentBlockNode: () => ({
contents: [], contents: [],

View File

@ -4,7 +4,7 @@ export default {
heroImage: 'heroImage', heroImage: 'heroImage',
teaser: 'A Module Mock Teaser', teaser: 'A Module Mock Teaser',
intro: 'intro', intro: 'intro',
assignments: {}, assignments: [],
objectiveGroups: [], objectiveGroups: [],
id: 'TW9kdWxlTm9kZToxMjM=', id: 'TW9kdWxlTm9kZToxMjM=',
chapters: [], chapters: [],

View File

@ -1,36 +0,0 @@
describe('Bookmarks', () => {
beforeEach(() => {
// todo: mock all the graphql queries and mutations
cy.exec('python ../server/manage.py prepare_bookmarks_for_cypress');
cy.viewport('macbook-15');
cy.apolloLogin('rachel.green', 'test');
});
it('should bookmark content block', () => {
cy.visit('/module/lohn-und-budget/');
cy.get('.content-component').contains('Das folgende Interview').parent().parent().as('interviewContent');
cy.get('@interviewContent').within(() => {
cy.get('.bookmark-actions__bookmark').click();
cy.get('.bookmark-actions__add-note').click();
});
cy.get('[data-cy=bookmark-note]').within(() => {
cy.get('.skillbox-input').type('Hallo Velo');
});
cy.get('[data-cy=modal-save-button]').click();
cy.get('@interviewContent').within(() => {
cy.get('.bookmark-actions__edit-note').click();
});
cy.get('[data-cy=bookmark-note]').within(() => {
cy.get('.skillbox-input').clear().type('Hello Bike');
});
cy.get('[data-cy=modal-save-button]').click();
});
});

View File

@ -0,0 +1,124 @@
import {getMinimalMe} from '../../support/helpers';
import minimalModule from '../../fixtures/module.minimal';
const {me: minimalMe} = getMinimalMe({});
describe('Bookmarks', () => {
beforeEach(() => {
cy.setup();
cy.mockGraphqlOps({
operations: {
MeQuery: {
me: minimalMe
},
ModuleDetailsQuery: {
module: {
...minimalModule,
chapters: [
{
title: 'My super Chapter',
contentBlocks: [
{
contents: [
{
type: 'text_block',
value: {
text: 'Das folgende Interview'
},
id: "df8212ee-3e82-49fa-977e-c4b60789163e"
}
]
}
]
}
]
}
},
UpdateLastModule: {},
UpdateContentBookmark: {
updateContentBookmark: {
success: true
}
},
UpdateChapterBookmark: {
updateChapterBookmark: {
success: true
}
},
AddNote: ({input: {note}}) => ({
addNote: {
note
}
}),
UpdateNote: ({input: {note}}) => ({
updateNote: {
note
}
})
}
});
});
it('should bookmark instrument', () => {
cy.visit();
});
it('should bookmark module', () => {
cy.visit();
});
it('should bookmark chapter', () => {
cy.visit('/module/lohn-und-budget/');
cy.getByDataCy('chapter-bookmark-actions').as('chapterBookmark');
cy.get('@chapterBookmark').within(() => {
cy.getByDataCy('bookmark-action').click();
cy.getByDataCy('add-note-action').click();
});
cy.get('[data-cy=bookmark-note]').within(() => {
cy.get('.skillbox-input').type('Hallo Velo');
});
cy.get('[data-cy=modal-save-button]').click();
cy.get('@chapterBookmark').within(() => {
cy.getByDataCy('edit-note-action').click();
});
cy.get('[data-cy=bookmark-note]').within(() => {
cy.get('.skillbox-input').clear().type('Hello Bike');
});
cy.get('[data-cy=modal-save-button]').click();
});
it('should bookmark content block', () => {
cy.visit('/module/lohn-und-budget/');
cy.getByDataCy('content-component').contains('Das folgende Interview').parent().parent().as('interviewContent');
cy.get('@interviewContent').within(() => {
cy.get('.bookmark-actions__bookmark').click();
cy.get('.bookmark-actions__add-note').click();
});
cy.get('[data-cy=bookmark-note]').within(() => {
cy.get('.skillbox-input').type('Hallo Velo');
});
cy.get('[data-cy=modal-save-button]').click();
cy.get('@interviewContent').within(() => {
cy.get('.bookmark-actions__edit-note').click();
});
cy.get('[data-cy=bookmark-note]').within(() => {
cy.get('.skillbox-input').clear().type('Hello Bike');
});
cy.get('[data-cy=modal-save-button]').click();
});
});

View File

@ -2,6 +2,7 @@
<div <div
:data-scrollto="chapter.id" :data-scrollto="chapter.id"
class="chapter" class="chapter"
data-cy="chapter"
> >
<div <div
:class="{'hideable-element--greyed-out': titleGreyedOut}" :class="{'hideable-element--greyed-out': titleGreyedOut}"
@ -25,6 +26,7 @@
:bookmarked="chapter.bookmark" :bookmarked="chapter.bookmark"
:note="note" :note="note"
class="chapter__bookmark-actions" class="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(!chapter.bookmark)"
@ -145,23 +147,28 @@
update: (store) => { update: (store) => {
const query = CHAPTER_QUERY; const query = CHAPTER_QUERY;
const variables = {id}; const variables = {id};
const data = store.readQuery({ const {chapter} = store.readQuery({
query, query,
variables, variables,
}); });
const chapter = data.chapter; let bookmark;
if (bookmarked) { if (bookmarked) {
chapter.bookmark = { bookmark = {
__typename: 'ChapterBookmarkNode', __typename: 'ChapterBookmarkNode',
note: null, note: null,
}; };
} else { } else {
chapter.bookmark = null; bookmark = null;
} }
data.chapter = chapter; const data = {
chapter: {
...chapter,
bookmark
}
};
store.writeQuery({ store.writeQuery({
data, data,

View File

@ -2,6 +2,7 @@
<div <div
:class="componentClass" :class="componentClass"
:data-scrollto="component.id" :data-scrollto="component.id"
data-cy="content-component"
> >
<bookmark-actions <bookmark-actions
:bookmarked="bookmarked" :bookmarked="bookmarked"

View File

@ -6,12 +6,14 @@
<a <a
:class="{'bookmark-actions__action--bookmarked': bookmarked}" :class="{'bookmark-actions__action--bookmarked': bookmarked}"
class="bookmark-actions__action bookmark-actions__bookmark" class="bookmark-actions__action bookmark-actions__bookmark"
data-cy="bookmark-action"
@click="$emit('bookmark')" @click="$emit('bookmark')"
> >
<bookmark-icon :bookmarked="bookmarked" /> <bookmark-icon :bookmarked="bookmarked" />
</a> </a>
<a <a
class="bookmark-actions__action bookmark-actions__add-note" class="bookmark-actions__action bookmark-actions__add-note"
data-cy="add-note-action"
v-if="bookmarked && !note" v-if="bookmarked && !note"
@click="$emit('add-note')" @click="$emit('add-note')"
> >
@ -19,6 +21,7 @@
</a> </a>
<a <a
:data-scrollto="note.id" :data-scrollto="note.id"
data-cy="edit-note-action"
class="bookmark-actions__action bookmark-actions__edit-note bookmark-actions__action--noted" class="bookmark-actions__action bookmark-actions__edit-note bookmark-actions__action--noted"
v-if="note" v-if="note"
@click="$emit('edit-note')" @click="$emit('edit-note')"

View File

@ -24,7 +24,7 @@ const typePolicies = {
navigation: showNavigationSidebarVar() navigation: showNavigationSidebarVar()
}; };
} }
} , },
scrollPosition: { scrollPosition: {
read() { read() {
return { return {
@ -48,44 +48,30 @@ const typePolicies = {
}, },
// these used to be in cacheRedirects, now here // these used to be in cacheRedirects, now here
// contentBlock: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ContentBlockNode', id: args.id}), contentBlock: { read: idToRefFactory('ContentBlockNode') },
contentBlock: { chapter: {read: idToRefFactory('ChapterNode')},
read: idToRefFactory('ContentBlockNode') assignment: {read: idToRefFactory('AssignmentNode')},
// read(_, {args, toReference}) { objective: {read: idToRefFactory('ObjectiveNode')},
// return toReference({ objectiveGroup: {read: idToRefFactory('ObjectiveGroupNode')},
// __typename: 'ContentBlockNode', projectEntry: {read: idToRefFactory('ProjectEntryNode')},
// id: args.id project: {
// }); read(_, {args: {slug, id}, toReference}) {
// } console.log(`Trying to reference project with slug ${slug}, id ${id}`);
} if (slug) {
}, return toReference({
// chapter: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ChapterNode', id: args.id}), __typename: 'ProjectNode',
chapter: {read: idToRefFactory('ChapterNode')}, slug
assignment: {read: idToRefFactory('AssignmentNode')}, });
objective: {read: idToRefFactory('ObjectiveNode')}, } else {
objectiveGroup: {read: idToRefFactory('ObjectiveGroupNode')}, return toReference({
projectEntry: {read: idToRefFactory('ProjectEntryNode')}, __typename: 'ProjectNode',
project: { id
read(_, {args: {slug, id}, toReference}) { });
console.log(`Trying to reference project with slug ${slug}, id ${id}`); }
if (slug) { }
return toReference({ },
__typename: 'ProjectNode', }
slug
});
} else {
return toReference({
__typename: 'ProjectNode',
id
});
}
}
},
// assignment: (_, args, {getCacheKey}) => getCacheKey({__typename: 'AssignmentNode', id: args.id}),
// objective: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ObjectiveNode', id: args.id}),
// objectiveGroup: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ObjectiveGroupNode', id: args.id}),
// projectEntry: (_, args, {getCacheKey}) => getCacheKey({__typename: 'ProjectEntryNode', id: args.id}),
}, },
}; };

View File

@ -16,22 +16,35 @@ export const constructNoteMutation = (n) => {
if (n.type === 'ContentBlockNode') { if (n.type === 'ContentBlockNode') {
const query = CONTENT_BLOCK_QUERY; const query = CONTENT_BLOCK_QUERY;
const variables = {id: n.block}; const variables = {id: n.block};
const data = store.readQuery({ const {contentBlock} = store.readQuery({
query, query,
variables variables
}); });
const bookmarks = data.contentBlock.bookmarks; let bookmarks;
let index = bookmarks.findIndex(compareUuid(n)); let index = contentBlock.bookmarks.findIndex(compareUuid(n));
if (index > -1) { if (index > -1) {
let el = bookmarks[index]; const el = {
el.note = note; ...contentBlock.bookmarks[index],
bookmarks.splice(index, 1, el); note
};
bookmarks = [
...contentBlock.bookmarks.slice(0, index),
el,
...contentBlock.bookmarks.slice(index + 1)
];
} else {
bookmarks = [...contentBlock.bookmarks];
} }
data.contentBlock.bookmarks = bookmarks; const data = {
contentBlock: {
...contentBlock,
bookmarks
}
};
store.writeQuery({ store.writeQuery({
data, data,
@ -70,16 +83,23 @@ export const constructNoteMutation = (n) => {
const type = getBlockType(n.parent) === 'ChapterNode' ? 'chapter' : 'module'; const type = getBlockType(n.parent) === 'ChapterNode' ? 'chapter' : 'module';
const query = type === 'chapter' ? CHAPTER_QUERY : MODULE_QUERY; const query = type === 'chapter' ? CHAPTER_QUERY : MODULE_QUERY;
const variables = {id: n.parent}; const variables = {id: n.parent};
const data = store.readQuery({ const fromStore = store.readQuery({
query, query,
variables variables
}); });
const bookmark = data[type].bookmark; const entity = fromStore[type];
let bookmark = {
...entity.bookmark,
note
};
bookmark.note = note; const data = {
[type]: {
data[type].bookmark = bookmark; ...entity,
bookmark
}
};
store.writeQuery({ store.writeQuery({
data, data,

View File

@ -70,27 +70,40 @@ export const constructContentComponentBookmarkMutation = (uuid, bookmarked, pare
update: (store) => { update: (store) => {
const query = CONTENT_BLOCK_QUERY; const query = CONTENT_BLOCK_QUERY;
const variables = {id: root}; const variables = {id: root};
const data = store.readQuery({ const {contentBlock} = store.readQuery({
query, query,
variables variables
}); });
const bookmarks = data.contentBlock.bookmarks; // const bookmarks = data.contentBlock.bookmarks;
let bookmarks;
if (bookmarked) { if (bookmarked) {
bookmarks.push({ bookmarks = [
...contentBlock.bookmarks,
{
note: null, note: null,
uuid, uuid,
__typename: 'ContentBlockBookmarkNode' __typename: 'ContentBlockBookmarkNode'
}); }
];
} else { } else {
let index = bookmarks.findIndex(compareUuid(uuid)); let index = bookmarks.findIndex(compareUuid(uuid));
if (index > -1) { if (index > -1) {
bookmarks.splice(index, 1); bookmarks.splice(index, 1);
} }
bookmarks = [
...contentBlock.bookmarks.slice(0, index),
...contentBlock.bookmarks.slice(index + 1)
];
} }
data.contentBlock.bookmarks = bookmarks; const data = {
contentBlock: {
...contentBlock,
bookmarks
}
};
store.writeQuery({ store.writeQuery({
data, data,