A few weeks back, I was just scrolling through Twitter and stumbled upon the awesome personal site of Jane Manchun Wong. Her site had this cool feature that displayed the distance between me and her.
It was super fascinating and got me thinking, why not add something like that to my own site?
So I started my research and even asked her how she did it or if she could drop a tutorial, but she didn't reply, which I totally get. Then I hit up my friend Buddhsen Tripathi on Twitter, and he suggested using the geolocation API and sent me a blog article. But after reading the article, I realized that calculating the distance would require users visiting my site to give location permission, which most people would probably hesitate to do. Again, totally understandable.
Lastly, I discovered that we can use the user's IP address to achieve this too. The distance won't be super accurate, but hey, something is better than nothing, right? So, after some Googling and a chat with ChatGPT, I started working on that feature. Here's a tutorial on how to implement it:
We're gonna build a Next.js component that figures out the distance between where the user is and a fixed spot on the server. This is super handy for apps that wanna show how far a user is from a certain place. We'll use TypeScript to keep everything type-safe and axios
to handle the HTTP requests. Assuming you already know and have set up a Next.js project, letās dive in and start building our feature.
Step 1: Fetching the User's IP Address
To get the user's location, we first need their IP address. We can do this using an API that returns the user's public IP address. Here's how:
//app/lib/getUserIp.ts
import axios from 'axios';
export async function getUserIp(): Promise<string> {
const response = await axios.get('[https://api.ipify.org?format=json](https://api.ipify.org/?format=json)');
return response.data.ip;
}
In this code:
-
We use the
axios
library to make a GET request tohttps://api.ipify.org
, which returns the user's public IP address in JSON format. -
The
getUserIp
function returns the IP address as a string.
Next, we'll use the IP address to get the user's location. We'll create another function that makes an API request to ipinfo.io
and returns the user's location data:
//app/lib/getUserLocation.ts
import axios from 'axios';
export interface Location {
city: string;
region: string;
country: string;
loc: string; // "latitude,longitude"
}
export async function getLocation(ip: string): Promise<Location> {
const response = await axios.get<Location>(`https://ipinfo.io/${ip}/json?token="your ipinfo acces code here"`);
return response.data;
}
In this code:
-
We define a
Location
interface to type the response from the API, which includes the user's city, region, country, and geographical coordinates (loc
). -
The
getLocation
function takes an IP address as an argument, makes a GET request toipinfo.io
, and returns the location data.
To calculate the distance between the user's location and a fixed point (e.g., your server's location), you can use the Haversine formula. Here's a basic example of how to implement this calculation:
//app/lib/calculateDistance.ts
export function calculateDistance(lat1: number, lon1: number, lat2: number, lon2: number): number {
const R = 6371; // Radius of the Earth in kilometers
const dLat = (lat2 - lat1) * (Math.PI / 180);
const dLon = (lon2 - lon1) * (Math.PI / 180);
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1 * (Math.PI / 180)) * Math.cos(lat2 * (Math.PI / 180)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c; // Distance in kilometers
}
Step 4: Building the Location Distance Component
Alright, now that we've got all the functions sorted, let's put together a React component to make it all work. This component will get the user's IP, find their location, calculate the distance to a fixed spot, and display it.
//app/components/LocationDistance.tsx
"use client";
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { calculateDistance } from '@/lib/calculateDistance';
import { Location, getLocation } from '@/lib/getLocation';
import { getUserIp } from '@/lib/getUserIp';
// Hardcoded server coordinates
const SERVER_LAT = 24.8346780; // Your latitude
const SERVER_LON = 92.8165690; // Your longitude
const LocationDistance: React.FC = () => {
const [distance, setDistance] = useState<number | null>(null);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchData = async () => {
try {
const userIp = await getUserIp();
const userLocation = await getLocation(userIp);
const [userLat, userLon] = userLocation.loc.split(',').map(Number);
const distance = calculateDistance(userLat, userLon, SERVER_LAT, SERVER_LON);
setDistance(distance);
} catch (err: any) {
if (axios.isAxiosError(err)) {
setError(`Failed to fetch location: ${err.message}`);
} else {
setError(`Unexpected error: ${err}`);
}
}
};
fetchData();
}, []);
if (error) {
return <h1 className='dark:text-slate-400 text-slate-600'>Error: {error}</h1>;
}
if (distance === null) {
return <h1 className='dark:text-slate-400 text-slate-600'>Calculating.....</h1>;
}
return <h1 className='dark:text-slate-400 italic text-sm text-slate-600'>{distance.toFixed(2)} km away!</h1>;
};
export default LocationDistance;
Step 5: Displaying the Component
Finally, youāll wanna drop this component into your app. Hereās a quick example of how to do it:
// app/components/MyLocation.tsx
import React from 'react';
import LocationDistance from './LocationDistance';
const MyLocation = () => {
return (
<div className='w-full flex items-center gap-2'>
<span>āļø</span>
<a
href="https://en.wikipedia.org/wiki/Silchar"
className="underline flex items-center gap-1"
target="_blank"
>
<span>Silchar, Assam, India</span>
</a>
|<LocationDistance/>
</div>
);
};
export default MyLocation;
This is how it looks now
Conclusion
In this tutorial, we've shown you how to build a Next.js component that figures out and shows the distance between where you are and a set spot. We covered using axios
for API requests, dealing with errors, and using React hooks to manage state. It's a cool feature you can add to all sorts of apps. Happy coding! š¤
Thank You