Used PreactModal for unpublish-post feature (#18019)

* Used preact modal

* Minor fix

* UI fix

* Appplied minor suggestions
This commit is contained in:
Rajat Talesra 2022-07-06 16:29:08 +05:30 committed by GitHub
parent 04ebdbab1c
commit bc0e5ced6c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 76 additions and 147 deletions

View file

@ -389,11 +389,6 @@ export function addBottomActionsListeners() {
});
}
const unpublishArticleBtn = document.getElementById('unpublish-article-btn');
if (unpublishArticleBtn) {
unpublishArticleBtn.addEventListener('click', toggleUnpublishPostModal);
}
document
.getElementById('open-flag-user-modal')
.addEventListener('click', toggleFlagUserModal);
@ -406,8 +401,13 @@ export function addBottomActionsListeners() {
.getElementById('unsuspend-user-btn')
?.addEventListener('click', toggleModal);
document.getElementById('unpublish-all-posts-btn')
document
.getElementById('unpublish-all-posts-btn')
?.addEventListener('click', toggleUnpublishAllPostsModal);
document
.getElementById('unpublish-article-btn')
?.addEventListener('click', toggleUnpublishPostModal);
}
export function initializeActionsPanel() {

View file

@ -6,23 +6,13 @@ getCsrfToken().then(() => {
if (articleContainer) {
const user = userData();
const {
articleId,
articleSlug,
authorId: articleAuthorId,
authorName,
authorUsername,
path,
} = articleContainer.dataset;
const { authorId: articleAuthorId, path } = articleContainer.dataset;
const initializeModerationsTools = async () => {
const { initializeActionsPanel } = await import(
'../actionsPanel/initializeActionsPanelToggle'
);
const { initializeFlagUserModal } = await import('./flagUserModal');
const { initializeUnpublishPostModal } = await import(
'./unpublishPostModal.jsx'
);
// If the user can moderate an article give them access to this panel.
// Note: this assumes we're within the article context (which is the case
@ -41,17 +31,10 @@ getCsrfToken().then(() => {
if (user?.id !== articleAuthorId && !isModerationPage()) {
initializeActionsPanel(user, path);
initializeFlagUserModal(articleAuthorId);
initializeUnpublishPostModal(
articleId,
authorName,
authorUsername,
articleSlug,
);
// "/mod" page
} else if (isModerationPage()) {
initializeActionsPanel(user, path);
initializeFlagUserModal(articleAuthorId);
initializeUnpublishPostModal(articleId, authorUsername, articleSlug);
}
}
};

View file

@ -1,8 +1,6 @@
import { h, render } from 'preact';
import PropTypes from 'prop-types';
import { request } from '../utilities/http';
import { ButtonNew as Button } from '@crayons';
import RemoveIcon from '@images/x.svg';
/* eslint-disable no-restricted-globals */
import { closeWindowModal, showWindowModal } from '@utilities/showModal';
import { request } from '@utilities/http';
async function confirmAdminUnpublishPost(id, username, slug) {
try {
@ -30,127 +28,53 @@ async function confirmAdminUnpublishPost(id, username, slug) {
});
}
toggleUnpublishPostModal();
closeWindowModal(window.parent.document);
}
let modalContents;
/**
* Helper function to handle finding and caching modal content. Since our Preact modal helper works by duplicating HTML content,
* and our modals rely on IDs to label form controls, we remove the original hidden content from the DOM to avoid ID conflicts.
*
* @param {string} modalContentSelector The CSS selector used to identify the correct modal content
*/
function getModalContents(modalContentSelector) {
if (!modalContents) {
const modalContentElement =
window.parent.document.querySelector(modalContentSelector);
modalContents = modalContentElement.innerHTML;
modalContentElement.remove();
}
return modalContents;
}
function activateModalUnpublishBtn(id, username, slug) {
const unpublishBtn = window.parent.document.getElementById(
'confirm-unpublish-post-action',
);
unpublishBtn?.addEventListener('click', () => {
confirmAdminUnpublishPost(id, username, slug);
});
}
/**
* Shows or hides the flag user modal.
*/
export function toggleUnpublishPostModal() {
const modalContainer = top.document.getElementsByClassName(
'unpublish-post-modal-container',
)[0];
modalContainer.classList.toggle('hidden');
export function toggleUnpublishPostModal(event) {
event.preventDefault;
const { articleId, authorUsername, articleSlug, modalContentSelector } =
event.target.dataset;
if (!modalContainer.classList.contains('hidden')) {
top.window.scrollTo(0, 0);
top.document.body.style.height = '100vh';
top.document.body.style.overflowY = 'hidden';
} else {
top.document.body.style.height = 'inherit';
top.document.body.style.overflowY = 'inherit';
}
showWindowModal({
document: window.parent.document,
modalContent: getModalContents(modalContentSelector),
title: 'Unpublish post',
size: 'small',
onOpen: () => {
activateModalUnpublishBtn(articleId, authorUsername, articleSlug);
},
});
}
/**
* Initializes the Unpublish Post modal for the given article ID, author username and article slug.
*
* @param {number} articleId
* @param {string} authorUsername
* @param {string} articleSlug
*/
export function initializeUnpublishPostModal(
articleId,
authorName,
authorUsername,
articleSlug,
) {
// Check whether context is ModCenter or Friday-Night-Mode
const modContainer = document.getElementById('mod-container');
if (!modContainer) {
return;
}
render(
<UnpublishPostModal
articleId={articleId}
authorName={authorName}
authorUsername={authorUsername}
articleSlug={articleSlug}
/>,
document.getElementsByClassName('unpublish-post-modal-container')[0],
);
}
/**
* A modal for unpublishing a post. This can be used in the moderation center
* or on an article page.
*
* @param {number} props.articleId ID of the article to be unpublished.
* @param {string} props.authorUsername Username of the article's author.
* @param {string} props.articleSlug Slug of the article to be unpublished.
*/
export function UnpublishPostModal({
articleId,
authorName,
authorUsername,
articleSlug,
}) {
return (
<div
data-testid="unpublish-post-modal"
class="crayons-modal crayons-modal--small absolute unpublish-post-modal"
>
<div class="crayons-modal__box">
<header class="crayons-modal__box__header unpublish-post-modal-header">
<h2 class="crayons-modal__box__header__title">Unpublish post</h2>
<Button
icon={RemoveIcon}
className="inline-flex"
onClick={toggleUnpublishPostModal}
/>
</header>
<div class="crayons-modal__box__body">
<div class="grid gap-4">
<p>
Once unpublished, this post will become invisible to the public
and only accessible to {authorName}.
</p>
<p>They can still re-publish the post if they are not suspended.</p>
<div>
<Button
destructive
variant="primary"
className="mr-2"
id="confirm-unpublish-post-action"
onClick={(_event) => {
confirmAdminUnpublishPost(
articleId,
authorUsername,
articleSlug,
);
}}
>
Unpublish post
</Button>
</div>
</div>
</div>
</div>
<div
role="presentation"
class="crayons-modal__overlay"
onClick={toggleUnpublishPostModal}
onKeyUp={toggleUnpublishPostModal}
/>
</div>
);
}
UnpublishPostModal.displayName = 'UnpublishPostModal';
UnpublishPostModal.propTypes = {
articleId: PropTypes.number.isRequired,
authorUsername: PropTypes.string.isRequired,
articleSlug: PropTypes.string.isRequired,
};

View file

@ -223,6 +223,7 @@
<%= render "moderations/modals/suspend_user_modal" %>
<%= render "moderations/modals/unsuspend_user_modal" %>
<%= render "moderations/modals/unpublish_all_posts" %>
<%= render "moderations/modals/unpublish_post_modal" %>
<div class="fullscreen-code js-fullscreen-code"></div>
<%= javascript_packs_with_chunks_tag "followButtons", defer: true %>

View file

@ -54,7 +54,11 @@
<% if policy(@moderatable).revoke_publication? %>
<button
class="c-btn c-btn--primary c-btn--destructive w-100 my-4"
id="unpublish-article-btn">
id="unpublish-article-btn"
data-article-id="<%= @moderatable.id %>"
data-author-username="<%= @moderatable.username %>"
data-article-slug="<%= @moderatable.slug %>"
data-modal-content-selector="#unpublish-post-modal">
<%= t("views.moderations.actions.unpublish") %>
</button>
<% end %>

View file

@ -0,0 +1,17 @@
<% name = @article.cached_user_name %>
<div id="unpublish-post-modal" class="hidden">
<p>
Once unpublished, this post will become invisible to the public
and only accessible to <%= name %>.
</p>
<p>They can still re-publish the post if they are not suspended.</p>
<div class="mt-4">
<button
destructive
variant="primary"
class="c-btn c-btn--primary c-btn--destructive"
id="confirm-unpublish-post-action">
Unpublish post
</button>
</div>
</div>