Add file upload to website and integrate into chat
Some checks failed
Deploy with Docker Compose / deploy (push) Has been cancelled
Some checks failed
Deploy with Docker Compose / deploy (push) Has been cancelled
This commit is contained in:
@@ -8,6 +8,7 @@ const messagesStore = useMessagesStore();
|
||||
const messages = computed(() => messagesStore.messages);
|
||||
const messageInput = ref("");
|
||||
const messagesContainer = ref(null);
|
||||
const fileInput = ref(null);
|
||||
|
||||
function scrollToBottom() {
|
||||
nextTick(() => {
|
||||
@@ -27,6 +28,17 @@ function sendMessage() {
|
||||
messageInput.value = "";
|
||||
}
|
||||
|
||||
async function onFileSelected(e) {
|
||||
const file = e.target.files[0];
|
||||
if (!file) return;
|
||||
await messagesStore.uploadAndSendFile(file);
|
||||
fileInput.value.value = "";
|
||||
}
|
||||
|
||||
function isImageUrl(url) {
|
||||
return /\.(jpg|jpeg|png|gif|webp)$/i.test(url);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
messagesStore.connect();
|
||||
});
|
||||
@@ -45,9 +57,20 @@ onUnmounted(() => {
|
||||
<p v-for="message in messages" :key="message.id">
|
||||
<span class="text-tertiary">{{ message.authorId }}:</span>
|
||||
{{ message.text }}
|
||||
<template v-if="message.fileUrl">
|
||||
<img v-if="isImageUrl(message.fileUrl)" :src="message.fileUrl"
|
||||
class="max-w-xs max-h-48 rounded" />
|
||||
<a v-else :href="message.fileUrl" target="_blank"
|
||||
class="underline">{{ message.fileUrl.split('/').pop() }}</a>
|
||||
</template>
|
||||
</p>
|
||||
</div>
|
||||
<input v-model="messageInput" @keyup.enter="sendMessage" />
|
||||
<Button @click="sendMessage">Send</Button>
|
||||
<input ref="fileInput" type="file" class="hidden"
|
||||
@change="onFileSelected" />
|
||||
<div class="flex gap-2">
|
||||
<Button @click="sendMessage">Send</Button>
|
||||
<Button @click="fileInput.click()">Attach</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { ref, computed } from "vue";
|
||||
import axios from "axios";
|
||||
|
||||
function getWebSocketURL() {
|
||||
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
||||
@@ -59,6 +60,19 @@ export const useMessagesStore = defineStore("messages", () => {
|
||||
messages.value = [];
|
||||
}
|
||||
|
||||
async function uploadAndSendFile(file) {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
const res = await axios.post("/api/messages/upload", formData);
|
||||
const { url } = res.data;
|
||||
if (!socket.value || !isConnected.value) return;
|
||||
socket.value.send(JSON.stringify({ text: "", fileUrl: url }));
|
||||
} catch (err) {
|
||||
lastError.value = err;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
messages,
|
||||
isConnected,
|
||||
@@ -70,5 +84,6 @@ export const useMessagesStore = defineStore("messages", () => {
|
||||
disconnect,
|
||||
sendMessage,
|
||||
clearMessages,
|
||||
uploadAndSendFile,
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user