Fixed characters not showing after logging in, added loading screen before showing characters, worked on GM tools

This commit is contained in:
Dennis Postma 2024-06-10 02:39:00 +02:00
parent 2f7153fbfe
commit 3e003962dc
10 changed files with 85 additions and 26 deletions

View File

@ -0,0 +1 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_z9k8{transform-origin:center;animation:spinner_StKS .75s infinite linear}@keyframes spinner_StKS{100%{transform:rotate(360deg)}}</style><path d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z" opacity=".25"/><path d="M12,4a8,8,0,0,1,7.89,6.7A1.53,1.53,0,0,0,21.38,12h0a1.5,1.5,0,0,0,1.48-1.75,11,11,0,0,0-21.72,0A1.5,1.5,0,0,0,2.62,12h0a1.53,1.53,0,0,0,1.49-1.3A8,8,0,0,1,12,4Z" class="spinner_z9k8"/></svg>

After

Width:  |  Height:  |  Size: 537 B

View File

@ -0,0 +1 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>.spinner_qM83{animation:spinner_8HQG 1.05s infinite}.spinner_oXPr{animation-delay:.1s}.spinner_ZTLf{animation-delay:.2s}@keyframes spinner_8HQG{0%,57.14%{animation-timing-function:cubic-bezier(0.33,.66,.66,1);transform:translate(0)}28.57%{animation-timing-function:cubic-bezier(0.33,0,.66,.33);transform:translateY(-6px)}100%{transform:translate(0)}}</style><circle class="spinner_qM83" cx="4" cy="12" r="3"/><circle class="spinner_qM83 spinner_oXPr" cx="12" cy="12" r="3"/><circle class="spinner_qM83 spinner_ZTLf" cx="20" cy="12" r="3"/></svg>

After

Width:  |  Height:  |  Size: 635 B

View File

@ -18,13 +18,12 @@ import Game from '@/components/Game.vue'
const screen: Ref<string> = ref('login') const screen: Ref<string> = ref('login')
const socket = useSocketStore() const socket = useSocketStore()
socket.$subscribe( socket.$subscribe((mutation, state) => {
(mutation, state) => {
if (!state.connection) { if (!state.connection) {
screen.value = 'login' screen.value = 'login'
} }
if (state.connection) { if (state.token && state.connection) {
screen.value = 'characters' screen.value = 'characters'
if (state.character) { if (state.character) {

View File

@ -16,12 +16,12 @@ body {
} }
h1, h2, h3, h4, h5, h6, button, a { h1, h2, h3, h4, h5, h6, button, a {
font-family: "Poppins"; font-family: "Poppins", serif;
color: $white; color: $white;
} }
p, span, li, label { p, span, li, label {
font-family: "Inter"; font-family: "Inter", serif;
color: $white; color: $white;
} }
button, a { button, a {
@ -37,6 +37,10 @@ button, input {
button { button {
text-align: center; text-align: center;
&.w-full {
width: 100%;
}
&.btn-cyan { &.btn-cyan {
background-color: rgba($cyan, 0.5); background-color: rgba($cyan, 0.5);
border: 1px solid $white; border: 1px solid $white;

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="character-select-screen"> <div class="character-select-screen">
<div class="ui-wrapper"> <div class="ui-wrapper">
<div class="characters-wrapper"> <div class="characters-wrapper" v-if="!isLoading">
<div v-for="character in characters" :key="character.id" class="character" :class="{ active: selected_character == character.id }"> <div v-for="character in characters" :key="character.id" class="character" :class="{ active: selected_character == character.id }">
<input type="radio" :id="character.id" name="character" :value="character.id" v-model="selected_character" /> <input type="radio" :id="character.id" name="character" :value="character.id" v-model="selected_character" />
<label :for="character.id">{{ character.name }}</label> <label :for="character.id">{{ character.name }}</label>
@ -23,8 +23,13 @@
</button> </button>
</div> </div>
</div> </div>
<div v-else>
<div class="loading-spinner">
<img src="/assets/icons/loading-icon1.svg" />
</div>
</div>
<div class="button-wrapper"> <div class="button-wrapper" v-if="!isLoading">
<button class="btn-cyan" :disabled="!selected_character" @click="select_character()"> <button class="btn-cyan" :disabled="!selected_character" @click="select_character()">
PLAY PLAY
<img draggable="false" src="/assets/icons/arrow.svg"> <img draggable="false" src="/assets/icons/arrow.svg">
@ -55,18 +60,26 @@
<script setup lang="ts"> <script setup lang="ts">
import { useSocketStore } from '@/stores/socket' import { useSocketStore } from '@/stores/socket'
import { ref } from 'vue' import { onBeforeMount, onMounted, ref } from 'vue'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import {type Character as CharacterT} from '@/types' import {type Character as CharacterT} from '@/types'
const isLoading = ref(true)
const characters = ref([]) const characters = ref([])
const socket = useSocketStore() const socket = useSocketStore();
// Fetch characters // Fetch characters
socket.getConnection.on('character:list', (data: any) => { socket.getConnection.on('character:list', (data: any) => {
characters.value = data characters.value = data
}) })
socket.getConnection.emit('character:list')
onMounted(() => {
// wait 1.5 sec
setTimeout(() => {
socket.getConnection.emit('character:list')
isLoading.value = false
}, 1000)
});
// Select character logics // Select character logics
const selected_character = ref(null) const selected_character = ref(null)
@ -123,6 +136,14 @@ function create() {
content: ''; content: '';
} }
.loading-spinner img {
width: 5rem;
// css color
filter: invert(1);
// white
filter: invert(80%);
}
.characters-wrapper { .characters-wrapper {
display: flex; display: flex;
justify-content: center; justify-content: center;

View File

@ -32,6 +32,7 @@ import { login, register } from '@/services/authentication'
import { useNotificationStore } from '@/stores/notifications' import { useNotificationStore } from '@/stores/notifications'
import ZoneEditor from '@/components/utilities/zoneEditor/ZoneEditor.vue' import ZoneEditor from '@/components/utilities/zoneEditor/ZoneEditor.vue'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
import { useSocketStore } from '@/stores/socket'
const bgm = ref('bgm') const bgm = ref('bgm')
if (bgm.value.paused) { if (bgm.value.paused) {
@ -39,6 +40,7 @@ if (bgm.value.paused) {
window.addEventListener('keydown', () => bgm.value.play()) window.addEventListener('keydown', () => bgm.value.play())
} }
const socket = useSocketStore()
const notifications = useNotificationStore() const notifications = useNotificationStore()
const username = ref('') const username = ref('')
const password = ref('') const password = ref('')
@ -55,7 +57,11 @@ async function loginFunc() {
if (response.success === undefined) { if (response.success === undefined) {
notifications.addNotification({ message: response.error }) notifications.addNotification({ message: response.error })
return
} }
socket.setToken(response.token)
socket.initConnection();
} }
async function registerFunc() { async function registerFunc() {
@ -70,7 +76,11 @@ async function registerFunc() {
if (response.success === undefined) { if (response.success === undefined) {
notifications.addNotification({ message: response.error }) notifications.addNotification({ message: response.error })
return
} }
socket.setToken(response.token)
socket.initConnection();
} }
</script> </script>

View File

@ -45,9 +45,7 @@ const properties = defineProps({
} }
}) })
watch( watch(() => properties.isModalOpen, (value) => {
() => properties.isModalOpen,
(value) => {
isModalOpenRef.value = value isModalOpenRef.value = value
} }
) )
@ -124,6 +122,16 @@ const stopDrag = () => {
isDragging.value = false isDragging.value = false
} }
watch(() => properties.modalWidth, (value) => {
width.value = value
}
)
watch(() => properties.modalHeight, (value) => {
height.value = value
}
)
onMounted(() => { onMounted(() => {
addEventListener('mousemove', drag) addEventListener('mousemove', drag)
addEventListener('mouseup', stopDrag) addEventListener('mouseup', stopDrag)
@ -142,13 +150,11 @@ onUnmounted(() => {
// Make sure modal doesn't go off screen // Make sure modal doesn't go off screen
watch( watch(() => x.value, (value) => {
() => x.value, (value) => {
if (value < 0) { x.value = 0 } else if (value + width.value > window.innerWidth) { x.value = window.innerWidth - width.value } if (value < 0) { x.value = 0 } else if (value + width.value > window.innerWidth) { x.value = window.innerWidth - width.value }
} }
) )
watch( watch(() => y.value, (value) => {
() => y.value, (value) => {
if (value < 0) { y.value = 0 } else if (value + height.value > window.innerHeight) { y.value = window.innerHeight - height.value } if (value < 0) { y.value = 0 } else if (value + height.value > window.innerHeight) { y.value = window.innerHeight - height.value }
} }
) )

View File

@ -1,10 +1,15 @@
<template> <template>
<Modal :isModalOpen="true"> <Modal :isModalOpen="true" :closable="false" :modal-width="200" :modal-height="260">
<template #modalHeader> <template #modalHeader>
<h3 class="modal-title">GM tools</h3> <h3 class="modal-title">GM tools</h3>
</template> </template>
<template #modalBody> <template #modalBody>
<p></p> <div class="content">
<button class="btn-cyan w-full" type="button">Zone manager</button>
<button class="btn-cyan w-full" type="button">Player manager</button>
<button class="btn-cyan w-full" type="button">Item manager</button>
<button class="btn-cyan w-full" type="button">NPC manager</button>
</div>
</template> </template>
</Modal> </Modal>
</template> </template>
@ -12,3 +17,11 @@
import ZoneEditor from '@/components/utilities/zoneEditor/ZoneEditor.vue' import ZoneEditor from '@/components/utilities/zoneEditor/ZoneEditor.vue'
import Modal from '@/components/utilities/Modal.vue' import Modal from '@/components/utilities/Modal.vue'
</script> </script>
<style lang="scss">
.content {
display: flex;
flex-direction: column;
gap: 0.8rem;
}
</style>

View File

@ -7,8 +7,7 @@ export async function register(username: string, password: string, socketStore =
try { try {
const response = await axios.post(`${config.server_endpoint}/register`, { username, password }) const response = await axios.post(`${config.server_endpoint}/register`, { username, password })
useCookies().set('token', response.data.token as string) useCookies().set('token', response.data.token as string)
await socketStore.setupSocketConnection() return { success: true, token: response.data.token}
return { success: true }
} catch (error: any) { } catch (error: any) {
return { error: error.response.data.message } return { error: error.response.data.message }
} }
@ -18,8 +17,7 @@ export async function login(username: string, password: string, socketStore = us
try { try {
const response = await axios.post(`${config.server_endpoint}/login`, { username, password }) const response = await axios.post(`${config.server_endpoint}/login`, { username, password })
useCookies().set('token', response.data.token as string) useCookies().set('token', response.data.token as string)
await socketStore.setupSocketConnection() return { success: true, token: response.data.token}
return { success: true }
} catch (error: any) { } catch (error: any) {
return { error: error.response.data.message } return { error: error.response.data.message }
} }

View File

@ -6,17 +6,19 @@ import type { Character, User } from '@/types'
export const useSocketStore: StoreDefinition = defineStore('socket', { export const useSocketStore: StoreDefinition = defineStore('socket', {
state: () => ({ state: () => ({
token: '' as string | null,
connection: null as Socket | null, connection: null as Socket | null,
user: null as User | null, user: null as User | null,
character: null as Character | null character: null as Character | null
}), }),
getters: { getters: {
getToken: (state: any) => state.token as string,
getConnection: (state: any) => state.connection as Socket, getConnection: (state: any) => state.connection as Socket,
getUser: (state: any) => state.user as User, getUser: (state: any) => state.user as User,
getCharacter: (state: any) => state.character as Character getCharacter: (state: any) => state.character as Character
}, },
actions: { actions: {
setupSocketConnection() { initConnection() {
this.connection = io(config.server_endpoint, { this.connection = io(config.server_endpoint, {
withCredentials: true, withCredentials: true,
transports: ['websocket'], transports: ['websocket'],
@ -27,7 +29,7 @@ export const useSocketStore: StoreDefinition = defineStore('socket', {
this.connection.emit('login') this.connection.emit('login')
// set user // set user
this.connection.on('login', (user: User) => { this.connection.on('logged_in', (user: User) => {
this.setUser(user) this.setUser(user)
}) })
@ -43,11 +45,15 @@ export const useSocketStore: StoreDefinition = defineStore('socket', {
this.connection.disconnect() this.connection.disconnect()
this.connection = null this.connection = null
this.token = null
this.user = null this.user = null
this.character = null this.character = null
useCookies().remove('token') useCookies().remove('token')
}, },
setToken(token: string) {
this.token = token
},
setUser(user: User | null) { setUser(user: User | null) {
this.user = user this.user = user
}, },