docbrown/app/javascript/packs/flagUserModal.jsx
Arit Amana a78ccf2310
[deploy] [ModCenter] Fix "FlagUser" Modal functionality (#8995)
* Make FlagUserModal show up on click

* Explain extra div

* Make sure "Vomit All" reaction fires accurately

* Make test-file comment clearer

* Fix bug when 2 articles are open and the FlagUser modal does not open for the first article

* Still working it out ...

* Tests broken; need help

* Get rid of debugging alerts

* Fixed broken tests for <SingleArticle />

* Write tests for ModerationArticles component

* Complete tests for ModerationArticles component

* Employ safer Preact testing techniques

* Query all articles using "data-testid"

* Revert changes

* Got it working with portals for non-iframe implementation.

* wip tests

* Got mod tools flag user modal wprking on article page again.

* Added some documentation the code.

* Now confirm is disabled until you select an item in the flag user modal.

* Revert "wip tests"

This reverts commit fb7a0825039fd377cad04d9dedad9d1146b03978.

* test prep

* Fixed broken test.

* Refactored to use useRef hook.

* Rename a variable

* remove unnecessary comments

Co-authored-by: Nick Taylor <nick@dev.to>
2020-07-15 13:54:52 -04:00

208 lines
6.3 KiB
JavaScript

import { h, render } from 'preact';
import { useState, useRef } from 'preact/hooks';
import PropTypes from 'prop-types';
import { request } from '../utilities/http';
import { Button } from '@crayons/Button/Button';
async function confirmFlagUser({ reactableType, category, reactableId }) {
const body = JSON.stringify({
reactable_type: reactableType,
category,
reactable_id: reactableId,
});
try {
const response = await request('/reactions', {
method: 'POST',
body,
});
const outcome = await response.json();
if (outcome.result === 'create') {
top.addSnackbarItem({
message: 'All posts by this author will be less visible.',
addCloseButton: true,
});
} else if (outcome.result === null) {
top.addSnackbarItem({
message:
"It seems you've already reduced the visibility of this author's posts.",
addCloseButton: true,
});
} else {
top.addSnackbarItem({
message: `Response from server: ${JSON.stringify(outcome)}`,
addCloseButton: true,
});
}
} catch (error) {
top.addSnackbarItem({
message: error,
addCloseButton: true,
});
}
toggleFlagUserModal();
}
/**
* Shows or hides the flag user modal.
*/
export function toggleFlagUserModal() {
const modalContainer = document.querySelector('.flag-user-modal-container');
modalContainer.classList.toggle('hidden');
if (!modalContainer.classList.contains('hidden')) {
window.scrollTo(0, 0);
document.body.style.height = '100vh';
document.body.style.overflowY = 'hidden';
} else {
document.body.style.height = 'inherit';
document.body.style.overflowY = 'inherit';
}
}
/**
* Initializes the flag user modal for the given author ID.
*
* @param {number} authorId
*/
export function initializeFlagUserModal(authorId) {
// Check whether context is ModCenter or Friday-Night-Mode
const modContainer = document.getElementById('mod-container');
if (!modContainer) {
return;
}
render(
<FlagUserModal authorId={authorId} />,
document.querySelector('.flag-user-modal-container'),
);
modContainer.addEventListener('load', () => {
modContainer.contentWindow.document
.getElementById('open-flag-user-modal')
.addEventListener('click', toggleFlagUserModal);
});
}
/**
* A modal for flagging a user and their content. This can be used in the moderation
* or on an article page.
*
* @param {string} props.modCenterUrl (optional) The article URL loaded when in the moderation center.
* @param {number} props.authorId The author ID associated to the content being moderated.
*/
export function FlagUserModal({ modCenterArticleUrl, authorId }) {
const [isConfirmButtonEnabled, enableConfirmButton] = useState(false);
const vomitAllRef = useRef(null);
return (
<div
data-testid="flag-user-modal"
class="crayons-modal crayons-modal--s absolute flag-user-modal"
>
<div class="crayons-modal__box">
<header class="crayons-modal__box__header flag-user-modal-header">
<h2>Flag User</h2>
<button
type="button"
class="crayons-btn crayons-btn--icon crayons-btn--ghost modal-header-close-icon"
onClick={toggleFlagUserModal}
>
<svg
width="24"
height="24"
viewBox="0 0 24 24"
class="crayons-icon"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636l4.95 4.95z" />
</svg>
</button>
</header>
<div class="crayons-modal__box__body flag-user-modal-body">
<span>
Thanks for keeping DEV safe. Here is what you can do to flag this
user:
</span>
<div class="crayons-fields">
<div class="crayons-field crayons-field--radio">
<input
type="radio"
id="vomit-all"
ref={vomitAllRef}
name="flag-user"
class="crayons-radio"
data-reactable-id={authorId}
data-category="vomit"
data-reactable-type="User"
checked={isConfirmButtonEnabled}
onClick={(event) => {
const { target } = event;
enableConfirmButton(target.checked);
}}
/>
<label htmlFor="vomit-all" class="crayons-field__label">
Make all posts by this author less visible
<p class="crayons-field__description">
This author consistently posts content that violates DEV's
code of conduct because it is harassing, offensive or spammy.
</p>
</label>
</div>
<a
href={`/report-abuse?url=${
modCenterArticleUrl
? `${document.location.origin}${modCenterArticleUrl}`
: document.location
}`}
class="fs-base abuse-report-link"
>
Report other inappropriate conduct
</a>
</div>
<div class="buttons-container">
<Button
class="crayons-btn crayons-btn--danger mr-2"
id="confirm-flag-user-action"
onClick={(_event) => {
const {
current: { dataset: adminVomitReaction },
} = vomitAllRef;
confirmFlagUser(adminVomitReaction);
enableConfirmButton(false);
}}
disabled={!isConfirmButtonEnabled}
>
Confirm action
</Button>
<Button
class="crayons-btn crayons-btn--secondary"
id="cancel-flag-user-action"
onClick={toggleFlagUserModal}
>
Cancel
</Button>
</div>
</div>
</div>
<div
role="presentation"
class="crayons-modal__overlay"
onClick={toggleFlagUserModal}
onKeyUp={toggleFlagUserModal}
/>
</div>
);
}
FlagUserModal.displayName = 'FlagUserModal';
FlagUserModal.propTypes = {
moderationUrl: PropTypes.string,
authorId: PropTypes.number.isRequired,
};