From f36eeb0602b27cc828795394b1aa6696fc7f4567 Mon Sep 17 00:00:00 2001
From: saschrad <saschrad@stud.ntnu.no>
Date: Tue, 3 May 2022 15:50:24 +0200
Subject: [PATCH] Rewritten the whole chat

---
 .../ChatComponents/ChatComponent.vue          | 229 ++++++++++++++++++
 src/components/ChatComponents/ChatMessage.vue |  32 ++-
 src/components/ChatComponents/ChatProfile.vue |   7 +-
 .../ChatComponents/ChatsComponent.vue         | 181 ++++++++++++++
 src/views/TestView.vue                        |   7 +-
 5 files changed, 445 insertions(+), 11 deletions(-)
 create mode 100644 src/components/ChatComponents/ChatComponent.vue
 create mode 100644 src/components/ChatComponents/ChatsComponent.vue

diff --git a/src/components/ChatComponents/ChatComponent.vue b/src/components/ChatComponents/ChatComponent.vue
new file mode 100644
index 0000000..9e89948
--- /dev/null
+++ b/src/components/ChatComponents/ChatComponent.vue
@@ -0,0 +1,229 @@
+<template>
+  <div class="chat-container">
+    <div class="header">
+      <div
+        v-on:click="openHamburgerMethod"
+        class="hamburger grid space-y-2 content-center m-3"
+      >
+        <div class="w-8 h-0.5 bg-gray-600"></div>
+        <div class="w-8 h-0.5 bg-gray-600"></div>
+        <div class="w-8 h-0.5 bg-gray-600"></div>
+      </div>
+      <div class="flex">
+        <img class="pfp" :src="this.src" alt="Profile Picture" />
+        <h1>{{ name }}</h1>
+      </div>
+      <div></div>
+    </div>
+    <div class="conversation">
+      <ChatMessage
+        v-for="(message, i) in messages"
+        v-bind:key="i"
+        :message="message"
+      ></ChatMessage>
+    </div>
+    <div
+      class="
+        flex
+        items-center
+        justify-between
+        w-full
+        p-3
+        border-t border-gray-300
+      "
+    >
+      <input
+        v-on:keyup.enter="sendMessage"
+        type="text"
+        placeholder="Message"
+        class="
+          block
+          w-full
+          py-2
+          pl-4
+          mx-3
+          bg-gray-100
+          rounded-full
+          outline-none
+          focus:text-gray-700
+        "
+        name="message"
+        v-model="message"
+      />
+      <button v-on:click="sendMessage" style="padding: 10px; color: red">
+        <svg
+          class="w-5 h-5 text-gray-500 origin-center transform rotate-90"
+          xmlns="http://www.w3.org/2000/svg"
+          viewBox="0 0 20 20"
+          fill="currentColor"
+        >
+          <path
+            d="M10.894 2.553a1 1 0 00-1.788 0l-7 14a1 1 0 001.169 1.409l5-1.429A1 1 0 009 15.571V11a1 1 0 112 0v4.571a1 1 0 00.725.962l5 1.428a1 1 0 001.17-1.408l-7-14z"
+          />
+        </svg>
+      </button>
+    </div>
+  </div>
+</template>
+
+<script>
+import ChatMessage from "./ChatMessage.vue";
+import axios from "axios";
+import ws from "@/services/ws";
+export default {
+  props: {
+    openHamburger: { type: Function },
+    recipientID: {
+      type: Number,
+    },
+  },
+  data() {
+    return {
+      src: "https://pbs.twimg.com/media/FEaFK4OWUAAlgiV?format=jpg&name=900x900",
+      messages: [],
+      canScroll: true,
+      scrollBehavior: "",
+      recipient: null,
+    };
+  },
+  components: {
+    ChatMessage,
+  },
+  computed: {
+    name() {
+      console.log(this.recipient);
+      return this.recipient
+        ? this.recipient.firstName + " " + this.recipient.lastName
+        : "N/A";
+    },
+  },
+  methods: {
+    openHamburgerMethod() {
+      this.$emit("openHamburger");
+    },
+    scroll() {
+      let container = this.$el.querySelector(".conversation");
+      container.scrollTop = container.scrollHeight;
+    },
+    async sendMessage() {
+      if (this.message == null || this.message == "") return;
+      this.canScroll = true;
+      const token = this.$store.state.user.token;
+      await axios.post(
+        process.env.VUE_APP_BASEURL +
+          `chats/users/${this.recipientID}/messages`,
+        {
+          message: this.message,
+        },
+        {
+          headers: {
+            Authorization: `Bearer ${token}`,
+          },
+        }
+      );
+      this.message = "";
+      ws.sendMessage({
+        sender: parseInt(this.userid),
+        recipient: this.recipientID,
+      });
+      this.reloadMessages();
+    },
+    async reloadMessages() {
+      const token = this.$store.state.user.token;
+      const response = await fetch(
+        `${process.env.VUE_APP_BASEURL}chats/users/${this.recipientID}/messages`,
+        {
+          method: "GET",
+          headers: {
+            "Content-Type": "application/json",
+            Authorization: `Bearer ${token}`,
+          },
+        }
+      );
+      this.messages = await response.json();
+    },
+    async getRecipient() {
+      const token = this.$store.state.user.token;
+      const response = await fetch(
+        `${process.env.VUE_APP_BASEURL}users/${this.recipientID}/profile`,
+        {
+          method: "GET",
+          headers: {
+            "Content-Type": "application/json",
+            Authorization: `Bearer ${token}`,
+          },
+        }
+      );
+
+      this.recipient = await response.json();
+    },
+  },
+  watch: {
+    async recipientID() {
+      await this.reloadMessages();
+      await this.getRecipient();
+    },
+  },
+  async created() {
+    await this.reloadMessages();
+    await this.getRecipient();
+  },
+  updated() {
+    if (this.canScroll) this.scroll();
+    this.canScroll = false;
+    this.scrollBehavior = "smooth";
+  },
+};
+</script>
+
+<style scoped>
+.hamburger {
+  display: none;
+}
+
+.chat-container {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+  width: auto;
+}
+
+.conversation {
+  height: 100%;
+  width: 100%;
+  padding: 1.25rem;
+  overflow-y: scroll;
+  scroll-behavior: v-bind(scrollBehavior);
+}
+
+.header {
+  display: flex;
+  flex-direction: row;
+  padding: 0.75rem;
+  border-bottom: 1px solid black;
+}
+
+.header h1 {
+  align-self: center;
+  margin-left: 10px;
+  color: #4b5563;
+  font-weight: bold;
+}
+
+.pfp {
+  object-fit: cover;
+  width: 2.5rem;
+  height: 2.5rem;
+  border-radius: 50%;
+}
+
+@media screen and (max-width: 600px) {
+  .header {
+    justify-content: space-between;
+  }
+
+  .hamburger {
+    display: block;
+  }
+}
+</style>
\ No newline at end of file
diff --git a/src/components/ChatComponents/ChatMessage.vue b/src/components/ChatComponents/ChatMessage.vue
index d699677..c0a900f 100644
--- a/src/components/ChatComponents/ChatMessage.vue
+++ b/src/components/ChatComponents/ChatMessage.vue
@@ -1,22 +1,40 @@
 <template>
-  <div v-bind:class="'w-full break-words flex ' + side()">
+  <div v-bind:class="'blob-container ' + this.side()">
     <div
-      style="max-width: 70%"
       v-bind:class="
-        this.color() + ' rounded px-5 py-2 my-2 relative ' + this.textColor()
+        this.color() + ' message-container ' +this.textColor()
       "
     >
-      <span class="block"
-        >{{ this.message.content }} {{ this.message.from }}</span
+      <span class="message"
+        >{{ this.message.content }}</span
       >
-      <span class="block text-xs text-right">{{ this.calculateTime() }}</span>
+      <span class="">{{ this.calculateTime() }}</span>
     </div>
   </div>
 </template>
 
+<style scoped>
+  .blob-container {
+    display: flex;
+    max-width: 100%;
+  }
+
+  .message {
+    word-break: break-word;
+    display: block;
+  }
+
+  .message-container {
+    border-radius: 10px;
+    max-width: 70%;
+    padding: 0.75rem;
+    margin-top: 0.25rem;
+    margin-bottom: 0.25rem; 
+  }
+</style>
 <script>
 import { parseCurrentUser } from "@/utils/token-utils";
-
+//block text-xs text-right
 export default {
   props: {
     message: Object,
diff --git a/src/components/ChatComponents/ChatProfile.vue b/src/components/ChatComponents/ChatProfile.vue
index 7e1e9aa..8d5c5bf 100644
--- a/src/components/ChatComponents/ChatProfile.vue
+++ b/src/components/ChatComponents/ChatProfile.vue
@@ -52,9 +52,12 @@ export default {
   },
   methods: {
     selectUser() {
-      console.log(this.conversation.recipient.userId);
-      this.$emit("recipient", this.conversation.recipient.userId);
+      console.log(this.conversation?.recipient.userId);
+      this.$emit("recipient", this.conversation?.recipient.userId);
     },
   },
+  created() {
+    console.log("convesation", this.conversation);
+  }
 };
 </script>
diff --git a/src/components/ChatComponents/ChatsComponent.vue b/src/components/ChatComponents/ChatsComponent.vue
new file mode 100644
index 0000000..936b95c
--- /dev/null
+++ b/src/components/ChatComponents/ChatsComponent.vue
@@ -0,0 +1,181 @@
+<template>
+    <div class="chat">
+      <div class="conversations">
+        <h1 >Samtaler:</h1>
+        <hr/>
+        <ChatProfile
+          v-for="(conversation, i) in conversations"
+          :conversation="conversation"
+          :key="i"
+          @recipient="selectUser"
+        ></ChatProfile>
+        <div class="button">
+          <colored-button text="Ny Samtale"></colored-button>
+        </div>
+      </div>
+      <div class="current-chat">
+        <ChatComponent @openHamburger="openHamburger" v-if="recipient" :recipientID="recipient"></ChatComponent>
+        <div v-else><p>NOTHING HERE :)</p></div>
+      </div>
+    </div>
+</template>
+
+<script>
+import ChatProfile from './ChatProfile.vue';
+import ChatComponent from './ChatComponent.vue';
+//import ChatMessage from "./ChatMessage.vue";
+import axios from "axios";
+import { parseCurrentUser } from "@/utils/token-utils";
+import ws from "@/services/ws";
+import ColoredButton from '../BaseComponents/ColoredButton.vue';
+
+export default {
+  props: {
+
+  },
+  data: () => {
+    return {
+      messages: [],
+      message: "",
+      recipient: null,
+      hambuger: "none",
+      conversations: [
+
+      ],
+      hambugerDisplay: "none"
+    };
+  },
+  components: { ChatProfile, ChatComponent, ColoredButton},
+  computed: {
+    userid() {
+      return parseCurrentUser().accountId;
+    },
+    recipientID() {
+      return this.recipient.userId;
+    },
+    name() {
+      return this.recipient.firstName + " " + this.recipient.lastName;
+    },
+  },
+  methods: {
+    selectUser(recipientID) {
+      this.hambugerDisplay = "none"
+      this.recipient = this.conversations.find(
+        (conversation) => conversation.recipient.userId == recipientID
+      )?.recipient.userId;
+
+      console.log("New recipient", this.recipient)
+    },
+    openHamburger() {
+      this.hambugerDisplay = "block"
+    },
+    calculateSide(from) {
+      return from == this.userid ? "end" : "start";
+    },
+    async sendMessage() {
+      const token = this.$store.state.user.token;
+      await axios.post(
+        process.env.VUE_APP_BASEURL +
+          `chats/users/${this.recipientID}/messages`,
+        {
+          message: this.message,
+        },
+        {
+          headers: {
+            Authorization: `Bearer ${token}`,
+          },
+        }
+      );
+      this.message = "";
+      ws.sendMessage({
+        sender: parseInt(this.userid),
+        recipient: this.recipientID,
+      });
+      this.reloadMessages();
+    },
+    async reloadMessages() {
+      const token = this.$store.state.user.token;
+      const response = await fetch(
+        `${process.env.VUE_APP_BASEURL}chats/users/${this.recipientID}/messages`,
+        {
+          method: "GET",
+          headers: {
+            "Content-Type": "application/json",
+            Authorization: `Bearer ${token}`,
+          },
+        }
+      );
+
+      this.messages = await response.json();
+    },
+  },
+  async created() {
+    const token = this.$store.state.user.token;
+
+    // Get all conversations from api with /chats/users
+    const conResponse = await fetch(`${process.env.VUE_APP_BASEURL}chats/users`, {
+      method: "GET",
+      headers: {
+        "Content-Type": "application/json",
+        Authorization: `Bearer ${token}`,
+      },
+    }); // add error handling
+    this.conversations = await conResponse.json();
+  
+    ws.on("NEW_MESSAGE", () => {
+      this.reloadMessages();
+    });
+  },
+};
+</script>
+<style scoped>
+  .chat {
+    display: flex;
+    flex-direction: row;
+    width: 100%;
+    height: min(100vh - 3.5rem);
+  }
+
+  .current-chat {
+    width: 100%;
+    height: 100%;
+  }
+
+  .conversations {
+    min-width: 300px;
+    border-right-width: 1px;
+    border-color: black;
+    height: 100%;
+  }
+
+  .conversations h1 {
+    padding: 0.5rem;  
+    padding-left: 0;
+  align-self: center;
+  margin-left: 10px;
+  color: #4b5563;
+  font-weight: bold;
+  font-size: large;
+}
+
+  @media screen and (max-width: 600px) {
+    .conversations {
+          display: v-bind(hambugerDisplay);
+          z-index: 99;
+          width: 100%;
+          position: absolute;
+          background-color: white;
+    }
+
+    .conversations h1 {
+      text-align: center;
+    }
+    
+  }
+
+  .button {
+    display: flex;
+    justify-content: center;
+    padding: 0.75rem;
+  }
+</style>
\ No newline at end of file
diff --git a/src/views/TestView.vue b/src/views/TestView.vue
index 7537e2d..60d0d1c 100644
--- a/src/views/TestView.vue
+++ b/src/views/TestView.vue
@@ -1,15 +1,18 @@
 <template>
-  <div />
+  <chats-component></chats-component>
 </template>
 
 <script>
+import ChatsComponent from '@/components/ChatComponents/ChatsComponent.vue';
 export default {
+  components: {
+    ChatsComponent,
+  },
   data() {
     return {
       show: false,
     };
   },
-  components: {},
   methods: {
     toggleModal() {
       this.show = !this.show;
-- 
GitLab