From 0af907c1d4c1410e39215ae8906435bf0445dd10 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Mon, 9 Feb 2026 16:31:28 +0100 Subject: [PATCH] View management --- src/app/api/view-run/route.ts | 5 +++++ src/app/runs/[runId]/components/RunTimer.tsx | 10 +++++++-- src/app/runs/[runId]/page.tsx | 7 ++++-- src/modules/live-run/actions.ts | 4 ++++ src/modules/live-run/core.ts | 23 ++++++++++++++++++++ 5 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/app/api/view-run/route.ts b/src/app/api/view-run/route.ts index 7dc3097..3bc6c7c 100644 --- a/src/app/api/view-run/route.ts +++ b/src/app/api/view-run/route.ts @@ -2,6 +2,7 @@ import { WebSocketServer, WebSocket } from "ws"; import Redis from "ioredis"; import { NextRequest, NextResponse } from "next/server"; import { LiveRunEvent } from "@/modules/live-run/types"; +import { getLiveRun, updateLiveRunViews } from "@/modules/live-run/core"; export function GET(req: NextRequest) { const headers = new Headers(); @@ -16,6 +17,9 @@ export function UPGRADE(client: WebSocket, server: WebSocketServer) { client.once("message", async (message) => { runId = message.toString(); + + await updateLiveRunViews(runId, 1); + let lastEvent: LiveRunEvent | null = null; const sendText = async () => { @@ -57,6 +61,7 @@ export function UPGRADE(client: WebSocket, server: WebSocketServer) { client.once("close", async () => { if (runId) await subscriber.unsubscribe(`liveRun:${runId}`); subscriber.quit(); + await updateLiveRunViews(runId, -1); }); client.on("error", (err) => { diff --git a/src/app/runs/[runId]/components/RunTimer.tsx b/src/app/runs/[runId]/components/RunTimer.tsx index da520b8..dc5f38d 100644 --- a/src/app/runs/[runId]/components/RunTimer.tsx +++ b/src/app/runs/[runId]/components/RunTimer.tsx @@ -4,7 +4,13 @@ import { LiveRun } from "@/modules/live-run/types"; import { Eye } from "lucide-react"; import { useEffect, useState } from "react"; -export default function RunTimer({ run }: { run: LiveRun }) { +export default function RunTimer({ + run, + views, +}: { + run: LiveRun; + views: number | null; +}) { const [time, setTime] = useState("00:00:00"); useEffect(() => { @@ -29,7 +35,7 @@ export default function RunTimer({ run }: { run: LiveRun }) {

- {run.views} + {views || run.views}

diff --git a/src/app/runs/[runId]/page.tsx b/src/app/runs/[runId]/page.tsx index 958c5fd..c47c258 100644 --- a/src/app/runs/[runId]/page.tsx +++ b/src/app/runs/[runId]/page.tsx @@ -7,7 +7,7 @@ import { FileTree } from "./components/FileTree"; import { File } from "lucide-react"; import Editor from "./components/Editor"; import useAction, { useActionInterval } from "@/hook/use-action"; -import { getLiveRun } from "@/modules/live-run/actions"; +import { getLiveRun, getLiveRunViews } from "@/modules/live-run/actions"; import ProblemCard from "@/app/problems/components/ProblemCard"; import ProfileCard from "./components/ProfileCard"; import { getProblem } from "@/modules/problems/actions"; @@ -18,6 +18,9 @@ export default function Run() { const params = useParams<{ runId: string }>(); const [run] = useAction(() => getLiveRun(params.runId), [params]); + const [views] = useActionInterval(() => getLiveRunViews(params.runId), 2500, [ + params, + ]); const [problem] = useAction( async () => (run?.id ? getProblem(run.problem) : null), @@ -55,7 +58,7 @@ export default function Run() {
- {run && } + {run && }
diff --git a/src/modules/live-run/actions.ts b/src/modules/live-run/actions.ts index 19d4cc5..b878f8d 100644 --- a/src/modules/live-run/actions.ts +++ b/src/modules/live-run/actions.ts @@ -10,3 +10,7 @@ export async function getLiveRuns(): Promise { export async function getLiveRun(id: string): Promise { return Core.getLiveRun(id); } + +export async function getLiveRunViews(id: string): Promise { + return Core.getLiveRunViews(id); +} diff --git a/src/modules/live-run/core.ts b/src/modules/live-run/core.ts index 55d4a7f..6d90c0a 100644 --- a/src/modules/live-run/core.ts +++ b/src/modules/live-run/core.ts @@ -28,6 +28,29 @@ export async function getLiveRun(id: string): Promise { return JSON.parse(data) as LiveRun; } +/** + * Get live run views from Redis + */ +export async function getLiveRunViews(id: string): Promise { + const run = await getLiveRun(id); + if (!run) return null; + return run.views; +} + +/** + * Get live run views from Redis + */ +export async function updateLiveRunViews( + id: string, + increment: number, +): Promise { + const run = await getLiveRun(id); + if (!run) return null; + run.views += increment; + await redis.set(`liveRun:${run.id}`, JSON.stringify(run)); + return run.views; +} + /** * Get all live runs */