/** * External dependencies */ import { JetpackLogo } from '@automattic/jetpack-components'; import { __experimentalConfirmDialog as ConfirmDialog } from '@wordpress/components'; // eslint-disable-line @wordpress/no-unsafe-wp-apis import { DataViews } from '@wordpress/dataviews/wp'; import { dateI18n, getSettings as getDateSettings } from '@wordpress/date'; import { useCallback, useEffect, useMemo, useState } from '@wordpress/element'; import { __, _n, sprintf } from '@wordpress/i18n'; import { useNavigate } from 'react-router'; /** * Internal dependencies */ import useConfigValue from '../../hooks/use-config-value.ts'; import CreateFormButton from '../components/create-form-button/index.tsx'; import DataViewsHeaderRow from '../components/dataviews-header-row/index.tsx'; import { EmptyWrapper } from '../components/empty-responses/index.tsx'; import Page from '../components/page/index.tsx'; import useDeleteForm from '../hooks/use-delete-form.ts'; import useFormsData from '../hooks/use-forms-data.ts'; import { defaultLayouts, useView } from './views.ts'; import './style.scss'; import type { FormListItem } from '../hooks/use-forms-data.ts'; import type { Action, Operator } from '@wordpress/dataviews/wp'; /** * Forms dashboard "Forms" route. * * @return {JSX.Element|null} The Forms list page, or null when redirecting. */ export default function FormsDashboardForms(): JSX.Element | null { const navigate = useNavigate(); const isCentralFormManagementEnabled = useConfigValue( 'isCentralFormManagementEnabled' ); const isCentralFormManagementDisabled = isCentralFormManagementEnabled === false; const dateSettings = getDateSettings(); const [ view, setView ] = useView(); const statusQuery = useMemo( () => { const statusFilterValue = view.filters?.find( filter => filter.field === 'status' )?.value; // Default: show all non-trash forms (matches WP core list behavior). const nonTrashStatuses = 'publish,draft,pending,future,private'; if ( ! statusFilterValue ) { return nonTrashStatuses; } if ( statusFilterValue === 'all' ) { return nonTrashStatuses; } return statusFilterValue; }, [ view.filters ] ); const isViewingTrash = useMemo( () => { const statusFilterValue = view.filters?.find( filter => filter.field === 'status' )?.value; return statusFilterValue === 'trash'; }, [ view.filters ] ); const { records, isLoading, totalItems, totalPages } = useFormsData( view.page, view.perPage, view.search, statusQuery ); const { isDeleting, trashForms, restoreForms, isPermanentDeleteConfirmOpen, openPermanentDeleteConfirm, closePermanentDeleteConfirm, confirmPermanentDelete, } = useDeleteForm( { view, setView, recordsLength: records?.length ?? 0, statusQuery, } ); const [ selection, setSelection ] = useState< string[] >( [] ); const [ pendingPermanentDeleteCount, setPendingPermanentDeleteCount ] = useState( 0 ); useEffect( () => { if ( isCentralFormManagementDisabled ) { navigate( '/responses', { replace: true } ); } }, [ isCentralFormManagementDisabled, navigate ] ); // Selection is local (non-URL) state. Clear selection whenever the view changes (page/perPage/search/filters). useEffect( () => { setSelection( [] ); }, [ view.page, view.perPage, view.search, view.filters ] ); const onOpenPermanentDeleteConfirm = useCallback( ( items: FormListItem[] ) => { setPendingPermanentDeleteCount( items?.length ?? 0 ); openPermanentDeleteConfirm( items ); }, [ openPermanentDeleteConfirm ] ); const onClosePermanentDeleteConfirm = useCallback( () => { setPendingPermanentDeleteCount( 0 ); closePermanentDeleteConfirm(); }, [ closePermanentDeleteConfirm ] ); const onConfirmPermanentDelete = useCallback( async () => { setPendingPermanentDeleteCount( 0 ); try { await confirmPermanentDelete(); } finally { setSelection( [] ); } }, [ confirmPermanentDelete ] ); const statusLabel = useCallback( ( status: string ) => { switch ( status ) { 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 status; } }, [] ); const fields = useMemo( () => [ { id: 'title', label: __( 'Form name', 'jetpack-forms' ), getValue: ( { item }: { item: FormListItem } ) => item.title, render: ( { item }: { item: FormListItem } ) => item.title || __( '(no title)', 'jetpack-forms' ), enableSorting: false, enableHiding: false, }, { id: 'entries', label: __( 'Entries', 'jetpack-forms' ), getValue: ( { item }: { item: FormListItem } ) => item.entriesCount ?? 0, render: ( { item }: { item: FormListItem } ) => item.entriesCount ?? 0, enableSorting: false, }, { id: 'status', label: __( 'Status', 'jetpack-forms' ), getValue: ( { item }: { item: FormListItem } ) => item.status, render: ( { item }: { item: FormListItem } ) => statusLabel( item.status ), elements: [ { label: __( 'All', 'jetpack-forms' ), value: 'all' }, { label: __( 'Published', 'jetpack-forms' ), value: 'publish' }, { label: __( 'Draft', 'jetpack-forms' ), value: 'draft' }, { label: __( 'Pending review', 'jetpack-forms' ), value: 'pending' }, { label: __( 'Scheduled', 'jetpack-forms' ), value: 'future' }, { label: __( 'Private', 'jetpack-forms' ), value: 'private' }, { label: __( 'Trash', 'jetpack-forms' ), value: 'trash' }, ], // Mark as primary so the filter UI (and its pill) is visible by default on load. // DataViews expects `operators` to be typed as a known operator union; keep this narrowly typed. filterBy: { operators: [ 'is' ] as Operator[], isPrimary: true }, enableSorting: false, }, { id: 'modified', label: __( 'Last updated', 'jetpack-forms' ), type: 'date' as const, render: ( { item }: { item: FormListItem } ) => dateI18n( dateSettings.formats.datetime, item.modified ), enableSorting: false, }, ], [ dateSettings.formats.datetime, statusLabel ] ); const actions = useMemo( () => { const actionsList: Action< FormListItem >[] = [ { id: 'view-responses', isPrimary: false, label: __( 'View responses', 'jetpack-forms' ), supportsBulk: false, callback( items: FormListItem[] ) { const [ item ] = items; if ( ! item ) { return; } navigate( `/forms/${ item.id }/responses` ); }, }, { id: 'edit-form', isPrimary: false, label: __( 'Edit', 'jetpack-forms' ), supportsBulk: false, async callback( items: FormListItem[] ) { const [ item ] = items; if ( ! item ) { return; } const fallbackEditUrl = `post.php?post=${ item.id }&action=edit&post_type=jetpack_form`; const editUrl = item.editUrl || fallbackEditUrl; const url = new URL( editUrl, window.location.origin ); window.location.href = url.toString(); }, }, ]; if ( isViewingTrash ) { actionsList.push( { id: 'restore-form', isPrimary: false, label: __( 'Restore', 'jetpack-forms' ), supportsBulk: true, async callback( items: FormListItem[] ) { if ( isDeleting ) { return; } try { await restoreForms( items ); } finally { setSelection( [] ); } }, } ); actionsList.push( { id: 'delete-form-permanently', isPrimary: false, label: __( 'Delete permanently', 'jetpack-forms' ), supportsBulk: true, async callback( items: FormListItem[] ) { if ( isDeleting ) { return; } if ( ! items?.length ) { return; } onOpenPermanentDeleteConfirm( items ); }, } ); return actionsList; } actionsList.push( { id: 'trash-form', isPrimary: false, label: __( 'Trash', 'jetpack-forms' ), supportsBulk: true, async callback( items: FormListItem[] ) { if ( isDeleting ) { return; } try { await trashForms( items ); } finally { setSelection( [] ); } }, } ); return actionsList; }, [ isDeleting, isViewingTrash, navigate, onOpenPermanentDeleteConfirm, restoreForms, trashForms, ] ); const paginationInfo = useMemo( () => ( { totalItems: totalItems ?? 0, totalPages: totalPages ?? 0, } ), [ totalItems, totalPages ] ); const onChangeView = useCallback( newView => setView( newView ), [ setView ] ); const headerActions = useMemo( () => [ ], [] ); const getItemId = useCallback( ( item: FormListItem ) => String( item.id ), [] ); const onClickItem = useCallback( ( item: FormListItem ) => { navigate( `/forms/${ item.id }/responses` ); }, [ navigate ] ); // Avoid rendering if the flag is off (we'll redirect). if ( isCentralFormManagementDisabled ) { return null; } return (
{ __( 'Forms', 'jetpack-forms' ) }
} subTitle={ __( 'View and manage all your forms in one place.', 'jetpack-forms' ) } actions={ headerActions } hasPadding={ false } > } /> } view={ view } onChangeView={ onChangeView } selection={ selection } onChangeSelection={ setSelection } onClickItem={ onClickItem } getItemId={ getItemId } defaultLayouts={ defaultLayouts } >

{ __( 'Delete permanently', 'jetpack-forms' ) }

{ pendingPermanentDeleteCount === 1 ? __( 'This will permanently delete this form. This action cannot be undone.', 'jetpack-forms' ) : sprintf( /* translators: %d: number of forms */ _n( 'This will permanently delete %d form. This action cannot be undone.', 'This will permanently delete %d forms. This action cannot be undone.', pendingPermanentDeleteCount, 'jetpack-forms' ), pendingPermanentDeleteCount ) }

); }