Implement instant websocket room updates

This commit is contained in:
2026-08-25 22:23:38 +02:00
parent bfc93dceba
commit d6e5455e90
18 changed files with 303 additions and 130 deletions
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { useForm } from '@inertiajs/vue3';
import { useHttp } from '@inertiajs/vue3';
import { Eye, RotateCcw, Trash2 } from '@lucide/vue';
import { nextRound, reset as resetRound, reveal } from '@/routes/room';
@@ -7,26 +7,29 @@ import type { RoomModeratorControlsProps } from '@/types/room';
const props = defineProps<RoomModeratorControlsProps>();
const revealForm = useForm<{ room?: string }>({});
const nextRoundForm = useForm<{ room?: string }>({});
const resetForm = useForm<{ room?: string }>({});
const revealRequest = useHttp<{ room?: string }>(
() => reveal(props.roomId),
{},
);
const nextRoundRequest = useHttp<{ room?: string }>(
() => nextRound(props.roomId),
{},
);
const resetRequest = useHttp<{ room?: string }>(
() => resetRound(props.roomId),
{},
);
function revealCards(): void {
revealForm.submit(reveal(props.roomId), {
preserveScroll: true,
});
void revealRequest.submit();
}
function startNextRound(): void {
nextRoundForm.submit(nextRound(props.roomId), {
preserveScroll: true,
});
void nextRoundRequest.submit();
}
function resetVotes(): void {
resetForm.submit(resetRound(props.roomId), {
preserveScroll: true,
});
void resetRequest.submit();
}
</script>
@@ -35,7 +38,7 @@ function resetVotes(): void {
<button
type="button"
class="inline-flex items-center gap-2 rounded-xl border border-slate-600 bg-slate-800 px-4 py-2.5 font-semibold text-slate-200 transition hover:bg-slate-700 disabled:cursor-not-allowed disabled:opacity-40"
:disabled="resetForm.processing || !hasVotes"
:disabled="resetRequest.processing || !hasVotes"
@click="resetVotes"
>
<Trash2 class="size-4" />
@@ -45,18 +48,18 @@ function resetVotes(): void {
<div class="moderator-controls">
<p
v-if="revealForm.errors.room || nextRoundForm.errors.room"
v-if="revealRequest.errors.room || nextRoundRequest.errors.room"
class="max-w-64 rounded-lg bg-rose-950/90 px-3 py-2 text-right text-sm text-rose-200 shadow-lg"
role="alert"
>
{{ revealForm.errors.room ?? nextRoundForm.errors.room }}
{{ revealRequest.errors.room ?? nextRoundRequest.errors.room }}
</p>
<button
v-if="!revealed"
type="button"
class="inline-flex items-center gap-2 rounded-xl border border-slate-300 bg-slate-100 px-5 py-2.5 font-semibold text-slate-900 transition hover:bg-white disabled:opacity-50"
:disabled="revealForm.processing"
:disabled="revealRequest.processing"
@click="revealCards"
>
<Eye class="size-4" />
@@ -67,7 +70,7 @@ function resetVotes(): void {
v-else
type="button"
class="inline-flex items-center gap-2 rounded-xl border border-slate-300 bg-slate-100 px-5 py-2.5 font-semibold text-slate-900 transition hover:bg-white disabled:opacity-50"
:disabled="nextRoundForm.processing"
:disabled="nextRoundRequest.processing"
@click="startNextRound"
>
<RotateCcw class="size-4" />