User is now able to start a new dm chat with another user, optimized message loading

This commit is contained in:
joschuatonn
2024-06-16 18:03:33 +02:00
parent fee2fb4bdd
commit e239e69ff7
3 changed files with 122 additions and 50 deletions

View File

@@ -5,6 +5,7 @@ export interface ptpUser {
username: string;
status: string;
profilepicture: string;
isPrivate: boolean;
}
export interface responseModel {
@@ -20,6 +21,7 @@ export interface chat{
displayName: string;
profilepicture: string;
profilepictureAsString: string;
isGroupChat: boolean;
}
export interface message {

View File

@@ -53,6 +53,7 @@
:selected="chat.id == selectedChat.id"
:chat="chat"
@click="selectChat(chat as chat)"
:lastMessage="getChatPreviewMessage(chat.id)"
></ChatCardComponent>
<ProfileCardComponent
@@ -61,11 +62,16 @@
:selected="chat.id == selectedChat.id"
@click="selectChat(chat as chat)"
slim
:lastMessage="getChatPreviewMessage(chat.id)"
></ProfileCardComponent>
<p v-else>
<span v-for="member in chat.members">{{ member.id }}<br></span>
</p>
<ChatCardComponent
v-else
:selected="chat.id == selectedChat.id"
:chat="chat"
@click="selectChat(chat as chat)"
:lastMessage="getChatPreviewMessage(chat.id)"
></ChatCardComponent>
</div>
</div>
</div>
@@ -92,7 +98,7 @@
:image="selectedChat.members.find((member) => member.id !== userStore.user!.id)?.profilepicture"
></HeaderInfoContainerComponent>
<div v-else-if="selectedChat.members.length > 2" style="display: flex;">
<div v-else style="display: flex;">
<HeaderInfoContainerComponent
:displayName="selectedChat.displayName"
:image="selectedChat.profilepictureAsString"
@@ -100,7 +106,8 @@
<div>
<p style="overflow: hidden;white-space: nowrap;text-overflow: ellipsis;line-height: 14px;height:50px;margin: 0px;display: table-cell;vertical-align: middle;padding: 10px;max-width: 300px;">
<span>Du, </span>
<span>Du</span>
<span v-if="selectedChat.members.length > 1">, </span>
<span v-for="(user, index) in selectedChat.members.filter(u => u.id != userStore.user!.id)">@{{ user.username }}{{ index < selectedChat.members.length - 2 ? ", " : "" }} </span>
</p>
</div>
@@ -113,37 +120,13 @@
</div>
<div v-if="selectedUser.id != null" id="messageContainer" style="padding: 25px;overflow-y: auto;height: 100%;display: flex;flex-direction: column-reverse;">
<div v-if="selectedUser.id != null && selectedChat.members.length == 2" id="messageContainer" style="padding: 25px;overflow-y: auto;height: 100%;display: flex;flex-direction: column-reverse;">
<div v-if="!hasChatWith(selectedUser.id)" style="width: 100%; text-align: center;font-size: 1.2rem;">
<p>Das ist der Beginn deines Chats mit <strong>{{selectedUser.firstName}} {{selectedUser.lastName}}</strong></p>
</div>
<div v-else>
<p>Du hast schonmal mit dem geschrieben wie schön</p>
<div v-for="(message, index) in (messageStore.messages[selectedChat.id])" :key="index">
<MessageComponent
v-if="message.gif"
:url="message.content"
:timestamp="message.timestamp"
:own-message="message.isOwn"
gif
></MessageComponent>
<MessageComponent
v-if="!message.gif && message.link"
:url="message.content"
:timestamp="message.timestamp"
:own-message="message.isOwn"
link
></MessageComponent>
<MessageComponent
v-if="!message.gif && !message.link"
:message="message.content"
:timestamp="message.timestamp"
:own-message="message.isOwn"
></MessageComponent>
</div>
</div>
</div>
@@ -173,7 +156,7 @@
<div class="footer">
<q-input filled v-model="message" placeholder="Nachricht eingeben" tabindex="0" @keyup.enter.prevent="sendMessage">
<q-input filled v-model="message" placeholder="Nachricht eingeben" tabindex="0" @keyup.enter.prevent="sendMessage" :disable="!selectedChat.id">
<template v-slot:after>
<q-btn round dense flat icon="gif_box" id="sendMessageBtn" style="font-size: 1.2rem;" @click="toggleGifMenu"></q-btn>
</template>
@@ -219,7 +202,7 @@
import ProfileCardComponent from 'components/ProfileCardComponent.vue';
import ChatCardComponent from 'components/ChatCardComponent.vue';
import HeaderInfoContainerComponent from 'components/HeaderInfoContainerComponent.vue';
import {message} from 'src/models';
import type {message} from 'src/models';
import type {chat, ptpUser} from 'src/models';
import {useUserStore} from 'stores/user-store';
import { useChatStore } from 'stores/chat-store';
@@ -257,6 +240,31 @@ import { useMessageStore } from 'src/stores/message-store';
let messages : message[] = [
];
const getChatPreviewMessage = (chatId : number) => {
const messageArray : message[] = messageStore.messages[chatId];
if(messageArray && messageArray.length > 0) {
const newestMessage = messageArray[0];
let messageContent = newestMessage.content;
let userDescriptor = newestMessage.sender.firstName;
if(isTenorGifUrl(newestMessage.content)) {
messageContent = "GIF";
}
if(newestMessage.sender.id == userStore.user!.id) {
userDescriptor = "Du";
}
return userDescriptor + ": " + messageContent;
} else {
return "Der Chat wurde erstellt";
}
}
function isUrl(url : string) {
try {
new URL(url);
@@ -292,7 +300,7 @@ import { useMessageStore } from 'src/stores/message-store';
function getGifs() {
let query = gifSearch.value != "" ? gifSearch.value : "shrek";
let query = gifSearch.value != "" ? gifSearch.value : "the office";
if(changed.value) {
tenorStore.getGifsBySearchTerm(query, loadedGifsAmount);
@@ -309,7 +317,16 @@ import { useMessageStore } from 'src/stores/message-store';
}
function sendMessage() {
messageStore.sendMessage(selectedChat.value.id, userStore.user!.id, message.value);
if(selectedChat.value.id != -1) {
messageStore.sendMessage(selectedChat.value.id, userStore.user!.id, message.value);
} else {
messageStore.createChatAndSendFirstMessage(selectedUser.value.id,userStore.user!.id, message.value).then((response) => {
reloadChats().then(() => {
activeMenu.value = 'chats';
selectChat(chatStore.chats.find((chat) => chat.id == response)!);
});
});
}
message.value = "";
}
@@ -325,13 +342,17 @@ import { useMessageStore } from 'src/stores/message-store';
}
function getMessages() {
if(selectedChat.value.id != null) {
messageStore.loadMessagesByChatID(selectedChat.value.id);
for(let chat of chatStore.chats) {
messageStore.loadMessagesByChatID(chat.id);
}
}
setInterval(getMessages, 2000);
const reloadChats = async() => {
await chatStore.loadChatsByUser();
};
setInterval(getMessages, 5000);
setInterval(getGifs, 500);
@@ -347,7 +368,18 @@ import { useMessageStore } from 'src/stores/message-store';
function selectUser(user : ptpUser) {
selectedUser.value = user;
selectedChat.value = {} as chat;
//selectedChat.value = {} as chat;
// CHECKEN, OB ES SCHON EINEN CHAT GIBT
const exampleChat: chat = {
id: -1,
members: [user, userStore.user!],
messages: [],
displayName: user.firstName + " " + user.lastName,
profilepicture: user.profilepicture,
profilepictureAsString: user.profilepicture,
isGroupChat: false
};
selectedChat.value = exampleChat;
}
function selectChat(chat : chat) {
@@ -365,22 +397,19 @@ import { useMessageStore } from 'src/stores/message-store';
// Hier wird geprüft, ob es ein Chat mit einem bestimmten anderen Nutzer existiert
const chatExists = chatStore.chats.find((chat) => chat.members.length === 2 && chat.members.find((member) => member.id === id));
if(chatExists) return true;
return false;
return Boolean(chatExists);
}
// Init methods
loadChats();
const user = ref();
onMounted(() => {
//alert("mounted");
user.value = userStore.user;
//alert(user.value.firstName);
})
</script>

View File

@@ -2,11 +2,14 @@ import { defineStore } from 'pinia';
import { api } from 'src/boot/axios';
import { message, ptpUser, responseModel } from 'src/models';
import Keycloak, { KeycloakInitOptions, KeycloakLoginOptions } from 'keycloak-js';
import { useNotificationStore } from './notification-store';
import { useUserStore } from './user-store';
export const useMessageStore = defineStore('messageStore', {
state: () => ({
messages: [[]] as [message[]],
loadedMessagesForChats: [] as number[],
}),
actions: {
async sendMessage(chatId : number, senderId : string, content : string) {
@@ -16,9 +19,28 @@ export const useMessageStore = defineStore('messageStore', {
});
},
async createChatAndSendFirstMessage(receiverId : string, senderId : string, content : string) {
const config = { headers: {'Content-Type': 'application/json'} };
return (await api.post("/messages/dm/"+senderId+"/"+receiverId, content, config).then((response) => {
console.info("LET ME IN");
console.info(response.data);
console.info(response.data.id);
this.loadMessagesByChatID(response.data.id);
return response.data.id;
}));
},
loadMessagesByChatID(chatID : number) {
this.getAllMessagesByChatID(chatID).then((messages) => {
messages.forEach((message : message) => {
const notificationStore = useNotificationStore();
const userStore = useUserStore();
const messagesTemp : message[] = [];
const initialLoad = !this.loadedMessagesForChats.includes(chatID);
this.getAllMessagesByChatID(chatID).then((responseBody) => {
responseBody.response.forEach((message : message) => {
message.content = message.content.substring(1, message.content.length-1);
if (isUrl(message.content)) {
if (isTenorGifUrl(message.content)) {
@@ -27,14 +49,33 @@ export const useMessageStore = defineStore('messageStore', {
message.link = true;
}
}
});
this.messages[chatID] = messages;
if(!this.loadedMessagesForChats.includes(chatID)){
this.messages[chatID] = [];
this.loadedMessagesForChats.push(chatID);
}
if(!initialLoad){
if(message.sender.id !== userStore.user!.id) {
notificationStore.sendNotificationIfAllowed(message.sender.profilepicture, message.sender.username, message.content);
}
}
this.messages[chatID].unshift(message);
});
});
},
async getAllMessagesByChatID(chatID : number) {
return (await api.get("/messages/"+chatID)).data;
//const timestamp = !this.messages[chatID] ? 0 : this.messages[chatID][0].timestamp;
let timestamp = "0";
if(this.loadedMessagesForChats.includes(chatID)){
timestamp = this.messages[chatID][0].timestamp;
}
//console.log("Timestamp: "+timestamp);
return (await api.get("/messages/"+chatID+"/"+timestamp)).data;
},
},
});