"use strict";

exports.__esModule = true;
exports.default = Thread;

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

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

var _Widget = _interopRequireDefault(require("../Widget"));

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

var _Message = _interopRequireDefault(require("../Message"));

var _lodash = _interopRequireDefault(require("lodash"));

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

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

var _ConfirmDialog = _interopRequireDefault(require("../../shared/ConfirmDialog/ConfirmDialog"));

var _MessageEditor = _interopRequireDefault(require("../MessageEditor"));

var _Autocomplete = _interopRequireDefault(require("@mui/material/Autocomplete"));

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

var _notistack = require("notistack");

var _pubsubJs = _interopRequireDefault(require("pubsub-js"));

var _useThemeProps = _interopRequireDefault(require("@mui/material/styles/useThemeProps"));

var _Icon = _interopRequireDefault(require("@mui/material/Icon"));

const _excluded = ["id", "receiverId", "autoHide", "className", "openNewMessage", "onNewMessageSent", "onMessageSent", "shouldUpdate"];

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 smessages = (0, _reactIntl.defineMessages)({
  placeholder: {
    id: 'ui.thread.newMessage.autocomplete.placeholder',
    defaultMessage: 'ui.thread.newMessage.autocomplete.placeholder'
  }
});
const PREFIX = 'SCThread';
const classes = {
  root: `${PREFIX}-root`,
  threadBox: `${PREFIX}-thread-box`,
  emptyBox: `${PREFIX}-empty-box`,
  newMessageBox: `${PREFIX}-new-message-box`,
  newMessageEditor: `${PREFIX}-new-message-editor`,
  newMessageEmptyBox: `${PREFIX}-new-message-empty-box`,
  newMessageHeader: `${PREFIX}-new-message-header`,
  sender: `${PREFIX}-sender`,
  receiver: `${PREFIX}-receiver`,
  center: `${PREFIX}-center`,
  autocomplete: `${PREFIX}-autocomplete`
};
const Root = (0, _styles.styled)(_Widget.default, {
  name: PREFIX,
  slot: 'Root',
  overridesResolver: (props, styles) => styles.root
})(({
  theme
}) => ({
  width: '600px',
  height: '100%',
  [`& .${classes.threadBox}`]: {
    display: 'inline-block',
    maxHeight: '600px',
    width: 'inherit',
    overflow: 'auto'
  },
  [`& .${classes.emptyBox}`]: {
    display: 'flex',
    height: '100%',
    background: theme.palette.grey['A200'],
    justifyContent: 'center',
    alignItems: 'center',
    '& .MuiTypography-root': {
      fontSize: '1.5rem'
    }
  },
  [`& .${classes.newMessageBox}`]: {
    display: 'flex',
    flexFlow: 'column',
    height: '100%'
  },
  [`& .${classes.newMessageEditor}`]: {
    flexGrow: 0,
    flexShrink: 1,
    flexBasis: '40px'
  },
  [`& .${classes.newMessageEmptyBox}`]: {
    flexGrow: 1,
    flexShrink: 1,
    flexBasis: 'auto'
  },
  [`& .${classes.sender}`]: {
    display: 'flex',
    justifyContent: 'flex-end',
    '& .SCMessage-message-box': {
      backgroundColor: theme.palette.grey[400]
    }
  },
  [`& .${classes.receiver}`]: {
    display: 'flex',
    justifyContent: 'flex-start',
    '& .SCMessage-message-box': {
      backgroundColor: theme.palette.grey['A200']
    },
    '& .SCMessage-message-time': {
      display: 'flex',
      justifyContent: 'flex-start'
    }
  },
  [`& .${classes.center}`]: {
    display: 'flex',
    justifyContent: 'center'
  },
  [`& .${classes.newMessageHeader}`]: {
    marginLeft: theme.spacing(1),
    marginTop: theme.spacing(1)
  },
  [`& .${classes.autocomplete}`]: {
    marginRight: theme.spacing(1)
  }
}));

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

 #### Import

 ```jsx
 import {Thread} from '@selfcommunity/ui';
 ```

 #### Component Name

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


 #### CSS

 |Rule Name|Global class|Description|
 |---|---|---|
 |root|.SCThread-root|Styles applied to the root element.|
 |emptyBox|.SCThread-empty-box|Styles applied to the empty box element.|
 |sender|.SCThread-sender|Styles applied to the sender element.|
 |receiver|.SCThread-receiver|Styles applied to the receiver element.|
 |center|.SCThread-center|Styles applied to the center section.|
 |threadBox|.SCThread-thread-box|Styles applied to the thread box element.|
 |emptyBox|.SCThread-empty-box|Styles applied to the empty box element.|
 |newMessageBox|.SCThread-new-message-box|Styles applied to the new message box element.|
 |newMessageEditor|.SCThread-new-message-editor|Styles applied to the new message editor.|
 |newMessageEmptyBox|.SCThread-new-message-empty-box|Styles applied to the new message empty box element.|
 |newMessageHeader|.SCThread-new-message-header|Styles applied to the new message header section.|
 |autocomplete|.SCThread-autocomplete|Styles applied to new message user insertion autocomplete.|

 * @param inProps
 */
function Thread(inProps) {
  // PROPS
  const props = (0, _useThemeProps.default)({
    props: inProps,
    name: PREFIX
  });

  const {
    id,
    receiverId,
    autoHide,
    className,
    openNewMessage,
    onNewMessageSent,
    onMessageSent,
    shouldUpdate
  } = props,
        rest = _objectWithoutPropertiesLoose(props, _excluded); // CONTEXT


  const scUserContext = (0, _react.useContext)(_core.SCUserContext);
  const {
    enqueueSnackbar,
    closeSnackbar
  } = (0, _notistack.useSnackbar)(); // STATE

  const [loading, setLoading] = (0, _react.useState)(true);
  const [messages, setMessages] = (0, _react.useState)([]);
  const loggedUser = scUserContext.user && scUserContext.user.id;
  const [isHovered, setIsHovered] = (0, _react.useState)({});
  const [openDeleteMessageDialog, setOpenDeleteMessageDialog] = (0, _react.useState)(false);
  const [deletingMsg, setDeletingMsg] = (0, _react.useState)(null);
  const [message, setMessage] = (0, _react.useState)('');
  const [messageFile, setMessageFile] = (0, _react.useState)(null);
  const [sending, setSending] = (0, _react.useState)(false);
  const [followers, setFollowers] = (0, _react.useState)([]);
  const [recipients, setRecipients] = (0, _react.useState)([]); // REFS

  const refreshSubscription = (0, _react.useRef)(null); // INTL

  const intl = (0, _reactIntl.useIntl)(); // UTILS

  const format = item => intl.formatDate(item.created_at, {
    weekday: 'long',
    day: 'numeric',
    month: 'long'
  }); // HANDLERS


  const formatMessages = messages => {
    return _lodash.default.groupBy(messages, format);
  };

  const formattedMessages = (0, _react.useMemo)(() => {
    return formatMessages(messages);
  }, [messages]);

  const handleMessage = m => {
    setMessage(m);
  };

  const handleMessageFile = f => {
    setMessageFile(f);
  };

  const handleMouseEnter = index => {
    setIsHovered(prevState => {
      return Object.assign({}, prevState, {
        [index]: true
      });
    });
  };

  const handleMouseLeave = index => {
    setIsHovered(prevState => {
      return Object.assign({}, prevState, {
        [index]: false
      });
    });
  };

  const handleClose = () => {
    setOpenDeleteMessageDialog(false);
  };

  function handleDeleteDialog(msg) {
    setOpenDeleteMessageDialog(true);
    setDeletingMsg(msg);
  }

  const selectRecipients = (event, recipient) => {
    setRecipients(recipient);
  };

  const ids = (0, _react.useMemo)(() => {
    if (recipients !== null) {
      return recipients.map(u => {
        return parseInt(u.id, 10);
      });
    }
  }, [recipients]);
  /**
   * Handles deletion of a single message
   * @param id
   */

  function handleDelete() {
    _core.http.request({
      url: _core.Endpoints.DeleteASingleMessage.url({
        id: deletingMsg.id
      }),
      method: _core.Endpoints.DeleteASingleMessage.method
    }).then(() => {
      const result = messages.filter(m => m.id !== deletingMsg.id);
      setMessages(result);
      handleClose();
    }).catch(error => {
      console.log(error);

      let _snackBar = enqueueSnackbar( /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, {
        id: "ui.common.error",
        defaultMessage: "ui.common.error"
      }), {
        variant: 'error',
        onClick: () => {
          closeSnackbar(_snackBar);
        }
      });
    });
  }

  function sendMessage() {
    if (_core.UserUtils.isBlocked(scUserContext.user)) {
      enqueueSnackbar( /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, {
        id: "ui.common.userBlocked",
        defaultMessage: "ui.common.userBlocked"
      }), {
        variant: 'warning',
        autoHideDuration: 3000
      });
    } else {
      _core.http.request({
        url: _core.Endpoints.SendMessage.url(),
        method: _core.Endpoints.SendMessage.method,
        data: {
          recipients: openNewMessage ? ids : [receiverId],
          message: message,
          file_uuid: messageFile != null ? messageFile : null
        }
      }).then(res => {
        setMessages(prev => [...prev, res.data]);
        setSending(false);
        onMessageSent(res.data);
        shouldUpdate(false);

        if (openNewMessage) {
          onNewMessageSent(res.data);
          shouldUpdate(true);
        }
      }).catch(error => {
        console.log(error);

        let _snackBar = enqueueSnackbar( /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, {
          id: "ui.common.error.messageError",
          defaultMessage: "ui.common.error.messageError"
        }), {
          variant: 'error',
          onClick: () => {
            closeSnackbar(_snackBar);
          }
        });
      });
    }
  }
  /**
   * Fetches user followers
   */


  function fetchFollowers() {
    _core.http.request({
      url: _core.Endpoints.UserFollowers.url({
        id: scUserContext['user'].id
      }),
      method: _core.Endpoints.UserFollowers.method
    }).then(res => {
      const data = res.data;
      setFollowers(data.results);
    }).catch(error => {
      console.log(error);
    });
  }
  /**
   * Fetches thread
   */


  function fetchThread() {
    _core.http.request({
      url: _core.Endpoints.GetAThread.url(),
      method: _core.Endpoints.GetAThread.method,
      params: {
        thread: id
      }
    }).then(res => {
      const data = res.data;
      setMessages(data.results);
      setLoading(false);
    }).catch(error => {
      console.log(error);
    });
  }
  /**
   * On mount, fetches thread
   * if openNewMessage is true, fetches user followers too.
   */


  (0, _react.useEffect)(() => {
    if (openNewMessage) {
      fetchFollowers();
    }

    fetchThread();
  }, [id, openNewMessage]);
  /**
   * When a ws notification arrives, update data
   */

  (0, _react.useEffect)(() => {
    refreshSubscription.current = _pubsubJs.default.subscribe(`${_core.SCNotificationTopicType.INTERACTION}.${_core.SCNotificationTypologyType.PRIVATE_MESSAGE}`, subscriber);
    return () => {
      _pubsubJs.default.unsubscribe(refreshSubscription.current);
    };
  }, [messages]);
  /**
   * Notification subscriber
   */

  const subscriber = (msg, data) => {
    const res = data.data;
    const newMessages = [...messages];
    const index = newMessages.findIndex(m => m.sender.id === res.notification_obj.message.sender.id);

    if (index !== -1) {
      setMessages(prev => [...prev, res.notification_obj.message]);
    }
  };
  /**
   * Renders thread component
   * @return {JSX.Element}
   */


  function renderThread() {
    return /*#__PURE__*/_react.default.createElement(_material.Box, {
      className: classes.threadBox
    }, openDeleteMessageDialog && /*#__PURE__*/_react.default.createElement(_ConfirmDialog.default, {
      open: openDeleteMessageDialog,
      title: /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, {
        id: "ui.thread.message.dialog.msg",
        defaultMessage: "ui.thread.message.dialog.msg"
      }),
      btnConfirm: /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, {
        id: "ui.thread.message.dialog.confirm",
        defaultMessage: "ui.thread.message.dialog.confirm"
      }),
      onConfirm: () => handleDelete(),
      onClose: handleClose
    }), Object.keys(formattedMessages).map((key, index) => /*#__PURE__*/_react.default.createElement("div", {
      key: index
    }, /*#__PURE__*/_react.default.createElement(_material.ListSubheader, {
      className: classes.center
    }, key), formattedMessages[key].map((msg, index) => /*#__PURE__*/_react.default.createElement("div", {
      key: index,
      className: loggedUser === msg.sender.id ? classes.sender : classes.receiver
    }, /*#__PURE__*/_react.default.createElement(_Message.default, {
      elevation: 0,
      message: msg,
      key: msg.id,
      snippetType: false,
      loggedUser: loggedUser,
      onMouseEnter: () => handleMouseEnter(msg.id),
      onMouseLeave: () => handleMouseLeave(msg.id),
      isHovering: isHovered[msg.id],
      onDeleteIconClick: () => handleDeleteDialog(msg)
    }))))), /*#__PURE__*/_react.default.createElement(_MessageEditor.default, {
      send: () => sendMessage(),
      isSending: sending,
      getMessage: handleMessage,
      getMessageFile: handleMessageFile
    }));
  }
  /**
   * Renders empty box (when there is no thread open) or new message box
   * @return {JSX.Element}
   */


  function renderNewOrNoMessageBox() {
    return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, openNewMessage ? /*#__PURE__*/_react.default.createElement(_material.Box, {
      className: classes.newMessageBox
    }, /*#__PURE__*/_react.default.createElement(_material.Box, {
      sx: {
        flexGrow: 0,
        flexShrink: 1,
        flexBasis: 'auto'
      }
    }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
      container: true,
      className: classes.newMessageHeader
    }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
      item: true,
      xs: 4,
      sx: {
        display: 'flex',
        alignItems: 'center'
      }
    }, /*#__PURE__*/_react.default.createElement(_Icon.default, {
      sx: {
        marginRight: '8px'
      },
      fontSize: "small"
    }, "person"), /*#__PURE__*/_react.default.createElement(_material.Typography, {
      sx: {
        fontWeight: 'bold'
      }
    }, /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, {
      defaultMessage: "ui.thread.newMessage.to",
      id: "ui.thread.newMessage.to"
    }))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
      item: true,
      xs: 8
    }, /*#__PURE__*/_react.default.createElement(_Autocomplete.default, {
      className: classes.autocomplete,
      multiple: true,
      freeSolo: true,
      options: followers,
      getOptionLabel: option => option.username,
      renderInput: params => /*#__PURE__*/_react.default.createElement(_material.TextField, _extends({}, params, {
        placeholder: `${intl.formatMessage(smessages.placeholder)}`,
        variant: "standard",
        InputProps: Object.assign({}, params.InputProps, {
          disableUnderline: true
        })
      })),
      onChange: selectRecipients
    })))), /*#__PURE__*/_react.default.createElement(_material.Box, {
      className: classes.newMessageEmptyBox
    }), /*#__PURE__*/_react.default.createElement(_material.Box, {
      className: classes.newMessageEditor
    }, /*#__PURE__*/_react.default.createElement(_MessageEditor.default, {
      send: () => sendMessage(),
      isSending: sending,
      getMessage: handleMessage,
      getMessageFile: handleMessageFile
    }))) : /*#__PURE__*/_react.default.createElement(_material.Box, {
      className: classes.emptyBox
    }, /*#__PURE__*/_react.default.createElement(_material.Typography, {
      component: "h3"
    }, /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, {
      id: "ui.thread.emptyBox.message",
      defaultMessage: "ui.thread.emptyBox.message"
    }))));
  } // Anonymous


  if (!scUserContext.user) {
    return null;
  }
  /**
   * Renders the component (if not hidden by autoHide prop)
   */


  if (!autoHide) {
    return /*#__PURE__*/_react.default.createElement(Root, _extends({}, rest, {
      className: (0, _classnames.default)(classes.root, className)
    }), id ? renderThread() : renderNewOrNoMessageBox());
  }

  return null;
}