Skip to content

Commit

Permalink
DataViews: Type the BulkActions component (#61666)
Browse files Browse the repository at this point in the history
Co-authored-by: youknowriad <[email protected]>
Co-authored-by: jorgefilipecosta <[email protected]>
  • Loading branch information
3 people authored May 14, 2024
1 parent 995a293 commit bfba381
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { useMemo, useState, useCallback, useEffect } from '@wordpress/element';
* Internal dependencies
*/
import { unlock } from './lock-unlock';
import type { Action, ActionModal, Data, Item } from './types';

const {
DropdownMenuV2: DropdownMenu,
Expand All @@ -21,19 +22,55 @@ const {
DropdownMenuSeparatorV2: DropdownMenuSeparator,
} = unlock( componentsPrivateApis );

export function useHasAPossibleBulkAction( actions, item ) {
interface ActionWithModalProps {
action: ActionModal;
selectedItems: Item[];
setActionWithModal: ( action?: ActionModal ) => void;
onMenuOpenChange: ( isOpen: boolean ) => void;
}

interface BulkActionsItemProps {
action: Action;
selectedItems: Item[];
setActionWithModal: ( action?: ActionModal ) => void;
}

interface ActionsMenuGroupProps {
actions: Action[];
selectedItems: Item[];
setActionWithModal: ( action?: ActionModal ) => void;
}

interface BulkActionsProps {
data: Data;
actions: Action[];
selection: string[];
onSelectionChange: ( selection: Item[] ) => void;
getItemId: ( item: Item ) => string;
}

export function useHasAPossibleBulkAction( actions: Action[], item: Item ) {
return useMemo( () => {
return actions.some( ( action ) => {
return action.supportsBulk && action.isEligible( item );
return (
action.supportsBulk &&
( ! action.isEligible || action.isEligible( item ) )
);
} );
}, [ actions, item ] );
}

export function useSomeItemHasAPossibleBulkAction( actions, data ) {
export function useSomeItemHasAPossibleBulkAction(
actions: Action[],
data: Data
) {
return useMemo( () => {
return data.some( ( item ) => {
return actions.some( ( action ) => {
return action.supportsBulk && action.isEligible( item );
return (
action.supportsBulk &&
( ! action.isEligible || action.isEligible( item ) )
);
} );
} );
}, [ actions, data ] );
Expand All @@ -44,36 +81,44 @@ function ActionWithModal( {
selectedItems,
setActionWithModal,
onMenuOpenChange,
} ) {
}: ActionWithModalProps ) {
const eligibleItems = useMemo( () => {
return selectedItems.filter( ( item ) => action.isEligible( item ) );
return selectedItems.filter(
( item ) => ! action.isEligible || action.isEligible( item )
);
}, [ action, selectedItems ] );
const { RenderModal, hideModalHeader } = action;
const onCloseModal = useCallback( () => {
setActionWithModal( undefined );
}, [ setActionWithModal ] );
return (
<Modal
title={ ! hideModalHeader && action.label }
title={ ! hideModalHeader ? action.label : undefined }
__experimentalHideHeader={ !! hideModalHeader }
onRequestClose={ onCloseModal }
overlayClassName="dataviews-action-modal"
>
<RenderModal
items={ eligibleItems }
closeModal={ onCloseModal }
onPerform={ () => onMenuOpenChange( false ) }
onActionPerformed={ () => onMenuOpenChange( false ) }
/>
</Modal>
);
}

function BulkActionItem( { action, selectedItems, setActionWithModal } ) {
function BulkActionItem( {
action,
selectedItems,
setActionWithModal,
}: BulkActionsItemProps ) {
const eligibleItems = useMemo( () => {
return selectedItems.filter( ( item ) => action.isEligible( item ) );
return selectedItems.filter(
( item ) => ! action.isEligible || action.isEligible( item )
);
}, [ action, selectedItems ] );

const shouldShowModal = !! action.RenderModal;
const shouldShowModal = 'RenderModal' in action;

return (
<DropdownMenuItem
Expand All @@ -96,7 +141,11 @@ function BulkActionItem( { action, selectedItems, setActionWithModal } ) {
);
}

function ActionsMenuGroup( { actions, selectedItems, setActionWithModal } ) {
function ActionsMenuGroup( {
actions,
selectedItems,
setActionWithModal,
}: ActionsMenuGroupProps ) {
return (
<>
<DropdownMenuGroup>
Expand All @@ -120,16 +169,20 @@ export default function BulkActions( {
selection,
onSelectionChange,
getItemId,
} ) {
}: BulkActionsProps ) {
const bulkActions = useMemo(
() => actions.filter( ( action ) => action.supportsBulk ),
[ actions ]
);
const [ isMenuOpen, onMenuOpenChange ] = useState( false );
const [ actionWithModal, setActionWithModal ] = useState();
const [ actionWithModal, setActionWithModal ] = useState<
ActionModal | undefined
>();
const selectableItems = useMemo( () => {
return data.filter( ( item ) => {
return bulkActions.some( ( action ) => action.isEligible( item ) );
return bulkActions.some(
( action ) => ! action.isEligible || action.isEligible( item )
);
} );
}, [ data, bulkActions ] );

Expand Down
5 changes: 5 additions & 0 deletions packages/dataviews/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ interface ActionBase {
* Whether the item passed as an argument supports the current action.
*/
isEligible?: ( item: Item ) => boolean;

/**
* Whether the action can be used as a bulk action.
*/
supportsBulk?: boolean;
}

export interface ActionModal extends ActionBase {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export const deleteAction = {
},
hideModalHeader: true,
supportsBulk: true,
RenderModal: ( { items, closeModal, onPerform } ) => {
RenderModal: ( { items, closeModal, onActionPerformed } ) => {
const { __experimentalDeleteReusableBlock } =
useDispatch( reusableBlocksStore );
const { createErrorNotice, createSuccessNotice } =
Expand Down Expand Up @@ -191,8 +191,8 @@ export const deleteAction = {
} else {
deletePattern();
}
if ( onPerform ) {
onPerform();
if ( onActionPerformed ) {
onActionPerformed();
}
closeModal();
};
Expand Down

0 comments on commit bfba381

Please sign in to comment.