feat: Add post actions dropdown menu

Adds a dropdown menu for comments and posts to perform actions like pinning, unpinning, reporting etc.
This commit is contained in:
Kshitij Sobti
2021-09-11 11:47:27 +05:30
parent 669aa22400
commit 5db87f54bb
19 changed files with 578 additions and 253 deletions

View File

@@ -1,15 +1,23 @@
/* eslint-disable import/prefer-default-export */
import { useContext } from 'react';
import { getIn } from 'formik';
import { useRouteMatch } from 'react-router';
import { Routes } from '../data/constants';
import { AppContext } from '@edx/frontend-platform/react';
import {
Delete, Edit, Flag, Pin, QuestionAnswer, VerifiedBadge,
} from '@edx/paragon/icons';
export function buildIntlSelectionList(options, intl, messages) {
import { ContentActions, Routes } from '../data/constants';
import messages from './messages';
export function buildIntlSelectionList(options, intl, messagesData) {
return Object.values(options)
.map(
option => (
{
label: intl.formatMessage(messages[option]),
label: intl.formatMessage(messagesData[option]),
value: option,
}
),
@@ -45,3 +53,119 @@ export function useCommentsPagePath() {
const { params } = useRouteMatch(Routes.COMMENTS.PAGE);
return Routes.COMMENTS.PAGES[params.page];
}
/**
* Check if the provided comment or post supports the provided option.
* @param {{}} commentOrPost
* @param {ContentActions} action
* @param {UserData} user
* @returns {boolean}
*/
export function permissionCheck(commentOrPost, action, user) {
if (commentOrPost.editableFields.includes(action)) {
return true;
}
if (action === ContentActions.DELETE && (user.administrator || commentOrPost.author === user.username)) {
return true;
}
if ((action === ContentActions.CLOSE || action === ContentActions.PIN) && user.administrator) {
return true;
}
return false;
}
/**
* List of all possible actions for comments or posts.
*
* * `id` is a unique id for each action.
* * `action` is the action being performed. One action can
* have multiple mutually-exclusive entries (such as close/open)..
* * `icon` is the icon component to show for the action.
* * `label` is the translatable label message that can be passed to intl.
* * `condition` is the array where the first one is a property of the post
* or comment and the second is the value.
* e.g. for ['pinned', false] the action will show up if the comment/post has post.pinned=false
*/
const ACTIONS_LIST = [
{
id: 'edit',
action: ContentActions.EDIT_CONTENT,
icon: Edit,
label: messages.editAction,
},
{
id: 'pin',
action: ContentActions.PIN,
icon: Pin,
label: messages.pinAction,
condition: ['pinned', false],
},
{
id: 'unpin',
action: ContentActions.PIN,
icon: Pin,
label: messages.unpinAction,
condition: ['pinned', true],
},
{
id: 'endorse',
action: ContentActions.ENDORSE,
icon: VerifiedBadge,
label: messages.endorseAction,
condition: ['endorsed', false],
},
{
id: 'unendorse',
action: ContentActions.ENDORSE,
icon: VerifiedBadge,
label: messages.unendorseAction,
condition: ['endorsed', true],
},
{
id: 'close',
action: ContentActions.CLOSE,
icon: QuestionAnswer,
label: messages.closeAction,
condition: ['closed', false],
},
{
id: 'reopen',
action: ContentActions.CLOSE,
icon: QuestionAnswer,
label: messages.reopenAction,
condition: ['closed', true],
},
{
id: 'report',
action: ContentActions.REPORT,
icon: Flag,
label: messages.reportAction,
condition: ['abuseFlagged', false],
},
{
id: 'unreport',
action: ContentActions.REPORT,
icon: Flag,
label: messages.unreportAction,
condition: ['abuseFlagged', true],
},
{
id: 'delete',
action: ContentActions.DELETE,
icon: Delete,
label: messages.deleteAction,
},
];
export function useActions(commentOrPost) {
const { authenticatedUser } = useContext(AppContext);
return ACTIONS_LIST.filter(
({
action,
condition = null,
}) => (
permissionCheck(commentOrPost, action, authenticatedUser)
&& (condition ? commentOrPost[condition[0]] === condition[1] : true)
),
);
}