1
+ import React , { createContext , useContext , useState , useEffect , ReactNode } from "react" ;
2
+ import { PublicKey } from "@solana/web3.js" ;
3
+
4
+ // Define phantom wallet type without extending Window
5
+ type PhantomWallet = {
6
+ isPhantom ?: boolean ;
7
+ connect : ( ) => Promise < { publicKey : { toString : ( ) => string } } > ;
8
+ disconnect : ( ) => Promise < void > ;
9
+ on : ( event : string , callback : ( ) => void ) => void ;
10
+ removeListener : ( event : string , callback : ( ) => void ) => void ;
11
+ } ;
12
+
13
+ // Helper function to get phantom wallet
14
+ const getPhantomWallet = ( ) : PhantomWallet | undefined => {
15
+ if ( typeof window !== "undefined" ) {
16
+ return ( window as any ) . solana ;
17
+ }
18
+ return undefined ;
19
+ } ;
20
+
21
+ type WalletContextType = {
22
+ wallet : PhantomWallet | undefined ;
23
+ publicKey : string | null ;
24
+ connected : boolean ;
25
+ connecting : boolean ;
26
+ connectWallet : ( ) => Promise < void > ;
27
+ disconnectWallet : ( ) => Promise < void > ;
28
+ } ;
29
+
30
+ const WalletContext = createContext < WalletContextType > ( {
31
+ wallet : undefined ,
32
+ publicKey : null ,
33
+ connected : false ,
34
+ connecting : false ,
35
+ connectWallet : async ( ) => { } ,
36
+ disconnectWallet : async ( ) => { } ,
37
+ } ) ;
38
+
39
+ export const useWallet = ( ) => useContext ( WalletContext ) ;
40
+
41
+ type WalletProviderProps = {
42
+ children : ReactNode ;
43
+ } ;
44
+
45
+ export const WalletProvider : React . FC < WalletProviderProps > = ( { children } ) => {
46
+ const [ wallet , setWallet ] = useState < PhantomWallet | undefined > ( undefined ) ;
47
+ const [ publicKey , setPublicKey ] = useState < string | null > ( null ) ;
48
+ const [ connected , setConnected ] = useState < boolean > ( false ) ;
49
+ const [ connecting , setConnecting ] = useState < boolean > ( false ) ;
50
+
51
+ useEffect ( ( ) => {
52
+ const phantom = getPhantomWallet ( ) ;
53
+ setWallet ( phantom ) ;
54
+
55
+ // Handle account changes
56
+ const onAccountChange = ( ) => {
57
+ if ( wallet && wallet . isPhantom ) {
58
+ const key = ( wallet as any ) . publicKey ?. toString ( ) ;
59
+ setPublicKey ( key || null ) ;
60
+ setConnected ( ! ! key ) ;
61
+ }
62
+ } ;
63
+
64
+ if ( phantom ) {
65
+ phantom . on ( "accountChanged" , onAccountChange ) ;
66
+ phantom . on ( "connect" , onAccountChange ) ;
67
+ phantom . on ( "disconnect" , ( ) => {
68
+ setPublicKey ( null ) ;
69
+ setConnected ( false ) ;
70
+ } ) ;
71
+ }
72
+
73
+ return ( ) => {
74
+ if ( phantom ) {
75
+ phantom . removeListener ( "accountChanged" , onAccountChange ) ;
76
+ phantom . removeListener ( "connect" , onAccountChange ) ;
77
+ phantom . removeListener ( "disconnect" , ( ) => {
78
+ setPublicKey ( null ) ;
79
+ setConnected ( false ) ;
80
+ } ) ;
81
+ }
82
+ } ;
83
+ } , [ wallet ] ) ;
84
+
85
+ const connectWallet = async ( ) : Promise < void > => {
86
+ if ( ! wallet ) return ;
87
+ try {
88
+ setConnecting ( true ) ;
89
+ const response = await wallet . connect ( ) ;
90
+ setPublicKey ( response . publicKey . toString ( ) ) ;
91
+ setConnected ( true ) ;
92
+ } catch ( error ) {
93
+ console . error ( "Connection error:" , error ) ;
94
+ } finally {
95
+ setConnecting ( false ) ;
96
+ }
97
+ } ;
98
+
99
+ const disconnectWallet = async ( ) : Promise < void > => {
100
+ if ( ! wallet ) return ;
101
+ try {
102
+ await wallet . disconnect ( ) ;
103
+ setPublicKey ( null ) ;
104
+ setConnected ( false ) ;
105
+ } catch ( error ) {
106
+ console . error ( "Disconnection error:" , error ) ;
107
+ }
108
+ } ;
109
+
110
+ return (
111
+ < WalletContext . Provider
112
+ value = { {
113
+ wallet,
114
+ publicKey,
115
+ connected,
116
+ connecting,
117
+ connectWallet,
118
+ disconnectWallet,
119
+ } }
120
+ >
121
+ { children }
122
+ </ WalletContext . Provider >
123
+ ) ;
124
+ } ;
0 commit comments