diff --git a/app/javascript/actionsPanel/actionsPanel.js b/app/javascript/actionsPanel/actionsPanel.js index 2e585fa90..d13d38aa5 100644 --- a/app/javascript/actionsPanel/actionsPanel.js +++ b/app/javascript/actionsPanel/actionsPanel.js @@ -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() { diff --git a/app/javascript/packs/articleModerationTools.js b/app/javascript/packs/articleModerationTools.js index 88cad26ff..eb85429da 100644 --- a/app/javascript/packs/articleModerationTools.js +++ b/app/javascript/packs/articleModerationTools.js @@ -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); } } }; diff --git a/app/javascript/packs/unpublishPostModal.jsx b/app/javascript/packs/unpublishPostModal.jsx index 4eb379fd7..c5511441a 100644 --- a/app/javascript/packs/unpublishPostModal.jsx +++ b/app/javascript/packs/unpublishPostModal.jsx @@ -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( - , - 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 ( -
-
-
-

Unpublish post

-
-
-
-

- Once unpublished, this post will become invisible to the public - and only accessible to {authorName}. -

-

They can still re-publish the post if they are not suspended.

-
- -
-
-
-
- - ); -} - -UnpublishPostModal.displayName = 'UnpublishPostModal'; -UnpublishPostModal.propTypes = { - articleId: PropTypes.number.isRequired, - authorUsername: PropTypes.string.isRequired, - articleSlug: PropTypes.string.isRequired, -}; diff --git a/app/views/articles/show.html.erb b/app/views/articles/show.html.erb index c8720eee9..16c7b6a88 100644 --- a/app/views/articles/show.html.erb +++ b/app/views/articles/show.html.erb @@ -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" %>
<%= javascript_packs_with_chunks_tag "followButtons", defer: true %> diff --git a/app/views/moderations/actions_panel.html.erb b/app/views/moderations/actions_panel.html.erb index 1306186c0..32cd2c281 100644 --- a/app/views/moderations/actions_panel.html.erb +++ b/app/views/moderations/actions_panel.html.erb @@ -54,7 +54,11 @@ <% if policy(@moderatable).revoke_publication? %> <% end %> diff --git a/app/views/moderations/modals/_unpublish_post_modal.html.erb b/app/views/moderations/modals/_unpublish_post_modal.html.erb new file mode 100644 index 000000000..3e2f966c9 --- /dev/null +++ b/app/views/moderations/modals/_unpublish_post_modal.html.erb @@ -0,0 +1,17 @@ +<% name = @article.cached_user_name %> +