Skip to content

Commit 268c61d

Browse files
authored
Merge pull request #3 from hyli-org/wallet-as-module
Wallet as module
2 parents 111adc5 + d5d8e98 commit 268c61d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1864
-1431
lines changed

front/.env

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
VITE_SERVER_BASE_URL=http://localhost:4000
2-
VITE_WS_URL=ws://localhost:8081/ws
1+
VITE_WALLET_SERVER_BASE_URL=http://localhost:4000
2+
VITE_WALLET_WS_URL=ws://localhost:8081/ws
33
VITE_NODE_BASE_URL=http://localhost:4321
44
VITE_INDEXER_BASE_URL=http://localhost:4321
55
VITE_TX_EXPLORER_URL=http://localhost:8000

front/.env.production

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
VITE_SERVER_BASE_URL=https://wallet.testnet.hyle.eu
2-
VITE_WS_URL=wss://wallet.testnet.hyle.eu/ws
1+
VITE_WALLET_SERVER_BASE_URL=https://wallet.testnet.hyle.eu
2+
VITE_WALLET_WS_URL=wss://wallet.testnet.hyle.eu/ws
33
VITE_NODE_BASE_URL=https://node.testnet.hyle.eu
44
VITE_INDEXER_BASE_URL=https://indexer.testnet.hyle.eu
55
VITE_TX_EXPLORER_URL=https://hyleou.hyle.eu/

front/bun.lockb

25.5 KB
Binary file not shown.

front/package.json

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "hyle-wallet",
2+
"name": "hyle-wallet-front",
33
"private": true,
44
"version": "0.0.0",
55
"type": "module",
@@ -17,24 +17,25 @@
1717
"elliptic": "^6.6.1",
1818
"hyle": "^0.2.5",
1919
"hyle-check-secret": "^0.3.2",
20+
"hyle-wallet": "file:../hyle-wallet",
2021
"react": "^19.1.0",
2122
"react-dom": "^19.1.0",
22-
"react-router-dom": "^7.5.0"
23+
"react-router-dom": "^7.6.0"
2324
},
2425
"devDependencies": {
25-
"@eslint/js": "^9.24.0",
26-
"@types/react": "^19.1.2",
27-
"@types/react-dom": "^19.1.2",
28-
"@vitejs/plugin-react": "^4.4.0",
26+
"@eslint/js": "^9.26.0",
27+
"@types/react": "^19.1.4",
28+
"@types/react-dom": "^19.1.5",
29+
"@vitejs/plugin-react": "^4.4.1",
2930
"autoprefixer": "^10.4.21",
30-
"eslint": "^9.24.0",
31+
"eslint": "^9.26.0",
3132
"eslint-plugin-react-hooks": "^5.2.0",
32-
"eslint-plugin-react-refresh": "^0.4.19",
33-
"globals": "^15.15.0",
33+
"eslint-plugin-react-refresh": "^0.4.20",
34+
"globals": "^16.1.0",
3435
"postcss": "^8.5.3",
35-
"tailwindcss": "^4.1.4",
36-
"typescript": "~5.7.3",
37-
"typescript-eslint": "^8.30.1",
38-
"vite": "^6.2.6"
36+
"tailwindcss": "^4.1.6",
37+
"typescript": "~5.8.3",
38+
"typescript-eslint": "^8.32.1",
39+
"vite": "^6.3.5"
3940
}
4041
}

front/src/App.tsx

Lines changed: 69 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,141 +1,90 @@
1-
import { useState, useEffect } from 'react';
2-
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
1+
import { useEffect } from 'react';
2+
import { BrowserRouter, Routes, Route, useNavigate } from 'react-router-dom';
33
import './App.css';
4-
import { Balance } from './components/wallet/Balance';
5-
import { Send } from './components/wallet/Send';
6-
import { History } from './components/wallet/History';
7-
import { SessionKeys } from './components/wallet/SessionKeys';
8-
import { WalletLayout } from './components/layout/WalletLayout';
9-
import { Wallet, Transaction } from './types/wallet';
10-
import { indexerService } from './services/IndexerService';
11-
import { useConfig } from './hooks/useConfig';
12-
import { AppEvent, webSocketService } from './services/WebSocketService';
13-
import { ConnectWallet } from './components/connect/ConnectWallet';
14-
import { ConnectWalletExamples } from './components/connect/ConnectWalletExamples';
15-
16-
function App() {
17-
const [wallet, setWallet] = useState<Wallet | null>(null);
18-
const [balance, setBalance] = useState<number>(0);
19-
const [transactions, setTransactions] = useState<Transaction[]>([]);
4+
import { WalletShowcase } from './components/WalletShowcase';
5+
import { useWalletBalance } from './hooks/useWalletBalance';
6+
import { useWalletTransactions } from './hooks/useWalletTransactions';
7+
import { useWebSocketConnection } from './hooks/useWebSocketConnection';
8+
import { getPublicRoutes, getProtectedRoutes, ROUTES } from './routes/routes';
9+
import { WalletProvider, useWallet } from 'hyle-wallet';
10+
import { useConfig } from 'hyle-wallet';
11+
import { LoadingErrorState } from './components/common/LoadingErrorState';
12+
13+
function AppContent() {
2014
const { isLoading: isLoadingConfig, error: configError } = useConfig();
21-
22-
// Function to fetch balance
23-
const fetchBalance = async () => {
24-
if (wallet) {
25-
const balance = await indexerService.getBalance(wallet.address);
26-
setBalance(balance);
27-
}
28-
};
29-
30-
// Function to fetch transaction history
31-
const fetchTransactions = async () => {
32-
if (wallet) {
33-
const transactions = await indexerService.getTransactionHistory(wallet.address);
34-
setTransactions(transactions);
15+
const { wallet, logout, stage, error } = useWallet();
16+
const navigate = useNavigate();
17+
18+
// Use custom hooks
19+
const { balance, fetchBalance } = useWalletBalance(wallet?.address);
20+
const {
21+
transactions,
22+
handleTxEvent
23+
} = useWalletTransactions(wallet?.address);
24+
25+
// Setup WebSocket connection
26+
useWebSocketConnection(wallet?.address, event => {
27+
handleTxEvent(event);
28+
// If transaction was successful, update balance
29+
if (event.tx.status === 'Success') {
30+
fetchBalance();
3531
}
36-
};
32+
});
3733

38-
// Initialize WebSocket connection when wallet is set
34+
// Redirect back to root on auth settlement error and show message via state
3935
useEffect(() => {
40-
if (wallet) {
41-
webSocketService.connect(wallet.address);
42-
43-
const handleTxEvent = async (event: AppEvent['TxEvent']) => {
44-
console.log('Received transaction event:', event);
45-
if (event.tx.status === 'Success') {
46-
// Update balance
47-
await fetchBalance();
48-
}
49-
50-
// Update transactions
51-
const newTransaction: Transaction = event.tx;
52-
53-
setTransactions(prevTransactions => {
54-
const existingIndex = prevTransactions.findIndex(tx => tx.id === newTransaction.id);
55-
if (existingIndex !== -1) {
56-
console.log('Updating existing transaction');
57-
// Update existing transaction in-place
58-
const updatedTransactions = [...prevTransactions];
59-
updatedTransactions[existingIndex] = newTransaction;
60-
return updatedTransactions;
61-
} else {
62-
console.log('Adding new transaction');
63-
// Add new transaction at the beginning of the list
64-
return [newTransaction, ...prevTransactions];
65-
}
66-
});
67-
};
68-
69-
const unsubscribeTxEvents = webSocketService.subscribeToTxEvents(handleTxEvent);
70-
71-
// Initial data fetch
72-
fetchBalance();
73-
fetchTransactions();
74-
75-
return () => {
76-
unsubscribeTxEvents();
77-
webSocketService.disconnect();
78-
};
36+
if (stage === 'error') {
37+
navigate(ROUTES.ROOT, { state: { authError: error } });
7938
}
80-
}, [wallet]);
81-
82-
const handleWalletLoggedIn = (loggedInWallet: Wallet) => {
83-
setWallet(loggedInWallet);
84-
localStorage.setItem('wallet', JSON.stringify(loggedInWallet));
85-
};
39+
}, [stage, error, navigate]);
8640

8741
const handleLogout = () => {
88-
setWallet(null);
89-
localStorage.removeItem('wallet');
42+
logout();
43+
navigate(ROUTES.ROOT);
9044
};
9145

92-
// Check if wallet exists in localStorage on component mount
93-
useEffect(() => {
94-
const storedWallet = localStorage.getItem('wallet');
95-
if (storedWallet) {
96-
setWallet(JSON.parse(storedWallet));
97-
}
98-
}, []);
99-
10046
if (isLoadingConfig) {
101-
return <div>Loading configuration...</div>;
47+
return <LoadingErrorState isLoading={true} error={null} loadingMessage="Loading configuration..." />;
10248
}
10349

10450
if (configError) {
105-
return <div>Error loading configuration: {configError}</div>;
51+
return <LoadingErrorState isLoading={false} error={`Error loading configuration: ${configError}`} />;
10652
}
10753

108-
return (
109-
<BrowserRouter>
110-
{/* Global connect wallet modal (renders its own button) */}
111-
{!wallet && (
112-
<div className="showcase-container">
113-
<div className="showcase-header">
114-
<h1>Wallet Integration</h1>
115-
<p>Connect to your wallet using a fully customizable modal component.</p>
116-
</div>
117-
<ConnectWalletExamples onWalletConnected={handleWalletLoggedIn} />
118-
</div>
119-
)}
120-
<Routes>
121-
<Route path="/" element={
122-
wallet ? <Navigate to="/wallet/balance" replace /> : <div />
123-
} />
54+
// If wallet is not connected, show the showcase screen
55+
if (!wallet) {
56+
return <WalletShowcase providers={['password', 'google', 'github']} />;
57+
}
12458

125-
{wallet && (
126-
<Route path="/wallet" element={<WalletLayout wallet={wallet} onLogout={handleLogout} />}>
127-
<Route path="balance" element={<Balance wallet={wallet} balance={balance} />} />
128-
<Route path="send" element={<Send wallet={wallet} />} />
129-
<Route path="history" element={<History transactions={transactions} />} />
130-
<Route path="session-keys" element={<SessionKeys wallet={wallet} />} />
131-
<Route index element={<Navigate to="balance" replace />} />
132-
</Route>
133-
)}
59+
// Generate routes based on authentication state
60+
const publicRoutes = getPublicRoutes();
61+
const protectedRoutes = getProtectedRoutes(wallet, balance, transactions, handleLogout);
62+
const allRoutes = [...publicRoutes, ...protectedRoutes];
63+
64+
return <Routes>{allRoutes.map(route =>
65+
<Route
66+
key={route.path}
67+
path={route.path}
68+
element={route.element}
69+
>
70+
{route.children?.map(childRoute => (
71+
<Route
72+
key={childRoute.path}
73+
path={childRoute.path}
74+
element={childRoute.element}
75+
index={childRoute.index}
76+
/>
77+
))}
78+
</Route>
79+
)}</Routes>;
80+
}
13481

135-
<Route path="*" element={<Navigate to="/" replace />} />
136-
</Routes>
82+
export default function App() {
83+
return (
84+
<BrowserRouter>
85+
<WalletProvider>
86+
<AppContent />
87+
</WalletProvider>
13788
</BrowserRouter>
13889
);
13990
}
140-
141-
export default App;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from 'react';
2+
import { HyleWallet } from 'hyle-wallet';
3+
import { useLocation } from 'react-router-dom';
4+
5+
type ProviderOption = 'password' | 'google' | 'github';
6+
7+
interface WalletShowcaseProps {
8+
providers: ProviderOption[];
9+
}
10+
11+
export const WalletShowcase: React.FC<WalletShowcaseProps> = ({ providers }) => {
12+
const location = useLocation();
13+
const authError = (location.state as any)?.authError as string | undefined;
14+
15+
return (
16+
<div className="showcase-container">
17+
<div className="showcase-header">
18+
<h1>Wallet Integration</h1>
19+
<p>Connect to your wallet using the default modal or your own custom UI.</p>
20+
</div>
21+
{authError && <div className="error-message" style={{ color: 'red' }}>{authError}</div>}
22+
<HyleWallet providers={providers} />
23+
</div>
24+
);
25+
};

0 commit comments

Comments
 (0)