diff --git a/lib/experiments-page.php b/lib/experiments-page.php
index d6263b93ff6f8..2be55174d5e54 100644
--- a/lib/experiments-page.php
+++ b/lib/experiments-page.php
@@ -165,12 +165,12 @@ function gutenberg_initialize_experiments_settings() {
add_settings_field(
'gutenberg-block-comment',
- __( 'Enable multi-user commenting on blocks', 'gutenberg' ),
+ __( 'Comments', 'gutenberg' ),
'gutenberg_display_experiment_field',
'gutenberg-experiments',
'gutenberg_experiments_section',
array(
- 'label' => __( 'Comments', 'gutenberg' ),
+ 'label' => __( 'Enable multi-user commenting on blocks', 'gutenberg' ),
'id' => 'gutenberg-block-comment',
)
);
diff --git a/packages/block-editor/src/components/block-toolbar/index.js b/packages/block-editor/src/components/block-toolbar/index.js
index d53cbd74939df..754e8946e3b0a 100644
--- a/packages/block-editor/src/components/block-toolbar/index.js
+++ b/packages/block-editor/src/components/block-toolbar/index.js
@@ -99,10 +99,10 @@ export function PrivateBlockToolbar( {
!! getBlockAttributes( clientId )?.metadata?.bindings
);
- // eslint-disable-next-line @wordpress/data-no-store-string-literals
- const commentID = select( 'core/block-editor' ).getBlock(
- selectedBlockClientId
- )?.attributes?.blockCommentId;
+ const commentID =
+ // eslint-disable-next-line @wordpress/data-no-store-string-literals
+ select( 'core/block-editor' ).getBlock( selectedBlockClientId )
+ ?.attributes?.blockCommentId || null;
return {
blockClientId: selectedBlockClientId,
diff --git a/packages/block-editor/src/components/collab/block-comment-menu-item.js b/packages/block-editor/src/components/collab/block-comment-menu-item.js
index 8ff965675db6a..7a661cd64f74c 100644
--- a/packages/block-editor/src/components/collab/block-comment-menu-item.js
+++ b/packages/block-editor/src/components/collab/block-comment-menu-item.js
@@ -6,14 +6,14 @@ import { MenuItem } from '@wordpress/components';
import { collabComment } from '@wordpress/icons';
import { useDispatch } from '@wordpress/data';
-export default function BlockCommentMenuItem( { clientId, onClose } ) {
-
+export default function BlockCommentMenuItem( { onClose } ) {
+ // eslint-disable-next-line @wordpress/data-no-store-string-literals
const { openGeneralSidebar } = useDispatch( 'core/edit-post' );
const openCollabBoard = () => {
onClose();
- openGeneralSidebar("edit-post/collab-sidebar");
- }
+ openGeneralSidebar( 'edit-post/collab-sidebar' );
+ };
return (
+
);
}
diff --git a/packages/block-editor/src/components/collab/test/__snapshots__/index.js.snap b/packages/block-editor/src/components/collab/test/__snapshots__/index.js.snap
deleted file mode 100644
index f2915ead7417b..0000000000000
--- a/packages/block-editor/src/components/collab/test/__snapshots__/index.js.snap
+++ /dev/null
@@ -1,169 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`AlignmentUI should allow custom alignment controls to be specified 1`] = `
-
-`;
-
-exports[`AlignmentUI should match snapshot when controls are hidden 1`] = `
-
-
-
-`;
-
-exports[`AlignmentUI should match snapshot when controls are visible 1`] = `
-
-`;
diff --git a/packages/block-editor/src/components/collab/test/index.js b/packages/block-editor/src/components/collab/test/index.js
deleted file mode 100644
index 178ba294127c3..0000000000000
--- a/packages/block-editor/src/components/collab/test/index.js
+++ /dev/null
@@ -1,183 +0,0 @@
-/**
- * External dependencies
- */
-import { render, screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-
-/**
- * WordPress dependencies
- */
-import { alignLeft, alignCenter } from '@wordpress/icons';
-
-/**
- * Internal dependencies
- */
-import AlignmentUI from '../ui';
-
-describe( 'AlignmentUI', () => {
- const alignment = 'left';
- const onChangeSpy = jest.fn();
-
- afterEach( () => {
- onChangeSpy.mockClear();
- } );
-
- test( 'should match snapshot when controls are hidden', () => {
- const { container } = render(
-
- );
-
- expect( container ).toMatchSnapshot();
- } );
-
- test( 'should match snapshot when controls are visible', () => {
- const { container } = render(
-
- );
-
- expect( container ).toMatchSnapshot();
- } );
-
- test( 'should expand controls when toggled', async () => {
- const user = userEvent.setup();
-
- const { unmount } = render(
-
- );
-
- expect(
- screen.queryByRole( 'menuitemradio', {
- name: /^Align text \w+$/,
- } )
- ).not.toBeInTheDocument();
-
- await user.click(
- screen.getByRole( 'button', {
- name: 'Align text',
- } )
- );
-
- expect(
- screen.getAllByRole( 'menuitemradio', {
- name: /^Align text \w+$/,
- } )
- ).toHaveLength( 3 );
-
- // Cancel running effects, like delayed dropdown menu popover positioning.
- unmount();
- } );
-
- test( 'should call on change with undefined when a control is already active', async () => {
- const user = userEvent.setup();
-
- render(
-
- );
-
- const activeControl = screen.getByRole( 'button', {
- name: /^Align text \w+$/,
- pressed: true,
- } );
-
- await user.click( activeControl );
-
- expect( activeControl ).toHaveAttribute( 'align', alignment );
- expect( onChangeSpy ).toHaveBeenCalledTimes( 1 );
- expect( onChangeSpy ).toHaveBeenCalledWith( undefined );
- } );
-
- test( 'should call on change a new value when the control is not active', async () => {
- const user = userEvent.setup();
-
- render(
-
- );
-
- const inactiveControl = screen.getByRole( 'button', {
- name: 'Align text center',
- pressed: false,
- } );
-
- await user.click( inactiveControl );
-
- expect( onChangeSpy ).toHaveBeenCalledTimes( 1 );
- expect( onChangeSpy ).toHaveBeenCalledWith( 'center' );
- } );
-
- test( 'should allow custom alignment controls to be specified', async () => {
- const user = userEvent.setup();
-
- const { container } = render(
-
- );
-
- expect( container ).toMatchSnapshot();
-
- expect(
- screen.getAllByRole( 'button', {
- name: /^My custom \w+$/,
- } )
- ).toHaveLength( 2 );
-
- // Should correctly call on change when right alignment is pressed (active alignment)
- const rightControl = screen.getByRole( 'button', {
- name: 'My custom right',
- } );
-
- await user.click( rightControl );
-
- expect( onChangeSpy ).toHaveBeenCalledTimes( 1 );
- expect( onChangeSpy ).toHaveBeenCalledWith( undefined );
- onChangeSpy.mockClear();
-
- // Should correctly call on change when right alignment is pressed (inactive alignment)
- const leftControl = screen.getByRole( 'button', {
- name: 'My custom left',
- } );
-
- await user.click( leftControl );
-
- expect( onChangeSpy ).toHaveBeenCalledTimes( 1 );
- expect( onChangeSpy ).toHaveBeenCalledWith( 'custom-left' );
- } );
-} );
diff --git a/packages/block-editor/src/components/collab/collab-board/index.js b/packages/editor/src/components/collab-sidebar/add-comment.js
similarity index 72%
rename from packages/block-editor/src/components/collab/collab-board/index.js
rename to packages/editor/src/components/collab-sidebar/add-comment.js
index 065c1f1002e9c..af4ec5cf0d1f2 100644
--- a/packages/block-editor/src/components/collab/collab-board/index.js
+++ b/packages/editor/src/components/collab-sidebar/add-comment.js
@@ -4,42 +4,61 @@
// eslint-disable-next-line no-restricted-imports
import apiFetch from '@wordpress/api-fetch';
import { __ } from '@wordpress/i18n';
+import { useSelect, useDispatch } from '@wordpress/data';
import { useState } from '@wordpress/element';
import {
- TextControl,
- Button,
- CheckboxControl,
__experimentalHStack as HStack,
__experimentalVStack as VStack,
- Modal,
+ Button,
+ TextControl,
+ CheckboxControl,
} from '@wordpress/components';
-import { dateI18n, format, getSettings } from '@wordpress/date';
+import { dateI18n, format } from '@wordpress/date';
import {
- commentAuthorAvatar as userIcon,
Icon,
- trash as deleteIcon,
edit as editIcon,
+ trash as deleteIcon,
+ commentAuthorAvatar as userIcon,
} from '@wordpress/icons';
-import { useSelect, useDispatch } from '@wordpress/data';
-//import { store as coreStore } from '@wordpress/core-data';
-//import { useEntityProp } from '@wordpress/core-data';
+/**
+ * Renders the new comment form.
+ *
+ * @param {Object} root0 The component props.
+ * @param {Function} root0.setReloadComments Function to reload comments.
+ */
+export function AddComment( { setReloadComments } ) {
+ const generateNewComment = () => ( {
+ commentId: Date.now(),
+ createdBy: currentUser,
+ comment: inputComment,
+ createdAt: new Date().toISOString(),
+ } );
+
+ // Get the date time format from WordPress settings.
+ const dateTimeFormat = 'h:i A';
-export default function BlockCommentModal( { clientId, onClose, threadId } ) {
// State to manage the comment thread.
const [ inputComment, setInputComment ] = useState( '' );
- const [ isResolved, setIsResolved ] = useState( false );
const [ isEditing, setIsEditing ] = useState( null );
- const [ showConfirmation, setShowConfirmation ] = useState( false );
+
const curruntUserData = useSelect( ( select ) => {
// eslint-disable-next-line @wordpress/data-no-store-string-literals
return select( 'core' ).getCurrentUser();
}, [] );
- const userAvatar = curruntUserData.avatar_urls[ 48 ] || null;
+ let userAvatar =
+ 'https://secure.gravatar.com/avatar/92929292929292929292929292929292?s=48&d=mm&r=g';
+ if ( curruntUserData?.avatar_urls ) {
+ userAvatar = curruntUserData?.avatar_urls[ 48 ];
+ }
+
+ //const userAvatar = curruntUserData?.avatar_urls[ 48 ] ? curruntUserData?.avatar_urls[ 48 ] : null;
+
const currentUser = curruntUserData?.name || null;
const allThreads = [];
+ let threadId = 0;
const currentThread = allThreads[ threadId ] ?? {};
const isCurrentThreadResolved = currentThread.threadIsResolved || false;
const commentsCount = isCurrentThreadResolved
@@ -51,16 +70,24 @@ export default function BlockCommentModal( { clientId, onClose, threadId } ) {
return select( 'core/editor' ).getCurrentPostId();
}, [] );
+ const clientId = useSelect( ( select ) => {
+ // eslint-disable-next-line @wordpress/data-no-store-string-literals
+ const { getSelectedBlockClientId } = select( 'core/block-editor' );
+ return getSelectedBlockClientId();
+ }, [] );
+
+ const blockCommentId = useSelect( ( select ) => {
+ const clientID =
+ // eslint-disable-next-line @wordpress/data-no-store-string-literals
+ select( 'core/block-editor' ).getSelectedBlockClientId();
+ // eslint-disable-next-line @wordpress/data-no-store-string-literals
+ return select( 'core/block-editor' ).getBlock( clientID )?.attributes
+ ?.blockCommentId;
+ }, [] );
+
// Get the dispatch functions to save the comment and update the block attributes.
// eslint-disable-next-line @wordpress/data-no-store-string-literals
const { updateBlockAttributes } = useDispatch( 'core/block-editor' );
- // Helper function to generate a new comment.
- const generateNewComment = () => ( {
- commentId: Date.now(),
- createdBy: currentUser,
- comment: inputComment,
- createdAt: new Date().toISOString(),
- } );
// // Function to add a border class to the content reference.
const setAttributes = () => {
@@ -69,26 +96,10 @@ export default function BlockCommentModal( { clientId, onClose, threadId } ) {
} );
};
- // Helper function to get updated comments structure
- const getUpdatedComments = ( newComment, threadKey ) => ( {
- ...allThreads,
- [ threadKey ]: {
- isResolved,
- createdAt:
- allThreads?.threadKey?.createdAt || new Date().toISOString(),
- createdBy: currentUser,
- comments: [
- ...( allThreads[ threadKey ]?.comments || [] ),
- newComment,
- ],
- },
- } );
-
// Function to save the comment.
const saveComment = () => {
const newComment = generateNewComment();
threadId = newComment?.commentId;
- const updatedComments = getUpdatedComments( newComment, threadId );
apiFetch( {
path: '/wp/v2/comments',
@@ -101,12 +112,11 @@ export default function BlockCommentModal( { clientId, onClose, threadId } ) {
comment_author: currentUser,
comment_approved: 0,
},
- } ).then( (response) => {
- threadId = response?.id;
- setAttributes( clientId, threadId );
- onClose();
+ } ).then( ( response ) => {
+ setAttributes( clientId, response?.id );
+ setInputComment( '' );
+ setReloadComments( true );
} );
-
};
// Function to edit the comment.
@@ -130,22 +140,6 @@ export default function BlockCommentModal( { clientId, onClose, threadId } ) {
setIsEditing( null );
};
- // Function to mark thread as resolved
- const markThreadAsResolved = () => {
- setIsResolved( true );
-
- const updatedComments = { ...allThreads };
-
- updatedComments[ threadId ] = {
- ...updatedComments[ threadId ],
- isResolved: true,
- resolvedBy: currentUser,
- resolvedAt: new Date().toISOString(),
- };
-
- onClose();
- };
-
// Function to delete a comment.
const deleteComment = ( commentId ) => {
// Filter out the comment to be deleted.
@@ -166,28 +160,11 @@ export default function BlockCommentModal( { clientId, onClose, threadId } ) {
}
};
- // Function to show the confirmation overlay.
- const showConfirmationOverlay = () => setShowConfirmation( true );
-
- // Function to hide the confirmation overlay.
- const hideConfirmationOverlay = () => setShowConfirmation( false );
-
- // Function to confirm and mark thread as resolved.
- const confirmAndMarkThreadAsResolved = () => {
- markThreadAsResolved();
- hideConfirmationOverlay();
- };
+ const handleCancel = () => {};
- // On cancel, remove the border if no comments are present.
- const handleCancel = () => {
- onClose();
- };
-
- // Get the date time format from WordPress settings.
- const dateTimeFormat = getSettings().formats.datetime;
return (
<>
-
+ { null !== clientId && 0 === blockCommentId && (
{ 0 < commentsCount && ! isCurrentThreadResolved && (
<>
@@ -203,17 +180,22 @@ export default function BlockCommentModal( { clientId, onClose, threadId } ) {
) => (
<>
{ isEditing === commentId && (
-
+
-
+
{ currentUser }
@@ -232,7 +214,7 @@ export default function BlockCommentModal( { clientId, onClose, threadId } ) {
spacing="2"
>
- { showConfirmation && (
- hideConfirmationOverlay() }
- className="confirmation-overlay"
- >
-
- { __(
- 'Are you sure you want to mark this thread as resolved?'
- ) }
-
- confirmAndMarkThreadAsResolved() }
- >
- { __( 'Yes' ) }
-
- hideConfirmationOverlay() }>
- { __( 'No' ) }
-
-
) }
>
);
diff --git a/packages/editor/src/components/collab-sidebar/comments.js b/packages/editor/src/components/collab-sidebar/comments.js
new file mode 100644
index 0000000000000..dfbd497a9b0d4
--- /dev/null
+++ b/packages/editor/src/components/collab-sidebar/comments.js
@@ -0,0 +1,1005 @@
+/**
+ * WordPress dependencies
+ */
+// eslint-disable-next-line no-restricted-imports
+import apiFetch from '@wordpress/api-fetch';
+import { useState, RawHTML } from '@wordpress/element';
+import {
+ __experimentalHStack as HStack,
+ __experimentalVStack as VStack,
+ __experimentalText as Text,
+ Button,
+ DropdownMenu,
+ TextareaControl,
+ Tooltip,
+} from '@wordpress/components';
+import { dateI18n, format } from '@wordpress/date';
+import { Icon, check, published, moreVertical } from '@wordpress/icons';
+import { __ } from '@wordpress/i18n';
+import { useSelect } from '@wordpress/data';
+
+export function Comments( { threads } ) {
+ const [ showConfirmation, setShowConfirmation ] = useState( false );
+ const [ showConfirmationTabId, setShowConfirmationTabId ] = useState( 0 );
+ const [ commentConfirmation, setCommentConfirmation ] = useState( false );
+ const [ deleteCommentShowConfirmation, setDeleteCommentShowConfirmation ] =
+ useState( false );
+ const [ commentDeleteMessage, setCommentDeleteMessage ] = useState( false );
+ const [ commentEdit, setCommentEdit ] = useState( false );
+ const [ newEditedComment, setNewEditedComment ] = useState( '' );
+ const [ commentEditedMessage, setCommentEditedMessage ] = useState( false );
+ const [ hasCommentReply, setHasCommentReply ] = useState( false );
+ const [ commentReply, setCommentReply ] = useState( '' );
+ const [ replyMessage, setReplyMessage ] = useState( false );
+
+ // Get the date time format from WordPress settings.
+ const dateTimeFormat = 'h:i A';
+ const currentUserData = useSelect( ( select ) => {
+ // eslint-disable-next-line @wordpress/data-no-store-string-literals
+ return select( 'core' ).getCurrentUser();
+ }, [] );
+ const currentUser = currentUserData?.name || null;
+ const postId = useSelect( ( select ) => {
+ // eslint-disable-next-line @wordpress/data-no-store-string-literals
+ return select( 'core/editor' ).getCurrentPostId();
+ }, [] );
+
+ const confirmAndMarkThreadAsResolved = ( threadID ) => {
+ setCommentConfirmation( false );
+ if ( threadID ) {
+ apiFetch( {
+ path: '/wp/v2/comments/' + threadID,
+ method: 'POST',
+ data: {
+ status: 'approved',
+ },
+ } ).then( ( response ) => {
+ if ( 'approved' === response.status ) {
+ setShowConfirmation( false );
+ setCommentConfirmation( true );
+ }
+ } );
+ }
+ };
+
+ const onEditComment = ( threadID ) => {
+ if ( threadID ) {
+ setHasCommentReply( false );
+ setCommentEdit( true );
+ }
+ };
+
+ const confirmEditComment = ( threadID ) => {
+ if ( threadID ) {
+ const editedComment = newEditedComment.replace(
+ /^|<\/p>$/g,
+ ''
+ );
+
+ apiFetch( {
+ path: '/wp/v2/comments/' + threadID,
+ method: 'POST',
+ data: {
+ content: editedComment,
+ },
+ } ).then( ( response ) => {
+ if ( 'trash' !== response.status && '' !== response.id ) {
+ setCommentEdit( false );
+ setCommentEditedMessage( true );
+ }
+ } );
+ }
+ };
+
+ const confirmDeleteComment = ( threadID ) => {
+ setDeleteCommentShowConfirmation( false );
+ if ( threadID ) {
+ apiFetch( {
+ path: '/wp/v2/comments/' + threadID,
+ method: 'DELETE',
+ } ).then( ( response ) => {
+ if ( 'trash' === response.status && '' !== response.id ) {
+ setCommentDeleteMessage( true );
+ }
+ } );
+ }
+ };
+
+ const onReplyComment = ( threadID ) => {
+ if ( threadID ) {
+ setCommentEdit( false );
+ setHasCommentReply( true );
+ }
+ };
+
+ const generateReplyComment = ( comment ) => ( {
+ commentId: Date.now(),
+ createdBy: currentUser,
+ comment,
+ createdAt: new Date().toISOString(),
+ } );
+
+ const confirmReplyComment = ( threadID ) => {
+ if ( threadID ) {
+ const newComment = generateReplyComment( commentReply );
+ apiFetch( {
+ path: '/wp/v2/comments/',
+ method: 'POST',
+ data: {
+ parent: threadID,
+ post: postId,
+ content: newComment.comment,
+ comment_date: newComment.createdAt,
+ comment_type: 'block_comment',
+ comment_author: currentUser,
+ comment_approved: 0,
+ },
+ } ).then( ( response ) => {
+ if ( 'trash' !== response.status && '' !== response.id ) {
+ setReplyMessage( true );
+ }
+ } );
+ }
+ };
+
+ return (
+ <>
+ {
+ // If there are no threads, show a message indicating no threads are available.
+ ( ! Array.isArray( threads ) || threads.length === 0 ) && (
+
+
+ { __( 'No comments available' ) }
+
+
+ )
+ }
+
+ { Array.isArray( threads ) &&
+ threads.length > 0 &&
+ threads.reverse().map( ( thread ) => (
+
+
+
+
+
+ { thread.author_name }
+
+
+
+
+ { thread.status !== 'approved' && (
+
+
+
+ {
+ setCommentConfirmation(
+ false
+ );
+ setShowConfirmation(
+ true
+ );
+ setShowConfirmationTabId(
+ thread.id
+ );
+ } }
+ />
+
+
+ { 0 === thread.parent ? (
+ {
+ setShowConfirmationTabId(
+ thread.id
+ );
+ onEditComment(
+ thread.id
+ );
+ },
+ },
+ {
+ title: __( 'Delete' ),
+ onClick: () => {
+ setCommentEdit(
+ false
+ );
+ setShowConfirmationTabId(
+ thread.id
+ );
+ setDeleteCommentShowConfirmation(
+ true
+ );
+ },
+ },
+ {
+ title: __( 'Reply' ),
+ onClick: () => {
+ setShowConfirmationTabId(
+ thread.id
+ );
+ onReplyComment(
+ thread.id
+ );
+ },
+ },
+ ] }
+ />
+ ) : (
+ {
+ setShowConfirmationTabId(
+ thread.id
+ );
+ onEditComment(
+ thread.id
+ );
+ },
+ },
+ {
+ title: __( 'Delete' ),
+ onClick: () => {
+ setCommentEdit(
+ false
+ );
+ setShowConfirmationTabId(
+ thread.id
+ );
+ setDeleteCommentShowConfirmation(
+ true
+ );
+ },
+ },
+ ] }
+ />
+ ) }
+
+ ) }
+ { thread.status === 'approved' && (
+
+
+
+
+
+ ) }
+
+
+
+
+ { commentEdit &&
+ thread.id === showConfirmationTabId && (
+ <>
+ /g,
+ ''
+ )
+ : thread.content.rendered.replace(
+ /<\/?p>/g,
+ ''
+ )
+ }
+ onChange={ ( value ) => {
+ setNewEditedComment(
+ value
+ );
+ } }
+ />
+
+ setCommentEdit( false )
+ }
+ >
+
+ {
+ confirmEditComment(
+ thread.id
+ );
+ setCommentEdit(
+ false
+ );
+ } }
+ >
+ { __( 'Update' ) }
+
+ {
+ setCommentEdit(
+ false
+ );
+ setShowConfirmation(
+ false
+ );
+ } }
+ >
+ { __( 'Cancel' ) }
+
+
+
+ >
+ ) }
+ { thread.content.rendered }
+
+
+
+ { hasCommentReply &&
+ thread.id === showConfirmationTabId && (
+
+
+ {
+ setCommentReply( value );
+ } }
+ />
+
+ setHasCommentReply( false )
+ }
+ >
+
+ {
+ confirmReplyComment(
+ thread.id
+ );
+ setHasCommentReply(
+ false
+ );
+ } }
+ className="is-compact"
+ >
+ { __( 'Reply' ) }
+
+ {
+ setHasCommentReply(
+ false
+ );
+ setShowConfirmation(
+ false
+ );
+ } }
+ className="is-compact"
+ >
+ { __( 'Cancel' ) }
+
+
+
+
+
+ ) }
+
+ { commentConfirmation &&
+ thread.id === showConfirmationTabId && (
+
+ { __( 'Thread marked as resolved.' ) }
+
+ ) }
+ { commentEditedMessage &&
+ thread.id === showConfirmationTabId && (
+
+ { __( 'Thread edited successfully.' ) }
+
+ ) }
+ { commentDeleteMessage &&
+ thread.id === showConfirmationTabId && (
+
+ { __( 'Thread deleted successfully.' ) }
+
+ ) }
+ { replyMessage &&
+ thread.id === showConfirmationTabId && (
+
+ { __( 'Reply added successfully.' ) }
+
+ ) }
+
+ { showConfirmation &&
+ thread.id === showConfirmationTabId && (
+
+ setShowConfirmation( false )
+ }
+ className="editor-collab-sidebar__useroverlay confirmation-overlay"
+ spacing="0"
+ justify="space-between"
+ >
+
+ { __(
+ 'Are you sure you want to mark this thread as resolved?'
+ ) }
+
+
+
+ confirmAndMarkThreadAsResolved(
+ thread.id
+ )
+ }
+ >
+ { __( 'Yes' ) }
+
+
+ setShowConfirmation( false )
+ }
+ >
+ { __( 'No' ) }
+
+
+
+ ) }
+
+ { deleteCommentShowConfirmation &&
+ thread.id === showConfirmationTabId && (
+
+ setDeleteCommentShowConfirmation(
+ false
+ )
+ }
+ className="editor-collab-sidebar__useroverlay confirmation-overlay"
+ spacing="0"
+ justify="space-between"
+ >
+
+ { __(
+ 'Are you sure you want to delete this thread?'
+ ) }
+
+
+
+ confirmDeleteComment(
+ thread.id
+ )
+ }
+ >
+ { __( 'Yes' ) }
+
+
+ setDeleteCommentShowConfirmation(
+ false
+ )
+ }
+ >
+ { __( 'No' ) }
+
+
+
+ ) }
+
+ { 0 < thread?.reply?.length &&
+ thread.reply.map( ( reply ) => (
+
+
+
+
+
+ { reply.author_name }
+
+
+
+
+ { reply.status !== 'approved' && (
+
+ { 0 === reply.parent && (
+ {
+ setShowConfirmationTabId(
+ reply.id
+ );
+ onEditComment(
+ reply.id
+ );
+ },
+ },
+ {
+ title: __(
+ 'Delete'
+ ),
+ onClick:
+ () => {
+ setCommentEdit(
+ false
+ );
+ setShowConfirmationTabId(
+ reply.id
+ );
+ setDeleteCommentShowConfirmation(
+ true
+ );
+ },
+ },
+ {
+ title: __(
+ 'Reply'
+ ),
+ onClick:
+ () => {
+ setShowConfirmationTabId(
+ reply.id
+ );
+ onReplyComment(
+ reply.id
+ );
+ },
+ },
+ ] }
+ />
+ ) }
+
+ { 0 !== reply.parent &&
+ thread.status !==
+ 'approved' && (
+ {
+ setShowConfirmationTabId(
+ reply.id
+ );
+ onEditComment(
+ reply.id
+ );
+ },
+ },
+ {
+ title: __(
+ 'Delete'
+ ),
+ onClick:
+ () => {
+ setCommentEdit(
+ false
+ );
+ setShowConfirmationTabId(
+ reply.id
+ );
+ setDeleteCommentShowConfirmation(
+ true
+ );
+ },
+ },
+ ] }
+ />
+ ) }
+
+ ) }
+
+
+
+
+ { commentEdit &&
+ reply.id ===
+ showConfirmationTabId && (
+ <>
+ /g,
+ ''
+ )
+ : reply.content.rendered.replace(
+ /<\/?p>/g,
+ ''
+ )
+ }
+ onChange={ (
+ value
+ ) => {
+ setNewEditedComment(
+ value
+ );
+ } }
+ />
+
+ setCommentEdit(
+ false
+ )
+ }
+ >
+
+ {
+ confirmEditComment(
+ reply.id
+ );
+ setCommentEdit(
+ false
+ );
+ } }
+ >
+ { __(
+ 'Update'
+ ) }
+
+ {
+ setCommentEdit(
+ false
+ );
+ setShowConfirmation(
+ false
+ );
+ } }
+ >
+ { __(
+ 'Cancel'
+ ) }
+
+
+
+ >
+ ) }
+
+ { reply.content.rendered }
+
+
+
+
+ { hasCommentReply &&
+ reply.id === showConfirmationTabId && (
+
+
+ {
+ setCommentReply(
+ value
+ );
+ } }
+ />
+
+ setHasCommentReply(
+ false
+ )
+ }
+ >
+
+ {
+ confirmReplyComment(
+ reply.id
+ );
+ setHasCommentReply(
+ false
+ );
+ } }
+ className="is-compact"
+ >
+ { __(
+ 'Reply'
+ ) }
+
+ {
+ setHasCommentReply(
+ false
+ );
+ setShowConfirmation(
+ false
+ );
+ } }
+ className="is-compact"
+ >
+ { __(
+ 'Cancel'
+ ) }
+
+
+
+
+
+ ) }
+
+ { commentConfirmation &&
+ reply.id === showConfirmationTabId && (
+
+ { __(
+ 'Thread marked as resolved.'
+ ) }
+
+ ) }
+ { commentEditedMessage &&
+ reply.id === showConfirmationTabId && (
+
+ { __(
+ 'Thread edited successfully.'
+ ) }
+
+ ) }
+ { commentDeleteMessage &&
+ reply.id === showConfirmationTabId && (
+
+ { __(
+ 'Thread deleted successfully.'
+ ) }
+
+ ) }
+ { replyMessage &&
+ reply.id === showConfirmationTabId && (
+
+ { __(
+ 'Reply added successfully.'
+ ) }
+
+ ) }
+
+ { showConfirmation &&
+ reply.id === showConfirmationTabId && (
+
+ setShowConfirmation( false )
+ }
+ className="editor-collab-sidebar__useroverlay confirmation-overlay"
+ spacing="0"
+ justify="space-between"
+ >
+
+ { __(
+ 'Are you sure you want to mark this thread as resolved?'
+ ) }
+
+
+
+ confirmAndMarkThreadAsResolved(
+ reply.id
+ )
+ }
+ >
+ { __( 'Yes' ) }
+
+
+ setShowConfirmation(
+ false
+ )
+ }
+ >
+ { __( 'No' ) }
+
+
+
+ ) }
+
+ { deleteCommentShowConfirmation &&
+ reply.id === showConfirmationTabId && (
+
+ setDeleteCommentShowConfirmation(
+ false
+ )
+ }
+ className="editor-collab-sidebar__useroverlay confirmation-overlay"
+ spacing="0"
+ justify="space-between"
+ >
+
+ { __(
+ 'Are you sure you want to delete this thread?'
+ ) }
+
+
+
+ confirmDeleteComment(
+ reply.id
+ )
+ }
+ >
+ { __( 'Yes' ) }
+
+
+ setDeleteCommentShowConfirmation(
+ false
+ )
+ }
+ >
+ { __( 'No' ) }
+
+
+
+ ) }
+
+ ) ) }
+
+ ) ) }
+ >
+ );
+}
diff --git a/packages/editor/src/components/collab-sidebar/index.js b/packages/editor/src/components/collab-sidebar/index.js
index c8b7d3d42c95b..215eb6c582a20 100644
--- a/packages/editor/src/components/collab-sidebar/index.js
+++ b/packages/editor/src/components/collab-sidebar/index.js
@@ -4,29 +4,10 @@
// eslint-disable-next-line no-restricted-imports
import apiFetch from '@wordpress/api-fetch';
import { __ } from '@wordpress/i18n';
-import { useSelect, useDispatch, withDispatch, withSelect } from '@wordpress/data';
-import { useState, useEffect, RawHTML } from '@wordpress/element';
-import {
- __experimentalHStack as HStack,
- __experimentalVStack as VStack,
- __experimentalText as Text,
- Button,
- DropdownMenu,
- TextareaControl,
- Tooltip,
- TextControl,
- CheckboxControl,
-} from '@wordpress/components';
-import { dateI18n, format, getSettings } from '@wordpress/date';
-import {
- comment as commentIcon,
- Icon,
- check,
- published,
- moreVertical
-} from '@wordpress/icons';
+import { useSelect } from '@wordpress/data';
+import { useState, useEffect } from '@wordpress/element';
+import { comment as commentIcon } from '@wordpress/icons';
-import { registerBlockType } from '@wordpress/blocks';
import { addFilter } from '@wordpress/hooks';
/**
@@ -34,14 +15,18 @@ import { addFilter } from '@wordpress/hooks';
*/
import PluginSidebar from '../plugin-sidebar';
import { collabSidebarName } from './constants';
+import { Comments } from './comments';
+import { AddComment } from './add-comment';
-import { store as blockEditorStore } from '../../store';
+const isBlockCommentExperimentEnabled =
+ window?.__experimentalEnableBlockComment;
-const isBlockCommentExperimentEnabled = window?.__experimentalEnableBlockComment;
-
-const modifyBlockCommentAttributes = (settings, name) => {
- if ( name && name?.includes( 'core/' ) ) {
- if( undefined === settings.attributes.blockCommentId || null === settings.attributes.blockCommentId ) {
+const modifyBlockCommentAttributes = ( settings, name ) => {
+ if ( name && name?.includes( 'core/' ) ) {
+ if (
+ undefined === settings.attributes.blockCommentId ||
+ null === settings.attributes.blockCommentId
+ ) {
settings.attributes = {
...settings.attributes,
blockCommentId: {
@@ -50,364 +35,82 @@ const modifyBlockCommentAttributes = (settings, name) => {
},
};
}
-
- }
- return settings;
+ }
+ return settings;
};
// Apply the filter to all core blocks
addFilter(
- 'blocks.registerBlockType',
- 'block-comment/modify-core-block-attributes',
- modifyBlockCommentAttributes
+ 'blocks.registerBlockType',
+ 'block-comment/modify-core-block-attributes',
+ modifyBlockCommentAttributes
);
/**
* Renders the Collab sidebar.
*/
export default function CollabSidebar() {
+ const [ threads, setThreads ] = useState( [] );
+ const [ reloadComments, setReloadComments ] = useState( false );
+ const postId = useSelect( ( select ) => {
+ // eslint-disable-next-line @wordpress/data-no-store-string-literals
+ return select( 'core/editor' ).getCurrentPostId();
+ }, [] );
- const postId = useSelect((select) => {
- return select('core/editor').getCurrentPostId();
- }, []);
-
- const [threads, setThreads] = useState([]);
- const [ showConfirmation, setShowConfirmation ] = useState( false );
- const [ showConfirmationTabId, setShowConfirmationTabId ] = useState( 0 );
- const [ commentConfirmation, setCommentConfirmation ] = useState( false );
- const [ deleteCommentShowConfirmation, setDeleteCommentShowConfirmation ] = useState( false );
- const [ commentDeleteMessage, setCommentDeleteMessage ] = useState( false );
- const [ commentEdit, setCommentEdit ] = useState( false );
- const [ newEditedComment, setNewEditedComment ] = useState( '' );
- const [ commentEditedMessage, setCommentEditedMessage ] = useState( false );
- const [ hasCommentReply, setHasCommentReply ] = useState( false );
- const [ commentReply, setCommentReply ] = useState( '' );
- const [ replyMessage, setReplyMessage ] = useState( false );
-
- useEffect(() => {
- if (postId) {
- apiFetch({
- path: '/wp/v2/comments?post=' + postId + '&type=block_comment' + '&status=any&per_page=100',
+ useEffect( () => {
+ if ( postId ) {
+ apiFetch( {
+ path:
+ '/wp/v2/comments?post=' +
+ postId +
+ '&type=block_comment' +
+ '&status=any&per_page=100',
method: 'GET',
- })
- .then((data) => {
-
+ } ).then( ( data ) => {
// Create a compare to store the references to all objects by id
const compare = {};
const result = [];
-
+
// Initialize each object with an empty `reply` array
- data.forEach(item => {
- compare[item.id] = { ...item, reply: [] };
- });
-
+ data.forEach( ( item ) => {
+ compare[ item.id ] = { ...item, reply: [] };
+ } );
+
// Iterate over the data to build the tree structure
- data.forEach(item => {
- if (item.parent === 0) {
+ data.forEach( ( item ) => {
+ if ( item.parent === 0 ) {
// If parent is 0, it's a root item, push it to the result array
- result.push(compare[item.id]);
- } else {
+ result.push( compare[ item.id ] );
+ } else if (
+ compare[ item.parent ] &&
+ 'trash' !== item.status
+ ) {
// Otherwise, find its parent and push it to the parent's `reply` array
- if (compare[item.parent]) {
- if( 'trash' !== item.status ) {
- compare[item.parent].reply.push(compare[item.id]);
- }
- }
+ compare[ item.parent ].reply.push( compare[ item.id ] );
}
- });
- const filteredComments = result.filter(comment => comment.status !== 'trash');
- setThreads(Array.isArray(filteredComments) ? filteredComments : []);
-
- })
+ } );
+ const filteredComments = result.filter(
+ ( comment ) => comment.status !== 'trash'
+ );
+ setThreads(
+ Array.isArray( filteredComments ) ? filteredComments : []
+ );
+ } );
}
- }, [postId]);
+ }, [ postId, reloadComments ] );
- const { threads: selectedThreads } = useSelect(() => {
+ const { threads: selectedThreads } = useSelect( () => {
return {
- threads: threads,
+ threads,
};
- }, [threads]);
+ }, [ threads ] );
// Check if the experimental flag is enabled.
if ( ! isBlockCommentExperimentEnabled ) {
return null; // or maybe return some message indicating no threads are available.
}
- const confirmAndMarkThreadAsResolved = ( threadID ) => {
- setCommentConfirmation( false );
- if (threadID) {
- apiFetch({
- path: '/wp/v2/comments/' + threadID,
- method: 'POST',
- data: {
- status: 'approved',
- }
- })
- .then((response) => {
- if ( 'approved' === response.status ) {
- setShowConfirmation( false );
- setCommentConfirmation( true );
- }
- })
- }
- };
-
- const onEditComment = ( threadID ) => {
- if ( threadID ) {
- setHasCommentReply( false );
- setCommentEdit( true );
- }
- };
-
- const confirmEditComment = ( threadID ) => {
- if (threadID) {
- const editedComment = newEditedComment.replace(/^
|<\/p>$/g, '');
-
- apiFetch({
- path: '/wp/v2/comments/' + threadID,
- method: 'POST',
- data: {
- content: editedComment,
- }
- })
- .then((response) => {
- if ( 'trash' !== response.status && '' !== response.id ) {
- setCommentEdit( false );
- setCommentEditedMessage( true );
- }
- })
- }
- };
-
- const confirmDeleteComment = ( threadID ) => {
- setDeleteCommentShowConfirmation( false );
- if (threadID) {
- apiFetch({
- path: '/wp/v2/comments/' + threadID,
- method: 'DELETE',
- })
- .then((response) => {
- if ( 'trash' === response.status && '' !== response.id ) {
- setCommentDeleteMessage( true );
- }
- })
- }
- };
-
- const onReplyComment = ( threadID ) => {
- if ( threadID ) {
- setCommentEdit( false );
- setHasCommentReply( true );
- }
- };
-
- const confirmReplyComment = ( threadID ) => {
- if (threadID) {
-
- const newComment = generateReplyComment( commentReply );
- const commentId = newComment?.commentId;
- const updatedComments = getUpdatedComments( newComment, commentId );
-
- apiFetch({
- path: '/wp/v2/comments/',
- method: 'POST',
- data: {
- parent: threadID,
- post: postID,
- content: newComment.comment,
- comment_date: newComment.createdAt,
- comment_type: 'block_comment',
- comment_author: currentUser,
- comment_approved: 0,
- }
- })
- .then((response) => {
- if ( 'trash' !== response.status && '' !== response.id ) {
- setReplyMessage( true );
- }
- })
- }
- }
-
- // Helper function to get updated comments structure
- const getUpdatedComments = ( newComment, threadKey ) => ( {
- ...threads,
- [ threadKey ]: {
- isResolved: false,
- createdAt:
- threads?.threadKey?.createdAt || new Date().toISOString(),
- createdBy: currentUser,
- comments: {
- 0: newComment,
- },
- },
- } );
-
- const generateReplyComment = (comment) => ( {
- commentId: Date.now(),
- createdBy: currentUser,
- comment,
- createdAt: new Date().toISOString(),
- } );
-
- const generateNewComment = () => ( {
- commentId: Date.now(),
- createdBy: currentUser,
- comment: inputComment,
- createdAt: new Date().toISOString(),
- } );
-
- // Get the date time format from WordPress settings.
- const dateTimeFormat = 'h:i A';
- const resultThreads = selectedThreads.map(thread => thread).reverse();
-
- // State to manage the comment thread.
- const [ inputComment, setInputComment ] = useState( '' );
- const [ isResolved, setIsResolved ] = useState( false );
- const [ isEditing, setIsEditing ] = useState( null );
- const curruntUserData = useSelect( ( select ) => {
- // eslint-disable-next-line @wordpress/data-no-store-string-literals
- return select( 'core' ).getCurrentUser();
- }, [] );
-
- let userAvatar = 'https://secure.gravatar.com/avatar/92929292929292929292929292929292?s=48&d=mm&r=g';
- if( curruntUserData?.avatar_urls ) {
- userAvatar = curruntUserData?.avatar_urls[ 48 ];
- }
-
- //const userAvatar = curruntUserData?.avatar_urls[ 48 ] ? curruntUserData?.avatar_urls[ 48 ] : null;
-
- const currentUser = curruntUserData?.name || null;
- const allThreads = [];
- const threadId = 0;
- const currentThread = allThreads[ threadId ] ?? {};
- const isCurrentThreadResolved = currentThread.threadIsResolved || false;
- const commentsCount = isCurrentThreadResolved
- ? 0
- : currentThread.comments?.length || 0;
- // eslint-disable-next-line @wordpress/data-no-store-string-literals
- const postID = useSelect( ( select ) => {
- // eslint-disable-next-line @wordpress/data-no-store-string-literals
- return select( 'core/editor' ).getCurrentPostId();
- }, [] );
-
- const clientId = useSelect((select) => {
- // eslint-disable-next-line @wordpress/data-no-store-string-literals
- const { getSelectedBlockClientId } = select('core/block-editor');
- return getSelectedBlockClientId();
- }, []);
-
- const blockCommentId = useSelect((select) => {
- // eslint-disable-next-line @wordpress/data-no-store-string-literals
- return select( 'core/block-editor' ).getBlock( select('core/block-editor').getSelectedBlockClientId() )?.attributes?.blockCommentId;
- }, []);
-
- // Get the dispatch functions to save the comment and update the block attributes.
- // eslint-disable-next-line @wordpress/data-no-store-string-literals
- const { updateBlockAttributes } = useDispatch( 'core/block-editor' );
-
- // eslint-disable-next-line @wordpress/data-no-store-string-literals
- const { closeGeneralSidebar } = useDispatch( 'core/edit-post' );
-
- // // Function to add a border class to the content reference.
- const setAttributes = ( clientId, threadId ) => {
- updateBlockAttributes( clientId, {
- blockCommentId: threadId,
- } );
-
- };
-
- // Function to save the comment.
- const saveComment = () => {
- const newComment = generateNewComment();
- apiFetch( {
- path: '/wp/v2/comments',
- method: 'POST',
- data: {
- post: postID,
- content: newComment.comment,
- comment_date: newComment.createdAt,
- comment_type: 'block_comment',
- comment_author: currentUser,
- comment_approved: 0,
- },
- } ).then( (response) => {
- const threadId = response?.id;
- setAttributes( clientId, threadId );
- setInputComment('');
- //onClose();
- } );
- };
-
- // Function to edit the comment.
- const editComment = ( commentId ) => {
- const editedComments = { ...allThreads };
-
- if (
- editedComments[ threadId ] &&
- editedComments[ threadId ].comments
- ) {
- editedComments[ threadId ].comments.map( ( comment ) => {
- if ( comment.commentId === commentId ) {
- comment.comment = inputComment;
- comment.date = new Date().toISOString();
- }
- return comment;
- } );
- }
-
- setInputComment( '' );
- setIsEditing( null );
- };
-
- // Function to mark thread as resolved
- const markThreadAsResolved = () => {
- setIsResolved( true );
-
- const updatedComments = { ...allThreads };
-
- updatedComments[ threadId ] = {
- ...updatedComments[ threadId ],
- isResolved: true,
- resolvedBy: currentUser,
- resolvedAt: new Date().toISOString(),
- };
-
- onClose();
- };
-
- // Function to delete a comment.
- const deleteComment = ( commentId ) => {
- // Filter out the comment to be deleted.
- const currentComments = allThreads[ threadId ].comments.filter(
- ( comment ) => comment.commentId !== commentId
- );
-
- const updatedComments = { ...allThreads };
-
- // If there are no comments, delete the thread.
- if ( currentComments.length === 0 ) {
- delete updatedComments[ threadId ];
- } else {
- updatedComments[ threadId ] = {
- ...allThreads[ threadId ],
- comments: currentComments,
- };
- }
- };
-
- // Function to show the confirmation overlay.
- const showConfirmationOverlay = () => setShowConfirmation( true );
-
- // Function to hide the confirmation overlay.
- const hideConfirmationOverlay = () => setShowConfirmation( false );
-
-
- // On cancel, remove the border if no comments are present.
- const handleCancel = () => {
- closeGeneralSidebar("edit-post/collab-sidebar");
- };
-
+ const resultThreads = selectedThreads.map( ( thread ) => thread ).reverse();
return (
-
- { null !== clientId && 0 === blockCommentId && (
-
- { 0 < commentsCount && ! isCurrentThreadResolved && (
- <>
- { currentThread.comments.map(
- (
- {
- createdBy,
- comment,
- timestamp,
- commentId,
- },
- index
- ) => (
- <>
- { isEditing === commentId && (
-
-
-
-
- { currentUser }
-
-
-
- setInputComment( val )
- }
- placeholder={ __(
- 'Add comment'
- ) }
- className="block-editor-format-toolbar__comment-input"
- />
-
- {
- setIsEditing(
- false
- );
- setInputComment(
- ''
- );
- } }
- />
-
- editComment(
- commentId
- )
- }
- />
-
-
- ) }
- { isEditing !== commentId && (
-
-
-
-
-
-
- { createdBy }
-
-
-
-
-
- { index === 0 && (
-
-
- showConfirmationOverlay()
- }
- label={ __(
- 'Resolve'
- ) }
- />
-
- ) }
- {
- setIsEditing(
- commentId
- );
- setInputComment(
- comment
- );
- } }
- />
-
- deleteComment(
- commentId
- )
- }
- />
-
-
-
- { comment }
-
-
- ) }
- >
- )
- ) }
- >
- ) }
- { ! isEditing && (
-
- { 0 === commentsCount && (
-
-
-
- { currentUser }
-
-
- ) }
- setInputComment( val ) }
- placeholder={ __( 'Add comment' ) }
- className="block-editor-format-toolbar__comment-input"
- />
-
- handleCancel() }
- />
- saveComment() }
- />
-
-
- ) }
-
- )
- }
-
- {
- // If there are no threads, show a message indicating no threads are available.
- (!Array.isArray(resultThreads) || resultThreads.length === 0) && (
-
-
- { __( 'No comments available' ) }
-
-
- )
- }
- { Array.isArray(resultThreads) && resultThreads.length > 0 &&
- resultThreads.reverse().map((thread) => (
-
-
-
-
-
- { thread.author_name }
-
-
-
-
- { thread.status !== 'approved' &&
-
-
-
- {
- setCommentConfirmation( false );
- setShowConfirmation( true )
- setShowConfirmationTabId( thread.id )
- }
- } />
-
-
- { 0 === thread.parent ? (
- {
- setShowConfirmationTabId( thread.id );
- onEditComment( thread.id );
- }
- },
- {
- title: __( 'Delete' ),
- onClick: () => {
- setCommentEdit( false );
- setShowConfirmationTabId( thread.id );
- setDeleteCommentShowConfirmation( true );
- }
- },
- {
- title: __( 'Reply' ),
- onClick: () => {
- setShowConfirmationTabId( thread.id );
- onReplyComment( thread.id );
- }
- },
- ] }
- />
- ) : (
- {
- setShowConfirmationTabId( thread.id );
- onEditComment( thread.id );
- }
- },
- {
- title: __( 'Delete' ),
- onClick: () => {
- setCommentEdit( false );
- setShowConfirmationTabId( thread.id );
- setDeleteCommentShowConfirmation( true );
- }
- },
- ] }
- />
- ) }
-
-
- }
- { thread.status === 'approved' &&
-
-
-
-
-
- }
-
-
-
-
- { commentEdit && thread.id === showConfirmationTabId && (
- <>
- /g, '') : thread.content.rendered.replace(/<\/?p>/g, '') }
- onChange={ ( value ) => {
- setNewEditedComment( value );
- } }
- />
- setCommentEdit( false ) }
- >
-
- {
- confirmEditComment( thread.id );
- setCommentEdit( false );
- } }
- >
- { __( 'Update' ) }
-
- {
- setCommentEdit( false );
- setShowConfirmation( false );
- } }
- >
- { __( 'Cancel' ) }
-
-
-
- >
- ) }
-
- { thread.content.rendered }
-
-
-
-
- { hasCommentReply && thread.id === showConfirmationTabId && (
-
-
- {
- setCommentReply( value );
- } }
- />
- setHasCommentReply( false ) }
- >
-
- {
- confirmReplyComment( thread.id );
- setHasCommentReply( false );
- } }
- className="is-compact"
- >
- { __( 'Reply' ) }
-
- {
- setHasCommentReply( false );
- setShowConfirmation( false );
- } }
- className="is-compact"
- >
- { __( 'Cancel' ) }
-
-
-
-
-
- ) }
-
- { commentConfirmation && thread.id === showConfirmationTabId && (
-
- { __( 'Thread marked as resolved.' ) }
-
- ) }
- { commentEditedMessage && thread.id === showConfirmationTabId && (
-
- { __( 'Thread edited successfully.' ) }
-
- ) }
- { commentDeleteMessage && thread.id === showConfirmationTabId && (
-
- { __( 'Thread deleted successfully.' ) }
-
- ) }
- { replyMessage && thread.id === showConfirmationTabId && (
-
- { __( 'Reply added successfully.' ) }
-
- ) }
-
- { showConfirmation && thread.id === showConfirmationTabId && (
- setShowConfirmation( false ) }
- className="editor-collab-sidebar__useroverlay confirmation-overlay"
- spacing="0"
- justify="space-between"
- >
-
- { __(
- 'Are you sure you want to mark this thread as resolved?'
- ) }
-
-
- confirmAndMarkThreadAsResolved( thread.id ) }
- >
- { __( 'Yes' ) }
-
- setShowConfirmation( false ) }>
- { __( 'No' ) }
-
-
-
- ) }
-
- { deleteCommentShowConfirmation && thread.id === showConfirmationTabId && (
- setDeleteCommentShowConfirmation( false ) }
- className="editor-collab-sidebar__useroverlay confirmation-overlay"
- spacing="0"
- justify="space-between"
- >
-
- { __(
- 'Are you sure you want to delete this thread?'
- ) }
-
-
- confirmDeleteComment( thread.id ) }
- >
- { __( 'Yes' ) }
-
- setDeleteCommentShowConfirmation( false ) }>
- { __( 'No' ) }
-
-
-
- ) }
-
- { 0 < thread.reply.length && (
- thread.reply.map((reply) => (
-
-
-
-
-
- { reply.author_name }
-
-
-
-
- { reply.status !== 'approved' &&
-
- { 0 === reply.parent && (
- {
- setShowConfirmationTabId( reply.id );
- onEditComment( reply.id );
- }
- },
- {
- title: __( 'Delete' ),
- onClick: () => {
- setCommentEdit( false );
- setShowConfirmationTabId( reply.id );
- setDeleteCommentShowConfirmation( true );
- }
- },
- {
- title: __( 'Reply' ),
- onClick: () => {
- setShowConfirmationTabId( reply.id );
- onReplyComment( reply.id );
- }
- },
- ] }
- />
- ) }
-
- { 0 !== reply.parent && thread.status !== 'approved' && (
- {
- setShowConfirmationTabId( reply.id );
- onEditComment( reply.id );
- }
- },
- {
- title: __( 'Delete' ),
- onClick: () => {
- setCommentEdit( false );
- setShowConfirmationTabId( reply.id );
- setDeleteCommentShowConfirmation( true );
- }
- },
- ] }
- />
- ) }
-
-
- }
-
-
-
-
- { commentEdit && reply.id === showConfirmationTabId && (
- <>
- /g, '') : reply.content.rendered.replace(/<\/?p>/g, '') }
- onChange={ ( value ) => {
- setNewEditedComment( value );
- } }
- />
- setCommentEdit( false ) }
- >
-
- {
- confirmEditComment( reply.id );
- setCommentEdit( false );
- } }
- >
- { __( 'Update' ) }
-
- {
- setCommentEdit( false );
- setShowConfirmation( false );
- } }
- >
- { __( 'Cancel' ) }
-
-
-
- >
- ) }
-
- { reply.content.rendered }
-
-
-
-
- { hasCommentReply && reply.id === showConfirmationTabId && (
-
-
- {
- setCommentReply( value );
- } }
- />
- setHasCommentReply( false ) }
- >
-
- {
- confirmReplyComment( reply.id );
- setHasCommentReply( false );
- } }
- className="is-compact"
- >
- { __( 'Reply' ) }
-
- {
- setHasCommentReply( false );
- setShowConfirmation( false );
- } }
- className="is-compact"
- >
- { __( 'Cancel' ) }
-
-
-
-
-
- ) }
-
- { commentConfirmation && reply.id === showConfirmationTabId && (
-
- { __( 'Thread marked as resolved.' ) }
-
- ) }
- { commentEditedMessage && reply.id === showConfirmationTabId && (
-
- { __( 'Thread edited successfully.' ) }
-
- ) }
- { commentDeleteMessage && reply.id === showConfirmationTabId && (
-
- { __( 'Thread deleted successfully.' ) }
-
- ) }
- { replyMessage && reply.id === showConfirmationTabId && (
-
- { __( 'Reply added successfully.' ) }
-
- ) }
-
- { showConfirmation && reply.id === showConfirmationTabId && (
- setShowConfirmation( false ) }
- className="editor-collab-sidebar__useroverlay confirmation-overlay"
- spacing="0"
- justify="space-between"
- >
-
- { __(
- 'Are you sure you want to mark this thread as resolved?'
- ) }
-
-
- confirmAndMarkThreadAsResolved( reply.id ) }
- >
- { __( 'Yes' ) }
-
- setShowConfirmation( false ) }>
- { __( 'No' ) }
-
-
-
- ) }
-
- { deleteCommentShowConfirmation && reply.id === showConfirmationTabId && (
- setDeleteCommentShowConfirmation( false ) }
- className="editor-collab-sidebar__useroverlay confirmation-overlay"
- spacing="0"
- justify="space-between"
- >
-
- { __(
- 'Are you sure you want to delete this thread?'
- ) }
-
-
- confirmDeleteComment( reply.id ) }
- >
- { __( 'Yes' ) }
-
- setDeleteCommentShowConfirmation( false ) }>
- { __( 'No' ) }
-
-
-
- ) }
-
-
-
- ))
- ) }
-
-
- ))
- }
-
+
+
);
diff --git a/packages/editor/src/components/collab-sidebar/style.scss b/packages/editor/src/components/collab-sidebar/style.scss
index bb4c8fde25893..6c8b582ba0731 100644
--- a/packages/editor/src/components/collab-sidebar/style.scss
+++ b/packages/editor/src/components/collab-sidebar/style.scss
@@ -1,174 +1,174 @@
.editor-collab-sidebar {
- &__activities {
- padding: 16px;
- background-color: #f9f9f9;
- }
-
- &__thread {
- position: relative;
- padding: 16px;
- border-radius: 8px;
- border: 1px solid $gray-300;
- background-color: $gray-100;
- margin-bottom: 16px;
-
- .components-base-control__field {
- margin-bottom: 0
- }
-
- input[type=text] {
- @include input-control;
- border-radius: 6px;
- padding: 8px 15px;
- }
- }
-
- &__activethread {
- border: 1.5px solid #3858E9;
- background-color: $white;
- box-shadow: 0px 5.5px 7.8px -0.3px rgba(0, 0, 0, 0.102);
- }
-
-
- &__editarea,
- &__replyComment {
- flex: 1;
-
- &__textarea{
- width: 100%;
- }
-
- .components-textarea-control__input {
- border: 1px solid $gray-300;
- border-radius: 8px;
- padding: 10px 15px;
- background-color: $gray-100;
- }
- }
-
- &__childThread {
- margin-top: 15px;
- }
-
- &__userName {
- font-size: 12px;
- font-weight: 400;
- line-height: 16px;
- text-align: left;
- color: $gray-700;
- text-transform: capitalize;
- }
-
- &__usertime {
- font-size: 12px;
- font-weight: 400;
- line-height: 16px;
- text-align: left;
- color: $gray-700;
- }
-
- &__usercomment {
- font-size: 13px;
- font-weight: 400;
- line-height: 20px;
- text-align: left;
- color: $gray-900;
-
- p {
- margin-bottom: 0;
- }
- }
-
- &__userIcon {
- border-radius: 50%;
- flex-shrink: 0;
- }
-
- &__userstatus {
- button {
- font-size: 12px;
- font-weight: 400;
- line-height: 16px;
- padding: 0;
- height: auto;
- box-shadow: none;
- outline: none;
- }
- }
-
- &__useroverlay {
- background-color: rgba(0, 0, 0, 0.7);
- width: 100%;
- height: 100%;
- text-align: center;
- position: absolute;
- top: 0;
- left: 0;
- z-index: 1;
- padding: 15px;
- border-radius: 8px;
- color: $white;
-
- p {
- margin-bottom: 15px;
- }
-
- button {
- height: 24px;
- padding: 6px;
- color: $white;
- }
- }
-
- &__resolvedIcon {
- fill: #008000;
- border-radius: 50%;
- width: 18px;
- height: 18px;
- border: 1px solid #008000;
- margin-right: 2px;
- margin-top: 5px;
- }
-
- &__commentUpdate {
- margin-left: auto;
-
- .components-button {
- &.is-compact {
- &.has-icon:not(.has-text) {
- min-width: 24px;
- padding: 0;
- width: 24px;
- height: 24px;
- flex-shrink: 0;
- }
- }
- }
-
- .components-dropdown {
- &.is-compact {
- flex-shrink: 0;
-
- .components-button {
- min-width: 24px;
- padding: 0;
- width: 24px;
- height: 24px;
- }
- }
- }
- }
-
- &__resolvedText {
- font-style: italic;
- font-weight: 500 !important;
- color: #808080 !important;
- margin-top: 5px !important;
- }
+ &__activities {
+ padding: 16px;
+ background-color: #f9f9f9;
+ }
+
+ &__thread {
+ position: relative;
+ padding: 16px;
+ border-radius: 8px;
+ border: 1px solid $gray-300;
+ background-color: $gray-100;
+ margin-bottom: 16px;
+
+ .components-base-control__field {
+ margin-bottom: 0;
+ }
+
+ input[type="text"] {
+ @include input-control;
+ border-radius: 6px;
+ padding: 8px 15px;
+ }
+ }
+
+ &__activethread {
+ border: 1.5px solid #3858e9;
+ background-color: $white;
+ box-shadow: 0 5.5px 7.8px -0.3px rgba(0, 0, 0, 0.102);
+ }
+
+
+ &__editarea,
+ &__replyComment {
+ flex: 1;
+
+ &__textarea {
+ width: 100%;
+ }
+
+ .components-textarea-control__input {
+ border: 1px solid $gray-300;
+ border-radius: 8px;
+ padding: 10px 15px;
+ background-color: $gray-100;
+ }
+ }
+
+ &__childThread {
+ margin-top: 15px;
+ }
+
+ &__userName {
+ font-size: 12px;
+ font-weight: 400;
+ line-height: 16px;
+ text-align: left;
+ color: $gray-700;
+ text-transform: capitalize;
+ }
+
+ &__usertime {
+ font-size: 12px;
+ font-weight: 400;
+ line-height: 16px;
+ text-align: left;
+ color: $gray-700;
+ }
+
+ &__usercomment {
+ font-size: 13px;
+ font-weight: 400;
+ line-height: 20px;
+ text-align: left;
+ color: $gray-900;
+
+ p {
+ margin-bottom: 0;
+ }
+ }
+
+ &__userIcon {
+ border-radius: 50%;
+ flex-shrink: 0;
+ }
+
+ &__userstatus {
+ button {
+ font-size: 12px;
+ font-weight: 400;
+ line-height: 16px;
+ padding: 0;
+ height: auto;
+ box-shadow: none;
+ outline: none;
+ }
+ }
+
+ &__useroverlay {
+ background-color: rgba(0, 0, 0, 0.7);
+ width: 100%;
+ height: 100%;
+ text-align: center;
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 1;
+ padding: 15px;
+ border-radius: 8px;
+ color: $white;
+
+ p {
+ margin-bottom: 15px;
+ }
+
+ button {
+ height: 24px;
+ padding: 6px;
+ color: $white;
+ }
+ }
+
+ &__resolvedIcon {
+ fill: #008000;
+ border-radius: 50%;
+ width: 18px;
+ height: 18px;
+ border: 1px solid #008000;
+ margin-right: 2px;
+ margin-top: 5px;
+ }
+
+ &__commentUpdate {
+ margin-left: auto;
+
+ .components-button {
+ &.is-compact {
+ &.has-icon:not(.has-text) {
+ min-width: 24px;
+ padding: 0;
+ width: 24px;
+ height: 24px;
+ flex-shrink: 0;
+ }
+ }
+ }
+
+ .components-dropdown {
+ &.is-compact {
+ flex-shrink: 0;
+
+ .components-button {
+ min-width: 24px;
+ padding: 0;
+ width: 24px;
+ height: 24px;
+ }
+ }
+ }
+ }
+
+ &__resolvedText {
+ font-style: italic;
+ font-weight: 500 !important;
+ color: #808080 !important;
+ margin-top: 5px !important;
+ }
}
.is-collab-block-selected {
- background-color: color-mix( in srgb, currentColor 5%, #182F97 20% );
+ background-color: color-mix(in srgb, currentColor 5%, #182f97 20%);
}
.block-editor-format-toolbar__comment-board {
diff --git a/packages/format-library/package.json b/packages/format-library/package.json
index 7ea25a917549d..531ec71224ce7 100644
--- a/packages/format-library/package.json
+++ b/packages/format-library/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/format-library",
- "version": "5.1.0",
+ "version": "5.6.0",
"description": "Format library for the WordPress editor.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
@@ -31,10 +31,7 @@
"@wordpress/block-editor": "file:../block-editor",
"@wordpress/components": "file:../components",
"@wordpress/compose": "file:../compose",
- "@wordpress/core-data": "file:../core-data",
"@wordpress/data": "file:../data",
- "@wordpress/date": "file:../date",
- "@wordpress/editor": "file:../editor",
"@wordpress/element": "file:../element",
"@wordpress/html-entities": "file:../html-entities",
"@wordpress/i18n": "file:../i18n",