Files
MineGeo/components/Results.tsx

122 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useI18n } from "@/components/I18nProvider";
import { useEffect, useState } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { api } from "./StartGame";
import { GuessMap } from "./GuessMap";
import type { SessionView } from "./Game";
import { difficulties } from "@/shared/protocol";
export function Results({ id }: { id: string }) {
const { t, formatNumber } = useI18n();
const [session, setSession] = useState<SessionView | null>(null),
[selected, setSelected] = useState(0),
[error, setError] = useState("");
const router = useRouter();
useEffect(() => {
let disposed = false;
setSession(null);
setSelected(0);
setError("");
api<SessionView>("sessions/" + id)
.then((s) => {
if (disposed) return;
if (s.round < 5) router.replace("/play/" + id);
else setSession(s);
})
.catch((e) => {
if (!disposed) setError(e.message);
});
return () => {
disposed = true;
};
}, [id, router]);
if (error) return <p role="alert">{t(error)}</p>;
if (!session)
return <p className="muted">{t("Unpacking your expedition…")}</p>;
const total = session.rounds.reduce((n, r) => n + (r.result?.score || 0), 0);
const current = session.rounds[selected].result;
return (
<>
<span className="eyebrow">
{t("EXPEDITION COMPLETE ·")}{" "}
{session.difficultySettings.id in difficulties
? t(session.difficultySettings.name)
: session.difficultySettings.name}
</span>
<h1>{t("Every guess is a story.")}</h1>
<p className="lead">
{session.name} {t("· Here’s where your instincts took you.")}
</p>
<div className="results-total">
{formatNumber(total)}
<small> / 25,000</small>
</div>
<div className="results-grid">
<div className="result-map">
<GuessMap
bounds={session.bounds}
image={session.map}
pin={current?.guess}
actual={current?.actual}
disabled
/>
</div>
<div className="result-summary">
<h2>{t("Your five-round journey")}</h2>
<div className="tabs">
{session.rounds.map((r, i) => (
<button
key={i}
className={i === selected ? "active" : ""}
aria-pressed={i === selected}
onClick={() => setSelected(i)}
>
{t("Round")} {i + 1}
</button>
))}
</div>
<table className="history-table">
<thead>
<tr>
<th>{t("ROUND")}</th>
<th>{t("DISTANCE")}</th>
<th>{t("POINTS")}</th>
</tr>
</thead>
<tbody>
{session.rounds.map((r, i) => (
<tr key={i}>
<td>{i + 1}</td>
<td>
{r.result?.timedOut
? t("Timed out")
: t("{count} blocks", {
count: formatNumber(
Math.round(r.result?.distance || 0),
),
})}
</td>
<td>{r.result ? formatNumber(r.result.score) : "—"}</td>
</tr>
))}
</tbody>
</table>
<div className="inline-actions">
<Link className="button primary" href="/servers">
{t("Another adventure →")}
</Link>
<Link className="button" href="/dashboard">
{t("My maps")}
</Link>
<Link className="text-link" href="/leaderboard">
{t("View leaderboard →")}
</Link>
</div>
</div>
</div>
</>
);
}