Files
webapp-front/pages/words.vue
T
2024-12-29 22:06:57 +01:00

87 lines
1.8 KiB
Vue

<script setup lang="ts">
import { subscribe } from "~/netcode";
import { handlers } from "~/netcode/handlers/word.handler";
import { useWordStore } from "~/store/word.store";
const newWord = ref("");
const wordStore = useWordStore();
await wordStore.fetchWordList();
const loading = ref(false);
const wordInput = ref<HTMLInputElement | null>(null);
async function createWord(e: Event) {
if (loading.value) {
return;
}
loading.value = true;
try {
await wordStore.createWord(newWord.value);
newWord.value = "";
} finally {
nextTick(() => {
loading.value = false;
nextTick(() => {
wordInput.value?.focus();
});
});
}
}
let eventSource: EventSource;
onBeforeMount(() => {
eventSource = subscribe(`/words/subscribe`);
eventSource.addEventListener("message", async (message) => {
const data = JSON.parse(message.data);
const type = data.type as string;
if (type in handlers) {
handlers[type as keyof typeof handlers](data);
}
});
});
onUnmounted(() => {
if (eventSource) {
eventSource.close();
}
});
</script>
<template>
<div id="words">
<div class="header">
<span>Word</span>
<span>Status</span>
<span></span>
<span>Submitter</span>
</div>
<Word v-for="word in wordStore.words" :id="word.id" :key="word.id" />
<div class="new-word">
<span>
<input
ref="wordInput"
type="text"
:disabled="loading"
@keypress.enter="createWord"
v-model="newWord"
/>
<button :disabled="loading" @click="createWord">Submit</button>
</span>
</div>
</div>
</template>
<style lang="css" scoped>
div#words {
display: grid;
grid-template-columns: 1fr;
}
div.header {
display: grid;
grid-template-columns: repeat(4, 1fr);
align-items: center;
}
</style>