fix: discussions redesign

This commit is contained in:
pateljannat
2021-09-06 18:59:59 +05:30
parent 916e64d607
commit d657525359
17 changed files with 460 additions and 251 deletions

View File

@@ -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)

View File

@@ -0,0 +1,28 @@
<form class="discussion-form">
<div class="form-group">
<div class="control-input-wrapper">
<div class="control-input">
<input type="text" autocomplete="off" class="input-with-feedback form-control topic-title" data-fieldtype="Data"
data-fieldname="feedback_comments" placeholder="Title" spellcheck="false"></input>
</div>
</div>
</div>
<div class="form-group">
<div class="control-input-wrapper">
<div class="control-input">
<textarea type="text" autocomplete="off" class="input-with-feedback form-control comment-field"
data-fieldtype="Text" data-fieldname="feedback_comments" placeholder="Enter a comment..."
spellcheck="false"></textarea>
</div>
</div>
</div>
<div class="comment-footer">
<div class="button is-default pull-right mb-5 submit-discussion" data-doctype="{{ doctype | urlencode }}"
data-docname="{{ docname | urlencode }}">
Post</div>
</div>
</form>

View File

@@ -1,80 +0,0 @@
<div class="modal fade discussion-modal" id="discussion-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<div class="course-home-headings modal-headings">Start a Discussion</div>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="discussions">
<form class="discussion-form" id="discussion-form">
<div class="form-group">
<div class="control-input-wrapper">
<div class="control-input">
<input type="text" autocomplete="off" class="input-with-feedback form-control topic-title"
data-fieldtype="Data" data-fieldname="feedback_comments" placeholder="Title"
spellcheck="false"></input>
</div>
</div>
</div>
<div class="form-group">
<div class="control-input-wrapper">
<div class="control-input">
<textarea type="text" autocomplete="off" class="input-with-feedback form-control comment-field"
data-fieldtype="Text" data-fieldname="feedback_comments" placeholder="Enter a comment..."
spellcheck="false"></textarea>
</div>
</div>
</div>
<div class="comment-footer">
<div class="button is-secondary pull-right mb-5" id="submit-discussion"
data-doctype="{{ doctype | urlencode }}" data-docname="{{ docname | urlencode }}">
Post</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script>
frappe.ready(() => {
$("#submit-discussion").click((e) => {
submit_discussion(e);
})
})
var submit_discussion = (e) => {
var title = $(".topic-title").val().trim();
var reply = $(".comment-field").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).attr("data-topic")
},
callback: (data) => {
}
})
}
}
</script>

View File

@@ -1,153 +1,54 @@
{% set topics = frappe.get_all("Discussion Topic",
{"reference_doctype": doctype, "reference_docname": docname}, ["name", "title", "owner", "creation"]) %}
<div class="discussions-parent">
<div class="mt-10 mb-5">
<span class="course-home-headings">{{_('Discussions')}}</span>
<span class="review-link button is-secondary pull-right">
New Topic
<img src="/assets/community/icons/small-add-black.svg">
</span>
</div>
{{ widgets.DiscussionComment(doctype=doctype, docname=docname) }}
{% include "community/templates/discussions/topic_modal.html" %}
<div class="discussions-parent">
<div class="discussions-header">
<span class="course-home-headings">{{_('Discussions')}}</span>
{% if topics %}
{% include "community/templates/discussions/button.html" %}
{% endif %}
</div>
{% if topics %}
<div class="common-card-style thread-card course-content-parent" data-doctype="{{ doctype }}"
data-docname="{{ docname }}">
<div>
<div class="discussions-sidebar">
{% include "community/templates/discussions/search.html" %}
{% for topic in topics %}
{% set replies = frappe.get_all("Discussion Reply", {"topic": topic.name})%}
<div class="pl-3 pr-3" data-target="#t{{ topic.name }}" data-toggle="collapse" aria-expanded="false">
<div class="discussion-topic-title">{{ topic.title }}</div>
<div class="mt-2 mb-3">
{% set creator = frappe.get_doc("User", topic.owner) %}
{{ widgets.Avatar(member=creator, avatar_class="avatar-small") }}
<a class="button-links" href="/users/{{ creator.username }}">
<span class="course-instructor">
{{ creator.full_name }}
</span>
</a>
<span class="muted-text">
<img src="/assets/community/icons/message.svg"> {{ replies | length }}
</span>
</div>
{% include "community/templates/discussions/sidebar.html" %}
{% endfor %}
</div>
<div class="mr-2" id="discussion-group">
{% include "community/templates/discussions/reply_section.html" %}
</div>
</div>
{% else %}
<div id="no-discussions" class="common-card-style thread-card">
<div class="no-discussions">
<div class="font-weight-bold">No Discussions</div>
<div class="muted-text mt-3 mb-3">There are no discussions for this {{ doctype | lower }}, why don't you start
one! </div>
{% if frappe.session.user == "Guest" %}
<div class="button is-primary mt-3" id="login-from-discussion">Log In</div>
{% elif not condition %}
<div class="button is-primary mt-3" id="login-from-discussion" data-redirect="{{ redirect_to }}">
{{ button_name }}
</div>
{% if loop.index != topics | length %}
<div class="card-divider"></div>
{% else %}
{% include "community/templates/discussions/button.html" %}
{% endif %}
{% endfor %}
</div>
<div id="discussion-group">
{% for topic in topics %}
{% set replies = frappe.get_all("Discussion Reply", {"topic": topic.name},
["reply", "owner", "creation"], order_by="creation")%}
<div class="collapse" id="t{{ topic.name }}" class="topic-parent" data-topic="{{ topic.name }}"
data-parent="#discussion-group">
<div class="course-home-headings p-0">{{ topic.title }}</div>
{% for reply in replies %}
{% include "community/templates/reply_card.html" %}
{% endfor %}
</div>
{% endfor %}
</div>
{% if not topics %}
<span id="no-discussions" class="text-center">
No discussions yet. <img src="/assets/community/icons/slash.svg">
</span>
{% endif %}
</div>
</div>
<script>
frappe.ready(() => {
setup_socket_io();
{% endif %}
</div>
set_docname_if_missing();
expand_first_discussion();
$(document).on("click", ".reply", (e) => {
show_new_topic_modal(e);
})
})
var show_new_topic_modal = (e) => {
e.preventDefault();
if (frappe.session.user == "Guest") {
window.location.href = `/login?redirect-to=/discussions/`;
return;
}
$("#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) => {
if ($(`.topic-parent[data-topic=${data.topic_info.name}]`).length) {
post_message_cleanup();
$(`.topic-parent[data-topic=${data.topic_info.name}]`).append(data.template);
}
else if ((decodeURIComponent($(".discussions-section").attr("data-doctype")) == data.topic_info.reference_doctype
&& decodeURIComponent($(".discussions-section").attr("data-docname")) == data.topic_info.reference_docname)) {
post_message_cleanup();
var html = `<div class="topic-parent" data-topic="${data.topic_info.name}">
<div class="font-weight-bold mb-5">${data.topic_info.title}</div>
${data.template}
</div>`;
$(".discussions-section").prepend(html);
}
}
var post_message_cleanup = () => {
$(".comment-field").val("");
$("#discussion-modal").modal("hide");
$("#no-discussions").addClass("hide");
}
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 = () => {
var elements = $(".discussions-parent .collapse");
elements.each((i, element) => {
if (i < 1) {
$(element).addClass("show");
return false;
}
});
}
</script>
{% block script %}
<script>{% include "community/templates/discussions/discussions.js" %}</script>
{% endblock %}

View File

@@ -58,7 +58,7 @@ class CustomUser(User):
"""
return frappe.get_all(
'LMS Course', {
'owner': self.name,
'instructor': self.name,
'is_published': True
})

View File

@@ -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;

View File

@@ -1,3 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 14.6667C4 15.1382 4.1873 15.5903 4.5207 15.9237C4.8541 16.2571 5.30628 16.4444 5.77778 16.4444H16.4444L20 20V5.77778C20 5.30628 19.8127 4.8541 19.4793 4.5207C19.1459 4.1873 18.6937 4 18.2222 4H5.77778C5.30628 4 4.8541 4.1873 4.5207 4.5207C4.1873 4.8541 4 5.30628 4 5.77778V14.6667Z" stroke="#4C5A67" stroke-linecap="round" stroke-linejoin="round"/>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.66659 9.77761C2.66659 10.0919 2.79145 10.3934 3.01372 10.6157C3.23598 10.8379 3.53744 10.9628 3.85177 10.9628H10.9629L13.3333 13.3332V3.85169C13.3333 3.53736 13.2084 3.2359 12.9861 3.01364C12.7639 2.79137 12.4624 2.6665 12.1481 2.6665H3.85177C3.53744 2.6665 3.23598 2.79137 3.01372 3.01364C2.79145 3.2359 2.66659 3.53736 2.66659 3.85169V9.77761Z" stroke="#4C5A67" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 464 B

After

Width:  |  Height:  |  Size: 528 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.5 7.44462C3.5 5.26607 5.26607 3.5 7.44462 3.5C9.62318 3.5 11.3892 5.26607 11.3892 7.44462C11.3892 8.50829 10.9683 9.47362 10.2838 10.1831C10.265 10.1972 10.247 10.2128 10.2299 10.2299C10.2128 10.247 10.1972 10.265 10.1831 10.2838C9.47362 10.9683 8.50829 11.3892 7.44462 11.3892C5.26607 11.3892 3.5 9.62318 3.5 7.44462ZM10.5696 11.2767C9.71788 11.9722 8.62996 12.3892 7.44462 12.3892C4.71378 12.3892 2.5 10.1755 2.5 7.44462C2.5 4.71378 4.71378 2.5 7.44462 2.5C10.1755 2.5 12.3892 4.71378 12.3892 7.44462C12.3892 8.62996 11.9722 9.71788 11.2767 10.5696L13.3538 12.6467C13.549 12.8419 13.549 13.1585 13.3538 13.3538C13.1585 13.549 12.8419 13.549 12.6467 13.3538L10.5696 11.2767Z" fill="#4C5A67"/>
</svg>

After

Width:  |  Height:  |  Size: 849 B

View File

@@ -0,0 +1,7 @@
{% if frappe.session.user != "Guest" and
(condition is not defined or (condition is defined and condition )) %}
<span class="button is-secondary reply">
New Discussion
<img src="/assets/community/icons/small-add-black.svg">
</span>
{% endif %}

View File

@@ -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 {
$('<div class="card-divider-dark mb-10"></div>' + 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}`;
}

View File

@@ -0,0 +1,13 @@
<div class="reply-card">
{% set member = frappe.get_doc("User", reply.owner) %}
<div class="d-flex align-items-center muted-text">
{% set member = frappe.get_doc("User", reply.owner) %}
{{ widgets.Avatar(member=member, avatar_class="avatar-small")}}
<a class="button-links ml-2" href="/user/{{ member.username }}">
{{ member.full_name }}
</a>
<div class="ml-2 frappe-timestamp" data-timestamp="{{ reply.creation }}"> just now </div>
</div>
<div class="card-divider mt-3"></div>
<div class="reply-text">{{ reply.reply }}</div>
</div>

View File

@@ -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")%}
<!-- Hack to reorganize the replies array. So even though we want reverse cronology, the first reply should appear first. -->
{% if replies.insert(0, replies.pop()) %}{% endif %}
{% if replies %}
<div class="collapse discussion-on-page" id="t{{ topic.name }}" data-topic="{{ topic.name }}"
data-parent="#discussion-group">
<div class="course-home-headings p-0">{{ topic.title }}</div>
{% for reply in replies %}
{% if loop.index == 2 %}
<div class="card-divider-dark mb-10"></div>
{% endif %}
{% include "community/templates/discussions/reply_card.html" %}
{% if loop.index == 1 %}
{% if frappe.session.user == "Guest" or (condition is defined and not condition) %}
<div class="d-flex flex-column align-items-center muted-text">
Want to join the discussion?
{% if frappe.session.user == "Guest" %}
<div class="button is-primary mt-3 mb-3" id="login-from-discussion">Log In</div>
{% elif not condition %}
<div class="button is-primary mt-3 mb-3" id="login-from-discussion" data-redirect="{{ redirect_to }}">{{ button_name }}
</div>
{% endif %}
</div>
{% else %}
{{ widgets.CommentBox(doctype=doctype, docname=docname) }}
{% endif %}
{% endif %}
{% endfor %}
</div>
{% endif %}
{% endfor %}

View File

@@ -0,0 +1,9 @@
<div class="form-group">
<div class="control-input-wrapper">
<div class="control-input">
<textarea type="text" autocomplete="off" class="input-with-feedback form-control search-field"
data-fieldtype="Text" data-fieldname="feedback_comments" placeholder="Search Topics"
spellcheck="false"></textarea>
</div>
</div>
</div>

View File

@@ -0,0 +1,20 @@
<div class="sidebar-parent">
<div class="sidebar-topic" data-target="#t{{ topic.name }}" data-toggle="collapse" aria-expanded="false">
<div class="discussion-topic-title">{{ topic.title }}</div>
<div class="mt-2 mb-3">
{% set creator = frappe.get_doc("User", topic.owner) %}
{{ widgets.Avatar(member=creator, avatar_class="avatar-small") }}
<span class="course-instructor">
{{ creator.full_name }}
</span>
<span class="muted-text pull-right">
<span class="mr-2">
<img src="/assets/community/icons/message.svg">
<span class="reply-count">{{ replies | length }}</span>
</span>
<span> {{ frappe.utils.format_date(topic.creation, "dd MMM YYYY") }} </span>
</span>
</div>
</div>
<div class="card-divider"></div>
</div>

View File

@@ -0,0 +1,15 @@
<div class="modal fade discussion-modal" id="discussion-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<div class="course-home-headings modal-headings">Start a Discussion</div>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
{{ widgets.CommentBox(doctype=doctype, docname=docname) }}
</div>
</div>
</div>
</div>

View File

@@ -1,17 +0,0 @@
<div class="reply-card">
{% set member = frappe.get_doc("User", reply.owner) %}
<div class="d-flex align-items-center">
{% set member = frappe.get_doc("User", reply.owner) %}
{{ widgets.Avatar(member=member, avatar_class="avatar-medium")}}
<div class="ml-2 flex-grow-1">
<a class="button-links" href="/user/{{ member.username }}">
<span class="muted-text">{{ member.full_name }}</span>
</a>
<div class="muted-text">{{ frappe.utils.format_datetime(reply.creation, "hh:mm a, dd MMM YYYY") }}</div>
</div>
<a href="" class="dark-links muted-text reply" data-topic="{{ topic.name }}">Reply</a>
</div>
<div class="card-divider mt-3"></div>
<div>{{ reply.reply }}</div>
</div>

View File

@@ -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) }}