feat: implement unique visitor tracking using Redis and display count on home page

This commit is contained in:
2026-06-28 22:39:52 +07:00 Unverified
parent 4d311e0804
commit 41d4e6b8f8
4 changed files with 49 additions and 6 deletions
+27
View File
@@ -3,9 +3,27 @@ import { Card, CardHeader } from "@/components/ui/card";
import Image from "next/image";
import { getFollowerCounts } from "@/lib/followers";
import { LinkCard } from "@/components/LinkCard";
import { getRedisClient } from "@/lib/redis";
import { headers } from "next/headers";
import { Users } from "lucide-react";
import { Kbd } from "@/components/ui/kbd";
export default async function Home() {
const counts = await getFollowerCounts();
const headersList = await headers();
const ip = headersList.get("x-forwarded-for") || headersList.get("x-real-ip") || "unknown";
let visitorCount = 0;
try {
const redis = await getRedisClient();
if (ip !== "unknown") {
await redis.sadd("erika:unique_visitors", ip);
}
visitorCount = await redis.scard("erika:unique_visitors");
} catch (e) {
console.error("Failed to track visitor:", e);
}
const jsonLd = {
"@context": "https://schema.org",
"@type": "ProfilePage",
@@ -20,6 +38,7 @@ export default async function Home() {
},
};
return (
<main className="flex min-h-screen flex-col items-center justify-center p-4">
<script
@@ -50,6 +69,14 @@ export default async function Home() {
<p className="text-sm text-zinc-400 mt-1">
{config.profile.desc}
</p>
{visitorCount > 0 && (
<div className="mt-3 flex justify-center">
<Kbd>
<Users className="size-3.5" />
<span>{visitorCount} Unique Visitors</span>
</Kbd>
</div>
)}
</div>
</CardHeader>
+6 -6
View File
@@ -56,11 +56,11 @@ export const config_p2 = {
desc: "กรอกฟอร์ม",
icon: "/icon/form.webp",
},
{
name: "Minecraft",
link: "/minecraft",
desc: "เข้าเซิร์ฟเวอร์ Minecraft",
icon: "/icon/mc.webp",
}
// {
// name: "Minecraft",
// link: "/minecraft",
// desc: "เข้าเซิร์ฟเวอร์ Minecraft",
// icon: "/icon/mc.webp",
// }
] as LinkConfig[]
};
+15
View File
@@ -0,0 +1,15 @@
// @ts-ignore
import { RedisClient } from "bun";
const globalForRedis = global as unknown as { redis: RedisClient };
export const getRedisClient = async () => {
if (!globalForRedis.redis) {
globalForRedis.redis = new RedisClient(process.env.REDIS_URL || "");
}
const client = globalForRedis.redis;
if (!client.connected) {
await client.connect();
}
return client;
};
+1
View File
@@ -1,6 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
serverExternalPackages: ["bun"],
allowedDevOrigins: ['test.gunshiz.top'],
images: {
remotePatterns: [