This commit is contained in:
Daniel Bulant 2026-05-16 15:11:38 +02:00
parent 49e3299224
commit d72bc9a303
No known key found for this signature in database
3 changed files with 81 additions and 5 deletions

View file

@ -75,6 +75,55 @@ export const quizRoutes = new Elysia()
},
{ auth: true },
)
.post(
"/restart",
async ({ user, set, params }) => {
const membership = await getMemberRecord(db, user.id);
if (!membership || membership.partyId !== params.partyId) {
set.status = 403;
return { error: "Not a member of this party" };
}
const currentParty = await db.query.party.findFirst({
where: {
id: params.partyId,
},
});
if (!currentParty) {
set.status = 404;
return { error: "Party not found" };
}
const quizData = currentParty.data as QuizState | null;
if (!quizData || quizData.status !== "results") {
set.status = 409;
return { error: "Quiz is not finished yet" };
}
await db
.update(party)
.set({
status: "started",
data: null,
lastUpdated: new Date(),
})
.where(eq(party.id, params.partyId));
const handle = await DBOS.startWorkflow(quizWf.restartQuiz, {
queueName: quizQueue.name,
enqueueOptions: { queuePartitionKey: params.partyId },
})(params.partyId);
const status = await getPartyStatus(params.partyId);
broadcastStatusToMembers(status);
return {
message: "Quiz restarted",
workflowId: handle.workflowID,
};
},
{ auth: true },
)
.post(
"/response",
async ({ user, body, params, set }) => {
@ -90,8 +139,6 @@ export const quizRoutes = new Elysia()
}
const quizData = party.data as QuizState | null;
console.log("response quiz data", party, quizData);
if (!quizData || quizData.status !== "running") {
set.status = 400;
return { error: "Quiz not running" };

View file

@ -32,6 +32,16 @@ export class QuizWorkflow extends ConfiguredInstance {
@DBOS.workflow()
async startQuiz(partyId: string): Promise<void> {
await partyAnalysisWorkflow.analyzeParty(partyId);
await this.runQuiz(partyId);
}
@DBOS.workflow()
async restartQuiz(partyId: string): Promise<void> {
await this.runQuiz(partyId);
}
private async runQuiz(partyId: string): Promise<void> {
const quizState: QuizState = {
status: "running",
workflowId: DBOS.workflowID ?? null,
@ -42,8 +52,6 @@ export class QuizWorkflow extends ConfiguredInstance {
history: [],
};
await partyAnalysisWorkflow.analyzeParty(partyId);
// Initialize quiz state
await QuizWorkflow.updatePartyData(partyId, quizState);
@ -196,7 +204,6 @@ export class QuizWorkflow extends ConfiguredInstance {
}
}
const _scoringGroups = groups.slice(0, Math.max(0, groups.length - 1));
if (groups.length <= 1) {
return round.responses.map((response) => [
response.playerId,

View file

@ -1,7 +1,13 @@
import { useState } from "react";
import { toast } from "sonner";
import { Button } from "#/components/ui/button";
import { useParty } from "#/hooks/use-party";
import { client } from "#/lib/eden";
export function Results() {
const { party, members } = useParty();
const [isRestarting, setIsRestarting] = useState(false);
if (!party?.data) return null;
const leaderboard = members
@ -18,6 +24,22 @@ export function Results() {
return (
<div className="space-y-4">
<h2 className="text-2xl font-semibold text-foreground">Leaderboard</h2>
<Button
disabled={isRestarting}
onClick={async () => {
if (isRestarting) return;
setIsRestarting(true);
try {
await client.api.party({ partyId: party.id }).quiz.restart.post();
} catch (error) {
toast((error as Error)?.message || "Failed to restart quiz.");
} finally {
setIsRestarting(false);
}
}}
>
{isRestarting ? "Restarting..." : "Play again"}
</Button>
<div className="space-y-2">
{leaderboard.length === 0 ? (
<p className="text-sm text-muted-foreground">No scores yet.</p>