Skip to content

Commit

Permalink
chore: refactor wallet-adapter-react to modular files
Browse files Browse the repository at this point in the history
  • Loading branch information
work-kevin-flynn committed Nov 19, 2024
1 parent 70d75fb commit f7ed0ab
Show file tree
Hide file tree
Showing 15 changed files with 273 additions and 205 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@ package.json.lerna_backup

*.crt
*.pem
.eslintcache
.eslintcache
**/jest-report.xml
**/coverage-summary.json
2 changes: 0 additions & 2 deletions packages/react/coverage/coverage-summary.json

This file was deleted.

3 changes: 0 additions & 3 deletions packages/react/jest-report.xml

This file was deleted.

4 changes: 3 additions & 1 deletion packages/react/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,9 @@ const config: Config = {
'^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
},
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
// transformIgnorePatterns: [],
transformIgnorePatterns: [
'.pnpm/node_modules/(?!((jest-)?react-native(-.*)?|@react-native(-community)?|victory(-.*)?|uuid)|react-navigation|@shopify/react-native-skia|@react-navigation/.*/)',
],

// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,
Expand Down
2 changes: 1 addition & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"scripts": {
"dev": "father dev",
"build": "father build",
"test": "jest --config=jest.config.ts --detectOpenHandles",
"test": "NODE_OPTIONS='$NODE_OPTIONS --experimental-vm-modules' jest --config=jest.config.ts --detectOpenHandles",
"test:coverage": "jest --config=jest.config.ts --coverage --detectOpenHandles"
},
"dependencies": {
Expand Down
27 changes: 27 additions & 0 deletions packages/react/src/__tests__/context.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { render, screen } from '@testing-library/react';
import { WebLoginProvider } from '../context';

const mockBridgeAPI = {
getSignIn: jest.fn((children) => children),
};

describe('WebLoginProvider', () => {
it('should render children with provided bridgeAPI', () => {
render(
<WebLoginProvider bridgeAPI={mockBridgeAPI}>
<div>Test Child</div>
</WebLoginProvider>,
);

expect(screen.getByText('Test Child')).toBeInTheDocument();
});

it('should return null if no bridgeAPI is provided', () => {
const { container } = render(
<WebLoginProvider bridgeAPI={null}>
<div>Test Child</div>
</WebLoginProvider>,
);
expect(container.firstChild).toBeNull();
});
});
7 changes: 4 additions & 3 deletions packages/react/src/__tests__/init.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// import { initBridge, IConfigProps, IBridgeAPI } from '@aelf-web-login/wallet-adapter-bridge';
import VConsole from 'vconsole';
import { init } from '../index';

jest.mock('vconsole');
Expand All @@ -8,14 +7,16 @@ jest.mock('@aelf-web-login/wallet-adapter-bridge', () => ({
}));

describe('init', () => {
it('should initialize VConsole if showVconsole is true', () => {
it('should initialize VConsole if showVconsole is true', async () => {
const options = { baseConfig: { showVconsole: true } };
init(options as any);
const VConsole = await import('vconsole');
expect(VConsole).toHaveBeenCalled();
});
it('should not initialize VConsole if showVconsole is false', () => {
it('should not initialize VConsole if showVconsole is false', async () => {
const options = { baseConfig: { showVconsole: false } };
init(options as any);
const VConsole = await import('vconsole');
expect(VConsole).not.toHaveBeenCalled();
});

Expand Down
26 changes: 0 additions & 26 deletions packages/react/src/__tests__/provider.test.ts

This file was deleted.

29 changes: 29 additions & 0 deletions packages/react/src/__tests__/useConnectWallet.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { render } from '@testing-library/react';
import useConnectWallet from '../useConnectWallet';
import { WebLoginProvider } from '../context';
import { IBridgeAPI } from '@aelf-web-login/wallet-adapter-bridge';

const mockBridgeAPI: IBridgeAPI = {
getSignIn: jest.fn((children) => children),
store: {
getState: () => null,
subscribe: () => null,
},
instance: {
connect: () => null,
},
};

const Comp = () => {
useConnectWallet();
return null;
};
describe('useConnectWallet', () => {
it('should render hook', () => {
render(
<WebLoginProvider bridgeAPI={mockBridgeAPI}>
<Comp />
</WebLoginProvider>,
);
});
});
26 changes: 26 additions & 0 deletions packages/react/src/__tests__/useExternalStore.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { render } from '@testing-library/react';
import useExternalStore from '../useExternalStore';
import { WebLoginProvider } from '../context';
import { IBridgeAPI } from '@aelf-web-login/wallet-adapter-bridge';

const mockBridgeAPI: Partial<IBridgeAPI> = {
getSignIn: jest.fn((children) => children),
store: {
getState: () => null,
subscribe: () => null,
},
};

const Comp = () => {
useExternalStore();
return null;
};
describe('useExternalStore', () => {
it('should render hook', () => {
render(
<WebLoginProvider bridgeAPI={mockBridgeAPI}>
<Comp />
</WebLoginProvider>,
);
});
});
39 changes: 39 additions & 0 deletions packages/react/src/context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { IBridgeAPI } from '@aelf-web-login/wallet-adapter-bridge';
import React from 'react';

const HOOK_ERROR_MESSAGE =
'Must call the provided initialization method`init` method before using hooks.';

const WebLoginContext: React.Context<IBridgeAPI> = React.createContext<IBridgeAPI>(
{} as IBridgeAPI,
);

export default WebLoginContext;

export function useWebLoginContext(): IBridgeAPI {
const bridgeAPI = React.useContext(WebLoginContext);

if (!bridgeAPI) {
throw new Error(HOOK_ERROR_MESSAGE);
}

return bridgeAPI;
}

export interface IWebLoginProviderProps {
children: React.ReactNode;
bridgeAPI: IBridgeAPI;
}

export const WebLoginProvider: React.FC<IWebLoginProviderProps> = ({ children, bridgeAPI }) => {
const { getSignIn } = bridgeAPI ?? {
getSignIn: () => null,
};

if (!bridgeAPI) {
return null;
}
return (
<WebLoginContext.Provider value={bridgeAPI}>{getSignIn(children)}</WebLoginContext.Provider>
);
};
172 changes: 4 additions & 168 deletions packages/react/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,169 +1,5 @@
/* eslint-disable @typescript-eslint/no-empty-function */
import {
ConnectedWallet,
enhancedLocalStorage,
PORTKEYAA,
} from '@aelf-web-login/wallet-adapter-base';
import { IBridgeAPI, IConfigProps, initBridge } from '@aelf-web-login/wallet-adapter-bridge';
import React, { useCallback, useMemo, useState, useSyncExternalStore } from 'react';
/* istanbul ignore file */

const HOOK_ERROR_MESSAGE =
'Must call the provided initialization method`init` method before using hooks.';
// let noCommonBaseModal = false;
export const init = (options: IConfigProps): IBridgeAPI => {
// noCommonBaseModal = options.baseConfig.noCommonBaseModal ?? false;
if (options.baseConfig.showVconsole && typeof window !== 'undefined') {
import('vconsole')
.then((VConsole) => new VConsole.default())
.catch((err) => console.log('Error loading VConsole:', err));
}
console.log('aelf-web-login-init..............31');
function initScriptAndMountApp() {
if (options.baseConfig.omitTelegramScript) {
return;
}
// const HOSTNAME_PREFIX_LIST = ['tg.', 'tg-test.', 'localhost'];
const TELEGRAM_SRC = 'https://telegram.org/js/telegram-web-app.js';
if (typeof window !== 'undefined' && typeof location !== 'undefined') {
// if (HOSTNAME_PREFIX_LIST.some(h => location.hostname.includes(h))) {
const script = document.createElement('script');
script.src = TELEGRAM_SRC;
script.async = false;
document.head.appendChild(script);
console.log('initScriptAndMountApp');
// }
}
}

initScriptAndMountApp();
const dataFromBridge = initBridge(options);
return dataFromBridge;
};

export const WebLoginContext: React.Context<IBridgeAPI> = React.createContext<IBridgeAPI>(
{} as IBridgeAPI,
);

interface IWebLoginProviderProps {
children: React.ReactNode;
bridgeAPI: IBridgeAPI;
}

export const WebLoginProvider: React.FC<IWebLoginProviderProps> = ({ children, bridgeAPI }) => {
// const { mountApp, unMountApp, getSignIn } = bridgeAPI ?? {
// mountApp: () => {},
// unMountApp: () => {},
// getSignIn: () => null,
// };
// useEffect(() => {
// if (noCommonBaseModal) {
// return;
// }
// mountApp();
// return unMountApp;
// }, [mountApp, unMountApp]);
const { getSignIn } = bridgeAPI ?? {
getSignIn: () => null,
};

if (!bridgeAPI) {
return null;
}
return (
<WebLoginContext.Provider value={bridgeAPI}>
{/* {noCommonBaseModal ? getSignIn(children) : children} */}
{getSignIn(children)}
</WebLoginContext.Provider>
);
};

export function useWebLoginContext(): IBridgeAPI {
const bridgeAPI = React.useContext(WebLoginContext);

if (!bridgeAPI) {
throw new Error(HOOK_ERROR_MESSAGE);
}

return bridgeAPI;
}

function useExternalStore() {
const { store } = useWebLoginContext();
const subscribe = useCallback(
(onStoreChange: () => void) => {
const unsubscribe = store.subscribe(onStoreChange);

return () => unsubscribe;
},
[store],
);

const getSnapshot = useCallback(() => {
return store.getState();
}, [store]);

const getServerSnapshot = () => getSnapshot();

return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
}

export function useConnectWallet() {
const { instance } = useWebLoginContext();
const stateFromStore = useExternalStore();
const {
connect,
disConnect,
lock,
getAccountByChainId,
getWalletSyncIsCompleted,
callSendMethod,
callViewMethod,
sendMultiTransaction,
getSignature,
clearManagerReadonlyStatus,
checkLoginStatus,
} = instance;
const [connecting, setConnecting] = useState(false);

const isConnected = useMemo(() => {
if (enhancedLocalStorage.getItem(ConnectedWallet) === PORTKEYAA) {
return !!stateFromStore.walletInfo;
} else {
return !!enhancedLocalStorage.getItem(ConnectedWallet) || !!stateFromStore.walletInfo;
}
}, [stateFromStore.walletInfo]);

const connectWallet = useCallback(async () => {
setConnecting(true);
const rs = await connect();
setConnecting(false);
return rs;
}, [connect]);

const disConnectWallet = useCallback(async () => {
const rs = await disConnect();
return rs;
}, [disConnect]);

return {
connectWallet,
disConnectWallet,
connecting,
walletInfo: stateFromStore.walletInfo,
isLocking: stateFromStore.isLocking,
walletType: stateFromStore.walletType,
isConnected: isConnected,
loginError: stateFromStore.loginError,
loginOnChainStatus: stateFromStore.loginOnChainStatus,
approvedGuardians: stateFromStore.approvedGuardians,
lock,
getAccountByChainId,
getWalletSyncIsCompleted,
callSendMethod,
callViewMethod,
getSignature,
sendMultiTransaction,
clearManagerReadonlyStatus,
checkLoginStatus,
};
}
export { default as init } from './init';
export { default as WebLoginContext, useWebLoginContext, WebLoginProvider } from './context';
export { default as useConnectWallet } from './useConnectWallet';
Loading

0 comments on commit f7ed0ab

Please sign in to comment.