This commit is contained in:
j3d1 2026-08-01 16:03:35 +02:00
parent 2f8683add1
commit cfcc2c15d3
15 changed files with 644 additions and 77 deletions

View file

@ -36,9 +36,11 @@
<button class="btn btn-primary" @click="tryRequestFriend">Send request</button>
</td>
</tr>
<tr v-for="friend in friendslist" :key="friend.name">
<td>{{ friend.username }}</td>
<td class="d-none d-md-table-cell">{{ friend.server.join(', ')}}</td>
<tr v-for="friend in friendslist" :key="friend.name">
<td>
<user-name-tag :user="friend"/>
</td>
<td class="d-none d-md-table-cell">{{ friend.server.join(', ')}}</td>
<td class="table-action">
<!--a href="#" class="align-middle">
<b-icon-pencil-square></b-icon-pencil-square>
@ -76,7 +78,7 @@
<tr v-for="request in requests" :key="request.befriender">
<td>{{ request.befriender }}</td>
<td class="d-none d-md-table-cell">
{{ request.befriender_public_key.slice(0, 32) }}...
{{ request.befriender_public_key?.slice(0, 32) ?? 'N/A' }}...
</td>
<td class="table-action">
<button class="btn btn-sm btn-success" @click="tryAcceptFriend(request)">
@ -100,14 +102,18 @@
</template>
<script>
import {mapActions, mapGetters} from "vuex";
import {mapActions, mapGetters, mapState} from "vuex";
import * as BIcons from "bootstrap-icons-vue";
import BaseLayout from "@/components/BaseLayout.vue";
import AuthenticatedImage from "@/components/AuthenticatedImage.vue";
import UserNameTag from "@/components/UserNameTag.vue";
export default {
name: 'Inventory',
components: {
BaseLayout,
AuthenticatedImage,
UserNameTag,
...BIcons
},
data() {
@ -119,6 +125,7 @@ export default {
}
},
computed: {
...mapState(['user']),
username() {
return this.$route.params.username
},
@ -128,12 +135,15 @@ export default {
},
methods: {
...mapActions(['fetchFriends', "lookupServer", "requestFriend", "acceptFriend", "fetchFriendRequests",
"declineFriend", "dropFriend"]),
"declineFriend", "dropFriend", "getFriendServers", "fetchFriendProfile"]),
fetchContent() {
this.fetchFriends().then((friends) => {
friends.map((friend) => {
// Handle both object and array formats
const friendsList = Array.isArray(friends) ? friends : Object.values(friends);
friendsList.map((friend) => {
this.lookupServer(friend).then((server) => {
this.friends[friend.username] = {...friend, server: server}
this.fetchFriendProfile({username: friend.username});
})
})
})

View file

@ -4,45 +4,70 @@
<div class="container-fluid p-0">
<h1 class="h3 mb-3">Search Inventories</h1>
<div class="row">
<div class="col-md-3">
<div class="card">
<SearchBox @change=""/>
</div>
</div>
<div class="col-12">
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">Results for "{{ query }}"</h5>
<button v-if="layout === 'grid'" @click="layout = 'table'" class="btn">
<b-icon-list></b-icon-list>
</button>
<button v-else @click="layout = 'grid'" class="btn">
<b-icon-grid></b-icon-grid>
</button>
</div>
<div class="card-body">
<table class="table table-striped">
<thead>
<tr>
<th style="width:40%;">Name</th>
<th style="width:25%">Owner</th>
<th class="d-none d-md-table-cell" style="width:25%">Amount</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="item in search_results" :key="item.id">
<td>
<router-link :to="`/inventory/${item.id}`">{{ item.name }}</router-link>
</td>
<td>{{ item.owner }}</td>
<td class="d-none d-md-table-cell">{{ item.owned_quantity }}</td>
<td class="table-action">
<!--<router-link :to="`/inventory/${item.id}/edit`">
<b-icon-pencil-square></b-icon-pencil-square>
</router-link>
<a :href="`/inventory/${item.id}/delete`"
@click.prevent="deleteInventoryItem(item)">
<b-icon-trash></b-icon-trash>
</a>-->
</td>
</tr>
</tbody>
</table>
<table class="table table-striped" v-if="layout === 'table'">
<thead>
<tr>
<th style="width:40%;">Name</th>
<th style="width:25%">Owner</th>
<th class="d-none d-md-table-cell" style="width:25%">Amount</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="item in search_results" :key="item.id">
<td>
<router-link :to="`/inventory/${item.id}`">{{ item.name }}</router-link>
</td>
<td>
<user-name-tag :user="item"/>
</td>
<td class="d-none d-md-table-cell">{{ item.owned_quantity }}</td>
<td class="table-action">
<!--<router-link :to="`/inventory/${item.id}/edit`">
<b-icon-pencil-square></b-icon-pencil-square>
</router-link>
<a :href="`/inventory/${item.id}/delete`"
@click.prevent="deleteInventoryItem(item)">
<b-icon-trash></b-icon-trash>
</a>-->
</td>
</tr>
</tbody>
</table>
<div class="card-body" v-else>
<div class="row">
<div class="col-12 col-md-4 col-lg-3 col-xl-2" v-for="item in search_results"
:key="item.id">
<div class="card">
<authenticated-image v-if="only_images(item.files).length > 0"
:src="only_images(item.files)[0].name"
:owner="only_images(item.files)[0].owner"
class="card-img-top img-preview"/>
<div class="card-body">
<h5 class="card-title mb-0">
<router-link :to="`/inventory/${item.id}`">
{{ item.name }}
</router-link></h5>
<div class="card-text text-black-50">
<user-name-tag :user="item" :width="24" :height="24"/>
<br>
<span class="float-right">{{ item.owned_quantity }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@ -57,11 +82,15 @@ import {mapActions} from 'vuex';
import * as BIcons from "bootstrap-icons-vue";
import BaseLayout from "@/components/BaseLayout.vue";
import SearchBox from "@/components/SearchBox.vue";
import AuthenticatedImage from "@/components/AuthenticatedImage.vue";
import UserNameTag from "@/components/UserNameTag.vue";
export default {
name: 'Search',
components: {
SearchBox,
AuthenticatedImage,
UserNameTag,
...BIcons,
BaseLayout
},
@ -74,19 +103,37 @@ export default {
data() {
return {
search_results: [],
layout: 'table'
}
},
methods: {
...mapActions(['fetchSearchResults']),
only_images(files) {
if (!files) return [];
return files.filter(file => file.mime_type.startsWith("image/"));
},
loadResults() {
this.fetchSearchResults({query: this.query}).then((results) => {
this.search_results = results;
});
}
},
async mounted() {
this.fetchSearchResults({query: this.query}).then((results) => {
this.search_results = results;
});
watch: {
query: {
immediate: false,
handler() {
this.loadResults();
}
}
},
mounted() {
this.loadResults();
}
}
</script>
<style scoped>
.img-preview {
object-fit: cover;
}
</style>