diff --git a/app/play/[level]/[attempt]/page.tsx b/app/play/[level]/[attempt]/page.tsx
new file mode 100644
index 0000000..04d4333
--- /dev/null
+++ b/app/play/[level]/[attempt]/page.tsx
@@ -0,0 +1,54 @@
+"use client";
+
+import * as React from "react";
+import { ChevronLeftIcon } from "@radix-ui/react-icons";
+import { useQuery } from "convex/react";
+import Link from "next/link";
+import { Visualizer } from "@/components/Visualizer";
+import { Button } from "@/components/ui/button";
+import { api } from "@/convex/_generated/api";
+
+export default function PlayLevelAttemptPage({
+ params,
+}: {
+ params: { level: string; attempt: string };
+}) {
+ const level = Number.parseInt(params.level, 10);
+ const attemptNum = Number.parseInt(params.attempt, 10);
+
+ const attempt = useQuery(api.playerresults.getUserAttempt, {
+ level,
+ attempt: attemptNum,
+ });
+
+ if (attempt === undefined) {
+ return
Loading...
;
+ } else if (attempt === null) {
+ return Attempt Not Found
;
+ }
+
+ return (
+
+
+
+
+
Night #{level}
+
Attempt #{attemptNum}
+
+
+
+
+ {attempt.didWin ? "You Survived!" : "You Died!"}
+
+
+
+ );
+}
diff --git a/app/play/[level]/page.tsx b/app/play/[level]/page.tsx
index cdc2d82..1409584 100644
--- a/app/play/[level]/page.tsx
+++ b/app/play/[level]/page.tsx
@@ -278,21 +278,24 @@ export default function PlayLevelPage({
{tries && tries.attempts && tries.attempts.length > 0 && (
<>
Tries
-
- {tries.attempts.map((attempt) => (
-
+ {tries.attempts.map((attempt, idx) => (
+
+ Attempt #{idx + 1}
+
+
))}
>
diff --git a/convex/playerresults.ts b/convex/playerresults.ts
index 639a4a9..21056aa 100644
--- a/convex/playerresults.ts
+++ b/convex/playerresults.ts
@@ -1,7 +1,51 @@
import { getAuthUserId } from "@convex-dev/auth/server";
import { v } from "convex/values";
+import { api } from "./_generated/api";
+import { Id } from "./_generated/dataModel";
import { mutation, query } from "./_generated/server";
+export const getUserAttempt = query({
+ args: {
+ attempt: v.number(),
+ level: v.number(),
+ },
+ handler: async (ctx, args) => {
+ const userId = await getAuthUserId(ctx);
+
+ if (!userId) {
+ return null;
+ }
+
+ const map = await ctx.runQuery(api.maps.getMapByLevel, {
+ level: args.level,
+ });
+
+ if (map === null) {
+ return null;
+ }
+
+ const userResults = await ctx.db
+ .query("userResults")
+ .withIndex("by_mapId_userId", (q) =>
+ q.eq("mapId", map._id).eq("userId", userId),
+ )
+ .collect();
+
+ if (userResults.length !== 1) {
+ return null;
+ }
+
+ const userResult = userResults[0];
+
+ if (userResult.attempts.length < args.attempt) {
+ return null;
+ }
+
+ const attemptId: Id<"attempts"> = userResult.attempts[args.attempt - 1];
+ return await ctx.db.get(attemptId);
+ },
+});
+
export const getUserMapStatus = query({
handler: async (ctx) => {
const userId = await getAuthUserId(ctx);