Skip to content

Commit

Permalink
Feedback change- Using Modal & page selection befor trashing
Browse files Browse the repository at this point in the history
  • Loading branch information
benazeer-ben committed Jan 8, 2025
1 parent 598b229 commit 55dd26f
Showing 1 changed file with 179 additions and 124 deletions.
303 changes: 179 additions & 124 deletions packages/fields/src/actions/trash-post.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,21 @@ import { useDispatch, select } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { __, _n, sprintf, _x } from '@wordpress/i18n';
import { store as noticesStore } from '@wordpress/notices';
import { useState } from '@wordpress/element';
import { useState, useEffect } from '@wordpress/element';
import {
Button,
__experimentalText as Text,
__experimentalHStack as HStack,
__experimentalVStack as VStack,
SelectControl,
} from '@wordpress/components';
import type { Action } from '@wordpress/dataviews';

/**
* Internal dependencies
*/
import { getItemTitle, isTemplateOrTemplatePart } from './utils';
import type { CoreDataError, PostWithPermissions } from '../types';
import { isTemplateOrTemplatePart } from './utils';
import type { PostWithPermissions } from '../types';

const trashPost: Action< PostWithPermissions > = {
id: 'move-to-trash',
Expand All @@ -41,25 +42,141 @@ const trashPost: Action< PostWithPermissions > = {
hideModalHeader: true,
RenderModal: ( { items, closeModal, onActionPerformed } ) => {
const [ isBusy, setIsBusy ] = useState( false );
const [ availablePages, setAvailablePages ] = useState<
Array< { id: number; title: { rendered: string } } >
>( [] );
const [ selectedHomepage, setSelectedHomepage ] = useState<
string | undefined
>( '' );
const [ selectedPostsPage, setSelectedPostsPage ] = useState<
string | undefined
>( '' );
const { createSuccessNotice, createErrorNotice } =
useDispatch( noticesStore );
const { deleteEntityRecord } = useDispatch( coreStore );
const { saveEntityRecord, deleteEntityRecord } =
useDispatch( coreStore );

// Fetch front page and posts page IDs
const frontPageId = (
select( coreStore ).getEntityRecord( 'root', 'site' ) as {
page_on_front?: number;
}
)?.page_on_front;

const postsPageId = (
select( coreStore ).getEntityRecord( 'root', 'site' ) as {
page_for_posts?: number;
}
)?.page_for_posts;

const isSpecialPage = items.some(
( item ) => item.id === frontPageId || item.id === postsPageId
const isTrashingHomePage = items.some(
( item ) => item.id === frontPageId
);
const isTrashingPostsPage = items.some(
( item ) => item.id === postsPageId
);

// Fetch available pages excluding the trashed one and posts page for homepage dropdown
useEffect( () => {
const fetchPages = async () => {
const pages = await select( coreStore ).getEntityRecords< {
id: number;
title: { rendered: string };
} >( 'postType', 'page', { per_page: -1 } );
setAvailablePages(
pages?.filter( ( page ) => {
const isTrashedPage = items.some(
( item ) => item.id === page.id
);
const isExcludedForHomepage =
( isTrashingHomePage && page.id === postsPageId ) ||
page.id === frontPageId;
return ! isTrashedPage && ! isExcludedForHomepage;
} ) || []
);
};
fetchPages();
}, [ items, isTrashingHomePage, postsPageId, frontPageId ] );

const handleDelete = async () => {
setIsBusy( true );
try {
// Update site settings for homepage or posts page
if ( isTrashingHomePage && selectedHomepage ) {
await saveEntityRecord( 'root', 'site', {
page_on_front: parseInt( selectedHomepage, 10 ),
} );
}
if ( isTrashingPostsPage && selectedPostsPage ) {
await saveEntityRecord( 'root', 'site', {
page_for_posts: parseInt( selectedPostsPage, 10 ),
} );
}

// Perform delete actions
const promiseResult = await Promise.allSettled(
items.map( ( item ) =>
deleteEntityRecord(
'postType',
item.type,
item.id.toString(),
{},
{ throwOnError: true }
)
)
);

if (
promiseResult.every(
( { status } ) => status === 'fulfilled'
)
) {
const successMessage =
promiseResult.length === 1
? sprintf(
// translators: %s: The item's title.
__( '"%s" moved to the trash.' ),
typeof items[ 0 ].title === 'object' &&
'rendered' in items[ 0 ].title
? items[ 0 ].title.rendered
: items[ 0 ].title
)
: sprintf(
// translators: %d: number of items to move to the trash.
_n(
'%s item moved to the trash.',
'%s items moved to the trash.',
items.length
),
items.length
);
createSuccessNotice( successMessage, {
type: 'snackbar',
id: 'move-to-trash-action',
} );
} else {
createErrorNotice(
__(
'An error occurred while moving the items to the trash.'
),
{ type: 'snackbar' }
);
}

if ( onActionPerformed ) {
onActionPerformed( items );
}
} catch ( error ) {
createErrorNotice(
__( 'An error occurred while deleting the item.' ),
{ type: 'snackbar' }
);
} finally {
setIsBusy( false );
closeModal?.();
}
};

return (
<VStack spacing="5">
<Text>
Expand All @@ -69,7 +186,10 @@ const trashPost: Action< PostWithPermissions > = {
__(
'Are you sure you want to move "%s" to the trash?'
),
getItemTitle( items[ 0 ] )
typeof items[ 0 ]?.title === 'object' &&
'rendered' in items[ 0 ].title
? items[ 0 ].title.rendered
: items[ 0 ]?.title || ''
)
: sprintf(
// translators: %d: The number of items (2 or more).
Expand All @@ -81,18 +201,53 @@ const trashPost: Action< PostWithPermissions > = {
items.length
) }
</Text>
{ isSpecialPage && (
<Text style={ { color: 'red' } }>
{ items.some( ( item ) => item.id === frontPageId ) &&
__(
'This page is currently set as the Home Page. Please select another page as the Front Page before deleting this one.'
{ ( isTrashingHomePage || isTrashingPostsPage ) &&
availablePages.length > 0 && (
<>
{ isTrashingHomePage && (
<SelectControl
__next40pxDefaultSize
__nextHasNoMarginBottom
label={ __( 'Choose a new homepage' ) }
value={ selectedHomepage }
options={ [
{
value: '',
label: __( 'Select a page' ),
},
...availablePages.map( ( page ) => ( {
value: page.id.toString(),
label: page.title.rendered,
} ) ),
] }
onChange={ ( value ) =>
setSelectedHomepage( value )
}
/>
) }
{ items.some( ( item ) => item.id === postsPageId ) &&
__(
'This page is currently set as the Posts Page. Please select another page as the Posts Page before deleting this one.'
{ isTrashingPostsPage && (
<SelectControl
__next40pxDefaultSize
__nextHasNoMarginBottom
label={ __( 'Choose a new posts page' ) }
value={ selectedPostsPage }
options={ [
{
value: '',
label: __( 'Select a page' ),
},
...availablePages.map( ( page ) => ( {
value: page.id.toString(),
label: page.title.rendered,
} ) ),
] }
onChange={ ( value ) =>
setSelectedPostsPage( value )
}
/>
) }
</Text>
) }
</>
) }
<HStack justify="right">
<Button
__next40pxDefaultSize
Expand All @@ -105,115 +260,15 @@ const trashPost: Action< PostWithPermissions > = {
</Button>
<Button
__next40pxDefaultSize
accessibleWhenDisabled
variant="primary"
onClick={ async () => {
setIsBusy( true );
const promiseResult = await Promise.allSettled(
items.map( ( item ) =>
deleteEntityRecord(
'postType',
item.type,
item.id.toString(),
{},
{ throwOnError: true }
)
)
);
// If all the promises were fulfilled with success.
if (
promiseResult.every(
( { status } ) => status === 'fulfilled'
)
) {
let successMessage;
if ( promiseResult.length === 1 ) {
successMessage = sprintf(
/* translators: The item's title. */
__( '"%s" moved to the trash.' ),
getItemTitle( items[ 0 ] )
);
} else {
successMessage = sprintf(
/* translators: The number of items. */
_n(
'%s item moved to the trash.',
'%s items moved to the trash.',
items.length
),
items.length
);
}
createSuccessNotice( successMessage, {
type: 'snackbar',
id: 'move-to-trash-action',
} );
} else {
// If there was at least one failure.
let errorMessage;
// If we were trying to delete a single item.
if ( promiseResult.length === 1 ) {
const typedError = promiseResult[ 0 ] as {
reason?: CoreDataError;
};
if ( typedError.reason?.message ) {
errorMessage =
typedError.reason.message;
} else {
errorMessage = __(
'An error occurred while moving the item to the trash.'
);
}
// If we were trying to delete multiple items.
} else {
const errorMessages = new Set();
const failedPromises = promiseResult.filter(
( { status } ) => status === 'rejected'
);
for ( const failedPromise of failedPromises ) {
const typedError = failedPromise as {
reason?: CoreDataError;
};
if ( typedError.reason?.message ) {
errorMessages.add(
typedError.reason.message
);
}
}
if ( errorMessages.size === 0 ) {
errorMessage = __(
'An error occurred while moving the items to the trash.'
);
} else if ( errorMessages.size === 1 ) {
errorMessage = sprintf(
/* translators: %s: an error message */
__(
'An error occurred while moving the item to the trash: %s'
),
[ ...errorMessages ][ 0 ]
);
} else {
errorMessage = sprintf(
/* translators: %s: a list of comma separated error messages */
__(
'Some errors occurred while moving the items to the trash: %s'
),
[ ...errorMessages ].join( ',' )
);
}
}
createErrorNotice( errorMessage, {
type: 'snackbar',
} );
}
if ( onActionPerformed ) {
onActionPerformed( items );
}
setIsBusy( false );
closeModal?.();
} }
isBusy={ isBusy }
disabled={ isBusy || isSpecialPage }
accessibleWhenDisabled
disabled={
isBusy ||
( isTrashingHomePage && ! selectedHomepage ) ||
( isTrashingPostsPage && ! selectedPostsPage )
}
onClick={ handleDelete }
>
{ _x( 'Trash', 'verb' ) }
</Button>
Expand Down

0 comments on commit 55dd26f

Please sign in to comment.