diff --git a/app/(protected)/dashboard/urls/meta-chart.tsx b/app/(protected)/dashboard/urls/meta-chart.tsx
index 717e520..f1c30d5 100644
--- a/app/(protected)/dashboard/urls/meta-chart.tsx
+++ b/app/(protected)/dashboard/urls/meta-chart.tsx
@@ -84,7 +84,7 @@ function generateStatsList(
let totalClicks = 0;
records.forEach((record) => {
- const dimValue = record[dimension] ?? ("(None)" as any);
+ const dimValue = record[dimension] || ("(None)" as any);
const click = record.click;
if (!dimensionCounts[dimValue]) {
@@ -101,7 +101,7 @@ function generateStatsList(
for (const [dimValue, clicks] of Object.entries(dimensionCounts)) {
const percentage = (clicks / totalClicks) * 100;
statsList.push({
- dimension: dimValue,
+ dimension: dimValue ?? "(None)",
clicks,
percentage: percentage.toFixed(0) + "%",
});
@@ -229,8 +229,12 @@ export function DailyPVUVChart({ data }: { data: UrlMeta[] }) {
-
-
+ {refererStats.length > 0 && (
+
+ )}
+ {countryStats.length > 0 && (
+
+ )}
diff --git a/app/api/s/route.ts b/app/api/s/route.ts
index ccf1ea9..d426560 100644
--- a/app/api/s/route.ts
+++ b/app/api/s/route.ts
@@ -2,17 +2,22 @@ import { NextRequest, NextResponse } from "next/server";
import { createUserShortUrlMeta, getUrlBySuffix } from "@/lib/dto/short-urls";
-export async function GET(req: NextRequest) {
+export async function POST(req: NextRequest) {
try {
- const url = new URL(req.url);
- const slug = url.searchParams.get("slug");
- const referer = url.searchParams.get("referer");
- const ip = url.searchParams.get("ip");
- const city = url.searchParams.get("city");
- const region = url.searchParams.get("region");
- const country = url.searchParams.get("country");
- const latitude = url.searchParams.get("latitude");
- const longitude = url.searchParams.get("longitude");
+ const {
+ slug,
+ referer,
+ ip,
+ city,
+ region,
+ country,
+ latitude,
+ longitude,
+ lang,
+ device,
+ browser,
+ } = await req.json();
+
if (!slug || !ip) return Response.json(null);
const res = await getUrlBySuffix(slug);
@@ -26,7 +31,7 @@ export async function GET(req: NextRequest) {
return Response.json(null);
}
- // console.log("[api/s]", ip, res.id);
+ console.log("[api/s]", device, browser);
await createUserShortUrlMeta({
urlId: res.id,
click: 1,
@@ -37,6 +42,9 @@ export async function GET(req: NextRequest) {
latitude,
longitude,
referer,
+ lang,
+ device,
+ browser,
});
return Response.json(res.target);
}
diff --git a/middleware.ts b/middleware.ts
index 1cba66e..e345b07 100644
--- a/middleware.ts
+++ b/middleware.ts
@@ -1,6 +1,7 @@
import { NextResponse } from "next/server";
import { geolocation } from "@vercel/functions";
import { auth } from "auth";
+import UAParser from "ua-parser-js";
import { siteConfig } from "./config/site";
@@ -12,13 +13,44 @@ export default auth(async (req) => {
const ip = req.headers.get("X-Forwarded-For");
if (req.url.includes("/s/")) {
const match = req.url.match(/[^/]+$/);
- const geo = geolocation(req);
if (match) {
+ const geo = geolocation(req);
+ const userLanguage = req.headers.get("accept-language")?.split(",")[0];
+
+ const ua = req.headers.get("user-agent");
+ const parser = new UAParser();
+ parser.setUA(ua);
+ const browser = parser.getBrowser();
+ const device = parser.getDevice();
+
+ console.log(device, browser);
+
const referer = req.headers.get("referer") || "(None)";
- const res = await fetch(
- `${siteConfig.url}/api/s?slug=${match[0]}&referer=${referer}&ip=${ip}&city=${geo?.city}®ion=${geo?.region}&country=${geo?.country}&latitude=${geo?.latitude}&longitude=${geo?.longitude}&flag=${geo?.flag}`,
- );
+ // const res1 = await fetch(
+ // `${siteConfig.url}/api/s?slug=${match[0]}&referer=${referer}&ip=${ip}&city=${geo?.city}®ion=${geo?.region}&country=${geo?.country}&latitude=${geo?.latitude}&longitude=${geo?.longitude}&flag=${geo?.flag}`,
+ // );
+
+ const res = await fetch(`${siteConfig.url}/api/s`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ slug: match[0],
+ referer,
+ ip,
+ city: geo?.city,
+ region: geo?.region,
+ country: geo?.country,
+ latitude: geo?.latitude,
+ longitude: geo?.longitude,
+ flag: geo?.flag,
+ lang: userLanguage,
+ device: device.model || "Unknown",
+ browser: browser.name || "Unknown",
+ }),
+ });
if (!res.ok) {
return NextResponse.redirect(`${siteConfig.url}/docs/short-urls`);
diff --git a/package.json b/package.json
index 12ff221..fd1b588 100644
--- a/package.json
+++ b/package.json
@@ -93,6 +93,7 @@
"swr": "^2.2.5",
"tailwind-merge": "^2.4.0",
"tailwindcss-animate": "^1.0.7",
+ "ua-parser-js": "^1.0.38",
"vaul": "^0.9.1",
"zod": "^3.23.8"
},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 11bf9b5..a98a25d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -230,6 +230,9 @@ importers:
tailwindcss-animate:
specifier: ^1.0.7
version: 1.0.7(tailwindcss@3.4.6)
+ ua-parser-js:
+ specifier: ^1.0.38
+ version: 1.0.38
vaul:
specifier: ^0.9.1
version: 0.9.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -6234,6 +6237,9 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
+ ua-parser-js@1.0.38:
+ resolution: {integrity: sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ==}
+
unbox-primitive@1.0.2:
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
@@ -13665,6 +13671,8 @@ snapshots:
typescript@5.5.3: {}
+ ua-parser-js@1.0.38: {}
+
unbox-primitive@1.0.2:
dependencies:
call-bind: 1.0.7
diff --git a/prisma/migrations/20240705091917_init/migration.sql b/prisma/migrations/20240705091917_init/migration.sql
index 21113d8..9320377 100644
--- a/prisma/migrations/20240705091917_init/migration.sql
+++ b/prisma/migrations/20240705091917_init/migration.sql
@@ -171,5 +171,8 @@ ALTER TABLE "url_metas" ADD COLUMN "region" TEXT;
ALTER TABLE "url_metas" ADD COLUMN "latitude" TEXT;
ALTER TABLE "url_metas" ADD COLUMN "longitude" TEXT;
ALTER TABLE "url_metas" ADD COLUMN "referer" TEXT;
+ALTER TABLE "url_metas" ADD COLUMN "lang" TEXT;
+ALTER TABLE "url_metas" ADD COLUMN "device" TEXT;
+ALTER TABLE "url_metas" ADD COLUMN "browser" TEXT;
-ALTER TABLE "user_url" ADD COLUMN "expiration" TEXT NOT NULL DEFAULT '-1';
\ No newline at end of file
+ALTER TABLE "user_urls" ADD COLUMN "expiration" TEXT NOT NULL DEFAULT '-1';
\ No newline at end of file
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 8e0b5ab..395033b 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -133,6 +133,9 @@ model UrlMeta {
latitude String?
longitude String?
referer String?
+ lang String?
+ device String?
+ browser String?
createdAt DateTime @default(now()) @map(name: "created_at")
updatedAt DateTime @default(now()) @map(name: "updated_at")