From ced74adff541685cad8bfcfd4cf332cadbdd8cf0 Mon Sep 17 00:00:00 2001 From: andrey-canon Date: Tue, 13 Jun 2023 11:31:47 -0500 Subject: [PATCH] feat: add frontend view for course feedback feat: Add basic frontend configuration fix: move to frontend folder feat: first approx to xp frontend templates fix: extract static folder from course experience fix: render react basic component feat: set environment and add report button feat: add feedback carousel component in template feat: add styles from learning mfe of stage This styles were built by learning mfe. This includes paragon vars that allow give more beauty approach to the component. feat: add paragon styles refactor: move main view to feedback courses view feat: generate final js file by using frontend-build chore: remove unused dependencies and add missing dependency feat: add templates files config feat: add backend for edxmako style: pass isort and pytest feat: change url for frontend courses test: add unittest for edxmako templates This is for course experience feedback templates. feat: add template render extra test style: add docstrings for tests feat: add hash to webpack built to uncache CDN Revert "feat: add hash to webpack built to uncache CDN" This reverts commit cd789c28fe3a9f201ffdf93a541ca754a1ca7f4e. fix: remove extra typo ; rendered in the component chore: pr feedback improve docstring feat: remove unnecessary pasted styles feat: add custom styles to manage feedback title feat: unset background color for body --- .babelrc | 4 + .env.frontend | 42 + .gitignore | 7 + .../course_experience/frontend/__init__.py | 0 .../src/components/FeedbackCarousel/index.jsx | 25 + .../components/FeedbackCarousel/index.scss | 17 + .../frontend/templates/__init__.py | 0 .../frontend/templates/feedback_courses.html | 12 + .../frontend/tests/__init__.py | 0 .../frontend/tests/test_views.py | 58 + eox_nelp/course_experience/frontend/urls.py | 10 + eox_nelp/course_experience/frontend/views.py | 22 + .../edxapp_wrapper/backends/edxmako_m_v1.py | 12 + eox_nelp/edxapp_wrapper/edxmako.py | 16 + .../test_backends/edxmako_m_v1.py | 10 + eox_nelp/settings/common.py | 1 + eox_nelp/settings/test.py | 29 + .../css/feedback_carousel.css | 63 + .../feedback_carousel/js/feedback_carousel.js | 2 + .../js/feedback_carousel.js.LICENSE.txt | 80 + eox_nelp/templates_config.py | 19 + eox_nelp/urls.py | 4 + package-lock.json | 36131 ++++++++++++++++ package.json | 35 + webpack.common.config.js | 35 + webpack.dev.config.js | 7 + webpack.prod.config.js | 7 + 27 files changed, 36648 insertions(+) create mode 100644 .babelrc create mode 100644 .env.frontend create mode 100644 eox_nelp/course_experience/frontend/__init__.py create mode 100644 eox_nelp/course_experience/frontend/src/components/FeedbackCarousel/index.jsx create mode 100644 eox_nelp/course_experience/frontend/src/components/FeedbackCarousel/index.scss create mode 100644 eox_nelp/course_experience/frontend/templates/__init__.py create mode 100644 eox_nelp/course_experience/frontend/templates/feedback_courses.html create mode 100644 eox_nelp/course_experience/frontend/tests/__init__.py create mode 100644 eox_nelp/course_experience/frontend/tests/test_views.py create mode 100644 eox_nelp/course_experience/frontend/urls.py create mode 100644 eox_nelp/course_experience/frontend/views.py create mode 100644 eox_nelp/edxapp_wrapper/backends/edxmako_m_v1.py create mode 100644 eox_nelp/edxapp_wrapper/edxmako.py create mode 100644 eox_nelp/edxapp_wrapper/test_backends/edxmako_m_v1.py create mode 100644 eox_nelp/static/feedback_carousel/css/feedback_carousel.css create mode 100644 eox_nelp/static/feedback_carousel/js/feedback_carousel.js create mode 100644 eox_nelp/static/feedback_carousel/js/feedback_carousel.js.LICENSE.txt create mode 100644 eox_nelp/templates_config.py create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 webpack.common.config.js create mode 100644 webpack.dev.config.js create mode 100644 webpack.prod.config.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..944226d9 --- /dev/null +++ b/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["@babel/preset-env", "@babel/preset-react"], + "plugins": ["@babel/plugin-proposal-class-properties"] +} diff --git a/.env.frontend b/.env.frontend new file mode 100644 index 00000000..a3db8eef --- /dev/null +++ b/.env.frontend @@ -0,0 +1,42 @@ +BASE_URL='http://lms.mango.edunext.link:8000' +ACCESS_TOKEN_COOKIE_NAME='edx-jwt-cookie-header-payload' +LMS_BASE_URL=http://lms.mango.edunext.link:8000 +BASE_URL='http://localhost:2000' +CONTACT_URL='http://lms.mango.edunext.link:8000/contact' +CREDENTIALS_BASE_URL='http://localhost:18150' +CREDIT_HELP_LINK_URL='https://edx.readthedocs.io/projects/edx-guide-for-students/en/latest/SFD_credit_courses.html#keep-track-of-credit-requirements' +CSRF_TOKEN_API_PATH='/csrf/api/v1/token' +DISCOVERY_API_BASE_URL='http://localhost:18381' +DISCUSSIONS_MFE_BASE_URL='http://localhost:2002' +ECOMMERCE_BASE_URL='http://localhost:18130' +ENABLE_JUMPNAV='true' +ENABLE_NOTICES='' +ENTERPRISE_LEARNER_PORTAL_HOSTNAME='localhost:8734' +EXAMS_BASE_URL='http://localhost:18740' +FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico +IGNORED_ERROR_REGEX='' +LANGUAGE_PREFERENCE_COOKIE_NAME='openedx-language-preference' +LOGIN_URL='http://lms.mango.edunext.link:8000/login' +LOGOUT_URL='http://lms.mango.edunext.link:8000/logout' +LOGO_URL='http://lms.mango.edunext.link:8000/theming/asset/images/logo.png' +LOGO_TRADEMARK_URL='http://lms.mango.edunext.link:8000/theming/asset/images/logo.png' +LOGO_WHITE_URL=https://edx-cdn.org/v3/default/logo-white.svg +LEGACY_THEME_NAME='' +MARKETING_SITE_BASE_URL='http://lms.mango.edunext.link:8000' +REFRESH_ACCESS_TOKEN_ENDPOINT='http://lms.mango.edunext.link:8000/login_refresh' +SEARCH_CATALOG_URL='http://lms.mango.edunext.link:8000/courses' +SEGMENT_KEY='' +SITE_NAME='edX' +SOCIAL_UTM_MILESTONE_CAMPAIGN='edxmilestone' +STUDIO_BASE_URL='http://localhost:18010' +SUPPORT_URL='https://support.edx.org' +SUPPORT_URL_CALCULATOR_MATH='https://support.edx.org/hc/en-us/articles/360000038428-Entering-math-expressions-in-assignments-or-the-calculator' +SUPPORT_URL_ID_VERIFICATION='https://support.edx.org/hc/en-us/articles/206503858-How-do-I-verify-my-identity' +SUPPORT_URL_VERIFIED_CERTIFICATE='https://support.edx.org/hc/en-us/articles/206502008-What-is-a-verified-certificate' +TERMS_OF_SERVICE_URL='https://www.edx.org/edx-terms-service' +TWITTER_HASHTAG='myedxjourney' +TWITTER_URL='https://twitter.com/edXOnline' +USER_INFO_COOKIE_NAME='edx-user-info' +SESSION_COOKIE_DOMAIN='mango.edunext.link:8000' +MFE_CONFIG_API_URL=/eox-nelp/api/mfe_config/v1/ +COURSE_EXPERIENCE_API_URL=/eox-nelp/api/experience/v1 diff --git a/.gitignore b/.gitignore index c6c12b5d..56d6f6cb 100644 --- a/.gitignore +++ b/.gitignore @@ -113,3 +113,10 @@ dmypy.json # VS Code .vscode + +# frontend dependencies +/node_modules + +#unnecesary files on frontend build +report.html +eox_nelp/static/*.svg diff --git a/eox_nelp/course_experience/frontend/__init__.py b/eox_nelp/course_experience/frontend/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/eox_nelp/course_experience/frontend/src/components/FeedbackCarousel/index.jsx b/eox_nelp/course_experience/frontend/src/components/FeedbackCarousel/index.jsx new file mode 100644 index 00000000..2a441d70 --- /dev/null +++ b/eox_nelp/course_experience/frontend/src/components/FeedbackCarousel/index.jsx @@ -0,0 +1,25 @@ +import React, { useState} from 'react'; +import ReactDOM from 'react-dom'; +import { APP_INIT_ERROR, APP_READY, subscribe, initialize } from '@edx/frontend-platform'; +import { getLocale, getMessages, IntlProvider } from '@edx/frontend-platform/i18n'; +import { FeedbackCarousel, messages as essentialsMessages } from '@edunext/frontend-essentials' + +import './index.scss'; + + +function LaunchFeedbackCarousel() { + const [locale, setLocale] = useState(getLocale()); + + return ( + + + + ); +} + +subscribe(APP_READY, () => { + ReactDOM.render(, document.getElementById('feedback-courses-carousel')); + +}); + +initialize({ messages: [essentialsMessages]}); diff --git a/eox_nelp/course_experience/frontend/src/components/FeedbackCarousel/index.scss b/eox_nelp/course_experience/frontend/src/components/FeedbackCarousel/index.scss new file mode 100644 index 00000000..8088285c --- /dev/null +++ b/eox_nelp/course_experience/frontend/src/components/FeedbackCarousel/index.scss @@ -0,0 +1,17 @@ +@import "~@edx/brand/paragon/fonts"; +@import "~@edx/brand/paragon/variables"; +@import "~@edx/paragon/scss/core/core"; +@import "~@edx/brand/paragon/overrides"; + +#feedback-courses-carousel .feedback-container .feedback-carousel-title { + margin: 0 0 20px 0; + color: var(--pgn-color-primary-base); +} + +body { + background-color: unset; +} + +.feedback-card { + background: white; +} diff --git a/eox_nelp/course_experience/frontend/templates/__init__.py b/eox_nelp/course_experience/frontend/templates/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/eox_nelp/course_experience/frontend/templates/feedback_courses.html b/eox_nelp/course_experience/frontend/templates/feedback_courses.html new file mode 100644 index 00000000..89c22a1d --- /dev/null +++ b/eox_nelp/course_experience/frontend/templates/feedback_courses.html @@ -0,0 +1,12 @@ +<%namespace name='static' file='static_content.html'/> + + + + Feedback courses general + + + + + + + diff --git a/eox_nelp/course_experience/frontend/tests/__init__.py b/eox_nelp/course_experience/frontend/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/eox_nelp/course_experience/frontend/tests/test_views.py b/eox_nelp/course_experience/frontend/tests/test_views.py new file mode 100644 index 00000000..0f2be030 --- /dev/null +++ b/eox_nelp/course_experience/frontend/tests/test_views.py @@ -0,0 +1,58 @@ +"""This file contains all the test for the course_experience views.py file. +Classes: + CourseExperienceFrontendTestCase: Test CourseExperienceFrontendView template. +""" +from django.apps import apps +from django.http import HttpResponse +from django.shortcuts import render +from django.test import TestCase +from django.urls import reverse +from mock import patch +from rest_framework.test import APIClient + + +class FrontendFeedbackCourseTestCase(TestCase): + """ Test FeedbackCoursesTemplate view """ + + def setUp(self): # pylint: disable=invalid-name + """ + Set base variables and objects across experience test cases. + """ + self.client = APIClient() + self.url_endpoint = reverse("course-experience-frontend:feedback-courses") + + @patch("eox_nelp.templates_config.edxmako") + def test_edxmako_render_correct_call(self, edxmako_mock): + """ Test edxmako functions from edxapp_wrapper are called with the right values. + Expected behavior: + - `edxmako_mock.paths.add_lookup` is called with course_experience_template_path. + (The path of course xp templates is used) + - The get request to the url_endpoint is using the template `feedback_courses.html`. + """ + course_experience_template_path = apps.get_app_config('eox_nelp').path + "/course_experience/frontend/templates" + edxmako_mock.shortcuts.render_to_response.return_value = HttpResponse(content='Template mock') + + self.client.get(self.url_endpoint) + + edxmako_mock.paths.add_lookup.assert_called_with('main', course_experience_template_path) + edxmako_mock.shortcuts.render_to_response.assert_called_with("feedback_courses.html", {}, 'main', None) + + @patch("eox_nelp.course_experience.frontend.views.render_to_response") + def test_feedback_course_template_behaviour(self, render_to_response_mock): + """ The correct rendering of the feedback courses template using the url_endpoint + for frontend feedback courses. + Expected behavior: + - Status code 200. + - Response has the correct title page. + - Response has the main div for feedback courses carousel. + - Response has the correct path to load styles with feedback carrousel css. + - Response has the correct path to load script with feedback carrousel js. + """ + render_to_response_mock.return_value = render(None, "feedback_courses.html") + + response = self.client.get(self.url_endpoint) + + self.assertContains(response, 'Feedback courses general', status_code=200) + self.assertContains(response, '