/**
* External dependencies
*/
import { isSimpleSite } from '@automattic/jetpack-script-data';
import {
Button,
ExternalLink,
__experimentalText as Text, // eslint-disable-line @wordpress/no-unsafe-wp-apis
__experimentalVStack as VStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis
} from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
import { createInterpolateElement, useCallback, useMemo } from '@wordpress/element';
import { __, _n, sprintf } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import useConfigValue from '../../../hooks/use-config-value.ts';
import { usePluginInstallation } from '../../../hooks/use-plugin-installation.ts';
import { INTEGRATIONS_STORE } from '../../../store/integrations/index.ts';
import CreateFormButton from '../create-form-button/index.tsx';
/**
* Types
*/
import type {
IntegrationsDispatch,
SelectIntegrations,
} from '../../../store/integrations/index.ts';
import type { Integration } from '../../../types/index.ts';
import type { ReactNode } from 'react';
type UseInstallAkismetReturn = {
shouldShowAkismetCta: boolean;
wrapperBody: ReactNode;
isInstallingAkismet: boolean;
canPerformAkismetAction: boolean;
wrapperButtonText: string;
handleAkismetSetup: () => Promise< void >;
};
type EmptyResponsesProps = {
status: string;
isSearch: boolean;
readStatusFilter?: 'unread' | 'read';
};
type EmptyWrapperProps = {
heading?: string;
body?: string | ReactNode;
actions?: ReactNode;
};
/**
* Hook to handle Akismet installation and activation.
*
* @return {UseInstallAkismetReturn} An object containing the necessary data and functions to handle Akismet installation and activation.
*/
const useInstallAkismet = (): UseInstallAkismetReturn => {
const { akismetIntegration } = useSelect( ( select: SelectIntegrations ) => {
const store = select( INTEGRATIONS_STORE );
const integrations = store.getIntegrations() || [];
return {
akismetIntegration: integrations.find(
( integration: Integration ) => integration.id === 'akismet'
),
};
}, [] ) as { akismetIntegration?: Integration };
const { refreshIntegrations } = useDispatch( INTEGRATIONS_STORE ) as IntegrationsDispatch;
const akismetIntegrationReady = useMemo(
() => !! akismetIntegration && ! akismetIntegration.__isPartial,
[ akismetIntegration ]
);
const isInstalled = !! akismetIntegration?.isInstalled;
const isAkismetActive = akismetIntegrationReady && isInstalled && !! akismetIntegration?.isActive;
const shouldShowAkismetCta = akismetIntegrationReady && ! isAkismetActive && ! isSimpleSite();
const akismetPluginFile = useMemo(
() => akismetIntegration?.pluginFile ?? 'akismet/akismet',
[ akismetIntegration?.pluginFile ]
);
const wrapperBody: ReactNode = createInterpolateElement(
__(
'Want automatic spam filtering? Akismet Anti-spam protects millions of sites. Learn more.',
'jetpack-forms'
),
{
moreInfoLink: ,
}
);
const activateButtonText = __( 'Activate Akismet Anti-spam', 'jetpack-forms' );
const installAndActivateButtonText = __( 'Install Akismet Anti-spam', 'jetpack-forms' );
const wrapperButtonText = isInstalled ? activateButtonText : installAndActivateButtonText;
const {
isInstalling: isInstallingAkismet,
installPlugin,
canInstallPlugins,
canActivatePlugins,
} = usePluginInstallation( {
slug: 'akismet',
pluginPath: akismetPluginFile,
isInstalled,
onSuccess: refreshIntegrations,
trackEventName: 'jetpack_forms_upsell_akismet_click',
trackEventProps: {
screen: 'dashboard',
},
successNotices: {
install: {
message: __( 'Akismet installed and activated.', 'jetpack-forms' ),
options: { type: 'snackbar', id: 'akismet-install-success' },
},
activate: {
message: __( 'Akismet activated.', 'jetpack-forms' ),
options: { type: 'snackbar', id: 'akismet-install-success' },
},
},
errorNotice: {
message: __( 'Could not set up Akismet. Please try again.', 'jetpack-forms' ),
options: { type: 'snackbar', id: 'akismet-install-error' },
},
} );
const canPerformAkismetAction =
isInstalled && akismetIntegrationReady
? canActivatePlugins !== false
: canInstallPlugins !== false;
const handleAkismetSetup = useCallback( async () => {
if ( isInstallingAkismet || ! akismetIntegrationReady || ! canPerformAkismetAction ) {
return;
}
await installPlugin();
}, [ isInstallingAkismet, akismetIntegrationReady, canPerformAkismetAction, installPlugin ] );
return {
shouldShowAkismetCta,
wrapperBody,
isInstallingAkismet,
canPerformAkismetAction,
wrapperButtonText,
handleAkismetSetup,
};
};
export const EmptyWrapper = ( { heading = '', body = '', actions = null }: EmptyWrapperProps ) => (
{ heading && (
{ heading }
) }
{ body && { body } }
{ actions && { actions } }
);
const EmptyResponses = ( { status, isSearch, readStatusFilter }: EmptyResponsesProps ) => {
const emptyTrashDays = useConfigValue( 'emptyTrashDays' ) ?? 0;
const {
shouldShowAkismetCta,
wrapperBody,
isInstallingAkismet,
canPerformAkismetAction,
wrapperButtonText,
handleAkismetSetup,
} = useInstallAkismet();
// Handle search and filter states first
const hasReadStatusFilter = !! readStatusFilter;
const searchHeading = __( 'No results found', 'jetpack-forms' );
const searchMessage = __(
"Try adjusting your search or filters to find what you're looking for.",
'jetpack-forms'
);
if ( isSearch || hasReadStatusFilter ) {
return ;
}
const noTrashHeading = __( 'Trash is empty', 'jetpack-forms' );
const noTrashMessage = sprintf(
/* translators: %d number of days. */
_n(
'Items in trash are permanently deleted after %d day.',
'Items in trash are permanently deleted after %d days.',
emptyTrashDays,
'jetpack-forms'
),
emptyTrashDays
);
if ( status === 'trash' ) {
return (
0 && noTrashMessage } />
);
}
const noSpamHeading = __( 'Lucky you, no spam!', 'jetpack-forms' );
const noSpamMessage = __(
'Spam responses are permanently deleted after 15 days.',
'jetpack-forms'
);
if ( status === 'spam' ) {
if ( shouldShowAkismetCta ) {
return (
{ wrapperButtonText }
}
/>
);
}
return ;
}
return (
}
/>
);
};
export default EmptyResponses;