Compare commits

...

3 Commits

6 changed files with 38 additions and 1 deletions

View File

@@ -55,6 +55,8 @@ export const ContentActions = {
CHANGE_TOPIC: 'topic_id', CHANGE_TOPIC: 'topic_id',
CHANGE_TYPE: 'type', CHANGE_TYPE: 'type',
VOTE: 'voted', VOTE: 'voted',
ACCEPT_REVIEW: 'accept_review',
REJECT_REVIEW: 'reject_review',
}; };
/** /**

View File

@@ -26,6 +26,16 @@ const messages = defineMessages({
defaultMessage: 'Unpin', defaultMessage: 'Unpin',
description: 'Action to unpin a post', description: 'Action to unpin a post',
}, },
acceptReview: {
id: 'discussions.actions.reviewAccept',
defaultMessage: 'Accept',
description: 'Action to accept content flagged for review',
},
rejectReview: {
id: 'discussions.actions.reviewReject',
defaultMessage: 'Decline',
description: 'Action to reject content flagged for review',
},
deleteAction: { deleteAction: {
id: 'discussions.actions.delete', id: 'discussions.actions.delete',
defaultMessage: 'Delete', defaultMessage: 'Delete',

View File

@@ -151,6 +151,7 @@ export async function updateThread(threadId, {
pinned, pinned,
editReasonCode, editReasonCode,
closeReasonCode, closeReasonCode,
reviewStatus,
} = {}) { } = {}) {
const url = `${getThreadsApiUrl()}${threadId}/`; const url = `${getThreadsApiUrl()}${threadId}/`;
const patchData = snakeCaseObject({ const patchData = snakeCaseObject({
@@ -166,6 +167,7 @@ export async function updateThread(threadId, {
pinned, pinned,
editReasonCode, editReasonCode,
closeReasonCode, closeReasonCode,
reviewStatus,
}); });
const { data } = await getAuthenticatedHttpClient() const { data } = await getAuthenticatedHttpClient()
.patch(url, patchData, { headers: { 'Content-Type': 'application/merge-patch+json' } }); .patch(url, patchData, { headers: { 'Content-Type': 'application/merge-patch+json' } });

View File

@@ -239,6 +239,7 @@ export function createNewThread({
export function updateExistingThread(threadId, { export function updateExistingThread(threadId, {
flagged, voted, read, topicId, type, title, content, following, closed, pinned, closeReasonCode, editReasonCode, flagged, voted, read, topicId, type, title, content, following, closed, pinned, closeReasonCode, editReasonCode,
reviewStatus,
}) { }) {
return async (dispatch) => { return async (dispatch) => {
try { try {
@@ -256,6 +257,7 @@ export function updateExistingThread(threadId, {
pinned, pinned,
editReasonCode, editReasonCode,
closeReasonCode, closeReasonCode,
reviewStatus,
})); }));
const data = await updateThread(threadId, { const data = await updateThread(threadId, {
flagged, flagged,
@@ -270,6 +272,7 @@ export function updateExistingThread(threadId, {
pinned, pinned,
editReasonCode, editReasonCode,
closeReasonCode, closeReasonCode,
reviewStatus,
}); });
dispatch(updateThreadSuccess(camelCaseObject(data))); dispatch(updateThreadSuccess(camelCaseObject(data)));
} catch (error) { } catch (error) {

View File

@@ -44,6 +44,7 @@ function Post({
const userHasModerationPrivileges = useSelector(selectUserHasModerationPrivileges); const userHasModerationPrivileges = useSelector(selectUserHasModerationPrivileges);
const displayPostFooter = post.following || post.voteCount || post.closed const displayPostFooter = post.following || post.voteCount || post.closed
|| (post.groupId && userHasModerationPrivileges); || (post.groupId && userHasModerationPrivileges);
const displayReviewContentLabel = post.reviewStatus === "PENDING";
const handleAbusedFlag = useCallback(() => { const handleAbusedFlag = useCallback(() => {
if (post.abuseFlagged) { if (post.abuseFlagged) {
@@ -85,6 +86,8 @@ function Post({
[ContentActions.COPY_LINK]: () => { navigator.clipboard.writeText(`${window.location.origin}/${courseId}/posts/${post.id}`); }, [ContentActions.COPY_LINK]: () => { navigator.clipboard.writeText(`${window.location.origin}/${courseId}/posts/${post.id}`); },
[ContentActions.PIN]: () => dispatch(updateExistingThread(post.id, { pinned: !post.pinned })), [ContentActions.PIN]: () => dispatch(updateExistingThread(post.id, { pinned: !post.pinned })),
[ContentActions.REPORT]: () => handleAbusedFlag(), [ContentActions.REPORT]: () => handleAbusedFlag(),
[ContentActions.ACCEPT_REVIEW]: () => dispatch(updateExistingThread(post.id, { reviewStatus: "ACCEPTED" })),
[ContentActions.REJECT_REVIEW]: () => dispatch(updateExistingThread(post.id, { reviewStatus: "REJECTED" })),
}), [ }), [
showDeleteConfirmation, showDeleteConfirmation,
history, history,
@@ -144,6 +147,8 @@ function Post({
/> />
<AlertBanner content={post} /> <AlertBanner content={post} />
<PostHeader post={post} /> <PostHeader post={post} />
{displayReviewContentLabel && <p style= {{ background: "yellow" }}> This content is under review </p>}
<div className="d-flex mt-14px text-break font-style text-primary-500"> <div className="d-flex mt-14px text-break font-style text-primary-500">
<HTMLLoader htmlNode={post.renderedBody} componentId="post" cssClassName="html-loader" testId={post.id} /> <HTMLLoader htmlNode={post.renderedBody} componentId="post" cssClassName="html-loader" testId={post.id} />
</div> </div>

View File

@@ -5,7 +5,8 @@ import { generatePath, useRouteMatch } from 'react-router';
import { getConfig } from '@edx/frontend-platform'; import { getConfig } from '@edx/frontend-platform';
import { import {
CheckCircle, CheckCircleOutline, Delete, Edit, Lock, LockOpen, Pin, Report, Verified, VerifiedOutline, CheckCircle, CheckCircleOutline, Close, Delete, Done,
Edit, Lock, LockOpen, Pin, Report, Verified, VerifiedOutline,
} from '@edx/paragon/icons'; } from '@edx/paragon/icons';
import { InsertLink } from '../components/icons'; import { InsertLink } from '../components/icons';
@@ -173,6 +174,20 @@ export const ACTIONS_LIST = [
label: messages.deleteAction, label: messages.deleteAction,
conditions: { canDelete: true }, conditions: { canDelete: true },
}, },
{
id: 'accept-review',
action: ContentActions.ACCEPT_REVIEW,
icon: Done,
label: messages.acceptReview,
conditions: { reviewStatus: 'PENDING' },
},
{
id: 'reject-review',
action: ContentActions.REJECT_REVIEW,
icon: Close,
label: messages.rejectReview,
conditions: { reviewStatus: 'PENDING' },
},
]; ];
export function useActions(content) { export function useActions(content) {