Skip to content

Commit a20f085

Browse files
authored
fix: Merge gist version of upProvider (#8)
* fix: Repair upProvider.tsx * fix: Merge gist version of upProvider * fix: Repair other lint problems.
1 parent 5b9559a commit a20f085

File tree

2 files changed

+101
-52
lines changed

2 files changed

+101
-52
lines changed

components/Donate.tsx

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
/**
22
* A component that facilitates LYX token transfers to a specified LUKSO address.
3-
*
3+
*
44
* @component
55
* @param {Object} props - Component props
66
* @param {string} [props.selectedAddress] - Optional hex address of the donation recipient.
77
* If not provided, uses the first address from context.
8-
*
8+
*
99
* Features:
1010
* - Amount validation (${minAmount}-${maxAmount} LYX)
1111
* - Integration with UP Browser wallet
1212
* - Recipient profile display using LuksoProfile
1313
* - Real-time amount validation
14-
*
14+
*
1515
* @requires useUpProvider - Hook for UP Browser wallet integration
1616
* @requires LuksoProfile - Component for displaying LUKSO profile information
1717
* @requires viem - For handling blockchain transactions
1818
*/
19-
'use client';
19+
"use client";
2020

21-
import { useCallback, useEffect, useState } from 'react';
22-
import { parseUnits } from 'viem';
23-
import { useUpProvider } from './upProvider';
24-
import { LuksoProfile } from './LuksoProfile';
21+
import { useCallback, useEffect, useState } from "react";
22+
import { parseUnits } from "viem";
23+
import { useUpProvider } from "./upProvider";
24+
import { LuksoProfile } from "./LuksoProfile";
25+
import { waitForTransactionReceipt } from "viem/actions";
2526

2627
const minAmount = 1.0;
2728
const maxAmount = 1000;
@@ -34,7 +35,7 @@ export function Donate({ selectedAddress }: DonateProps) {
3435
const { client, accounts, contextAccounts, walletConnected } =
3536
useUpProvider();
3637
const [amount, setAmount] = useState<number>(minAmount);
37-
const [error, setError] = useState('');
38+
const [error, setError] = useState("");
3839
const recipientAddress = selectedAddress || contextAccounts[0];
3940
const [isLoading, setIsLoading] = useState(false);
4041

@@ -44,7 +45,7 @@ export function Donate({ selectedAddress }: DonateProps) {
4445
} else if (value > maxAmount) {
4546
setError(`Amount cannot exceed ${maxAmount} LYX.`);
4647
} else {
47-
setError('');
48+
setError("");
4849
}
4950
setAmount(value);
5051
}, []);
@@ -53,7 +54,7 @@ export function Donate({ selectedAddress }: DonateProps) {
5354
validateAmount(amount);
5455
}, [amount, validateAmount]);
5556

56-
const sendToken = async () => {
57+
const sendToken = useCallback(async () => {
5758
if (!client || !walletConnected || !amount) {
5859
return;
5960
}
@@ -64,19 +65,29 @@ export function Donate({ selectedAddress }: DonateProps) {
6465
account: accounts[0] as `0x${string}`,
6566
to: recipientAddress as `0x${string}`,
6667
value: parseUnits(amount.toString(), 18),
68+
chain: client.chain,
6769
});
6870

6971
// Wait for transaction confirmation
70-
await client.waitForTransactionReceipt({ hash: tx });
71-
72+
await waitForTransactionReceipt(client, { hash: tx });
73+
7274
// Reset amount after successful transaction
7375
setAmount(minAmount);
7476
} catch (err) {
75-
console.error('Transaction failed:', err);
77+
console.error("Transaction failed:", err);
7678
} finally {
7779
setIsLoading(false);
7880
}
79-
};
81+
}, [accounts, amount, client, recipientAddress, walletConnected]);
82+
83+
const sendTokenKeyPress = useCallback(
84+
(e: React.KeyboardEvent) => {
85+
if (e.key === "Enter" || e.key === " ") {
86+
sendToken();
87+
}
88+
},
89+
[sendToken]
90+
);
8091

8192
const handleOnInput = useCallback(
8293
(e: React.ChangeEvent<HTMLInputElement>) => {
@@ -88,7 +99,6 @@ export function Donate({ selectedAddress }: DonateProps) {
8899

89100
return (
90101
<div className="w-full bg-white/80 backdrop-blur-md rounded-2xl">
91-
92102
<div className="rounded-xl">
93103
<div className="flex flex-row items-center justify-center gap-2">
94104
<LuksoProfile address={recipientAddress} />
@@ -107,12 +117,13 @@ export function Donate({ selectedAddress }: DonateProps) {
107117
is-full-width
108118
is-disabled={!walletConnected}
109119
className="mt-2"
110-
></lukso-input>
120+
/>
111121
{error && <p className="text-red-500 text-sm mt-1">{error}</p>}
112122
</div>
113123

114124
<lukso-button
115125
onClick={sendToken}
126+
onKeyPress={sendTokenKeyPress}
116127
variant="primary"
117128
size="medium"
118129
className="mt-2"

components/upProvider.tsx

Lines changed: 73 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,26 @@
1414
* - selectedAddress: Currently selected address for transactions
1515
* - isSearching: Loading state indicator
1616
*/
17-
'use client';
17+
"use client";
1818

19-
import { createClientUPProvider } from "@lukso/up-provider";
19+
import {
20+
createClientUPProvider,
21+
type UPClientProvider,
22+
} from "@lukso/up-provider";
2023
import { createWalletClient, custom } from "viem";
2124
import { lukso, luksoTestnet } from "viem/chains";
22-
import { createContext, useContext, useEffect, useState, ReactNode } from "react";
25+
import {
26+
createContext,
27+
useContext,
28+
useEffect,
29+
useState,
30+
type ReactNode,
31+
useMemo,
32+
} from "react";
2333

2434
interface UpProviderContext {
25-
provider: any;
26-
client: any;
35+
provider: UPClientProvider | null;
36+
client: ReturnType<typeof createWalletClient> | null;
2737
chainId: number;
2838
accounts: Array<`0x${string}`>;
2939
contextAccounts: Array<`0x${string}`>;
@@ -36,7 +46,8 @@ interface UpProviderContext {
3646

3747
const UpContext = createContext<UpProviderContext | undefined>(undefined);
3848

39-
const provider = typeof window !== "undefined" ? createClientUPProvider() : null;
49+
const provider =
50+
typeof window !== "undefined" ? createClientUPProvider() : null;
4051

4152
export function useUpProvider() {
4253
const context = useContext(UpContext);
@@ -53,20 +64,26 @@ interface UpProviderProps {
5364
export function UpProvider({ children }: UpProviderProps) {
5465
const [chainId, setChainId] = useState<number>(0);
5566
const [accounts, setAccounts] = useState<Array<`0x${string}`>>([]);
56-
const [contextAccounts, setContextAccounts] = useState<Array<`0x${string}`>>([]);
67+
const [contextAccounts, setContextAccounts] = useState<Array<`0x${string}`>>(
68+
[]
69+
);
5770
const [walletConnected, setWalletConnected] = useState(false);
58-
const [selectedAddress, setSelectedAddress] = useState<`0x${string}` | null>(null);
71+
const [selectedAddress, setSelectedAddress] = useState<`0x${string}` | null>(
72+
null
73+
);
5974
const [isSearching, setIsSearching] = useState(false);
75+
const [account] = accounts ?? [];
76+
const [contextAccount] = contextAccounts ?? [];
6077

61-
const client = (() => {
78+
const client = useMemo(() => {
6279
if (provider && chainId) {
6380
return createWalletClient({
6481
chain: chainId === 42 ? lukso : luksoTestnet,
6582
transport: custom(provider),
6683
});
6784
}
6885
return null;
69-
})();
86+
}, [chainId]);
7087

7188
useEffect(() => {
7289
let mounted = true;
@@ -75,18 +92,21 @@ export function UpProvider({ children }: UpProviderProps) {
7592
try {
7693
if (!client || !provider) return;
7794

78-
const _chainId = (await client.getChainId()) as number;
95+
const _accounts = (await provider.request(
96+
"eth_accounts",
97+
[]
98+
)) as Array<`0x${string}`>;
7999
if (!mounted) return;
80-
setChainId(_chainId);
100+
setAccounts(_accounts);
81101

82-
const _accounts = (await client.getAddresses()) as Array<`0x${string}`>;
102+
const _chainId = (await provider.request("eth_chainId")) as number;
83103
if (!mounted) return;
84-
setAccounts(_accounts);
104+
setChainId(_chainId);
85105

86106
const _contextAccounts = provider.contextAccounts;
87107
if (!mounted) return;
88108
setContextAccounts(_contextAccounts);
89-
setWalletConnected(_accounts.length > 0 && _contextAccounts.length > 0);
109+
setWalletConnected(_accounts[0] != null && _contextAccounts[0] != null);
90110
} catch (error) {
91111
console.error(error);
92112
}
@@ -97,12 +117,12 @@ export function UpProvider({ children }: UpProviderProps) {
97117
if (provider) {
98118
const accountsChanged = (_accounts: Array<`0x${string}`>) => {
99119
setAccounts(_accounts);
100-
setWalletConnected(_accounts.length > 0 && contextAccounts.length > 0);
120+
setWalletConnected(_accounts[0] != null && contextAccount != null);
101121
};
102122

103123
const contextAccountsChanged = (_accounts: Array<`0x${string}`>) => {
104124
setContextAccounts(_accounts);
105-
setWalletConnected(accounts.length > 0 && _accounts.length > 0);
125+
setWalletConnected(account != null && _accounts[0] != null);
106126
};
107127

108128
const chainChanged = (_chainId: number) => {
@@ -116,30 +136,48 @@ export function UpProvider({ children }: UpProviderProps) {
116136
return () => {
117137
mounted = false;
118138
provider.removeListener("accountsChanged", accountsChanged);
119-
provider.removeListener("contextAccountsChanged", contextAccountsChanged);
139+
provider.removeListener(
140+
"contextAccountsChanged",
141+
contextAccountsChanged
142+
);
120143
provider.removeListener("chainChanged", chainChanged);
121144
};
122145
}
123-
}, [client, accounts.length, contextAccounts.length]);
124-
146+
// If you want to be responsive to account changes
147+
// you also need to look at the first account rather
148+
// then the length or the whole array. Unfortunately react doesn't properly
149+
// look at array values like vue or knockout.
150+
}, [client, account, contextAccount]);
151+
152+
// There has to be a useMemo to make sure the context object doesn't change on every
153+
// render.
154+
const data = useMemo(() => {
155+
return {
156+
provider,
157+
client,
158+
chainId,
159+
accounts,
160+
contextAccounts,
161+
walletConnected,
162+
selectedAddress,
163+
setSelectedAddress,
164+
isSearching,
165+
setIsSearching,
166+
};
167+
}, [
168+
client,
169+
chainId,
170+
accounts,
171+
contextAccounts,
172+
walletConnected,
173+
selectedAddress,
174+
isSearching,
175+
]);
125176
return (
126-
<UpContext.Provider
127-
value={{
128-
provider,
129-
client,
130-
chainId,
131-
accounts,
132-
contextAccounts,
133-
walletConnected,
134-
selectedAddress,
135-
setSelectedAddress,
136-
isSearching,
137-
setIsSearching,
138-
}}
139-
>
177+
<UpContext.Provider value={data}>
140178
<div className="min-h-screen flex items-center justify-center">
141179
{children}
142180
</div>
143181
</UpContext.Provider>
144182
);
145-
}
183+
}

0 commit comments

Comments
 (0)