UNPKG

@woocommerce/data

Version:
260 lines (259 loc) 8.47 kB
/** * External dependencies */ import { apiFetch, select, dispatch as depreciatedDispatch, } from '@wordpress/data-controls'; import { _n, sprintf } from '@wordpress/i18n'; import { controls } from '@wordpress/data'; import { recordEvent } from '@woocommerce/tracks'; /** * Internal dependencies */ import { STORE_NAME } from './constants'; import { ACTION_TYPES as TYPES } from './action-types'; import { WC_ADMIN_NAMESPACE } from '../constants'; import { isRestApiError } from '../types'; // Can be removed in WP 5.9, wp.data is supported in >5.7. const dispatch = controls && controls.dispatch ? controls.dispatch : depreciatedDispatch; const resolveSelect = controls && controls.resolveSelect ? controls.resolveSelect : select; class PluginError extends Error { constructor(message, data) { super(message); this.data = data; } } const isPluginResponseError = (plugins, error) => typeof error === 'object' && error !== null && plugins[0] in error; const formatErrorMessage = (actionType = 'install', plugins, rawErrorMessage) => { return sprintf( /* translators: %(actionType): install or activate (the plugin). %(pluginName): a plugin slug (e.g. woocommerce-services). %(error): a single error message or in plural a comma separated error message list.*/ _n('Could not %(actionType)s %(pluginName)s plugin, %(error)s', 'Could not %(actionType)s the following plugins: %(pluginName)s with these Errors: %(error)s', Object.keys(plugins).length || 1, 'woocommerce'), { actionType, pluginName: plugins.join(', '), error: rawErrorMessage, }); }; export function updateActivePlugins(active, replace = false) { return { type: TYPES.UPDATE_ACTIVE_PLUGINS, active, replace, }; } export function updateInstalledPlugins(installed, replace = false) { return { type: TYPES.UPDATE_INSTALLED_PLUGINS, installed, replace, }; } export function setIsRequesting(selector, isRequesting) { return { type: TYPES.SET_IS_REQUESTING, selector, isRequesting, }; } export function setError(selector, error) { return { type: TYPES.SET_ERROR, selector, error, }; } export function updateIsJetpackConnected(jetpackConnection) { return { type: TYPES.UPDATE_JETPACK_CONNECTION, jetpackConnection, }; } export function updateJetpackConnectionData(results) { return { type: TYPES.UPDATE_JETPACK_CONNECTION_DATA, results, }; } export function updateJetpackConnectUrl(redirectUrl, jetpackConnectUrl) { return { type: TYPES.UPDATE_JETPACK_CONNECT_URL, jetpackConnectUrl, redirectUrl, }; } export const createErrorNotice = (errorMessage) => { return dispatch('core/notices', 'createNotice', 'error', errorMessage); }; export function setPaypalOnboardingStatus(status) { return { type: TYPES.SET_PAYPAL_ONBOARDING_STATUS, paypalOnboardingStatus: status, }; } export function setRecommendedPlugins(type, plugins) { return { type: TYPES.SET_RECOMMENDED_PLUGINS, recommendedType: type, plugins, }; } function* handlePluginAPIError(actionType, plugins, error) { let rawErrorMessage; if (isPluginResponseError(plugins, error)) { // Backend error messages are in the form of { plugin-slug: [ error messages ] }. rawErrorMessage = Object.values(error).join(', \n'); } else { // Other error such as API connection errors. rawErrorMessage = isRestApiError(error) || error instanceof Error ? error.message : JSON.stringify(error); } // Track the error. switch (actionType) { case 'install': recordEvent('install_plugins_error', { plugins: plugins.join(', '), message: rawErrorMessage, }); break; case 'activate': recordEvent('activate_plugins_error', { plugins: plugins.join(', '), message: rawErrorMessage, }); } throw new PluginError(formatErrorMessage(actionType, plugins, rawErrorMessage), error); } // Action Creator Generators export function* installPlugins(plugins, async = false) { var _a, _b; yield setIsRequesting('installPlugins', true); try { const results = yield apiFetch({ path: `${WC_ADMIN_NAMESPACE}/plugins/install`, method: 'POST', data: { plugins: plugins.join(','), async }, }); if ((_a = results.data.installed) === null || _a === void 0 ? void 0 : _a.length) { yield updateInstalledPlugins(results.data.installed); } if (((_b = results.errors) === null || _b === void 0 ? void 0 : _b.errors) && Object.keys(results.errors.errors).length) { throw results.errors.errors; } return results; } catch (error) { yield setError('installPlugins', error); yield handlePluginAPIError('install', plugins, error); } finally { yield setIsRequesting('installPlugins', false); } } export function* activatePlugins(plugins) { yield setIsRequesting('activatePlugins', true); try { const results = yield apiFetch({ path: `${WC_ADMIN_NAMESPACE}/plugins/activate`, method: 'POST', data: { plugins: plugins.join(',') }, }); if (results.data.activated.length) { yield updateActivePlugins(results.data.activated); } if (Object.keys(results.errors.errors).length) { throw results.errors.errors; } return results; } catch (error) { yield setError('activatePlugins', error); yield handlePluginAPIError('activate', plugins, error); } finally { yield setIsRequesting('activatePlugins', false); } } export function* installAndActivatePlugins(plugins) { try { const installations = yield dispatch(STORE_NAME, 'installPlugins', plugins); const activations = yield dispatch(STORE_NAME, 'activatePlugins', plugins); return { ...activations, data: { ...activations.data, ...installations.data, }, }; } catch (error) { throw error; } } export function* connectToJetpack(getAdminLink) { const url = yield resolveSelect(STORE_NAME, 'getJetpackConnectUrl', { redirect_url: getAdminLink('admin.php?page=wc-admin'), }); const error = yield resolveSelect(STORE_NAME, 'getPluginsError', 'getJetpackConnectUrl'); if (error) { throw new Error(error); } else { return url; } } export function* installJetpackAndConnect(errorAction, getAdminLink) { try { yield dispatch(STORE_NAME, 'installPlugins', ['jetpack']); yield dispatch(STORE_NAME, 'activatePlugins', ['jetpack']); const url = yield dispatch(STORE_NAME, 'connectToJetpack', getAdminLink); window.location.href = url; } catch (error) { if (error instanceof Error) { yield errorAction(error.message); } else { throw error; } } } export function* connectToJetpackWithFailureRedirect(failureRedirect, errorAction, getAdminLink) { try { const url = yield dispatch(STORE_NAME, 'connectToJetpack', getAdminLink); window.location.href = url; } catch (error) { if (error instanceof Error) { yield errorAction(error.message); } else { throw error; } window.location.href = failureRedirect; } } const SUPPORTED_TYPES = ['payments']; export function* dismissRecommendedPlugins(type) { if (!SUPPORTED_TYPES.includes(type)) { return []; } const plugins = yield resolveSelect(STORE_NAME, 'getRecommendedPlugins', type); yield setRecommendedPlugins(type, []); let success; try { const url = WC_ADMIN_NAMESPACE + '/payment-gateway-suggestions/dismiss'; success = yield apiFetch({ path: url, method: 'POST', }); } catch (error) { success = false; } if (!success) { // Reset recommended plugins yield setRecommendedPlugins(type, plugins); } return success; }