[Glitch] Add notifications for statuses deleted by moderators

Port front-end changes from 2fb76550a9 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
lolsob-rspec
Eugen Rochko 2022-01-17 09:41:33 +01:00 committed by Claire
parent 485cf5c0c1
commit a5cb48879d
4 changed files with 488 additions and 16 deletions

View File

@ -0,0 +1,159 @@
import React from 'react';
import PropTypes from 'prop-types';
import api from 'flavours/glitch/util/api';
import { injectIntl, defineMessages } from 'react-intl';
import classNames from 'classnames';
const messages = defineMessages({
other: { id: 'report.categories.other', defaultMessage: 'Other' },
spam: { id: 'report.categories.spam', defaultMessage: 'Spam' },
violation: { id: 'report.categories.violation', defaultMessage: 'Content violates one or more server rules' },
});
class Category extends React.PureComponent {
static propTypes = {
id: PropTypes.string.isRequired,
text: PropTypes.string.isRequired,
selected: PropTypes.bool,
disabled: PropTypes.bool,
onSelect: PropTypes.func,
children: PropTypes.node,
};
handleClick = () => {
const { id, disabled, onSelect } = this.props;
if (!disabled) {
onSelect(id);
}
};
render () {
const { id, text, disabled, selected, children } = this.props;
return (
<div tabIndex='0' role='button' className={classNames('report-reason-selector__category', { selected, disabled })} onClick={this.handleClick}>
{selected && <input type='hidden' name='report[category]' value={id} />}
<div className='report-reason-selector__category__label'>
<span className={classNames('poll__input', { active: selected, disabled })} />
{text}
</div>
{(selected && children) && (
<div className='report-reason-selector__category__rules'>
{children}
</div>
)}
</div>
);
}
}
class Rule extends React.PureComponent {
static propTypes = {
id: PropTypes.string.isRequired,
text: PropTypes.string.isRequired,
selected: PropTypes.bool,
disabled: PropTypes.bool,
onToggle: PropTypes.func,
};
handleClick = () => {
const { id, disabled, onToggle } = this.props;
if (!disabled) {
onToggle(id);
}
};
render () {
const { id, text, disabled, selected } = this.props;
return (
<div tabIndex='0' role='button' className={classNames('report-reason-selector__rule', { selected, disabled })} onClick={this.handleClick}>
<span className={classNames('poll__input', { checkbox: true, active: selected, disabled })} />
{selected && <input type='hidden' name='report[rule_ids][]' value={id} />}
{text}
</div>
);
}
}
export default @injectIntl
class ReportReasonSelector extends React.PureComponent {
static propTypes = {
id: PropTypes.string.isRequired,
category: PropTypes.string.isRequired,
rule_ids: PropTypes.arrayOf(PropTypes.string),
disabled: PropTypes.bool,
intl: PropTypes.object.isRequired,
};
state = {
category: this.props.category,
rule_ids: this.props.rule_ids || [],
rules: [],
};
componentDidMount() {
api().get('/api/v1/instance').then(res => {
this.setState({
rules: res.data.rules,
});
}).catch(err => {
console.error(err);
});
}
_save = () => {
const { id, disabled } = this.props;
const { category, rule_ids } = this.state;
if (disabled) {
return;
}
api().put(`/api/v1/admin/reports/${id}`, {
category,
rule_ids,
}).catch(err => {
console.error(err);
});
};
handleSelect = id => {
this.setState({ category: id }, () => this._save());
};
handleToggle = id => {
const { rule_ids } = this.state;
if (rule_ids.includes(id)) {
this.setState({ rule_ids: rule_ids.filter(x => x !== id ) }, () => this._save());
} else {
this.setState({ rule_ids: [...rule_ids, id] }, () => this._save());
}
};
render () {
const { disabled, intl } = this.props;
const { rules, category, rule_ids } = this.state;
return (
<div className='report-reason-selector'>
<Category id='other' text={intl.formatMessage(messages.other)} selected={category === 'other'} onSelect={this.handleSelect} disabled={disabled} />
<Category id='spam' text={intl.formatMessage(messages.spam)} selected={category === 'spam'} onSelect={this.handleSelect} disabled={disabled} />
<Category id='violation' text={intl.formatMessage(messages.violation)} selected={category === 'violation'} onSelect={this.handleSelect} disabled={disabled}>
{rules.map(rule => <Rule key={rule.id} id={rule.id} text={rule.text} selected={rule_ids.includes(rule.id)} onToggle={this.handleToggle} disabled={disabled} />)}
</Category>
</div>
);
}
}

View File

@ -595,39 +595,44 @@ body,
.log-entry {
line-height: 20px;
padding: 15px 0;
padding: 15px;
padding-left: 15px * 2 + 40px;
background: $ui-base-color;
border-bottom: 1px solid lighten($ui-base-color, 4%);
border-bottom: 1px solid darken($ui-base-color, 8%);
position: relative;
&:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
&:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom: 0;
}
&:hover {
background: lighten($ui-base-color, 4%);
}
&__header {
display: flex;
justify-content: flex-start;
align-items: center;
color: $darker-text-color;
font-size: 14px;
padding: 0 10px;
}
&__avatar {
margin-right: 10px;
position: absolute;
left: 15px;
top: 15px;
.avatar {
display: block;
margin: 0;
border-radius: 50%;
border-radius: 4px;
width: 40px;
height: 40px;
}
}
&__content {
max-width: calc(100% - 90px);
}
&__title {
word-wrap: break-word;
}
@ -643,6 +648,14 @@ body,
text-decoration: none;
font-weight: 500;
}
a {
&:hover,
&:focus,
&:active {
text-decoration: underline;
}
}
}
a.name-tag,
@ -671,8 +684,9 @@ a.inline-name-tag,
a.name-tag,
.name-tag {
display: flex;
display: inline-flex;
align-items: center;
vertical-align: top;
.avatar {
display: block;
@ -1130,3 +1144,287 @@ a.sparkline {
}
}
}
.report-reason-selector {
border-radius: 4px;
background: $ui-base-color;
margin-bottom: 20px;
&__category {
cursor: pointer;
border-bottom: 1px solid darken($ui-base-color, 8%);
&:last-child {
border-bottom: 0;
}
&__label {
padding: 15px;
}
&__rules {
margin-left: 30px;
}
}
&__rule {
cursor: pointer;
padding: 15px;
}
}
.report-header {
display: grid;
grid-gap: 15px;
grid-template-columns: minmax(0, 1fr) 300px;
&__details {
&__item {
border-bottom: 1px solid lighten($ui-base-color, 8%);
padding: 15px 0;
&:last-child {
border-bottom: 0;
}
&__header {
font-weight: 600;
padding: 4px 0;
}
}
&--horizontal {
display: grid;
grid-auto-columns: minmax(0, 1fr);
grid-auto-flow: column;
.report-header__details__item {
border-bottom: 0;
}
}
}
}
.account-card {
background: $ui-base-color;
border-radius: 4px;
&__header {
padding: 4px;
border-radius: 4px;
height: 128px;
img {
display: block;
margin: 0;
width: 100%;
height: 100%;
object-fit: cover;
background: darken($ui-base-color, 8%);
}
}
&__title {
margin-top: -25px;
display: flex;
align-items: flex-end;
&__avatar {
padding: 15px;
img {
display: block;
margin: 0;
width: 56px;
height: 56px;
background: darken($ui-base-color, 8%);
border-radius: 8px;
}
}
.display-name {
color: $darker-text-color;
padding-bottom: 15px;
font-size: 15px;
bdi {
display: block;
color: $primary-text-color;
font-weight: 500;
}
}
}
&__bio {
padding: 0 15px;
overflow: hidden;
text-overflow: ellipsis;
word-wrap: break-word;
max-height: 18px * 2;
position: relative;
&::after {
display: block;
content: "";
width: 50px;
height: 18px;
position: absolute;
bottom: 0;
right: 15px;
background: linear-gradient(to left, $ui-base-color, transparent);
pointer-events: none;
}
}
&__actions {
display: flex;
align-items: center;
padding-top: 10px;
&__button {
flex: 0 0 auto;
padding: 0 15px;
}
}
&__counters {
flex: 1 1 auto;
display: grid;
grid-auto-columns: minmax(0, 1fr);
grid-auto-flow: column;
&__item {
padding: 15px;
text-align: center;
color: $primary-text-color;
font-weight: 600;
font-size: 15px;
small {
display: block;
color: $darker-text-color;
font-weight: 400;
font-size: 13px;
}
}
}
}
.report-notes {
margin-bottom: 20px;
&__item {
background: $ui-base-color;
position: relative;
padding: 15px;
padding-left: 15px * 2 + 40px;
border-bottom: 1px solid darken($ui-base-color, 8%);
&:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
&:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom: 0;
}
&:hover {
background-color: lighten($ui-base-color, 4%);
}
&__avatar {
position: absolute;
left: 15px;
top: 15px;
border-radius: 4px;
width: 40px;
height: 40px;
}
&__header {
color: $darker-text-color;
font-size: 15px;
line-height: 20px;
margin-bottom: 4px;
.username a {
color: $primary-text-color;
font-weight: 500;
text-decoration: none;
margin-right: 5px;
&:hover,
&:focus,
&:active {
text-decoration: underline;
}
}
time {
margin-left: 5px;
vertical-align: baseline;
}
}
&__content {
font-size: 15px;
line-height: 20px;
word-wrap: break-word;
font-weight: 400;
color: $primary-text-color;
p {
margin-bottom: 20px;
white-space: pre-wrap;
unicode-bidi: plaintext;
&:last-child {
margin-bottom: 0;
}
}
}
&__actions {
position: absolute;
top: 15px;
right: 15px;
text-align: right;
}
}
}
.report-actions {
border: 1px solid darken($ui-base-color, 8%);
&__item {
display: flex;
align-items: center;
line-height: 18px;
border-bottom: 1px solid darken($ui-base-color, 8%);
&:last-child {
border-bottom: 0;
}
&__button {
flex: 0 0 auto;
width: 100px;
padding: 15px;
padding-right: 0;
.button {
display: block;
width: 100%;
}
}
&__description {
padding: 15px;
font-size: 14px;
color: $dark-text-color;
}
}
}

View File

@ -150,6 +150,21 @@
&:active {
outline: 0 !important;
}
&.disabled {
border-color: $dark-text-color;
&.active {
background: $dark-text-color;
}
&:active,
&:focus,
&:hover {
border-color: $dark-text-color;
border-width: 1px;
}
}
}
&__number {

View File

@ -3,7 +3,7 @@ export const profileLink = '/settings/profile';
export const signOutLink = '/auth/sign_out';
export const termsLink = '/terms';
export const accountAdminLink = (id) => `/admin/accounts/${id}`;
export const statusAdminLink = (account_id, status_id) => `/admin/accounts/${account_id}/statuses/${status_id}`;
export const statusAdminLink = (account_id, status_id) => `/admin/accounts/${account_id}/statuses?id=${status_id}`;
export const filterEditLink = (id) => `/filters/${id}/edit`;
export const relationshipsLink = '/relationships';
export const securityLink = '/auth/edit';