strapi-plugin-comments 1.0.4 → 2.0.0-beta.4
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/.circleci/config.yml +2 -2
- package/README.md +53 -126
- package/admin/src/components/ConfirmationDialog/index.js +56 -0
- package/admin/src/components/DiscussionStatus/index.js +33 -0
- package/admin/src/components/DiscussionThread/index.js +59 -0
- package/admin/src/components/DiscussionThreadItem/index.js +87 -0
- package/admin/src/components/DiscussionThreadItem/styles.js +88 -0
- package/admin/src/components/DiscussionThreadItemActions/index.js +178 -0
- package/admin/src/components/DiscussionThreadItemActions/styles.js +22 -0
- package/admin/src/components/DiscussionThreadItemMeta/index.js +31 -0
- package/admin/src/components/DiscussionThreadItemWarnings/index.js +141 -0
- package/admin/src/components/DiscussionThreadItemWarnings/styles.js +7 -0
- package/admin/src/components/EntityDetails/index.js +53 -0
- package/admin/src/{containers → components}/Initializer/index.js +4 -4
- package/admin/src/components/LoadingIndicatorOverlay/index.js +15 -0
- package/admin/src/components/LoadingIndicatorOverlay/styles.js +20 -0
- package/admin/src/components/Nav/index.js +45 -0
- package/admin/src/components/PluginIcon/index.js +12 -0
- package/admin/src/components/ReportsReviewModal/index.js +43 -0
- package/admin/src/components/ReportsReviewTable/index.js +146 -0
- package/admin/src/components/TableFilters/index.js +53 -0
- package/admin/src/components/TablePagination/index.js +35 -0
- package/admin/src/components/icons/comments.js +9 -0
- package/admin/src/components/icons/index.js +6 -0
- package/admin/src/components/icons/lock.js +22 -0
- package/admin/src/components/icons/review.js +18 -0
- package/admin/src/components/icons/unlock.js +20 -0
- package/admin/src/index.js +58 -42
- package/admin/src/pages/App/index.js +71 -0
- package/admin/src/pages/App/reducer/actions.js +8 -0
- package/admin/src/pages/App/reducer/constants.js +4 -0
- package/admin/src/pages/App/reducer/index.js +26 -0
- package/admin/src/pages/App/reducer/init.js +7 -0
- package/admin/src/pages/App/reducer/selectors.js +35 -0
- package/admin/src/pages/App/utils/api.js +12 -0
- package/admin/src/pages/ComingSoonPage/index.js +25 -0
- package/admin/src/pages/Details/index.js +109 -0
- package/admin/src/pages/Details/utils/api.js +41 -0
- package/admin/src/pages/Discover/components/DiscoverTableRow/index.js +196 -0
- package/admin/src/pages/Discover/index.js +157 -0
- package/admin/src/pages/Discover/utils/api.js +14 -0
- package/admin/src/pages/Discover/utils/filtersSchema.js +9 -0
- package/admin/src/permissions.js +13 -37
- package/admin/src/pluginId.js +2 -4
- package/admin/src/reducers.js +8 -0
- package/admin/src/translations/en.json +73 -37
- package/admin/src/translations/fr.json +1 -0
- package/admin/src/utils/axiosInstance.js +35 -0
- package/admin/src/utils/constants.js +25 -6
- package/admin/src/utils/getApiUrl.js +5 -0
- package/admin/src/utils/getMessage.js +21 -0
- package/admin/src/utils/getRelatedGroups.js +5 -0
- package/admin/src/utils/getUrl.js +5 -0
- package/admin/src/utils/handleAPIError.js +15 -0
- package/admin/src/utils/index.js +6 -0
- package/codecov.yml +2 -1
- package/content-types/comment.js +97 -0
- package/content-types/index.js +11 -0
- package/content-types/report.js +54 -0
- package/package.json +11 -25
- package/server/bootstrap.js +5 -0
- package/server/config/index.js +10 -0
- package/server/controllers/admin.js +134 -0
- package/server/controllers/client.js +117 -0
- package/server/controllers/index.js +9 -0
- package/{controllers → server/controllers}/utils/__tests__/functions.test.js +0 -0
- package/{controllers → server/controllers}/utils/functions.js +1 -1
- package/server/destroy.js +5 -0
- package/server/index.js +22 -0
- package/server/register.js +5 -0
- package/server/routes/admin.js +92 -0
- package/server/routes/client.js +52 -0
- package/server/routes/index.js +15 -0
- package/server/services/admin.js +215 -0
- package/server/services/client.js +227 -0
- package/server/services/common.js +197 -0
- package/server/services/index.js +11 -0
- package/{services → server/services}/utils/__tests__/functions.test.js +0 -0
- package/{services → server/services}/utils/functions.js +17 -6
- package/server/utils/constants.js +16 -0
- package/{services → server}/utils/error.js +0 -0
- package/server/utils/functions.js +19 -0
- package/strapi-admin.js +3 -0
- package/strapi-server.js +9 -0
- package/admin/src/assets/images/icon-cross-blue.svg +0 -1
- package/admin/src/assets/images/icon_remove.svg +0 -19
- package/admin/src/assets/images/logo.svg +0 -5
- package/admin/src/components/AbuseReportsPopUp/ItemPreviewContainer.js +0 -8
- package/admin/src/components/AbuseReportsPopUp/ModalFooter.js +0 -31
- package/admin/src/components/AbuseReportsPopUp/TableContainer.js +0 -63
- package/admin/src/components/AbuseReportsPopUp/index.js +0 -148
- package/admin/src/components/Container/index.js +0 -7
- package/admin/src/components/EmptyView/index.js +0 -25
- package/admin/src/components/Filters/index.js +0 -151
- package/admin/src/components/Filters/index.styled.js +0 -82
- package/admin/src/components/Filters/utils.js +0 -21
- package/admin/src/components/Item/CardItem.js +0 -30
- package/admin/src/components/Item/CardWrapper.js +0 -10
- package/admin/src/components/Item/index.js +0 -107
- package/admin/src/components/ItemDetails/CardItem.js +0 -33
- package/admin/src/components/ItemDetails/CardLevelCounter.js +0 -46
- package/admin/src/components/ItemDetails/CardLevelCounterLink.js +0 -24
- package/admin/src/components/ItemDetails/CardLevelWrapper.js +0 -22
- package/admin/src/components/ItemDetails/CardWrapper.js +0 -52
- package/admin/src/components/ItemDetails/index.js +0 -167
- package/admin/src/components/ItemFooter/CardItemAuthor.js +0 -10
- package/admin/src/components/ItemFooter/CardItemRelation.js +0 -18
- package/admin/src/components/ItemFooter/Wrapper.js +0 -20
- package/admin/src/components/ItemFooter/index.js +0 -87
- package/admin/src/components/ItemHeader/CardHeaderBlocked.js +0 -24
- package/admin/src/components/ItemHeader/CardHeaderIndicator.js +0 -30
- package/admin/src/components/ItemHeader/CardHeaderIndicatorBlue.js +0 -11
- package/admin/src/components/ItemHeader/CardHeaderIndicatorRed.js +0 -11
- package/admin/src/components/ItemHeader/CardHeaderIndicatorsContainer.js +0 -18
- package/admin/src/components/ItemHeader/CardHeaderPending.js +0 -11
- package/admin/src/components/ItemHeader/CardHeaderReports.js +0 -40
- package/admin/src/components/ItemHeader/Wrapper.js +0 -16
- package/admin/src/components/ItemHeader/index.js +0 -97
- package/admin/src/components/ItemModeration/Wrapper.js +0 -19
- package/admin/src/components/ItemModeration/index.js +0 -84
- package/admin/src/components/List/Container.js +0 -20
- package/admin/src/components/List/index.js +0 -21
- package/admin/src/components/Search/index.js +0 -83
- package/admin/src/containers/App/Wrapper.js +0 -14
- package/admin/src/containers/App/index.js +0 -47
- package/admin/src/containers/DataManagerProvider/actions.js +0 -15
- package/admin/src/containers/DataManagerProvider/index.js +0 -332
- package/admin/src/containers/DataManagerProvider/init.js +0 -5
- package/admin/src/containers/DataManagerProvider/reducer.js +0 -59
- package/admin/src/containers/DetailsView/Wrapper.js +0 -18
- package/admin/src/containers/DetailsView/index.js +0 -106
- package/admin/src/containers/ListView/FadedWrapper.js +0 -42
- package/admin/src/containers/ListView/Footer.js +0 -53
- package/admin/src/containers/ListView/Wrapper.js +0 -17
- package/admin/src/containers/ListView/components.js +0 -138
- package/admin/src/containers/ListView/index.js +0 -45
- package/admin/src/containers/Panel/actions.js +0 -5
- package/admin/src/containers/Panel/index.js +0 -191
- package/admin/src/containers/Panel/index.styled.js +0 -6
- package/admin/src/containers/Panel/reducer.js +0 -44
- package/admin/src/contexts/DataManagerContext.js +0 -5
- package/admin/src/hooks/useDataManager.js +0 -6
- package/admin/src/lifecycles.js +0 -3
- package/admin/src/translations/index.js +0 -7
- package/admin/src/utils/getTrad.js +0 -5
- package/admin/src/utils/getTradId.js +0 -5
- package/config/functions/bootstrap.js +0 -62
- package/config/routes.json +0 -142
- package/config/schema.graphql.js +0 -268
- package/controllers/comments.js +0 -228
- package/models/comment.js +0 -8
- package/models/comment.settings.json +0 -102
- package/models/report.js +0 -8
- package/models/report.settings.json +0 -49
- package/services/comments.js +0 -539
- package/services/utils/constants.js +0 -9
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Entity Details
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { useState, useEffect } from 'react';
|
|
8
|
+
import { useIntl } from 'react-intl';
|
|
9
|
+
import PropTypes from 'prop-types';
|
|
10
|
+
import { isEmpty } from 'lodash';
|
|
11
|
+
import { Badge } from '@strapi/design-system/Badge';
|
|
12
|
+
import { Button } from '@strapi/design-system/Button';
|
|
13
|
+
import { BaseCheckbox } from '@strapi/design-system/BaseCheckbox';
|
|
14
|
+
import { Flex } from '@strapi/design-system/Flex';
|
|
15
|
+
import { Table, Thead, Tbody, TFooter, Tr, Th, Td } from '@strapi/design-system/Table';
|
|
16
|
+
import { Typography } from '@strapi/design-system/Typography';
|
|
17
|
+
import { VisuallyHidden } from '@strapi/design-system/VisuallyHidden';
|
|
18
|
+
import { Check } from '@strapi/icons';
|
|
19
|
+
import { useOverlayBlocker } from '@strapi/helper-plugin';
|
|
20
|
+
import { getMessage } from '../../utils';
|
|
21
|
+
import { REPORT_REASON, REPORT_STATUS } from '../../utils/constants';
|
|
22
|
+
|
|
23
|
+
const ReportsReviewTable = ({
|
|
24
|
+
commentId,
|
|
25
|
+
items,
|
|
26
|
+
mutation,
|
|
27
|
+
onBlockButtonsStateChange,
|
|
28
|
+
}) => {
|
|
29
|
+
|
|
30
|
+
const [storedItems, setStoredItems] = useState([]);
|
|
31
|
+
|
|
32
|
+
const { formatDate } = useIntl();
|
|
33
|
+
|
|
34
|
+
const { lockApp } = useOverlayBlocker();
|
|
35
|
+
|
|
36
|
+
const renderStatus = resolved => {
|
|
37
|
+
const status = resolved ? REPORT_STATUS.RESOLVED : REPORT_STATUS.OPEN;
|
|
38
|
+
let color = 'alternative';
|
|
39
|
+
switch (status) {
|
|
40
|
+
case REPORT_STATUS.RESOLVED:
|
|
41
|
+
color = 'success';
|
|
42
|
+
break;
|
|
43
|
+
case REPORT_STATUS.OPEN:
|
|
44
|
+
color = 'danger';
|
|
45
|
+
};
|
|
46
|
+
return (<Badge backgroundColor={`${color}100`} textColor={`${color}600`}>{ getMessage(`page.details.panel.discussion.warnings.reports.dialog.status.${status}`, status) }</Badge>);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const renderReason = reason => {
|
|
50
|
+
let color = 'neutral';
|
|
51
|
+
switch (reason) {
|
|
52
|
+
case REPORT_REASON.DISCRIMINATION:
|
|
53
|
+
color = 'danger';
|
|
54
|
+
break;
|
|
55
|
+
case REPORT_REASON.BAD_LANGUAGE:
|
|
56
|
+
color = 'warning';
|
|
57
|
+
};
|
|
58
|
+
return (<Badge backgroundColor={`${color}100`} textColor={`${color}600`}>{ getMessage(`page.details.panel.discussion.warnings.reports.dialog.reason.${reason}`, reason) }</Badge>);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const handleClickResolve = async (reportId) => {
|
|
62
|
+
lockApp();
|
|
63
|
+
const item = await mutation.mutateAsync({
|
|
64
|
+
id: commentId,
|
|
65
|
+
reportId,
|
|
66
|
+
});
|
|
67
|
+
console.log(item);
|
|
68
|
+
if (item) {
|
|
69
|
+
const updatedItems = storedItems.map(_ => ({
|
|
70
|
+
..._,
|
|
71
|
+
resolved: reportId === _.id ? true : _.resolved,
|
|
72
|
+
}));
|
|
73
|
+
setStoredItems(updatedItems);
|
|
74
|
+
onBlockButtonsStateChange(updatedItems.filter(_ => !_.resolved).length === 0);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
setStoredItems(items);
|
|
80
|
+
}, []);
|
|
81
|
+
|
|
82
|
+
if (isEmpty(storedItems)) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const COL_COUNT = 6;
|
|
87
|
+
|
|
88
|
+
return (<Table colCount={COL_COUNT} rowCount={storedItems.length}>
|
|
89
|
+
<Thead>
|
|
90
|
+
<Tr>
|
|
91
|
+
<Th>
|
|
92
|
+
<BaseCheckbox aria-label="Select all entries" />
|
|
93
|
+
</Th>
|
|
94
|
+
<Th>
|
|
95
|
+
<Typography variant="sigma">{ getMessage('page.details.panel.discussion.warnings.reports.dialog.reason') }</Typography>
|
|
96
|
+
</Th>
|
|
97
|
+
<Th>
|
|
98
|
+
<Typography variant="sigma">{ getMessage('page.details.panel.discussion.warnings.reports.dialog.content') }</Typography>
|
|
99
|
+
</Th>
|
|
100
|
+
<Th>
|
|
101
|
+
<Typography variant="sigma">{ getMessage('page.details.panel.discussion.warnings.reports.dialog.createdAt') }</Typography>
|
|
102
|
+
</Th>
|
|
103
|
+
<Th>
|
|
104
|
+
<Typography variant="sigma">{ getMessage('page.details.panel.discussion.warnings.reports.dialog.status') }</Typography>
|
|
105
|
+
</Th>
|
|
106
|
+
<Th>
|
|
107
|
+
<VisuallyHidden>{ getMessage('page.details.panel.discussion.warnings.reports.dialog.actions') }</VisuallyHidden>
|
|
108
|
+
</Th>
|
|
109
|
+
</Tr>
|
|
110
|
+
</Thead>
|
|
111
|
+
<Tbody>
|
|
112
|
+
{storedItems.map(entry => <Tr key={entry.id}>
|
|
113
|
+
<Td>
|
|
114
|
+
<BaseCheckbox aria-label={`Select report`} />
|
|
115
|
+
</Td>
|
|
116
|
+
<Td>
|
|
117
|
+
<Typography textColor="neutral800">{renderReason(entry.reason)}</Typography>
|
|
118
|
+
</Td>
|
|
119
|
+
<Td>
|
|
120
|
+
<Typography textColor="neutral800">{entry.content}</Typography>
|
|
121
|
+
</Td>
|
|
122
|
+
<Td>
|
|
123
|
+
<Typography textColor="neutral800">{ formatDate(entry.createdAt, { dateStyle: 'short', timeStyle: 'short' }) }</Typography>
|
|
124
|
+
</Td>
|
|
125
|
+
<Td>
|
|
126
|
+
<Typography textColor="neutral800">{ renderStatus(entry.resolved) }</Typography>
|
|
127
|
+
</Td>
|
|
128
|
+
<Td>
|
|
129
|
+
{ !entry.resolved && (<Flex direction="column" alignItems="flex-end">
|
|
130
|
+
<Button onClick={() => handleClickResolve(entry.id)} startIcon={<Check />} variant="success">{ getMessage('page.details.panel.discussion.warnings.reports.dialog.actions.resolve', 'resolve') }</Button>
|
|
131
|
+
</Flex>) }
|
|
132
|
+
</Td>
|
|
133
|
+
</Tr>)}
|
|
134
|
+
</Tbody>
|
|
135
|
+
{/* <TFooter /> */}
|
|
136
|
+
</Table>)
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
ReportsReviewTable.propTypes = {
|
|
140
|
+
commentId: PropTypes.string.isRequired,
|
|
141
|
+
items: PropTypes.array.isRequired,
|
|
142
|
+
mutation: PropTypes.func.isRequired,
|
|
143
|
+
onBlockButtonsStateChange: PropTypes.func.isRequired,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export default ReportsReviewTable;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React, { useRef, useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Button } from '@strapi/design-system/Button';
|
|
4
|
+
import { Box } from '@strapi/design-system/Box';
|
|
5
|
+
import { Filter } from '@strapi/icons';
|
|
6
|
+
import { FilterListURLQuery, FilterPopoverURLQuery } from '@strapi/helper-plugin';
|
|
7
|
+
import { getMessage } from '../../utils';
|
|
8
|
+
|
|
9
|
+
const TableFilters = ({ displayedFilters }) => {
|
|
10
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
11
|
+
const buttonRef = useRef();
|
|
12
|
+
|
|
13
|
+
const handleToggle = () => {
|
|
14
|
+
setIsVisible(prev => !prev);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<>
|
|
19
|
+
<Box paddingTop={1} paddingBottom={1}>
|
|
20
|
+
<Button
|
|
21
|
+
variant="tertiary"
|
|
22
|
+
ref={buttonRef}
|
|
23
|
+
startIcon={<Filter />}
|
|
24
|
+
onClick={handleToggle}
|
|
25
|
+
size="S"
|
|
26
|
+
>
|
|
27
|
+
{getMessage('page.discover.table.filters')}
|
|
28
|
+
</Button>
|
|
29
|
+
{isVisible && (
|
|
30
|
+
<FilterPopoverURLQuery
|
|
31
|
+
displayedFilters={displayedFilters}
|
|
32
|
+
isVisible={isVisible}
|
|
33
|
+
onToggle={handleToggle}
|
|
34
|
+
source={buttonRef}
|
|
35
|
+
/>
|
|
36
|
+
)}
|
|
37
|
+
</Box>
|
|
38
|
+
<FilterListURLQuery filtersSchema={displayedFilters} />
|
|
39
|
+
</>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
TableFilters.propTypes = {
|
|
44
|
+
displayedFilters: PropTypes.arrayOf(
|
|
45
|
+
PropTypes.shape({
|
|
46
|
+
name: PropTypes.string.isRequired,
|
|
47
|
+
metadatas: PropTypes.shape({ label: PropTypes.string }),
|
|
48
|
+
fieldSchema: PropTypes.shape({ type: PropTypes.string }),
|
|
49
|
+
})
|
|
50
|
+
).isRequired,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default TableFilters;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Box } from '@strapi/design-system/Box';
|
|
4
|
+
import { Flex } from '@strapi/design-system/Flex';
|
|
5
|
+
import { PaginationURLQuery, PageSizeURLQuery } from '@strapi/helper-plugin';
|
|
6
|
+
|
|
7
|
+
const TablePagination = ({ pagination }) => {
|
|
8
|
+
return (
|
|
9
|
+
<Box paddingTop={4}>
|
|
10
|
+
<Flex alignItems="flex-end" justifyContent="space-between">
|
|
11
|
+
<PageSizeURLQuery trackedEvent="willChangeNumberOfEntriesPerPage" />
|
|
12
|
+
<PaginationURLQuery pagination={pagination} />
|
|
13
|
+
</Flex>
|
|
14
|
+
</Box>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
TablePagination.defaultProps = {
|
|
19
|
+
pagination: {
|
|
20
|
+
pageCount: 0,
|
|
21
|
+
pageSize: 10,
|
|
22
|
+
total: 0,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
TablePagination.propTypes = {
|
|
27
|
+
pagination: PropTypes.shape({
|
|
28
|
+
page: PropTypes.number,
|
|
29
|
+
pageCount: PropTypes.number,
|
|
30
|
+
pageSize: PropTypes.number,
|
|
31
|
+
total: PropTypes.number,
|
|
32
|
+
}),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export default TablePagination;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
const initSize = 576;
|
|
5
|
+
|
|
6
|
+
const CommentsIcon = ({ width = 24, height = 24 }) =>
|
|
7
|
+
<svg viewBox={`0 0 ${width} ${height}`} xmlns="http://www.w3.org/2000/svg"><g style={ {transform: `scale(${width/initSize})` } }><path d="M416 192c0-88.4-93.1-160-208-160S0 103.6 0 192c0 34.3 14.1 65.9 38 92-13.4 30.2-35.5 54.2-35.8 54.5-2.2 2.3-2.8 5.7-1.5 8.7S4.8 352 8 352c36.6 0 66.9-12.3 88.7-25 32.2 15.7 70.3 25 111.3 25 114.9 0 208-71.6 208-160zm122 220c23.9-26 38-57.7 38-92 0-66.9-53.5-124.2-129.3-148.1.9 6.6 1.3 13.3 1.3 20.1 0 105.9-107.7 192-240 192-10.8 0-21.3-.8-31.7-1.9C207.8 439.6 281.8 480 368 480c41 0 79.1-9.2 111.3-25 21.8 12.7 52.1 25 88.7 25 3.2 0 6.1-1.9 7.3-4.8 1.3-2.9.7-6.3-1.5-8.7-.3-.3-22.4-24.2-35.8-54.5z"/></g></svg>;
|
|
8
|
+
|
|
9
|
+
export default CommentsIcon;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
const initSize = 330;
|
|
5
|
+
|
|
6
|
+
const LockIcon = ({ width, height, size = 16 }) =>
|
|
7
|
+
<svg
|
|
8
|
+
width={width || size}
|
|
9
|
+
height={height || size}
|
|
10
|
+
viewBox={`0 0 ${width || size} ${height || size}`}
|
|
11
|
+
style={{ width: `${width || size}px`, height: `${height || size}px`, }}
|
|
12
|
+
xmlns="http://www.w3.org/2000/svg">
|
|
13
|
+
<g style={ { transform: `scale(${(width || size)/initSize})` } }>
|
|
14
|
+
<path d="M165,330c63.411,0,115-51.589,115-115c0-29.771-11.373-56.936-30-77.379V85c0-46.869-38.131-85-85-85
|
|
15
|
+
S80.001,38.131,80.001,85v52.619C61.373,158.064,50,185.229,50,215C50,278.411,101.589,330,165,330z M180,219.986V240
|
|
16
|
+
c0,8.284-6.716,15-15,15s-15-6.716-15-15v-20.014c-6.068-4.565-10-11.824-10-19.986c0-13.785,11.215-25,25-25s25,11.215,25,25
|
|
17
|
+
C190,208.162,186.068,215.421,180,219.986z M110.001,85c0-30.327,24.673-55,54.999-55c30.327,0,55,24.673,55,55v29.029
|
|
18
|
+
C203.652,105.088,184.91,100,165,100c-19.909,0-38.651,5.088-54.999,14.028V85z"/>
|
|
19
|
+
</g>
|
|
20
|
+
</svg>
|
|
21
|
+
|
|
22
|
+
export default LockIcon;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
const initSize = 24;
|
|
5
|
+
|
|
6
|
+
const ReviewIcon = ({ width, height, size = 16 }) =>
|
|
7
|
+
<svg
|
|
8
|
+
width={width || size}
|
|
9
|
+
height={height || size}
|
|
10
|
+
viewBox={`0 0 ${width || size} ${height || size}`}
|
|
11
|
+
style={{ width: `${width || size}px`, height: `${height || size}px`, }}
|
|
12
|
+
xmlns="http://www.w3.org/2000/svg">
|
|
13
|
+
<g style={ {transform: `scale(${(width || size)/initSize})` } }>
|
|
14
|
+
<path strokeWidth="1" d="M5.5,21 C7.98528137,21 10,18.9852814 10,16.5 C10,14.0147186 7.98528137,12 5.5,12 C3.01471863,12 1,14.0147186 1,16.5 C1,18.9852814 3.01471863,21 5.5,21 Z M1,16 L1,7 L1,6.5 C1,4.01471863 3.01471863,2 5.5,2 L6,2 M23,16 L23,7 L23,6.5 C23,4.01471863 20.9852814,2 18.5,2 L18,2 M18.5,21 C20.9852814,21 23,18.9852814 23,16.5 C23,14.0147186 20.9852814,12 18.5,12 C16.0147186,12 14,14.0147186 14,16.5 C14,18.9852814 16.0147186,21 18.5,21 Z M10,17 C10,17 10,15 12,15 C14,15 14,17 14,17"/>
|
|
15
|
+
</g>
|
|
16
|
+
</svg>
|
|
17
|
+
|
|
18
|
+
export default ReviewIcon;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
const initSize = 330;
|
|
5
|
+
|
|
6
|
+
const UnlockIcon = ({ width, height, size = 16 }) =>
|
|
7
|
+
<svg
|
|
8
|
+
width={width || size}
|
|
9
|
+
height={height || size}
|
|
10
|
+
viewBox={`0 0 ${width || size} ${height || size}`}
|
|
11
|
+
style={{ width: `${width || size}px`, height: `${height || size}px`, }}
|
|
12
|
+
xmlns="http://www.w3.org/2000/svg">
|
|
13
|
+
<g style={ { transform: `scale(${(width || size)/initSize})` } }>
|
|
14
|
+
<path d="M15,160c8.283,0,15-6.716,15-15V85c0-30.327,24.672-55,55-55c30.326,0,55,24.673,55,55v42.893
|
|
15
|
+
c-24.479,21.105-40,52.327-40,87.107c0,63.411,51.588,115,115,115c63.41,0,115-51.589,115-115s-51.59-115-115-115
|
|
16
|
+
c-15.961,0-31.172,3.271-45,9.174V85c0-46.869-38.131-85-85-85S0,38.131,0,85v60C0,153.284,6.715,160,15,160z"/>
|
|
17
|
+
</g>
|
|
18
|
+
</svg>
|
|
19
|
+
|
|
20
|
+
export default UnlockIcon;
|
package/admin/src/index.js
CHANGED
|
@@ -1,49 +1,65 @@
|
|
|
1
|
+
import { prefixPluginTranslations } from '@strapi/helper-plugin';
|
|
1
2
|
import pluginPkg from '../../package.json';
|
|
2
3
|
import pluginId from './pluginId';
|
|
4
|
+
import Initializer from './components/Initializer';
|
|
5
|
+
import PluginIcon from './components/PluginIcon';
|
|
3
6
|
import pluginPermissions from './permissions';
|
|
4
|
-
import
|
|
5
|
-
import App from './containers/App';
|
|
6
|
-
import Initializer from './containers/Initializer';
|
|
7
|
-
import lifecycles from './lifecycles';
|
|
8
|
-
import trads from './translations';
|
|
7
|
+
import reducers from './reducers';
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
const pluginDescription = pluginPkg.strapi.description || pluginPkg.description;
|
|
9
|
+
const name = pluginPkg.strapi.name;
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
layout: null,
|
|
26
|
-
lifecycles,
|
|
27
|
-
mainComponent: App,
|
|
28
|
-
name,
|
|
29
|
-
pluginLogo,
|
|
30
|
-
preventComponentRendering: false,
|
|
31
|
-
trads,
|
|
32
|
-
menu: {
|
|
33
|
-
pluginsSectionLinks: [
|
|
34
|
-
{
|
|
35
|
-
destination: `/plugins/${pluginId}`,
|
|
36
|
-
icon,
|
|
37
|
-
name,
|
|
38
|
-
label: {
|
|
39
|
-
id: `${pluginId}.plugin.name`,
|
|
40
|
-
defaultMessage: 'COMMENTS',
|
|
41
|
-
},
|
|
42
|
-
permissions: pluginPermissions.main,
|
|
43
|
-
},
|
|
44
|
-
],
|
|
45
|
-
},
|
|
46
|
-
};
|
|
11
|
+
export default {
|
|
12
|
+
register(app) {
|
|
13
|
+
app.addMenuLink({
|
|
14
|
+
to: `/plugins/${pluginId}/discover`,
|
|
15
|
+
badgeContent: 1,
|
|
16
|
+
icon: PluginIcon,
|
|
17
|
+
intlLabel: {
|
|
18
|
+
id: `${pluginId}.plugin.name`,
|
|
19
|
+
defaultMessage: name,
|
|
20
|
+
},
|
|
21
|
+
Component: async () => {
|
|
22
|
+
const component = await import(/* webpackChunkName: "[request]" */ './pages/App');
|
|
47
23
|
|
|
48
|
-
|
|
24
|
+
return component;
|
|
25
|
+
},
|
|
26
|
+
permissions: pluginPermissions,
|
|
27
|
+
});
|
|
28
|
+
app.addReducers(reducers);
|
|
29
|
+
app.registerPlugin({
|
|
30
|
+
id: pluginId,
|
|
31
|
+
initializer: Initializer,
|
|
32
|
+
isReady: false,
|
|
33
|
+
name,
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
bootstrap(app) {
|
|
38
|
+
// app.injectContentManagerComponent('editView', 'informations', {
|
|
39
|
+
// name: 'comments-link',
|
|
40
|
+
// Component: () => 'TODO: Comments count',
|
|
41
|
+
// });
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
async registerTrads({ locales }) {
|
|
45
|
+
const importedTrads = await Promise.all(
|
|
46
|
+
locales.map(locale => {
|
|
47
|
+
return import(`./translations/${locale}.json`)
|
|
48
|
+
.then(({ default: data }) => {
|
|
49
|
+
return {
|
|
50
|
+
data: prefixPluginTranslations(data, pluginId),
|
|
51
|
+
locale,
|
|
52
|
+
};
|
|
53
|
+
})
|
|
54
|
+
.catch(() => {
|
|
55
|
+
return {
|
|
56
|
+
data: {},
|
|
57
|
+
locale,
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
})
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return Promise.resolve(importedTrads);
|
|
64
|
+
},
|
|
49
65
|
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* This component is the skeleton around the actual pages, and should only
|
|
4
|
+
* contain code that should be seen on all pages. (e.g. navigation bar)
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from 'react';
|
|
9
|
+
import { connect } from 'react-redux';
|
|
10
|
+
import { bindActionCreators, compose } from 'redux';
|
|
11
|
+
import { Switch, Route } from 'react-router-dom';
|
|
12
|
+
import { useQuery } from 'react-query';
|
|
13
|
+
import {
|
|
14
|
+
NotFound,
|
|
15
|
+
LoadingIndicatorPage,
|
|
16
|
+
useNotification } from '@strapi/helper-plugin';
|
|
17
|
+
|
|
18
|
+
import ComingSoonPage from '../ComingSoonPage';
|
|
19
|
+
import getUrl from '../../utils/getUrl';
|
|
20
|
+
import Discover from '../Discover';
|
|
21
|
+
import Details from '../Details';
|
|
22
|
+
import { fetchConfig } from './utils/api';
|
|
23
|
+
import { setConfig } from './reducer/actions';
|
|
24
|
+
import makeAppView from './reducer/selectors';
|
|
25
|
+
|
|
26
|
+
const App = ({ setConfig }) => {
|
|
27
|
+
|
|
28
|
+
const toggleNotification = useNotification();
|
|
29
|
+
|
|
30
|
+
const { isLoading, isFetching } = useQuery(
|
|
31
|
+
'get-config', () => fetchConfig(toggleNotification),
|
|
32
|
+
{
|
|
33
|
+
initialData: { },
|
|
34
|
+
onSuccess: (response) => {
|
|
35
|
+
setConfig(response);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if (isLoading || isFetching) {
|
|
41
|
+
return (<LoadingIndicatorPage />)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div>
|
|
46
|
+
<Switch>
|
|
47
|
+
<Route path={ getUrl('dashboard') } component={ComingSoonPage} exact />
|
|
48
|
+
<Route path={ getUrl('discover') } component={Discover} exact />
|
|
49
|
+
<Route path={ getUrl('discover/:id') } component={Details} exact />
|
|
50
|
+
<Route path={ getUrl('reports') } component={ComingSoonPage} exact />
|
|
51
|
+
<Route path={ getUrl('settings') } component={ComingSoonPage} exact />
|
|
52
|
+
<Route component={NotFound} />
|
|
53
|
+
</Switch>
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const mapStateToProps = makeAppView();
|
|
59
|
+
|
|
60
|
+
export function mapDispatchToProps(dispatch) {
|
|
61
|
+
return bindActionCreators(
|
|
62
|
+
{ setConfig },
|
|
63
|
+
dispatch
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
const withConnect = connect(
|
|
67
|
+
mapStateToProps,
|
|
68
|
+
mapDispatchToProps
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
export default compose(withConnect)(App);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import produce from 'immer'; // current
|
|
2
|
+
import { set } from 'lodash';
|
|
3
|
+
import { GET_CONFIG, SET_CONFIG } from './constants';
|
|
4
|
+
|
|
5
|
+
const initialState = {
|
|
6
|
+
config: {},
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const reducer = (state = initialState, action) =>
|
|
10
|
+
// eslint-disable-next-line consistent-return
|
|
11
|
+
produce(state, draftState => {
|
|
12
|
+
switch (action.type) {
|
|
13
|
+
case SET_CONFIG: {
|
|
14
|
+
set(draftState, 'config', action.data);
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
case GET_CONFIG: {
|
|
18
|
+
return draftState?.config;
|
|
19
|
+
}
|
|
20
|
+
default:
|
|
21
|
+
return draftState;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export default reducer;
|
|
26
|
+
export { initialState };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import { createSelector } from 'reselect';
|
|
4
|
+
import { initialState } from './';
|
|
5
|
+
import { REDUCER_NAME } from './constants';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Direct selector to the listView state domain
|
|
9
|
+
*/
|
|
10
|
+
const appView = () => state => state[REDUCER_NAME] || initialState;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Other specific selectors
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Default selector used by listView
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const makeAppView = () =>
|
|
21
|
+
createSelector(
|
|
22
|
+
appView(),
|
|
23
|
+
substate => {
|
|
24
|
+
return substate;
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const selectConfig = state => {
|
|
29
|
+
const { config } = state;
|
|
30
|
+
|
|
31
|
+
return config;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default makeAppView;
|
|
35
|
+
export { appView, selectConfig };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { getApiURL, axiosInstance, handleAPIError } from '../../../utils';
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line import/prefer-default-export
|
|
4
|
+
export const fetchConfig = async (toggleNotification) => {
|
|
5
|
+
try {
|
|
6
|
+
const { data } = await axiosInstance.get(getApiURL(`moderate/config`));
|
|
7
|
+
|
|
8
|
+
return data;
|
|
9
|
+
} catch (err) {
|
|
10
|
+
handleAPIError(err, toggleNotification);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*
|
|
2
|
+
*
|
|
3
|
+
* Coming soon page
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { memo } from 'react';
|
|
8
|
+
import { Box } from '@strapi/design-system/Box';
|
|
9
|
+
import { EmptyStateLayout } from '@strapi/design-system/EmptyStateLayout';
|
|
10
|
+
import { Layout } from '@strapi/design-system/Layout';
|
|
11
|
+
import { Illo } from '@strapi/icons';
|
|
12
|
+
import getMessage from '../../utils/getMessage';
|
|
13
|
+
import Nav from '../../components/Nav';
|
|
14
|
+
|
|
15
|
+
const ComingSoonPage = () => {
|
|
16
|
+
return (<Box background="neutral100">
|
|
17
|
+
<Layout sideNav={<Nav />}>
|
|
18
|
+
<Box padding={8} background="neutral100">
|
|
19
|
+
<EmptyStateLayout icon={<Illo />} content={getMessage('page.coming.soon')} />
|
|
20
|
+
</Box>
|
|
21
|
+
</Layout>
|
|
22
|
+
</Box>);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default memo(ComingSoonPage);
|