Skip to content

Commit

Permalink
feat: add redis and view counter
Browse files Browse the repository at this point in the history
  • Loading branch information
mxkaske committed May 14, 2023
1 parent 400c03b commit 97369c4
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 4 deletions.
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=
36 changes: 36 additions & 0 deletions app/api/incr/route.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Redis } from "@upstash/redis";
import { NextRequest, NextResponse } from "next/server";

const redis = Redis.fromEnv();

export const runtime = "edge";

export async function GET(request: NextRequest) {
const ip = request.ip;
const searchParams = request.nextUrl.searchParams;
const hasSlug = searchParams.has("slug");
const slug = hasSlug ? searchParams.get("slug") : null;

if (ip) {
const buf = await crypto.subtle.digest(
"SHA-256",
new TextEncoder().encode(ip)
);

const hash = Array.from(new Uint8Array(buf))
.map((b) => b.toString(16).padStart(2, "0"))
.join("");

const isNew = await redis.set(["deduplicate", hash, slug].join(":"), true, {
nx: true,
ex: 24 * 60 * 60, // 1d
});

if (!isNew) {
new NextResponse("Already Increased Counter", { status: 200 });
}
}

await redis.incr(["pageviews", "posts", slug].join(":"));
return new NextResponse("Increased Counter", { status: 202 });
}
6 changes: 6 additions & 0 deletions app/post/[slug]/content.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
"use client";

import React from "react";
import { Post } from "@/.contentlayer/generated";
import { components } from "@/lib/mdx";
import { useMDXComponent } from "next-contentlayer/hooks";

export function Content({ post }: { post: Post }) {
const MDXContent = useMDXComponent(post.body.code);

React.useEffect(() => {
fetch(`/api/incr?slug=${post.slug}`);
}, [post.slug]);

return (
<div className="prose dark:prose-invert mx-auto">
<MDXContent components={components} />
Expand Down
28 changes: 25 additions & 3 deletions app/post/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { notFound } from "next/navigation";
import { Content } from "./content";
import { Github } from "lucide-react";
import { Link } from "@/components/mdx/link";
import { Redis } from "@upstash/redis";

const redis = Redis.fromEnv();

function formatDate(date: Date) {
return new Intl.DateTimeFormat("en-US", {
Expand All @@ -11,11 +14,23 @@ function formatDate(date: Date) {
}).format(date);
}

export default function CraftPage({ params }: { params: { slug: string } }) {
function formatNumber(value: number) {
return new Intl.NumberFormat("en-US").format(value);
}

export default async function CraftPage({
params,
}: {
params: { slug: string };
}) {
const post = allPosts.find((c) => c.url === `/post/${params.slug}`);
if (!post) {
notFound();
}

const views =
(await redis.get<number>(["pageviews", "posts", post.slug].join(":"))) ?? 0;

return (
<article className="max-w-prose mx-auto">
<div className="flex justify-between items-end">
Expand All @@ -37,8 +52,15 @@ export default function CraftPage({ params }: { params: { slug: string } }) {
</a>
</div>
<Content post={post} />
<div className="mt-8">
<Link href="/">Back</Link>
<div className="mt-8 flex justify-between items-center">
<div>
<Link href="/">Back</Link>
</div>
<div>
<p className="text-muted-foreground font-mono text-sm tracking-tighter">
{formatNumber(views)} views
</p>
</div>
</div>
</article>
);
Expand Down
2 changes: 1 addition & 1 deletion contentlayer.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const Post = defineDocumentType(() => ({
computedFields: {
slug: {
type: "string",
resolve: (post) => `${post._raw.sourceFileName}`,
resolve: (post) => `${post._raw.flattenedPath}`,
},
url: {
type: "string",
Expand Down
61 changes: 61 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@types/node": "20.1.1",
"@types/react": "18.2.6",
"@types/react-dom": "18.2.4",
"@upstash/redis": "^1.20.6",
"@vercel/og": "^0.5.4",
"autoprefixer": "10.4.14",
"class-variance-authority": "^0.6.0",
Expand Down

0 comments on commit 97369c4

Please sign in to comment.