@@ -4,22 +4,28 @@ export default function IPLookup() {
44 const [ ipAddress , setIpAddress ] = useState ( '' ) ;
55 const [ result , setResult ] = useState ( null ) ;
66 const [ loading , setLoading ] = useState ( false ) ;
7+ const [ error , setError ] = useState ( null ) ;
78
89 const lookupIP = async ( ip ) => {
910 setLoading ( true ) ;
11+ setError ( null ) ;
1012 try {
11- // Using ipapi.co - free, no API key
12- const url = ip
13- ? `https://ipapi.co/${ ip } /json/`
14- : 'https://ipapi.co/json/' ;
15-
13+ const url = ip
14+ ? `http://ip-api.com/json/${ ip } ?fields=status,message,country,countryCode,region,regionName,city,zip,lat,lon,timezone,isp,org,as,query`
15+ : `http://ip-api.com/json/?fields=status,message,country,countryCode,region,regionName,city,zip,lat,lon,timezone,isp,org,as,query` ;
16+
1617 const response = await fetch ( url ) ;
1718 const data = await response . json ( ) ;
18-
19- setResult ( data ) ;
20- } catch ( error ) {
21- console . error ( 'Error:' , error ) ;
22- setResult ( { error : 'Failed to lookup IP' } ) ;
19+
20+ if ( data . status === 'fail' ) {
21+ setError ( data . message ) ;
22+ setResult ( null ) ;
23+ } else {
24+ setResult ( data ) ;
25+ }
26+ } catch ( err ) {
27+ setError ( 'Failed to lookup IP' ) ;
28+ console . error ( 'Error:' , err ) ;
2329 }
2430 setLoading ( false ) ;
2531 } ;
@@ -30,50 +36,87 @@ export default function IPLookup() {
3036 } ;
3137
3238 return (
33- < div className = "p-6" >
34- < h1 className = "text-2xl font-bold mb-4 " > IP Address Lookup</ h1 >
35-
36- < div className = "flex gap-2 mb-4 " >
39+ < div className = "max-w-4xl mx-auto p-6" >
40+ < h1 className = "text-3xl font-bold mb-6 " > IP Address Lookup</ h1 >
41+
42+ < div className = "flex gap-2 mb-6 " >
3743 < input
3844 type = "text"
3945 placeholder = "Enter IP address (e.g., 8.8.8.8)"
4046 value = { ipAddress }
4147 onChange = { ( e ) => setIpAddress ( e . target . value ) }
42- className = "flex-1 px-4 py-2 border rounded"
48+ className = "flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 "
4349 />
44- < button
50+ < button
4551 onClick = { ( ) => lookupIP ( ipAddress ) }
4652 disabled = { loading }
47- className = "px-6 py-2 bg-blue-500 text-white rounded"
53+ className = "px-6 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 disabled:bg-gray-400 "
4854 >
49- Lookup
55+ { loading ? 'Loading...' : ' Lookup' }
5056 </ button >
51- < button
57+ < button
5258 onClick = { getMyIP }
5359 disabled = { loading }
54- className = "px-6 py-2 bg-green-500 text-white rounded"
60+ className = "px-6 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600 disabled:bg-gray-400 "
5561 >
5662 My IP
5763 </ button >
5864 </ div >
5965
60- { loading && < p > Loading...</ p > }
61-
62- { result && ! result . error && (
63- < div className = "bg-gray-100 p-4 rounded" >
64- < p > < strong > IP:</ strong > { result . ip } </ p >
65- < p > < strong > City:</ strong > { result . city } </ p >
66- < p > < strong > Region:</ strong > { result . region } </ p >
67- < p > < strong > Country:</ strong > { result . country_name } </ p >
68- < p > < strong > Timezone:</ strong > { result . timezone } </ p >
69- < p > < strong > ISP:</ strong > { result . org } </ p >
70- < p > < strong > Latitude:</ strong > { result . latitude } </ p >
71- < p > < strong > Longitude:</ strong > { result . longitude } </ p >
66+ { error && (
67+ < div className = "bg-slate-800 border border-red-400 text-red-700 px-4 py-3 rounded mb-4" >
68+ { error }
7269 </ div >
7370 ) }
7471
75- { result ?. error && (
76- < p className = "text-red-500" > { result . error } </ p >
72+ { result && (
73+ < div className = "bg-gray-500 border border-gray-700 rounded-lg shadow-sm overflow-hidden" >
74+ < div className = "bg-gray-50 px-6 py-4 border-b border-gray-200" >
75+ < h2 className = "text-xl font-semibold" > IP Information</ h2 >
76+ </ div >
77+ < div className = "p-6 grid grid-cols-1 md:grid-cols-2 gap-4" >
78+ < div className = "flex flex-col" >
79+ < span className = "text-sm text-gray-500 mb-1" > IP Address</ span >
80+ < span className = "font-mono font-semibold" > { result . query } </ span >
81+ </ div >
82+ < div className = "flex flex-col" >
83+ < span className = "text-sm text-gray-500 mb-1" > Country</ span >
84+ < span className = "font-medium" > { result . country } ({ result . countryCode } )</ span >
85+ </ div >
86+ < div className = "flex flex-col" >
87+ < span className = "text-sm text-gray-500 mb-1" > Region</ span >
88+ < span className = "font-medium" > { result . regionName } </ span >
89+ </ div >
90+ < div className = "flex flex-col" >
91+ < span className = "text-sm text-gray-500 mb-1" > City</ span >
92+ < span className = "font-medium" > { result . city } </ span >
93+ </ div >
94+ < div className = "flex flex-col" >
95+ < span className = "text-sm text-gray-500 mb-1" > ZIP Code</ span >
96+ < span className = "font-medium" > { result . zip || 'N/A' } </ span >
97+ </ div >
98+ < div className = "flex flex-col" >
99+ < span className = "text-sm text-gray-500 mb-1" > Timezone</ span >
100+ < span className = "font-medium" > { result . timezone } </ span >
101+ </ div >
102+ < div className = "flex flex-col" >
103+ < span className = "text-sm text-gray-500 mb-1" > ISP</ span >
104+ < span className = "font-medium" > { result . isp } </ span >
105+ </ div >
106+ < div className = "flex flex-col" >
107+ < span className = "text-sm text-gray-500 mb-1" > Organization</ span >
108+ < span className = "font-medium" > { result . org } </ span >
109+ </ div >
110+ < div className = "flex flex-col" >
111+ < span className = "text-sm text-gray-500 mb-1" > AS Number</ span >
112+ < span className = "font-mono text-sm" > { result . as } </ span >
113+ </ div >
114+ < div className = "flex flex-col" >
115+ < span className = "text-sm text-gray-500 mb-1" > Coordinates</ span >
116+ < span className = "font-mono text-sm" > { result . lat } , { result . lon } </ span >
117+ </ div >
118+ </ div >
119+ </ div >
77120 ) }
78121 </ div >
79122 ) ;
0 commit comments