Commit e960b26f authored by Max Alekseenko's avatar Max Alekseenko

add disclaimer to marketplace

parent 12b0f109
......@@ -15,6 +15,7 @@ interface Props extends MarketplaceAppPreview {
isFavorite: boolean;
onFavoriteClick: (id: string, isFavorite: boolean) => void;
isLoading: boolean;
showDisclaimer: (id: string) => void;
}
const MarketplaceAppCard = ({
......@@ -30,9 +31,18 @@ const MarketplaceAppCard = ({
isFavorite,
onFavoriteClick,
isLoading,
showDisclaimer,
}: Props) => {
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) => {
event.preventDefault();
onInfoClick(id);
......@@ -100,6 +110,7 @@ const MarketplaceAppCard = ({
url={ url }
external={ external }
title={ title }
onClick={ handleClick }
/>
</Skeleton>
......
import { LinkOverlay } from '@chakra-ui/react';
import NextLink from 'next/link';
import React from 'react';
import type { MouseEvent } from 'react';
type Props = {
id: string;
url: string;
external?: boolean;
title: string;
onClick?: (event: MouseEvent) => void;
}
const MarketplaceAppCardLink = ({ url, external, id, title }: Props) => {
const MarketplaceAppCardLink = ({ url, external, id, title, onClick }: Props) => {
return external ? (
<LinkOverlay href={ url } isExternal={ true }>
{ title }
</LinkOverlay>
) : (
<NextLink href={{ pathname: '/apps/[id]', query: { id } }} passHref legacyBehavior>
<LinkOverlay>
<LinkOverlay onClick={ onClick }>
{ title }
</LinkOverlay>
</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 = {
favoriteApps: Array<string>;
onFavoriteClick: (id: string, isFavorite: boolean) => void;
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 ? (
<Grid
templateColumns={{
......@@ -41,6 +42,7 @@ const MarketplaceList = ({ apps, onAppClick, favoriteApps, onFavoriteClick, isLo
isFavorite={ favoriteApps.includes(app.id) }
onFavoriteClick={ onFavoriteClick }
isLoading={ isLoading }
showDisclaimer={ showDisclaimer }
/>
)) }
</Grid>
......
......@@ -29,6 +29,8 @@ export default function useMarketplace() {
const [ selectedCategoryId, setSelectedCategoryId ] = React.useState<string>(MarketplaceCategory.ALL);
const [ filterQuery, setFilterQuery ] = React.useState(defaultFilterQuery);
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 favoriteApps = getFavoriteApps();
......@@ -46,10 +48,20 @@ export default function useMarketplace() {
const showAppInfo = React.useCallback((id: string) => {
setSelectedAppId(id);
setIsAppInfoModalOpen(true);
}, []);
const showDisclaimer = React.useCallback((id: string) => {
setSelectedAppId(id);
setIsDisclaimerModalOpen(true);
}, []);
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) => {
setSelectedCategoryId(newCategory);
......@@ -104,6 +116,9 @@ export default function useMarketplace() {
clearSelectedAppId,
favoriteApps,
onFavoriteClick: handleFavoriteClick,
isAppInfoModalOpen,
isDisclaimerModalOpen,
showDisclaimer,
}), [
selectedCategoryId,
categories,
......@@ -118,5 +133,8 @@ export default function useMarketplace() {
isPlaceholderData,
showAppInfo,
debouncedFilterQuery,
isAppInfoModalOpen,
isDisclaimerModalOpen,
showDisclaimer,
]);
}
......@@ -5,6 +5,7 @@ import config from 'configs/app';
import PlusIcon from 'icons/plus.svg';
import MarketplaceAppModal from 'ui/marketplace/MarketplaceAppModal';
import MarketplaceCategoriesMenu from 'ui/marketplace/MarketplaceCategoriesMenu';
import MarketplaceDisclaimerModal from 'ui/marketplace/MarketplaceDisclaimerModal';
import MarketplaceList from 'ui/marketplace/MarketplaceList';
import FilterInput from 'ui/shared/filters/FilterInput';
......@@ -27,6 +28,9 @@ const Marketplace = () => {
clearSelectedAppId,
favoriteApps,
onFavoriteClick,
isAppInfoModalOpen,
isDisclaimerModalOpen,
showDisclaimer,
} = useMarketplace();
if (isError) {
......@@ -68,9 +72,10 @@ const Marketplace = () => {
favoriteApps={ favoriteApps }
onFavoriteClick={ onFavoriteClick }
isLoading={ isPlaceholderData }
showDisclaimer={ showDisclaimer }
/>
{ selectedApp && (
{ (selectedApp && isAppInfoModalOpen) && (
<MarketplaceAppModal
onClose={ clearSelectedAppId }
isFavorite={ favoriteApps.includes(selectedApp.id) }
......@@ -79,6 +84,14 @@ const Marketplace = () => {
/>
) }
{ (selectedApp && isDisclaimerModalOpen) && (
<MarketplaceDisclaimerModal
isOpen={ isDisclaimerModalOpen }
onClose={ clearSelectedAppId }
appId={ selectedApp.id }
/>
) }
<Skeleton
isLoaded={ !isPlaceholderData }
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