From d657525359b9d942dbccfab603c813e4dbb708b1 Mon Sep 17 00:00:00 2001 From: pateljannat Date: Mon, 6 Sep 2021 18:59:59 +0530 Subject: [PATCH] fix: discussions redesign --- .../discussion_reply/discussion_reply.py | 11 +- community/community/widgets/CommentBox.html | 28 +++ .../community/widgets/DiscussionComment.html | 80 ------- .../community/widgets/DiscussionMessage.html | 177 ++++------------ community/overrides/user.py | 2 +- community/public/css/style.css | 83 +++++++- community/public/icons/message.svg | 4 +- community/public/icons/search.svg | 3 + community/templates/discussions/button.html | 7 + .../templates/discussions/discussions.js | 198 ++++++++++++++++++ .../templates/discussions/reply_card.html | 13 ++ .../templates/discussions/reply_section.html | 41 ++++ community/templates/discussions/search.html | 9 + community/templates/discussions/sidebar.html | 20 ++ .../templates/discussions/topic_modal.html | 15 ++ community/templates/reply_card.html | 17 -- community/www/batch/learn.html | 3 +- 17 files changed, 460 insertions(+), 251 deletions(-) create mode 100644 community/community/widgets/CommentBox.html delete mode 100644 community/community/widgets/DiscussionComment.html create mode 100644 community/public/icons/search.svg create mode 100644 community/templates/discussions/button.html create mode 100644 community/templates/discussions/discussions.js create mode 100644 community/templates/discussions/reply_card.html create mode 100644 community/templates/discussions/reply_section.html create mode 100644 community/templates/discussions/search.html create mode 100644 community/templates/discussions/sidebar.html create mode 100644 community/templates/discussions/topic_modal.html delete mode 100644 community/templates/reply_card.html diff --git a/community/community/doctype/discussion_reply/discussion_reply.py b/community/community/doctype/discussion_reply/discussion_reply.py index 2ba1f1ed..973a3a7b 100644 --- a/community/community/doctype/discussion_reply/discussion_reply.py +++ b/community/community/doctype/discussion_reply/discussion_reply.py @@ -14,11 +14,16 @@ class DiscussionReply(Document): }, "widgets": Widgets() } - template = frappe.render_template("community/templates/reply_card.html", data) - topic_info = frappe.db.get_value("Discussion Topic", self.topic, ["reference_doctype", "reference_docname", "name", "title"], as_dict=True) + template = frappe.render_template("community/templates/discussions/reply_card.html", data) + topic_info = frappe.get_all("Discussion Topic", {"name": self.topic}, ["reference_doctype", "reference_docname", "name", "title", "owner", "creation"]) + sidebar = frappe.render_template("community/templates/discussions/sidebar.html", { "topic": topic_info[0], "widgets": Widgets() }) + new_topic_template = frappe.render_template("community/templates/discussions/reply_section.html", { "topics": topic_info, "widgets": Widgets() }) + frappe.publish_realtime(event="publish_message", message = { "template": template, - "topic_info": topic_info + "topic_info": topic_info[0], + "sidebar": sidebar, + "new_topic_template": new_topic_template }, after_commit=True) diff --git a/community/community/widgets/CommentBox.html b/community/community/widgets/CommentBox.html new file mode 100644 index 00000000..04926a56 --- /dev/null +++ b/community/community/widgets/CommentBox.html @@ -0,0 +1,28 @@ +
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ + + +
diff --git a/community/community/widgets/DiscussionComment.html b/community/community/widgets/DiscussionComment.html deleted file mode 100644 index a1126de7..00000000 --- a/community/community/widgets/DiscussionComment.html +++ /dev/null @@ -1,80 +0,0 @@ - - - diff --git a/community/community/widgets/DiscussionMessage.html b/community/community/widgets/DiscussionMessage.html index b1b89ca2..e5bb3552 100644 --- a/community/community/widgets/DiscussionMessage.html +++ b/community/community/widgets/DiscussionMessage.html @@ -1,153 +1,54 @@ {% set topics = frappe.get_all("Discussion Topic", {"reference_doctype": doctype, "reference_docname": docname}, ["name", "title", "owner", "creation"]) %} -
-
- {{_('Discussions')}} - - New Topic - - -
- {{ widgets.DiscussionComment(doctype=doctype, docname=docname) }} +{% include "community/templates/discussions/topic_modal.html" %} +
+
+ {{_('Discussions')}} + {% if topics %} + {% include "community/templates/discussions/button.html" %} + {% endif %} +
+ + {% if topics %}
-
+
+ {% include "community/templates/discussions/search.html" %} {% for topic in topics %} {% set replies = frappe.get_all("Discussion Reply", {"topic": topic.name})%} - + +
+ {% include "community/templates/discussions/reply_section.html" %} +
+
+ {% else %} + +
+
+
No Discussions
+
There are no discussions for this {{ doctype | lower }}, why don't you start + one!
+ {% if frappe.session.user == "Guest" %} +
Log In
+ {% elif not condition %} +
+ {{ button_name }}
- {% if loop.index != topics | length %} -
+ {% else %} + {% include "community/templates/discussions/button.html" %} {% endif %} - {% endfor %} -
- -
- {% for topic in topics %} - {% set replies = frappe.get_all("Discussion Reply", {"topic": topic.name}, - ["reply", "owner", "creation"], order_by="creation")%} -
-
{{ topic.title }}
- {% for reply in replies %} - {% include "community/templates/reply_card.html" %} - {% endfor %} -
- {% endfor %} -
- - {% if not topics %} - - No discussions yet. - - {% endif %} -
- +{% block script %} + +{% endblock %} diff --git a/community/overrides/user.py b/community/overrides/user.py index 51ba0bad..ffce3bb5 100644 --- a/community/overrides/user.py +++ b/community/overrides/user.py @@ -58,7 +58,7 @@ class CustomUser(User): """ return frappe.get_all( 'LMS Course', { - 'owner': self.name, + 'instructor': self.name, 'is_published': True }) diff --git a/community/public/css/style.css b/community/public/css/style.css index 36649075..f066ac34 100644 --- a/community/public/css/style.css +++ b/community/public/css/style.css @@ -143,12 +143,12 @@ input[type=checkbox] { } .card-divider { - border: 1px solid #F4F5F6; + border: 1px solid #EEF0F2; margin-bottom: 1rem; } .card-divider-dark { - border: 1px solid #E2E6E9; + border: 1px solid #C8CFD5; margin-bottom: 16px; } @@ -221,6 +221,7 @@ input[type=checkbox] { padding-right: 1rem; } } + .button-links { color: #4C5A67; } @@ -1284,18 +1285,74 @@ pre { padding: 1rem; } -textarea.form-control { - height: 300px; -} - -.discussion-on-page .form-control { +.discussions-parent .form-control { background-color: #FFFFFF; font-size: inherit; color: inherit; + padding: 0.75rem 1rem; } -.discussion-on-page textarea { - height: 160px; +.discussion-on-page .comment-field { + height: 48px; + box-shadow: inset 0px 0px 4px rgba(0, 0, 0, 0.2); + border-radius: 4px; +} + +.modal .comment-field { + height: 300px; +} + +.no-discussions { + width: 250px; + margin: 0 auto; + text-align: center; +} + +.no-discussions .button { + margin: auto; +} + +.discussions-header { + margin: 2.5rem 0 1.25rem; +} + +.discussions-header .button { + float: right; +} + +.discussions-parent .search-field { + background-color: #E2E6E9; + background-image: url(/assets/community/icons/search.svg); + background-repeat: no-repeat; + text-indent: 1.5rem; + background-position: 1rem 0.7rem; + height: 36px; + font-size: 12px; + padding: 0.65rem 0.9rem; +} + +.discussions-sidebar { + background-color: #F4F5F6; + padding: 0.75rem; + border-radius: 4px; + max-height: 700px; + overflow-y: auto; +} + +#discussion-group { + max-height: 700px; + overflow-y: auto; +} + +.sidebar-topic { + padding: 0.75rem; + margin: 0.75rem 0; + cursor: pointer; +} + +.sidebar-topic[aria-expanded="true"] { + background: #FFFFFF; + border-radius: 4px; } .comment-footer { @@ -1315,6 +1372,14 @@ textarea.form-control { color: var(--text-color); } +.discussion-on-page .topic-title { + display: none; +} + +.discussions-sidebar .sidebar-parent:last-child .card-divider { + display: none; +} + .certificate-page .common-card-style { color: black; font-size: 1.25rem; diff --git a/community/public/icons/message.svg b/community/public/icons/message.svg index 241069d5..0f46b786 100644 --- a/community/public/icons/message.svg +++ b/community/public/icons/message.svg @@ -1,3 +1,3 @@ - - + + diff --git a/community/public/icons/search.svg b/community/public/icons/search.svg new file mode 100644 index 00000000..2cd7407c --- /dev/null +++ b/community/public/icons/search.svg @@ -0,0 +1,3 @@ + + + diff --git a/community/templates/discussions/button.html b/community/templates/discussions/button.html new file mode 100644 index 00000000..9148f770 --- /dev/null +++ b/community/templates/discussions/button.html @@ -0,0 +1,7 @@ +{% if frappe.session.user != "Guest" and +(condition is not defined or (condition is defined and condition )) %} + + New Discussion + + +{% endif %} diff --git a/community/templates/discussions/discussions.js b/community/templates/discussions/discussions.js new file mode 100644 index 00000000..818b6096 --- /dev/null +++ b/community/templates/discussions/discussions.js @@ -0,0 +1,198 @@ +frappe.ready(() => { + setup_socket_io(); + + set_docname_if_missing(); + + expand_first_discussion(); + + $(".search-field").keyup((e) => { + search_topic(e); + }); + + $(".reply").click((e) => { + show_new_topic_modal(e); + }); + + $("#login-from-discussion").click((e) => { + login_from_discussion(e); + }); + + $(".sidebar-topic").click((e) => { + if ($(e.currentTarget).attr("aria-expanded") == "true") { + e.stopPropagation(); + } + }); + + $(document).on("click", ".submit-discussion", (e) => { + submit_discussion(e); + }); +}) + +var show_new_topic_modal = (e) => { + e.preventDefault(); + $("#discussion-modal").modal("show"); + var topic = $(e.currentTarget).attr("data-topic"); + $(".modal-headings").text(topic ? "Reply" : "Start a Discussion"); + topic ? $(".topic-title").addClass("hide") : $(".topic-title").removeClass("hide"); + $("#submit-discussion").attr("data-topic", topic ? topic : ""); +} + +var setup_socket_io = () => { + const assets = [ + "/assets/frappe/js/lib/socket.io.min.js", + "/assets/frappe/js/frappe/socketio_client.js", + ] + + frappe.require(assets, () => { + if (window.dev_server) { + frappe.boot.socketio_port = "9000"; + } + frappe.socketio.init(9000); + frappe.socketio.socket.on("publish_message", (data) => { + publish_message(data); + }) + }) +} + +var publish_message = (data) => { + post_message_cleanup(); + + if ($(`.discussion-on-page[data-topic=${data.topic_info.name}]`).length) { + if ($(`.discussion-on-page[data-topic=${data.topic_info.name}] .card-divider-dark`).length) { + $(data.template).insertAfter(`.discussion-on-page[data-topic=${data.topic_info.name}] .card-divider-dark`); + } + else { + + $('
' + data.template).insertAfter(`.discussion-on-page[data-topic=${data.topic_info.name}] .discussion-form`); + } + } + else if ((decodeURIComponent($(".discussions-parent .course-content-parent").attr("data-doctype")) == data.topic_info.reference_doctype + && decodeURIComponent($(".discussions-parent .course-content-parent").attr("data-docname")) == data.topic_info.reference_docname)) { + $(data.sidebar).insertAfter(`.discussions-sidebar .form-group`); + $(`#discussion-group`).prepend(data.new_topic_template); + + if (data.topic_info.owner == frappe.session.user) { + $(".discussion-on-page").collapse(); + $(".sidebar-topic").first().click(); + } + + } + else { + window.location.reload(); + } + + update_reply_count(data.topic_info.name); +} + +var post_message_cleanup = () => { + $(".comment-field").val(""); + $("#discussion-modal").modal("hide"); + $("#no-discussions").addClass("hide"); +} + +var update_reply_count = (topic) => { + var reply_count = $(`[data-target='#t${topic}']`).find(".reply-count").text(); + reply_count = parseInt(reply_count) + 1; + $(`[data-target='#t${topic}']`).find(".reply-count").text(reply_count); +} + +var set_docname_if_missing = () => { + if ($("[data-docname='None']").length) { + frappe.call({ + method: "community.community.doctype.discussion_topic.discussion_topic.get_docname", + args: { + "route": window.location.href.split("/").slice(-1)[0] + }, + callback: (data) => { + $("[data-docname='None']").attr("data-docname", data.message); + } + }) + } +} + +var expand_first_discussion = () => { + $($(".discussions-parent .collapse")[0]).addClass("show"); + $($(".discussions-sidebar [data-toggle='collapse']")[0]).attr("aria-expanded", true); +} + +var search_topic = (e) => { + var input = $(e.currentTarget).val(); + + var topics = $(".discussions-parent .discussion-topic-title"); + if (input.length < 3 || input.trim() == "") { + topics.closest(".sidebar-parent").removeClass("hide"); + return + } + + topics.each((i, elem) => { + var topic_id = $(elem).parent().attr("data-target"); + + /* Check match in replies */ + var match_in_reply = false; + var replies = $(`${topic_id}`); + for (var reply of replies.find(".reply-text")) { + if (has_common_substring($(reply).text(), input)) { + match_in_reply = true; + break; + } + } + + /* Match found in title or replies, then show */ + if (has_common_substring($(elem).text(), input) || match_in_reply) { + $(elem).closest(".sidebar-parent").removeClass("hide") + } + else { + $(elem).closest(".sidebar-parent").addClass("hide"); + } + + }) +} + +var has_common_substring = (str1, str2) => { + var str1_arr = str1.toLowerCase().split(" "); + var str2_arr = str2.toLowerCase().split(" "); + + var substring_found = false; + for (var first_word of str1_arr) { + for (var second_word of str2_arr) { + if (first_word.indexOf(second_word) > -1) { + substring_found = true; + break; + } + } + } + return substring_found; +} + +var submit_discussion = (e) => { + e.preventDefault(); + e.stopImmediatePropagation(); + + var title = $(".topic-title:visible").length ? $(".topic-title:visible").val().trim() : ""; + var reply = $(".comment-field:visible").val().trim(); + + if (reply) { + var doctype = $(e.currentTarget).attr("data-doctype"); + doctype = doctype ? decodeURIComponent(doctype) : doctype; + + var docname = $(e.currentTarget).attr("data-docname"); + docname = docname ? decodeURIComponent(docname) : docname; + + frappe.call({ + method: "community.community.doctype.discussion_topic.discussion_topic.submit_discussion", + args: { + "doctype": doctype ? doctype : "", + "docname": docname ? docname : "", + "reply": reply, + "title": title, + "topic_name": $(e.currentTarget).closest(".discussion-on-page").attr("data-topic") + } + }) + + } +} + +var login_from_discussion = (e) => { + var redirect = $(e.currentTarget).attr("data-redirect") || window.location.href; + window.location.href = `/login?redirect-to=${redirect}`; +} diff --git a/community/templates/discussions/reply_card.html b/community/templates/discussions/reply_card.html new file mode 100644 index 00000000..ff60bc13 --- /dev/null +++ b/community/templates/discussions/reply_card.html @@ -0,0 +1,13 @@ +
+ {% set member = frappe.get_doc("User", reply.owner) %} +
+ {% set member = frappe.get_doc("User", reply.owner) %} + {{ widgets.Avatar(member=member, avatar_class="avatar-small")}} + + {{ member.full_name }} + +
just now
+
+
+
{{ reply.reply }}
+
diff --git a/community/templates/discussions/reply_section.html b/community/templates/discussions/reply_section.html new file mode 100644 index 00000000..9db944a4 --- /dev/null +++ b/community/templates/discussions/reply_section.html @@ -0,0 +1,41 @@ +{% for topic in topics %} +{% set replies = frappe.get_all("Discussion Reply", {"topic": topic.name}, +["reply", "owner", "creation"], order_by="creation desc")%} + + +{% if replies.insert(0, replies.pop()) %}{% endif %} + +{% if replies %} +
+
{{ topic.title }}
+ {% for reply in replies %} + + {% if loop.index == 2 %} +
+ {% endif %} + + {% include "community/templates/discussions/reply_card.html" %} + + {% if loop.index == 1 %} + + {% if frappe.session.user == "Guest" or (condition is defined and not condition) %} +
+ Want to join the discussion? + {% if frappe.session.user == "Guest" %} +
Log In
+ {% elif not condition %} +
{{ button_name }} +
+ {% endif %} +
+ {% else %} + {{ widgets.CommentBox(doctype=doctype, docname=docname) }} + {% endif %} + + {% endif %} + + {% endfor %} +
+{% endif %} +{% endfor %} diff --git a/community/templates/discussions/search.html b/community/templates/discussions/search.html new file mode 100644 index 00000000..2b4b6785 --- /dev/null +++ b/community/templates/discussions/search.html @@ -0,0 +1,9 @@ +
+
+
+ +
+
+
diff --git a/community/templates/discussions/sidebar.html b/community/templates/discussions/sidebar.html new file mode 100644 index 00000000..ea74fb08 --- /dev/null +++ b/community/templates/discussions/sidebar.html @@ -0,0 +1,20 @@ + diff --git a/community/templates/discussions/topic_modal.html b/community/templates/discussions/topic_modal.html new file mode 100644 index 00000000..98682d6f --- /dev/null +++ b/community/templates/discussions/topic_modal.html @@ -0,0 +1,15 @@ + diff --git a/community/templates/reply_card.html b/community/templates/reply_card.html deleted file mode 100644 index 4bcb5970..00000000 --- a/community/templates/reply_card.html +++ /dev/null @@ -1,17 +0,0 @@ -
- {% set member = frappe.get_doc("User", reply.owner) %} -
- {% set member = frappe.get_doc("User", reply.owner) %} - {{ widgets.Avatar(member=member, avatar_class="avatar-medium")}} -
- - {{ member.full_name }} - -
{{ frappe.utils.format_datetime(reply.creation, "hh:mm a, dd MMM YYYY") }}
-
- - Reply -
-
-
{{ reply.reply }}
-
diff --git a/community/www/batch/learn.html b/community/www/batch/learn.html index 49016c64..650e8a2c 100644 --- a/community/www/batch/learn.html +++ b/community/www/batch/learn.html @@ -102,8 +102,9 @@ {% endmacro %} {% macro Discussions() %} +{% set is_instructor = frappe.session.user == course.instructor %} {% set title = lesson.title + " - " + course.title %} -{% set condition = membership or is_instructor %} +{% set condition = is_instructor if is_instructor else membership %} {{ widgets.DiscussionMessage(doctype="Lesson", docname=lesson.name, condition=condition, button_name="Start Learning", redirect_to="/courses/" + course.name) }}