Current File : /home/jeconsul/public_html/wp-content/plugins/suremails/src/utils/plugin-utils.js
/**
 * Plugin Utility Functions
 *
 * Contains reusable functions for installing and activating plugins.
 *
 */

import { __, sprintf } from '@wordpress/i18n';

/**
 * Performs the given plugin or theme operation (install or activate).
 *
 * @param {Object}   plugin          - The plugin or theme object.
 * @param {string}   operation       - The operation ('install' or 'activate').
 * @param {Function} setLoadingState - Function to update loading state (array of plugin slugs).
 * @return {Promise} Resolves when operation is complete.
 */
export const handlePluginOperation = ( plugin, operation, setLoadingState ) => {
	return new Promise( async ( resolve, reject ) => {
		const isInstall = operation === 'install';
		// Determine the item type. If plugin.type is 'theme', we treat it as a theme; otherwise, as a plugin.
		const itemType = plugin.type === 'theme' ? 'theme' : 'plugin';

		if ( ! wp.updates ) {
			reject(
				new Error(
					__( 'WordPress updates API not available.', 'suremails' )
				)
			);
			return;
		}

		// Add the plugin slug to the loading state.
		setLoadingState( ( prev ) => [ ...prev, plugin.slug ] );

		// For install, use the appropriate wp.updates function.
		// For activate, we use wp.ajax.send with an action based on the item type.
		const operationFunction = isInstall
			? wp.updates[
					`install${
						itemType.charAt( 0 ).toUpperCase() + itemType.slice( 1 )
					}`
			  ]
			: wp.ajax.send;

		// Data to send: for installation, we simply send the slug;
		// for activation: for plugins we use the plugin file path; for themes, just the slug.
		const data = isInstall
			? { slug: plugin.slug }
			: {
					slug: plugin.init,
					_ajax_nonce: window.suremails?._ajax_nonce,
			  };

		const commonOptions = {
			success: () => {
				resolve();
			},
			error: ( error ) => {
				reject(
					new Error(
						error.errorMessage ||
							__( 'Operation failed.', 'suremails' )
					)
				);
			},
		};

		if ( isInstall ) {
			operationFunction( {
				...data,
				...commonOptions,
			} );
		} else {
			// For activation, use a different ajax action if it's a theme.
			const actionName =
				itemType === 'plugin'
					? 'suremails-activate_plugin'
					: 'suremails-activate_theme';
			operationFunction( actionName, {
				data,
				...commonOptions,
			} );
		}
	} );
};

/**
 * Install and then automatically activate a plugin or theme.
 *
 * @param {Object}   plugin               - The plugin or theme object.
 * @param {Object}   pluginsData          - Installed/active plugins data.
 * @param {Array}    installingPlugins    - Array of slugs currently installing.
 * @param {Array}    activatingPlugins    - Array of slugs currently activating.
 * @param {Function} setInstallingPlugins - Setter for installing plugins state.
 * @param {Function} setActivatingPlugins - Setter for activating plugins state.
 * @param {Object}   queryClient          - React Query client for cache invalidation.
 * @param {Function} toast                - Toast function for notifications.
 * @return {Promise} Resolves when installation and activation complete.
 */
export const installAndActivatePlugin = async (
	plugin,
	pluginsData,
	installingPlugins,
	activatingPlugins,
	setInstallingPlugins,
	setActivatingPlugins,
	queryClient,
	toast
) => {
	// Determine the type string for toast messages.
	// translators: %s: Plugin or Theme.
	const typeStr =
		plugin.type === 'theme'
			? __( 'Theme', 'suremails' )
			: __( 'Plugin', 'suremails' );

	if ( pluginsData.installed.includes( plugin.slug ) ) {
		toast.info(
			/* translators: %s: Plugin or Theme. */
			sprintf( __( '%s is already installed.', 'suremails' ), typeStr )
		);
		return;
	}

	if ( installingPlugins.length > 0 || activatingPlugins.length > 0 ) {
		toast.info(
			sprintf(
				/* translators: %s: Plugin or Theme. */
				__(
					'Another %s operation is in progress. Please wait.',
					'suremails'
				),
				typeStr
			)
		);
		return;
	}

	try {
		await handlePluginOperation( plugin, 'install', setInstallingPlugins );
		toast.success(
			/* translators: %s: Plugin or Theme. */
			sprintf( __( '%s installed successfully.', 'suremails' ), typeStr )
		);
		// Refresh the plugins data.
		queryClient.invalidateQueries( [ 'installed-plugins' ] );
		// Automatically activate after installation.
		await activatePlugin(
			plugin,
			pluginsData,
			installingPlugins,
			activatingPlugins,
			setActivatingPlugins,
			queryClient,
			toast
		);
	} catch ( error ) {
		toast.error(
			/* translators: %s: Plugin or Theme. */
			sprintf( __( 'Failed to install %s.', 'suremails' ), typeStr )
		);
	} finally {
		setInstallingPlugins( ( prev ) =>
			prev.filter( ( slug ) => slug !== plugin.slug )
		);
	}
};

/**
 * Activate a plugin.
 *
 * @param {Object}   plugin               - The plugin or theme object.
 * @param {Object}   pluginsData          - Installed/active plugins data.
 * @param {Array}    installingPlugins    - Array of slugs currently installing.
 * @param {Array}    activatingPlugins    - Array of slugs currently activating.
 * @param {Function} setActivatingPlugins - Setter for activating plugins state.
 * @param {Object}   queryClient          - React Query client for cache invalidation.
 * @param {Function} toast                - Toast function for notifications.
 * @return {Promise} Resolves when activation is complete.
 */
export const activatePlugin = async (
	plugin,
	pluginsData,
	installingPlugins,
	activatingPlugins,
	setActivatingPlugins,
	queryClient,
	toast
) => {
	// Determine the type string (should be "Plugin").
	// translators: %s: Plugin.
	const typeStr =
		plugin.type === 'theme'
			? __( 'Theme', 'suremails' )
			: __( 'Plugin', 'suremails' );

	if ( pluginsData.active.includes( plugin.slug ) ) {
		toast.info(
			/* translators: %s: Plugin or Theme. */
			sprintf( __( '%s is already activated.', 'suremails' ), typeStr )
		);
		return;
	}

	if ( installingPlugins.length > 0 || activatingPlugins.length > 0 ) {
		toast.info(
			sprintf(
				/* translators: %s: Plugin or Theme. */
				__(
					'Another %s operation is in progress. Please wait.',
					'suremails'
				),
				typeStr
			)
		);
		return;
	}

	try {
		await handlePluginOperation( plugin, 'activate', setActivatingPlugins );
		toast.success(
			/* translators: %s: Plugin or Theme. */
			sprintf( __( '%s activated successfully.', 'suremails' ), typeStr )
		);
		// Refresh the plugins data.
		queryClient.invalidateQueries( [ 'installed-plugins' ] );
	} catch ( error ) {
		toast.error(
			/* translators: %s: Plugin or Theme. */
			sprintf( __( 'Failed to activate %s.', 'suremails' ), typeStr )
		);
	} finally {
		setActivatingPlugins( ( prev ) =>
			prev.filter( ( slug ) => slug !== plugin.slug )
		);
	}
};

/**
 * Activate a theme.
 *
 * @param {Object}   item                 - The theme object.
 * @param {Object}   pluginsData          - Installed/active plugins data.
 * @param {Array}    installingPlugins    - Array of slugs currently installing.
 * @param {Array}    activatingPlugins    - Array of slugs currently activating.
 * @param {Function} setActivatingPlugins - Setter for activating plugins state.
 * @param {Object}   queryClient          - React Query client for cache invalidation.
 * @param {Function} toast                - Toast function for notifications.
 * @return {Promise} Resolves when activation is complete.
 */
export const activateTheme = async (
	item,
	pluginsData,
	installingPlugins,
	activatingPlugins,
	setActivatingPlugins,
	queryClient,
	toast
) => {
	// translators: %s: Theme.
	const typeStr = __( 'Theme', 'suremails' );

	if ( pluginsData.active.includes( item.slug ) ) {
		toast.info(
			/* translators: %s: Plugin or Theme. */
			sprintf( __( '%s is already activated.', 'suremails' ), typeStr )
		);
		return;
	}

	if ( installingPlugins.length > 0 || activatingPlugins.length > 0 ) {
		toast.info(
			sprintf(
				// translators: %s: Theme.
				__(
					'Another %s operation is in progress. Please wait.',
					'suremails'
				),
				typeStr
			)
		);
		return;
	}

	// Add theme slug to activating state.
	setActivatingPlugins( ( prev ) => [ ...prev, item.slug ] );

	const data = {
		slug: item.slug,
		_ajax_nonce: window.suremails?._ajax_nonce,
	};

	wp.ajax.send( 'suremails-activate_theme', {
		data,
		success: () => {
			toast.success(
				sprintf(
					/* translators: %s: Theme. */
					__( '%s activated successfully.', 'suremails' ),
					typeStr
				)
			);
			queryClient.invalidateQueries( [ 'installed-plugins' ] );
		},
		error: () => {
			toast.error(
				/* translators: %s: Theme. */
				sprintf( __( 'Failed to activate %s.', 'suremails' ), typeStr )
			);
		},
		complete: () => {
			setActivatingPlugins( ( prev ) =>
				prev.filter( ( slug ) => slug !== item.slug )
			);
		},
	} );
};