restart
This commit is contained in:
parent
49e3299224
commit
d72bc9a303
3 changed files with 81 additions and 5 deletions
|
|
@ -75,6 +75,55 @@ export const quizRoutes = new Elysia()
|
||||||
},
|
},
|
||||||
{ auth: true },
|
{ 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(
|
.post(
|
||||||
"/response",
|
"/response",
|
||||||
async ({ user, body, params, set }) => {
|
async ({ user, body, params, set }) => {
|
||||||
|
|
@ -90,8 +139,6 @@ export const quizRoutes = new Elysia()
|
||||||
}
|
}
|
||||||
const quizData = party.data as QuizState | null;
|
const quizData = party.data as QuizState | null;
|
||||||
|
|
||||||
console.log("response quiz data", party, quizData);
|
|
||||||
|
|
||||||
if (!quizData || quizData.status !== "running") {
|
if (!quizData || quizData.status !== "running") {
|
||||||
set.status = 400;
|
set.status = 400;
|
||||||
return { error: "Quiz not running" };
|
return { error: "Quiz not running" };
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,16 @@ export class QuizWorkflow extends ConfiguredInstance {
|
||||||
|
|
||||||
@DBOS.workflow()
|
@DBOS.workflow()
|
||||||
async startQuiz(partyId: string): Promise<void> {
|
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 = {
|
const quizState: QuizState = {
|
||||||
status: "running",
|
status: "running",
|
||||||
workflowId: DBOS.workflowID ?? null,
|
workflowId: DBOS.workflowID ?? null,
|
||||||
|
|
@ -42,8 +52,6 @@ export class QuizWorkflow extends ConfiguredInstance {
|
||||||
history: [],
|
history: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
await partyAnalysisWorkflow.analyzeParty(partyId);
|
|
||||||
|
|
||||||
// Initialize quiz state
|
// Initialize quiz state
|
||||||
await QuizWorkflow.updatePartyData(partyId, quizState);
|
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) {
|
if (groups.length <= 1) {
|
||||||
return round.responses.map((response) => [
|
return round.responses.map((response) => [
|
||||||
response.playerId,
|
response.playerId,
|
||||||
|
|
|
||||||
|
|
@ -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 { useParty } from "#/hooks/use-party";
|
||||||
|
import { client } from "#/lib/eden";
|
||||||
|
|
||||||
export function Results() {
|
export function Results() {
|
||||||
const { party, members } = useParty();
|
const { party, members } = useParty();
|
||||||
|
const [isRestarting, setIsRestarting] = useState(false);
|
||||||
if (!party?.data) return null;
|
if (!party?.data) return null;
|
||||||
|
|
||||||
const leaderboard = members
|
const leaderboard = members
|
||||||
|
|
@ -18,6 +24,22 @@ export function Results() {
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<h2 className="text-2xl font-semibold text-foreground">Leaderboard</h2>
|
<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">
|
<div className="space-y-2">
|
||||||
{leaderboard.length === 0 ? (
|
{leaderboard.length === 0 ? (
|
||||||
<p className="text-sm text-muted-foreground">No scores yet.</p>
|
<p className="text-sm text-muted-foreground">No scores yet.</p>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue