| 1 |
const { products = [] } = window.extSharedData; |
| 2 |
|
| 3 |
export const selectIsLoading = (state) => |
| 4 |
state.isSearchPluginsLoading || state.isInstalledPluginsLoading; |
| 5 |
|
| 6 |
export const selectIsError = (state) => |
| 7 |
state.isSearchPluginsError || state.isInstalledPluginsError; |
| 8 |
|
| 9 |
export const selectAllRecommendations = (state) => { |
| 10 |
const triggeredBySlug = new Map(); |
| 11 |
const { searchPlugins, installedPlugins, searchPluginsLimit } = state; |
| 12 |
const activePlugins = installedPlugins.filter( |
| 13 |
({ status }) => status === 'active', |
| 14 |
); |
| 15 |
const limitedSearchPlugins = searchPlugins.slice(0, searchPluginsLimit); |
| 16 |
|
| 17 |
// We filter out products that: |
| 18 |
const recommendations = products |
| 19 |
// 1. Are not enabled for this slot. |
| 20 |
.filter((product) => product.slots.includes('plugin-search')) |
| 21 |
// 2. Are not triggering a match in plugin search results. |
| 22 |
.filter((product) => |
| 23 |
product.pluginSearchTriggerSlugs.some((triggerSlug) => { |
| 24 |
// We only compare against the results up to the set limit. |
| 25 |
const included = limitedSearchPlugins.includes(triggerSlug); |
| 26 |
if (included) { |
| 27 |
triggeredBySlug.set(product.slug, triggerSlug); |
| 28 |
} |
| 29 |
return included; |
| 30 |
}), |
| 31 |
) |
| 32 |
// 3. Are plugins and are already installed. |
| 33 |
.filter( |
| 34 |
(product) => |
| 35 |
product.ctaType !== 'plugin' || |
| 36 |
!installedPlugins.find(({ slug }) => slug === product.ctaPluginSlug), |
| 37 |
) |
| 38 |
// 4. Are excluded because a specified plugin is already active. |
| 39 |
.filter((product) => |
| 40 |
product.pluginExclusions.every( |
| 41 |
(pluginExclusion) => |
| 42 |
!activePlugins.find(({ slug }) => slug === pluginExclusion), |
| 43 |
), |
| 44 |
) |
| 45 |
// 5. Are excluded because a plugin dependency is not installed. |
| 46 |
.filter((product) => |
| 47 |
product.pluginDependencies.every((pluginDependency) => |
| 48 |
installedPlugins.find(({ slug }) => slug === pluginDependency), |
| 49 |
), |
| 50 |
) |
| 51 |
.filter(Boolean) |
| 52 |
.map((product) => ({ |
| 53 |
...product, |
| 54 |
title: product.pluginSearchCustomTitle || product.title, |
| 55 |
description: product.pluginSearchCustomDescription || product.description, |
| 56 |
ctaContent: product.pluginSearchCustomCtaContent || product.ctaContent, |
| 57 |
triggerContent: triggeredBySlug.get(product.slug), |
| 58 |
triggerType: 'plugin-slug', |
| 59 |
})) |
| 60 |
// Sort recommendations based on the order of their trigger slugs in the search results. |
| 61 |
.sort( |
| 62 |
(a, b) => |
| 63 |
limitedSearchPlugins.indexOf(a.triggerContent) - |
| 64 |
limitedSearchPlugins.indexOf(b.triggerContent), |
| 65 |
); |
| 66 |
|
| 67 |
return recommendations; |
| 68 |
}; |
| 69 |
|
| 70 |
export const selectRecommendations = (state) => { |
| 71 |
const recommendations = selectAllRecommendations(state); |
| 72 |
return recommendations.slice(0, state.recommendationsLimit); |
| 73 |
}; |
| 74 |
|
| 75 |
export const selectSearchPlugins = (state) => |
| 76 |
state.searchPlugins.slice(0, state.searchPluginsLimit); |
| 77 |
|
| 78 |
export const selectInstalledPlugins = (state) => |
| 79 |
state.installedPlugins.map((plugin) => plugin.slug); |
| 80 |
|
| 81 |
export const selectActivePlugins = (state) => |
| 82 |
state.installedPlugins |
| 83 |
.filter((plugin) => plugin.status === 'active') |
| 84 |
.map((plugin) => plugin.slug); |
| 85 |
|