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")