Commit 66ec60d0 authored by Igor Stuev's avatar Igor Stuev Committed by GitHub

Merge pull request #1613 from blockscout/remove-marketplace-experiment

Remove marketplace experiment
parents 7c693149 687c5ac0
...@@ -7,7 +7,6 @@ import { STORAGE_KEY, STORAGE_LIMIT } from './consts'; ...@@ -7,7 +7,6 @@ import { STORAGE_KEY, STORAGE_LIMIT } from './consts';
export interface GrowthBookFeatures { export interface GrowthBookFeatures {
test_value: string; test_value: string;
marketplace_exp: boolean;
} }
export const growthBook = (() => { export const growthBook = (() => {
......
...@@ -4,7 +4,6 @@ import React, { useCallback } from 'react'; ...@@ -4,7 +4,6 @@ import React, { useCallback } from 'react';
import type { MarketplaceAppPreview } from 'types/client/marketplace'; import type { MarketplaceAppPreview } from 'types/client/marketplace';
import useFeatureValue from 'lib/growthbook/useFeatureValue';
import * as mixpanel from 'lib/mixpanel/index'; import * as mixpanel from 'lib/mixpanel/index';
import type { IconName } from 'ui/shared/IconSvg'; import type { IconName } from 'ui/shared/IconSvg';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
...@@ -31,13 +30,10 @@ const MarketplaceAppCard = ({ ...@@ -31,13 +30,10 @@ const MarketplaceAppCard = ({
onInfoClick, onInfoClick,
isFavorite, isFavorite,
onFavoriteClick, onFavoriteClick,
isLoading: isDataLoading, isLoading,
showDisclaimer, showDisclaimer,
internalWallet, internalWallet,
}: Props) => { }: Props) => {
const { value: isExperiment, isLoading: isExperimentLoading } = useFeatureValue('marketplace_exp', false);
const isLoading = isDataLoading || isExperimentLoading;
const categoriesLabel = categories.join(', '); const categoriesLabel = categories.join(', ');
const handleClick = useCallback((event: MouseEvent) => { const handleClick = useCallback((event: MouseEvent) => {
...@@ -59,7 +55,6 @@ const MarketplaceAppCard = ({ ...@@ -59,7 +55,6 @@ const MarketplaceAppCard = ({
}, [ onFavoriteClick, id, isFavorite ]); }, [ onFavoriteClick, id, isFavorite ]);
const logoUrl = useColorModeValue(logo, logoDarkMode || logo); const logoUrl = useColorModeValue(logo, logoDarkMode || logo);
const moreButtonBgGradient = `linear(to-r, ${ useColorModeValue('whiteAlpha.50', 'blackAlpha.50') }, ${ useColorModeValue('white', 'black') } 20%)`;
const [ integrationIcon, integrationIconColor, integrationText ] = React.useMemo(() => { const [ integrationIcon, integrationIconColor, integrationText ] = React.useMemo(() => {
let icon: IconName = 'integration/partial'; let icon: IconName = 'integration/partial';
...@@ -94,14 +89,14 @@ const MarketplaceAppCard = ({ ...@@ -94,14 +89,14 @@ const MarketplaceAppCard = ({
role="group" role="group"
> >
<Box <Box
display={{ base: 'grid', sm: isExperiment ? 'flex' : 'block' }} display={{ base: 'grid', sm: 'flex' }}
flexDirection={ isExperiment ? 'column' : undefined } flexDirection="column"
gridTemplateColumns={{ base: '64px 1fr', sm: '1fr' }} gridTemplateColumns={{ base: '64px 1fr', sm: '1fr' }}
gridTemplateRows={{ base: 'none', sm: 'none' }} gridTemplateRows={{ base: 'none', sm: 'none' }}
gridRowGap={{ base: 2, sm: 0 }} gridRowGap={{ base: 2, sm: 0 }}
gridColumnGap={{ base: 4, sm: 0 }} gridColumnGap={{ base: 4, sm: 0 }}
height="100%" height="100%"
alignContent={ isExperiment ? 'start' : undefined } alignContent="start"
> >
<Skeleton <Skeleton
isLoaded={ !isLoading } isLoaded={ !isLoading }
...@@ -137,25 +132,23 @@ const MarketplaceAppCard = ({ ...@@ -137,25 +132,23 @@ const MarketplaceAppCard = ({
title={ title } title={ title }
onClick={ handleClick } onClick={ handleClick }
/> />
{ isExperiment && ( <Tooltip
<Tooltip label={ integrationText }
label={ integrationText } textAlign="center"
textAlign="center" padding={ 2 }
padding={ 2 } openDelay={ 300 }
openDelay={ 300 } maxW={ 400 }
maxW={ 400 } >
> <IconSvg
<IconSvg name={ integrationIcon }
name={ integrationIcon } boxSize={ 5 }
boxSize={ 5 } color={ integrationIconColor }
color={ integrationIconColor } position="relative"
position="relative" cursor="pointer"
cursor="pointer" verticalAlign="middle"
verticalAlign="middle" marginBottom={ 1 }
marginBottom={ 1 } />
/> </Tooltip>
</Tooltip>
) }
</Skeleton> </Skeleton>
<Skeleton <Skeleton
...@@ -171,63 +164,34 @@ const MarketplaceAppCard = ({ ...@@ -171,63 +164,34 @@ const MarketplaceAppCard = ({
isLoaded={ !isLoading } isLoaded={ !isLoading }
fontSize={{ base: 'xs', sm: 'sm' }} fontSize={{ base: 'xs', sm: 'sm' }}
lineHeight="20px" lineHeight="20px"
noOfLines={ isExperiment ? 3 : 4 } noOfLines={ 3 }
> >
{ shortDescription } { shortDescription }
</Skeleton> </Skeleton>
{ !isLoading && ( { !isLoading && (
isExperiment ? ( <Box
<Box display="flex"
display="flex" position={{ base: 'absolute', sm: 'relative' }}
position={{ base: 'absolute', sm: 'relative' }} bottom={{ base: 3, sm: 0 }}
bottom={{ base: 3, sm: 0 }} left={{ base: 3, sm: 0 }}
left={{ base: 3, sm: 0 }} marginTop={{ base: 0, sm: 'auto' }}
marginTop={{ base: 0, sm: 'auto' }} paddingTop={{ base: 0, sm: 4 }}
paddingTop={{ base: 0, sm: 4 }} >
> <Link
<Link fontSize={{ base: 'xs', sm: 'sm' }}
fontSize={{ base: 'xs', sm: 'sm' }} paddingRight={{ sm: 2 }}
paddingRight={{ sm: 2 }} href="#"
href="#" onClick={ handleInfoClick }
onClick={ handleInfoClick }
>
More info
</Link>
</Box>
) : (
<Box
position="absolute"
right={{ base: 3, sm: '20px' }}
bottom={{ base: 3, sm: '20px' }}
paddingLeft={ 8 }
bgGradient={ moreButtonBgGradient }
> >
<Link More info
fontSize={{ base: 'xs', sm: 'sm' }} </Link>
display="flex" </Box>
alignItems="center"
paddingRight={{ sm: 2 }}
maxW="100%"
overflow="hidden"
href="#"
onClick={ handleInfoClick }
>
More
<IconSvg
name="arrows/north-east"
marginLeft={ 1 }
boxSize={ 4 }
/>
</Link>
</Box>
)
) } ) }
{ !isLoading && ( { !isLoading && (
<IconButton <IconButton
display={{ base: 'block', sm: isFavorite || isExperiment ? 'block' : 'none' }} display={{ base: 'block', sm: isFavorite ? 'block' : 'none' }}
_groupHover={{ display: 'block' }} _groupHover={{ display: 'block' }}
position="absolute" position="absolute"
right={{ base: 3, sm: '10px' }} right={{ base: 3, sm: '10px' }}
......
import { Box, Button, Menu, MenuButton, MenuList, Skeleton } from '@chakra-ui/react';
import React from 'react';
import { MarketplaceCategory } from 'types/client/marketplace';
import IconSvg from 'ui/shared/IconSvg';
import MarketplaceCategoriesMenuItem from './MarketplaceCategoriesMenuItem';
type Props = {
categories: Array<string>;
selectedCategoryId: string;
onSelect: (category: string) => void;
isLoading: boolean;
}
const MarketplaceCategoriesMenu = ({ selectedCategoryId, onSelect, categories, isLoading }: Props) => {
const options = React.useMemo(() => ([
MarketplaceCategory.FAVORITES,
MarketplaceCategory.ALL,
...categories,
]), [ categories ]);
if (isLoading) {
return (
<Skeleton
h="40px"
w={{ base: '100%', sm: '120px' }}
borderRadius="base"
mb={{ base: 2, sm: 0 }}
mr={{ base: 0, sm: 2 }}
/>
);
}
return (
<Menu>
<MenuButton
as={ Button }
mb={{ base: 2, sm: 0 }}
mr={{ base: 0, sm: 2 }}
size="md"
variant="outline"
colorScheme="gray"
flexShrink={ 0 }
>
<Box
as="span"
display="flex"
alignItems="center"
>
{ selectedCategoryId }
<IconSvg transform="rotate(-90deg)" ml={{ base: 'auto', sm: 1 }} name="arrows/east-mini" w={ 5 } h={ 5 }/>
</Box>
</MenuButton>
<MenuList zIndex={ 3 }>
{ options.map((category: string) => (
<MarketplaceCategoriesMenuItem
key={ category }
id={ category }
onClick={ onSelect }
/>
)) }
</MenuList>
</Menu>
);
};
export default React.memo(MarketplaceCategoriesMenu);
import { MenuItem } from '@chakra-ui/react';
import React, { useCallback } from 'react';
import { MarketplaceCategory } from 'types/client/marketplace';
import type { IconName } from 'ui/shared/IconSvg';
import IconSvg from 'ui/shared/IconSvg';
type Props = {
id: string;
onClick: (category: string) => void;
}
const ICONS: Record<string, IconName> = {
[MarketplaceCategory.FAVORITES]: 'star_filled',
};
const MarketplaceCategoriesMenuItem = ({ id, onClick }: Props) => {
const handleSelection = useCallback(() => {
onClick(id);
}, [ id, onClick ]);
return (
<MenuItem
key={ id }
onClick={ handleSelection }
display="flex"
alignItems="center"
>
{ id in ICONS && <IconSvg mr={ 3 } name={ ICONS[id] } w={ 4 } h={ 4 } color="blackAlpha.800"/> }
{ id }
</MenuItem>
);
};
export default MarketplaceCategoriesMenuItem;
...@@ -4,7 +4,6 @@ import React from 'react'; ...@@ -4,7 +4,6 @@ import React from 'react';
import type { MarketplaceAppPreview } from 'types/client/marketplace'; import type { MarketplaceAppPreview } from 'types/client/marketplace';
import { MarketplaceCategory } from 'types/client/marketplace'; import { MarketplaceCategory } from 'types/client/marketplace';
import useFeatureValue from 'lib/growthbook/useFeatureValue';
import { apos } from 'lib/html-entities'; import { apos } from 'lib/html-entities';
import EmptySearchResult from 'ui/shared/EmptySearchResult'; import EmptySearchResult from 'ui/shared/EmptySearchResult';
import IconSvg from 'ui/shared/IconSvg'; import IconSvg from 'ui/shared/IconSvg';
...@@ -22,8 +21,6 @@ type Props = { ...@@ -22,8 +21,6 @@ type Props = {
} }
const MarketplaceList = ({ apps, onAppClick, favoriteApps, onFavoriteClick, isLoading, showDisclaimer, selectedCategoryId }: Props) => { const MarketplaceList = ({ apps, onAppClick, favoriteApps, onFavoriteClick, isLoading, showDisclaimer, selectedCategoryId }: Props) => {
const { value: isExperiment } = useFeatureValue('marketplace_exp', false);
return apps.length > 0 ? ( return apps.length > 0 ? (
<Grid <Grid
templateColumns={{ templateColumns={{
...@@ -56,7 +53,7 @@ const MarketplaceList = ({ apps, onAppClick, favoriteApps, onFavoriteClick, isLo ...@@ -56,7 +53,7 @@ const MarketplaceList = ({ apps, onAppClick, favoriteApps, onFavoriteClick, isLo
) : ( ) : (
<EmptySearchResult <EmptySearchResult
text={ text={
(selectedCategoryId === MarketplaceCategory.FAVORITES && !favoriteApps.length && isExperiment) ? ( (selectedCategoryId === MarketplaceCategory.FAVORITES && !favoriteApps.length) ? (
<> <>
You don{ apos }t have any favorite apps. You don{ apos }t have any favorite apps.
Click on the <IconSvg name="star_outline" w={ 4 } h={ 4 } mb={ -0.5 }/> icon on the app{ apos }s card to add it to Favorites. Click on the <IconSvg name="star_outline" w={ 4 } h={ 4 } mb={ -0.5 }/> icon on the app{ apos }s card to add it to Favorites.
......
...@@ -7,7 +7,6 @@ import { MarketplaceCategory } from 'types/client/marketplace'; ...@@ -7,7 +7,6 @@ import { MarketplaceCategory } 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 useApiFetch from 'lib/api/useApiFetch'; import useApiFetch from 'lib/api/useApiFetch';
import useFeatureValue from 'lib/growthbook/useFeatureValue';
import useFetch from 'lib/hooks/useFetch'; import useFetch from 'lib/hooks/useFetch';
import { MARKETPLACE_APP } from 'stubs/marketplace'; import { MARKETPLACE_APP } from 'stubs/marketplace';
...@@ -23,10 +22,7 @@ function isAppCategoryMatches(category: string, app: MarketplaceAppOverview, fav ...@@ -23,10 +22,7 @@ function isAppCategoryMatches(category: string, app: MarketplaceAppOverview, fav
app.categories.includes(category); app.categories.includes(category);
} }
function sortApps(apps: Array<MarketplaceAppOverview>, isExperiment: boolean) { function sortApps(apps: Array<MarketplaceAppOverview>) {
if (!isExperiment) {
return apps.sort((a, b) => a.title.localeCompare(b.title));
}
return apps.sort((a, b) => { return apps.sort((a, b) => {
const priorityA = a.priority || 0; const priorityA = a.priority || 0;
const priorityB = b.priority || 0; const priorityB = b.priority || 0;
...@@ -50,7 +46,6 @@ function sortApps(apps: Array<MarketplaceAppOverview>, isExperiment: boolean) { ...@@ -50,7 +46,6 @@ function sortApps(apps: Array<MarketplaceAppOverview>, isExperiment: boolean) {
export default function useMarketplaceApps(filter: string, selectedCategoryId: string = MarketplaceCategory.ALL, favoriteApps: Array<string> = []) { export default function useMarketplaceApps(filter: string, selectedCategoryId: string = MarketplaceCategory.ALL, favoriteApps: Array<string> = []) {
const fetch = useFetch(); const fetch = useFetch();
const apiFetch = useApiFetch(); const apiFetch = useApiFetch();
const { value: isExperiment } = useFeatureValue('marketplace_exp', false);
const { isPlaceholderData, isError, error, data } = useQuery<unknown, ResourceError<unknown>, Array<MarketplaceAppOverview>>({ const { isPlaceholderData, isError, error, data } = useQuery<unknown, ResourceError<unknown>, Array<MarketplaceAppOverview>>({
queryKey: [ 'marketplace-dapps' ], queryKey: [ 'marketplace-dapps' ],
...@@ -63,7 +58,7 @@ export default function useMarketplaceApps(filter: string, selectedCategoryId: s ...@@ -63,7 +58,7 @@ export default function useMarketplaceApps(filter: string, selectedCategoryId: s
return apiFetch('marketplace_dapps', { pathParams: { chainId: config.chain.id } }); return apiFetch('marketplace_dapps', { pathParams: { chainId: config.chain.id } });
} }
}, },
select: (data) => sortApps(data as Array<MarketplaceAppOverview>, isExperiment), select: (data) => sortApps(data as Array<MarketplaceAppOverview>),
placeholderData: feature.isEnabled ? Array(9).fill(MARKETPLACE_APP) : undefined, placeholderData: feature.isEnabled ? Array(9).fill(MARKETPLACE_APP) : undefined,
staleTime: Infinity, staleTime: Infinity,
enabled: feature.isEnabled, enabled: feature.isEnabled,
......
...@@ -5,7 +5,6 @@ import type { MarketplaceAppOverview } from 'types/client/marketplace'; ...@@ -5,7 +5,6 @@ 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';
import { CATEGORIES } from 'stubs/marketplace'; import { CATEGORIES } from 'stubs/marketplace';
...@@ -14,7 +13,6 @@ const categoriesUrl = (feature.isEnabled && feature.categoriesUrl) || ''; ...@@ -14,7 +13,6 @@ const categoriesUrl = (feature.isEnabled && feature.categoriesUrl) || '';
export default function useMarketplaceCategories(apps: Array<MarketplaceAppOverview> | undefined, isAppsPlaceholderData: boolean) { export default function useMarketplaceCategories(apps: Array<MarketplaceAppOverview> | undefined, isAppsPlaceholderData: boolean) {
const apiFetch = useApiFetch(); const apiFetch = useApiFetch();
const { value: isExperiment } = useFeatureValue('marketplace_exp', false);
const { isPlaceholderData, data } = useQuery<unknown, ResourceError<unknown>, Array<string>>({ const { isPlaceholderData, data } = useQuery<unknown, ResourceError<unknown>, Array<string>>({
queryKey: [ 'marketplace-categories' ], queryKey: [ 'marketplace-categories' ],
...@@ -41,7 +39,7 @@ export default function useMarketplaceCategories(apps: Array<MarketplaceAppOverv ...@@ -41,7 +39,7 @@ export default function useMarketplaceCategories(apps: Array<MarketplaceAppOverv
}); });
}); });
if (data?.length && !isPlaceholderData && isExperiment) { if (data?.length && !isPlaceholderData) {
categoryNames = data; categoryNames = data;
} else { } else {
categoryNames = Object.keys(grouped); categoryNames = Object.keys(grouped);
...@@ -50,7 +48,7 @@ export default function useMarketplaceCategories(apps: Array<MarketplaceAppOverv ...@@ -50,7 +48,7 @@ export default function useMarketplaceCategories(apps: Array<MarketplaceAppOverv
return categoryNames return categoryNames
.map(category => ({ name: category, count: grouped[category] || 0 })) .map(category => ({ name: category, count: grouped[category] || 0 }))
.filter(c => c.count > 0); .filter(c => c.count > 0);
}, [ apps, isAppsPlaceholderData, data, isPlaceholderData, isExperiment ]); }, [ apps, isAppsPlaceholderData, data, isPlaceholderData ]);
return React.useMemo(() => ({ return React.useMemo(() => ({
isPlaceholderData: isAppsPlaceholderData || isPlaceholderData, isPlaceholderData: isAppsPlaceholderData || isPlaceholderData,
......
...@@ -6,10 +6,8 @@ import type { TabItem } from 'ui/shared/Tabs/types'; ...@@ -6,10 +6,8 @@ import type { TabItem } from 'ui/shared/Tabs/types';
import config from 'configs/app'; import config from 'configs/app';
import throwOnResourceLoadError from 'lib/errors/throwOnResourceLoadError'; import throwOnResourceLoadError from 'lib/errors/throwOnResourceLoadError';
import useFeatureValue from 'lib/growthbook/useFeatureValue';
import useIsMobile from 'lib/hooks/useIsMobile'; import useIsMobile from 'lib/hooks/useIsMobile';
import MarketplaceAppModal from 'ui/marketplace/MarketplaceAppModal'; import MarketplaceAppModal from 'ui/marketplace/MarketplaceAppModal';
import MarketplaceCategoriesMenu from 'ui/marketplace/MarketplaceCategoriesMenu';
import MarketplaceDisclaimerModal from 'ui/marketplace/MarketplaceDisclaimerModal'; import MarketplaceDisclaimerModal from 'ui/marketplace/MarketplaceDisclaimerModal';
import MarketplaceList from 'ui/marketplace/MarketplaceList'; import MarketplaceList from 'ui/marketplace/MarketplaceList';
import FilterInput from 'ui/shared/filters/FilterInput'; import FilterInput from 'ui/shared/filters/FilterInput';
...@@ -64,7 +62,6 @@ const Marketplace = () => { ...@@ -64,7 +62,6 @@ const Marketplace = () => {
isCategoriesPlaceholderData, isCategoriesPlaceholderData,
} = useMarketplace(); } = useMarketplace();
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const { value: isExperiment } = useFeatureValue('marketplace_exp', false);
const categoryTabs = React.useMemo(() => { const categoryTabs = React.useMemo(() => {
const tabs: Array<TabItem> = categories.map(category => ({ const tabs: Array<TabItem> = categories.map(category => ({
...@@ -143,43 +140,28 @@ const Marketplace = () => { ...@@ -143,43 +140,28 @@ const Marketplace = () => {
</Flex> </Flex>
) } ) }
/> />
{ isExperiment && ( <Box marginTop={{ base: 0, lg: 8 }}>
<Box marginTop={{ base: 0, lg: 8 }}> { (isCategoriesPlaceholderData) ? (
{ (isCategoriesPlaceholderData) ? ( <TabsSkeleton tabs={ categoryTabs }/>
<TabsSkeleton tabs={ categoryTabs }/> ) : (
) : ( <TabsWithScroll
<TabsWithScroll tabs={ categoryTabs }
tabs={ categoryTabs } onTabChange={ handleCategoryChange }
onTabChange={ handleCategoryChange } defaultTabIndex={ selectedCategoryIndex }
defaultTabIndex={ selectedCategoryIndex } marginBottom={{ base: 0, lg: -2 }}
marginBottom={{ base: 0, lg: -2 }}
/>
) }
</Box>
) }
<Box
display="flex"
flexDirection={{ base: 'column', sm: 'row' }}
>
{ !isExperiment && (
<MarketplaceCategoriesMenu
categories={ categories.map(c => c.name) }
selectedCategoryId={ selectedCategoryId }
onSelect={ onCategoryChange }
isLoading={ isPlaceholderData }
/> />
) } ) }
<FilterInput
initialValue={ filterQuery }
onChange={ onSearchInputChange }
marginBottom={{ base: '4', lg: '6' }}
w="100%"
placeholder="Find app"
isLoading={ isPlaceholderData }
/>
</Box> </Box>
<FilterInput
initialValue={ filterQuery }
onChange={ onSearchInputChange }
marginBottom={{ base: '4', lg: '6' }}
w="100%"
placeholder="Find app"
isLoading={ isPlaceholderData }
/>
<MarketplaceList <MarketplaceList
apps={ displayedApps } apps={ displayedApps }
onAppClick={ showAppInfo } onAppClick={ showAppInfo }
......
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