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
+20 -16
View File
@@ -1,13 +1,14 @@
<script setup lang="ts">
import { useForm } from '@inertiajs/vue3';
import { useHttp } from '@inertiajs/vue3';
import { Keyboard } from '@lucide/vue';
import { useEventListener } from '@vueuse/core';
import { watch } from 'vue';
import { store as storeVote } from '@/routes/room/vote';
import type { RoomVoteDeckProps } from '@/types/room';
import type { RoomVoteDeckEmits, RoomVoteDeckProps } from '@/types/room';
const props = defineProps<RoomVoteDeckProps>();
const emit = defineEmits<RoomVoteDeckEmits>();
const cardShortcuts = [
'1',
@@ -25,29 +26,32 @@ const cardShortcuts = [
),
];
const voteForm = useForm({
const voteRequest = useHttp(() => storeVote(props.roomId), {
value: props.currentVote ?? '',
});
watch(
() => props.currentVote,
(value) => {
if (!voteForm.processing) {
voteForm.value = value ?? '';
if (!voteRequest.processing) {
voteRequest.value = value ?? '';
}
},
);
function submitVote(value: string): void {
if (props.revealed || voteForm.processing) {
if (props.revealed || voteRequest.processing) {
return;
}
voteForm.value = value;
voteForm.submit(storeVote(props.roomId), {
preserveScroll: true,
const previousVote = props.currentVote;
voteRequest.value = value;
emit('vote-changed', value);
void voteRequest.submit({
onError: () => {
voteForm.value = props.currentVote ?? '';
voteRequest.value = previousVote ?? '';
emit('vote-changed', previousVote);
},
});
}
@@ -71,7 +75,7 @@ function handleKeyboardVote(event: KeyboardEvent): void {
if (
!props.presenterMode ||
props.revealed ||
voteForm.processing ||
voteRequest.processing ||
event.repeat ||
event.altKey ||
event.ctrlKey ||
@@ -118,10 +122,10 @@ useEventListener('keydown', handleKeyboardVote);
class="deck-card"
:class="{
'is-selected':
!presenterMode && voteForm.value === card.key,
!presenterMode && voteRequest.value === card.key,
}"
:disabled="voteForm.processing"
:aria-pressed="voteForm.value === card.key"
:disabled="voteRequest.processing"
:aria-pressed="voteRequest.value === card.key"
:aria-label="`Karte ${card.label} wählen`"
@click="submitVote(card.key)"
>
@@ -138,11 +142,11 @@ useEventListener('keydown', handleKeyboardVote);
</div>
<p
v-if="voteForm.errors.value"
v-if="voteRequest.errors.value"
class="mt-3 text-sm text-rose-300"
role="alert"
>
{{ voteForm.errors.value }}
{{ voteRequest.errors.value }}
</p>
</section>
</template>