Skip to content

Commit

Permalink
MarkAsComplete modal in LearnImmersiveLayout flow
Browse files Browse the repository at this point in the history
- LearningActivityBar is hard coded to show when not in production - should be from content metadata.
- Added GlobalSnackbar to LearnImmersiveLayout
- MarkAsComplete modal now uses available Vuex action to dispatch progress update.
  • Loading branch information
nucleogenesis committed Sep 7, 2021
1 parent b6a52e2 commit ab8a2dc
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 37 deletions.
10 changes: 9 additions & 1 deletion kolibri/plugins/learn/assets/src/views/LearnImmersiveLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
:learningActivities="mappedLearningActivities"
:isLessonContext="true"
:isBookmarked="true"
:allowMarkComplete="false"
:allowMarkComplete="allowMarkComplete"
data-test="learningActivityBar"
@navigateBack="navigateBack"
/>
Expand Down Expand Up @@ -46,6 +46,7 @@
data-test="contentPage"
/>
</div>
<GlobalSnackbar />
</div>

</template>
Expand All @@ -59,6 +60,7 @@
import AuthMessage from 'kolibri.coreVue.components.AuthMessage';
import { LearningActivities } from 'kolibri.coreVue.vuex.constants';
import commonCoreStrings from 'kolibri.coreVue.mixins.commonCoreStrings';
import GlobalSnackbar from '../../../../../../kolibri/core/assets/src/views/GlobalSnackbar';
import SkipNavigationLink from '../../../../../../kolibri/core/assets/src/views/SkipNavigationLink';
import AppError from '../../../../../../kolibri/core/assets/src/views/AppError';
import ContentPage from './ContentPage';
Expand Down Expand Up @@ -93,6 +95,7 @@
AppError,
AuthMessage,
ContentPage,
GlobalSnackbar,
LearningActivityBar,
SkipNavigationLink,
},
Expand Down Expand Up @@ -141,6 +144,11 @@
resourceTitle() {
return this.content ? this.content.title : '';
},
allowMarkComplete() {
// TODO: This should be determined by some other means. Content metadata?
const DEV_ONLY = process.env.NODE_ENV !== 'production';
return DEV_ONLY;
},
mappedLearningActivities() {
let learningActivities = [];
if (this.content && this.content.kind) {
Expand Down
11 changes: 10 additions & 1 deletion kolibri/plugins/learn/assets/src/views/LearningActivityBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@
</CoreMenu>
</span>
</template>
<MarkAsCompleteModal
v-if="showMarkAsCompleteModal && allowMarkComplete"
@completed="showMarkAsCompleteModal = false"
@cancel="showMarkAsCompleteModal = false"
/>
</UiToolbar>

</template>
Expand All @@ -92,7 +97,8 @@
import UiToolbar from 'kolibri.coreVue.components.UiToolbar';
import TextTruncator from 'kolibri.coreVue.components.TextTruncator';
import { LearningActivities } from 'kolibri.coreVue.vuex.constants';
import LearningActivityIcon from './LearningActivityIcon.vue';
import LearningActivityIcon from './LearningActivityIcon';
import MarkAsCompleteModal from './MarkAsCompleteModal';
export default {
name: 'LearningActivityBar',
Expand All @@ -102,6 +108,7 @@
UiToolbar,
TextTruncator,
LearningActivityIcon,
MarkAsCompleteModal,
},
mixins: [KResponsiveWindowMixin],
/**
Expand Down Expand Up @@ -159,6 +166,7 @@
data() {
return {
isMenuOpen: false,
showMarkAsCompleteModal: false,
};
},
computed: {
Expand Down Expand Up @@ -224,6 +232,7 @@
},
created() {
window.addEventListener('click', this.onWindowClick);
this.$on('markComplete', () => (this.showMarkAsCompleteModal = true));
},
beforeDestroy() {
window.removeEventListener('click', this.onWindowClick);
Expand Down
20 changes: 2 additions & 18 deletions kolibri/plugins/learn/assets/src/views/MarkAsCompleteModal.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<template>

<KModal
v-if="contentSessionLogId"
:title="$tr('markResourceAsCompleteLabel')"
:submitText="coreString('confirmAction')"
:cancelText="coreString('cancelAction')"
Expand All @@ -17,33 +16,18 @@
<script>
import commonCoreStrings from 'kolibri.coreVue.mixins.commonCoreStrings';
import { ContentSessionLogResource } from 'kolibri.resources';
export default {
name: 'MarkAsCompleteModal',
mixins: [commonCoreStrings],
props: {
// When truthy, the modal is shown. It is the implementer's charge
// to decide when this is visible. The `complete` event will be
// emitted upon successful API request in markResourceAsCompleted().
contentSessionLogId: {
type: String,
default: null,
},
},
methods: {
/*
* Emits "complete" event on success.
* Errors handled using the `handleApiError` action.
*/
markResourceAsCompleted() {
ContentSessionLogResource.saveModel({
id: this.contentSessionLogId,
data: {
progress: 1,
},
exists: true,
})
this.$store
.dispatch('updateProgress', { progressPercent: 1 })
.then(() => {
this.$emit('complete');
this.$store.dispatch('createSnackbar', this.$tr('resourceCompletedSnackbar'));
Expand Down
21 changes: 4 additions & 17 deletions kolibri/plugins/learn/assets/test/views/mark-as-complete.spec.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
import KModal from 'kolibri-design-system/lib/KModal';
import { mount } from '@vue/test-utils';
import { ContentSessionLogResource } from 'kolibri.resources';
import MarkAsCompleteModal from '../../src/views/MarkAsCompleteModal';

describe('Mark as complete modal', () => {
let wrapper;
let markSpy;
let mockStore;
let resourceSpy;
let testSessionId = 'test';

beforeAll(() => {
// Mock $store.dispatch to return a Promise
mockStore = { dispatch: jest.fn().mockImplementation(() => Promise.resolve()) };
markSpy = jest.spyOn(MarkAsCompleteModal.methods, 'markResourceAsCompleted');
resourceSpy = jest.spyOn(ContentSessionLogResource, 'saveModel');
resourceSpy.mockImplementation(() => Promise.resolve());

wrapper = mount(MarkAsCompleteModal, {
propsData: {
Expand All @@ -29,10 +25,9 @@ describe('Mark as complete modal', () => {

describe('When the user cancels the modal', () => {
// This describe() should go before subsequent ones
// to avoid needing to resourceSpy.mockReset()
it('emits a cancel event', () => {
wrapper.findComponent(KModal).vm.$emit('cancel');
expect(resourceSpy).not.toHaveBeenCalled();
expect(mockStore.dispatch).not.toHaveBeenCalled();
expect(wrapper.emitted().cancel).toBeTruthy();
});
});
Expand All @@ -48,18 +43,10 @@ describe('Mark as complete modal', () => {
expect(wrapper.emitted().complete).toBeTruthy();
});
it('dispatches an createSnackbar message', () => {
expect(mockStore.dispatch).toHaveBeenCalledWith('createSnackbar', 'Resource completed');
expect(mockStore.dispatch).toHaveBeenCalledWith('updateProgress', { progressPercent: 1 });
});
});

describe('markResourceAsCompleted', () => {
it('makes a PATCH request to /api/logger/contentsessionlog', () => {
wrapper.findComponent(KModal).vm.$emit('submit');
expect(resourceSpy).toHaveBeenCalledWith({
id: testSessionId,
data: { progress: 1 },
exists: true,
});
it('dispatches an createSnackbar message', () => {
expect(mockStore.dispatch).toHaveBeenCalledWith('createSnackbar', 'Resource completed');
});
});
});

0 comments on commit ab8a2dc

Please sign in to comment.