Skip to content

Commit

Permalink
fix: working on ic wallet
Browse files Browse the repository at this point in the history
  • Loading branch information
veeso committed Feb 26, 2025
1 parent c4bfd06 commit 5cb6cd1
Show file tree
Hide file tree
Showing 16 changed files with 492 additions and 56 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"react": "^19",
"react-dom": "^19",
"react-helmet": "^6",
"react-ic-wallet": "^0.4.0",
"react-icons": "^5.4.0",
"react-leaflet": "5.0.0",
"react-loading-skeleton": "^3.5.0",
Expand All @@ -59,6 +60,7 @@
"prettier": "^3",
"process": "^0.11.10",
"tailwindcss": "^3",
"tseslint": "^0.0.2",
"typescript": "~5.7.3",
"typescript-eslint": "^8",
"vite": "^6"
Expand Down
21 changes: 17 additions & 4 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
import 'react-loading-skeleton/dist/skeleton.css';
import { IcWalletProvider } from 'react-ic-wallet';

import AppLayout from './js/components/AppLayout';
import AppContextProvider from './js/components/App/AppContext';
import AppContextProvider, {
useAppContext,
} from './js/components/App/AppContext';
import AppError from './js/components/Status/AppError';
import AppSuccess from './js/components/Status/AppSuccess';

const App = () => (
<AppContextProvider>
<AppError />
<AppSuccess />
<AppLayout />
<AppLayoutWrapper />
</AppContextProvider>
);

const AppLayoutWrapper = () => {
const { icWallet } = useAppContext();

return (
<IcWalletProvider provider={icWallet}>
<AppError />
<AppSuccess />
<AppLayout />
</IcWalletProvider>
);
};

export default App;
45 changes: 0 additions & 45 deletions src/Router.tsx

This file was deleted.

Binary file added src/assets/images/bitfinity-wallet.webp
Binary file not shown.
Binary file added src/assets/images/icp-wallet.webp
Binary file not shown.
Binary file added src/assets/images/plug-wallet.webp
Binary file not shown.
6 changes: 6 additions & 0 deletions src/js/components/App/AppContext.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import * as React from 'react';
import { WalletProvider } from 'react-ic-wallet';

interface Context {
appSuccess?: string;
appError?: string;
setAppError: (error?: string) => void;
setAppSuccess: (message?: string) => void;
icWallet?: WalletProvider;
setIcWallet?: (icWallet: WalletProvider | undefined) => void;
}

const AppContext = React.createContext<Context>({
Expand All @@ -15,6 +18,7 @@ const AppContext = React.createContext<Context>({
const AppContextProvider = ({ children }: { children?: React.ReactNode }) => {
const [appError, setAppError] = React.useState<string>();
const [appSuccess, setAppSuccess] = React.useState<string>();
const [icWallet, setIcWallet] = React.useState<WalletProvider | undefined>();

return (
<AppContext.Provider
Expand All @@ -23,6 +27,8 @@ const AppContextProvider = ({ children }: { children?: React.ReactNode }) => {
appSuccess,
setAppError,
setAppSuccess,
icWallet,
setIcWallet,
}}
>
{children}
Expand Down
8 changes: 5 additions & 3 deletions src/js/components/Header/Desktop.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import Container from '../reusable/Container';

import { Route } from '../../utils/routes';
import TopbarLink from './TopbarLink';
import Dropdown from './Dropdown';
import IcConnect from '../IcConnect';

import EkokeLogo from '../../../assets/images/ekoke-logo.webp';
import Dropdown from './Dropdown';

const Desktop = () => (
<div className="fixed block sm:hidden left-0 top-0 h-[80px] w-full bg-page z-40 shadow-sm">
Expand All @@ -23,7 +23,9 @@ const Desktop = () => (
]}
/>
</Container.FlexRow>
<Container.Flex className="flex-1 justify-end 3xl:justify-start px-8"></Container.Flex>
<Container.Flex className="flex-1 justify-end 3xl:justify-start px-8">
<IcConnect />
</Container.Flex>
</Container.FlexRow>
</div>
);
Expand Down
5 changes: 4 additions & 1 deletion src/js/components/Header/Mobile.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Container from '../reusable/Container';
import { Route } from '../../utils/routes';
import Link from '../reusable/Link';
import IcConnect from '../IcConnect';

import EkokeLogo from '../../../assets/images/ekoke-logo.webp';

Expand All @@ -16,7 +17,9 @@ const Mobile = () => (
</Container.FlexRow>
</Container.Container>
</Container.FlexRow>
<Container.FlexRow className="h-[60px] w-full items-center justify-center gap-4"></Container.FlexRow>
<Container.FlexRow className="h-[60px] w-full items-center justify-center gap-4">
<IcConnect />
</Container.FlexRow>
</div>
);

Expand Down
93 changes: 93 additions & 0 deletions src/js/components/IcConnect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import * as React from 'react';
import { WalletProvider, useIcWallet } from 'react-ic-wallet';

import Button from './reusable/Button';
import Container from './reusable/Container';
import InternetComputer from './svg/InternetComputer';
import { useAppContext } from './App/AppContext';
import WalletSelector from './IcConnect/WalletSelector';
import { setUserIcWallet } from '../utils/storage';
import DisconnectPopup from './IcConnect/DisconnectPopup';

const IcConnect = () => {
const { status, connect, disconnect, principal } = useIcWallet();
const { icWallet, setIcWallet } = useAppContext();
const [showWalletSelector, setShowWalletSelector] = React.useState(false);
const [showDisconnectPopup, setShowDisconnectPopup] = React.useState(false);

const disabled = ['initializing', 'unavailable', 'connecting'].includes(
status,
);

const onDisconnect = () => {
if (setIcWallet) {
setIcWallet(undefined);
}
setUserIcWallet(undefined);

return disconnect();
};

const onClick = () => {
if (status === 'notConnected') {
setShowWalletSelector(true);
} else if (status === 'connected') {
setShowDisconnectPopup(true);
}
return undefined;
};

const onWalletSelect = (wallet: WalletProvider) => {
if (setIcWallet) {
setIcWallet(wallet);
}
setShowWalletSelector(false);
};

const text = () => {
if (status === 'initializing') return 'Initializing...';
if (status === 'unavailable') return 'IC Wallet not available';
if (status === 'notConnected') return 'Login';
if (status === 'connecting') return 'Connecting...';
if (status === 'connected')
return `${principal.toString().substring(0, 18)}...`;
return undefined;
};

React.useEffect(() => {
console.log('ic status', status, 'ic wallet', icWallet);
if (icWallet !== undefined && status === 'notConnected') {
connect()
.then(() => {
setUserIcWallet(icWallet);
})
.catch((e) => {
console.error('Failed to connect to wallet', e);
});
}
}, [icWallet, status, connect]);

return (
<>
<Container.FlexRow className="items-center gap-8">
<Button.Alternative
className="my-0 !mb-0"
onClick={onClick}
disabled={disabled}
>
<InternetComputer className="inline w-[32px] mr-2" />
{text()}
</Button.Alternative>
</Container.FlexRow>
{showWalletSelector ? <WalletSelector onSelect={onWalletSelect} /> : null}
{showDisconnectPopup ? (
<DisconnectPopup
onDisconnect={onDisconnect}
onDismiss={() => setShowDisconnectPopup(false)}
/>
) : null}
</>
);
};

export default IcConnect;
29 changes: 29 additions & 0 deletions src/js/components/IcConnect/DisconnectPopup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Container from '../reusable/Container';
import Button from '../reusable/Button';

const DisconnectPopup = ({
onDisconnect,
onDismiss,
}: {
onDisconnect: () => void;
onDismiss: () => void;
}) => {
return (
<Container.Container className="h-screen left-0 overflow-hidden fixed right-0 top-0 w-screen z-50">
<Container.Container className="bg-gray-800/60 h-screen w-screen" />
<Container.Container className="bg-white bottom-0 h-fit sm:h-[70vh] sm:rounded-t-xl left-0 m-auto p-8 fixed right-0 top-0 sm:top-auto sm:bottom-0 w-fit min-w-[25%] sm:w-full">
<Container.FlexCols className="gap-4 text-lg p-4">
<span className="text-lg text-center block text-text">
Do you want to disconnect your wallet?
</span>
<Container.FlexResponsiveRow className="items-center justify-between gap-8">
<Button.Danger onClick={onDisconnect}>Disconnect</Button.Danger>
<Button.Alternative onClick={onDismiss}>Cancel</Button.Alternative>
</Container.FlexResponsiveRow>
</Container.FlexCols>
</Container.Container>
</Container.Container>
);
};

export default DisconnectPopup;
76 changes: 76 additions & 0 deletions src/js/components/IcConnect/WalletSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { WalletProvider } from 'react-ic-wallet';

import Container from '../reusable/Container';
import Button from '../reusable/Button';

import IcpWalletLogo from '../../../assets/images/icp-wallet.webp';
import BitfinityWalletLogo from '../../../assets/images/bitfinity-wallet.webp';
import PlugWalletLogo from '../../../assets/images/plug-wallet.webp';

const WalletSelector = ({
onSelect,
}: {
onSelect: (wallet: WalletProvider) => void;
}) => {
return (
<Container.Container className="h-screen left-0 overflow-hidden fixed right-0 top-0 w-screen z-50">
<Container.Container className="bg-gray-800/60 h-screen w-screen" />
<Container.Container className="bg-white bottom-0 h-fit sm:h-[70vh] sm:rounded-t-xl left-0 m-auto p-8 fixed right-0 top-0 sm:top-auto sm:bottom-0 w-fit min-w-[25%] sm:w-full">
<Container.FlexCols className="gap-4 text-lg p-4">
<span className="text-lg text-center block text-text">
Connect a wallet
</span>
<Container.Container className="grid grid-cols-2 sm:grid-cols-1 gap-4 px-4">
<Wallet
logo={IcpWalletLogo}
name="Internet Identity"
onSelect={onSelect}
wallet={WalletProvider.Dfinity}
/>
<Wallet
logo={BitfinityWalletLogo}
name="Bitfinity Wallet"
onSelect={onSelect}
wallet={WalletProvider.Bitfinity}
/>
<Wallet
logo={PlugWalletLogo}
name="Plug"
onSelect={onSelect}
wallet={WalletProvider.Plug}
/>
</Container.Container>
</Container.FlexCols>
</Container.Container>
</Container.Container>
);
};

const Wallet = ({
logo,
name,
onSelect,
wallet,
}: {
logo: string;
name: string;
onSelect: (wallet: WalletProvider) => void;
wallet: WalletProvider;
}) => (
<Container.Container>
<Button.Alternative className="w-full" onClick={() => onSelect(wallet)}>
<Container.FlexRow className="items-center justify-between w-full">
<span className="text-lg text-text">{name}</span>
<img
className="rounded-full bg-white border border-gray-300 p-1 w-[48px] h-[48px]"
src={logo}
alt={name}
width={64}
height={64}
/>
</Container.FlexRow>
</Button.Alternative>
</Container.Container>
);

export default WalletSelector;
2 changes: 1 addition & 1 deletion src/js/components/reusable/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ const Input = (props: InputProps) => {
};

interface IconInputProps extends InputProps {
icon: JSX.Element;
icon: React.ReactNode;
}

const IconInput = (props: IconInputProps) => {
Expand Down
Loading

0 comments on commit 5cb6cd1

Please sign in to comment.