import { create } from 'zustand'; import { Button, Dialog, FormGroup, Icon, Input, Link, Loader, } from '@vegaprotocol/ui-toolkit'; import { useCallback, useState } from 'react'; import type { WalletClientError } from '@vegaprotocol/wallet-client'; import { t } from '@vegaprotocol/i18n'; import type { VegaConnector } from '../connectors'; import { ViewConnector } from '../connectors'; import { JsonRpcConnector, RestConnector } from '../connectors'; import { RestConnectorForm } from './rest-connector-form'; import { JsonRpcConnectorForm } from './json-rpc-connector-form'; import { Networks, useEnvironment, ExternalLinks, } from '@vegaprotocol/environment'; import { ConnectDialogContent, ConnectDialogFooter, ConnectDialogTitle, } from './connect-dialog-elements'; import type { Status } from '../use-json-rpc-connect'; import { useJsonRpcConnect } from '../use-json-rpc-connect'; import { ViewConnectorForm } from './view-connector-form'; import { useChainIdQuery } from './__generated__/ChainId'; import { useVegaWallet } from '../use-vega-wallet'; export const CLOSE_DELAY = 1700; type Connectors = { [key: string]: VegaConnector }; type WalletType = 'jsonRpc' | 'hosted' | 'view'; export interface VegaConnectDialogProps { connectors: Connectors; onChangeOpen?: (open: boolean) => void; riskMessage?: React.ReactNode; } export const useVegaWalletDialogStore = create()( (set) => ({ vegaWalletDialogOpen: false, updateVegaWalletDialog: (open: boolean) => set({ vegaWalletDialogOpen: open }), openVegaWalletDialog: () => set({ vegaWalletDialogOpen: true }), closeVegaWalletDialog: () => set({ vegaWalletDialogOpen: false }), }) ); export interface VegaWalletDialogStore { vegaWalletDialogOpen: boolean; updateVegaWalletDialog: (open: boolean) => void; openVegaWalletDialog: () => void; closeVegaWalletDialog: () => void; } export const VegaConnectDialog = ({ connectors, onChangeOpen, riskMessage, }: VegaConnectDialogProps) => { const vegaWalletDialogOpen = useVegaWalletDialogStore( (store) => store.vegaWalletDialogOpen ); const updateVegaWalletDialog = useVegaWalletDialogStore( (store) => (open: boolean) => { store.updateVegaWalletDialog(open); onChangeOpen?.(open); } ); const closeVegaWalletDialog = useVegaWalletDialogStore((store) => () => { store.closeVegaWalletDialog(); onChangeOpen?.(false); }); const { disconnect, acknowledgeNeeded } = useVegaWallet(); const onVegaWalletDialogChange = useCallback( (open: boolean) => { updateVegaWalletDialog(open); if (!open && acknowledgeNeeded) { disconnect(); } }, [updateVegaWalletDialog, acknowledgeNeeded, disconnect] ); const { data, error, loading } = useChainIdQuery(); const renderContent = () => { if (error) { return ( {t('Could not retrieve chain id')} ); } if (loading || !data) { return ( {t('Fetching chain ID')}
); } return ( ); }; return ( {renderContent()} ); }; const ConnectDialogContainer = ({ connectors, closeDialog, appChainId, riskMessage, }: { connectors: Connectors; closeDialog: () => void; appChainId: string; riskMessage?: React.ReactNode; }) => { const { VEGA_WALLET_URL, VEGA_ENV, HOSTED_WALLET_URL } = useEnvironment(); const [selectedConnector, setSelectedConnector] = useState(); const [walletUrl, setWalletUrl] = useState(VEGA_WALLET_URL || ''); const [walletType, setWalletType] = useState(); const reset = useCallback(() => { setSelectedConnector(undefined); setWalletType(undefined); }, []); const delayedOnConnect = useCallback(() => { setTimeout(() => { closeDialog(); }, CLOSE_DELAY); }, [closeDialog]); const { connect, ...jsonRpcState } = useJsonRpcConnect(delayedOnConnect); const handleSelect = (type: WalletType, isHosted = false) => { let connector; if (isHosted) { // If the user has selected hosted wallet ensure that we are connecting to https://vega-hosted-wallet.on.fleek.co/ // otherwise use the default walletUrl or what has been put in the input connector = connectors['rest']; connector.url = HOSTED_WALLET_URL || walletUrl; } else { connector = connectors[type]; connector.url = walletUrl; } if (!connector) { throw new Error(`Connector type: ${type} not configured`); } setSelectedConnector(connector); setWalletType(type); // Immediately connect on selection if jsonRpc is selected, we can't do this // for rest because we need to show an authentication form if (connector instanceof JsonRpcConnector) { connect(connector, appChainId); } }; return selectedConnector !== undefined && walletType !== undefined ? ( ) : ( ); }; const ConnectorList = ({ onSelect, walletUrl, setWalletUrl, isMainnet, }: { onSelect: (type: WalletType, isHosted?: boolean) => void; walletUrl: string; setWalletUrl: (value: string) => void; isMainnet: boolean; }) => { return ( <> {t('Connect')}
  • onSelect('jsonRpc')} />
  • {!isMainnet && (
  • onSelect('hosted', true)} />
  • )}
  • {t('OR')}
    onSelect('view')} />
); }; const SelectedForm = ({ type, connector, appChainId, jsonRpcState, reset, onConnect, riskMessage, }: { type: WalletType; connector: VegaConnector; appChainId: string; jsonRpcState: { status: Status; error: WalletClientError | null; }; reset: () => void; onConnect: () => void; riskMessage?: React.ReactNode; }) => { if (connector instanceof RestConnector) { return ( <> {t('Connect')}
{type === 'hosted' ? (

{t('For demo purposes get a ')} {t('hosted wallet')} {t(', or for the real experience create a wallet in the ')} {t('Vega wallet app')}

) : ( )} ); } if (connector instanceof JsonRpcConnector) { return ( ); } if (connector instanceof ViewConnector) { return ( <> ); } throw new Error('No connector selected'); }; const ConnectionOption = ({ type, text, onClick, }: { type: WalletType; text: string; onClick: () => void; }) => { return ( ); }; const CustomUrlInput = ({ walletUrl, setWalletUrl, }: { walletUrl: string; setWalletUrl: (url: string) => void; }) => { const [urlInputExpanded, setUrlInputExpanded] = useState(false); return urlInputExpanded ? ( <>

{t('Custom wallet location')}

setWalletUrl(e.target.value)} name="wallet-url" />

{t('Choose wallet app to connect')}

) : (

{t( 'Choose wallet app to connect, or to change port or server URL enter a ' )} {' '} {t(' first')}

); };