websockets implemented
This commit is contained in:
208
frontend/src/views/social/FriendsView.vue
Normal file
208
frontend/src/views/social/FriendsView.vue
Normal file
@@ -0,0 +1,208 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2>{{ $t('friends.title') }}</h2>
|
||||
<div class="tabs-container">
|
||||
<div class="tab" v-for="(tab, index) in tabs" :key="tab.name" :class="{ active: activeTab === index }"
|
||||
@click="selectTab(index)">
|
||||
{{ $t(tab.label) }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="(tab, index) in tabs" v-show="activeTab === index" :key="tab.name">
|
||||
<v-data-table :items="paginatedData(tab.data, tab.pagination.page)" :headers="headers"
|
||||
:items-per-page="tab.pagination.itemsPerPage" class="elevation-1">
|
||||
<template v-slot:body="{ items }">
|
||||
<tr v-for="(item, index) in items" :key="index">
|
||||
<td :class="'font-color-gender-' + item.user.gender.toLowerCase().replace(' ', '')">
|
||||
{{ item.user.username }}
|
||||
</td>
|
||||
<td>{{ item.user.age }}</td>
|
||||
<td>{{ $t(`gender.${item.user.gender}`) }}</td>
|
||||
<td>
|
||||
<template v-if="tab.name === 'existingFriends'">
|
||||
<v-btn color="error" @click="endFriendship(item.user.hashedId)">{{ $t('friends.actions.end')
|
||||
}}</v-btn>
|
||||
</template>
|
||||
<template v-if="tab.name === 'pendingFriends'">
|
||||
<v-btn color="success" @click="acceptFriendship(item.user.hashedId)">{{
|
||||
$t('friends.actions.accept') }}</v-btn>
|
||||
<v-btn color="error" @click="rejectFriendship(item.user.hashedId)">{{
|
||||
$t('friends.actions.reject') }}</v-btn>
|
||||
</template>
|
||||
<template v-if="tab.name === 'requestedFriends'">
|
||||
<v-btn color="warning" @click="withdrawRequest(item.user.hashedId)">{{
|
||||
$t('friends.actions.withdraw') }}</v-btn>
|
||||
</template>
|
||||
<template v-if="tab.name === 'rejectedFriends'">
|
||||
<v-btn color="success" @click="acceptFriendship(item.user.hashedId)">{{
|
||||
$t('friends.actions.accept') }}</v-btn>
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</v-data-table>
|
||||
<v-pagination v-model="tab.pagination.page"
|
||||
:length="Math.ceil(tab.data.length / tab.pagination.itemsPerPage)" :total-visible="5"
|
||||
class="mt-4"></v-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getFriendships, endFriendship, acceptFriendship, rejectFriendship, withdrawRequest } from "@/api/friendshipApi";
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: "FriendsView",
|
||||
data() {
|
||||
return {
|
||||
activeTab: 0,
|
||||
headers: [
|
||||
{ text: this.$t("friends.headers.name"), value: "name" },
|
||||
{ text: this.$t("friends.headers.age"), value: "age" },
|
||||
{ text: this.$t("friends.headers.gender"), value: "gender" },
|
||||
{ text: this.$t("friends.headers.actions"), value: "actions", sortable: false },
|
||||
],
|
||||
tabs: [
|
||||
{ name: "existingFriends", label: "friends.tabs.existing", data: [], pagination: { page: 1, itemsPerPage: 10 } },
|
||||
{ name: "pendingFriends", label: "friends.tabs.pending", data: [], pagination: { page: 1, itemsPerPage: 10 } },
|
||||
{ name: "requestedFriends", label: "friends.tabs.requested", data: [], pagination: { page: 1, itemsPerPage: 10 } },
|
||||
{ name: "rejectedFriends", label: "friends.tabs.rejected", data: [], pagination: { page: 1, itemsPerPage: 10 } },
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['socket', 'user']),
|
||||
},
|
||||
methods: {
|
||||
async fetchFriendships() {
|
||||
try {
|
||||
const friendships = await getFriendships(false);
|
||||
this.distributeFriendships(friendships);
|
||||
} catch (error) {
|
||||
console.error("Error fetching friendships:", error);
|
||||
}
|
||||
},
|
||||
distributeFriendships(friendships) {
|
||||
this.tabs.forEach(tab => (tab.data = []));
|
||||
friendships.forEach(friendship => {
|
||||
if (friendship.accepted) {
|
||||
this.tabs.find(tab => tab.name === "existingFriends").data.push(friendship);
|
||||
} else if (friendship.denied) {
|
||||
const tabName = friendship.initiatorId === this.$store.state.user.hashedId
|
||||
? "requestedFriends"
|
||||
: "rejectedFriends";
|
||||
this.tabs.find(tab => tab.name === tabName).data.push(friendship);
|
||||
} else if (friendship.withdrawn) {
|
||||
this.tabs.find(tab => tab.name === "requestedFriends").data.push(friendship);
|
||||
} else {
|
||||
const tabName = friendship.isInitiator
|
||||
? "requestedFriends"
|
||||
: "pendingFriends";
|
||||
this.tabs.find(tab => tab.name === tabName).data.push(friendship);
|
||||
}
|
||||
});
|
||||
},
|
||||
selectTab(index) {
|
||||
this.activeTab = index;
|
||||
},
|
||||
paginatedData(data, page) {
|
||||
const start = (page - 1) * 10;
|
||||
const end = start + 10;
|
||||
return data.slice(start, end);
|
||||
},
|
||||
async endFriendship(friendUserId) {
|
||||
try {
|
||||
await endFriendship(friendUserId);
|
||||
this.fetchFriendships();
|
||||
} catch (error) {
|
||||
console.error("Error ending friendship:", error);
|
||||
}
|
||||
},
|
||||
async acceptFriendship(friendUserId) {
|
||||
try {
|
||||
await acceptFriendship(friendUserId);
|
||||
this.fetchFriendships();
|
||||
} catch (error) {
|
||||
console.error("Error accepting friendship:", error);
|
||||
}
|
||||
},
|
||||
async rejectFriendship(friendUserId) {
|
||||
try {
|
||||
await rejectFriendship(friendUserId);
|
||||
this.fetchFriendships();
|
||||
} catch (error) {
|
||||
console.error("Error rejecting friendship:", error);
|
||||
}
|
||||
},
|
||||
async withdrawRequest(friendUserId) {
|
||||
try {
|
||||
await withdrawRequest(friendUserId);
|
||||
this.fetchFriendships();
|
||||
} catch (error) {
|
||||
console.error("Error withdrawing request:", error);
|
||||
}
|
||||
},
|
||||
setupSocketListener() {
|
||||
if (this.socket) {
|
||||
console.log("Setting up friendshipChanged listener");
|
||||
this.socket.on("friendshipChanged", (data) => {
|
||||
console.log("Friendship changed:", data);
|
||||
this.fetchFriendships();
|
||||
});
|
||||
} else {
|
||||
console.error("Socket not initialized");
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.fetchFriendships();
|
||||
this.setupSocketListener();
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (this.socket) {
|
||||
this.socket.off("friendshipChanged");
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tabs-container {
|
||||
display: flex;
|
||||
border-bottom: 1px solid #999;
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.tab {
|
||||
padding: 2px 4px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
border: 1px solid #999;
|
||||
transition: background-color 0.3s ease, color 0.3s ease;
|
||||
}
|
||||
|
||||
.tab:not(.active):hover {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
background-color: #F9A22C;
|
||||
color: #7E471B;
|
||||
border-color: #F9A22C;
|
||||
}
|
||||
|
||||
.font-color-gender-male {
|
||||
color: #1E90FF;
|
||||
}
|
||||
|
||||
.font-color-gender-female {
|
||||
color: #FF69B4;
|
||||
}
|
||||
|
||||
.font-color-gender-nonbinary {
|
||||
color: #DAA520;
|
||||
}
|
||||
</style>
|
||||
@@ -82,6 +82,7 @@ import apiClient from '@/utils/axios.js';
|
||||
import Multiselect from 'vue-multiselect';
|
||||
import FolderItem from '../../components/FolderItem.vue';
|
||||
import 'vue-multiselect/dist/vue-multiselect.min.css';
|
||||
import { EventBus } from '@/utils/eventBus.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -107,6 +108,10 @@ export default {
|
||||
if (this.folders) {
|
||||
this.selectFolder(this.folders);
|
||||
}
|
||||
EventBus.on('folderCreated', this.loadFolders);
|
||||
},
|
||||
beforeUnmount() {
|
||||
EventBus.off('folderCreated', this.loadFolders);
|
||||
},
|
||||
methods: {
|
||||
async loadFolders() {
|
||||
|
||||
Reference in New Issue
Block a user