feat: improve flow of risk disclaimer presentation

This commit is contained in:
maciek
2023-05-15 16:44:21 +02:00
parent 1a67c41bb4
commit 264b9a59dd
8 changed files with 189 additions and 44 deletions
+16 -3
View File
@@ -28,6 +28,7 @@ import {
ProtocolUpgradeCountdown,
ProtocolUpgradeCountdownMode,
} from '@vegaprotocol/proposals';
import { useCallback } from 'react';
export const Navbar = ({
theme = 'system',
@@ -36,9 +37,11 @@ export const Navbar = ({
}) => {
const { VEGA_DOCS_URL, GITHUB_FEEDBACK_URL } = useEnvironment();
const tokenLink = useLinks(DApp.Token);
const { marketId } = useGlobalStore((store) => ({
marketId: store.marketId,
}));
const marketId = useGlobalStore((store) => store.marketId);
const update = useGlobalStore((store) => store.update);
const showDisclaimer = useCallback(() => {
update({ shouldDisplayDisclaimerDialog: true });
}, [update]);
const tradingPath = marketId
? Links[Routes.MARKET](marketId)
: Links[Routes.MARKET]();
@@ -109,6 +112,16 @@ export const Navbar = ({
{t('Give Feedback')}
</NavExternalLink>
</NavigationItem>
<NavigationItem>
<NavigationLink
data-testid="Portfolio"
to="/#"
onClick={showDisclaimer}
end
>
{t('Disclaimer')}
</NavigationLink>
</NavigationItem>
</NavigationList>
</NavigationContent>
</NavigationItem>
@@ -0,0 +1,28 @@
import { t } from '@vegaprotocol/i18n';
export const Disclaimer = () => {
return (
<>
<p className="mb-6 mt-4">
{t(
'Vega is a decentralised peer-to-peer protocol that can be used to create liquidity and trade derivatives of cryptocurrencies. The Vega Protocol is an implementation layer (layer one) protocol made of free, public, open-source or source-available software. Use of the Vega Protocol involves various risks, including but not limited to, losses while digital assets are being supplied to the Vega Protocol and losses due to the fluctuation of prices of assets. Before using the Vega Protocol, you should review the relevant documentation to make sure that you understand how it works. dditionally, just as you can access email protocols such as SMTP through multiple email clients, ou can potentially access the Vega Protocol through dozens of web or mobile interfaces. You are responsible for doing your own diligence on those interfaces to understand the associated risks and any fees.'
)}
</p>
<p className="mb-6">
{t(
'As described in the Vega Protocol core license, the Vega Protocol is provided "as is", at your own risk, and without warranties of any kind. Although Gobalsky Labs Limited developed much of the initial code for the Vega Protocol, it does not provide or control the Vega Protocol, which is run by third parties deploying it on a bespoke blockchain. Upgrades and modifications to the Vega Protocol are managed in a community-driven way by holders of the VEGA governance token.'
)}
</p>
<p className="mb-6">
{t(
'No developer or entity involved in creating the Vega Protocol will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the Vega Protocol, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or legal costs, or loss of profits, cryptocurrencies, tokens or anything else of value.'
)}
</p>
<p className="mb-8">
{t(
'This website is not located on the world wide web and its data is not stored on servers - physical or virtual. It is located on a decentralised network, the Interplanetary File System ("IPFS"). The IPFS decentralised web is made up of all the computers (nodes) connected to it. Data is therefore stored on many different computers. No party is the operator or hoster of this website. The information provided on this website does not constitute investment advice, financial advice, trading advice, or any other sort of advice and you should not treat any of the website\'s content as such. No party recommends that any cryptocurrency asset should be bought, sold, or held by you via this website. Do conduct your own due diligence and consult our financial advisor before making any investment decisions.'
)}
</p>
</>
);
};
@@ -1,6 +1,8 @@
import { t } from '@vegaprotocol/i18n';
import {
Button,
ExternalLink,
Icon,
Link,
VegaIcon,
VegaIconNames,
@@ -15,6 +17,8 @@ import {
useEnvironment,
} from '@vegaprotocol/environment';
import { useLocalStorage } from '@vegaprotocol/react-helpers';
import { useGlobalStore } from '../../stores';
import { useVegaWallet } from '@vegaprotocol/wallet';
interface Props {
onClose: () => void;
@@ -31,27 +35,21 @@ export const RiskNoticeDialog = ({ onClose, network }: Props) => {
return (
<>
{network === Networks.MAINNET ? (
<MainnetContent />
<MainnetContent handleAcceptRisk={handleAcceptRisk} />
) : (
<TestnetContent network={network} />
<TestnetContent network={network} handleAcceptRisk={handleAcceptRisk} />
)}
<div className="my-4">
<TelemetryApproval
helpText={t(
'Help identify bugs and improve the service by sharing anonymous usage data. You can change this in your settings at any time.'
)}
/>
</div>
<Button onClick={handleAcceptRisk}>
{network === Networks.MAINNET
? t('I understand, Continue')
: t('Continue')}
</Button>
</>
);
};
const TestnetContent = ({ network }: { network: Networks }) => {
const TestnetContent = ({
network,
handleAcceptRisk,
}: {
network: Networks;
handleAcceptRisk: () => void;
}) => {
const { GITHUB_FEEDBACK_URL } = useEnvironment();
const docsLink = useDocsLink();
@@ -91,29 +89,75 @@ const TestnetContent = ({ network }: { network: Networks }) => {
</li>
</ul>
)}
<div className="my-4">
<TelemetryApproval
helpText={t(
'Help identify bugs and improve the service by sharing anonymous usage data. You can change this in your settings at any time.'
)}
/>
</div>
<Button onClick={handleAcceptRisk}>{t('Continue')}</Button>
</>
);
};
const MainnetContent = () => {
const MainnetContent = ({
handleAcceptRisk,
}: {
handleAcceptRisk: () => void;
}) => {
const updateStore = useGlobalStore((store) => store.update);
const { disconnect } = useVegaWallet();
const revokeWalletConnection = () => {
updateStore({ shouldDisplayMainnetRiskDialog: false });
disconnect();
};
const openDisclaimer = () => {
updateStore({ shouldDisplayDisclaimerDialog: true });
};
return (
<>
<h4 className="text-xl mb-2 mt-4">
{t('Regulation may apply to use of this app')}
</h4>
<p className="mb-6">
{t(
'This decentralised application allows you to connect to and use publicly available blockchain services operated by third parties that may include trading, financial products, or other services that may be subject to legal and regulatory restrictions in your jurisdiction. This application is a front end only and does not hold any funds or provide any products or services. It is available to anyone with an internet connection via IPFS and other methods, and the ability to access it does not imply any right to use any services or that it is legal for you to do so. By using this application you accept that it is your responsibility to ensure that your use of the application and any blockchain services accessed through it is compliant with applicable laws and regulations in your jusrisdiction.'
)}
</p>
<h4 className="text-xl mb-2">
{t('Technical and financial risk of loss')}
</h4>
<div className="mt-6">
<div className="bg-neutral-100 dark:bg-neutral-800 dark:text-neutral-200 p-6 mb-6">
<ul className="list-disc ml-6 text-lg">
<li>
{t(
'No party hosts or operates this IFPS website or offers any financial advice'
)}
</li>
<li>
{t(
'You may encounter bugs, loss of functionality or loss of assets'
)}
</li>
<li>
{t('No party accepts any liability for any losses whatsoever')}
</li>
</ul>
</div>
<p className="mb-8">
{t(
'The public blockchain services accessible via this decentralised application are operated by third parties and may carry significant risks including the potential loss of all funds that you deposit or hold with these services. Technical risks include the risk of loss in the event of the failure or compromise of the public blockchain infrastructure or smart contracts that provide any services you use. Financial risks include but are not limited to losses due to volatility, excessive leverage, low liquidity, and your own lack of understanding of the services you use. By using this decentralised application you accept that it is your responsibility to ensure that you understand any services you use and the technical and financial risks inherent in your use. Do not risk what you cannot afford to lose.'
)}
'By using the Vega Console, you acknowledge that you have read and understood the'
)}{' '}
<ExternalLink onClick={openDisclaimer} className="underline">
<span className="flex items-center gap-2">
<span>{t('Vega Console Disclaimer')}</span>
<Icon name="arrow-top-right" size={3} />
</span>
</ExternalLink>
.
</p>
</>
<div className="grid grid-cols-2 gap-5">
<div>
<Button onClick={revokeWalletConnection} fill>
{t('Cancel')}
</Button>
</div>
<div>
<Button onClick={handleAcceptRisk} variant="primary" fill>
{t('I agree')}
</Button>
</div>
</div>
</div>
);
};
@@ -9,6 +9,7 @@ import * as constants from '../constants';
import { RiskNoticeDialog } from './risk-notice-dialog';
import { WelcomeNoticeDialog } from './welcome-notice-dialog';
import { WelcomeLandingDialog } from './welcome-landing-dialog';
import { Disclaimer } from './disclaimer';
import { useGlobalStore } from '../../stores';
import { useEnvironment } from '@vegaprotocol/environment';
import { Networks } from '@vegaprotocol/environment';
@@ -30,18 +31,39 @@ export const WelcomeDialog = () => {
const shouldDisplayWelcomeDialog = useGlobalStore(
(store) => store.shouldDisplayWelcomeDialog
);
const isRiskDialogNeeded = riskAccepted !== 'true' && !('Cypress' in window);
const isWelcomeDialogNeeded = pathname === '/' || shouldDisplayWelcomeDialog;
const onCloseDialog = useCallback(() => {
update({ shouldDisplayWelcomeDialog: isRiskDialogNeeded });
}, [update, isRiskDialogNeeded]);
const shouldDisplayDisclaimerDialog = useGlobalStore(
(store) => store.shouldDisplayDisclaimerDialog
);
const shouldDisplayMainnetRiskDialog = useGlobalStore(
(store) => store.shouldDisplayMainnetRiskDialog
);
const isRiskDialogNeeded =
riskAccepted !== 'true' &&
(VEGA_ENV !== Networks.MAINNET || shouldDisplayMainnetRiskDialog) &&
!('Cypress' in window);
if (isRiskDialogNeeded) {
const isWelcomeDialogNeeded = pathname === '/' || shouldDisplayWelcomeDialog;
const onCloseDialog = useCallback(() => {
update({
shouldDisplayWelcomeDialog:
isRiskDialogNeeded && VEGA_ENV !== Networks.MAINNET,
});
}, [update, isRiskDialogNeeded, VEGA_ENV]);
if (shouldDisplayDisclaimerDialog) {
title = t('Disclaimer');
dialogContent = <Disclaimer />;
size = 'medium';
onClose = () => update({ shouldDisplayDisclaimerDialog: false });
} else if (isRiskDialogNeeded) {
dialogContent = (
<RiskNoticeDialog onClose={onCloseDialog} network={VEGA_ENV} />
);
title = VEGA_ENV === Networks.MAINNET ? t('WARNING') : t('Vega Console');
size = 'medium';
title =
VEGA_ENV === Networks.MAINNET
? t('Understand the risk')
: t('Vega Console');
size = VEGA_ENV === Networks.MAINNET ? 'small' : 'medium';
} else if (isWelcomeDialogNeeded && data?.length === 0) {
dialogContent = <WelcomeNoticeDialog />;
onClose = onCloseDialog;
@@ -16,6 +16,8 @@ import { Link } from 'react-router-dom';
import { ProposedMarkets } from './proposed-markets';
import { Links, Routes } from '../../pages/client-router';
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
import { TelemetryApproval } from './telemetry-approval';
import { Networks, useEnvironment } from '@vegaprotocol/environment';
export const SelectMarketLandingTable = ({
markets,
@@ -94,6 +96,8 @@ export const WelcomeLandingDialog = ({
onClose,
}: LandingDialogContainerProps) => {
const { data, loading, error } = useMarketList();
const { VEGA_ENV } = useEnvironment();
const isMainnet = VEGA_ENV === Networks.MAINNET;
if (error) {
return (
<div className="flex justify-center items-center">
@@ -114,6 +118,13 @@ export const WelcomeLandingDialog = ({
<>
<WelcomeDialogHeader />
<SelectMarketLandingTable markets={data} onClose={onClose} />
{isMainnet && (
<TelemetryApproval
helpText={t(
'Help identify bugs and improve the service by sharing anonymous usage data. You can change this in your settings at any time.'
)}
/>
)}
</>
);
};
@@ -10,6 +10,7 @@ import {
useLinks,
} from '@vegaprotocol/environment';
import { ProposedMarkets } from './proposed-markets';
import { TelemetryApproval } from './telemetry-approval';
export const WelcomeNoticeDialog = () => {
const { VEGA_ENV } = useEnvironment();
@@ -56,6 +57,15 @@ export const WelcomeNoticeDialog = () => {
{t('Read about the mainnet launch')}
</ExternalLink>
</li>
{isMainnet && (
<li>
<TelemetryApproval
helpText={t(
'Help identify bugs and improve the service by sharing anonymous usage data. You can change this in your settings at any time.'
)}
/>
</li>
)}
</ul>
<ProposedMarkets />
</>
+15 -2
View File
@@ -9,13 +9,26 @@ import { DepositDialog } from '@vegaprotocol/deposits';
import { Web3ConnectUncontrolledDialog } from '@vegaprotocol/web3';
import { WelcomeDialog } from '../components/welcome-dialog';
import { TransferDialog } from '@vegaprotocol/accounts';
import { useGlobalStore } from '../stores';
import { useCallback } from 'react';
import { useLocalStorage } from '@vegaprotocol/react-helpers';
import * as constants from '../components/constants';
const DialogsContainer = () => {
const { isOpen, id, trigger, setOpen } = useAssetDetailsDialogStore();
const [riskAccepted] = useLocalStorage(constants.RISK_ACCEPTED_KEY);
const update = useGlobalStore((store) => store.update);
const openRiskDialog = useCallback(() => {
if (riskAccepted !== 'true') {
update({ shouldDisplayMainnetRiskDialog: true });
}
}, [update, riskAccepted]);
return (
<>
<VegaConnectDialog connectors={Connectors} />
<VegaConnectDialog
connectors={Connectors}
onChangeOpen={openRiskDialog}
/>
<AssetDetailsDialog
assetId={id}
trigger={trigger || null}
+4
View File
@@ -6,6 +6,8 @@ interface GlobalStore {
marketId: string | null;
update: (store: Partial<Omit<GlobalStore, 'update'>>) => void;
shouldDisplayWelcomeDialog: boolean;
shouldDisplayDisclaimerDialog: boolean;
shouldDisplayMainnetRiskDialog: boolean;
}
interface PageTitleStore {
@@ -16,6 +18,8 @@ interface PageTitleStore {
export const useGlobalStore = create<GlobalStore>()((set) => ({
marketId: LocalStorage.getItem('marketId') || null,
shouldDisplayWelcomeDialog: false,
shouldDisplayDisclaimerDialog: false,
shouldDisplayMainnetRiskDialog: false,
update: (newState) => {
set(
produce((state: GlobalStore) => {