"use strict";

exports.__esModule = true;
exports.default = CommentObject;

var _react = _interopRequireWildcard(require("react"));

var _styles = require("@mui/material/styles");

var _Card = _interopRequireDefault(require("@mui/material/Card"));

var _reactIntl = require("react-intl");

var _material = require("@mui/material");

var _Bullet = _interopRequireDefault(require("../../shared/Bullet"));

var _classnames = _interopRequireDefault(require("classnames"));

var _Votes = _interopRequireDefault(require("./Votes"));

var _Errors = require("../../constants/Errors");

var _Skeleton = _interopRequireDefault(require("./Skeleton"));

var _core = require("@selfcommunity/core");

var _lab = require("@mui/lab");

var _ThumbUpTwoTone = _interopRequireDefault(require("@mui/icons-material/ThumbUpTwoTone"));

var _ThumbUpOutlined = _interopRequireDefault(require("@mui/icons-material/ThumbUpOutlined"));

var _comments = require("../../types/comments");

var _ReplyComment = _interopRequireDefault(require("./ReplyComment"));

var _CommentActionsMenu = _interopRequireDefault(require("./CommentActionsMenu"));

var _DateTimeAgo = _interopRequireDefault(require("../../shared/DateTimeAgo"));

var _contribute = require("../../utils/contribute");

const _excluded = ["className", "commentObjectId", "commentObject", "feedObjectId", "feedObject", "feedObjectType", "commentsPageCount", "commentsOrderBy", "commentReply", "onOpenReply", "onVote", "onFetchLatestComment", "CommentObjectSkeletonProps", "ReplyCommentObjectProps"];

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }

function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }

const messages = (0, _reactIntl.defineMessages)({
  reply: {
    id: 'ui.commentObject.reply',
    defaultMessage: 'ui.commentObject.reply'
  },
  voteUp: {
    id: 'ui.commentObject.voteUp',
    defaultMessage: 'ui.commentObject.voteUp'
  },
  voteDown: {
    id: 'ui.commentObject.voteDown',
    defaultMessage: 'ui.commentObject.voteDown'
  }
});
const PREFIX = 'SCCommentObject';
const classes = {
  root: `${PREFIX}-root`,
  comment: `${PREFIX}-comment`,
  avatarWrap: `${PREFIX}-avatar-wrap`,
  avatar: `${PREFIX}-avatar`,
  author: `${PREFIX}-author`,
  content: `${PREFIX}-content`,
  textContent: `${PREFIX}-text-content`,
  commentChild: `${PREFIX}-comment-child`,
  btnVotes: `${PREFIX}-btn-votes`,
  votes: `${PREFIX}-votes`,
  btnViewPreviousComments: `${PREFIX}-btn-view-previous-comments`,
  commentActionsMenu: `${PREFIX}-comment-actions-menu`,
  deleted: `${PREFIX}-deleted`,
  activityAt: `${PREFIX}-activity-at`,
  reply: `${PREFIX}-reply`
};
const Root = (0, _styles.styled)(_material.Box, {
  name: PREFIX,
  slot: 'Root',
  overridesResolver: (props, styles) => styles.root
})(({
  theme
}) => ({
  overflow: 'auto',
  '& .MuiSvgIcon-root': {
    width: '0.7em',
    marginBottom: '0.5px'
  },
  [`& .${classes.comment}`]: {
    paddingBottom: 0
  },
  [`& .${classes.avatarWrap}`]: {
    minWidth: 46
  },
  [`& .${classes.avatar}`]: {
    width: 35,
    height: 35
  },
  [`& .${classes.author}`]: {
    textDecoration: 'none',
    '& span': {
      fontWeight: '600'
    }
  },
  [`& .${classes.content}`]: {
    '& .MuiCardContent-root': {
      padding: '7px 13px 7px 13px'
    }
  },
  [`& .${classes.textContent}`]: {
    '& p': {
      marginBlockStart: '0.3em',
      marginBlockEnd: '0.3em'
    }
  },
  [`& .${classes.commentChild}`]: {
    paddingLeft: '70px'
  },
  [`& .${classes.btnViewPreviousComments}`]: {
    paddingLeft: '70px',
    textTransform: 'capitalize'
  },
  [`& .${classes.commentActionsMenu}`]: {
    position: 'absolute',
    top: 10,
    right: 11
  },
  [`& .${classes.deleted}`]: {
    opacity: 0.3
  },
  [`& .${classes.activityAt}`]: {
    display: 'flex',
    textDecoration: 'none',
    color: theme.palette.grey[700]
  },
  [`& .${classes.reply}`]: {
    textTransform: 'capitalize',
    color: theme.palette.text.primary
  }
}));

/**
 *> API documentation for the Community-UI Comment Object component. Learn about the available props and the CSS API.

 #### Import

 ```jsx
 import {CommentObject} from '@selfcommunity/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.|
 |avatarWrap|.SCCommentObject-avatar-wrap|Styles applied to avatar wrap.|
 |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.|
 |commentChild|.SCCommentObject-comment-child|Styles applied to the comment child element.|
 |btnVotes|.SCCommentObject-btn-votes|Styles applied to the vote button element.|
 |votes|.SCCommentObject-votes|Styles applied to the votes section.|
 |btnViewPreviousComments|.SCCommentObject-btn-view-previous-comments|Styles applied to previous comment button element|
 |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.|

 * @param props
 */
function CommentObject(props) {
  // PROPS
  const {
    className,
    commentObjectId,
    commentObject,
    feedObjectId,
    feedObject,
    feedObjectType = _core.SCFeedObjectTypologyType.POST,
    commentsPageCount = 5,
    commentsOrderBy = _comments.CommentsOrderBy.ADDED_AT_DESC,
    commentReply,
    onOpenReply,
    onVote,
    onFetchLatestComment,
    CommentObjectSkeletonProps = {
      elevation: 0,
      variant: 'outlined'
    },
    ReplyCommentObjectProps = {
      elevation: 0,
      variant: 'outlined'
    }
  } = props,
        rest = _objectWithoutPropertiesLoose(props, _excluded); // CONTEXT


  const scContext = (0, _core.useSCContext)();
  const scUserContext = (0, _react.useContext)(_core.SCUserContext);
  const scRoutingContext = (0, _core.useSCRouting)();
  const intl = (0, _reactIntl.useIntl)(); // STATE

  const {
    obj,
    setObj
  } = (0, _core.useSCFetchCommentObject)({
    id: commentObjectId,
    commentObject
  });
  const [loadingVote, setLoadingVote] = (0, _react.useState)(false);
  const [loadingLatestComments, setLoadingLatestComments] = (0, _react.useState)(false);
  const [next, setNext] = (0, _react.useState)(null);
  const [replyComment, setReplyComment] = (0, _react.useState)(commentReply);
  const [isReplying, setIsReplying] = (0, _react.useState)(false);
  const [editComment, setEditComment] = (0, _react.useState)(null);
  const [isSavingComment, setIsSavingComment] = (0, _react.useState)(false);
  /**
   * Render added_at of the comment
   * @param comment
   */

  function renderTimeAgo(comment) {
    return /*#__PURE__*/_react.default.createElement(_core.Link, {
      to: scRoutingContext.url(_core.SCRoutes.COMMENT_ROUTE_NAME, (0, _contribute.getRouteData)(comment)),
      className: classes.activityAt
    }, /*#__PURE__*/_react.default.createElement(_DateTimeAgo.default, {
      date: comment.added_at
    }));
  }
  /**
   * Render vote action
   * @param comment
   */


  function renderActionVote(comment) {
    return /*#__PURE__*/_react.default.createElement(_lab.LoadingButton, {
      variant: 'text',
      sx: {
        minWidth: 30
      },
      onClick: () => !scUserContext.user ? scContext.settings.handleAnonymousAction() : vote(comment),
      disabled: loadingVote,
      color: "inherit"
    }, comment.voted ? /*#__PURE__*/_react.default.createElement(_material.Tooltip, {
      title: /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, {
        id: 'ui.commentObject.voteDown',
        defaultMessage: 'ui.commentObject.voteDown'
      })
    }, /*#__PURE__*/_react.default.createElement(_ThumbUpTwoTone.default, {
      fontSize: 'small',
      color: "primary"
    })) : /*#__PURE__*/_react.default.createElement(_material.Tooltip, {
      title: /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, {
        id: 'ui.commentObject.voteUp',
        defaultMessage: 'ui.commentObject.voteUp'
      })
    }, /*#__PURE__*/_react.default.createElement(_ThumbUpOutlined.default, {
      fontSize: 'small',
      color: "inherit"
    })));
  }
  /**
   * Render Reply action
   * @param comment
   */


  function renderActionReply(comment) {
    return /*#__PURE__*/_react.default.createElement(_material.Button, {
      className: classes.reply,
      variant: "text",
      onClick: () => !scUserContext.user ? scContext.settings.handleAnonymousAction() : reply(comment),
      color: "inherit"
    }, intl.formatMessage(messages.reply));
  }
  /**
   * Render Votes counter
   */


  function renderVotes(comment) {
    return /*#__PURE__*/_react.default.createElement(_Votes.default, {
      commentObject: comment,
      sx: {
        display: {
          xs: 'none',
          sm: 'block'
        }
      }
    });
  }
  /**
   * Handle reply: open Editor
   * @param comment
   */


  function reply(comment) {
    setReplyComment(comment);
    onOpenReply && onOpenReply(comment);
  }
  /**
   * Handle fetch latest comments
   * @param comment
   */


  function loadLatestComment() {
    setLoadingLatestComments(true);
    fetchLatestComment().then(data => {
      const newObj = obj;
      obj.latest_comments = obj.latest_comments.length <= 1 ? [...data.results.reverse()] : [...data.results.reverse(), ...obj.latest_comments];
      setObj(newObj);
      setNext(data.next);
      setLoadingLatestComments(false);
      onFetchLatestComment && onFetchLatestComment();
    }).catch(error => {
      _core.Logger.error(_Errors.SCOPE_SC_UI, error);
    });
  }
  /**
   * fetchVotes
   */


  const fetchLatestComment = (0, _react.useMemo)(() => () => {
    return _core.http.request({
      url: next ? next : `${_core.Endpoints.Comments.url()}?${feedObjectType}=${feedObjectId ? feedObjectId : feedObject.id}&parent=${obj.id}&limit=${commentsPageCount}&ordering=${commentsOrderBy}`,
      method: _core.Endpoints.Comments.method
    }).then(res => {
      if (res.status >= 300) {
        return Promise.reject(res);
      }

      return Promise.resolve(res.data);
    });
  }, [obj, next, commentsOrderBy, commentsPageCount]);
  /**
   * Perform vote comment
   */

  const performVoteComment = (0, _react.useMemo)(() => comment => {
    return _core.http.request({
      url: _core.Endpoints.Vote.url({
        type: _core.SCCommentTypologyType,
        id: comment.id
      }),
      method: _core.Endpoints.Vote.method
    }).then(res => {
      if (res.status >= 300) {
        return Promise.reject(res);
      }

      return Promise.resolve(res.data);
    });
  }, [obj]);
  /**
   * Handle vote comment
   * @param comment
   */

  function vote(comment) {
    setLoadingVote(true);
    performVoteComment(comment).then(data => {
      const newObj = obj;

      if (comment.parent) {
        // 2° comment level
        const newLatestComments = obj.latest_comments.map(lc => {
          if (lc.id === comment.id) {
            lc.voted = !lc.voted;
            lc.vote_count = lc.vote_count - (lc.voted ? -1 : 1);
          }

          return lc;
        });
        obj.latest_comments = newLatestComments;
      } else {
        // 1° comment level
        obj.voted = !obj.voted;
        obj.vote_count = obj.vote_count - (obj.voted ? -1 : 1);
      }

      setObj(newObj);
      setLoadingVote(false);
      onVote && onVote(comment);
    }).catch(error => {
      _core.Logger.error(_Errors.SCOPE_SC_UI, error);
    });
  }
  /**
   * Perform reply
   * Comment of second level
   */


  const performReply = comment => {
    return _core.http.request({
      url: _core.Endpoints.NewComment.url({}),
      method: _core.Endpoints.NewComment.method,
      data: Object.assign({
        [`${feedObjectType}`]: feedObjectId ? feedObjectId : feedObject.id,
        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) {
    setIsReplying(true);
    performReply(comment).then(data => {
      setObj(Object.assign({}, obj, {
        latest_comments: [...obj.latest_comments, ...[data]]
      }));
      setReplyComment(null);
      setIsReplying(false);
    }).catch(error => {
      _core.Logger.error(_Errors.SCOPE_SC_UI, error);
    });
  }
  /**
   * Handle comment delete
   */


  function handleDelete(comment) {
    if (comment.parent) {
      const _latestComment = obj.latest_comments.map(c => {
        if (c.id === comment.id) {
          c.deleted = true;
        }

        return c;
      });

      setObj(Object.assign({}, obj, {
        latest_comments: _latestComment
      }));
    } else {
      setObj(Object.assign({}, obj, {
        deleted: true
      }));
    }
  }
  /**
   * Handle comment restore
   */


  function handleRestore(comment) {
    if (comment.parent) {
      const _latestComment = obj.latest_comments.map(c => {
        if (c.id === comment.id) {
          c.deleted = false;
        }

        return c;
      });

      setObj(Object.assign({}, obj, {
        latest_comments: _latestComment
      }));
    } else {
      setObj(Object.assign({}, obj, {
        deleted: false
      }));
    }
  }
  /**
   * Handle edit comment
   */


  function handleEdit(comment) {
    setEditComment(comment);
  }

  function handleCancel() {
    setEditComment(null);
  }
  /**
   * Perform save/update comment
   */


  const performSave = comment => {
    return _core.http.request({
      url: _core.Endpoints.UpdateComment.url({
        id: editComment.id
      }),
      method: _core.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) {
    setIsSavingComment(true);
    performSave(comment).then(data => {
      if (data.parent) {
        const _latestComment = obj.latest_comments.map(c => {
          if (c.id === data.id) {
            return data;
          }

          return c;
        });

        setObj(Object.assign({}, obj, {
          latest_comments: _latestComment
        }));
      } else {
        setObj(Object.assign({}, obj, {
          text: data.text,
          html: data.html,
          summary: data.summary,
          added_at: data.added_at
        }));
      }

      setEditComment(null);
      setIsSavingComment(false);
    }).catch(error => {
      _core.Logger.error(_Errors.SCOPE_SC_UI, error);
    });
  }
  /**
   * Render comment & latest activities
   * @param comment
   */


  function renderComment(comment) {
    if (comment.deleted && scUserContext.user && !scUserContext.user.role || scUserContext.user && scUserContext.user.role && !scUserContext.user.role.includes('admin')) {
      // if the logged user isn't an administrator can't view the comment
      return null;
    }

    return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, {
      key: comment.id
    }, editComment && editComment.id === comment.id ? /*#__PURE__*/_react.default.createElement(_ReplyComment.default, {
      text: comment.html,
      autoFocus: true,
      id: `reply-${comment.id}`,
      commentObject: comment,
      onSave: handleSave,
      onCancel: handleCancel,
      readOnly: isReplying,
      inline: !comment.parent,
      ReplyBoxProps: ReplyCommentObjectProps
    }) : /*#__PURE__*/_react.default.createElement(_material.ListItem, {
      button: false,
      alignItems: "flex-start",
      classes: {
        root: (0, _classnames.default)(classes.comment, {
          [classes.commentChild]: Boolean(comment.parent)
        })
      }
    }, /*#__PURE__*/_react.default.createElement(_material.ListItemAvatar, {
      classes: {
        root: classes.avatarWrap
      }
    }, /*#__PURE__*/_react.default.createElement(_core.Link, {
      to: scRoutingContext.url('profile', {
        id: comment.author.id
      })
    }, /*#__PURE__*/_react.default.createElement(_material.Avatar, {
      alt: obj.author.username,
      variant: "circular",
      src: comment.author.avatar,
      classes: {
        root: classes.avatar
      }
    }))), /*#__PURE__*/_react.default.createElement(_material.ListItemText, {
      disableTypography: true,
      secondary: /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_Card.default, _extends({
        classes: {
          root: classes.content
        }
      }, rest), /*#__PURE__*/_react.default.createElement(_material.CardContent, {
        classes: {
          root: (0, _classnames.default)({
            [classes.deleted]: obj.deleted
          })
        }
      }, /*#__PURE__*/_react.default.createElement(_core.Link, {
        className: classes.author,
        to: scRoutingContext.url('profile', {
          id: comment.author.id
        })
      }, /*#__PURE__*/_react.default.createElement(_material.Typography, {
        component: "span",
        sx: {
          display: 'inline'
        },
        gutterBottom: true,
        color: "inherit"
      }, comment.author.username)), /*#__PURE__*/_react.default.createElement(_material.Typography, {
        className: classes.textContent,
        variant: "body2",
        gutterBottom: true,
        dangerouslySetInnerHTML: {
          __html: comment.html
        }
      })), scUserContext.user && /*#__PURE__*/_react.default.createElement(_material.Box, {
        className: classes.commentActionsMenu
      }, /*#__PURE__*/_react.default.createElement(_CommentActionsMenu.default, {
        commentObject: comment,
        feedObject: feedObject,
        feedObjectId: feedObjectId,
        feedObjectType: feedObjectType,
        onRestore: handleRestore,
        onDelete: handleDelete,
        onEdit: handleEdit
      }))), /*#__PURE__*/_react.default.createElement(_material.Box, {
        component: "span",
        sx: {
          display: 'flex',
          justifyContent: 'flex-start',
          p: '2px'
        }
      }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
        component: "span",
        item: true,
        sm: "auto",
        container: true,
        direction: "row",
        alignItems: "center"
      }, renderTimeAgo(comment), /*#__PURE__*/_react.default.createElement(_Bullet.default, {
        sx: {
          paddingLeft: '10px',
          paddingTop: '1px'
        }
      }), renderActionVote(comment), /*#__PURE__*/_react.default.createElement(_Bullet.default, {
        sx: {
          paddingTop: '1px'
        }
      }), renderActionReply(comment), renderVotes(comment))))
    })), renderLatestComment(comment), scUserContext.user && replyComment && (replyComment.id === comment.id || replyComment.parent === comment.id) && !comment.parent && /*#__PURE__*/_react.default.createElement(_ReplyComment.default, _extends({
      text: replyComment.parent ? `@${replyComment.author.username}, ` : '',
      autoFocus: true,
      id: `reply-${replyComment.id}`,
      commentObject: replyComment,
      onReply: handleReply,
      readOnly: isReplying
    }, rest)));
  }
  /**
   * Render Latest Comment
   * @param comment
   */


  function renderLatestComment(comment) {
    var _comment$latest_comme, _comment$latest_comme2, _comment$latest_comme3;

    return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, comment.comment_count - ((_comment$latest_comme = comment.latest_comments) == null ? void 0 : _comment$latest_comme.length) >= 1 && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, loadingLatestComments ? /*#__PURE__*/_react.default.createElement(_material.Box, {
      sx: {
        paddingLeft: '55px',
        paddingRight: 0
      }
    }, /*#__PURE__*/_react.default.createElement(_Skeleton.default, rest)) : /*#__PURE__*/_react.default.createElement(_material.Button, {
      color: "inherit",
      variant: "text",
      onClick: loadLatestComment,
      disabled: loadingLatestComments || !feedObjectId && !feedObject,
      classes: {
        text: (0, _classnames.default)(classes.btnViewPreviousComments, classes.commentChild)
      }
    }, /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, {
      id: 'ui.commentObject.viewLatestComment',
      defaultMessage: 'ui.commentObject.viewLatestComment',
      values: {
        total: comment.comment_count - ((_comment$latest_comme2 = comment.latest_comments) == null ? void 0 : _comment$latest_comme2.length)
      }
    }))), (_comment$latest_comme3 = comment.latest_comments) == null ? void 0 : _comment$latest_comme3.map(lc => /*#__PURE__*/_react.default.createElement(_react.default.Fragment, {
      key: lc.id
    }, renderComment(lc))));
  }
  /**
   * Render comments
   */


  let comment;

  if (obj) {
    comment = renderComment(obj);
  } else {
    comment = /*#__PURE__*/_react.default.createElement(_Skeleton.default, CommentObjectSkeletonProps);
  }
  /**
   * Render object
   */


  return /*#__PURE__*/_react.default.createElement(Root, {
    className: className
  }, comment);
}