2020-10-06 21:35:13 +02:00
|
|
|
// @flow
|
|
|
|
import { SORT_COMMENTS_NEW, SORT_COMMENTS_BEST, SORT_COMMENTS_CONTROVERSIAL } from 'constants/comment';
|
2022-01-24 17:07:09 +01:00
|
|
|
import { FREE_GLOBAL_STICKERS, PAID_GLOBAL_STICKERS } from 'constants/stickers';
|
|
|
|
import * as REACTION_TYPES from 'constants/reactions';
|
|
|
|
|
|
|
|
const ALL_VALID_STICKERS = [...FREE_GLOBAL_STICKERS, ...PAID_GLOBAL_STICKERS];
|
|
|
|
const stickerRegex = /(<stkr>:[A-Z0-9_]+:<stkr>)/;
|
2020-10-06 21:35:13 +02:00
|
|
|
|
|
|
|
// Mostly taken from Reddit's sorting functions
|
|
|
|
// https://github.com/reddit-archive/reddit/blob/master/r2/r2/lib/db/_sorts.pyx
|
|
|
|
|
2020-10-07 22:18:16 +02:00
|
|
|
type SortProps = {
|
|
|
|
comments: ?Array<Comment>,
|
|
|
|
reactionsById: {},
|
|
|
|
sort: string,
|
2021-05-17 21:55:23 +02:00
|
|
|
isMyComment: (string) => boolean,
|
2020-10-07 22:18:16 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
export function sortComments(sortProps: SortProps): Array<Comment> {
|
2021-07-15 16:43:28 +02:00
|
|
|
const { comments, reactionsById, sort, isMyComment } = sortProps;
|
2020-10-07 22:18:16 +02:00
|
|
|
|
2021-05-15 06:56:58 +02:00
|
|
|
if (!comments) return [];
|
2020-10-06 21:35:13 +02:00
|
|
|
|
2020-10-07 22:18:16 +02:00
|
|
|
return comments.slice().sort((a: Comment, b: Comment) => {
|
2020-10-08 17:31:36 +02:00
|
|
|
if (a.is_pinned) {
|
|
|
|
return -1;
|
|
|
|
} else if (b.is_pinned) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-05-15 06:56:58 +02:00
|
|
|
if (sort === SORT_COMMENTS_NEW) return 0;
|
2020-10-06 21:35:13 +02:00
|
|
|
|
2020-10-07 22:18:16 +02:00
|
|
|
const aIsMine = isMyComment(a.channel_id);
|
|
|
|
const bIsMine = isMyComment(b.channel_id);
|
|
|
|
|
2021-07-15 16:43:28 +02:00
|
|
|
if (aIsMine) {
|
2020-10-07 22:18:16 +02:00
|
|
|
return -1;
|
2021-07-15 16:43:28 +02:00
|
|
|
} else if (bIsMine) {
|
2020-10-07 22:18:16 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-10-06 21:35:13 +02:00
|
|
|
const aReactions = reactionsById[a.comment_id];
|
|
|
|
const bReactions = reactionsById[b.comment_id];
|
|
|
|
const aLikes = (aReactions && aReactions[REACTION_TYPES.LIKE]) || 0;
|
|
|
|
const aDislikes = (aReactions && aReactions[REACTION_TYPES.DISLIKE]) || 0;
|
|
|
|
const bLikes = (bReactions && bReactions[REACTION_TYPES.LIKE]) || 0;
|
|
|
|
const bDislikes = (bReactions && bReactions[REACTION_TYPES.DISLIKE]) || 0;
|
|
|
|
|
2020-10-07 22:18:16 +02:00
|
|
|
if (sort === SORT_COMMENTS_CONTROVERSIAL) {
|
2020-10-06 21:35:13 +02:00
|
|
|
if (aLikes === 0 && aDislikes === 0) {
|
|
|
|
return 1;
|
|
|
|
} else if (bLikes === 0 && bDislikes === 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const aMagnitude = aLikes + aDislikes;
|
|
|
|
const bMagnitude = bLikes + bDislikes;
|
|
|
|
|
|
|
|
const aBalance = aLikes > aDislikes ? aDislikes / aLikes : aLikes / aDislikes;
|
|
|
|
const bBalance = bLikes > bDislikes ? bDislikes / bLikes : bLikes / bDislikes;
|
|
|
|
|
|
|
|
return bMagnitude ** bBalance - aMagnitude ** aBalance;
|
|
|
|
}
|
|
|
|
|
2020-10-07 22:18:16 +02:00
|
|
|
if (sort === SORT_COMMENTS_BEST) {
|
2020-10-06 21:35:13 +02:00
|
|
|
const aN = aLikes + aDislikes;
|
|
|
|
const bN = bLikes + bDislikes;
|
|
|
|
|
2020-10-28 17:17:22 +01:00
|
|
|
if (aLikes === 0 && bLikes === 0 && (aDislikes || bDislikes)) {
|
|
|
|
return aDislikes - bDislikes;
|
2020-11-02 23:15:06 +01:00
|
|
|
} else if (aLikes === 0 && bLikes > 0) {
|
|
|
|
return 1;
|
|
|
|
} else if (bLikes === 0 && aLikes > 1) {
|
|
|
|
return -1;
|
2020-10-06 21:35:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const z = 1.281551565545; // 80% confidence
|
|
|
|
const aP = aLikes / aN;
|
|
|
|
const bP = bLikes / bN;
|
|
|
|
|
|
|
|
const aLeft = aP + (1 / (2 * aN)) * z * z;
|
|
|
|
const aRight = z * Math.sqrt((aP * (1 - aP)) / aN + (z * z) / (4 * aN * aN));
|
|
|
|
const aUnder = 1 + (1 / aN) * z * z;
|
|
|
|
|
|
|
|
const bLeft = bP + (1 / (2 * bN)) * z * z;
|
|
|
|
const bRight = z * Math.sqrt((bP * (1 - bP)) / bN + (z * z) / (4 * bN * bN));
|
|
|
|
const bUnder = 1 + (1 / bN) * z * z;
|
|
|
|
|
|
|
|
return (bLeft - bRight) / bUnder - (aLeft - aRight) / aUnder;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
});
|
|
|
|
}
|
2022-01-24 17:07:09 +01:00
|
|
|
|
|
|
|
export const buildValidSticker = (sticker: string) => `<stkr>${sticker}<stkr>`;
|
|
|
|
|
|
|
|
export function parseSticker(comment: string) {
|
|
|
|
const matchSticker = comment.match(stickerRegex);
|
|
|
|
const stickerValue = matchSticker && matchSticker[0];
|
|
|
|
const commentIsSticker = stickerValue && stickerValue.length === comment.length;
|
|
|
|
|
|
|
|
return (
|
|
|
|
commentIsSticker &&
|
|
|
|
ALL_VALID_STICKERS.find((sticker) => {
|
|
|
|
// $FlowFixMe
|
|
|
|
return sticker.name === stickerValue.replaceAll('<stkr>', '');
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
2022-02-09 16:27:11 +01:00
|
|
|
|
|
|
|
export function getStickerUrl(comment: string) {
|
|
|
|
const stickerFromComment = parseSticker(comment);
|
|
|
|
return stickerFromComment && stickerFromComment.url;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getCommentsListTitle(totalComments: number) {
|
|
|
|
const title =
|
|
|
|
(totalComments === 0 && __('Leave a comment')) ||
|
|
|
|
(totalComments === 1 && __('1 comment')) ||
|
|
|
|
__('%total_comments% comments', { total_comments: totalComments });
|
|
|
|
|
|
|
|
return title;
|
|
|
|
}
|