From 3dd6cf864cb29bfbf89dd15c0154c486fa0e5477 Mon Sep 17 00:00:00 2001 From: ihor-romaniuk Date: Tue, 9 Jan 2024 15:31:18 +0100 Subject: [PATCH 1/2] feat: [AXIMST-15] Course unit - add new component section --- src/course-unit/CourseUnit.jsx | 5 +- src/course-unit/CourseUnit.scss | 1 + src/course-unit/CourseUnit.test.jsx | 7 + .../__mocks__/courseSectionVertical.js | 1418 +++++++++++++++++ src/course-unit/__mocks__/index.js | 2 +- .../add-component/AddComponent.jsx | 35 + .../add-component/AddComponent.scss | 12 + .../add-component/AddComponent.test.jsx | 59 + .../add-component/ComponentIcon.jsx | 17 + src/course-unit/add-component/messages.js | 14 + src/course-unit/constants.js | 19 + src/i18n/messages/ar.json | 4 +- src/i18n/messages/de.json | 4 +- src/i18n/messages/de_DE.json | 4 +- src/i18n/messages/es_419.json | 4 +- src/i18n/messages/fa_IR.json | 4 +- src/i18n/messages/fr.json | 4 +- src/i18n/messages/fr_CA.json | 4 +- src/i18n/messages/hi.json | 4 +- src/i18n/messages/it.json | 4 +- src/i18n/messages/it_IT.json | 4 +- src/i18n/messages/pt.json | 4 +- src/i18n/messages/pt_PT.json | 4 +- src/i18n/messages/ru.json | 4 +- src/i18n/messages/uk.json | 4 +- src/i18n/messages/zh_CN.json | 4 +- 26 files changed, 1631 insertions(+), 18 deletions(-) create mode 100644 src/course-unit/__mocks__/courseSectionVertical.js create mode 100644 src/course-unit/add-component/AddComponent.jsx create mode 100644 src/course-unit/add-component/AddComponent.scss create mode 100644 src/course-unit/add-component/AddComponent.test.jsx create mode 100644 src/course-unit/add-component/ComponentIcon.jsx create mode 100644 src/course-unit/add-component/messages.js diff --git a/src/course-unit/CourseUnit.jsx b/src/course-unit/CourseUnit.jsx index e7a09a2d02..bbe3ba0241 100644 --- a/src/course-unit/CourseUnit.jsx +++ b/src/course-unit/CourseUnit.jsx @@ -12,6 +12,7 @@ import getPageHeadTitle from '../generic/utils'; import ProcessingNotification from '../generic/processing-notification'; import InternetConnectionAlert from '../generic/internet-connection-alert'; import Loading from '../generic/Loading'; +import AddComponent from './add-component/AddComponent'; import HeaderTitle from './header-title/HeaderTitle'; import Breadcrumbs from './breadcrumbs/Breadcrumbs'; import HeaderNavigations from './header-navigations/HeaderNavigations'; @@ -87,9 +88,9 @@ const CourseUnit = ({ courseId }) => { xl={[{ span: 9 }, { span: 3 }]} > - {/* TODO: Unit content will be added in the following tasks. */} - Unit content + + diff --git a/src/course-unit/CourseUnit.scss b/src/course-unit/CourseUnit.scss index 954bbbdacc..d3264d89f2 100644 --- a/src/course-unit/CourseUnit.scss +++ b/src/course-unit/CourseUnit.scss @@ -1,2 +1,3 @@ @import "./breadcrumbs/Breadcrumbs"; @import "./course-sequence/CourseSequence"; +@import "./add-component/AddComponent"; diff --git a/src/course-unit/CourseUnit.test.jsx b/src/course-unit/CourseUnit.test.jsx index 287d80ad1f..8143010dfb 100644 --- a/src/course-unit/CourseUnit.test.jsx +++ b/src/course-unit/CourseUnit.test.jsx @@ -9,14 +9,17 @@ import { getConfig, initializeMockApp } from '@edx/frontend-platform'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { + getCourseSectionVerticalApiUrl, getCourseUnitApiUrl, getXBlockBaseApiUrl, } from './data/api'; import { + fetchCourseSectionVerticalData, fetchCourseUnitQuery, } from './data/thunk'; import initializeStore from '../store'; import { + courseSectionVerticalMock, courseUnitIndexMock, } from './__mocks__'; import { executeThunk } from '../utils'; @@ -62,6 +65,10 @@ describe('', () => { .onGet(getCourseUnitApiUrl(courseId)) .reply(200, courseUnitIndexMock); await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch); + axiosMock + .onGet(getCourseSectionVerticalApiUrl(blockId)) + .reply(200, courseSectionVerticalMock); + await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch); }); it('render CourseUnit component correctly', async () => { diff --git a/src/course-unit/__mocks__/courseSectionVertical.js b/src/course-unit/__mocks__/courseSectionVertical.js new file mode 100644 index 0000000000..fdae7cdd56 --- /dev/null +++ b/src/course-unit/__mocks__/courseSectionVertical.js @@ -0,0 +1,1418 @@ +module.exports = { + language_code: 'en', + action: 'view', + xblock: { + display_name: 'Getting Started', + display_type: 'Unit', + category: 'vertical', + }, + is_unit_page: true, + is_collapsible: false, + position: 1, + prev_url: '%2Fcontainer%2Fblock-v1%3AedX%2BDemoX%2BDemo_Course%2Btype%40vertical%2Bblock%40vertical_0270f6de40fc', + next_url: '%2Fcontainer%2Fblock-v1%3AedX%2BDemoX%2BDemo_Course%2Btype%40vertical%2Bblock%404f6c1b4e316a419ab5b6bf30e6c708e9', + new_unit_category: 'vertical', + outline_url: '/course/course-v1:edX+DemoX+Demo_Course?format=concise', + ancestor_xblocks: [ + { + children: [ + { + url: '/course/course-v1:edX+DemoX+Demo_Course?show=block-v1%3AedX%2BDemoX%2BDemo_Course%2Btype%40chapter%2Bblock%40d8a6192ade314473a78242dfeedfbf5b', + display_name: 'Introduction 2', + }, + { + url: '/course/course-v1:edX+DemoX+Demo_Course?show=block-v1%3AedX%2BDemoX%2BDemo_Course%2Btype%40chapter%2Bblock%40interactive_demonstrations', + display_name: 'Example Week 1: Getting Started', + }, + { + url: '/course/course-v1:edX+DemoX+Demo_Course?show=block-v1%3AedX%2BDemoX%2BDemo_Course%2Btype%40chapter%2Bblock%40graded_interactions', + display_name: 'Example Week 2: Get Interactive', + }, + { + url: '/course/course-v1:edX+DemoX+Demo_Course?show=block-v1%3AedX%2BDemoX%2BDemo_Course%2Btype%40chapter%2Bblock%40social_integration', + display_name: 'Example Week 3: Be Social', + }, + { + url: '/course/course-v1:edX+DemoX+Demo_Course?show=block-v1%3AedX%2BDemoX%2BDemo_Course%2Btype%40chapter%2Bblock%401414ffd5143b4b508f739b563ab468b7', + display_name: 'About Exams and Certificates', + }, + ], + title: 'Example Week 1: Getting Started', + is_last: false, + }, + { + children: [ + { + url: '/course/course-v1:edX+DemoX+Demo_Course?show=block-v1%3AedX%2BDemoX%2BDemo_Course%2Btype%40sequential%2Bblock%4019a30717eff543078a5d94ae9d6c18a5', + display_name: 'Lesson 1 - Getting Started', + }, + { + url: '/course/course-v1:edX+DemoX+Demo_Course?show=block-v1%3AedX%2BDemoX%2BDemo_Course%2Btype%40sequential%2Bblock%40basic_questions', + display_name: 'Homework - Question Styles', + }, + ], + title: 'Lesson 1 - Getting Started', + is_last: true, + }, + ], + component_templates: [ + { + type: 'advanced', + templates: [ + { + display_name: 'Annotation', + category: 'annotatable', + boilerplate_name: null, + hinted: false, + tab: 'common', + support_level: true, + }, + { + display_name: 'Video', + category: 'videoalpha', + boilerplate_name: null, + hinted: false, + tab: 'common', + support_level: true, + }, + ], + display_name: 'Advanced', + support_legend: { + show_legend: false, + allow_unsupported_xblocks: false, + documentation_label: 'Your Platform Name Here Support Levels:', + }, + }, + { + type: 'discussion', + templates: [ + { + display_name: 'Discussion', + category: 'discussion', + boilerplate_name: null, + hinted: false, + tab: 'advanced', + support_level: true, + }, + ], + display_name: 'Discussion', + support_legend: { + show_legend: false, + allow_unsupported_xblocks: false, + documentation_label: 'Your Platform Name Here Support Levels:', + }, + }, + { + type: 'library', + templates: [ + { + display_name: 'Randomized Content Block', + category: 'library_content', + boilerplate_name: null, + hinted: false, + tab: 'common', + support_level: true, + }, + ], + display_name: 'Library Content', + support_legend: { + show_legend: false, + allow_unsupported_xblocks: false, + documentation_label: 'Your Platform Name Here Support Levels:', + }, + }, + { + type: 'html', + templates: [ + { + display_name: 'Text', + category: 'html', + boilerplate_name: null, + hinted: false, + tab: 'advanced', + support_level: true, + }, + { + display_name: 'Raw HTML', + category: 'html', + boilerplate_name: 'raw.yaml', + hinted: false, + tab: 'advanced', + support_level: true, + }, + { + display_name: 'Zooming Image Tool', + category: 'html', + boilerplate_name: 'zooming_image.yaml', + hinted: false, + tab: 'advanced', + support_level: true, + }, + { + display_name: 'IFrame Tool', + category: 'html', + boilerplate_name: 'iframe.yaml', + hinted: false, + tab: 'advanced', + support_level: true, + }, + { + display_name: 'Anonymous User ID', + category: 'html', + boilerplate_name: 'anon_user_id.yaml', + hinted: false, + tab: 'advanced', + support_level: true, + }, + { + display_name: 'Announcement', + category: 'html', + boilerplate_name: 'announcement.yaml', + hinted: false, + tab: 'advanced', + support_level: true, + }, + ], + display_name: 'Text', + support_legend: { + show_legend: false, + allow_unsupported_xblocks: false, + documentation_label: 'Your Platform Name Here Support Levels:', + }, + }, + { + type: 'openassessment', + templates: [ + { + display_name: 'Peer Assessment Only', + category: 'openassessment', + boilerplate_name: 'peer-assessment', + hinted: false, + tab: 'advanced', + support_level: true, + }, + { + display_name: 'Self Assessment Only', + category: 'openassessment', + boilerplate_name: 'self-assessment', + hinted: false, + tab: 'advanced', + support_level: true, + }, + { + display_name: 'Staff Assessment Only', + category: 'openassessment', + boilerplate_name: 'staff-assessment', + hinted: false, + tab: 'advanced', + support_level: true, + }, + { + display_name: 'Self Assessment to Peer Assessment', + category: 'openassessment', + boilerplate_name: 'self-to-peer', + hinted: false, + tab: 'advanced', + support_level: true, + }, + { + display_name: 'Self Assessment to Staff Assessment', + category: 'openassessment', + boilerplate_name: 'self-to-staff', + hinted: false, + tab: 'advanced', + support_level: true, + }, + ], + display_name: 'Open Response', + support_legend: { + show_legend: false, + allow_unsupported_xblocks: false, + documentation_label: 'Your Platform Name Here Support Levels:', + }, + }, + { + type: 'problem', + templates: [ + { + display_name: 'Blank Common Problem', + category: 'problem', + boilerplate_name: 'blank_common.yaml', + hinted: false, + tab: 'common', + support_level: true, + }, + ], + display_name: 'Problem', + support_legend: { + show_legend: false, + allow_unsupported_xblocks: false, + documentation_label: 'Your Platform Name Here Support Levels:', + }, + }, + { + type: 'video', + templates: [ + { + display_name: 'Video', + category: 'video', + boilerplate_name: null, + hinted: false, + tab: 'advanced', + support_level: true, + }, + ], + display_name: 'Video', + support_legend: { + show_legend: false, + allow_unsupported_xblocks: false, + documentation_label: 'Your Platform Name Here Support Levels:', + }, + }, + { + type: 'drag-and-drop-v2', + templates: [ + { + display_name: 'Drag and Drop', + category: 'drag-and-drop-v2', + boilerplate_name: null, + hinted: false, + tab: 'advanced', + support_level: true, + }, + ], + display_name: 'Drag and Drop', + support_legend: { + show_legend: false, + allow_unsupported_xblocks: false, + documentation_label: 'Your Platform Name Here Support Levels:', + }, + }, + ], + xblock_info: { + id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@867dddb6f55d410caaa9c1eb9c6743ec', + display_name: 'Getting Started', + category: 'vertical', + has_children: true, + edited_on: 'Jan 04, 2024 at 10:32 UTC', + published: true, + published_on: 'Dec 28, 2023 at 10:00 UTC', + studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@867dddb6f55d410caaa9c1eb9c6743ec', + released_to_students: true, + release_date: 'Feb 05, 2013 at 05:00 UTC', + visibility_state: 'needs_attention', + has_explicit_staff_lock: false, + start: '2013-02-05T05:00:00Z', + graded: false, + due_date: '', + due: null, + relative_weeks_due: null, + format: null, + course_graders: [ + 'Homework', + 'Exam', + ], + has_changes: true, + actions: { + deletable: true, + draggable: true, + childAddable: true, + duplicable: true, + }, + explanatory_message: null, + group_access: {}, + user_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + show_correctness: 'always', + discussion_enabled: true, + ancestor_info: { + ancestors: [ + { + id: 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@19a30717eff543078a5d94ae9d6c18a5', + display_name: 'Lesson 1 - Getting Started', + category: 'sequential', + has_children: true, + edited_on: 'Jan 04, 2024 at 10:32 UTC', + published: true, + published_on: 'Dec 28, 2023 at 10:00 UTC', + studio_url: '/course/course-v1:edX+DemoX+Demo_Course?show=block-v1%3AedX%2BDemoX%2BDemo_Course%2Btype%40sequential%2Bblock%4019a30717eff543078a5d94ae9d6c18a5', + released_to_students: true, + release_date: 'Feb 05, 2013 at 05:00 UTC', + visibility_state: 'needs_attention', + has_explicit_staff_lock: false, + start: '2013-02-05T05:00:00Z', + graded: false, + due_date: '', + due: null, + relative_weeks_due: null, + format: null, + course_graders: [ + 'Homework', + 'Exam', + ], + has_changes: null, + actions: { + deletable: true, + draggable: true, + childAddable: true, + duplicable: true, + }, + explanatory_message: null, + group_access: {}, + user_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + show_correctness: 'always', + hide_after_due: false, + is_proctored_exam: false, + was_exam_ever_linked_with_external: false, + online_proctoring_rules: '', + is_practice_exam: false, + is_onboarding_exam: false, + is_time_limited: false, + exam_review_rules: '', + default_time_limit_minutes: null, + proctoring_exam_configuration_link: null, + supports_onboarding: false, + show_review_rules: true, + child_info: { + category: 'vertical', + display_name: 'Unit', + children: [ + { + id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@867dddb6f55d410caaa9c1eb9c6743ec', + display_name: 'Getting Started', + category: 'vertical', + has_children: true, + edited_on: 'Jan 04, 2024 at 10:32 UTC', + published: true, + published_on: 'Dec 28, 2023 at 10:00 UTC', + studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@867dddb6f55d410caaa9c1eb9c6743ec', + released_to_students: true, + release_date: 'Feb 05, 2013 at 05:00 UTC', + visibility_state: 'needs_attention', + has_explicit_staff_lock: false, + start: '2013-02-05T05:00:00Z', + graded: false, + due_date: '', + due: null, + relative_weeks_due: null, + format: null, + course_graders: [ + 'Homework', + 'Exam', + ], + has_changes: true, + actions: { + deletable: true, + draggable: true, + childAddable: true, + duplicable: true, + }, + explanatory_message: null, + group_access: {}, + user_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + show_correctness: 'always', + discussion_enabled: true, + ancestor_has_staff_lock: false, + user_partition_info: { + selectable_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + selected_partition_index: -1, + selected_groups_label: '', + }, + enable_copy_paste_units: false, + }, + { + id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@4f6c1b4e316a419ab5b6bf30e6c708e9', + display_name: 'Working with Videos', + category: 'vertical', + has_children: true, + edited_on: 'Dec 28, 2023 at 10:00 UTC', + published: true, + published_on: 'Dec 28, 2023 at 10:00 UTC', + studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@4f6c1b4e316a419ab5b6bf30e6c708e9', + released_to_students: true, + release_date: 'Feb 05, 2013 at 05:00 UTC', + visibility_state: 'live', + has_explicit_staff_lock: false, + start: '2013-02-05T05:00:00Z', + graded: false, + due_date: '', + due: null, + relative_weeks_due: null, + format: null, + course_graders: [ + 'Homework', + 'Exam', + ], + has_changes: false, + actions: { + deletable: true, + draggable: true, + childAddable: true, + duplicable: true, + }, + explanatory_message: null, + group_access: {}, + user_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + show_correctness: 'always', + discussion_enabled: true, + ancestor_has_staff_lock: false, + user_partition_info: { + selectable_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + selected_partition_index: -1, + selected_groups_label: '', + }, + enable_copy_paste_units: false, + }, + { + id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@3dc16db8d14842e38324e95d4030b8a0', + display_name: 'Videos on edX', + category: 'vertical', + has_children: true, + edited_on: 'Dec 28, 2023 at 10:00 UTC', + published: true, + published_on: 'Dec 28, 2023 at 10:00 UTC', + studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@3dc16db8d14842e38324e95d4030b8a0', + released_to_students: true, + release_date: 'Feb 05, 2013 at 05:00 UTC', + visibility_state: 'live', + has_explicit_staff_lock: false, + start: '2013-02-05T05:00:00Z', + graded: false, + due_date: '', + due: null, + relative_weeks_due: null, + format: null, + course_graders: [ + 'Homework', + 'Exam', + ], + has_changes: false, + actions: { + deletable: true, + draggable: true, + childAddable: true, + duplicable: true, + }, + explanatory_message: null, + group_access: {}, + user_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + show_correctness: 'always', + discussion_enabled: true, + ancestor_has_staff_lock: false, + user_partition_info: { + selectable_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + selected_partition_index: -1, + selected_groups_label: '', + }, + enable_copy_paste_units: false, + }, + { + id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@4a1bba2a403f40bca5ec245e945b0d76', + display_name: 'Video Demonstrations', + category: 'vertical', + has_children: true, + edited_on: 'Dec 28, 2023 at 10:00 UTC', + published: true, + published_on: 'Dec 28, 2023 at 10:00 UTC', + studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@4a1bba2a403f40bca5ec245e945b0d76', + released_to_students: true, + release_date: 'Feb 05, 2013 at 05:00 UTC', + visibility_state: 'live', + has_explicit_staff_lock: false, + start: '2013-02-05T05:00:00Z', + graded: false, + due_date: '', + due: null, + relative_weeks_due: null, + format: null, + course_graders: [ + 'Homework', + 'Exam', + ], + has_changes: false, + actions: { + deletable: true, + draggable: true, + childAddable: true, + duplicable: true, + }, + explanatory_message: null, + group_access: {}, + user_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + show_correctness: 'always', + discussion_enabled: true, + ancestor_has_staff_lock: false, + user_partition_info: { + selectable_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + selected_partition_index: -1, + selected_groups_label: '', + }, + enable_copy_paste_units: false, + }, + { + id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@256f17a44983429fb1a60802203ee4e0', + display_name: 'Video Presentation Styles', + category: 'vertical', + has_children: true, + edited_on: 'Dec 28, 2023 at 10:00 UTC', + published: true, + published_on: 'Dec 28, 2023 at 10:00 UTC', + studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@256f17a44983429fb1a60802203ee4e0', + released_to_students: true, + release_date: 'Feb 05, 2013 at 05:00 UTC', + visibility_state: 'live', + has_explicit_staff_lock: false, + start: '2013-02-05T05:00:00Z', + graded: false, + due_date: '', + due: null, + relative_weeks_due: null, + format: null, + course_graders: [ + 'Homework', + 'Exam', + ], + has_changes: false, + actions: { + deletable: true, + draggable: true, + childAddable: true, + duplicable: true, + }, + explanatory_message: null, + group_access: {}, + user_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + show_correctness: 'always', + discussion_enabled: true, + ancestor_has_staff_lock: false, + user_partition_info: { + selectable_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + selected_partition_index: -1, + selected_groups_label: '', + }, + enable_copy_paste_units: false, + }, + { + id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@e3601c0abee6427d8c17e6d6f8fdddd1', + display_name: 'Interactive Questions', + category: 'vertical', + has_children: true, + edited_on: 'Dec 28, 2023 at 10:00 UTC', + published: true, + published_on: 'Dec 28, 2023 at 10:00 UTC', + studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@e3601c0abee6427d8c17e6d6f8fdddd1', + released_to_students: true, + release_date: 'Feb 05, 2013 at 05:00 UTC', + visibility_state: 'live', + has_explicit_staff_lock: false, + start: '2013-02-05T05:00:00Z', + graded: false, + due_date: '', + due: null, + relative_weeks_due: null, + format: null, + course_graders: [ + 'Homework', + 'Exam', + ], + has_changes: false, + actions: { + deletable: true, + draggable: true, + childAddable: true, + duplicable: true, + }, + explanatory_message: null, + group_access: {}, + user_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + show_correctness: 'always', + discussion_enabled: true, + ancestor_has_staff_lock: false, + user_partition_info: { + selectable_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + selected_partition_index: -1, + selected_groups_label: '', + }, + enable_copy_paste_units: false, + }, + { + id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@a79d59cd72034188a71d388f4954a606', + display_name: 'Exciting Labs and Tools', + category: 'vertical', + has_children: true, + edited_on: 'Dec 28, 2023 at 10:00 UTC', + published: true, + published_on: 'Dec 28, 2023 at 10:00 UTC', + studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@a79d59cd72034188a71d388f4954a606', + released_to_students: true, + release_date: 'Feb 05, 2013 at 05:00 UTC', + visibility_state: 'live', + has_explicit_staff_lock: false, + start: '2013-02-05T05:00:00Z', + graded: false, + due_date: '', + due: null, + relative_weeks_due: null, + format: null, + course_graders: [ + 'Homework', + 'Exam', + ], + has_changes: false, + actions: { + deletable: true, + draggable: true, + childAddable: true, + duplicable: true, + }, + explanatory_message: null, + group_access: {}, + user_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + show_correctness: 'always', + discussion_enabled: true, + ancestor_has_staff_lock: false, + user_partition_info: { + selectable_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + selected_partition_index: -1, + selected_groups_label: '', + }, + enable_copy_paste_units: false, + }, + { + id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@134df56c516a4a0dbb24dd5facef746e', + display_name: 'Reading Assignments', + category: 'vertical', + has_children: true, + edited_on: 'Dec 28, 2023 at 10:00 UTC', + published: true, + published_on: 'Dec 28, 2023 at 10:00 UTC', + studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@134df56c516a4a0dbb24dd5facef746e', + released_to_students: true, + release_date: 'Feb 05, 2013 at 05:00 UTC', + visibility_state: 'live', + has_explicit_staff_lock: false, + start: '2013-02-05T05:00:00Z', + graded: false, + due_date: '', + due: null, + relative_weeks_due: null, + format: null, + course_graders: [ + 'Homework', + 'Exam', + ], + has_changes: false, + actions: { + deletable: true, + draggable: true, + childAddable: true, + duplicable: true, + }, + explanatory_message: null, + group_access: {}, + user_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + show_correctness: 'always', + discussion_enabled: true, + ancestor_has_staff_lock: false, + user_partition_info: { + selectable_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + selected_partition_index: -1, + selected_groups_label: '', + }, + enable_copy_paste_units: false, + }, + { + id: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@d91b9e5d8bc64d57a1332d06bf2f2193', + display_name: 'When Are Your Exams? ', + category: 'vertical', + has_children: true, + edited_on: 'Dec 28, 2023 at 10:00 UTC', + published: true, + published_on: 'Dec 28, 2023 at 10:00 UTC', + studio_url: '/container/block-v1:edX+DemoX+Demo_Course+type@vertical+block@d91b9e5d8bc64d57a1332d06bf2f2193', + released_to_students: true, + release_date: 'Feb 05, 2013 at 05:00 UTC', + visibility_state: 'live', + has_explicit_staff_lock: false, + start: '2013-02-05T05:00:00Z', + graded: false, + due_date: '', + due: null, + relative_weeks_due: null, + format: null, + course_graders: [ + 'Homework', + 'Exam', + ], + has_changes: false, + actions: { + deletable: true, + draggable: true, + childAddable: true, + duplicable: true, + }, + explanatory_message: null, + group_access: {}, + user_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + show_correctness: 'always', + discussion_enabled: true, + ancestor_has_staff_lock: false, + user_partition_info: { + selectable_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + selected_partition_index: -1, + selected_groups_label: '', + }, + enable_copy_paste_units: false, + }, + ], + }, + ancestor_has_staff_lock: false, + user_partition_info: { + selectable_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + selected_partition_index: -1, + selected_groups_label: '', + }, + }, + { + id: 'block-v1:edX+DemoX+Demo_Course+type@chapter+block@interactive_demonstrations', + display_name: 'Example Week 1: Getting Started', + category: 'chapter', + has_children: true, + edited_on: 'Jan 04, 2024 at 10:32 UTC', + published: true, + published_on: 'Dec 28, 2023 at 10:00 UTC', + studio_url: '/course/course-v1:edX+DemoX+Demo_Course?show=block-v1%3AedX%2BDemoX%2BDemo_Course%2Btype%40chapter%2Bblock%40interactive_demonstrations', + released_to_students: true, + release_date: 'Feb 05, 2013 at 05:00 UTC', + visibility_state: 'live', + has_explicit_staff_lock: false, + start: '2013-02-05T05:00:00Z', + graded: false, + due_date: '', + due: null, + relative_weeks_due: null, + format: null, + course_graders: [ + 'Homework', + 'Exam', + ], + has_changes: null, + actions: { + deletable: true, + draggable: true, + childAddable: true, + duplicable: true, + }, + explanatory_message: null, + group_access: {}, + user_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + show_correctness: 'always', + highlights: [], + highlights_enabled: true, + highlights_preview_only: false, + highlights_doc_url: 'http://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/en/latest/developing_course/course_sections.html#set-section-highlights-for-weekly-course-highlight-messages', + ancestor_has_staff_lock: false, + user_partition_info: { + selectable_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + selected_partition_index: -1, + selected_groups_label: '', + }, + }, + { + id: 'block-v1:edX+DemoX+Demo_Course+type@course+block@course', + display_name: 'Demonstration Course', + category: 'course', + has_children: true, + unit_level_discussions: false, + edited_on: 'Jan 08, 2024 at 16:39 UTC', + published: true, + published_on: 'Jan 08, 2024 at 16:39 UTC', + studio_url: '/course/course-v1:edX+DemoX+Demo_Course', + released_to_students: true, + release_date: 'Feb 05, 2013 at 05:00 UTC', + visibility_state: null, + has_explicit_staff_lock: false, + start: '2013-02-05T05:00:00Z', + graded: false, + due_date: '', + due: null, + relative_weeks_due: null, + format: null, + course_graders: [ + 'Homework', + 'Exam', + ], + has_changes: null, + actions: { + deletable: true, + draggable: true, + childAddable: true, + duplicable: true, + }, + explanatory_message: null, + group_access: {}, + user_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + show_correctness: 'always', + highlights_enabled_for_messaging: false, + highlights_enabled: true, + highlights_preview_only: false, + highlights_doc_url: 'http://edx.readthedocs.io/projects/open-edx-building-and-running-a-course/en/latest/developing_course/course_sections.html#set-section-highlights-for-weekly-course-highlight-messages', + enable_proctored_exams: false, + create_zendesk_tickets: true, + enable_timed_exams: true, + ancestor_has_staff_lock: false, + user_partition_info: { + selectable_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + selected_partition_index: -1, + selected_groups_label: '', + }, + }, + ], + }, + ancestor_has_staff_lock: false, + user_partition_info: { + selectable_partitions: [ + { + id: 50, + name: 'Enrollment Track Groups', + scheme: 'enrollment_track', + groups: [ + { + id: 2, + name: 'Verified Certificate', + selected: false, + deleted: false, + }, + { + id: 1, + name: 'Audit', + selected: false, + deleted: false, + }, + ], + }, + ], + selected_partition_index: -1, + selected_groups_label: '', + }, + enable_copy_paste_units: false, + edited_by: 'edx', + published_by: null, + currently_visible_to_students: true, + has_partition_group_components: false, + release_date_from: 'Section "Example Week 1: Getting Started"', + staff_lock_from: null, + }, + draft_preview_link: '//preview.localhost:18000/courses/course-v1:edX+DemoX+Demo_Course/jump_to/block-v1:edX+DemoX+Demo_Course+type@vertical+block@867dddb6f55d410caaa9c1eb9c6743ec', + published_preview_link: '//localhost:18000/courses/course-v1:edX+DemoX+Demo_Course/jump_to/block-v1:edX+DemoX+Demo_Course+type@vertical+block@867dddb6f55d410caaa9c1eb9c6743ec', + show_unit_tags: false, + user_clipboard: { + content: null, + source_usage_key: '', + source_context_title: '', + source_edit_url: '', + }, + is_fullwidth_content: false, + assets_url: '/assets/course-v1:edX+DemoX+Demo_Course/', + unit_block_id: '867dddb6f55d410caaa9c1eb9c6743ec', + subsection_location: 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@19a30717eff543078a5d94ae9d6c18a5', +}; diff --git a/src/course-unit/__mocks__/index.js b/src/course-unit/__mocks__/index.js index ebf5206845..dbf4d113b3 100644 --- a/src/course-unit/__mocks__/index.js +++ b/src/course-unit/__mocks__/index.js @@ -1,2 +1,2 @@ -/* eslint-disable import/prefer-default-export */ export { default as courseUnitIndexMock } from './courseUnitIndex'; +export { default as courseSectionVerticalMock } from './courseSectionVertical'; diff --git a/src/course-unit/add-component/AddComponent.jsx b/src/course-unit/add-component/AddComponent.jsx new file mode 100644 index 0000000000..5a03e2e874 --- /dev/null +++ b/src/course-unit/add-component/AddComponent.jsx @@ -0,0 +1,35 @@ +import { useSelector } from 'react-redux'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Button } from '@edx/paragon'; + +import { getCourseSectionVertical } from '../data/selectors'; +import ComponentIcon from './ComponentIcon'; +import messages from './messages'; + +const AddComponent = () => { + const intl = useIntl(); + const { componentTemplates } = useSelector(getCourseSectionVertical); + + if (!Object.keys(componentTemplates).length) { + return null; + } + + return ( +
+
{intl.formatMessage(messages.title)}
+
    + {Object.keys(componentTemplates).map((component) => ( +
  • + +
  • + ))} +
+
+ ); +}; + +export default AddComponent; diff --git a/src/course-unit/add-component/AddComponent.scss b/src/course-unit/add-component/AddComponent.scss new file mode 100644 index 0000000000..aba0a04e1c --- /dev/null +++ b/src/course-unit/add-component/AddComponent.scss @@ -0,0 +1,12 @@ +.course-unit { + .new-component-type { + gap: .75rem; + } + + .add-component-button { + @include pgn-box-shadow(1, "down"); + + width: 11.63rem; + height: 6.875rem; + } +} diff --git a/src/course-unit/add-component/AddComponent.test.jsx b/src/course-unit/add-component/AddComponent.test.jsx new file mode 100644 index 0000000000..eaff9da870 --- /dev/null +++ b/src/course-unit/add-component/AddComponent.test.jsx @@ -0,0 +1,59 @@ +import MockAdapter from 'axios-mock-adapter'; +import { render } from '@testing-library/react'; + +import { initializeMockApp } from '@edx/frontend-platform'; +import { AppProvider } from '@edx/frontend-platform/react'; +import { IntlProvider } from '@edx/frontend-platform/i18n'; +import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; + +import initializeStore from '../../store'; +import { executeThunk } from '../../utils'; +import { fetchCourseSectionVerticalData } from '../data/thunk'; +import { getCourseSectionVerticalApiUrl } from '../data/api'; +import { courseSectionVerticalMock } from '../__mocks__'; +import AddComponent from './AddComponent'; +import messages from './messages'; + +let store; +let axiosMock; +const blockId = '123'; + +const renderComponent = (props) => render( + + + + + , +); + +describe('', () => { + beforeEach(async () => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + + store = initializeStore(); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + axiosMock + .onGet(getCourseSectionVerticalApiUrl(blockId)) + .reply(200, courseSectionVerticalMock); + await executeThunk(fetchCourseSectionVerticalData(blockId), store.dispatch); + }); + + it('render AddComponent component correctly', () => { + const { getByRole } = renderComponent(); + const componentTemplates = courseSectionVerticalMock.component_templates; + + expect(getByRole('heading', { name: messages.title.defaultMessage })).toBeInTheDocument(); + Object.keys(componentTemplates).map((component) => ( + expect(getByRole('button', { + name: new RegExp(`${messages.buttonText.defaultMessage} ${componentTemplates[component].display_name}`, 'i'), + })).toBeInTheDocument() + )); + }); +}); diff --git a/src/course-unit/add-component/ComponentIcon.jsx b/src/course-unit/add-component/ComponentIcon.jsx new file mode 100644 index 0000000000..0fe9321334 --- /dev/null +++ b/src/course-unit/add-component/ComponentIcon.jsx @@ -0,0 +1,17 @@ +import PropTypes from 'prop-types'; +import { Icon } from '@edx/paragon'; +import { EditNote as EditNoteIcon } from '@edx/paragon/icons'; + +import { COMPONENT_TYPE_ICON_MAP, COMPONENT_ICON_TYPES } from '../constants'; + +const ComponentIcon = ({ type }) => { + const icon = COMPONENT_TYPE_ICON_MAP[type] || EditNoteIcon; + + return ; +}; + +ComponentIcon.propTypes = { + type: PropTypes.oneOf(COMPONENT_ICON_TYPES).isRequired, +}; + +export default ComponentIcon; diff --git a/src/course-unit/add-component/messages.js b/src/course-unit/add-component/messages.js new file mode 100644 index 0000000000..94e6bf4833 --- /dev/null +++ b/src/course-unit/add-component/messages.js @@ -0,0 +1,14 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + title: { + id: 'course-authoring.course-unit.add.component.title', + defaultMessage: 'Add a new component', + }, + buttonText: { + id: 'course-authoring.course-unit.add.component.button.text', + defaultMessage: 'Add Component:', + }, +}); + +export default messages; diff --git a/src/course-unit/constants.js b/src/course-unit/constants.js index c35d980d1b..c2fbe49add 100644 --- a/src/course-unit/constants.js +++ b/src/course-unit/constants.js @@ -1,13 +1,21 @@ import { + BackHand as BackHandIcon, BookOpen as BookOpenIcon, Edit as EditIcon, FormatListBulleted as FormatListBulletedIcon, + HelpOutline as HelpOutlineIcon, + LibraryAdd as LibraryIcon, Lock as LockIcon, + QuestionAnswerOutline as QuestionAnswerOutlineIcon, + Science as ScienceIcon, + TextFields as TextFieldsIcon, VideoCamera as VideoCameraIcon, } from '@edx/paragon/icons'; export const UNIT_ICON_TYPES = ['video', 'other', 'vertical', 'problem', 'lock']; +export const COMPONENT_ICON_TYPES = ['advanced', 'discussion', 'library', 'openassessment', 'problem', 'video', 'drag-and-drop-v2']; + export const TYPE_ICONS_MAP = { video: VideoCameraIcon, other: BookOpenIcon, @@ -15,3 +23,14 @@ export const TYPE_ICONS_MAP = { problem: EditIcon, lock: LockIcon, }; + +export const COMPONENT_TYPE_ICON_MAP = { + advanced: ScienceIcon, + discussion: QuestionAnswerOutlineIcon, + library: LibraryIcon, + html: TextFieldsIcon, + openassessment: EditIcon, + problem: HelpOutlineIcon, + video: VideoCameraIcon, + 'drag-and-drop-v2': BackHandIcon, +}; diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index 393a9019a3..0c24ccbd7f 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -989,5 +989,7 @@ "course-authoring.course-unit.sequence-nav-label-text": "Sequence navigation", "course-authoring.course-unit.sequence.load.failure": "There was an error loading this course.", "course-authoring.course-unit.sequence.no.content": "There is no content here.", - "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}" + "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}", + "course-authoring.course-unit.add.component.title": "Add a new component", + "course-authoring.course-unit.add.component.button.text": "Add Component:" } diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index 09c7da1eb7..2500a14407 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -989,5 +989,7 @@ "course-authoring.course-unit.sequence-nav-label-text": "Sequence navigation", "course-authoring.course-unit.sequence.load.failure": "There was an error loading this course.", "course-authoring.course-unit.sequence.no.content": "There is no content here.", - "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}" + "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}", + "course-authoring.course-unit.add.component.title": "Add a new component", + "course-authoring.course-unit.add.component.button.text": "Add Component:" } diff --git a/src/i18n/messages/de_DE.json b/src/i18n/messages/de_DE.json index 0286fe7a06..de185d7071 100644 --- a/src/i18n/messages/de_DE.json +++ b/src/i18n/messages/de_DE.json @@ -989,5 +989,7 @@ "course-authoring.course-unit.sequence-nav-label-text": "Sequence navigation", "course-authoring.course-unit.sequence.load.failure": "There was an error loading this course.", "course-authoring.course-unit.sequence.no.content": "There is no content here.", - "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}" + "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}", + "course-authoring.course-unit.add.component.title": "Add a new component", + "course-authoring.course-unit.add.component.button.text": "Add Component:" } diff --git a/src/i18n/messages/es_419.json b/src/i18n/messages/es_419.json index c59fa68499..7999fe94ae 100644 --- a/src/i18n/messages/es_419.json +++ b/src/i18n/messages/es_419.json @@ -989,5 +989,7 @@ "course-authoring.course-unit.sequence-nav-label-text": "Sequence navigation", "course-authoring.course-unit.sequence.load.failure": "There was an error loading this course.", "course-authoring.course-unit.sequence.no.content": "There is no content here.", - "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}" + "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}", + "course-authoring.course-unit.add.component.title": "Add a new component", + "course-authoring.course-unit.add.component.button.text": "Add Component:" } diff --git a/src/i18n/messages/fa_IR.json b/src/i18n/messages/fa_IR.json index a8ef072f6d..bafa9a9fb7 100644 --- a/src/i18n/messages/fa_IR.json +++ b/src/i18n/messages/fa_IR.json @@ -12,5 +12,7 @@ "course-authoring.course-unit.sequence-nav-label-text": "Sequence navigation", "course-authoring.course-unit.sequence.load.failure": "There was an error loading this course.", "course-authoring.course-unit.sequence.no.content": "There is no content here.", - "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}" + "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}", + "course-authoring.course-unit.add.component.title": "Add a new component", + "course-authoring.course-unit.add.component.button.text": "Add Component:" } diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index e91037042e..da68eb6719 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -989,5 +989,7 @@ "course-authoring.course-unit.sequence-nav-label-text": "Sequence navigation", "course-authoring.course-unit.sequence.load.failure": "There was an error loading this course.", "course-authoring.course-unit.sequence.no.content": "There is no content here.", - "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}" + "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}", + "course-authoring.course-unit.add.component.title": "Add a new component", + "course-authoring.course-unit.add.component.button.text": "Add Component:" } diff --git a/src/i18n/messages/fr_CA.json b/src/i18n/messages/fr_CA.json index f3251fbbb0..ca1e8b4152 100644 --- a/src/i18n/messages/fr_CA.json +++ b/src/i18n/messages/fr_CA.json @@ -989,5 +989,7 @@ "course-authoring.course-unit.sequence-nav-label-text": "Sequence navigation", "course-authoring.course-unit.sequence.load.failure": "There was an error loading this course.", "course-authoring.course-unit.sequence.no.content": "There is no content here.", - "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}" + "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}", + "course-authoring.course-unit.add.component.title": "Add a new component", + "course-authoring.course-unit.add.component.button.text": "Add Component:" } diff --git a/src/i18n/messages/hi.json b/src/i18n/messages/hi.json index 09c7da1eb7..2500a14407 100644 --- a/src/i18n/messages/hi.json +++ b/src/i18n/messages/hi.json @@ -989,5 +989,7 @@ "course-authoring.course-unit.sequence-nav-label-text": "Sequence navigation", "course-authoring.course-unit.sequence.load.failure": "There was an error loading this course.", "course-authoring.course-unit.sequence.no.content": "There is no content here.", - "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}" + "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}", + "course-authoring.course-unit.add.component.title": "Add a new component", + "course-authoring.course-unit.add.component.button.text": "Add Component:" } diff --git a/src/i18n/messages/it.json b/src/i18n/messages/it.json index 09c7da1eb7..2500a14407 100644 --- a/src/i18n/messages/it.json +++ b/src/i18n/messages/it.json @@ -989,5 +989,7 @@ "course-authoring.course-unit.sequence-nav-label-text": "Sequence navigation", "course-authoring.course-unit.sequence.load.failure": "There was an error loading this course.", "course-authoring.course-unit.sequence.no.content": "There is no content here.", - "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}" + "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}", + "course-authoring.course-unit.add.component.title": "Add a new component", + "course-authoring.course-unit.add.component.button.text": "Add Component:" } diff --git a/src/i18n/messages/it_IT.json b/src/i18n/messages/it_IT.json index 21f4b2660f..333f18723d 100644 --- a/src/i18n/messages/it_IT.json +++ b/src/i18n/messages/it_IT.json @@ -989,5 +989,7 @@ "course-authoring.course-unit.sequence-nav-label-text": "Sequence navigation", "course-authoring.course-unit.sequence.load.failure": "There was an error loading this course.", "course-authoring.course-unit.sequence.no.content": "There is no content here.", - "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}" + "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}", + "course-authoring.course-unit.add.component.title": "Add a new component", + "course-authoring.course-unit.add.component.button.text": "Add Component:" } diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index 09c7da1eb7..2500a14407 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -989,5 +989,7 @@ "course-authoring.course-unit.sequence-nav-label-text": "Sequence navigation", "course-authoring.course-unit.sequence.load.failure": "There was an error loading this course.", "course-authoring.course-unit.sequence.no.content": "There is no content here.", - "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}" + "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}", + "course-authoring.course-unit.add.component.title": "Add a new component", + "course-authoring.course-unit.add.component.button.text": "Add Component:" } diff --git a/src/i18n/messages/pt_PT.json b/src/i18n/messages/pt_PT.json index b447c987fd..c281896c81 100644 --- a/src/i18n/messages/pt_PT.json +++ b/src/i18n/messages/pt_PT.json @@ -989,5 +989,7 @@ "course-authoring.course-unit.sequence-nav-label-text": "Sequence navigation", "course-authoring.course-unit.sequence.load.failure": "There was an error loading this course.", "course-authoring.course-unit.sequence.no.content": "There is no content here.", - "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}" + "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}", + "course-authoring.course-unit.add.component.title": "Add a new component", + "course-authoring.course-unit.add.component.button.text": "Add Component:" } diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json index 09c7da1eb7..2500a14407 100644 --- a/src/i18n/messages/ru.json +++ b/src/i18n/messages/ru.json @@ -989,5 +989,7 @@ "course-authoring.course-unit.sequence-nav-label-text": "Sequence navigation", "course-authoring.course-unit.sequence.load.failure": "There was an error loading this course.", "course-authoring.course-unit.sequence.no.content": "There is no content here.", - "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}" + "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}", + "course-authoring.course-unit.add.component.title": "Add a new component", + "course-authoring.course-unit.add.component.button.text": "Add Component:" } diff --git a/src/i18n/messages/uk.json b/src/i18n/messages/uk.json index 09c7da1eb7..2500a14407 100644 --- a/src/i18n/messages/uk.json +++ b/src/i18n/messages/uk.json @@ -989,5 +989,7 @@ "course-authoring.course-unit.sequence-nav-label-text": "Sequence navigation", "course-authoring.course-unit.sequence.load.failure": "There was an error loading this course.", "course-authoring.course-unit.sequence.no.content": "There is no content here.", - "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}" + "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}", + "course-authoring.course-unit.add.component.title": "Add a new component", + "course-authoring.course-unit.add.component.button.text": "Add Component:" } diff --git a/src/i18n/messages/zh_CN.json b/src/i18n/messages/zh_CN.json index 09c7da1eb7..2500a14407 100644 --- a/src/i18n/messages/zh_CN.json +++ b/src/i18n/messages/zh_CN.json @@ -989,5 +989,7 @@ "course-authoring.course-unit.sequence-nav-label-text": "Sequence navigation", "course-authoring.course-unit.sequence.load.failure": "There was an error loading this course.", "course-authoring.course-unit.sequence.no.content": "There is no content here.", - "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}" + "course-authoring.course-unit.sequence.navigation.menu": "{current} of {total}", + "course-authoring.course-unit.add.component.title": "Add a new component", + "course-authoring.course-unit.add.component.button.text": "Add Component:" } From 0e28829ed852653d17fdb7f60e8c84a440086bc7 Mon Sep 17 00:00:00 2001 From: ihor-romaniuk Date: Tue, 9 Jan 2024 15:36:44 +0100 Subject: [PATCH 2/2] feat: [AXIMST-221] Course unit - use view live and preview links from backend --- .env | 1 - .env.development | 1 - .env.test | 1 - src/course-unit/CourseUnit.test.jsx | 14 +++++++------- src/course-unit/hooks.jsx | 12 +++++------- src/course-unit/utils.jsx | 23 ----------------------- src/index.jsx | 1 - src/setupTest.js | 1 - 8 files changed, 12 insertions(+), 42 deletions(-) delete mode 100644 src/course-unit/utils.jsx diff --git a/.env b/.env index d5cb397aad..9c900c37fb 100644 --- a/.env +++ b/.env @@ -9,7 +9,6 @@ EXAMS_BASE_URL='' FAVICON_URL='' LANGUAGE_PREFERENCE_COOKIE_NAME='' LMS_BASE_URL='' -PREVIEW_BASE_URL='' LEARNING_BASE_URL='' LOGIN_URL='' LOGO_TRADEMARK_URL='' diff --git a/.env.development b/.env.development index 0f1b022a27..e0350715d9 100644 --- a/.env.development +++ b/.env.development @@ -43,4 +43,3 @@ HOTJAR_VERSION=6 HOTJAR_DEBUG=true INVITE_STUDENTS_EMAIL_TO="someone@domain.com" AI_TRANSLATIONS_BASE_URL='http://localhost:18760' -PREVIEW_BASE_URL='http://preview.localhost:18000' diff --git a/.env.test b/.env.test index 0689cddb3b..8c810bb90b 100644 --- a/.env.test +++ b/.env.test @@ -8,7 +8,6 @@ EXAMS_BASE_URL= FAVICON_URL='https://edx-cdn.org/v3/default/favicon.ico' LANGUAGE_PREFERENCE_COOKIE_NAME='openedx-language-preference' LMS_BASE_URL='http://localhost:18000' -PREVIEW_BASE_URL='http://preview.localhost:18000' LEARNING_BASE_URL='http://localhost:2000' LOGIN_URL='http://localhost:18000/login' LOGO_TRADEMARK_URL=https://edx-cdn.org/v3/default/logo-trademark.svg diff --git a/src/course-unit/CourseUnit.test.jsx b/src/course-unit/CourseUnit.test.jsx index 8143010dfb..3dd1b1e03a 100644 --- a/src/course-unit/CourseUnit.test.jsx +++ b/src/course-unit/CourseUnit.test.jsx @@ -5,7 +5,7 @@ import { import userEvent from '@testing-library/user-event'; import { IntlProvider } from '@edx/frontend-platform/i18n'; import { AppProvider } from '@edx/frontend-platform/react'; -import { getConfig, initializeMockApp } from '@edx/frontend-platform'; +import { initializeMockApp } from '@edx/frontend-platform'; import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { @@ -26,12 +26,10 @@ import { executeThunk } from '../utils'; import CourseUnit from './CourseUnit'; import headerNavigationsMessages from './header-navigations/messages'; import headerTitleMessages from './header-title/messages'; -import { getUnitPreviewPath, getUnitViewLivePath } from './utils'; let axiosMock; let store; const courseId = '123'; -const sectionId = '19a30717eff543078a5d94ae9d6c18a5'; const blockId = '567890'; const unitDisplayName = courseUnitIndexMock.metadata.display_name; @@ -91,19 +89,21 @@ describe('', () => { const { open } = window; window.open = jest.fn(); const { getByRole } = render(); + const { + draft_preview_link: draftPreviewLink, + published_preview_link: publishedPreviewLink, + } = courseSectionVerticalMock; await waitFor(() => { const viewLiveButton = getByRole('button', { name: headerNavigationsMessages.viewLiveButton.defaultMessage }); userEvent.click(viewLiveButton); expect(window.open).toHaveBeenCalled(); - const VIEW_LIVE_LINK = getConfig().LMS_BASE_URL + getUnitViewLivePath(courseId, blockId); - expect(window.open).toHaveBeenCalledWith(VIEW_LIVE_LINK, '_blank'); + expect(window.open).toHaveBeenCalledWith(publishedPreviewLink, '_blank'); const previewButton = getByRole('button', { name: headerNavigationsMessages.previewButton.defaultMessage }); userEvent.click(previewButton); expect(window.open).toHaveBeenCalled(); - const PREVIEW_LINK = getConfig().PREVIEW_BASE_URL + getUnitPreviewPath(courseId, sectionId, blockId); - expect(window.open).toHaveBeenCalledWith(PREVIEW_LINK, '_blank'); + expect(window.open).toHaveBeenCalledWith(draftPreviewLink, '_blank'); }); window.open = open; diff --git a/src/course-unit/hooks.jsx b/src/course-unit/hooks.jsx index 8daa5b7306..c1806f6469 100644 --- a/src/course-unit/hooks.jsx +++ b/src/course-unit/hooks.jsx @@ -1,6 +1,5 @@ -import { useContext, useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { AppContext } from '@edx/frontend-platform/react'; import { useNavigate } from 'react-router-dom'; import { RequestStatus } from '../data/constants'; @@ -12,21 +11,21 @@ import { fetchCourseSectionVerticalData, } from './data/thunk'; import { + getCourseSectionVertical, getCourseUnitData, getLoadingStatus, getSavingStatus, } from './data/selectors'; import { updateSavingStatus } from './data/slice'; -import { getUnitViewLivePath, getUnitPreviewPath } from './utils'; // eslint-disable-next-line import/prefer-default-export export const useCourseUnit = ({ courseId, blockId }) => { const dispatch = useDispatch(); - const { config } = useContext(AppContext); const courseUnit = useSelector(getCourseUnitData); const savingStatus = useSelector(getSavingStatus); const loadingStatus = useSelector(getLoadingStatus); + const { draftPreviewLink, publishedPreviewLink } = useSelector(getCourseSectionVertical); const navigate = useNavigate(); const [isTitleEditFormOpen, toggleTitleEditForm] = useState(false); @@ -35,11 +34,10 @@ export const useCourseUnit = ({ courseId, blockId }) => { const headerNavigationsActions = { handleViewLive: () => { - window.open(config.LMS_BASE_URL + getUnitViewLivePath(courseId, blockId), '_blank'); + window.open(publishedPreviewLink, '_blank'); }, handlePreview: () => { - const sectionId = courseUnit.ancestorInfo?.ancestors[0]?.id.split('@').pop(); - window.open(config.PREVIEW_BASE_URL + getUnitPreviewPath(courseId, sectionId, blockId), '_blank'); + window.open(draftPreviewLink, '_blank'); }, }; diff --git a/src/course-unit/utils.jsx b/src/course-unit/utils.jsx deleted file mode 100644 index 1ead399f71..0000000000 --- a/src/course-unit/utils.jsx +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable max-len */ -// @ts-check - -/** - * Method to return course unit view live URL path. - * @param {string} courseId - * @param {string} blockId - * @returns {string} {`/courses/${string}/jump_to/${string}`} - */ -export const getUnitViewLivePath = (courseId, blockId) => ( - `/courses/${courseId}/jump_to/${blockId}` -); - -/** - * Method to return course unit preview URL path. - * @param {string} courseId - * @param {string} sectionId - * @param {string} blockId - * @returns {string} {`/courses/${courseId}/courseware/interactive_demonstrations/${sectionId}/1?activate_block_id=${blockId}`} - */ -export const getUnitPreviewPath = (courseId, sectionId, blockId) => ( - `/courses/${courseId}/courseware/interactive_demonstrations/${sectionId}/1?activate_block_id=${blockId}` -); diff --git a/src/index.jsx b/src/index.jsx index 18777e342f..7ef042750d 100755 --- a/src/index.jsx +++ b/src/index.jsx @@ -101,7 +101,6 @@ initialize({ SUPPORT_URL: process.env.SUPPORT_URL || null, SUPPORT_EMAIL: process.env.SUPPORT_EMAIL || null, LEARNING_BASE_URL: process.env.LEARNING_BASE_URL, - PREVIEW_BASE_URL: process.env.PREVIEW_BASE_URL, EXAMS_BASE_URL: process.env.EXAMS_BASE_URL || null, CALCULATOR_HELP_URL: process.env.CALCULATOR_HELP_URL || null, ENABLE_PROGRESS_GRAPH_SETTINGS: process.env.ENABLE_PROGRESS_GRAPH_SETTINGS || 'false', diff --git a/src/setupTest.js b/src/setupTest.js index d8ddd45faa..dac2e09566 100755 --- a/src/setupTest.js +++ b/src/setupTest.js @@ -50,7 +50,6 @@ mergeConfig({ CALCULATOR_HELP_URL: process.env.CALCULATOR_HELP_URL || null, ENABLE_PROGRESS_GRAPH_SETTINGS: process.env.ENABLE_PROGRESS_GRAPH_SETTINGS || 'false', ENABLE_TEAM_TYPE_SETTING: process.env.ENABLE_TEAM_TYPE_SETTING === 'true', - PREVIEW_BASE_URL: process.env.PREVIEW_BASE_URL || '', }, 'CourseAuthoringConfig'); // Mock the plugins repo so jest will stop complaining about ES6 syntax