/**
* External dependencies
*/
import { useBreakpointMatch } from '@automattic/jetpack-components';
import JetpackLogo from '@automattic/jetpack-components/jetpack-logo';
import { Breadcrumbs } from '@wordpress/admin-ui';
import { DropdownMenu, Button } from '@wordpress/components';
import { store as coreDataStore } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import { useMemo } from '@wordpress/element';
import { decodeEntities } from '@wordpress/html-entities';
import { __, sprintf } from '@wordpress/i18n';
import { moreVertical } from '@wordpress/icons';
import { Badge, Stack } from '@wordpress/ui';
/**
* Internal dependencies
*/
import CreateFormButton from '../../components/create-form-button';
import EditFormButton from '../../components/edit-form-button';
import EmptySpamButton from '../../components/empty-spam-button';
import EmptySpamConfirmationModal from '../../components/empty-spam-button/confirmation-modal';
import EmptyTrashButton from '../../components/empty-trash-button';
import EmptyTrashConfirmationModal from '../../components/empty-trash-button/confirmation-modal';
import ExportResponsesButton from '../../components/export-responses/button';
import ExportResponsesModal from '../../components/export-responses/modal';
import useCreateForm from '../../hooks/use-create-form';
import useEmptySpam from '../../hooks/use-empty-spam';
import useEmptyTrash from '../../hooks/use-empty-trash';
import useExportResponses from '../../hooks/use-export-responses';
import useInboxData from '../../hooks/use-inbox-data';
import ManageIntegrationsButton from '../components/manage-integrations-button';
import useFormItemActions from './use-form-item-actions';
import type { ReactNode } from 'react';
type ResponsesStatusView = 'inbox' | 'spam' | 'trash';
type UsePageHeaderDetailsProps = {
screen: 'forms' | 'responses';
statusView?: ResponsesStatusView;
sourceId?: string | number;
formsCount?: number;
isIntegrationsEnabled: boolean;
showDashboardIntegrations: boolean;
onOpenIntegrations: () => void;
onOpenFormsHelp?: () => void;
};
type UsePageHeaderDetailsReturn = {
breadcrumbs: ReactNode;
badges?: ReactNode;
subtitle: ReactNode;
actions?: ReactNode;
};
/**
* Build wp-build page header details (breadcrumbs, subtitle, actions).
*
* This hook is intentionally scoped to just what is passed into the wp-build ``
* component to keep route files readable.
*
* @param props - Props.
* @return Page header details.
*/
export default function usePageHeaderDetails(
props: UsePageHeaderDetailsProps
): UsePageHeaderDetailsReturn {
const {
screen,
sourceId,
formsCount,
isIntegrationsEnabled,
showDashboardIntegrations,
onOpenIntegrations,
onOpenFormsHelp,
} = props;
const statusView: ResponsesStatusView = props.statusView ?? 'inbox';
const sourceIdNumber = useMemo( () => {
const value = sourceId;
const numberValue = typeof value === 'number' ? value : Number( value );
return Number.isFinite( numberValue ) && numberValue > 0 ? numberValue : null;
}, [ sourceId ] );
// Detect mobile viewport
const [ isSm ] = useBreakpointMatch( 'sm' );
// Mutually-exclusive screen flags.
const isFormsScreen = screen === 'forms';
const isSingleFormScreen = screen === 'responses' && sourceIdNumber !== null;
// Hooks for mobile dropdown menu actions
const { openNewForm } = useCreateForm();
const {
showExportModal,
openModal: openExportModal,
closeModal: closeExportModal,
onExport,
autoConnectGdrive,
exportLabel,
} = useExportResponses();
const { totalItems, isLoadingData } = useInboxData();
const hasResponses = ! isLoadingData && totalItems > 0;
// Empty spam/trash hooks
const emptySpam = useEmptySpam();
const emptyTrash = useEmptyTrash();
const formRecord = useSelect(
select =>
sourceIdNumber
? ( select( coreDataStore ).getEntityRecord(
'postType',
'jetpack_form',
sourceIdNumber
) as { title?: { rendered?: string }; status?: string } | undefined )
: undefined,
[ sourceIdNumber ]
);
const formTitle = useMemo( () => {
const rendered = formRecord?.title?.rendered || '';
return decodeEntities( rendered );
}, [ formRecord?.title?.rendered ] );
const formStatus = formRecord?.status;
const statusLabel = useMemo( () => {
switch ( formStatus ) {
case 'publish':
return __( 'Published', 'jetpack-forms' );
case 'draft':
return __( 'Draft', 'jetpack-forms' );
case 'pending':
return __( 'Pending review', 'jetpack-forms' );
case 'future':
return __( 'Scheduled', 'jetpack-forms' );
case 'private':
return __( 'Private', 'jetpack-forms' );
default:
return formStatus;
}
}, [ formStatus ] );
const badges = useMemo( () => {
if ( ! isSingleFormScreen || ! formStatus || formStatus === 'publish' ) {
return undefined;
}
return { statusLabel };
}, [ isSingleFormScreen, formStatus, statusLabel ] );
const { duplicateForm, previewForm, copyEmbed, copyShortcode } = useFormItemActions();
const formItemControls = useMemo( () => {
if ( ! sourceIdNumber ) {
return [];
}
const formItem = { id: sourceIdNumber, title: formTitle };
const controls: Array< { title: string; onClick: () => void } > = [
{
title: __( 'Duplicate', 'jetpack-forms' ),
onClick: () => duplicateForm( formItem ),
},
{
title: __( 'Preview', 'jetpack-forms' ),
onClick: () => previewForm( formItem ),
},
];
if ( navigator?.clipboard ) {
controls.push(
{
title: __( 'Copy embed', 'jetpack-forms' ),
onClick: () => copyEmbed( formItem ),
},
{
title: __( 'Copy shortcode', 'jetpack-forms' ),
onClick: () => copyShortcode( formItem ),
}
);
}
return controls;
}, [ sourceIdNumber, formTitle, duplicateForm, previewForm, copyEmbed, copyShortcode ] );
const breadcrumbsItems = useMemo( () => {
if ( isSingleFormScreen ) {
return [
{ label: __( 'Forms', 'jetpack-forms' ), to: '/forms' },
{ label: formTitle || __( 'Form responses', 'jetpack-forms' ) },
];
}
return [ { label: __( 'Forms', 'jetpack-forms' ) } ];
}, [ formTitle, isSingleFormScreen ] );
const breadcrumbs = useMemo( () => {
return (
);
}, [ breadcrumbsItems ] );
const subtitle = useMemo( () => {
if ( isFormsScreen ) {
const shortMessage = __( 'View and manage all your forms.', 'jetpack-forms' );
const longMessage = __( 'View and manage all your forms in one place.', 'jetpack-forms' );
const shouldShowFormsHelpLink =
!! onOpenFormsHelp && ( typeof formsCount !== 'number' || formsCount < 5 );
return shouldShowFormsHelpLink ? (
<>
{ shortMessage }{ ' ' }
>
) : (
longMessage
);
}
if ( isSingleFormScreen ) {
if ( formTitle ) {
return sprintf(
/* translators: %s: form name */
__( 'View responses for %s.', 'jetpack-forms' ),
formTitle
);
}
return __( 'View responses for this form.', 'jetpack-forms' );
}
return __( 'View and manage all your form responses in one place.', 'jetpack-forms' );
}, [ formTitle, isFormsScreen, isSingleFormScreen, onOpenFormsHelp, formsCount ] );
const actions = useMemo( () => {
// Mobile: show dropdown menu with actions
if ( isSm ) {
const dropdownControls = [];
if ( isFormsScreen ) {
// Forms screen: Manage integrations, Create a form
if ( isIntegrationsEnabled && showDashboardIntegrations ) {
dropdownControls.push( {
onClick: onOpenIntegrations,
title: __( 'Manage integrations', 'jetpack-forms' ),
} );
}
dropdownControls.push( {
onClick: () => openNewForm( {} ),
title: __( 'Create a form', 'jetpack-forms' ),
} );
} else if ( isSingleFormScreen ) {
// Single form screen: Edit form (not in trash/spam), Export, Empty trash/spam
if ( statusView === 'inbox' && sourceIdNumber ) {
dropdownControls.push( {
onClick: () => {
const fallbackEditUrl = `post.php?post=${ sourceIdNumber }&action=edit&post_type=jetpack_form`;
const url = new URL( fallbackEditUrl, window.location.origin );
window.location.href = url.toString();
},
title: __( 'Edit form', 'jetpack-forms' ),
} );
}
dropdownControls.push( {
onClick: openExportModal,
title: exportLabel,
isDisabled: ! hasResponses,
} );
if ( statusView === 'trash' ) {
dropdownControls.push( {
onClick: emptyTrash.openConfirmDialog,
title: __( 'Empty trash', 'jetpack-forms' ),
isDisabled: emptyTrash.isEmpty || emptyTrash.isEmptying,
} );
}
if ( statusView === 'spam' ) {
dropdownControls.push( {
onClick: emptySpam.openConfirmDialog,
title: __( 'Delete spam', 'jetpack-forms' ),
isDisabled: emptySpam.isEmpty || emptySpam.isEmptying,
} );
}
dropdownControls.push( ...formItemControls );
} else {
// Responses list screen: Manage integrations (inbox only), Create a form (inbox only), Export, Empty trash/spam
if ( statusView === 'inbox' && isIntegrationsEnabled && showDashboardIntegrations ) {
dropdownControls.push( {
onClick: onOpenIntegrations,
title: __( 'Manage integrations', 'jetpack-forms' ),
} );
}
if ( statusView === 'inbox' ) {
dropdownControls.push( {
onClick: () => openNewForm( { showPatterns: false } ),
title: __( 'Create a form', 'jetpack-forms' ),
} );
}
dropdownControls.push( {
onClick: openExportModal,
title: exportLabel,
isDisabled: ! hasResponses,
} );
if ( statusView === 'trash' ) {
dropdownControls.push( {
onClick: emptyTrash.openConfirmDialog,
title: __( 'Empty trash', 'jetpack-forms' ),
isDisabled: emptyTrash.isEmpty || emptyTrash.isEmptying,
} );
}
if ( statusView === 'spam' ) {
dropdownControls.push( {
onClick: emptySpam.openConfirmDialog,
title: __( 'Delete spam', 'jetpack-forms' ),
isDisabled: emptySpam.isEmpty || emptySpam.isEmptying,
} );
}
}
if ( dropdownControls.length === 0 ) {
return null;
}
return [
,
// Include modals when on mobile
...( showExportModal
? [
,
]
: [] ),
...( emptyTrash.isConfirmDialogOpen
? [
,
]
: [] ),
...( emptySpam.isConfirmDialogOpen
? [
,
]
: [] ),
];
}
// Desktop: show individual buttons
if ( isFormsScreen ) {
return [
...( isIntegrationsEnabled && showDashboardIntegrations
? [ ]
: [] ),
,
];
}
if ( isSingleFormScreen ) {
return [
...( sourceIdNumber
? [ ]
: [] ),
,
...( statusView === 'trash' ? [ ] : [] ),
...( statusView === 'spam' ? [ ] : [] ),
...( formItemControls.length > 0
? [
,
]
: [] ),
];
}
// Responses list screen.
return [
...( statusView === 'inbox' && isIntegrationsEnabled && showDashboardIntegrations
? [ ]
: [] ),
...( statusView === 'inbox'
? [
,
]
: [] ),
,
...( statusView === 'trash' ? [ ] : [] ),
...( statusView === 'spam' ? [ ] : [] ),
];
}, [
isSm,
isIntegrationsEnabled,
onOpenIntegrations,
showDashboardIntegrations,
sourceIdNumber,
isFormsScreen,
isSingleFormScreen,
formItemControls,
statusView,
openNewForm,
openExportModal,
showExportModal,
closeExportModal,
onExport,
autoConnectGdrive,
hasResponses,
exportLabel,
emptyTrash.openConfirmDialog,
emptyTrash.isEmpty,
emptyTrash.isEmptying,
emptyTrash.isConfirmDialogOpen,
emptyTrash.closeConfirmDialog,
emptyTrash.onConfirmEmptying,
emptyTrash.totalItemsTrash,
emptyTrash.selectedResponsesCount,
emptySpam.openConfirmDialog,
emptySpam.isEmpty,
emptySpam.isEmptying,
emptySpam.isConfirmDialogOpen,
emptySpam.closeConfirmDialog,
emptySpam.onConfirmEmptying,
emptySpam.totalItemsSpam,
emptySpam.selectedResponsesCount,
] );
return { breadcrumbs, badges, subtitle, actions };
}