Refactor/Project structure #67

Merged
KevinMidboe merged 56 commits from refactor/project-structure into master 2020-12-10 22:20:38 +00:00
2 changed files with 119 additions and 128 deletions
Showing only changes of commit ced7ebfcac - Show all commits

View File

@@ -40,22 +40,14 @@
<hr /> <hr />
<div class="middle-elements"> <div class="middle-elements">
<Attendees :attendees="attendees" class="outer-attendees" /> <Attendees :attendees="attendees" class="outer-attendees" />
<Chat <Chat class="outer-chat" />
class="outer-chat"
:chatHistory="chatHistory"
:historyPageSize="historyPageSize"
:usernameAllowed="usernameAllowed"
@loadMoreHistory="loadMoreHistory"
@message="sendMessage"
@username="setUsername"
/>
</div> </div>
<Vipps class="vipps" :amount="1" /> <Vipps class="vipps" :amount="1" />
</div> </div>
</template> </template>
<script> <script>
import { attendees, winners, getChatHistory, prelottery } from "@/api"; import { attendees, winners, prelottery } from "@/api";
import Chat from "@/ui/Chat"; import Chat from "@/ui/Chat";
import Vipps from "@/ui/Vipps"; import Vipps from "@/ui/Vipps";
import Attendees from "@/ui/Attendees"; import Attendees from "@/ui/Attendees";
@@ -74,21 +66,10 @@ export default {
socket: null, socket: null,
attendeesFetched: false, attendeesFetched: false,
winnersFetched: false, winnersFetched: false,
chatHistory: [],
historyPage: 0,
historyPageSize: 100,
lastHistoryPage: false,
usernameAccepted: false,
username: null,
wasDisconnected: false, wasDisconnected: false,
emitUsernameOnConnect: false,
ticketsBought: {} ticketsBought: {}
}; };
}, },
created() {
getChatHistory(0, this.historyPageSize)
.then(messages => this.chatHistory = messages);
},
mounted() { mounted() {
this.track(); this.track();
this.getAttendees(); this.getAttendees();
@@ -97,23 +78,10 @@ export default {
this.socket = io(`${BASE_URL}`); this.socket = io(`${BASE_URL}`);
this.socket.on("color_winner", msg => {}); this.socket.on("color_winner", msg => {});
this.socket.on("chat", msg => {
this.chatHistory.push(msg);
});
this.socket.on("disconnect", msg => { this.socket.on("disconnect", msg => {
this.wasDisconnected = true; this.wasDisconnected = true;
}); });
this.socket.on("connect", msg => {
if (
this.emitUsernameOnConnect ||
(this.wasDisconnected && this.username != null)
) {
this.setUsername(this.username);
}
});
this.socket.on("winner", async msg => { this.socket.on("winner", async msg => {
this.currentWinnerDrawn = true; this.currentWinnerDrawn = true;
this.currentWinner = { name: msg.name, color: msg.color }; this.currentWinner = { name: msg.name, color: msg.color };
@@ -132,14 +100,6 @@ export default {
this.socket.on("new_attendee", async msg => { this.socket.on("new_attendee", async msg => {
this.getAttendees(); this.getAttendees();
}); });
this.socket.on("accept_username", accepted => {
this.usernameAccepted = accepted;
if (!accepted) {
this.username = null;
} else {
window.localStorage.setItem("username", this.username);
}
});
}, },
beforeDestroy() { beforeDestroy() {
this.socket.disconnect(); this.socket.disconnect();
@@ -153,27 +113,6 @@ export default {
} }
}, },
methods: { methods: {
setUsername: function(username) {
this.username = username;
if (!this.socket || !this.socket.emit) {
this.emitUsernameOnConnect = true;
return;
}
this.socket.emit("username", { username });
},
sendMessage: function(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

@@ -2,23 +2,24 @@
<div class="chat-container"> <div class="chat-container">
<hr /> <hr />
<h2>Chat</h2> <h2>Chat</h2>
<div class="history" ref="history"> <div class="history" ref="history" v-if="chatHistory.length > 0">
<div class="opaque-skirt"></div> <div class="opaque-skirt"></div>
<div v-if="existsMore" class="fetch-older-history"> <div v-if="hasMorePages" class="fetch-older-history">
<button @click="$emit('loadMoreHistory')">Hent eldre meldinger</button> <button @click="loadMoreHistory">Hent eldre meldinger</button>
</div> </div>
<div class="history-message" <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}`"
> >
<div> <div>
<span class="user-name">{{ history.username }}</span> <span class="username">{{ history.username }}</span>
<span class="timestamp">{{ getTime(history.timestamp) }}</span> <span class="timestamp">{{ getTime(history.timestamp) }}</span>
</div> </div>
<span class="message">{{ history.message }}</span> <span class="message">{{ history.message }}</span>
</div> </div>
</div> </div>
<div v-if="usernameSet" class="input"> <div v-if="username" class="input">
<input @keyup.enter="sendMessage" type="text" v-model="message" placeholder="Melding.." /> <input @keyup.enter="sendMessage" type="text" v-model="message" placeholder="Melding.." />
<button @click="sendMessage">Send</button> <button @click="sendMessage">Send</button>
<button @click="removeUsername">Logg ut</button> <button @click="removeUsername">Logg ut</button>
@@ -37,63 +38,103 @@
</template> </template>
<script> <script>
import { getChatHistory } from "@/api";
import io from "socket.io-client";
export default { export default {
props: {
usernameAllowed: {
type: Boolean
},
chatHistory: {
type: Array
},
historyPageSize: {
type: Number
}
},
data() { data() {
return { return {
socket: null,
chatHistory: [],
hasMorePages: true,
message: "", message: "",
page: 1,
pageSize: 10,
temporaryUsername: null, temporaryUsername: null,
username: null, username: null
usernameSet: false,
existsMore: true
}; };
}, },
created() {
getChatHistory(1, this.pageSize)
.then(resp => {
this.chatHistory = resp.messages;
this.hasMorePages = resp.total != resp.messages.length;
});
const username = window.localStorage.getItem('username');
if (username) {
this.username = username;
this.emitUsernameOnConnect = true;
}
},
watch: { watch: {
chatHistory: { chatHistory: {
handler: function(newVal, oldVal) { handler: function(newVal, oldVal) {
if (this.$refs && this.$refs.history) { if (oldVal.length == 0) {
const firstMessages = oldVal.length == 0; this.scrollToBottomOfHistory();
const diffLargerThanOne = newVal.length - oldVal.length > 1; }
else if (newVal && newVal.length == oldVal.length) {
setTimeout(() => { if (this.isScrollPositionAtBottom()) {
if (firstMessages || diffLargerThanOne == false) { this.scrollToBottomOfHistory();
this.scrollToBottomOfHistory(); }
} else { } else {
this.scrollToStartOfNewMessages(); const prevOldestMessage = oldVal[0];
// what shows the load more button - if we scroll page and less than page size this.scrollToMessageElement(prevOldestMessage);
// come back we have reached a limit
this.existsMore = newVal.length - oldVal.length == this.historyPageSize
}
}, 100);
} }
}, },
deep: true deep: true
} }
}, },
mounted() { mounted() {
let username = window.localStorage.getItem("username"); const BASE_URL = __APIURL__ || window.location.origin;
if (username) { this.socket = io(`${BASE_URL}`);
this.username = username; this.socket.on("chat", msg => {
this.usernameSet = true; this.chatHistory.push(msg);
this.$emit("username", username); });
}
this.socket.on("disconnect", msg => {
this.wasDisconnected = true;
});
this.socket.on("connect", msg => {
if (
this.emitUsernameOnConnect ||
(this.wasDisconnected && this.username != null)
) {
this.setUsername(this.username);
}
});
this.socket.on("accept_username", msg => {
const { reason, success, username } = msg;
this.usernameAccepted = success;
if (success !== true) {
this.username = null;
alert(reason)
} else {
this.usernameAllowed = true;
this.username = username;
window.localStorage.setItem("username", username);
}
});
}, },
methods: { methods: {
pad: function(num) { loadMoreHistory() {
let { page, pageSize } = this;
page = page + 1;
getChatHistory(page, pageSize)
.then(resp => {
this.chatHistory = resp.messages.concat(this.chatHistory);
this.page = page;
this.hasMorePages = resp.total != this.chatHistory.length;
});
},
pad(num) {
if (num > 9) return num; if (num > 9) return num;
return `0${num}`; return `0${num}`;
}, },
getTime: function(timestamp) { getTime(timestamp) {
let date = new Date(timestamp); let date = new Date(timestamp);
const timeString = `${this.pad(date.getHours())}:${this.pad( const timeString = `${this.pad(date.getHours())}:${this.pad(
date.getMinutes() date.getMinutes()
@@ -104,40 +145,50 @@ export default {
} }
return `${date.toLocaleDateString()} ${timeString}`; return `${date.toLocaleDateString()} ${timeString}`;
}, },
sendMessage: function() { sendMessage() {
this.$emit("message", this.message); const message = { message: this.message };
this.message = ""; this.socket.emit("chat", message);
this.message = '';
this.scrollToBottomOfHistory();
}, },
removeUsername: function() { setUsername(username=undefined) {
if (this.temporaryUsername) {
username = this.temporaryUsername;
}
const message = { username: username };
this.socket.emit("username", message);
},
removeUsername() {
this.username = null; this.username = null;
this.temporaryUsername = null; this.temporaryUsername = null;
this.usernameSet = false;
window.localStorage.removeItem("username"); window.localStorage.removeItem("username");
this.$emit("username", null);
}, },
setUsername: function() { isScrollPositionAtBottom() {
if ( const { history } = this.$refs;
this.temporaryUsername.length > 3 && if (history) {
this.temporaryUsername.length < 30 return history.offsetHeight + history.scrollTop >= history.scrollHeight;
) {
this.username = this.temporaryUsername;
this.usernameSet = true;
this.$emit("username", this.username);
} }
return false
}, },
scrollToBottomOfHistory() { scrollToBottomOfHistory() {
if (this.$refs && this.$refs.history) { setTimeout(() => {
const { history } = this.$refs; const { history } = this.$refs;
history.scrollTop = history.scrollHeight; history.scrollTop = history.scrollHeight;
} }, 1);
}, },
scrollToStartOfNewMessages() { scrollToMessageElement(message) {
const { history } = this.$refs; const elemTimestamp = this.getTime(message.timestamp);
const histLength = history.children.length; const self = this;
const pages = Math.floor(histLength / 100); const getTimeStamp = (elem) => elem.getElementsByClassName('timestamp')[0].innerText;
const prevOldestMessageInNewList = (elem) => getTimeStamp(elem) == elemTimestamp;
const messageToScrollTo = history.children[histLength - ((pages * 100) + 3)] setTimeout(() => {
history.scrollTop = messageToScrollTo.offsetTop; const { history } = self.$refs;
const childrenElements = Array.from(history.getElementsByClassName('history-message'));
const elemInNewList = childrenElements.find(prevOldestMessageInNewList);
history.scrollTop = elemInNewList.offsetTop - 70
}, 1);
} }
} }
}; };
@@ -179,6 +230,7 @@ input {
.history { .history {
height: 75%; height: 75%;
overflow-y: scroll; overflow-y: scroll;
position: relative;
&-message { &-message {
display: flex; display: flex;
@@ -186,7 +238,7 @@ input {
margin: 0.35rem 0; margin: 0.35rem 0;
position: relative; position: relative;
.user-name { .username {
font-weight: bold; font-weight: bold;
font-size: 1.05rem; font-size: 1.05rem;
margin-right: 0.3rem; margin-right: 0.3rem;
@@ -217,7 +269,7 @@ input {
& .fetch-older-history { & .fetch-older-history {
display: flex; display: flex;
justify-content: center; justify-content: center;
margin: 0.2rem 0 0.5rem; margin: 1rem 0;
} }
@include mobile { @include mobile {