diff --git a/desk/src/pages/KnowledgeBaseArticle.vue b/desk/src/pages/KnowledgeBaseArticle.vue
index 4165cc881..63b6d4b99 100644
--- a/desk/src/pages/KnowledgeBaseArticle.vue
+++ b/desk/src/pages/KnowledgeBaseArticle.vue
@@ -47,27 +47,64 @@
/>
-
-
-
-
+
+
+
+
+
+
+
+
Did this article solve your issue?
+
+
+
+ {{
+ articleFeedback?.total_likes
+ }}
+
+
+
+ {{
+ articleFeedback?.total_dislikes
+ }}
+
+
+
+
+
@@ -102,7 +139,8 @@ import KnowledgeBaseArticleTopEdit from "./knowledge-base/KnowledgeBaseArticleTo
import KnowledgeBaseArticleTopNew from "./knowledge-base/KnowledgeBaseArticleTopNew.vue";
import KnowledgeBaseArticleTopView from "./knowledge-base/KnowledgeBaseArticleTopView.vue";
import { PreserveIds } from "@/tiptap-extensions";
-
+import { Icon } from "@iconify/vue";
+import { ArticleFeedback, Feedback } from "@/types";
const props = defineProps({
articleId: {
type: String,
@@ -146,7 +184,7 @@ const breadcrumbs = computed(() => {
},
},
];
- // if (options__.value.subCategoryId !== options__.value.categoryId) {
+
agentPortalItems.push({
label: options__.value.subCategoryName,
route: {
@@ -158,7 +196,6 @@ const breadcrumbs = computed(() => {
},
},
});
- // }
if (!isNew) {
agentPortalItems.push({
@@ -224,6 +261,7 @@ const topComponent = computed(() => {
return KnowledgeBaseArticleTopView;
});
+const articleFeedback = ref(null);
const article = createResource({
url: "helpdesk.helpdesk.doctype.hd_article.api.get_article",
params: {
@@ -231,6 +269,7 @@ const article = createResource({
},
onSuccess(data) {
articleTitle.value = data.title;
+ articleFeedback.value = data.feedbacks;
capture("article_viewed", {
data: {
user: authStore.userId,
@@ -242,6 +281,59 @@ const article = createResource({
auto: !isNew,
});
+const setFeedback = createResource({
+ url: "run_doc_method",
+ debounce: 300,
+ makeParams: () => ({
+ dt: "HD Article",
+ dn: props.articleId,
+ method: "set_feedback",
+ args: {
+ value: userAction.value,
+ },
+ }),
+ onSuccess: () => {
+ article.reload();
+ },
+});
+
+const userAction = ref("");
+function handleFeedbackClick(action: Feedback) {
+ if (
+ articleFeedback.value.user_feedback &&
+ articleFeedback.value.user_feedback === action
+ ) {
+ articleFeedback.value.user_feedback = null;
+
+ userAction.value = "";
+ } else {
+ articleFeedback.value.user_feedback = action;
+ userAction.value = action;
+ }
+ handleOptimisticUpdate(action);
+
+ setFeedback.submit();
+}
+
+function handleOptimisticUpdate(action: Feedback) {
+ if (action === "Like" && action === articleFeedback.value.user_feedback) {
+ articleFeedback.value.total_likes++;
+ articleFeedback.value.total_dislikes > 0 &&
+ articleFeedback.value.total_dislikes--;
+ } else if (
+ action === "Dislike" &&
+ action === articleFeedback.value.user_feedback
+ ) {
+ articleFeedback.value.total_dislikes++;
+ articleFeedback.value.total_likes > 0 &&
+ articleFeedback.value.total_likes--;
+ } else if (action == "Like" && !articleFeedback.value.user_feedback) {
+ articleFeedback.value.total_likes--;
+ } else if (action == "Dislike" && !articleFeedback.value.user_feedback) {
+ articleFeedback.value.total_dislikes--;
+ }
+}
+
const category = createDocumentResource({
doctype: "HD Article Category",
name: categoryId.value,
diff --git a/desk/src/types.ts b/desk/src/types.ts
index 97d40f0fc..d428705da 100644
--- a/desk/src/types.ts
+++ b/desk/src/types.ts
@@ -246,3 +246,11 @@ export interface Category {
};
children?: (Article | SubCategory)[];
}
+
+export interface ArticleFeedback {
+ user_feedback: string;
+ total_likes: number;
+ total_dislikes: number;
+}
+
+export type Feedback = "Like" | "Dislike" | "";
diff --git a/helpdesk/helpdesk/doctype/hd_article/api.py b/helpdesk/helpdesk/doctype/hd_article/api.py
index 84be868b1..5e07733f3 100644
--- a/helpdesk/helpdesk/doctype/hd_article/api.py
+++ b/helpdesk/helpdesk/doctype/hd_article/api.py
@@ -17,9 +17,28 @@ def get_article(name: str):
"HD Article Category", sub_category.parent_category or article["category"]
)
+ user = frappe.session.user
+ # TODO: views count increment with views field in HD Article
+ # if not is_agent() and user != author.name:
+ # frappe.db.set_value("HD Article", name, "views", article["views"] + 1)
+
+ feedbacks = {
+ "user_feedback": frappe.db.get_value(
+ "HD Article Feedback", {"user": user, "parent": name}, "feedback"
+ )
+ or None,
+ "total_likes": frappe.db.count(
+ "HD Article Feedback", {"parent": name, "feedback": "Like"}
+ ),
+ "total_dislikes": frappe.db.count(
+ "HD Article Feedback", {"parent": name, "feedback": "Dislike"}
+ ),
+ }
+
return {
**article,
"author": author,
"category": category,
"sub_category": sub_category,
+ "feedbacks": feedbacks,
}
diff --git a/helpdesk/helpdesk/doctype/hd_article/hd_article.json b/helpdesk/helpdesk/doctype/hd_article/hd_article.json
index d8b2db488..d86c6d703 100644
--- a/helpdesk/helpdesk/doctype/hd_article/hd_article.json
+++ b/helpdesk/helpdesk/doctype/hd_article/hd_article.json
@@ -17,7 +17,9 @@
"subtitle",
"article_image",
"content_section",
- "content"
+ "content",
+ "feedbacks_section",
+ "feedbacks"
],
"fields": [
{
@@ -97,11 +99,22 @@
"fieldname": "subtitle",
"fieldtype": "Small Text",
"label": "Subtitle"
+ },
+ {
+ "fieldname": "feedbacks_section",
+ "fieldtype": "Section Break",
+ "label": "Feedbacks"
+ },
+ {
+ "fieldname": "feedbacks",
+ "fieldtype": "Table",
+ "label": "feedbacks",
+ "options": "HD Article Feedback"
}
],
"links": [],
"make_attachments_public": 1,
- "modified": "2024-10-01 21:39:58.189965",
+ "modified": "2024-11-24 22:54:55.477514",
"modified_by": "Administrator",
"module": "Helpdesk",
"name": "HD Article",
diff --git a/helpdesk/helpdesk/doctype/hd_article/hd_article.py b/helpdesk/helpdesk/doctype/hd_article/hd_article.py
index c0e296c6c..b29b3c6d1 100644
--- a/helpdesk/helpdesk/doctype/hd_article/hd_article.py
+++ b/helpdesk/helpdesk/doctype/hd_article/hd_article.py
@@ -52,6 +52,21 @@ def before_save(self):
)
)
+ @frappe.whitelist()
+ def set_feedback(self, value):
+ user = frappe.session.user
+ feedback_exists = frappe.db.exists(
+ "HD Article Feedback", {"user": user, "parent": self.name}
+ )
+ if feedback_exists:
+ frappe.db.set_value(
+ "HD Article Feedback", feedback_exists, "feedback", value
+ )
+ return
+
+ self.append("feedbacks", {"user": user, "feedback": value})
+ self.save()
+
@property
def title_slug(self) -> str:
"""
diff --git a/helpdesk/helpdesk/doctype/hd_article_feedback/hd_article_feedback.js b/helpdesk/helpdesk/doctype/hd_article_feedback/hd_article_feedback.js
deleted file mode 100644
index ddb38d38d..000000000
--- a/helpdesk/helpdesk/doctype/hd_article_feedback/hd_article_feedback.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright (c) 2022, Frappe Technologies and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on("HD Article Feedback", {
- // refresh: function(frm) {
- // }
-});
diff --git a/helpdesk/helpdesk/doctype/hd_article_feedback/hd_article_feedback.json b/helpdesk/helpdesk/doctype/hd_article_feedback/hd_article_feedback.json
index 1114e3462..6e10b653e 100644
--- a/helpdesk/helpdesk/doctype/hd_article_feedback/hd_article_feedback.json
+++ b/helpdesk/helpdesk/doctype/hd_article_feedback/hd_article_feedback.json
@@ -1,67 +1,39 @@
{
"actions": [],
"allow_rename": 1,
- "creation": "2022-10-18 23:01:11.913095",
+ "creation": "2024-11-24 18:33:16.603719",
"doctype": "DocType",
- "editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "article",
"user",
"feedback"
],
"fields": [
- {
- "fieldname": "article",
- "fieldtype": "Link",
- "label": "Article",
- "options": "HD Article"
- },
{
"fieldname": "user",
"fieldtype": "Link",
+ "in_list_view": 1,
"label": "User",
"options": "User"
},
{
"fieldname": "feedback",
- "fieldtype": "Int",
- "label": "Feedback"
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Feedback",
+ "options": "\nLike\nDislike"
}
],
"index_web_pages_for_search": 1,
+ "istable": 1,
"links": [],
- "modified": "2023-03-26 23:06:42.029313",
+ "modified": "2024-11-24 18:46:11.731463",
"modified_by": "Administrator",
"module": "Helpdesk",
"name": "HD Article Feedback",
"owner": "Administrator",
- "permissions": [
- {
- "create": 1,
- "delete": 1,
- "email": 1,
- "export": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "System Manager",
- "share": 1,
- "write": 1
- },
- {
- "email": 1,
- "export": 1,
- "if_owner": 1,
- "print": 1,
- "read": 1,
- "report": 1,
- "role": "All",
- "share": 1,
- "write": 1
- }
- ],
- "sort_field": "modified",
+ "permissions": [],
+ "sort_field": "creation",
"sort_order": "DESC",
"states": []
-}
+}
\ No newline at end of file
diff --git a/helpdesk/helpdesk/doctype/hd_article_feedback/test_hd_article_feedback.py b/helpdesk/helpdesk/doctype/hd_article_feedback/test_hd_article_feedback.py
deleted file mode 100644
index 4083e9b31..000000000
--- a/helpdesk/helpdesk/doctype/hd_article_feedback/test_hd_article_feedback.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright (c) 2022, Frappe Technologies and Contributors
-# See license.txt
-
-# import frappe
-from frappe.tests.utils import FrappeTestCase
-
-
-class TestHDArticleFeedback(FrappeTestCase):
- pass