Add ability to ban users for limited time and to view in the 'Show blocked' (#140)

closes #88
This commit is contained in:
Jack & Burger
2018-07-09 16:58:08 +04:00
committed by Aleksei Gurianov
parent ce8c2c236f
commit 4cea9d5855
9 changed files with 110 additions and 10 deletions
+2 -2
View File
@@ -100,9 +100,9 @@ export const removeComment = ({ id }) =>
withCredentials: true,
});
export const blockUser = ({ id }) =>
export const blockUser = ({ id, ttl }) =>
fetcher.put({
url: `/admin/user/${id}?block=1`,
url: ttl === 'permanently' ? `/admin/user/${id}?block=1` : `/admin/user/${id}?block=1&ttl=${ttl}`,
withCredentials: true,
});
+20
View File
@@ -18,6 +18,25 @@ const PROVIDER_NAMES = {
const LS_COLLAPSE_KEY = '__remarkCollapsed';
const LS_SORT_KEY = '__remarkSort';
const BLOCKING_DURATIONS = [
{
label: 'Permanently',
value: 'permanently',
},
{
label: 'For a month',
value: `${30 * 60 * 24}m`,
},
{
label: 'For a week',
value: `${7 * 60 * 24}m`,
},
{
label: 'For a day',
value: `${60 * 24}m`,
},
];
module.exports = {
BASE_URL,
API_BASE,
@@ -32,4 +51,5 @@ module.exports = {
DEFAULT_SORT,
LS_COLLAPSE_KEY,
LS_SORT_KEY,
BLOCKING_DURATIONS,
};
@@ -0,0 +1,3 @@
.blocked-users__user-id {
color: #888;
}
@@ -51,6 +51,7 @@ export default class BlockedUsers extends Component {
<li className={b('blocked-users__list-item', {}, { view: isUserUnblocked ? 'invisible' : null })}>
<span className="blocked-users__username">{user.name}</span>{' '}
<span className="blocked-users__user-id">({user.id})</span>
<span className="blocked-users__user-block-ttl"> until {formatTime(new Date(user.time))}</span>
{isUserUnblocked && (
<span {...getHandleClickProps(() => this.block(user))} className="blocked-users__action">
block
@@ -70,3 +71,14 @@ export default class BlockedUsers extends Component {
);
}
}
function formatTime(time) {
// 'ru-RU' adds a dot as a separator
const date = time.toLocaleDateString(['ru-RU'], { day: '2-digit', month: '2-digit', year: '2-digit' });
// do it manually because Intl API doesn't add leading zeros to hours; idk why
const hours = `0${time.getHours()}`.slice(-2);
const mins = `0${time.getMinutes()}`.slice(-2);
return `${date} at ${hours}:${mins}`;
}
@@ -6,6 +6,7 @@ require('./__action/blocked-users__action.scss');
require('./__list/blocked-users__list.scss');
require('./__list-item/blocked-users__list-item.scss');
require('./__user-block-ttl/blocked-users__user-block-ttl.scss');
require('./__list-item/_view/_invisible/blocked-users__list-item_view_invisible.scss');
require('./__user-id/blocked-users__user-id.scss');
@@ -0,0 +1,10 @@
.comment__control_select {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
opacity: 0;
width: 100%;
cursor: pointer;
}
@@ -0,0 +1,9 @@
.comment__control_select-label {
position: relative;
white-space: nowrap;
font-weight: 700;
&::after {
content: '';
margin-left: 2px;
}
}
+51 -8
View File
@@ -3,7 +3,7 @@ import { h, Component } from 'preact';
import api from 'common/api';
import { getHandleClickProps } from 'common/accessibility';
import { API_BASE, BASE_URL, COMMENT_NODE_CLASSNAME_PREFIX } from 'common/constants';
import { API_BASE, BASE_URL, COMMENT_NODE_CLASSNAME_PREFIX, BLOCKING_DURATIONS } from 'common/constants';
import { url } from 'common/settings';
import store from 'common/store';
@@ -37,6 +37,8 @@ export default class Comment extends Component {
this.onEdit = this.onEdit.bind(this);
this.onReply = this.onReply.bind(this);
this.onDeleteClick = this.onDeleteClick.bind(this);
this.onBlockUserClick = this.onBlockUserClick.bind(this);
this.onUnblockUserClick = this.onUnblockUserClick.bind(this);
}
componentWillReceiveProps(nextProps) {
@@ -164,17 +166,41 @@ export default class Comment extends Component {
}
}
toggleBlock(isBlocked) {
onBlockUserClick(e) {
const {
id,
user: { id: userId },
} = this.props.data;
const promptMessage = `Do you want to ${isBlocked ? 'unblock' : 'block'} this user?`;
const ttl = e.target.value;
const duration = BLOCKING_DURATIONS.find(el => el.value === ttl).label;
const promptMessage =
ttl === 'permanently'
? 'Do you want to permanently block this user?'
: `Do you want to block this user (${duration.toLowerCase()})?`;
if (confirm(promptMessage)) {
this.setState({ userBlocked: true });
api
.blockUser({ id: userId, ttl })
.then(api.getComment({ id }))
.then(comment => store.replaceComment(comment));
}
}
onUnblockUserClick() {
const {
id,
user: { id: userId },
} = this.props.data;
const promptMessage = `Do you want to unblock this user?`;
if (confirm(promptMessage)) {
this.setState({ userBlocked: !isBlocked });
this.setState({ userBlocked: false });
(isBlocked ? api.unblockUser : api.blockUser)({ id: userId })
api
.unblockUser({ id: userId })
.then(api.getComment({ id }))
.then(comment => store.replaceComment(comment));
}
@@ -501,9 +527,26 @@ export default class Comment extends Component {
<span {...getHandleClickProps(() => this.togglePin(pinned))} className="comment__control">
{pinned ? 'Unpin' : 'Pin'}
</span>
<span {...getHandleClickProps(() => this.toggleBlock(userBlocked))} className="comment__control">
{userBlocked ? 'Unblock' : 'Block'}
</span>
{userBlocked && (
<span {...getHandleClickProps(() => this.onUnblockUserClick())} className="comment__control">
Unblock
</span>
)}
{!userBlocked && (
<span className="comment__control comment__control_select-label">
Block
{/* eslint-disable jsx-a11y/no-onchange */}
<select className="comment__control_select" onChange={this.onBlockUserClick}>
<option disabled selected value>
{' '}
Blocking period{' '}
</option>
{BLOCKING_DURATIONS.map(block => <option value={block.value}>{block.label}</option>)}
</select>
</span>
)}
{!deleted && (
<span {...getHandleClickProps(this.onDeleteClick)} className="comment__control">
+2
View File
@@ -13,6 +13,8 @@ require('./__avatar/_default/comment__avatar_default.scss');
require('./__body/comment__body.scss');
require('./__control/comment__control.scss');
require('./__control/_select/comment__control_select.scss');
require('./__control/_select-label/comment__control_select-label.scss');
require('./__controls/comment__controls.scss');
require('./__info/comment__info.scss');
require('./__input/comment__input.scss');