added errors and loading states to friends page

This commit is contained in:
2026-01-22 09:48:54 +01:00
parent 6c66b1cd7d
commit b0676d3834
4 changed files with 148 additions and 90 deletions

View File

@@ -335,7 +335,7 @@ async function onSend(content: string) {
color: var(--muted); color: var(--muted);
font-size: 1.1rem; font-size: 1.1rem;
z-index: 10; z-index: 10;
pointer-events: none; /* pointer-events: none; */
text-align: center; text-align: center;
} }
@@ -424,7 +424,7 @@ async function onSend(content: string) {
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
z-index: 10; z-index: 10;
pointer-events: none; /* pointer-events: none; */
text-align: center; text-align: center;
width: 100%; width: 100%;
} }

View File

@@ -67,6 +67,8 @@ friends-add-title = Add Friend
friends-send-request = Send Request friends-send-request = Send Request
friends-list-header = Your Friends friends-list-header = Your Friends
friends-error-required = Username is required. friends-error-required = Username is required.
friends-connectiong = Loading friends...
friends-list-empty = No friends found
## Notifications page ## Notifications page
notifications-title = Notifications notifications-title = Notifications
@@ -82,6 +84,8 @@ notifications-error-friend-accept = An error occurred while accepting the reques
notifications-error-friend-decline = An error occurred while declining the request. notifications-error-friend-decline = An error occurred while declining the request.
notifications-error-room-accept = An error occurred while accepting the invite. notifications-error-room-accept = An error occurred while accepting the invite.
notifications-error-room-decline = An error occurred while declining the invite. notifications-error-room-decline = An error occurred while declining the invite.
notifications-connectiong = Loading notifications...
notifications-empty = No notifications found
## Settings page ## Settings page
settings-loading = Loading settings... settings-loading = Loading settings...

View File

@@ -67,6 +67,8 @@ friends-add-title = Ajouter un ami
friends-send-request = Envoyer friends-send-request = Envoyer
friends-list-header = Vos Amis friends-list-header = Vos Amis
friends-error-required = Le nom d'utilisateur est requis. friends-error-required = Le nom d'utilisateur est requis.
friends-connectiong = Chargement des amis...
friends-list-empty = Pas d'amis trouvés
## Notifications page ## Notifications page
notifications-title = Notifications notifications-title = Notifications
@@ -82,6 +84,8 @@ notifications-error-friend-accept = Erreur lors de l'acceptation de la demande.
notifications-error-friend-decline = Erreur lors du refus de la demande. notifications-error-friend-decline = Erreur lors du refus de la demande.
notifications-error-room-accept = Erreur lors de l'acceptation de l'invitation. notifications-error-room-accept = Erreur lors de l'acceptation de l'invitation.
notifications-error-room-decline = Erreur lors du refus de l'invitation. notifications-error-room-decline = Erreur lors du refus de l'invitation.
notifications-connectiong = Chargement des notifications...
notifications-empty = Pas de notifications trouvées
## Settings page ## Settings page
settings-loading = Chargement des paramètres... settings-loading = Chargement des paramètres...

View File

@@ -15,7 +15,22 @@
<div class="friends-list"> <div class="friends-list">
<h2>{{ $t('friends-list-header') }}</h2> <h2>{{ $t('friends-list-header') }}</h2>
<div class="friends">
<!-- Loading State -->
<div class="wait-container" v-if="isLoading">
<p class="wait-msg">{{ $t('friends-connecting') }}</p>
</div>
<!-- Empty / Error / Retry State -->
<div class="wait-container" v-else-if="!friends || friends.length === 0">
<p class="wait-msg">{{ $t('friends-list-empty') || 'No friends yet' }}</p>
<button class="retry-btn" @click="loadFriends()">
<i class="fa-solid fa-rotate-right"></i>
</button>
</div>
<!-- Content State -->
<div class="friends" v-else>
<button class="friend" v-for="friend in friends" :key="friend.uuid" @click="openProfile(friend)"> <button class="friend" v-for="friend in friends" :key="friend.uuid" @click="openProfile(friend)">
<img :src="getAvatarUrl(friend.uuid)" @error="handleAvatarError" class="avatar" /> <img :src="getAvatarUrl(friend.uuid)" @error="handleAvatarError" class="avatar" />
<p>{{ friend.username }}</p> <p>{{ friend.username }}</p>
@@ -39,11 +54,23 @@ import UserProfileModal from '../components/UserProfileModal.vue'
const friends = ref<Friend[]>([]) const friends = ref<Friend[]>([])
const username = ref('') const username = ref('')
const errorMessage = ref('') const errorMessage = ref('')
const isLoading = ref(true)
const selectedFriend = ref<Friend | null>(null) const selectedFriend = ref<Friend | null>(null)
onMounted(async () => { async function loadFriends() {
isLoading.value = true
try {
friends.value = await fetchFriends() friends.value = await fetchFriends()
} catch (err) {
console.error("Failed to fetch friends", err)
} finally {
isLoading.value = false
}
}
onMounted(async () => {
await loadFriends()
}) })
const openProfile = (friend: Friend) => { const openProfile = (friend: Friend) => {
@@ -56,16 +83,13 @@ const handleAvatarError = (event: Event) => {
}; };
async function send() { async function send() {
if (!username.value) { if (!username.value) return
// errorMessage.value = 'Username is required.'
return
}
try { try {
await sendFriendRequest(username.value) await sendFriendRequest(username.value)
username.value = '' username.value = ''
errorMessage.value = '' errorMessage.value = ''
friends.value = await fetchFriends() await loadFriends()
} catch (err: any) { } catch (err: any) {
errorMessage.value = err errorMessage.value = err
} }
@@ -117,13 +141,44 @@ async function send() {
} }
.friends-list { .friends-list {
position: relative;
min-width: 250px; min-width: 250px;
min-height: 200px;
background: var(--panel); background: var(--panel);
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: var(--radius); border-radius: var(--radius);
padding: 1rem; padding: 1rem;
} }
.wait-container {
display: flex;
flex-direction: column;
gap: 1.2rem;
align-items: center;
justify-content: center;
padding: 2rem 0;
width: 100%;
}
.wait-msg {
color: var(--muted);
font-size: 1.1rem;
text-align: center;
}
.retry-btn {
background: transparent;
color: var(--text);
border: 1px solid var(--border);
padding: 0.5rem 1rem;
border-radius: var(--radius);
cursor: pointer;
}
.retry-btn:hover {
background: var(--panel-hover);
}
.friend { .friend {
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
@@ -131,23 +186,18 @@ async function send() {
color: var(--text); color: var(--text);
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: var(--radius); border-radius: var(--radius);
/* padding: 0.75rem 1rem; */
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
gap: 1.2rem; gap: 1.2rem;
margin: 0 0 0.5rem 0; cursor: pointer;
} }
.friend:hover p { .friend:hover p {
text-decoration: underline; text-decoration: underline;
} }
/* .friend:hover { */
/* background-color: var(--panel-hover); */
/* } */
.friends-list h2 { .friends-list h2 {
font-size: 1.25rem; font-size: 1.25rem;
margin-bottom: 1rem; margin-bottom: 1rem;