diff --git a/api/posts-service/get.js b/api/posts-service/get.js
index cc4da971..2f431363 100644
--- a/api/posts-service/get.js
+++ b/api/posts-service/get.js
@@ -2,21 +2,78 @@ import * as dynamoDbLib from "../libs/dynamodb-lib";
import * as userNameLib from "../libs/username-lib";
import { success, failure } from "../libs/response-lib";
+async function countReplyComments(commentId) {
+ const params = {
+ TableName: "NaadanChordsComments",
+ ScanFilter: {
+ commentId: {
+ ComparisonOperator: "EQ",
+ AttributeValueList: [commentId],
+ },
+ },
+ };
+ const comment = await dynamoDbLib.call("scan", params);
+ if (comment.Items && comment.Items.length === 1) {
+ let count = 1;
+ let commentItem = comment.Items[0];
+ let replies = commentItem.replies || [];
+ for (let i = 0; i < replies.length; i++) {
+ const replyCommentsCount = await countReplyComments(replies[i]);
+ count += replyCommentsCount;
+ }
+ return count;
+ }
+ return 0;
+}
+
+async function appendCommentsCount(item) {
+ let filterExpression = "contains(postId, :postId)";
+ let expressionAttributeValues = {};
+ expressionAttributeValues[`:postId`] = item.postId;
+
+ let params = {
+ TableName: "NaadanChordsComments",
+ FilterExpression: filterExpression,
+ ExpressionAttributeValues: expressionAttributeValues,
+ };
+
+ try {
+ let commentsResult = await dynamoDbLib.call("scan", params);
+ let comments = commentsResult.Items;
+ let commentsCount = 0;
+
+ for (let i = 0; i < comments.length; i++) {
+ let commentItem = comments[i];
+ let replies = commentItem.replies || [];
+ commentsCount += 1;
+ for (let j = 0; j < replies.length; j++) {
+ const replyCommentsCount = await countReplyComments(replies[j]);
+ commentsCount += replyCommentsCount;
+ }
+ }
+ item.commentsCount = commentsCount;
+ } catch (e) {
+ item.commentsError = e;
+ }
+
+ return item;
+}
+
async function appendRating(item) {
const params = {
TableName: "NaadanChordsRatings",
Key: {
- postId: item.postId
- }
+ postId: item.postId,
+ },
};
try {
let ratingResult = await dynamoDbLib.call("get", params);
- if(ratingResult && ratingResult.hasOwnProperty("Item")) {
+ if (ratingResult && ratingResult.hasOwnProperty("Item")) {
item.rating = ratingResult.Item.rating;
item.ratingCount = ratingResult.Item.count;
}
- } catch(e) {
+ } catch (e) {
item.ratingError = e;
}
@@ -26,7 +83,7 @@ async function appendRating(item) {
function retryLoop(postId) {
let keywords = postId.split("-");
- if(keywords.length > 1) {
+ if (keywords.length > 1) {
keywords.pop();
return retryGet(keywords.join("-"));
} else {
@@ -38,28 +95,29 @@ async function retryGet(postId) {
let params = {
TableName: "NaadanChords",
ScanFilter: {
- "postId": {
+ postId: {
ComparisonOperator: "CONTAINS",
- AttributeValueList: [postId]
- }
- }
+ AttributeValueList: [postId],
+ },
+ },
};
- if(postId.length > 2) {
+ if (postId.length > 2) {
try {
const result = await dynamoDbLib.call("scan", params);
- if(result.Items.length > 0) {
+ if (result.Items.length > 0) {
let finalResult = result.Items[0];
let userId = finalResult.userId;
//Get full attributes of author
let authorAttributes = await userNameLib.getAuthorAttributes(userId);
finalResult.authorName = authorAttributes.authorName;
- finalResult.userName = authorAttributes.preferredUsername ?? authorAttributes.userName;
+ finalResult.userName =
+ authorAttributes.preferredUsername ?? authorAttributes.userName;
finalResult.authorPicture = authorAttributes.picture;
//Do not expose userId
- delete(finalResult.userId);
+ delete finalResult.userId;
finalResult = await appendRating(finalResult);
return success(finalResult);
@@ -78,8 +136,8 @@ export async function main(event, context) {
const params = {
TableName: "NaadanChords",
Key: {
- postId: event.pathParameters.id
- }
+ postId: event.pathParameters.id,
+ },
};
try {
@@ -90,13 +148,15 @@ export async function main(event, context) {
//Get full attributes of author
let authorAttributes = await userNameLib.getAuthorAttributes(userId);
result.Item.authorName = authorAttributes.authorName;
- result.Item.userName = authorAttributes.preferredUsername ?? authorAttributes.userName;
+ result.Item.userName =
+ authorAttributes.preferredUsername ?? authorAttributes.userName;
result.Item.authorPicture = authorAttributes.picture;
//Do not expose userId
- delete(result.Item.userId);
+ delete result.Item.userId;
let finalResult = await appendRating(result.Item);
+ finalResult = await appendCommentsCount(result.Item);
return success(finalResult);
} else {
return retryGet(event.pathParameters.id);
@@ -104,4 +164,4 @@ export async function main(event, context) {
} catch (e) {
return failure({ status: false, error: e });
}
-}
\ No newline at end of file
+}
diff --git a/api/posts-service/list.js b/api/posts-service/list.js
index 0cef9293..a1230547 100644
--- a/api/posts-service/list.js
+++ b/api/posts-service/list.js
@@ -2,6 +2,81 @@ import * as dynamoDbLib from "../libs/dynamodb-lib";
import * as userNameLib from "../libs/username-lib";
import * as searchFilterLib from "../libs/searchfilter-lib";
+async function countReplyComments(commentId) {
+ const params = {
+ TableName: "NaadanChordsComments",
+ ScanFilter: {
+ commentId: {
+ ComparisonOperator: "EQ",
+ AttributeValueList: [commentId],
+ },
+ },
+ };
+ const comment = await dynamoDbLib.call("scan", params);
+ if (comment.Items && comment.Items.length === 1) {
+ let count = 1;
+ let commentItem = comment.Items[0];
+ let replies = commentItem.replies || [];
+ for (let i = 0; i < replies.length; i++) {
+ const replyCommentsCount = await countReplyComments(replies[i]);
+ count += replyCommentsCount;
+ }
+ return count;
+ }
+ return 0;
+}
+
+async function appendCommentsCount(result) {
+ let items = result.Items;
+ let filterExpression = "";
+ let expressionAttributeValues = {};
+
+ for (let i = 0; i < items.length; i++) {
+ let postId = items[i].postId;
+ if (filterExpression) {
+ filterExpression += ` OR contains(postId, :postId${i})`;
+ } else {
+ filterExpression = `contains(postId, :postId${i})`;
+ }
+ expressionAttributeValues[`:postId${i}`] = postId;
+ }
+
+ let params = {
+ TableName: "NaadanChordsComments",
+ FilterExpression: filterExpression,
+ ExpressionAttributeValues: expressionAttributeValues,
+ };
+
+ try {
+ let commentsResult = await dynamoDbLib.call("scan", params);
+ let comments = commentsResult.Items;
+ let commentsObject = {};
+
+ for (let i = 0; i < comments.length; i++) {
+ let commentItem = comments[i];
+ let replies = commentItem.replies || [];
+ commentsObject[commentItem.postId] =
+ (commentsObject[commentItem.postId] || 0) + 1;
+ for (let j = 0; j < replies.length; j++) {
+ const replyCommentsCount = await countReplyComments(replies[j]);
+ commentsObject[commentItem.postId] += replyCommentsCount;
+ }
+ }
+
+ for (let i = 0; i < items.length; i++) {
+ if (commentsObject.hasOwnProperty(items[i].postId)) {
+ items[i].commentsCount = commentsObject[items[i].postId];
+ }
+ }
+
+ result.Items = items;
+ } catch (e) {
+ result.commentsError = e;
+ }
+
+ return result;
+}
+
async function appendRatings(result) {
let items = result.Items;
let filterExpression = "";
@@ -213,6 +288,9 @@ export async function main(event, context, callback) {
//append ratings
let finalResult = await appendRatings(result);
+ //append comments count
+ finalResult = await appendCommentsCount(result);
+
return finalResult;
} catch (e) {
return { status: false, error: e };
diff --git a/package-lock.json b/package-lock.json
index 229cf6ea..eda1f11c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "naadan-chords",
- "version": "0.80.3",
+ "version": "0.80.4",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "naadan-chords",
- "version": "0.80.3",
+ "version": "0.80.4",
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.34",
"@fortawesome/free-brands-svg-icons": "^5.15.2",
diff --git a/package.json b/package.json
index 2d2fbac0..05d4c404 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "naadan-chords",
- "version": "0.80.3",
+ "version": "0.80.4",
"homepage": "https://www.naadanchords.com/",
"private": true,
"dependencies": {
diff --git a/src/containers/Content.css b/src/containers/Content.css
index 2c45e872..60b1ebe7 100644
--- a/src/containers/Content.css
+++ b/src/containers/Content.css
@@ -31,7 +31,7 @@
padding: 0.1em 0.4em 0.02em 0.4em;
vertical-align: text-bottom;
cursor: pointer;
- line-height: 0.93rem;
+ line-height: 1.05rem;
}
.Content .post small .badge {
@@ -141,6 +141,37 @@
top: -2px;
}
+.Content .rating-comments-container {
+ margin-top: 7px;
+}
+
+.Content .rating-comments-container.post-list {
+ float: right;
+ margin-top: 0;
+}
+
+.Content .post-comment-count {
+ margin-left: 0;
+ cursor: pointer;
+}
+
+.Content .post-comment-count.post-list {
+ margin-left: 10px;
+}
+
+.Content .post-comment-count .comment-text-container {
+ font-weight: bold;
+}
+
+.Content .post-comment-count .comment-icon {
+ margin-left: 4px;
+ font-size: 11px;
+}
+
+.Content .post-comment-count.post-list .comment-icon {
+ font-size: 9px;
+}
+
.Content .rate-container {
position: relative;
}
@@ -195,6 +226,10 @@
display: none;
}
+ .Content .post small .post-comment-count span.separator {
+ display: inline-block;
+ }
+
.Content .post small .meta-time-container {
display: block;
position: relative;
@@ -213,8 +248,9 @@
display: block;
}
- .Content .post-rating.post-list {
- display: block;
+ .Content .rating-comments-container {
+ display: flex;
+ float: none;
}
.Content .postList .post small span.separator {
diff --git a/src/containers/Content.js b/src/containers/Content.js
index 84b78c73..93c22f6e 100644
--- a/src/containers/Content.js
+++ b/src/containers/Content.js
@@ -22,6 +22,7 @@ import {
faRandom,
faHistory,
faUserCircle,
+ faCommentAlt,
} from "@fortawesome/free-solid-svg-icons";
import { slugify, capitalizeFirstLetter } from "../libs/utils";
import Sidebar from "./Sidebar";
@@ -302,7 +303,10 @@ export default class Content extends Component {
+ {
+ e.preventDefault();
+ this.ratingEl.current.scrollIntoView({
+ behavior: "instant",
+ block: "start",
+ });
+ this.ratingEl.current.click();
+ }}
+ >
+ Click here to add a comment
+
+
+ );
+ }
+ };
+
renderRateLink = (isPostList) => {
if (!isPostList) {
return (
@@ -366,7 +394,6 @@ export default class Content extends Component {
renderRating = (post, isPostList) => {
return (
- |
+
+ Why don't you start a discussion? :)
+
+ {this.renderCommentLink(isPostList)}
+