95 lines
3.3 KiB
JavaScript
95 lines
3.3 KiB
JavaScript
import React from 'react';
|
|
import PropTypes from 'prop-types';
|
|
|
|
import { useDispatch, useSelector } from 'react-redux';
|
|
import { useHistory, useLocation } from 'react-router-dom';
|
|
|
|
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
|
import { Hyperlink, useToggle } from '@edx/paragon';
|
|
|
|
import { ContentActions } from '../../../data/constants';
|
|
import { selectorForUnitSubsection, selectTopicContext } from '../../../data/selectors';
|
|
import { AlertBanner, DeleteConfirmation } from '../../common';
|
|
import { selectTopic } from '../../topics/data/selectors';
|
|
import { removeThread, updateExistingThread } from '../data/thunks';
|
|
import messages from './messages';
|
|
import PostFooter from './PostFooter';
|
|
import PostHeader from './PostHeader';
|
|
import { postShape } from './proptypes';
|
|
|
|
function Post({
|
|
post,
|
|
preview,
|
|
intl,
|
|
}) {
|
|
const location = useLocation();
|
|
const history = useHistory();
|
|
const dispatch = useDispatch();
|
|
const topic = useSelector(selectTopic(post.topicId));
|
|
const getTopicSubsection = useSelector(selectorForUnitSubsection);
|
|
const topicContext = useSelector(selectTopicContext(post.topicId));
|
|
|
|
const [isDeleting, showDeleteConfirmation, hideDeleteConfirmation] = useToggle(false);
|
|
const actionHandlers = {
|
|
[ContentActions.EDIT_CONTENT]: () => history.push({
|
|
...location,
|
|
pathname: `${location.pathname}/edit`,
|
|
}),
|
|
[ContentActions.DELETE]: showDeleteConfirmation,
|
|
[ContentActions.CLOSE]: () => dispatch(updateExistingThread(post.id, { closed: !post.closed })),
|
|
[ContentActions.PIN]: () => dispatch(updateExistingThread(post.id, { pinned: !post.pinned })),
|
|
[ContentActions.REPORT]: () => dispatch(updateExistingThread(post.id, { flagged: !post.abuseFlagged })),
|
|
};
|
|
|
|
const getTopicCategoryName = topicData => (
|
|
topicData.usageKey ? getTopicSubsection(topicData.usageKey)?.displayName : topicData.categoryId
|
|
);
|
|
return (
|
|
<div className="d-flex flex-column p-2.5 w-100 mw-100" data-testid={`post-${post.id}`}>
|
|
<DeleteConfirmation
|
|
isOpen={isDeleting}
|
|
title={intl.formatMessage(messages.deletePostTitle)}
|
|
description={intl.formatMessage(messages.deletePostDescription)}
|
|
onClose={hideDeleteConfirmation}
|
|
onDelete={() => {
|
|
dispatch(removeThread(post.id));
|
|
history.push('.');
|
|
hideDeleteConfirmation();
|
|
}}
|
|
/>
|
|
<div className="mb-4">
|
|
<AlertBanner postType={post.type} content={post} />
|
|
</div>
|
|
<PostHeader post={post} actionHandlers={actionHandlers} />
|
|
<div className="d-flex my-2 text-break">
|
|
{/* eslint-disable-next-line react/no-danger */}
|
|
<div dangerouslySetInnerHTML={{ __html: post.renderedBody }} />
|
|
</div>
|
|
{topicContext && topic && (
|
|
<div className="border p-3 rounded mb-3 mt-2 align-self-start">
|
|
{intl.formatMessage(messages.relatedTo)}{' '}
|
|
<Hyperlink
|
|
destination={topicContext.unitLink}
|
|
target="_top"
|
|
>
|
|
{`${getTopicCategoryName(topic)} / ${topic.name}`}
|
|
</Hyperlink>
|
|
</div>
|
|
)}
|
|
<PostFooter post={post} preview={preview} />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
Post.propTypes = {
|
|
intl: intlShape.isRequired,
|
|
post: postShape.isRequired,
|
|
preview: PropTypes.bool,
|
|
};
|
|
|
|
Post.defaultProps = {
|
|
preview: false,
|
|
};
|
|
|
|
export default injectIntl(Post);
|