diff --git a/app/soapbox/actions/admin.js b/app/soapbox/actions/admin.js index 3592b20bc..84ec80362 100644 --- a/app/soapbox/actions/admin.js +++ b/app/soapbox/actions/admin.js @@ -12,6 +12,10 @@ export const ADMIN_REPORTS_FETCH_REQUEST = 'ADMIN_REPORTS_FETCH_REQUEST'; export const ADMIN_REPORTS_FETCH_SUCCESS = 'ADMIN_REPORTS_FETCH_SUCCESS'; export const ADMIN_REPORTS_FETCH_FAIL = 'ADMIN_REPORTS_FETCH_FAIL'; +export const ADMIN_REPORTS_PATCH_REQUEST = 'ADMIN_REPORTS_PATCH_REQUEST'; +export const ADMIN_REPORTS_PATCH_SUCCESS = 'ADMIN_REPORTS_PATCH_SUCCESS'; +export const ADMIN_REPORTS_PATCH_FAIL = 'ADMIN_REPORTS_PATCH_FAIL'; + export const ADMIN_USERS_FETCH_REQUEST = 'ADMIN_USERS_FETCH_REQUEST'; export const ADMIN_USERS_FETCH_SUCCESS = 'ADMIN_USERS_FETCH_SUCCESS'; export const ADMIN_USERS_FETCH_FAIL = 'ADMIN_USERS_FETCH_FAIL'; @@ -67,6 +71,23 @@ export function fetchReports(params) { }; } +function patchReports(ids, state) { + const reports = ids.map(id => ({ id, state })); + return (dispatch, getState) => { + dispatch({ type: ADMIN_REPORTS_PATCH_REQUEST, reports }); + return api(getState) + .patch('/api/pleroma/admin/reports', { reports }) + .then(() => { + dispatch({ type: ADMIN_REPORTS_PATCH_SUCCESS, reports }); + }).catch(error => { + dispatch({ type: ADMIN_REPORTS_PATCH_FAIL, error, reports }); + }); + }; +} +export function closeReports(ids) { + return patchReports(ids, 'closed'); +} + export function fetchUsers(params) { return (dispatch, getState) => { dispatch({ type: ADMIN_USERS_FETCH_REQUEST, params }); diff --git a/app/soapbox/features/admin/components/report.js b/app/soapbox/features/admin/components/report.js index d0161f441..6b6fa2098 100644 --- a/app/soapbox/features/admin/components/report.js +++ b/app/soapbox/features/admin/components/report.js @@ -4,13 +4,15 @@ import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { injectIntl, FormattedMessage, defineMessages } from 'react-intl'; import Avatar from 'soapbox/components/avatar'; +import Button from 'soapbox/components/button'; import DropdownMenu from 'soapbox/containers/dropdown_menu_container'; -import { deactivateUsers } from 'soapbox/actions/admin'; +import { deactivateUsers, closeReports } from 'soapbox/actions/admin'; import snackbar from 'soapbox/actions/snackbar'; const messages = defineMessages({ deactivateUser: { id: 'admin.reports.actions.deactivate_user', defaultMessage: 'Deactivate {acct}' }, - deactivated: { id: 'admin.reports.deactivated_message', defaultMessage: '{acct} was deactivated' }, + userDeactivated: { id: 'admin.reports.user_deactivated_message', defaultMessage: '{acct} was deactivated' }, + reportClosed: { id: 'admin.reports.report_closed_message', defaultMessage: 'Report on {acct} was closed' }, }); export default @connect() @@ -30,11 +32,20 @@ class Report extends ImmutablePureComponent { }]; } + handleCloseReport = () => { + const { intl, dispatch, report } = this.props; + const nickname = report.getIn(['account', 'acct']); + dispatch(closeReports([report.get('id')])).then(() => { + const message = intl.formatMessage(messages.reportClosed, { acct: `@${nickname}` }); + dispatch(snackbar.success(message)); + }).catch(() => {}); + } + handleDeactivateUser = () => { const { intl, dispatch, report } = this.props; const nickname = report.getIn(['account', 'acct']); dispatch(deactivateUsers([nickname])).then(() => { - const message = intl.formatMessage(messages.deactivated, { acct: nickname }); + const message = intl.formatMessage(messages.userDeactivated, { acct: `@${nickname}` }); dispatch(snackbar.success(message)); }).catch(() => {}); } @@ -62,6 +73,9 @@ class Report extends ImmutablePureComponent {
+
diff --git a/app/soapbox/reducers/admin.js b/app/soapbox/reducers/admin.js index bdcdcd9ec..36e5f77fe 100644 --- a/app/soapbox/reducers/admin.js +++ b/app/soapbox/reducers/admin.js @@ -1,6 +1,8 @@ import { ADMIN_CONFIG_FETCH_SUCCESS, ADMIN_REPORTS_FETCH_SUCCESS, + ADMIN_REPORTS_PATCH_REQUEST, + ADMIN_REPORTS_PATCH_SUCCESS, ADMIN_USERS_FETCH_SUCCESS, ADMIN_USERS_DELETE_REQUEST, ADMIN_USERS_DELETE_SUCCESS, @@ -63,12 +65,31 @@ function importReports(state, reports) { }); } +function handleReportDiffs(state, reports) { + // Note: the reports here aren't full report objects + // hence the need for a new function. + return state.withMutations(state => { + reports.forEach(report => { + switch(report.state) { + case 'open': + state.update('openReports', orderedSet => orderedSet.add(report.id)); + break; + default: + state.update('openReports', orderedSet => orderedSet.delete(report.id)); + } + }); + }); +} + export default function admin(state = initialState, action) { switch(action.type) { case ADMIN_CONFIG_FETCH_SUCCESS: return state.set('configs', fromJS(action.configs)); case ADMIN_REPORTS_FETCH_SUCCESS: return importReports(state, action.reports); + case ADMIN_REPORTS_PATCH_REQUEST: + case ADMIN_REPORTS_PATCH_SUCCESS: + return handleReportDiffs(state, action.reports); case ADMIN_USERS_FETCH_SUCCESS: return importUsers(state, action.data.users); case ADMIN_USERS_DELETE_REQUEST: diff --git a/app/styles/components/admin.scss b/app/styles/components/admin.scss index a46265c67..7899634c4 100644 --- a/app/styles/components/admin.scss +++ b/app/styles/components/admin.scss @@ -143,5 +143,16 @@ &__actions { margin-left: auto; + display: flex; + + .icon-button { + padding-left: 10px; + + > div { + display: flex; + align-items: center; + justify-content: center; + } + } } }