Commit e960b26f authored by Max Alekseenko's avatar Max Alekseenko

add disclaimer to marketplace

parent 12b0f109
...@@ -15,6 +15,7 @@ interface Props extends MarketplaceAppPreview { ...@@ -15,6 +15,7 @@ interface Props extends MarketplaceAppPreview {
isFavorite: boolean; isFavorite: boolean;
onFavoriteClick: (id: string, isFavorite: boolean) => void; onFavoriteClick: (id: string, isFavorite: boolean) => void;
isLoading: boolean; isLoading: boolean;
showDisclaimer: (id: string) => void;
} }
const MarketplaceAppCard = ({ const MarketplaceAppCard = ({
...@@ -30,9 +31,18 @@ const MarketplaceAppCard = ({ ...@@ -30,9 +31,18 @@ const MarketplaceAppCard = ({
isFavorite, isFavorite,
onFavoriteClick, onFavoriteClick,
isLoading, isLoading,
showDisclaimer,
}: Props) => { }: Props) => {
const categoriesLabel = categories.join(', '); const categoriesLabel = categories.join(', ');
const handleClick = useCallback((event: MouseEvent) => {
const isShown = window.localStorage.getItem('marketplace-disclaimer-shown');
if (!isShown) {
event.preventDefault();
showDisclaimer(id);
}
}, [ showDisclaimer, id ]);
const handleInfoClick = useCallback((event: MouseEvent) => { const handleInfoClick = useCallback((event: MouseEvent) => {
event.preventDefault(); event.preventDefault();
onInfoClick(id); onInfoClick(id);
...@@ -100,6 +110,7 @@ const MarketplaceAppCard = ({ ...@@ -100,6 +110,7 @@ const MarketplaceAppCard = ({
url={ url } url={ url }
external={ external } external={ external }
title={ title } title={ title }
onClick={ handleClick }
/> />
</Skeleton> </Skeleton>
......
import { LinkOverlay } from '@chakra-ui/react'; import { LinkOverlay } from '@chakra-ui/react';
import NextLink from 'next/link'; import NextLink from 'next/link';
import React from 'react'; import React from 'react';
import type { MouseEvent } from 'react';
type Props = { type Props = {
id: string; id: string;
url: string; url: string;
external?: boolean; external?: boolean;
title: string; title: string;
onClick?: (event: MouseEvent) => void;
} }
const MarketplaceAppCardLink = ({ url, external, id, title }: Props) => { const MarketplaceAppCardLink = ({ url, external, id, title, onClick }: Props) => {
return external ? ( return external ? (
<LinkOverlay href={ url } isExternal={ true }> <LinkOverlay href={ url } isExternal={ true }>
{ title } { title }
</LinkOverlay> </LinkOverlay>
) : ( ) : (
<NextLink href={{ pathname: '/apps/[id]', query: { id } }} passHref legacyBehavior> <NextLink href={{ pathname: '/apps/[id]', query: { id } }} passHref legacyBehavior>
<LinkOverlay> <LinkOverlay onClick={ onClick }>
{ title } { title }
</LinkOverlay> </LinkOverlay>
</NextLink> </NextLink>
......
import { Heading, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, ModalOverlay, Text, Button, useColorModeValue } from '@chakra-ui/react';
import NextLink from 'next/link';
import React from 'react';
import useIsMobile from 'lib/hooks/useIsMobile';
type Props = {
isOpen: boolean;
onClose: () => void;
appId: string;
}
const MarketplaceDisclaimerModal = ({ isOpen, onClose, appId }: Props) => {
const isMobile = useIsMobile();
const handleContinueClick = React.useCallback(() => {
window.localStorage.setItem('marketplace-disclaimer-shown', 'true');
}, [ ]);
return (
<Modal
isOpen={ isOpen }
onClose={ onClose }
size={ isMobile ? 'full' : 'md' }
isCentered
>
<ModalOverlay/>
<ModalContent>
<ModalHeader>
<Heading
as="h2"
fontSize="2xl"
fontWeight="medium"
lineHeight={ 1 }
color={ useColorModeValue('blackAlpha.800', 'whiteAlpha.800') }
>
Disclaimer
</Heading>
</ModalHeader>
<ModalBody>
<Text color={ useColorModeValue('gray.800', 'whiteAlpha.800') }>
You are now accessing a third-party app. Blockscout does not own, control, maintain, or audit 3rd party apps,{ ' ' }
and is not liable for any losses associated with these interactions. Please do so at your own risk.
<br/><br/>
By clicking continue, you agree that you understand the risks and have read the Disclaimer.
</Text>
</ModalBody>
<ModalFooter
display="flex"
flexDirection="row"
alignItems="center"
>
<NextLink href={{ pathname: '/apps/[id]', query: { id: appId } }} passHref legacyBehavior>
<Button
variant="solid"
colorScheme="blue"
mr={ 6 }
py="10px"
onClick={ handleContinueClick }
>
Continue to app
</Button>
</NextLink>
<Button
variant="outline"
colorScheme="blue"
onClick={ onClose }
>
Cancel
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
};
export default MarketplaceDisclaimerModal;
...@@ -14,9 +14,10 @@ type Props = { ...@@ -14,9 +14,10 @@ type Props = {
favoriteApps: Array<string>; favoriteApps: Array<string>;
onFavoriteClick: (id: string, isFavorite: boolean) => void; onFavoriteClick: (id: string, isFavorite: boolean) => void;
isLoading: boolean; isLoading: boolean;
showDisclaimer: (id: string) => void;
} }
const MarketplaceList = ({ apps, onAppClick, favoriteApps, onFavoriteClick, isLoading }: Props) => { const MarketplaceList = ({ apps, onAppClick, favoriteApps, onFavoriteClick, isLoading, showDisclaimer }: Props) => {
return apps.length > 0 ? ( return apps.length > 0 ? (
<Grid <Grid
templateColumns={{ templateColumns={{
...@@ -41,6 +42,7 @@ const MarketplaceList = ({ apps, onAppClick, favoriteApps, onFavoriteClick, isLo ...@@ -41,6 +42,7 @@ const MarketplaceList = ({ apps, onAppClick, favoriteApps, onFavoriteClick, isLo
isFavorite={ favoriteApps.includes(app.id) } isFavorite={ favoriteApps.includes(app.id) }
onFavoriteClick={ onFavoriteClick } onFavoriteClick={ onFavoriteClick }
isLoading={ isLoading } isLoading={ isLoading }
showDisclaimer={ showDisclaimer }
/> />
)) } )) }
</Grid> </Grid>
......
...@@ -29,6 +29,8 @@ export default function useMarketplace() { ...@@ -29,6 +29,8 @@ export default function useMarketplace() {
const [ selectedCategoryId, setSelectedCategoryId ] = React.useState<string>(MarketplaceCategory.ALL); const [ selectedCategoryId, setSelectedCategoryId ] = React.useState<string>(MarketplaceCategory.ALL);
const [ filterQuery, setFilterQuery ] = React.useState(defaultFilterQuery); const [ filterQuery, setFilterQuery ] = React.useState(defaultFilterQuery);
const [ favoriteApps, setFavoriteApps ] = React.useState<Array<string>>([]); const [ favoriteApps, setFavoriteApps ] = React.useState<Array<string>>([]);
const [ isAppInfoModalOpen, setIsAppInfoModalOpen ] = React.useState<boolean>(false);
const [ isDisclaimerModalOpen, setIsDisclaimerModalOpen ] = React.useState<boolean>(false);
const handleFavoriteClick = React.useCallback((id: string, isFavorite: boolean) => { const handleFavoriteClick = React.useCallback((id: string, isFavorite: boolean) => {
const favoriteApps = getFavoriteApps(); const favoriteApps = getFavoriteApps();
...@@ -46,10 +48,20 @@ export default function useMarketplace() { ...@@ -46,10 +48,20 @@ export default function useMarketplace() {
const showAppInfo = React.useCallback((id: string) => { const showAppInfo = React.useCallback((id: string) => {
setSelectedAppId(id); setSelectedAppId(id);
setIsAppInfoModalOpen(true);
}, []);
const showDisclaimer = React.useCallback((id: string) => {
setSelectedAppId(id);
setIsDisclaimerModalOpen(true);
}, []); }, []);
const debouncedFilterQuery = useDebounce(filterQuery, 500); const debouncedFilterQuery = useDebounce(filterQuery, 500);
const clearSelectedAppId = React.useCallback(() => setSelectedAppId(null), []); const clearSelectedAppId = React.useCallback(() => {
setSelectedAppId(null);
setIsAppInfoModalOpen(false);
setIsDisclaimerModalOpen(false);
}, []);
const handleCategoryChange = React.useCallback((newCategory: string) => { const handleCategoryChange = React.useCallback((newCategory: string) => {
setSelectedCategoryId(newCategory); setSelectedCategoryId(newCategory);
...@@ -104,6 +116,9 @@ export default function useMarketplace() { ...@@ -104,6 +116,9 @@ export default function useMarketplace() {
clearSelectedAppId, clearSelectedAppId,
favoriteApps, favoriteApps,
onFavoriteClick: handleFavoriteClick, onFavoriteClick: handleFavoriteClick,
isAppInfoModalOpen,
isDisclaimerModalOpen,
showDisclaimer,
}), [ }), [
selectedCategoryId, selectedCategoryId,
categories, categories,
...@@ -118,5 +133,8 @@ export default function useMarketplace() { ...@@ -118,5 +133,8 @@ export default function useMarketplace() {
isPlaceholderData, isPlaceholderData,
showAppInfo, showAppInfo,
debouncedFilterQuery, debouncedFilterQuery,
isAppInfoModalOpen,
isDisclaimerModalOpen,
showDisclaimer,
]); ]);
} }
...@@ -5,6 +5,7 @@ import config from 'configs/app'; ...@@ -5,6 +5,7 @@ import config from 'configs/app';
import PlusIcon from 'icons/plus.svg'; import PlusIcon from 'icons/plus.svg';
import MarketplaceAppModal from 'ui/marketplace/MarketplaceAppModal'; import MarketplaceAppModal from 'ui/marketplace/MarketplaceAppModal';
import MarketplaceCategoriesMenu from 'ui/marketplace/MarketplaceCategoriesMenu'; import MarketplaceCategoriesMenu from 'ui/marketplace/MarketplaceCategoriesMenu';
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';
...@@ -27,6 +28,9 @@ const Marketplace = () => { ...@@ -27,6 +28,9 @@ const Marketplace = () => {
clearSelectedAppId, clearSelectedAppId,
favoriteApps, favoriteApps,
onFavoriteClick, onFavoriteClick,
isAppInfoModalOpen,
isDisclaimerModalOpen,
showDisclaimer,
} = useMarketplace(); } = useMarketplace();
if (isError) { if (isError) {
...@@ -68,9 +72,10 @@ const Marketplace = () => { ...@@ -68,9 +72,10 @@ const Marketplace = () => {
favoriteApps={ favoriteApps } favoriteApps={ favoriteApps }
onFavoriteClick={ onFavoriteClick } onFavoriteClick={ onFavoriteClick }
isLoading={ isPlaceholderData } isLoading={ isPlaceholderData }
showDisclaimer={ showDisclaimer }
/> />
{ selectedApp && ( { (selectedApp && isAppInfoModalOpen) && (
<MarketplaceAppModal <MarketplaceAppModal
onClose={ clearSelectedAppId } onClose={ clearSelectedAppId }
isFavorite={ favoriteApps.includes(selectedApp.id) } isFavorite={ favoriteApps.includes(selectedApp.id) }
...@@ -79,6 +84,14 @@ const Marketplace = () => { ...@@ -79,6 +84,14 @@ const Marketplace = () => {
/> />
) } ) }
{ (selectedApp && isDisclaimerModalOpen) && (
<MarketplaceDisclaimerModal
isOpen={ isDisclaimerModalOpen }
onClose={ clearSelectedAppId }
appId={ selectedApp.id }
/>
) }
<Skeleton <Skeleton
isLoaded={ !isPlaceholderData } isLoaded={ !isPlaceholderData }
marginTop={{ base: 8, sm: 16 }} marginTop={{ base: 8, sm: 16 }}
......
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