refactor so that consuming app chooses to render modal and what connectors to use
This commit is contained in:
parent
ff24a4a3ba
commit
fba3101753
6
apps/trading/lib/connectors.ts
Normal file
6
apps/trading/lib/connectors.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { InjectedConnector, RestConnector } from '@vegaprotocol/react-helpers';
|
||||
|
||||
export const Connectors = {
|
||||
injected: new InjectedConnector(),
|
||||
rest: new RestConnector(),
|
||||
};
|
@ -50,15 +50,19 @@ function VegaTradingApp({ Component, pageProps }: AppProps) {
|
||||
);
|
||||
}
|
||||
|
||||
const VegaWalletButton = () => {
|
||||
const { setConnectDialog, disconnect, publicKeys } = useVegaWallet();
|
||||
interface VegaWalletButtonProps {
|
||||
setConnectDialog: (isOpen: boolean) => void;
|
||||
}
|
||||
|
||||
const VegaWalletButton = ({ setConnectDialog }: VegaWalletButtonProps) => {
|
||||
const { disconnect, publicKeys } = useVegaWallet();
|
||||
const isConnected = publicKeys !== null;
|
||||
|
||||
const handleClick = () => {
|
||||
if (isConnected) {
|
||||
disconnect();
|
||||
} else {
|
||||
setConnectDialog();
|
||||
setConnectDialog(true);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,63 +1,80 @@
|
||||
import { useState } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { Dialog } from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
InjectedConnector,
|
||||
RestConnector,
|
||||
VegaConnector,
|
||||
} from './vega-wallet-connectors';
|
||||
import { VegaConnector } from './connectors';
|
||||
import { RestConnectorForm } from './rest-connector-form';
|
||||
import { useEffect } from 'react';
|
||||
import { RestConnector, useVegaWallet } from '.';
|
||||
|
||||
export const Connectors = {
|
||||
injected: new InjectedConnector(),
|
||||
rest: new RestConnector(),
|
||||
};
|
||||
|
||||
interface ConnectDialogProps {
|
||||
interface VegaConnectDialogProps {
|
||||
connectors: { [name: string]: VegaConnector };
|
||||
dialogOpen: boolean;
|
||||
setDialogOpen: (isOpen: boolean) => void;
|
||||
connect: (connector: VegaConnector) => void;
|
||||
}
|
||||
|
||||
export function ConnectDialog({
|
||||
export function VegaConnectDialog({
|
||||
connectors,
|
||||
dialogOpen,
|
||||
setDialogOpen,
|
||||
connect,
|
||||
}: ConnectDialogProps) {
|
||||
const [isRestConnector, setIsRestConnector] = useState(false);
|
||||
}: VegaConnectDialogProps) {
|
||||
const { connect } = useVegaWallet();
|
||||
const [selectedConnector, setSelectedConnector] =
|
||||
useState<VegaConnector | null>(null);
|
||||
|
||||
const connectAndClose = useCallback(
|
||||
(connector: VegaConnector) => {
|
||||
connect(connector);
|
||||
setDialogOpen(false);
|
||||
},
|
||||
[connect, setDialogOpen]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!dialogOpen) {
|
||||
setIsRestConnector(false);
|
||||
if (
|
||||
selectedConnector !== null &&
|
||||
selectedConnector instanceof RestConnector === false
|
||||
) {
|
||||
connectAndClose(selectedConnector);
|
||||
}
|
||||
}, [dialogOpen]);
|
||||
}, [selectedConnector, connectAndClose]);
|
||||
|
||||
return (
|
||||
<Dialog open={dialogOpen} setOpen={setDialogOpen}>
|
||||
<div className="bg-black p-5 w-100 text-white">
|
||||
{isRestConnector ? (
|
||||
<RestConnectorForm setDialogOpen={setDialogOpen} />
|
||||
) : (
|
||||
<div className="flex gap-5 flex-col">
|
||||
{Object.entries(Connectors).map(([key, connector]) => (
|
||||
<button
|
||||
key={key}
|
||||
onClick={() => {
|
||||
if (key === 'rest') {
|
||||
// show form so that we can get an authentication token before 'connecting'
|
||||
setIsRestConnector(true);
|
||||
} else {
|
||||
connect(connector);
|
||||
setDialogOpen(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{key} provider
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{selectedConnector instanceof RestConnector ? (
|
||||
<RestConnectorForm
|
||||
connector={selectedConnector}
|
||||
setDialogOpen={setDialogOpen}
|
||||
onAuthenticate={() => {
|
||||
connectAndClose(selectedConnector);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
gap: 10,
|
||||
}}
|
||||
>
|
||||
{Object.entries(connectors).map(([key, connector]) => (
|
||||
<button
|
||||
key={key}
|
||||
onClick={() => {
|
||||
setSelectedConnector(connector);
|
||||
// if (key === 'rest') {
|
||||
// // show form so that we can get an authentication token before 'connecting'
|
||||
// setIsRestConnector(true);
|
||||
// } else {
|
||||
// connect(connector);
|
||||
// setDialogOpen(false);
|
||||
// }
|
||||
}}
|
||||
>
|
||||
{key} provider
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { VegaKey } from '@vegaprotocol/vegawallet-service-api-client';
|
||||
import { createContext } from 'react';
|
||||
import { VegaConnector } from './vega-wallet-connectors';
|
||||
import { VegaConnector } from './connectors';
|
||||
|
||||
interface VegaWalletContextShape {
|
||||
publicKey: VegaKey | null;
|
||||
publicKeys: VegaKey[] | null;
|
||||
setConnectDialog: (isOpen?: boolean) => void;
|
||||
connect: (connector: VegaConnector) => Promise<void>;
|
||||
disconnect: () => Promise<void>;
|
||||
connector: VegaConnector | null;
|
@ -1,3 +1,5 @@
|
||||
export * from './vega-wallet-provider';
|
||||
export * from './vega-wallet-context';
|
||||
export * from './provider';
|
||||
export * from './context';
|
||||
export * from './hooks';
|
||||
export * from './connect-dialog';
|
||||
export * from './connectors';
|
||||
|
@ -1,40 +1,31 @@
|
||||
import { VegaKey } from '@vegaprotocol/vegawallet-service-api-client';
|
||||
import { ReactNode, useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { ConnectDialog } from './connect-dialog';
|
||||
import { VegaConnector } from './vega-wallet-connectors';
|
||||
import { VegaWalletContext } from './vega-wallet-context';
|
||||
import { VegaConnector } from './connectors';
|
||||
import { VegaWalletContext } from './context';
|
||||
|
||||
interface VegaWalletProviderProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const VegaWalletProvider = ({ children }: VegaWalletProviderProps) => {
|
||||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
const [publicKey, setPublicKey] = useState<VegaKey | null>(null);
|
||||
const [publicKeys, setPublicKeys] = useState<VegaKey[] | null>(null);
|
||||
const connector = useRef<VegaConnector | null>(null);
|
||||
|
||||
const setConnectDialog = useCallback((isOpen?: boolean) => {
|
||||
setDialogOpen((curr) => {
|
||||
if (isOpen === undefined) return !curr;
|
||||
return isOpen;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const connect = useCallback(async (c: VegaConnector) => {
|
||||
connector.current = c;
|
||||
try {
|
||||
const res = await c.connect();
|
||||
setPublicKeys(res);
|
||||
setPublicKey(res[0]);
|
||||
} catch (err) {
|
||||
console.log('connect failed');
|
||||
}
|
||||
}, []);
|
||||
|
||||
const disconnect = useCallback(async () => {
|
||||
if (!connector.current) return;
|
||||
try {
|
||||
await connector.current.disconnect();
|
||||
await connector.current?.disconnect();
|
||||
setPublicKeys(null);
|
||||
setPublicKey(null);
|
||||
connector.current = null;
|
||||
@ -47,21 +38,15 @@ export const VegaWalletProvider = ({ children }: VegaWalletProviderProps) => {
|
||||
return {
|
||||
publicKey,
|
||||
publicKeys,
|
||||
setConnectDialog,
|
||||
connect,
|
||||
disconnect,
|
||||
connector: connector.current,
|
||||
};
|
||||
}, [publicKey, publicKeys, connect, disconnect, setConnectDialog, connector]);
|
||||
}, [publicKey, publicKeys, connect, disconnect, connector]);
|
||||
|
||||
return (
|
||||
<VegaWalletContext.Provider value={contextValue}>
|
||||
{children}
|
||||
<ConnectDialog
|
||||
dialogOpen={dialogOpen}
|
||||
setDialogOpen={setDialogOpen}
|
||||
connect={connect}
|
||||
/>
|
||||
</VegaWalletContext.Provider>
|
||||
);
|
||||
};
|
@ -1,6 +1,5 @@
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useVegaWallet } from '.';
|
||||
import { Connectors } from './connect-dialog';
|
||||
import { RestConnector } from '.';
|
||||
|
||||
interface FormFields {
|
||||
wallet: string;
|
||||
@ -8,23 +7,31 @@ interface FormFields {
|
||||
}
|
||||
|
||||
interface RestConnectorFormProps {
|
||||
connector: RestConnector;
|
||||
setDialogOpen: (isOpen: boolean) => void;
|
||||
onAuthenticate: () => void;
|
||||
}
|
||||
|
||||
export function RestConnectorForm({ setDialogOpen }: RestConnectorFormProps) {
|
||||
const { connect } = useVegaWallet();
|
||||
const { register, handleSubmit } = useForm<FormFields>();
|
||||
export function RestConnectorForm({
|
||||
connector,
|
||||
setDialogOpen,
|
||||
onAuthenticate,
|
||||
}: RestConnectorFormProps) {
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
} = useForm<FormFields>();
|
||||
|
||||
async function onSubmit(fields: FormFields) {
|
||||
try {
|
||||
const success = await Connectors.rest.authenticate({
|
||||
const success = await connector.authenticate({
|
||||
wallet: fields.wallet,
|
||||
passphrase: fields.passphrase,
|
||||
});
|
||||
|
||||
if (success) {
|
||||
connect(Connectors.rest);
|
||||
setDialogOpen(false);
|
||||
onAuthenticate();
|
||||
} else {
|
||||
throw new Error('Authentication failed');
|
||||
}
|
||||
@ -35,21 +42,21 @@ export function RestConnectorForm({ setDialogOpen }: RestConnectorFormProps) {
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="vega-wallet-form">
|
||||
<div className="mb-5">
|
||||
<div style={{ marginBottom: 10 }}>
|
||||
<input
|
||||
{...register('wallet')}
|
||||
{...register('wallet', { required: 'Required' })}
|
||||
type="text"
|
||||
placeholder="Wallet"
|
||||
className="text-black"
|
||||
/>
|
||||
{errors.wallet?.message && <div>{errors.wallet.message}</div>}
|
||||
</div>
|
||||
<div className="mb-5">
|
||||
<div style={{ marginBottom: 10 }}>
|
||||
<input
|
||||
{...register('passphrase')}
|
||||
{...register('passphrase', { required: 'Required' })}
|
||||
type="text"
|
||||
placeholder="Passphrase"
|
||||
className="text-black"
|
||||
/>
|
||||
{errors.passphrase?.message && <div>{errors.passphrase.message}</div>}
|
||||
</div>
|
||||
<button type="submit">Connect</button>
|
||||
</form>
|
||||
|
@ -1,18 +1,19 @@
|
||||
// TODO: fine for now however will leak state between tests (we don't really have) in future. Ideally should use a provider
|
||||
export const LocalStorage = {
|
||||
getItem: (key: string) => {
|
||||
if (typeof window === 'undefined') return null;
|
||||
try {
|
||||
const item = window.localStorage.getItem(key);
|
||||
return item ? JSON.parse(item) : null;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
},
|
||||
setItem: (key: string, value: any) => {
|
||||
if (typeof window === 'undefined') return;
|
||||
try {
|
||||
window.localStorage.setItem(key, JSON.stringify(value));
|
||||
const item = window.localStorage.getItem(key);
|
||||
return item;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
setItem: (key: string, value: string) => {
|
||||
if (typeof window === 'undefined') return;
|
||||
try {
|
||||
window.localStorage.setItem(key, value);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
@ -11,10 +11,25 @@ export function Dialog({ children, open, setOpen }: DialogProps) {
|
||||
return (
|
||||
<DialogPrimitives.Root open={open} onOpenChange={(x) => setOpen(x)}>
|
||||
<DialogPrimitives.Portal>
|
||||
<DialogPrimitives.Overlay className="bg-gray/75 fixed inset-0" />
|
||||
<DialogPrimitives.Overlay
|
||||
style={{
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
background: 'rgba(0,0,0,0.3)',
|
||||
}}
|
||||
/>
|
||||
<DialogPrimitives.Content
|
||||
style={{ width: 300, top: 40, left: 'calc(50% - 150px)' }}
|
||||
className="fixed inset-0"
|
||||
style={{
|
||||
position: 'fixed',
|
||||
width: 300,
|
||||
background: 'white',
|
||||
top: 40,
|
||||
left: 'calc(50% - 150px)',
|
||||
padding: 20,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</DialogPrimitives.Content>
|
||||
|
Loading…
Reference in New Issue
Block a user