Commit 6f8ae2e2 authored by Max Alekseenko's avatar Max Alekseenko

post-review fixes

parent add54ac4
...@@ -10,7 +10,6 @@ export { default as googleAnalytics } from './googleAnalytics'; ...@@ -10,7 +10,6 @@ export { default as googleAnalytics } from './googleAnalytics';
export { default as graphqlApiDocs } from './graphqlApiDocs'; export { default as graphqlApiDocs } from './graphqlApiDocs';
export { default as growthBook } from './growthBook'; export { default as growthBook } from './growthBook';
export { default as marketplace } from './marketplace'; export { default as marketplace } from './marketplace';
export { default as marketplaceCategories } from './marketplaceCategories';
export { default as mixpanel } from './mixpanel'; export { default as mixpanel } from './mixpanel';
export { default as nameService } from './nameService'; export { default as nameService } from './nameService';
export { default as restApiDocs } from './restApiDocs'; export { default as restApiDocs } from './restApiDocs';
......
...@@ -6,10 +6,11 @@ import { getEnvValue, getExternalAssetFilePath } from '../utils'; ...@@ -6,10 +6,11 @@ import { getEnvValue, getExternalAssetFilePath } from '../utils';
// config file will be downloaded at run-time and saved in the public folder // config file will be downloaded at run-time and saved in the public folder
const configUrl = getExternalAssetFilePath('NEXT_PUBLIC_MARKETPLACE_CONFIG_URL'); const configUrl = getExternalAssetFilePath('NEXT_PUBLIC_MARKETPLACE_CONFIG_URL');
const submitFormUrl = getEnvValue('NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM'); const submitFormUrl = getEnvValue('NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM');
const categoriesUrl = getExternalAssetFilePath('NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL');
const title = 'Marketplace'; const title = 'Marketplace';
const config: Feature<{ configUrl: string; submitFormUrl: string }> = (() => { const config: Feature<{ configUrl: string; submitFormUrl: string; categoriesUrl: string | undefined }> = (() => {
if ( if (
chain.rpcUrl && chain.rpcUrl &&
configUrl && configUrl &&
...@@ -20,6 +21,7 @@ const config: Feature<{ configUrl: string; submitFormUrl: string }> = (() => { ...@@ -20,6 +21,7 @@ const config: Feature<{ configUrl: string; submitFormUrl: string }> = (() => {
isEnabled: true, isEnabled: true,
configUrl, configUrl,
submitFormUrl, submitFormUrl,
categoriesUrl,
}); });
} }
......
import type { Feature } from './types';
import { getExternalAssetFilePath } from '../utils';
// config file will be downloaded at run-time and saved in the public folder
const configUrl = getExternalAssetFilePath('NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL');
const title = 'Marketplace categories';
const config: Feature<{ configUrl: string }> = (() => {
if (configUrl) {
return Object.freeze({
title,
isEnabled: true,
configUrl,
});
}
return Object.freeze({
title,
isEnabled: false,
});
})();
export default config;
...@@ -83,7 +83,8 @@ const marketplaceSchema = yup ...@@ -83,7 +83,8 @@ const marketplaceSchema = yup
.of(marketplaceAppSchema), .of(marketplaceAppSchema),
NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL: yup NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL: yup
.array() .array()
.json(), .json()
.of(yup.string()),
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM: yup NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM: yup
.string() .string()
.when('NEXT_PUBLIC_MARKETPLACE_CONFIG_URL', { .when('NEXT_PUBLIC_MARKETPLACE_CONFIG_URL', {
......
...@@ -421,7 +421,7 @@ This feature is **always enabled**, but you can configure its behavior by passin ...@@ -421,7 +421,7 @@ This feature is **always enabled**, but you can configure its behavior by passin
| NEXT_PUBLIC_MARKETPLACE_CONFIG_URL | `string` | URL of configuration file (`.json` format only) which contains list of apps that will be shown on the marketplace page. See [below](#marketplace-app-configuration-properties) list of available properties for an app | Required | - | `https://example.com/marketplace_config.json` | | NEXT_PUBLIC_MARKETPLACE_CONFIG_URL | `string` | URL of configuration file (`.json` format only) which contains list of apps that will be shown on the marketplace page. See [below](#marketplace-app-configuration-properties) list of available properties for an app | Required | - | `https://example.com/marketplace_config.json` |
| NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM | `string` | Link to form where authors can submit their dapps to the marketplace | Required | - | `https://airtable.com/shrqUAcjgGJ4jU88C` | | NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM | `string` | Link to form where authors can submit their dapps to the marketplace | Required | - | `https://airtable.com/shrqUAcjgGJ4jU88C` |
| NEXT_PUBLIC_NETWORK_RPC_URL | `string` | See in [Blockchain parameters](ENVS.md#blockchain-parameters) section | Required | - | `https://core.poa.network` | | NEXT_PUBLIC_NETWORK_RPC_URL | `string` | See in [Blockchain parameters](ENVS.md#blockchain-parameters) section | Required | - | `https://core.poa.network` |
| NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL | `string` | URL of configuration file (`.json` format only) which the list of categories to be displayed on the markeplace page in the specified order | - | - | `https://example.com/marketplace_categories.json` | | NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL | `string` | URL of configuration file (`.json` format only) which contains the list of categories to be displayed on the markeplace page in the specified order. If no URL is provided, then the list of categories will be compiled based on the `categories` fields from the marketplace (apps) configuration file | - | - | `https://example.com/marketplace_categories.json` |
#### Marketplace app configuration properties #### Marketplace app configuration properties
...@@ -440,6 +440,8 @@ This feature is **always enabled**, but you can configure its behavior by passin ...@@ -440,6 +440,8 @@ This feature is **always enabled**, but you can configure its behavior by passin
| twitter | `string` | Displayed twitter link | - | `'https://twitter.com/blockscoutcom'` | | twitter | `string` | Displayed twitter link | - | `'https://twitter.com/blockscoutcom'` |
| telegram | `string` | Displayed telegram link | - | `'https://t.me/poa_network'` | | telegram | `string` | Displayed telegram link | - | `'https://t.me/poa_network'` |
| github | `string` | Displayed github link | - | `'https://github.com/blockscout'` | | github | `string` | Displayed github link | - | `'https://github.com/blockscout'` |
| internalWallet | `boolean` | `true` means that the application can automatically connect to the Blockscout wallet. | - | `true` |
| priority | `number` | The higher the priority, the higher the app will appear in the list on the Marketplace page. | - | `7` |
#### Marketplace categories ids #### Marketplace categories ids
......
import _groudBy from 'lodash/groupBy';
import _pickBy from 'lodash/pickBy'; import _pickBy from 'lodash/pickBy';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import React from 'react'; import React from 'react';
import { MarketplaceCategory } from 'types/client/marketplace'; import { MarketplaceCategory } from 'types/client/marketplace';
import useFeatureValue from 'lib/growthbook/useFeatureValue';
import useDebounce from 'lib/hooks/useDebounce'; import useDebounce from 'lib/hooks/useDebounce';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import getQueryParamString from 'lib/router/getQueryParamString'; import getQueryParamString from 'lib/router/getQueryParamString';
...@@ -74,24 +72,7 @@ export default function useMarketplace() { ...@@ -74,24 +72,7 @@ export default function useMarketplace() {
}, []); }, []);
const { isPlaceholderData, isError, error, data, displayedApps } = useMarketplaceApps(debouncedFilterQuery, selectedCategoryId, favoriteApps); const { isPlaceholderData, isError, error, data, displayedApps } = useMarketplaceApps(debouncedFilterQuery, selectedCategoryId, favoriteApps);
const { isPlaceholderData: isCategoriesPlaceholderData, data: categories } = useMarketplaceCategories(data);
const { value: isExperiment } = useFeatureValue('marketplace_exp', false);
const { isPlaceholderData: isCategoriesPlaceholderData, data: categoriesData } = useMarketplaceCategories();
const categories = React.useMemo(() => {
let categoryNames: Array<string> = [];
const grouped = _groudBy(data, app => app.categories);
if (categoriesData?.length && isExperiment) {
categoryNames = categoriesData;
} else {
categoryNames = Object.keys(grouped);
}
return categoryNames
.map(category => ({ name: category, count: grouped[category]?.length || 0 }))
.filter(c => c.count > 0);
}, [ data, categoriesData, isExperiment ]);
React.useEffect(() => { React.useEffect(() => {
setFavoriteApps(getFavoriteApps()); setFavoriteApps(getFavoriteApps());
......
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import _groudBy from 'lodash/groupBy';
import React from 'react'; import React from 'react';
import type { MarketplaceAppOverview } from 'types/client/marketplace';
import config from 'configs/app'; import config from 'configs/app';
import type { ResourceError } from 'lib/api/resources'; import type { ResourceError } from 'lib/api/resources';
import useFeatureValue from 'lib/growthbook/useFeatureValue';
import useApiFetch from 'lib/hooks/useFetch'; import useApiFetch from 'lib/hooks/useFetch';
const feature = config.features.marketplaceCategories; const feature = config.features.marketplace;
const configUrl = feature.isEnabled ? feature.configUrl : ''; const categoriesUrl = (feature.isEnabled && feature.categoriesUrl) || '';
export default function useMarketplaceCategories() { export default function useMarketplaceCategories(apps: Array<MarketplaceAppOverview>) {
const apiFetch = useApiFetch(); const apiFetch = useApiFetch();
return useQuery<unknown, ResourceError<unknown>, Array<string>>({ const { value: isExperiment } = useFeatureValue('marketplace_exp', true);
const { isPlaceholderData, data } = useQuery<unknown, ResourceError<unknown>, Array<string>>({
queryKey: [ 'marketplace-categories' ], queryKey: [ 'marketplace-categories' ],
queryFn: async() => apiFetch(configUrl, undefined, { resource: 'marketplace-categories' }), queryFn: async() => apiFetch(categoriesUrl, undefined, { resource: 'marketplace-categories' }),
select: (data) => (data as Array<string>), placeholderData: categoriesUrl ? Array(9).fill('Bridge').map((c, i) => c + i) : undefined,
placeholderData: feature.isEnabled ? Array(9).fill('Bridge').map((c, i) => c + i) : undefined,
staleTime: Infinity, staleTime: Infinity,
enabled: feature.isEnabled, enabled: Boolean(categoriesUrl),
}); });
const categories = React.useMemo(() => {
let categoryNames: Array<string> = [];
const grouped = _groudBy(apps, app => app.categories);
if (data?.length && isExperiment) {
categoryNames = data;
} else {
categoryNames = Object.keys(grouped);
}
return categoryNames
.map(category => ({ name: category, count: grouped[category]?.length || 0 }))
.filter(c => c.count > 0);
}, [ apps, data, isExperiment ]);
return React.useMemo(() => ({
isPlaceholderData,
data: categories,
}), [ isPlaceholderData, categories ]);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment