Merge pull request #17 from KevinMidboe/refactor/chat-history

Refactor/chat history
This commit is contained in:
2020-06-26 13:28:59 +02:00
committed by GitHub
4 changed files with 104 additions and 26 deletions

View File

@@ -11,9 +11,7 @@ import VirtualLotteryPage from "@/components/VirtualLotteryPage";
export default { export default {
components: { components: {
Tabs, Tabs
GeneratePage,
VirtualLotteryPage
}, },
data() { data() {
return { return {

View File

@@ -43,9 +43,11 @@
<Chat <Chat
class="outer-chat" class="outer-chat"
:chatHistory="chatHistory" :chatHistory="chatHistory"
:historyPageSize="historyPageSize"
:usernameAllowed="usernameAllowed" :usernameAllowed="usernameAllowed"
v-on:message="sendMessage" @loadMoreHistory="loadMoreHistory"
v-on:username="setUsername" @message="sendMessage"
@username="setUsername"
/> />
</div> </div>
<Vipps class="vipps" :amount="1" /> <Vipps class="vipps" :amount="1" />
@@ -74,6 +76,9 @@ export default {
attendeesFetched: false, attendeesFetched: false,
winnersFetched: false, winnersFetched: false,
chatHistory: [], chatHistory: [],
historyPage: 0,
historyPageSize: 100,
lastHistoryPage: false,
usernameAccepted: false, usernameAccepted: false,
username: null, username: null,
wasDisconnected: false, wasDisconnected: false,
@@ -158,6 +163,15 @@ export default {
sendMessage: function(msg) { sendMessage: function(msg) {
this.socket.emit("chat", { message: msg }); this.socket.emit("chat", { message: msg });
}, },
loadMoreHistory: function() {
const { historyPage, historyPageSize } = this;
const page = historyPage + 1;
getChatHistory(page * historyPageSize, historyPageSize).then(messages => {
this.chatHistory = messages.concat(this.chatHistory);
this.historyPage = page;
});
},
getWinners: async function() { getWinners: async function() {
let response = await winners(); let response = await winners();
if (response) { if (response) {

View File

@@ -3,12 +3,18 @@
<hr /> <hr />
<h2>Chat</h2> <h2>Chat</h2>
<div class="history" ref="history"> <div class="history" ref="history">
<div <div class="opaque-skirt"></div>
<div v-if="existsMore" class="fetch-older-history">
<button @click="$emit('loadMoreHistory')">Hent eldre meldinger</button>
</div>
<div class="history-message"
v-for="(history, index) in chatHistory" v-for="(history, index) in chatHistory"
:key="`${history.username}-${history.timestamp}-${index}`" :key="`${history.username}-${history.timestamp}-${index}`"
> >
<span class="timestamp">[{{ getTime(history.timestamp) }}]</span> <div>
<span class="user-name">{{ history.username }}:</span> <span class="user-name">{{ history.username }}</span>
<span class="timestamp">{{ getTime(history.timestamp) }}</span>
</div>
<span class="message">{{ history.message }}</span> <span class="message">{{ history.message }}</span>
</div> </div>
</div> </div>
@@ -38,6 +44,9 @@ export default {
}, },
chatHistory: { chatHistory: {
type: Array type: Array
},
historyPageSize: {
type: Number
} }
}, },
data() { data() {
@@ -45,16 +54,27 @@ export default {
message: "", message: "",
temporaryUsername: null, temporaryUsername: null,
username: null, username: null,
usernameSet: false usernameSet: false,
existsMore: true
}; };
}, },
watch: { watch: {
chatHistory: { chatHistory: {
handler() { handler: function(newVal, oldVal) {
if (this.$refs && this.$refs.history) { if (this.$refs && this.$refs.history) {
const firstMessages = oldVal.length == 0;
const diffLargerThanOne = newVal.length - oldVal.length > 1;
setTimeout(() => { setTimeout(() => {
this.$refs.history.scrollTop = this.$refs.history.scrollHeight; if (firstMessages || diffLargerThanOne == false) {
}, 10); this.scrollToBottomOfHistory();
} else {
this.scrollToStartOfNewMessages();
// what shows the load more button - if we scroll page and less than page size
// come back we have reached a limit
this.existsMore = newVal.length - oldVal.length == this.historyPageSize
}
}, 100);
} }
}, },
deep: true deep: true
@@ -62,12 +82,11 @@ export default {
}, },
mounted() { mounted() {
let username = window.localStorage.getItem("username"); let username = window.localStorage.getItem("username");
if (!username) { if (username) {
return; this.username = username;
this.usernameSet = true;
this.$emit("username", username);
} }
this.username = username;
this.usernameSet = true;
this.$emit("username", username);
}, },
methods: { methods: {
pad: function(num) { pad: function(num) {
@@ -105,6 +124,20 @@ export default {
this.usernameSet = true; this.usernameSet = true;
this.$emit("username", this.username); this.$emit("username", this.username);
} }
},
scrollToBottomOfHistory() {
if (this.$refs && this.$refs.history) {
const { history } = this.$refs;
history.scrollTop = history.scrollHeight;
}
},
scrollToStartOfNewMessages() {
const { history } = this.$refs;
const histLength = history.children.length;
const pages = Math.floor(histLength / 100);
const messageToScrollTo = history.children[histLength - ((pages * 100) + 3)]
history.scrollTop = messageToScrollTo.offsetTop;
} }
} }
}; };
@@ -127,6 +160,7 @@ hr {
.chat-container { .chat-container {
height: 100%; height: 100%;
width: 50%; width: 50%;
position: relative;
@include mobile { @include mobile {
width: 100%; width: 100%;
@@ -146,6 +180,46 @@ input {
height: 75%; height: 75%;
overflow-y: scroll; overflow-y: scroll;
&-message {
display: flex;
flex-direction: column;
margin: 0.35rem 0;
position: relative;
.user-name {
font-weight: bold;
font-size: 1.05rem;
margin-right: 0.3rem;
}
.timestamp {
font-size: 0.9rem;
top: 2px;
position: absolute;
}
}
&-message:nth-of-type(2) {
margin-top: 1rem;
}
& .opaque-skirt {
width: 100%;
position: absolute;
height: 1rem;
z-index: 1;
background: linear-gradient(
to bottom,
white,
rgba(255, 255, 255, 0)
);
}
& .fetch-older-history {
display: flex;
justify-content: center;
margin: 0.2rem 0 0.5rem;
}
@include mobile { @include mobile {
height: 300px; height: 300px;
} }

View File

@@ -10,12 +10,7 @@
>{{ tab.name }}</div> >{{ tab.name }}</div>
</div> </div>
<div class="tab-elements"> <div class="tab-elements">
<component <component :is="tabs[chosenTab].component" />
v-for="(tab, index) in tabs"
:key="index"
:is="tab.component"
:class="chosenTab == index ? null : 'hide'"
/>
</div> </div>
</div> </div>
</template> </template>
@@ -54,9 +49,6 @@ export default {
h1 { h1 {
text-align: center; text-align: center;
} }
.hide {
display: none;
}
.tab-container { .tab-container {
display: flex; display: flex;