strapi-plugin-comments 2.0.0-rc.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +109 -67
- package/__mocks__/initSetup.js +53 -0
- package/admin/src/components/ActionButton/styles.js +10 -0
- package/admin/src/components/DiscussionThread/index.js +3 -7
- package/admin/src/components/DiscussionThreadItem/index.js +25 -70
- package/admin/src/components/DiscussionThreadItem/styles.js +4 -79
- package/admin/src/components/DiscussionThreadItemActions/index.js +82 -40
- package/admin/src/components/DiscussionThreadItemActions/styles.js +1 -12
- package/admin/src/components/DiscussionThreadItemApprovalFlowActions/index.js +2 -3
- package/admin/src/components/DiscussionThreadItemFooter/index.js +47 -0
- package/admin/src/components/DiscussionThreadItemFooter/styles.js +13 -0
- package/admin/src/components/DiscussionThreadItemReviewAction/index.js +131 -0
- package/admin/src/components/IconButton/styles.js +14 -0
- package/admin/src/components/ReportsReviewModal/index.js +1 -1
- package/admin/src/components/ReportsReviewTable/index.js +12 -6
- package/admin/src/components/StatusBadge/index.js +17 -0
- package/admin/src/components/StatusBadge/styles.js +17 -0
- package/admin/src/pages/Details/components/DetailsEntity/index.js +42 -24
- package/admin/src/pages/Details/components/DetailsFilters/index.js +8 -10
- package/admin/src/pages/Details/index.js +6 -15
- package/admin/src/pages/Discover/components/DiscoverTableRow/index.js +30 -67
- package/admin/src/translations/en.json +13 -15
- package/admin/src/utils/resolveCommentStatus.js +4 -4
- package/content-types/comment.js +0 -4
- package/package.json +8 -5
- package/server/controllers/client.js +11 -6
- package/server/controllers/utils/__tests__/functions.test.js +2 -2
- package/server/controllers/utils/parsers.js +6 -2
- package/server/graphql/mutations/createAbuseReport.js +8 -3
- package/server/graphql/mutations/createComment.js +8 -3
- package/server/graphql/mutations/removeComment.js +8 -3
- package/server/graphql/mutations/updateComment.js +8 -3
- package/server/graphql/queries/findAllFlat.js +4 -2
- package/server/graphql/queries/findAllInHierarchy.js +3 -3
- package/server/graphql/resolvers-config.js +13 -8
- package/server/graphql/types/comment-nested.js +1 -1
- package/server/graphql/types/comment.js +0 -1
- package/server/graphql/types/create-comment-author.js +1 -1
- package/server/graphql/types/identify-comment-author.js +1 -1
- package/server/graphql/types/index.js +0 -1
- package/server/services/__tests__/common.test.js +165 -0
- package/server/services/admin.js +10 -7
- package/server/services/client.js +45 -31
- package/server/services/common.js +71 -19
- package/server/services/utils/__tests__/functions.test.js +9 -73
- package/server/services/utils/functions.js +23 -34
- package/server/utils/__tests__/functions.test.js +17 -0
- package/server/utils/constants.js +1 -0
- package/.circleci/config.yml +0 -48
- package/.eslintrc +0 -35
- package/.github/pull_request_template.md +0 -13
- package/.nvmrc +0 -1
- package/admin/src/components/DiscussionThreadItemMeta/index.js +0 -42
- package/admin/src/components/DiscussionThreadItemWarnings/index.js +0 -147
- package/admin/src/components/DiscussionThreadItemWarnings/styles.js +0 -7
- package/codecov.yml +0 -4
- package/public/assets/logo.png +0 -0
- package/public/assets/preview.png +0 -0
- package/server/graphql/types/comment-author-user.js +0 -9
|
@@ -1,86 +1,22 @@
|
|
|
1
|
-
const PluginError = require('
|
|
2
|
-
const {
|
|
1
|
+
const PluginError = require('../../../utils/error');
|
|
2
|
+
const { resolveUserContextError, getModelUid } = require('../functions');
|
|
3
3
|
|
|
4
4
|
beforeEach(() => {
|
|
5
5
|
Object.defineProperty(global, 'strapi', {
|
|
6
|
-
value:
|
|
7
|
-
plugins: {
|
|
8
|
-
comments: {
|
|
9
|
-
package: require('../../../package.json'),
|
|
10
|
-
services: {
|
|
11
|
-
comments: require('../../comments'),
|
|
12
|
-
},
|
|
13
|
-
models: {
|
|
14
|
-
comment: require('../../../models/comment.settings.json'),
|
|
15
|
-
report: require('../../../models/report.settings.json'),
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
config: {
|
|
20
|
-
plugins: {
|
|
21
|
-
comments: {
|
|
22
|
-
enableUsers: false,
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
},
|
|
6
|
+
value: require('../../../../__mocks__/initSetup')(),
|
|
27
7
|
writable: true,
|
|
28
8
|
});
|
|
29
9
|
})
|
|
30
10
|
|
|
31
|
-
describe('Test
|
|
32
|
-
|
|
33
|
-
describe('Bad Words filtering', () => {
|
|
34
|
-
const text = 'Lorem ipsum dolor sit fuck amet';
|
|
35
|
-
|
|
36
|
-
test('Should find bad words usage and throw error PluginError', () => {
|
|
37
|
-
expect.assertions(6);
|
|
38
|
-
try {
|
|
39
|
-
checkBadWords(text);
|
|
40
|
-
} catch (e) {
|
|
41
|
-
expect(e).toBeInstanceOf(PluginError);
|
|
42
|
-
expect(e).toHaveProperty('status', 400);
|
|
43
|
-
expect(e).toHaveProperty('name', 'Strapi:Plugin:Comments');
|
|
44
|
-
expect(e).toHaveProperty('message', 'Bad language used! Please polite your comment...');
|
|
45
|
-
expect(e).toHaveProperty('payload');
|
|
46
|
-
expect(e.payload).toEqual(expect.objectContaining({
|
|
47
|
-
content: {
|
|
48
|
-
original: text,
|
|
49
|
-
filtered: text.replace('fuck', '****'),
|
|
50
|
-
}
|
|
51
|
-
}));
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test('Should skip bad words filtering because of configuration change', () => {
|
|
56
|
-
global.strapi.config.plugins.comments.badWords = false;
|
|
57
|
-
|
|
58
|
-
expect(checkBadWords(text)).toEqual(text);
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
describe('Extracting metadata', () => {
|
|
63
|
-
test('Should extract plugin metadata properly', () => {
|
|
64
|
-
const { model, service, plugin, pluginName } = extractMeta(strapi.plugins);
|
|
65
|
-
|
|
66
|
-
expect(model).toHaveProperty('info.name', 'comment');
|
|
67
|
-
expect(service).toHaveProperty('findAll');
|
|
68
|
-
expect(Object.keys(plugin)).toEqual(expect.arrayContaining(['package', 'services', 'models']));
|
|
69
|
-
expect(pluginName).toBe('comments');
|
|
70
|
-
});
|
|
71
|
-
});
|
|
11
|
+
describe('Test service functions utils', () => {
|
|
72
12
|
|
|
73
|
-
describe('
|
|
74
|
-
test('
|
|
75
|
-
|
|
76
|
-
expect(isValidUserContext(undefined)).toEqual(true);
|
|
77
|
-
expect(isValidUserContext({ id: 1 })).toEqual(true);
|
|
13
|
+
describe('Getting models uid\'s ', () => {
|
|
14
|
+
test('Should get comments uid', () => {
|
|
15
|
+
expect(getModelUid('comment')).toBe('plugins::comments.comment');
|
|
78
16
|
});
|
|
79
17
|
|
|
80
|
-
test('
|
|
81
|
-
|
|
82
|
-
expect(isValidUserContext(undefined)).toEqual(false);
|
|
83
|
-
expect(isValidUserContext({ id: 1 })).toEqual(true);
|
|
18
|
+
test('Should get report uid', () => {
|
|
19
|
+
expect(getModelUid('comment-report')).toBe('plugins::comments.comment-report');
|
|
84
20
|
});
|
|
85
21
|
});
|
|
86
22
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
const BadWordsFilter = require('bad-words');
|
|
2
1
|
const PluginError = require('./../../utils/error');
|
|
3
2
|
const { REGEX } = require('./../../utils/constants')
|
|
4
|
-
const { first,
|
|
3
|
+
const { first, isObject, isEmpty } = require('lodash');
|
|
5
4
|
|
|
6
5
|
const buildNestedStructure = (
|
|
7
6
|
entities,
|
|
@@ -33,7 +32,7 @@ const buildNestedStructure = (
|
|
|
33
32
|
|
|
34
33
|
module.exports = {
|
|
35
34
|
isEqualEntity: (existing, data, user) => {
|
|
36
|
-
const {
|
|
35
|
+
const { author: existingAuthor } = existing;
|
|
37
36
|
const { author } = data;
|
|
38
37
|
|
|
39
38
|
// Disallow approval status change by Client
|
|
@@ -42,10 +41,10 @@ module.exports = {
|
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
// Make sure that author is exact the same
|
|
45
|
-
if (
|
|
46
|
-
const existingUserId =
|
|
47
|
-
const receivedUserId = user?.id || author;
|
|
48
|
-
return existingUserId === receivedUserId;
|
|
44
|
+
if (user) {
|
|
45
|
+
const existingUserId = existingAuthor?.id || existingAuthor;
|
|
46
|
+
const receivedUserId = user?.id || author?.id;
|
|
47
|
+
return receivedUserId && (existingUserId === receivedUserId);
|
|
49
48
|
}
|
|
50
49
|
return existingAuthor.id === author?.id;
|
|
51
50
|
},
|
|
@@ -63,21 +62,6 @@ module.exports = {
|
|
|
63
62
|
reports: (item.reports || []).filter(report => !report.resolved),
|
|
64
63
|
} : item),
|
|
65
64
|
|
|
66
|
-
checkBadWords: content => {
|
|
67
|
-
const config = get(strapi.config, 'plugins.comments.badWords', true);
|
|
68
|
-
if (config) {
|
|
69
|
-
const filter = new BadWordsFilter(isObject(config) ? config : undefined);
|
|
70
|
-
if (content && filter.isProfane(content)) {
|
|
71
|
-
throw new PluginError(400, 'Bad language used! Please polite your comment...', {
|
|
72
|
-
content: {
|
|
73
|
-
original: content,
|
|
74
|
-
filtered: content && filter.clean(content),
|
|
75
|
-
},
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return content;
|
|
80
|
-
},
|
|
81
65
|
convertContentTypeNameToSlug: str => {
|
|
82
66
|
const plainConversion = str.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`);
|
|
83
67
|
return first(plainConversion) === '-' ? plainConversion.slice(1, plainConversion.length) : plainConversion;
|
|
@@ -85,22 +69,27 @@ module.exports = {
|
|
|
85
69
|
|
|
86
70
|
buildNestedStructure,
|
|
87
71
|
|
|
88
|
-
isValidUserContext: (user = {}) => {
|
|
89
|
-
const builtInContextEnabled = get(strapi.config, 'plugins.comments.enableUsers', false);
|
|
90
|
-
return builtInContextEnabled ? !isNil(user.id) : true;
|
|
91
|
-
},
|
|
92
|
-
|
|
93
72
|
buildAuthorModel: (item) => {
|
|
94
73
|
const { authorUser, authorId, authorName, authorEmail, authorAvatar, ...rest } = item;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
74
|
+
let author = {};
|
|
75
|
+
if (authorUser) {
|
|
76
|
+
author = {
|
|
77
|
+
id: authorUser.id,
|
|
78
|
+
name: authorUser.username,
|
|
79
|
+
email: authorUser.email,
|
|
80
|
+
avatar: authorUser.avatar,
|
|
81
|
+
};
|
|
82
|
+
} else if(authorId) {
|
|
83
|
+
author = {
|
|
84
|
+
id: authorId,
|
|
85
|
+
name: authorName,
|
|
86
|
+
email: authorEmail,
|
|
87
|
+
avatar: authorAvatar,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
101
90
|
return {
|
|
102
91
|
...rest,
|
|
103
|
-
author,
|
|
92
|
+
author: isEmpty(author) ? undefined : author,
|
|
104
93
|
};
|
|
105
94
|
},
|
|
106
95
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const { getPluginService } = require('../functions');
|
|
2
|
+
|
|
3
|
+
beforeEach(() => {
|
|
4
|
+
Object.defineProperty(global, 'strapi', {
|
|
5
|
+
value: require('../../../__mocks__/initSetup')(),
|
|
6
|
+
writable: true,
|
|
7
|
+
});
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
describe('Test plugin functions utils', () => {
|
|
11
|
+
|
|
12
|
+
describe('Get plugin service', () => {
|
|
13
|
+
test('Should get common service', () => {
|
|
14
|
+
expect(getPluginService('common')).toHaveProperty('findAllFlat');
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -8,6 +8,7 @@ const REGEX = {
|
|
|
8
8
|
uid: /^(?<type>[a-z0-9-]+)\:{2}(?<api>[a-z0-9-]+)\.{1}(?<contentType>[a-z0-9-]+)$/i,
|
|
9
9
|
relatedUid: /^(?<uid>[a-z0-9-]+\:{2}[a-z0-9-]+\.[a-z0-9-]+)\:{1}(?<id>[a-z0-9-]+)$/i,
|
|
10
10
|
email: /\S+@\S+\.\S+/,
|
|
11
|
+
sorting: /^(?<path>[a-z0-9-_\:\.]+)\:+(asc|desc)$/i
|
|
11
12
|
};
|
|
12
13
|
|
|
13
14
|
module.exports = {
|
package/.circleci/config.yml
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
version: 2.1
|
|
2
|
-
orbs:
|
|
3
|
-
codecov: codecov/codecov@1.1.1
|
|
4
|
-
jobs:
|
|
5
|
-
build-and-test:
|
|
6
|
-
environment:
|
|
7
|
-
CODECOV_TOKEN: 02e2d4e8-88c4-4e5d-99da-a9a2888634c6
|
|
8
|
-
docker:
|
|
9
|
-
- image: circleci/node:12.13.0
|
|
10
|
-
working_directory: ~/repo
|
|
11
|
-
steps:
|
|
12
|
-
- checkout
|
|
13
|
-
- run:
|
|
14
|
-
name: set GIT name and email
|
|
15
|
-
command: |
|
|
16
|
-
git config --global -l
|
|
17
|
-
git config --global user.email "$GIT_COMMITTER_EMAIL"
|
|
18
|
-
git config --global user.name "$GIT_COMMITTER_NAME"
|
|
19
|
-
git config --global -l
|
|
20
|
-
- restore_cache:
|
|
21
|
-
keys:
|
|
22
|
-
# when lock file changes, use increasingly general patterns to restore cache
|
|
23
|
-
- strapi-plugin-comments-v2-{{ checksum "yarn.lock" }}
|
|
24
|
-
- strapi-plugin-comments-
|
|
25
|
-
- run:
|
|
26
|
-
name: Echo versions
|
|
27
|
-
command: |
|
|
28
|
-
node --version
|
|
29
|
-
yarn --version
|
|
30
|
-
- run:
|
|
31
|
-
name: Install
|
|
32
|
-
command: |
|
|
33
|
-
yarn install
|
|
34
|
-
- run:
|
|
35
|
-
name: Test
|
|
36
|
-
command: |
|
|
37
|
-
yarn test:unit
|
|
38
|
-
- codecov/upload:
|
|
39
|
-
flags: unittest
|
|
40
|
-
file:
|
|
41
|
-
- save_cache:
|
|
42
|
-
paths:
|
|
43
|
-
- ./node_modules
|
|
44
|
-
key: strapi-plugin-comments-v2-{{ checksum "yarn.lock" }}
|
|
45
|
-
workflows:
|
|
46
|
-
build-and-test:
|
|
47
|
-
jobs:
|
|
48
|
-
- build-and-test
|
package/.eslintrc
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"parserOptions": {
|
|
3
|
-
"jsx": true,
|
|
4
|
-
"useJSXTextNode": true,
|
|
5
|
-
"sourceType": "module"
|
|
6
|
-
},
|
|
7
|
-
"plugins": ["react-hooks", "import"],
|
|
8
|
-
"rules": {
|
|
9
|
-
"no-console": "warn",
|
|
10
|
-
"curly": "warn",
|
|
11
|
-
"prefer-template": "warn",
|
|
12
|
-
|
|
13
|
-
"react-hooks/rules-of-hooks": "error",
|
|
14
|
-
"react-hooks/exhaustive-deps": "error",
|
|
15
|
-
|
|
16
|
-
"import/no-default-export": "warn",
|
|
17
|
-
"import/newline-after-import": "warn",
|
|
18
|
-
"import/order": [
|
|
19
|
-
"warn",
|
|
20
|
-
{
|
|
21
|
-
"newlines-between": "always",
|
|
22
|
-
"alphabetize": { "order": "asc" },
|
|
23
|
-
"pathGroupsExcludedImportTypes": ["builtin"],
|
|
24
|
-
"groups": [
|
|
25
|
-
"builtin",
|
|
26
|
-
"external",
|
|
27
|
-
"internal",
|
|
28
|
-
"parent",
|
|
29
|
-
"sibling",
|
|
30
|
-
"index"
|
|
31
|
-
]
|
|
32
|
-
}
|
|
33
|
-
]
|
|
34
|
-
}
|
|
35
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
## Ticket
|
|
2
|
-
|
|
3
|
-
https://github.com/VirtusLab/strapi-plugin-comments/issues/-<your-ticket-#>
|
|
4
|
-
|
|
5
|
-
## Summary
|
|
6
|
-
|
|
7
|
-
What does this PR do/solve?
|
|
8
|
-
|
|
9
|
-
> PRs should be as small as they need to be, if this section starts becoming a novel you should _seriously_ consider breaking it up into multiple PRs
|
|
10
|
-
|
|
11
|
-
## Test Plan
|
|
12
|
-
|
|
13
|
-
How are you testing the work you're submitting?
|
package/.nvmrc
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
v14.17.3
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
* Entity Details
|
|
4
|
-
*
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import React from 'react';
|
|
8
|
-
import PropTypes from 'prop-types';
|
|
9
|
-
import { useIntl } from 'react-intl';
|
|
10
|
-
import { Box } from '@strapi/design-system/Box';
|
|
11
|
-
import { Flex } from '@strapi/design-system/Flex';
|
|
12
|
-
import { Stack } from '@strapi/design-system/Stack';
|
|
13
|
-
import { Typography } from '@strapi/design-system/Typography';
|
|
14
|
-
|
|
15
|
-
const DiscussionThreadItemMeta = ({ author, createdAt, updatedAt }) => {
|
|
16
|
-
|
|
17
|
-
const { formatDate } = useIntl();
|
|
18
|
-
|
|
19
|
-
const dateTime = formatDate(updatedAt || createdAt, { dateStyle: 'short', timeStyle: 'short' });
|
|
20
|
-
const { name } = author;
|
|
21
|
-
|
|
22
|
-
return (<Flex as={Box} paddingTop={2} direction="row">
|
|
23
|
-
<Stack size={2} horizontal style={{ flexGrow: 1, justifyContent: 'space-between'}}>
|
|
24
|
-
<Typography variant="pi" fontWeight="bold">{ name }</Typography>
|
|
25
|
-
<Typography variant="pi">{ dateTime }</Typography>
|
|
26
|
-
</Stack>
|
|
27
|
-
</Flex>);
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
DiscussionThreadItemMeta.propTypes = {
|
|
31
|
-
author: PropTypes.shape({
|
|
32
|
-
id: PropTypes.oneOfType(PropTypes.string, PropTypes.number).isRequired,
|
|
33
|
-
name: PropTypes.string.isRequired,
|
|
34
|
-
email: PropTypes.string,
|
|
35
|
-
avatar: PropTypes.string,
|
|
36
|
-
}).isRequired,
|
|
37
|
-
createdAt: PropTypes.string.isRequired,
|
|
38
|
-
updatedAt: PropTypes.string,
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export default DiscussionThreadItemMeta;
|
|
42
|
-
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
* Entity Details
|
|
4
|
-
*
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import React, { useState } from 'react';
|
|
8
|
-
import PropTypes from 'prop-types';
|
|
9
|
-
import { useMutation, useQueryClient } from 'react-query';
|
|
10
|
-
import { isEmpty, orderBy } from 'lodash';
|
|
11
|
-
import { Badge } from '@strapi/design-system/Badge';
|
|
12
|
-
import { Box } from '@strapi/design-system/Box';
|
|
13
|
-
import { Button } from '@strapi/design-system/Button';
|
|
14
|
-
import { Divider } from '@strapi/design-system/Divider';
|
|
15
|
-
import { Flex } from '@strapi/design-system/Flex';
|
|
16
|
-
import { Typography } from '@strapi/design-system/Typography';
|
|
17
|
-
import { useNotification, useOverlayBlocker } from '@strapi/helper-plugin';
|
|
18
|
-
import { getMessage, handleAPIError } from '../../utils';
|
|
19
|
-
import { blockItem, blockItemThread, resolveReport } from '../../pages/utils/api';
|
|
20
|
-
import { DiscussionThreadItemWarningsWrapper } from './styles';
|
|
21
|
-
import ReportsReviewModal from '../ReportsReviewModal';
|
|
22
|
-
import ReportsReviewTable from '../ReportsReviewTable';
|
|
23
|
-
import pluginId from '../../pluginId';
|
|
24
|
-
import { LockIcon, ReviewIcon } from '../icons';
|
|
25
|
-
|
|
26
|
-
const DiscussionThreadItemWarnings = (item) => {
|
|
27
|
-
const { id, reports, gotThread, allowedActions: { canModerate, canAccessReports, canReviewReports }} = item;
|
|
28
|
-
|
|
29
|
-
const [reportsReviewVisible, setReportsReviewVisible] = useState(false);
|
|
30
|
-
const [blockButtonsDisabled, setBlockButtonsDisabled] = useState(false);
|
|
31
|
-
|
|
32
|
-
const toggleNotification = useNotification();
|
|
33
|
-
const queryClient = useQueryClient();
|
|
34
|
-
const { lockApp, unlockApp } = useOverlayBlocker();
|
|
35
|
-
|
|
36
|
-
const onSuccess = (message, stateAction = () => {}, indalidate = true) => async () => {
|
|
37
|
-
if (indalidate) {
|
|
38
|
-
await queryClient.invalidateQueries('get-details-data');
|
|
39
|
-
}
|
|
40
|
-
toggleNotification({
|
|
41
|
-
type: 'success',
|
|
42
|
-
message: `${pluginId}.${message}`,
|
|
43
|
-
});
|
|
44
|
-
stateAction(false);
|
|
45
|
-
unlockApp();
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const onError = err => { handleAPIError(err, toggleNotification); };
|
|
49
|
-
|
|
50
|
-
const resolveReportMutation = useMutation(resolveReport, {
|
|
51
|
-
onSuccess: onSuccess('page.details.panel.discussion.warnings.reports.dialog.confirmation.success', () => {}, false),
|
|
52
|
-
onError,
|
|
53
|
-
refetchActive: false,
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
const blockItemMutation = useMutation(blockItem, {
|
|
57
|
-
onSuccess: onSuccess(
|
|
58
|
-
'page.details.actions.comment.block.confirmation.success',
|
|
59
|
-
setReportsReviewVisible
|
|
60
|
-
),
|
|
61
|
-
onError,
|
|
62
|
-
refetchActive: false,
|
|
63
|
-
});
|
|
64
|
-
const blockItemThreadMutation = useMutation(blockItemThread, {
|
|
65
|
-
onSuccess: onSuccess(
|
|
66
|
-
'page.details.actions.thread.block.confirmation.success',
|
|
67
|
-
setReportsReviewVisible
|
|
68
|
-
),
|
|
69
|
-
onError,
|
|
70
|
-
refetchActive: false,
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
const handleReportsReviewClick = () => setReportsReviewVisible(true);
|
|
74
|
-
const handleBlockItemClick = async () => {
|
|
75
|
-
lockApp();
|
|
76
|
-
blockItemMutation.mutate(id);
|
|
77
|
-
};
|
|
78
|
-
const handleBlockItemThreadClick = async () => {
|
|
79
|
-
lockApp();
|
|
80
|
-
blockItemThreadMutation.mutate(id);
|
|
81
|
-
};
|
|
82
|
-
const handleReportsReviewClose = async () => {
|
|
83
|
-
await queryClient.invalidateQueries('get-details-data')
|
|
84
|
-
setReportsReviewVisible(false);
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const handleBlockButtonsStateChange = disabled => setBlockButtonsDisabled(disabled);
|
|
88
|
-
|
|
89
|
-
const isLoading = blockItemMutation.isLoading || blockItemThreadMutation.isLoading || resolveReportMutation.isLoading;
|
|
90
|
-
const openReports = reports?.filter(_ => !_.resolved);
|
|
91
|
-
|
|
92
|
-
if (isEmpty(reports) || isEmpty(openReports)) {
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return (<>
|
|
97
|
-
{ canAccessReports && (<DiscussionThreadItemWarningsWrapper as={Flex} direction="row" padding={2} background="danger100" borderColor="danger200" border={1} hasRadius>
|
|
98
|
-
<Box as={Flex} paddingRight={2} direction="row" grow={1}>
|
|
99
|
-
<Badge textColor="neutral0" backgroundColor="warning600">{ openReports.length }</Badge>
|
|
100
|
-
<Box paddingLeft={2}>
|
|
101
|
-
<Typography textColor="warning600" fontWeight="bold">{getMessage(`page.details.panel.discussion.warnings.reports.description`, 'abuse reports')}</Typography>
|
|
102
|
-
</Box>
|
|
103
|
-
</Box>
|
|
104
|
-
<Button onClick={handleReportsReviewClick} variant="ghost" endIcon={<ReviewIcon />}>
|
|
105
|
-
{ getMessage(`page.details.actions.comment.report.review`, 'review') }
|
|
106
|
-
</Button>
|
|
107
|
-
</DiscussionThreadItemWarningsWrapper>) }
|
|
108
|
-
{ (canAccessReports || canReviewReports) && (<ReportsReviewModal
|
|
109
|
-
isVisible={reportsReviewVisible}
|
|
110
|
-
isActionAsync={isLoading}
|
|
111
|
-
onClose={handleReportsReviewClose}
|
|
112
|
-
startActions={canModerate && (<>
|
|
113
|
-
<Button onClick={handleBlockItemClick} variant="danger-light" startIcon={<LockIcon />} disabled={blockButtonsDisabled}>
|
|
114
|
-
{ getMessage(`page.details.actions.comment.block`, 'Block comment') }
|
|
115
|
-
</Button>
|
|
116
|
-
{ gotThread && (<Button onClick={handleBlockItemThreadClick} variant="danger" startIcon={<LockIcon />} disabled={blockButtonsDisabled}>
|
|
117
|
-
{ getMessage(`page.details.actions.thread.block`, 'Block thread') }
|
|
118
|
-
</Button>) }
|
|
119
|
-
</>)}
|
|
120
|
-
item={item}>
|
|
121
|
-
<Typography variant="sigma" textColor="neutral600" id="reports-list">
|
|
122
|
-
{ getMessage('page.details.panel.discussion.warnings.reports.list', 'List') }
|
|
123
|
-
</Typography>
|
|
124
|
-
<Box paddingTop={2} paddingBottom={6}>
|
|
125
|
-
<Divider />
|
|
126
|
-
</Box>
|
|
127
|
-
<ReportsReviewTable
|
|
128
|
-
commentId={id}
|
|
129
|
-
items={orderBy(reports, ['resolved', 'createdAt'], ['DESC', 'DESC'])}
|
|
130
|
-
mutation={resolveReportMutation}
|
|
131
|
-
allowedActions={{ canAccessReports, canReviewReports }}
|
|
132
|
-
onBlockButtonsStateChange={handleBlockButtonsStateChange}
|
|
133
|
-
/>
|
|
134
|
-
</ReportsReviewModal>) }
|
|
135
|
-
</>);
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
DiscussionThreadItemWarnings.propTypes = {
|
|
139
|
-
allowedActions: PropTypes.shape({
|
|
140
|
-
canModerate: PropTypes.bool,
|
|
141
|
-
canAccessReports: PropTypes.bool,
|
|
142
|
-
canReviewReports: PropTypes.bool,
|
|
143
|
-
}),
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
export default DiscussionThreadItemWarnings;
|
|
147
|
-
|
package/codecov.yml
DELETED
package/public/assets/logo.png
DELETED
|
Binary file
|
|
Binary file
|