"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = tslib_1.__importStar(require("react"));
const styles_1 = require("@mui/material/styles");
const Widget_1 = tslib_1.__importDefault(require("../Widget"));
const react_intl_1 = require("react-intl");
const material_1 = require("@mui/material");
const Bullet_1 = tslib_1.__importDefault(require("../../shared/Bullet"));
const classnames_1 = tslib_1.__importDefault(require("classnames"));
const Errors_1 = require("../../constants/Errors");
const Skeleton_1 = tslib_1.__importDefault(require("./Skeleton"));
const comments_1 = require("../../types/comments");
const CommentsObject_1 = tslib_1.__importDefault(require("../CommentsObject"));
const CommentObjectReply_1 = tslib_1.__importDefault(require("../CommentObjectReply"));
const ContributionActionsMenu_1 = tslib_1.__importDefault(require("../../shared/ContributionActionsMenu"));
const DateTimeAgo_1 = tslib_1.__importDefault(require("../../shared/DateTimeAgo"));
const contribution_1 = require("../../utils/contribution");
const notistack_1 = require("notistack");
const system_1 = require("@mui/system");
const BaseItem_1 = tslib_1.__importDefault(require("../../shared/BaseItem"));
const types_1 = require("@selfcommunity/types");
const api_services_1 = require("@selfcommunity/api-services");
const utils_1 = require("@selfcommunity/utils");
const react_core_1 = require("@selfcommunity/react-core");
const VoteButton_1 = tslib_1.__importDefault(require("../VoteButton"));
const VoteAudienceButton_1 = tslib_1.__importDefault(require("../VoteAudienceButton"));
const UserDeletedSnackBar_1 = tslib_1.__importDefault(require("../../shared/UserDeletedSnackBar"));
const UserAvatar_1 = tslib_1.__importDefault(require("../../shared/UserAvatar"));
const constants_1 = require("./constants");
const classes = {
    root: `${constants_1.PREFIX}-root`,
    comment: `${constants_1.PREFIX}-comment`,
    nestedComments: `${constants_1.PREFIX}-nested-comments`,
    avatar: `${constants_1.PREFIX}-avatar`,
    content: `${constants_1.PREFIX}-content`,
    showMoreContent: `${constants_1.PREFIX}-show-more-content`,
    author: `${constants_1.PREFIX}-author`,
    textContent: `${constants_1.PREFIX}-text-content`,
    commentActionsMenu: `${constants_1.PREFIX}-comment-actions-menu`,
    deleted: `${constants_1.PREFIX}-deleted`,
    activityAt: `${constants_1.PREFIX}-activity-at`,
    vote: `${constants_1.PREFIX}-vote`,
    voteAudience: `${constants_1.PREFIX}-vote-audience`,
    reply: `${constants_1.PREFIX}-reply`,
    contentSubSection: `${constants_1.PREFIX}-comment-sub-section`,
    collapsed: `${constants_1.PREFIX}-collapsed`,
    flagChip: `${constants_1.PREFIX}-flag-chip`
};
const Root = (0, styles_1.styled)(material_1.Box, {
    name: constants_1.PREFIX,
    slot: 'Root'
})(() => ({}));
/**
 * > API documentation for the Community-JS Comment Object component. Learn about the available props and the CSS API.
 *
 *
 * This component renders a comment item.
 * Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/CommentObject)

 #### Import

 ```jsx
 import {CommentObject} from '@selfcommunity/react-ui';
 ```

 #### Component Name

 The name `SCCommentObject` can be used when providing style overrides in the theme.


 #### CSS

 |Rule Name|Global class|Description|
 |---|---|---|
 |root|.SCCommentObject-root|Styles applied to the root element.|
 |comment|.SCCommentObject-comment|Styles applied to comment element.|
 |nestedComments|.SCCommentObject-nestedComments|Styles applied to nested comments element wrapper.|
 |avatar|.SCCommentObject-avatar|Styles applied to the avatar element.|
 |author|.SCCommentObject-author|Styles applied to the author section.|
 |content|.SCCommentObject-content|Styles applied to content section.|
 |textContent|.SCCommentObject-text-content|Styles applied to text content section.|
 |vote|.SCCommentObject-vote|Styles applied to the votes section.|
 |btnVotes|.SCCommentObject-vote-audience|Styles applied to the votes audience section.|
 |commentActionsMenu|.SCCommentObject-comment-actions-menu|Styles applied to comment action menu element.|
 |deleted|.SCCommentObject-deleted|Styles applied to tdeleted element.|
 |activityAt|.SCCommentObject-activity-at|Styles applied to activity at section.|
 |reply|.SCCommentObject-reply|Styles applied to the reply element.|
 |contentSubSection|.SCCommentObject-content-sub-section|Styles applied to the comment subsection|

 * @param inProps
 */
function CommentObject(inProps) {
    // PROPS
    const props = (0, system_1.useThemeProps)({
        props: inProps,
        name: constants_1.PREFIX
    });
    const { id = `comment_object_${props.commentObjectId ? props.commentObjectId : props.commentObject ? props.commentObject.id : ''}`, className, commentObjectId, commentObject, feedObjectId, feedObject, feedObjectType = types_1.SCContributionType.POST, commentReply, onOpenReply, onDelete, onCollapsed, onRestore, onVote, elevation = 0, truncateContent = false, CommentObjectSkeletonProps = { elevation, WidgetProps: { variant: 'outlined' } }, CommentObjectReplyProps = { elevation, WidgetProps: { variant: 'outlined' } }, linkableCommentDateTime = true, cacheStrategy = utils_1.CacheStrategies.NETWORK_ONLY, CommentsObjectComponentProps = {} } = props, rest = tslib_1.__rest(props, ["id", "className", "commentObjectId", "commentObject", "feedObjectId", "feedObject", "feedObjectType", "commentReply", "onOpenReply", "onDelete", "onCollapsed", "onRestore", "onVote", "elevation", "truncateContent", "CommentObjectSkeletonProps", "CommentObjectReplyProps", "linkableCommentDateTime", "cacheStrategy", "CommentsObjectComponentProps"]);
    // CONTEXT
    const scContext = (0, react_core_1.useSCContext)();
    const scUserContext = (0, react_1.useContext)(react_core_1.SCUserContext);
    const scRoutingContext = (0, react_core_1.useSCRouting)();
    const { enqueueSnackbar } = (0, notistack_1.useSnackbar)();
    // STATE
    const { obj, setObj } = (0, react_core_1.useSCFetchCommentObject)({ id: commentObjectId, commentObject, cacheStrategy });
    const [collapsed, setCollapsed] = (0, react_1.useState)(obj === null || obj === void 0 ? void 0 : obj.collapsed);
    const [replyComment, setReplyComment] = (0, react_1.useState)(commentReply);
    const [isReplying, setIsReplying] = (0, react_1.useState)(false);
    const [isSavingComment, setIsSavingComment] = (0, react_1.useState)(false);
    const [editComment, setEditComment] = (0, react_1.useState)(null);
    const commentsObject = (0, react_core_1.useSCFetchCommentObjects)({
        id: feedObjectId,
        feedObject,
        feedObjectType,
        orderBy: comments_1.SCCommentsOrderBy.ADDED_AT_DESC,
        parent: commentObject ? commentObject.id : commentObjectId,
        cacheStrategy
    });
    const [openAlert, setOpenAlert] = (0, react_1.useState)(false);
    // HANDLERS
    const handleVoteSuccess = (contribution) => {
        setObj(contribution);
        onVote && onVote(contribution);
    };
    /**
     * Update state object
     * @param newObj
     */
    function updateObject(newObj) {
        utils_1.LRUCache.set(react_core_1.SCCache.getCommentObjectCacheKey(obj.id), newObj);
        setObj(newObj);
        const contributionType = (0, contribution_1.getContributionType)(obj);
        utils_1.LRUCache.deleteKeysWithPrefix(react_core_1.SCCache.getCommentObjectsCachePrefixKeys(newObj[contributionType].id, contributionType));
    }
    /**
     * Render added_at of the comment
     * @param comment
     */
    function renderTimeAgo(comment) {
        return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: linkableCommentDateTime ? ((0, jsx_runtime_1.jsx)(react_core_1.Link, Object.assign({ to: scRoutingContext.url(react_core_1.SCRoutes.COMMENT_ROUTE_NAME, (0, contribution_1.getRouteData)(comment)), className: classes.activityAt }, { children: (0, jsx_runtime_1.jsx)(DateTimeAgo_1.default, { date: comment.added_at }) }))) : ((0, jsx_runtime_1.jsx)(DateTimeAgo_1.default, { date: comment.added_at })) }));
    }
    /**
     * Render CommentObjectReply action
     * @param comment
     */
    function renderActionReply(comment) {
        return ((0, jsx_runtime_1.jsx)(material_1.Button, Object.assign({ className: classes.reply, variant: "text", onClick: () => reply(comment) }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.commentObject.reply", defaultMessage: "ui.commentObject.reply" }) })));
    }
    /**
     * Handle reply: open Editor
     * @param comment
     */
    function reply(comment) {
        if (!scUserContext.user) {
            scContext.settings.handleAnonymousAction();
        }
        else {
            setReplyComment(comment);
            onOpenReply && onOpenReply(comment);
        }
    }
    /**
     * Perform reply
     * Comment of second level
     */
    const performReply = (comment) => {
        return api_services_1.http
            .request({
            url: api_services_1.Endpoints.NewComment.url({}),
            method: api_services_1.Endpoints.NewComment.method,
            data: Object.assign(Object.assign({ [`${feedObject ? feedObject.type : feedObjectType}`]: feedObject ? feedObject.id : feedObjectId, parent: replyComment.parent ? replyComment.parent : replyComment.id }, (replyComment.parent ? { in_reply_to: replyComment.id } : {})), { text: comment })
        })
            .then((res) => {
            if (res.status >= 300) {
                return Promise.reject(res);
            }
            return Promise.resolve(res.data);
        });
    };
    /**
     * Handle comment of 2° level
     */
    function handleReply(comment) {
        if (react_core_1.UserUtils.isBlocked(scUserContext.user)) {
            enqueueSnackbar((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.common.userBlocked", defaultMessage: "ui.common.userBlocked" }), {
                variant: 'warning',
                autoHideDuration: 3000
            });
        }
        else {
            setIsReplying(true);
            performReply(comment)
                .then((data) => {
                // if add a comment -> the comment must be untruncated
                const _data = data;
                _data.summary_truncated = false;
                updateObject(Object.assign(Object.assign({}, obj), { comment_count: obj.comment_count + 1, latest_comments: [...obj.latest_comments, _data] }));
                setReplyComment(null);
                setIsReplying(false);
            })
                .catch((error) => {
                utils_1.Logger.error(Errors_1.SCOPE_SC_UI, error);
                enqueueSnackbar((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.common.error.action", defaultMessage: "ui.common.error.action" }), {
                    variant: 'error',
                    autoHideDuration: 3000
                });
                setIsReplying(false);
            });
        }
    }
    /**
     * Handle comment delete
     */
    function handleDelete(comment) {
        updateObject(comment);
        onDelete && onDelete(comment);
    }
    /**
     * Handle comment delete
     */
    function handleHide(comment) {
        updateObject(Object.assign({}, obj, { collapsed: !obj.collapsed }));
        onCollapsed && onCollapsed(comment);
    }
    /**
     * Handle comment restore
     */
    function handleRestore(comment) {
        updateObject(Object.assign({}, obj, { deleted: false }));
        onRestore && onRestore(comment);
    }
    /**
     * Handle edit comment
     */
    function handleEdit(comment) {
        setEditComment(comment);
    }
    function handleCancel() {
        setEditComment(null);
    }
    /**
     * Perform save/update comment
     */
    const performSave = (comment) => {
        return api_services_1.http
            .request({
            url: api_services_1.Endpoints.UpdateComment.url({ id: editComment.id }),
            method: api_services_1.Endpoints.UpdateComment.method,
            data: { text: comment }
        })
            .then((res) => {
            if (res.status >= 300) {
                return Promise.reject(res);
            }
            return Promise.resolve(res.data);
        });
    };
    /**
     * Handle save comment
     */
    function handleSave(comment) {
        if (react_core_1.UserUtils.isBlocked(scUserContext.user)) {
            enqueueSnackbar((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.common.userBlocked", defaultMessage: "ui.common.userBlocked" }), {
                variant: 'warning',
                autoHideDuration: 3000
            });
        }
        else {
            setIsSavingComment(true);
            performSave(comment)
                .then((data) => {
                const newObj = Object.assign({}, obj, {
                    text: data.text,
                    html: data.html,
                    summary: data.summary,
                    added_at: data.added_at
                });
                updateObject(newObj);
                setEditComment(null);
                setIsSavingComment(false);
            })
                .catch((error) => {
                utils_1.Logger.error(Errors_1.SCOPE_SC_UI, error);
                enqueueSnackbar((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.common.error.action", defaultMessage: "ui.common.error.action" }), {
                    variant: 'error',
                    autoHideDuration: 3000
                });
            });
        }
    }
    /**
     * Render comment & latest activities
     * @param comment
     */
    function renderComment(comment) {
        if (comment.deleted &&
            (!scUserContext.user || (scUserContext.user && !react_core_1.UserUtils.isStaff(scUserContext.user) && scUserContext.user.id !== comment.author.id))) {
            // render the comment if user is logged and is staff (admin, moderator)
            // or the comment author is the logged user
            return null;
        }
        const summaryHtmlTruncated = 'summary_truncated' in comment ? comment.summary_truncated : false;
        const commentHtml = 'summary_html' in comment && truncateContent && summaryHtmlTruncated ? comment.summary_html : comment.html;
        const summaryHtml = (0, contribution_1.getCommentContributionHtml)(commentHtml, scRoutingContext.url);
        return ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [collapsed ? ((0, jsx_runtime_1.jsx)(BaseItem_1.default, { elevation: 0, className: classes.comment, disableTypography: true, primary: (0, jsx_runtime_1.jsxs)(Widget_1.default, Object.assign({ className: (0, classnames_1.default)(classes.content, classes.collapsed), elevation: elevation }, rest, { children: [(0, jsx_runtime_1.jsx)(material_1.CardContent, Object.assign({ className: (0, classnames_1.default)({ [classes.deleted]: obj && obj.deleted }) }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.commentObject.collapsed", defaultMessage: "ui.commentObject.collapsed" }) })), (0, jsx_runtime_1.jsx)(material_1.Box, Object.assign({ className: classes.commentActionsMenu }, { children: (0, jsx_runtime_1.jsx)(material_1.IconButton, Object.assign({ onClick: () => setCollapsed(!collapsed) }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "visibility" }) })) }))] })) })) : editComment && editComment.id === comment.id ? ((0, jsx_runtime_1.jsx)(material_1.Box, Object.assign({ className: classes.comment }, { children: (0, jsx_runtime_1.jsx)(CommentObjectReply_1.default, Object.assign({ text: comment.html, autoFocus: true, id: `edit-${comment.id}`, onSave: handleSave, onCancel: handleCancel, editable: !isReplying || !isSavingComment }, CommentObjectReplyProps)) }))) : ((0, jsx_runtime_1.jsx)(BaseItem_1.default, { elevation: 0, className: classes.comment, image: (0, jsx_runtime_1.jsx)(react_core_1.Link, Object.assign({}, (!comment.author.deleted && { to: scRoutingContext.url(react_core_1.SCRoutes.USER_PROFILE_ROUTE_NAME, comment.author) }), { onClick: comment.author.deleted ? () => setOpenAlert(true) : null }, { children: (0, jsx_runtime_1.jsx)(UserAvatar_1.default, Object.assign({ hide: !obj.author.community_badge }, { children: (0, jsx_runtime_1.jsx)(material_1.Avatar, { alt: obj.author.username, variant: "circular", src: comment.author.avatar, className: classes.avatar }) })) })), disableTypography: true, primary: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(Widget_1.default, Object.assign({ className: classes.content, elevation: elevation }, rest, { children: [(0, jsx_runtime_1.jsxs)(material_1.CardContent, Object.assign({ className: (0, classnames_1.default)({ [classes.deleted]: obj && obj.deleted }) }, { children: [(0, jsx_runtime_1.jsx)(react_core_1.Link, Object.assign({ className: classes.author }, (!comment.author.deleted && { to: scRoutingContext.url(react_core_1.SCRoutes.USER_PROFILE_ROUTE_NAME, comment.author) }), { onClick: comment.author.deleted ? () => setOpenAlert(true) : null }, { children: (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ component: "span" }, { children: comment.author.username })) })), comment.collapsed && ((0, jsx_runtime_1.jsx)(material_1.Chip, { className: classes.flagChip, color: "error", size: "small", label: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.commentObject.flag", defaultMessage: "ui.commentObject.flag" }) })), (0, jsx_runtime_1.jsx)(material_1.Typography, { className: classes.textContent, variant: "body2", gutterBottom: true, dangerouslySetInnerHTML: { __html: summaryHtml } }), summaryHtmlTruncated && truncateContent && ((0, jsx_runtime_1.jsx)(react_core_1.Link, Object.assign({ to: scRoutingContext.url(react_core_1.SCRoutes.COMMENT_ROUTE_NAME, (0, contribution_1.getRouteData)(comment)), className: classes.showMoreContent }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.commentObject.showMore", defaultMessage: "ui.commentObject.showMore" }) })))] })), scUserContext.user && ((0, jsx_runtime_1.jsx)(material_1.Box, Object.assign({ className: classes.commentActionsMenu }, { children: (0, jsx_runtime_1.jsx)(ContributionActionsMenu_1.default, { commentObject: comment, onRestoreContribution: handleRestore, onHideContribution: handleHide, onDeleteContribution: handleDelete, onEditContribution: handleEdit }) })))] })), (0, jsx_runtime_1.jsxs)(material_1.Box, Object.assign({ component: "span", className: classes.contentSubSection }, { children: [renderTimeAgo(comment), (0, jsx_runtime_1.jsx)(Bullet_1.default, {}), (0, jsx_runtime_1.jsx)(VoteButton_1.default, { size: "small", className: classes.vote, contributionId: comment.id, contributionType: types_1.SCContributionType.COMMENT, contribution: comment, onVote: handleVoteSuccess }), (0, jsx_runtime_1.jsx)(Bullet_1.default, {}), renderActionReply(comment), (0, jsx_runtime_1.jsx)(VoteAudienceButton_1.default, { size: "small", className: classes.voteAudience, contributionId: comment.id, contributionType: types_1.SCContributionType.COMMENT, contribution: comment })] }))] }) })), comment.comment_count > 0 && (0, jsx_runtime_1.jsx)(material_1.Box, Object.assign({ className: classes.nestedComments }, { children: renderLatestComment(comment) })), scUserContext.user && replyComment && (replyComment.id === comment.id || replyComment.parent === comment.id) && !comment.parent && ((0, jsx_runtime_1.jsx)(material_1.Box, Object.assign({ className: classes.nestedComments }, { children: (0, jsx_runtime_1.jsx)(CommentObjectReply_1.default, Object.assign({ text: `@${replyComment.author.username}, `, autoFocus: true, id: `reply-${replyComment.id}`, onReply: handleReply, editable: !isReplying }, CommentObjectReplyProps), `reply-${replyComment.id}`) })))] }, comment.id));
    }
    /**
     * Render Latest Comment
     * @param comment
     */
    function renderLatestComment(comment) {
        return ((0, jsx_runtime_1.jsx)(CommentsObject_1.default, Object.assign({ feedObject: commentsObject.feedObject, feedObjectType: commentsObject.feedObject ? commentsObject.feedObject.type : feedObjectType, hideAdvertising: true, comments: [].concat(commentsObject.comments).reverse(), endComments: comment.latest_comments, previous: comment.comment_count > comment.latest_comments.length ? commentsObject.next : null, isLoadingPrevious: commentsObject.isLoadingNext, handlePrevious: commentsObject.getNextPage, CommentComponentProps: Object.assign(Object.assign({ onOpenReply: reply, CommentObjectSkeletonProps, elevation: elevation, linkableCommentDateTime: linkableCommentDateTime }, rest), { cacheStrategy,
                truncateContent }), CommentsObjectSkeletonProps: { count: 1, CommentObjectSkeletonProps: CommentObjectSkeletonProps }, inPlaceLoadMoreContents: true }, CommentsObjectComponentProps, { cacheStrategy: cacheStrategy })));
    }
    /**
     * Render comments
     */
    let comment;
    if (obj) {
        comment = renderComment(obj);
    }
    else {
        comment = (0, jsx_runtime_1.jsx)(Skeleton_1.default, Object.assign({}, CommentObjectSkeletonProps));
    }
    /**
     * Render object
     */
    return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(Root, Object.assign({ id: id, className: (0, classnames_1.default)(classes.root, className) }, { children: comment })), openAlert && (0, jsx_runtime_1.jsx)(UserDeletedSnackBar_1.default, { open: openAlert, handleClose: () => setOpenAlert(false) })] }));
}
exports.default = CommentObject;
