Skip to content

Commit b404cdb

Browse files
committed
Merge branch 'feat/ip-geolocation' into chore/all-my-stuffs
# Conflicts: # components.d.ts # src/tools/index.ts
2 parents ab3f00e + a0b8cf0 commit b404cdb

File tree

3 files changed

+130
-0
lines changed

3 files changed

+130
-0
lines changed

src/tools/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { tool as dateDurationCalculator } from './date-duration-calculator';
2626
import { tool as textToUnicode } from './text-to-unicode';
2727
import { tool as certificateKeyParser } from './certificate-key-parser';
2828
import { tool as crcCalculator } from './crc-calculator';
29+
import { tool as ipGeoLocation } from './ip-geo-location';
2930
import { tool as safelinkDecoder } from './safelink-decoder';
3031
import { tool as xmlToJson } from './xml-to-json';
3132
import { tool as jsonToXml } from './json-to-xml';
@@ -253,6 +254,7 @@ export const toolsByCategory: ToolCategory[] = [
253254
emailParser,
254255
outlookParser,
255256
integersToIp,
257+
ipGeoLocation,
256258
],
257259
},
258260
{

src/tools/ip-geo-location/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { World } from '@vicons/tabler';
2+
import { defineTool } from '../tool';
3+
4+
export const tool = defineTool({
5+
name: 'IP Geo Location',
6+
path: '/ip-geo-location',
7+
description: 'Retrieve information about an IPv4/6 address or domain location',
8+
keywords: ['ip', 'domain', 'geo', 'location'],
9+
component: () => import('./ip-geo-location.vue'),
10+
icon: World,
11+
createdAt: new Date('2024-01-17'),
12+
});
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<script setup lang="ts">
2+
import type { CKeyValueListItems } from '@/ui/c-key-value-list/c-key-value-list.types';
3+
4+
const ip = ref('8.8.8.8');
5+
const errorMessage = ref('');
6+
7+
const fields: Array<{ field: string; name: string }> = [
8+
{ field: 'ip', name: 'IP' },
9+
{ field: 'hostname', name: 'Host Name' },
10+
{ field: 'country', name: 'Country Code' },
11+
{ field: 'region', name: 'Region/state Code' },
12+
{ field: 'city', name: 'City' },
13+
{ field: 'postal', name: 'Postal Code' },
14+
{ field: 'loc', name: 'Latitude/Longitude' },
15+
{ field: 'timezone', name: 'Timezone' },
16+
{ field: 'org', name: 'Organization Name' },
17+
];
18+
19+
const geoInfos = ref<CKeyValueListItems>([]);
20+
const geoInfosData = ref<{
21+
loc?: string
22+
}>({});
23+
const status = ref<'pending' | 'error' | 'success'>('pending');
24+
const token = useStorage('ip-geoloc:token', '');
25+
26+
const openStreetMapUrl = computed(
27+
() => {
28+
const [gpsLatitude, gpsLongitude] = geoInfosData.value.loc?.split(',') || [];
29+
return gpsLatitude && gpsLongitude ? `https://www.openstreetmap.org/?mlat=${gpsLatitude}&mlon=${gpsLongitude}#map=18/${gpsLatitude}/${gpsLongitude}` : undefined;
30+
},
31+
);
32+
33+
async function onGetInfos() {
34+
try {
35+
status.value = 'pending';
36+
37+
const geoInfoQueryResponse = await fetch(
38+
token.value !== ''
39+
? `https://ipinfo.io/${ip.value}/json?token=${token.value}`
40+
: `https://ipinfo.io/${ip.value}/json`);
41+
if (!geoInfoQueryResponse.ok) {
42+
throw geoInfoQueryResponse.statusText;
43+
}
44+
45+
const data = await geoInfoQueryResponse.json();
46+
47+
const allGeoInfos = [];
48+
for (const field of fields) {
49+
if (data[field.field]) {
50+
allGeoInfos.push({
51+
label: field.name,
52+
value: data[field.field],
53+
});
54+
}
55+
}
56+
57+
status.value = 'success';
58+
geoInfos.value = allGeoInfos;
59+
geoInfosData.value = data;
60+
}
61+
catch (e: any) {
62+
errorMessage.value = e.toString();
63+
status.value = 'error';
64+
return [];
65+
}
66+
}
67+
</script>
68+
69+
<template>
70+
<div>
71+
<div flex items-center gap-2>
72+
<c-input-text
73+
v-model:value="ip"
74+
placeholder="Enter an IPv4/6"
75+
@update:value="() => { status = 'pending' }"
76+
/>
77+
<c-button align-center @click="onGetInfos">
78+
Get GEO Location Infos
79+
</c-button>
80+
</div>
81+
82+
<details mt-2>
83+
<summary>Optional ipinfo.io token</summary>
84+
<c-input-text
85+
v-model:value="token"
86+
placeholder="Optional ipinfo.io token"
87+
@update:value="() => { status = 'pending' }"
88+
/>
89+
<n-p>
90+
<n-a href="https://ipinfo.io/">
91+
Signup for a free token
92+
</n-a>
93+
</n-p>
94+
</details>
95+
96+
<n-divider />
97+
98+
<c-card v-if="status === 'pending'" mt-5>
99+
Click on button above to get latest infos
100+
</c-card>
101+
102+
<c-card v-if="status === 'success' && openStreetMapUrl" mt-4>
103+
<c-button :href="openStreetMapUrl" target="_blank">
104+
Localize on Open Street Map
105+
</c-button>
106+
</c-card>
107+
108+
<c-card v-if="status === 'success'" mt-5>
109+
<c-key-value-list :items="geoInfos" />
110+
</c-card>
111+
112+
<n-alert v-if="status === 'error'" title="Errors occured" type="error" mt-5>
113+
{{ errorMessage }}
114+
</n-alert>
115+
</div>
116+
</template>

0 commit comments

Comments
 (0)