From 9bc5408a44b095e73f68a8cbc4806667a1e4c7c2 Mon Sep 17 00:00:00 2001 From: pateljannat Date: Mon, 28 Jun 2021 12:52:10 +0530 Subject: [PATCH 01/16] feat: course card redesign --- .../lms/doctype/lms_course/lms_course.json | 21 +- .../lms/doctype/lms_course/lms_course.py | 3 + .../lms/doctype/lms_course_review/__init__.py | 0 .../lms_course_review/lms_course_review.js | 8 + .../lms_course_review/lms_course_review.json | 49 ++++ .../lms_course_review/lms_course_review.py | 8 + .../test_lms_course_review.py | 8 + community/public/css/style.css | 223 +++++++++++++++--- community/public/css/style.less | 33 --- community/public/icons/black-arrow.svg | 3 + community/public/icons/calendar.svg | 3 + community/public/icons/clock.svg | 3 + community/public/icons/rating-filled.svg | 3 + community/public/icons/rating.svg | 3 + community/public/icons/user.svg | 4 + community/public/icons/white-arrow.svg | 3 + community/www/__init__.py | 0 community/www/__pycache__/__init__.py | 0 community/www/batch/__pycache__/__init__.py | 0 community/www/courses/__init__.py | 0 community/www/courses/__pycache__/__init__.py | 0 community/www/courses/index.html | 100 ++++++-- community/www/courses/index.py | 8 +- community/www/dashboard/__init__.py | 0 .../www/dashboard/__pycache__/__init__.py | 0 community/www/hackathons/__init__.py | 0 .../www/hackathons/__pycache__/__init__.py | 0 community/www/hackathons/macros/__init__.py | 0 community/www/home/__init__.py | 0 community/www/home/__pycache__/__init__.py | 0 community/www/macros/__init__.py | 0 community/www/my-courses/__init__.py | 0 .../www/my-courses/__pycache__/__init__.py | 0 community/www/profiles/__init__.py | 0 .../www/profiles/__pycache__/__init__.py | 0 community/www/sketches/__init__.py | 0 .../www/sketches/__pycache__/__init__.py | 0 37 files changed, 389 insertions(+), 94 deletions(-) create mode 100644 community/lms/doctype/lms_course_review/__init__.py create mode 100644 community/lms/doctype/lms_course_review/lms_course_review.js create mode 100644 community/lms/doctype/lms_course_review/lms_course_review.json create mode 100644 community/lms/doctype/lms_course_review/lms_course_review.py create mode 100644 community/lms/doctype/lms_course_review/test_lms_course_review.py create mode 100644 community/public/icons/black-arrow.svg create mode 100644 community/public/icons/calendar.svg create mode 100644 community/public/icons/clock.svg create mode 100644 community/public/icons/rating-filled.svg create mode 100644 community/public/icons/rating.svg create mode 100644 community/public/icons/user.svg create mode 100644 community/public/icons/white-arrow.svg create mode 100644 community/www/__init__.py create mode 100644 community/www/__pycache__/__init__.py create mode 100644 community/www/batch/__pycache__/__init__.py create mode 100644 community/www/courses/__init__.py create mode 100644 community/www/courses/__pycache__/__init__.py create mode 100644 community/www/dashboard/__init__.py create mode 100644 community/www/dashboard/__pycache__/__init__.py create mode 100644 community/www/hackathons/__init__.py create mode 100644 community/www/hackathons/__pycache__/__init__.py create mode 100644 community/www/hackathons/macros/__init__.py create mode 100644 community/www/home/__init__.py create mode 100644 community/www/home/__pycache__/__init__.py create mode 100644 community/www/macros/__init__.py create mode 100644 community/www/my-courses/__init__.py create mode 100644 community/www/my-courses/__pycache__/__init__.py create mode 100644 community/www/profiles/__init__.py create mode 100644 community/www/profiles/__pycache__/__init__.py create mode 100644 community/www/sketches/__init__.py create mode 100644 community/www/sketches/__pycache__/__init__.py diff --git a/community/lms/doctype/lms_course/lms_course.json b/community/lms/doctype/lms_course/lms_course.json index 8b46e3ec..d35fa59f 100644 --- a/community/lms/doctype/lms_course/lms_course.json +++ b/community/lms/doctype/lms_course/lms_course.json @@ -21,12 +21,14 @@ "engine": "InnoDB", "field_order": [ "title", - "is_published", - "disable_self_learning", - "column_break_3", "short_code", "video_link", + "column_break_3", + "is_published", + "disable_self_learning", + "image", "section_break_5", + "tags", "short_introduction", "description" ], @@ -80,6 +82,17 @@ "fieldname": "disable_self_learning", "fieldtype": "Check", "label": "Disable Self Learning" + }, + { + "fieldname": "image", + "fieldtype": "Attach Image", + "label": "Preview Image", + "reqd": 1 + }, + { + "fieldname": "tags", + "fieldtype": "Data", + "label": "Tags" } ], "index_web_pages_for_search": 1, @@ -106,7 +119,7 @@ "link_fieldname": "course" } ], - "modified": "2021-06-21 11:34:04.552376", + "modified": "2021-06-28 12:04:21.524161", "modified_by": "Administrator", "module": "LMS", "name": "LMS Course", diff --git a/community/lms/doctype/lms_course/lms_course.py b/community/lms/doctype/lms_course/lms_course.py index a98a5e63..7889eb23 100644 --- a/community/lms/doctype/lms_course/lms_course.py +++ b/community/lms/doctype/lms_course/lms_course.py @@ -241,6 +241,9 @@ class LMSCourse(Document): member_names = [m['member'] for m in memberships] return find_all("User", name=["IN", member_names]) + def get_tags(self): + return self.tags.split(",") if self.tags else [] + def get_outline(self): return CourseOutline(self) diff --git a/community/lms/doctype/lms_course_review/__init__.py b/community/lms/doctype/lms_course_review/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/lms/doctype/lms_course_review/lms_course_review.js b/community/lms/doctype/lms_course_review/lms_course_review.js new file mode 100644 index 00000000..8382eb52 --- /dev/null +++ b/community/lms/doctype/lms_course_review/lms_course_review.js @@ -0,0 +1,8 @@ +// Copyright (c) 2021, FOSS United and contributors +// For license information, please see license.txt + +frappe.ui.form.on('LMS Course Review', { + // refresh: function(frm) { + + // } +}); diff --git a/community/lms/doctype/lms_course_review/lms_course_review.json b/community/lms/doctype/lms_course_review/lms_course_review.json new file mode 100644 index 00000000..8db5bf63 --- /dev/null +++ b/community/lms/doctype/lms_course_review/lms_course_review.json @@ -0,0 +1,49 @@ +{ + "actions": [], + "creation": "2021-06-28 12:30:02.111289", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "review", + "rating" + ], + "fields": [ + { + "fieldname": "review", + "fieldtype": "Small Text", + "in_list_view": 1, + "label": "Review", + "reqd": 1 + }, + { + "fieldname": "rating", + "fieldtype": "Rating", + "label": "Rating" + } + ], + "index_web_pages_for_search": 1, + "links": [], + "modified": "2021-06-28 12:30:15.953008", + "modified_by": "Administrator", + "module": "LMS", + "name": "LMS Course Review", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/community/lms/doctype/lms_course_review/lms_course_review.py b/community/lms/doctype/lms_course_review/lms_course_review.py new file mode 100644 index 00000000..e2361ad0 --- /dev/null +++ b/community/lms/doctype/lms_course_review/lms_course_review.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, FOSS United and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class LMSCourseReview(Document): + pass diff --git a/community/lms/doctype/lms_course_review/test_lms_course_review.py b/community/lms/doctype/lms_course_review/test_lms_course_review.py new file mode 100644 index 00000000..da8a1450 --- /dev/null +++ b/community/lms/doctype/lms_course_review/test_lms_course_review.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, FOSS United and Contributors +# See license.txt + +# import frappe +import unittest + +class TestLMSCourseReview(unittest.TestCase): + pass diff --git a/community/public/css/style.css b/community/public/css/style.css index a3116517..4c8b8311 100644 --- a/community/public/css/style.css +++ b/community/public/css/style.css @@ -17,7 +17,7 @@ --h-color: var(--c2); - --text-color: #333; + --text-color: #192734; --text-color-light: #ccc; --cta-color: var(--c4); @@ -25,6 +25,8 @@ --received-message: var(--c8); --checkbox-size: 14px; --control-bg: var(--gray-100); + --muted-text: #4C5A67; + --button-background: #EEF0F2; } body { @@ -32,18 +34,6 @@ body { margin: 0px; } - -/* .course-details { - margin: 20px 0px; -} - -.course-details h2 { - color: var(--h-color); - font-size: 1.4em; - font-weight: bold; - margin: 20px 0px 10px 0px; -} */ - .chapter-plan { border-radius: 10px; margin: 20px 0px; @@ -57,21 +47,6 @@ body { font-weight: bold; } -/* .chapter-number { - background: var(--text-color); - color: white; - border-radius: 50%; - height: 24px; - min-width: 24px; - align-items: center; - padding: 2px 8px 2px 8px; - margin-right: 5px; -} - -.chapter-description { - margin: 20px 0px; -} */ - .lessons { padding-left: 20px; } @@ -265,3 +240,195 @@ input[type=checkbox] { border-radius: 50px; padding: 5px; } + +.course-image { + height: 168px; + width: 352px; + border-top-left-radius: 8px; + border-top-right-radius: 8px; + background-size: 352px 168px; +} + +@media (max-width: 768px) { + .course-image { + width: 336px; + } +} + +@media (max-width: 375px) { + .course-image { + width: 312px; + background-size: cover; + background-repeat: no-repeat; + } +} + +.course-tags { + display: flex; + position: relative; + top: 12px; + left: 12px; + height: 20px; +} + +.course-card-pills { + background: #ffffff; + margin: 0px 10px; + border-radius: 4px; + padding: 4px 6px; + font-size: 10px; + line-height: 120%; + text-align: center; + letter-spacing: 0.011em; + text-transform: uppercase; + color: #2C5477; + font-weight: bold; + box-shadow: 0px 5px 10px rgb(0 0 0 / 10%); +} + +.common-page-style { + background: #F4F5F6; +} + +.common-card-style { + display: flex; + flex-direction: column; + align-items: flex-start; + background: #FFFFFF; + border-radius: 8px; + width: 352px; + height: 380px; + margin: 0px 16px 32px; + box-shadow: 0px 5px 10px rgb(0 0 0 / 10%); +} + +@media (max-width: 768px) { + .common-card-style { + width: 336px; + } +} + +@media (max-width: 375px) { + .common-card-style { + width: 312px; + } +} + +.course-card-meta { + font-size: 12px; + line-height: 135%; + margin: 12px 16px 8px; + color: var(--muted-text); + height: 15px; +} + +.course-card-content { + width: 100%; +} + +.course-card-title { + font-weight: 600; + font-size: 18px; + line-height: 156%; + letter-spacing: -0.014em; + color: var(--text-color); + align-self: stretch; + margin: 0px 16px 16px; + height: 45px; +} + +.card-divider { + border: 1px solid #E2E6E9; + margin: 0px 16px 16px; +} + +.course-card-meta-2 { + margin: 0px 16px 16px; +} + +.course-instructor { + margin: 0px 8px; + font-size: 12px; + line-height: 135%; + color: var(--text-color); +} + +.course-student-count { + font-size: 12px; + line-height: 135%; + color: var(--muted-text); + float: right; +} + +.view-course-link { + height: 32px; + margin: 0px 16px 16px; + background: var(--button-background); + border-radius: 4px; + font-size: 12px; + padding: 8px 0px 8px; + text-align: center; + line-height: 135%; + color: var(--text-color); +} + +.course-cards-parent { + display: flex; + flex-wrap: wrap; +} + +@media (max-width: 375px) { + .course-cards-parent { + justify-content: center; + } +} + +.course-divider { + border: 1px solid #E2E6E9; + margin: 16px 0px 30px; +} + +.courses-header { + padding: 50px 0px 20px; + color: var(--text-color); + font-weight: 600; + font-size: 22px; + line-height: 145%; + letter-spacing: -0.0175em +} + +.course-top-section { + margin: 0px 140px 0px; +} + +@media (max-width: 768px) { + .course-top-section { + margin: 0px 40px 0px; + } +} + +@media (max-width: 375px) { + .course-top-section { + margin: 0px 24px 0px; + } +} + +.is-primary { + background: var(--primary-color); + color: #FFFFFF; +} + +.button-links:hover { + text-decoration: none; +} + +.icon-background { + border-radius: 50%; + padding: 3px; + width: 24px; + height: 24px; +} + +.small-margin { + margin-left: 10px; +} diff --git a/community/public/css/style.less b/community/public/css/style.less index 3de921c9..d7fdbb1c 100644 --- a/community/public/css/style.less +++ b/community/public/css/style.less @@ -138,39 +138,6 @@ section.lightgray { color: var(--tag-color); } -.course-header { - margin-top: 20px; -} - -/* -.course-header { - margin-top: 20px; - padding: 20px; - background: var(--header-bg); - color: var(--header-color); - border-radius: 9px; -} - -.course-author-avatar { - width: 20px; - height: 20px; - border-radius: 50%; - margin-right: 20px; -} - -.course-header h1 { - color: inherit; -} - -*/ - -// .gray-section { -// background:#F6F6F6; -// border: 1px solid #C4C4C4; -// padding: 20px; -// margin: 20px 0px; -// } - .instructor-title { color: black; } diff --git a/community/public/icons/black-arrow.svg b/community/public/icons/black-arrow.svg new file mode 100644 index 00000000..b242af38 --- /dev/null +++ b/community/public/icons/black-arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/community/public/icons/calendar.svg b/community/public/icons/calendar.svg new file mode 100644 index 00000000..fd4c50e4 --- /dev/null +++ b/community/public/icons/calendar.svg @@ -0,0 +1,3 @@ + + + diff --git a/community/public/icons/clock.svg b/community/public/icons/clock.svg new file mode 100644 index 00000000..fd6aed95 --- /dev/null +++ b/community/public/icons/clock.svg @@ -0,0 +1,3 @@ + + + diff --git a/community/public/icons/rating-filled.svg b/community/public/icons/rating-filled.svg new file mode 100644 index 00000000..260c7f4d --- /dev/null +++ b/community/public/icons/rating-filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/community/public/icons/rating.svg b/community/public/icons/rating.svg new file mode 100644 index 00000000..dade2e61 --- /dev/null +++ b/community/public/icons/rating.svg @@ -0,0 +1,3 @@ + + + diff --git a/community/public/icons/user.svg b/community/public/icons/user.svg new file mode 100644 index 00000000..66b19fb9 --- /dev/null +++ b/community/public/icons/user.svg @@ -0,0 +1,4 @@ + + + + diff --git a/community/public/icons/white-arrow.svg b/community/public/icons/white-arrow.svg new file mode 100644 index 00000000..71bebd47 --- /dev/null +++ b/community/public/icons/white-arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/community/www/__init__.py b/community/www/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/__pycache__/__init__.py b/community/www/__pycache__/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/batch/__pycache__/__init__.py b/community/www/batch/__pycache__/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/courses/__init__.py b/community/www/courses/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/courses/__pycache__/__init__.py b/community/www/courses/__pycache__/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/courses/index.html b/community/www/courses/index.html index 89de4c19..253f9ade 100644 --- a/community/www/courses/index.html +++ b/community/www/courses/index.html @@ -9,37 +9,87 @@ {% endblock %} {% block content %} -
-
-

{{ 'All Courses' }}

-
- {% for course in courses %} - {{ course_card(course) }} - {% endfor %} - +
+
+
+
+ {{ 'All Courses' }} +
+
+
+ {% for course in courses %} + {{ course_card(course) }} + {% endfor %} +
-
+ {% endblock %} {% macro course_card(course) %} -
- -
-
-
{{ course.title }}
- {% if course.description %} -
- {{ frappe.utils.md_to_html(course.description[:200]) }} -
- {% endif %} -
+
+ +
+
+ {% if course.get_chapters() | length %} + + {{ course.get_chapters() | length }} Chapters + + {% endif %} + {% if course.get_chapters() | length and course.get_upcoming_batches() | length %} + . + {% endif %} + {% if course.get_upcoming_batches() | length %} + + {{ course.get_upcoming_batches() | length }} Open Batches + + {% endif %} +
+
{{ course.title }}
+
+
+ {{ widgets.Avatar(member=course.get_instructor(), avatar_class="avatar-small") }} + + {{ course.get_instructor().full_name }} + + {% if course.get_students() | length %} + + + {{ course.get_students() | length }} + + {% endif %} +
+ + {% if course.get_membership(frappe.session.user) %} + + {% else %} + + {% endif %} + +
{% endmacro %} + +{% block script %} + +{% endblock %} diff --git a/community/www/courses/index.py b/community/www/courses/index.py index 49b1864a..86d6acf2 100644 --- a/community/www/courses/index.py +++ b/community/www/courses/index.py @@ -5,8 +5,8 @@ def get_context(context): context.courses = get_courses() def get_courses(): - courses = frappe.get_all( - "LMS Course", - fields=['name', 'title', 'description'] - ) + course_names = frappe.get_all("LMS Course", pluck="name") + courses = [] + for course in course_names: + courses.append(frappe.get_doc("LMS Course", course)) return courses diff --git a/community/www/dashboard/__init__.py b/community/www/dashboard/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/dashboard/__pycache__/__init__.py b/community/www/dashboard/__pycache__/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/hackathons/__init__.py b/community/www/hackathons/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/hackathons/__pycache__/__init__.py b/community/www/hackathons/__pycache__/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/hackathons/macros/__init__.py b/community/www/hackathons/macros/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/home/__init__.py b/community/www/home/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/home/__pycache__/__init__.py b/community/www/home/__pycache__/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/macros/__init__.py b/community/www/macros/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/my-courses/__init__.py b/community/www/my-courses/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/my-courses/__pycache__/__init__.py b/community/www/my-courses/__pycache__/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/profiles/__init__.py b/community/www/profiles/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/profiles/__pycache__/__init__.py b/community/www/profiles/__pycache__/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/sketches/__init__.py b/community/www/sketches/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/sketches/__pycache__/__init__.py b/community/www/sketches/__pycache__/__init__.py new file mode 100644 index 00000000..e69de29b From 3aa974f8bdf94f1b6882f72c170ed6c956413b97 Mon Sep 17 00:00:00 2001 From: pateljannat Date: Mon, 28 Jun 2021 13:26:29 +0530 Subject: [PATCH 02/16] fix: removed review doctype --- .../lms/doctype/lms_course_review/__init__.py | 0 .../lms_course_review/lms_course_review.js | 8 --- .../lms_course_review/lms_course_review.json | 49 ------------------- .../lms_course_review/lms_course_review.py | 8 --- .../test_lms_course_review.py | 8 --- 5 files changed, 73 deletions(-) delete mode 100644 community/lms/doctype/lms_course_review/__init__.py delete mode 100644 community/lms/doctype/lms_course_review/lms_course_review.js delete mode 100644 community/lms/doctype/lms_course_review/lms_course_review.json delete mode 100644 community/lms/doctype/lms_course_review/lms_course_review.py delete mode 100644 community/lms/doctype/lms_course_review/test_lms_course_review.py diff --git a/community/lms/doctype/lms_course_review/__init__.py b/community/lms/doctype/lms_course_review/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/community/lms/doctype/lms_course_review/lms_course_review.js b/community/lms/doctype/lms_course_review/lms_course_review.js deleted file mode 100644 index 8382eb52..00000000 --- a/community/lms/doctype/lms_course_review/lms_course_review.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2021, FOSS United and contributors -// For license information, please see license.txt - -frappe.ui.form.on('LMS Course Review', { - // refresh: function(frm) { - - // } -}); diff --git a/community/lms/doctype/lms_course_review/lms_course_review.json b/community/lms/doctype/lms_course_review/lms_course_review.json deleted file mode 100644 index 8db5bf63..00000000 --- a/community/lms/doctype/lms_course_review/lms_course_review.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "actions": [], - "creation": "2021-06-28 12:30:02.111289", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "review", - "rating" - ], - "fields": [ - { - "fieldname": "review", - "fieldtype": "Small Text", - "in_list_view": 1, - "label": "Review", - "reqd": 1 - }, - { - "fieldname": "rating", - "fieldtype": "Rating", - "label": "Rating" - } - ], - "index_web_pages_for_search": 1, - "links": [], - "modified": "2021-06-28 12:30:15.953008", - "modified_by": "Administrator", - "module": "LMS", - "name": "LMS Course Review", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1 -} \ No newline at end of file diff --git a/community/lms/doctype/lms_course_review/lms_course_review.py b/community/lms/doctype/lms_course_review/lms_course_review.py deleted file mode 100644 index e2361ad0..00000000 --- a/community/lms/doctype/lms_course_review/lms_course_review.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2021, FOSS United and contributors -# For license information, please see license.txt - -# import frappe -from frappe.model.document import Document - -class LMSCourseReview(Document): - pass diff --git a/community/lms/doctype/lms_course_review/test_lms_course_review.py b/community/lms/doctype/lms_course_review/test_lms_course_review.py deleted file mode 100644 index da8a1450..00000000 --- a/community/lms/doctype/lms_course_review/test_lms_course_review.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2021, FOSS United and Contributors -# See license.txt - -# import frappe -import unittest - -class TestLMSCourseReview(unittest.TestCase): - pass From 0c64d46e999c45f4a851ab173b491d563eab7572 Mon Sep 17 00:00:00 2001 From: pateljannat Date: Mon, 28 Jun 2021 20:27:17 +0530 Subject: [PATCH 03/16] feat: reviews --- .gitignore | 3 + community/hooks.py | 3 +- .../lms/doctype/lms_course/lms_course.py | 33 +++++++++- .../lms/doctype/lms_course_review/__init__.py | 0 .../lms_course_review/lms_course_review.js | 8 +++ .../lms_course_review/lms_course_review.json | 54 ++++++++++++++++ .../lms_course_review/lms_course_review.py | 8 +++ .../test_lms_course_review.py | 8 +++ community/lms/widgets/Reviews.html | 61 +++++++++++++++++++ community/templates/pages/reviews.js | 37 +++++++++++ community/www/__init__.py | 0 community/www/courses/__init__.py | 0 community/www/courses/course.html | 3 +- community/www/courses/course.py | 4 +- community/www/dashboard/__init__.py | 0 community/www/hackathons/__init__.py | 0 community/www/hackathons/macros/__init__.py | 0 community/www/home/__init__.py | 0 community/www/macros/__init__.py | 0 community/www/my-courses/__init__.py | 0 community/www/profiles/__init__.py | 0 community/www/sketches/__init__.py | 0 22 files changed, 217 insertions(+), 5 deletions(-) create mode 100644 community/lms/doctype/lms_course_review/__init__.py create mode 100644 community/lms/doctype/lms_course_review/lms_course_review.js create mode 100644 community/lms/doctype/lms_course_review/lms_course_review.json create mode 100644 community/lms/doctype/lms_course_review/lms_course_review.py create mode 100644 community/lms/doctype/lms_course_review/test_lms_course_review.py create mode 100644 community/lms/widgets/Reviews.html create mode 100644 community/templates/pages/reviews.js create mode 100644 community/www/__init__.py create mode 100644 community/www/courses/__init__.py create mode 100644 community/www/dashboard/__init__.py create mode 100644 community/www/hackathons/__init__.py create mode 100644 community/www/hackathons/macros/__init__.py create mode 100644 community/www/home/__init__.py create mode 100644 community/www/macros/__init__.py create mode 100644 community/www/my-courses/__init__.py create mode 100644 community/www/profiles/__init__.py create mode 100644 community/www/sketches/__init__.py diff --git a/.gitignore b/.gitignore index f6a99e30..222921e1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ tags community/docs/current community/public/dist +__pycache__/ +*.py[cod] +*$py.class diff --git a/community/hooks.py b/community/hooks.py index 5666dd53..dbf8f2a2 100644 --- a/community/hooks.py +++ b/community/hooks.py @@ -165,7 +165,8 @@ whitelist = [ "/add-a-new-batch", "/new-sign-up", "/message", - "/about" + "/about", + "/lms-course-review" ] whitelist_rules = [{"from_route": p, "to_route": p[1:]} for p in whitelist] diff --git a/community/lms/doctype/lms_course/lms_course.py b/community/lms/doctype/lms_course/lms_course.py index a98a5e63..613c5a6c 100644 --- a/community/lms/doctype/lms_course/lms_course.py +++ b/community/lms/doctype/lms_course/lms_course.py @@ -199,7 +199,12 @@ class LMSCourse(Document): } if batch: filters["batch"] = batch - membership = frappe.db.get_value("LMS Batch Membership", filters, ["name","batch", "current_lesson"], as_dict=True) + + membership = frappe.db.get_value("LMS Batch Membership", + filters, + ["name", "batch", "current_lesson", "member_type"], + as_dict=True) + if membership and membership.batch: membership.batch_title = frappe.db.get_value("LMS Batch", membership.batch, "title") return membership @@ -241,6 +246,32 @@ class LMSCourse(Document): member_names = [m['member'] for m in memberships] return find_all("User", name=["IN", member_names]) + def get_reviews(self): + reviews = frappe.get_all("LMS Course Review", + { + "course": self.name + }, + ["review", "rating", "owner"], + order_by= "creation desc") + + for review in reviews: + review.owner_details = frappe.get_doc("User", review.owner) + + return reviews + + def is_eligibleto_review(self, membership): + """ Checks if user is eligible to review the course """ + if not membership: + return False + if frappe.db.count("LMS Course Review", + { + "course": self.name, + "owner": frappe.session.user + }): + return False + return True + + def get_outline(self): return CourseOutline(self) diff --git a/community/lms/doctype/lms_course_review/__init__.py b/community/lms/doctype/lms_course_review/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/lms/doctype/lms_course_review/lms_course_review.js b/community/lms/doctype/lms_course_review/lms_course_review.js new file mode 100644 index 00000000..8382eb52 --- /dev/null +++ b/community/lms/doctype/lms_course_review/lms_course_review.js @@ -0,0 +1,8 @@ +// Copyright (c) 2021, FOSS United and contributors +// For license information, please see license.txt + +frappe.ui.form.on('LMS Course Review', { + // refresh: function(frm) { + + // } +}); diff --git a/community/lms/doctype/lms_course_review/lms_course_review.json b/community/lms/doctype/lms_course_review/lms_course_review.json new file mode 100644 index 00000000..c2684bbe --- /dev/null +++ b/community/lms/doctype/lms_course_review/lms_course_review.json @@ -0,0 +1,54 @@ +{ + "actions": [], + "creation": "2021-06-28 13:36:36.146718", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "review", + "rating", + "course" + ], + "fields": [ + { + "fieldname": "review", + "fieldtype": "Small Text", + "label": "Review" + }, + { + "fieldname": "rating", + "fieldtype": "Rating", + "label": "Rating" + }, + { + "fieldname": "course", + "fieldtype": "Link", + "label": "Course", + "options": "LMS Course" + } + ], + "index_web_pages_for_search": 1, + "links": [], + "modified": "2021-06-28 15:00:35.146196", + "modified_by": "Administrator", + "module": "LMS", + "name": "LMS Course Review", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/community/lms/doctype/lms_course_review/lms_course_review.py b/community/lms/doctype/lms_course_review/lms_course_review.py new file mode 100644 index 00000000..e2361ad0 --- /dev/null +++ b/community/lms/doctype/lms_course_review/lms_course_review.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, FOSS United and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + +class LMSCourseReview(Document): + pass diff --git a/community/lms/doctype/lms_course_review/test_lms_course_review.py b/community/lms/doctype/lms_course_review/test_lms_course_review.py new file mode 100644 index 00000000..da8a1450 --- /dev/null +++ b/community/lms/doctype/lms_course_review/test_lms_course_review.py @@ -0,0 +1,8 @@ +# Copyright (c) 2021, FOSS United and Contributors +# See license.txt + +# import frappe +import unittest + +class TestLMSCourseReview(unittest.TestCase): + pass diff --git a/community/lms/widgets/Reviews.html b/community/lms/widgets/Reviews.html new file mode 100644 index 00000000..5c20d42b --- /dev/null +++ b/community/lms/widgets/Reviews.html @@ -0,0 +1,61 @@ +
+
+
Review
+ {% if course.is_eligibleto_review(membership) %} + + Provide your Feedback + + {% endif %} +
+
+ {% for review in course.get_reviews() %} +
+
{{ review.review }}
+ +
+ {% endfor %} +
+
+ + + + + + diff --git a/community/templates/pages/reviews.js b/community/templates/pages/reviews.js new file mode 100644 index 00000000..eaa1bd6f --- /dev/null +++ b/community/templates/pages/reviews.js @@ -0,0 +1,37 @@ + +frappe.ready(() => { + $("#provide-feedback").click((e) => { + e.preventDefault(); + let d = new frappe.ui.Dialog({ + title: 'Provide your Feedback', + fields: [ + { + label: 'Rating', + fieldname: 'rating', + fieldtype: 'Rating' + }, + { + label: 'Review', + fieldname: 'review', + fieldtype: 'Small Text' + } + ], + primary_action_label: 'Submit', + primary_action(values) { + console.log(values); + frappe.call({ + method: "community.lms.doctype.lms_course.lms_course", + args: { + course: "{{ course.name }}", + rating: values.rating, + review: values.review + }, + callback: (data) => { + d.hide(); + } + }) + } + }); + d.show(); + }) +}) diff --git a/community/www/__init__.py b/community/www/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/courses/__init__.py b/community/www/courses/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/courses/course.html b/community/www/courses/course.html index 7947fd5f..b1e13352 100644 --- a/community/www/courses/course.html +++ b/community/www/courses/course.html @@ -15,7 +15,7 @@

{{course.title}}

- {% if not course.disable_self_learning and not course.is_mentor(frappe.session.user) %} + {% if not course.disable_self_learning and not membership %}
@@ -32,6 +32,7 @@ {{ widgets.InstructorSection(instructor=course.get_instructor()) }} {{ BatchSection(course) }} {{ widgets.CourseOutline(course=course, show_link=membership) }} + {{ widgets.Reviews(course=course, membership=membership) }}
diff --git a/community/www/courses/course.py b/community/www/courses/course.py index 7f5c5fab..c847cdba 100644 --- a/community/www/courses/course.py +++ b/community/www/courses/course.py @@ -20,5 +20,5 @@ def get_context(context): context.course.query_parameter = "?batch=" + membership.batch if membership and membership.batch else "" context.membership = membership if not course.is_mentor(frappe.session.user) and membership: - frappe.local.flags.redirect_location = f"/courses/{course.name}/learn" - raise frappe.Redirect + """ frappe.local.flags.redirect_location = f"/courses/{course.name}/learn" + raise frappe.Redirect """ diff --git a/community/www/dashboard/__init__.py b/community/www/dashboard/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/hackathons/__init__.py b/community/www/hackathons/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/hackathons/macros/__init__.py b/community/www/hackathons/macros/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/home/__init__.py b/community/www/home/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/macros/__init__.py b/community/www/macros/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/my-courses/__init__.py b/community/www/my-courses/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/profiles/__init__.py b/community/www/profiles/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/www/sketches/__init__.py b/community/www/sketches/__init__.py new file mode 100644 index 00000000..e69de29b From ee8273fd30712d437cd1a2f0a76c8067aaf8808e Mon Sep 17 00:00:00 2001 From: pateljannat Date: Wed, 30 Jun 2021 16:16:22 +0530 Subject: [PATCH 04/16] feat: new fields in user doctype and new web form --- community/fixtures/custom_field.json | 108 +++++++++++++++++ community/hooks.py | 4 +- community/lms/web_form/profile/__init__.py | 0 community/lms/web_form/profile/profile.js | 3 + community/lms/web_form/profile/profile.json | 125 ++++++++++++++++++++ community/lms/web_form/profile/profile.py | 5 + community/lms/widgets/Reviews.html | 4 +- community/public/css/style.css | 15 +-- community/www/courses/index.html | 24 ++-- 9 files changed, 262 insertions(+), 26 deletions(-) create mode 100644 community/fixtures/custom_field.json create mode 100644 community/lms/web_form/profile/__init__.py create mode 100644 community/lms/web_form/profile/profile.js create mode 100644 community/lms/web_form/profile/profile.json create mode 100644 community/lms/web_form/profile/profile.py diff --git a/community/fixtures/custom_field.json b/community/fixtures/custom_field.json new file mode 100644 index 00000000..d3bb2124 --- /dev/null +++ b/community/fixtures/custom_field.json @@ -0,0 +1,108 @@ +[ + { + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "doctype": "Custom Field", + "dt": "User", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "linkedin", + "fieldtype": "Data", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "mobile_no", + "label": "LinkedIn ID", + "length": 0, + "mandatory_depends_on": null, + "modified": "2021-06-30 14:46:55.834145", + "name": "User-linkedin", + "no_copy": 0, + "non_negative": 0, + "options": null, + "parent": null, + "parentfield": null, + "parenttype": null, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "translatable": 1, + "unique": 0, + "width": null + }, + { + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "doctype": "Custom Field", + "dt": "User", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "github", + "fieldtype": "Data", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "linkedin", + "label": "Github ID", + "length": 0, + "mandatory_depends_on": null, + "modified": "2021-06-30 14:46:55.834145", + "name": "User-github", + "no_copy": 0, + "non_negative": 0, + "options": null, + "parent": null, + "parentfield": null, + "parenttype": null, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "translatable": 1, + "unique": 0, + "width": null + } +] diff --git a/community/hooks.py b/community/hooks.py index dbf8f2a2..f6a8b4ab 100644 --- a/community/hooks.py +++ b/community/hooks.py @@ -104,6 +104,8 @@ doc_events = { # ] #} +fixtures = ["Custom Field"] + # Testing # ------- @@ -166,7 +168,7 @@ whitelist = [ "/new-sign-up", "/message", "/about", - "/lms-course-review" + "/review" ] whitelist_rules = [{"from_route": p, "to_route": p[1:]} for p in whitelist] diff --git a/community/lms/web_form/profile/__init__.py b/community/lms/web_form/profile/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/community/lms/web_form/profile/profile.js b/community/lms/web_form/profile/profile.js new file mode 100644 index 00000000..699703c5 --- /dev/null +++ b/community/lms/web_form/profile/profile.js @@ -0,0 +1,3 @@ +frappe.ready(function() { + // bind events here +}) \ No newline at end of file diff --git a/community/lms/web_form/profile/profile.json b/community/lms/web_form/profile/profile.json new file mode 100644 index 00000000..c4962a94 --- /dev/null +++ b/community/lms/web_form/profile/profile.json @@ -0,0 +1,125 @@ +{ + "accept_payment": 0, + "allow_comments": 0, + "allow_delete": 0, + "allow_edit": 1, + "allow_incomplete": 0, + "allow_multiple": 0, + "allow_print": 0, + "amount": 0.0, + "amount_based_on_field": 0, + "apply_document_permissions": 0, + "breadcrumbs": "", + "button_label": "Save", + "creation": "2021-06-30 13:48:13.682851", + "doc_type": "User", + "docstatus": 0, + "doctype": "Web Form", + "idx": 0, + "is_standard": 1, + "login_required": 1, + "max_attachment_size": 0, + "modified": "2021-06-30 15:53:20.967466", + "modified_by": "Administrator", + "module": "LMS", + "name": "profile", + "owner": "Administrator", + "payment_button_label": "Buy Now", + "published": 1, + "route": "profile", + "route_to_success_link": 0, + "show_attachments": 0, + "show_in_grid": 0, + "show_sidebar": 0, + "sidebar_items": [], + "success_url": "/profile", + "title": "Profile", + "web_form_fields": [ + { + "allow_read_on_all_link_options": 0, + "fieldname": "first_name", + "fieldtype": "Data", + "hidden": 0, + "label": "First Name", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 1, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "middle_name", + "fieldtype": "Data", + "hidden": 0, + "label": "Middle Name (Optional)", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "last_name", + "fieldtype": "Data", + "hidden": 0, + "label": "Last Name", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "description": "Get your globally recognized avatar from Gravatar.com", + "fieldname": "user_image", + "fieldtype": "Attach Image", + "hidden": 0, + "label": "User Image", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "username", + "fieldtype": "Data", + "hidden": 0, + "label": "Username", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "mobile_no", + "fieldtype": "Data", + "hidden": 0, + "label": "Mobile No", + "max_length": 0, + "max_value": 0, + "options": "Phone", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "bio", + "fieldtype": "Small Text", + "hidden": 0, + "label": "Bio", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + } + ] +} \ No newline at end of file diff --git a/community/lms/web_form/profile/profile.py b/community/lms/web_form/profile/profile.py new file mode 100644 index 00000000..e1ada619 --- /dev/null +++ b/community/lms/web_form/profile/profile.py @@ -0,0 +1,5 @@ +import frappe + +def get_context(context): + # do your magic here + pass diff --git a/community/lms/widgets/Reviews.html b/community/lms/widgets/Reviews.html index 9e0cf18b..962ad6fb 100644 --- a/community/lms/widgets/Reviews.html +++ b/community/lms/widgets/Reviews.html @@ -7,7 +7,7 @@ {% endif %} -
+
{% for review in course.get_reviews() %}
{{ review.review }}
@@ -19,7 +19,7 @@ {{ course.get_instructor().full_name }}
-
+
{% for i in [1, 2, 3, 4, 5] %} diff --git a/community/public/css/style.css b/community/public/css/style.css index 89efd067..06bc5b21 100644 --- a/community/public/css/style.css +++ b/community/public/css/style.css @@ -297,6 +297,7 @@ input[type=checkbox] { background: #FFFFFF; border-radius: 8px; box-shadow: 0px 5px 10px rgb(0 0 0 / 10%); + position: relative; } .course-card { @@ -375,7 +376,7 @@ input[type=checkbox] { color: var(--text-color); } -.course-cards-parent { +.cards-parent { display: flex; flex-wrap: wrap; } @@ -386,13 +387,8 @@ input[type=checkbox] { } } -.course-divider { - border: 1px solid #E2E6E9; - margin: 16px 0px 30px; -} - .courses-header { - padding: 50px 0px 20px; + padding: 50px 30px 20px; color: var(--text-color); font-weight: 600; font-size: 22px; @@ -448,8 +444,8 @@ input[type=checkbox] { } .review-card { - width: 300px; - height: 200px; + width: 100%; + height: fit-content; margin: 0px 16px 32px; padding: 16px; } @@ -457,7 +453,6 @@ input[type=checkbox] { .review-card-footer { width: 100%; display: flex; - justify-content: space-between; } .review-content { diff --git a/community/www/courses/index.html b/community/www/courses/index.html index f10c0b1f..63ec84e1 100644 --- a/community/www/courses/index.html +++ b/community/www/courses/index.html @@ -15,8 +15,7 @@
{{ 'All Courses' }}
-
-
+
{% for course in courses %} {{ course_card(course) }} {% endfor %} @@ -66,18 +65,17 @@ {% endif %}
- - {% if course.get_membership(frappe.session.user) %} - - {% else %} - - {% endif %} - + {% if course.get_membership(frappe.session.user) %} + + {% else %} + + {% endif %}
+
{% endmacro %} From 45d88bdc08aab1877c1ce31a1298b7912e9be5ee Mon Sep 17 00:00:00 2001 From: pateljannat Date: Fri, 2 Jul 2021 15:43:21 +0530 Subject: [PATCH 05/16] feat: course header wide --- community/lms/doctype/chapter/chapter.py | 4 + community/lms/widgets/ChapterTeaser.html | 56 ++- community/lms/widgets/CourseOutline.html | 15 +- community/public/css/style.css | 596 +++++++++++++---------- community/public/icons/down-arrow.svg | 3 + community/public/icons/play.svg | 3 + community/public/icons/rating.svg | 2 +- community/public/icons/side-arrow.svg | 3 + community/public/icons/tick.svg | 3 + community/public/images/Vector.png | Bin 206 -> 200 bytes community/templates/quiz.html | 9 +- community/www/batch/members.html | 7 +- community/www/courses/course.html | 189 ++++--- 13 files changed, 503 insertions(+), 387 deletions(-) create mode 100644 community/public/icons/down-arrow.svg create mode 100644 community/public/icons/play.svg create mode 100644 community/public/icons/side-arrow.svg create mode 100644 community/public/icons/tick.svg diff --git a/community/lms/doctype/chapter/chapter.py b/community/lms/doctype/chapter/chapter.py index b616de2c..a563c7e0 100644 --- a/community/lms/doctype/chapter/chapter.py +++ b/community/lms/doctype/chapter/chapter.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document +from ...utils import slugify class Chapter(Document): def get_lessons(self): @@ -13,3 +14,6 @@ class Chapter(Document): fields='name', order_by="index_") return [frappe.get_doc('Lesson', row['name']) for row in rows] + + def get_slugified_chapter_title(self): + return slugify(self.title) diff --git a/community/lms/widgets/ChapterTeaser.html b/community/lms/widgets/ChapterTeaser.html index 5a49f5b3..537c952c 100644 --- a/community/lms/widgets/ChapterTeaser.html +++ b/community/lms/widgets/ChapterTeaser.html @@ -1,28 +1,42 @@ -
-
-
{{index}}. {{ chapter.title }}
-
- {{ chapter.description or "" }} +
+ +