feat: implement unique visitor tracking using Redis and display count on home page
This commit is contained in:
@@ -3,9 +3,27 @@ import { Card, CardHeader } from "@/components/ui/card";
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { getFollowerCounts } from "@/lib/followers";
|
import { getFollowerCounts } from "@/lib/followers";
|
||||||
import { LinkCard } from "@/components/LinkCard";
|
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() {
|
export default async function Home() {
|
||||||
const counts = await getFollowerCounts();
|
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 = {
|
const jsonLd = {
|
||||||
"@context": "https://schema.org",
|
"@context": "https://schema.org",
|
||||||
"@type": "ProfilePage",
|
"@type": "ProfilePage",
|
||||||
@@ -20,6 +38,7 @@ export default async function Home() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="flex min-h-screen flex-col items-center justify-center p-4">
|
<main className="flex min-h-screen flex-col items-center justify-center p-4">
|
||||||
<script
|
<script
|
||||||
@@ -50,6 +69,14 @@ export default async function Home() {
|
|||||||
<p className="text-sm text-zinc-400 mt-1">
|
<p className="text-sm text-zinc-400 mt-1">
|
||||||
{config.profile.desc}
|
{config.profile.desc}
|
||||||
</p>
|
</p>
|
||||||
|
{visitorCount > 0 && (
|
||||||
|
<div className="mt-3 flex justify-center">
|
||||||
|
<Kbd>
|
||||||
|
<Users className="size-3.5" />
|
||||||
|
<span>{visitorCount} Unique Visitors</span>
|
||||||
|
</Kbd>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -56,11 +56,11 @@ export const config_p2 = {
|
|||||||
desc: "กรอกฟอร์ม",
|
desc: "กรอกฟอร์ม",
|
||||||
icon: "/icon/form.webp",
|
icon: "/icon/form.webp",
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
name: "Minecraft",
|
// name: "Minecraft",
|
||||||
link: "/minecraft",
|
// link: "/minecraft",
|
||||||
desc: "เข้าเซิร์ฟเวอร์ Minecraft",
|
// desc: "เข้าเซิร์ฟเวอร์ Minecraft",
|
||||||
icon: "/icon/mc.webp",
|
// icon: "/icon/mc.webp",
|
||||||
}
|
// }
|
||||||
] as LinkConfig[]
|
] as LinkConfig[]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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,6 +1,7 @@
|
|||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
|
serverExternalPackages: ["bun"],
|
||||||
allowedDevOrigins: ['test.gunshiz.top'],
|
allowedDevOrigins: ['test.gunshiz.top'],
|
||||||
images: {
|
images: {
|
||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
|
|||||||
Reference in New Issue
Block a user