import { AppState } from "reducers"; import { get } from "lodash"; import { CommentThread, Comment } from "entities/Comments/CommentsInterfaces"; import { options as filterOptions } from "comments/AppComments/AppCommentsFilterPopover"; import moment from "moment"; export const refCommentThreadsSelector = ( refId: string, applicationId?: string, ) => (state: AppState) => get( state.ui.comments.applicationCommentThreadsByRef, `${applicationId}.${refId}`, [], ); export const commentThreadsSelector = (commentThreadId: string) => ( state: AppState, ) => state.ui.comments.commentThreadsMap[commentThreadId]; export const unpublishedCommentThreadSelector = (refId: string) => ( state: AppState, ) => state.ui.comments.unpublishedCommentThreads[refId]; export const commentModeSelector = (state: AppState) => state.ui.comments?.isCommentMode; export const applicationCommentsSelector = (applicationId: string) => ( state: AppState, ) => state.ui.comments.applicationCommentThreadsByRef[applicationId]; export const areCommentsEnabledForUserAndApp = (state: AppState) => state.ui.comments?.areCommentsEnabled; /** * Comments are stored as a map of refs (for example widgetIds) * Flatten to fetch all application comment threads */ export const getAppCommentThreads = ( threadsByRefMap: Record>, ): Array => { if (!threadsByRefMap) return []; return Object.entries(threadsByRefMap).reduce( (res: Array, [, threadIds]) => { return [...res, ...threadIds]; }, [], ); }; export const allCommentThreadsMap = (state: AppState) => state.ui.comments.commentThreadsMap; const getSortIndexBool = (a: boolean, b: boolean) => { if (a && b) return 0; if (a) return -1; if (b) return 1; else return 0; }; const getSortIndexTime = ( a: string | number = new Date().toISOString(), b: string | number = new Date().toISOString(), ) => { if (moment(a).isSame(moment(b))) return 0; if (moment(a).isAfter(moment(b))) return -1; else return 1; }; const getContainsMyComment = ( thread: CommentThread, currentUserUsername?: string, ) => thread.comments.some( (comment: Comment) => comment.authorUsername === currentUserUsername, ); export const getSortedAndFilteredAppCommentThreadIds = ( applicationThreadIds: Array, commentThreadsMap: Record, shouldShowResolved: boolean, appCommentsFilter: typeof filterOptions[number]["value"], currentUserUsername?: string, ): Array => { if (!applicationThreadIds) return []; return applicationThreadIds .sort((a, b) => { const { pinnedState: isAPinned, updationTime: updationTimeA, } = commentThreadsMap[a]; const { pinnedState: isBPinned, updationTime: updationTimeB, } = commentThreadsMap[b]; let sortIdx = getSortIndexBool(!!isAPinned?.active, !!isBPinned?.active); if (sortIdx !== 0) return sortIdx; sortIdx = getSortIndexTime( isAPinned?.updationTime?.epochSecond, isBPinned?.updationTime?.epochSecond, ); if (sortIdx !== 0) return sortIdx; return getSortIndexTime(updationTimeA, updationTimeB); }) .filter((threadId: string) => { const thread = commentThreadsMap[threadId]; // Happens during delete thread if (!thread) return false; const isResolved = thread.resolvedState?.active; const isPinned = thread.pinnedState?.active; switch (appCommentsFilter) { case "show-only-yours": { const containsMyComment = getContainsMyComment( thread, currentUserUsername, ); return containsMyComment; } case "show-only-pinned": { return isPinned && (!isResolved || shouldShowResolved); } default: { return shouldShowResolved || !isResolved; } } }); }; export const shouldShowResolved = (state: AppState) => state.ui.comments.shouldShowResolvedAppCommentThreads; export const appCommentsFilter = (state: AppState) => state.ui.comments.appCommentsFilter; export const showUnreadIndicator = (state: AppState) => state.ui.comments.showUnreadIndicator; export const visibleCommentThread = (state: AppState) => state.ui.comments.visibleCommentThreadId; export const isIntroCarouselVisibleSelector = (state: AppState) => state.ui.comments.isIntroCarouselVisible;