- Added support for additional UI locales including Cebuano and Spanish, improving accessibility for a broader user base. - Updated language selection components in the AppHeader and SettingsWidget to reflect new language options, enhancing user experience. - Enhanced localization of various UI elements across components, ensuring consistent language representation and improved user engagement. - Implemented logic to synchronize user language preferences with backend settings, providing a seamless experience when changing languages.
163 lines
4.8 KiB
Vue
163 lines
4.8 KiB
Vue
<template>
|
|
<div class="guestbook-view">
|
|
<section class="guestbook-hero surface-card">
|
|
<div>
|
|
<span class="guestbook-kicker">{{ $t('socialnetwork.guestbook.kicker') }}</span>
|
|
<h2>{{ $t('socialnetwork.guestbook.title') }}</h2>
|
|
<p>{{ $t('socialnetwork.guestbook.intro') }}</p>
|
|
</div>
|
|
</section>
|
|
<div v-if="guestbookEntries.length === 0" class="guestbook-empty surface-card">{{ $t('socialnetwork.profile.guestbook.noEntries') }}
|
|
</div>
|
|
<div v-else class="guestbook-entries">
|
|
<article v-for="entry in guestbookEntries" :key="entry.id" class="guestbook-entry surface-card">
|
|
<img v-if="entry.image" :src="entry.image.url" alt="Entry Image"
|
|
class="guestbook-image" />
|
|
<p v-html="sanitizedContent(entry)"></p>
|
|
<div class="entry-info">
|
|
<span class="entry-timestamp">{{ new Date(entry.createdAt).toLocaleString() }}</span>
|
|
<span class="entry-user">
|
|
<span @click="openProfile(entry.senderUsername)">{{ entry.sender }}</span>
|
|
</span>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
<div class="pagination">
|
|
<button @click="loadGuestbookEntries(currentPage - 1)" v-if="currentPage !== 1">{{
|
|
$t('socialnetwork.guestbook.prevPage') }}</button>
|
|
<span>{{ $t('socialnetwork.guestbook.page') }} {{ currentPage }} / {{ totalPages }}</span>
|
|
<button @click="loadGuestbookEntries(currentPage + 1)" v-if="currentPage < totalPages">{{
|
|
$t('socialnetwork.guestbook.nextPage')
|
|
}}</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { mapActions, mapGetters } from 'vuex';
|
|
import apiClient from '@/utils/axios.js';
|
|
import DOMPurify from 'dompurify';
|
|
|
|
export default {
|
|
name: 'GuestbookView',
|
|
data() {
|
|
return {
|
|
guestbookEntries: [],
|
|
currentPage: 1,
|
|
totalPages: 1,
|
|
};
|
|
},
|
|
computed: {
|
|
...mapGetters(['user']),
|
|
},
|
|
methods: {
|
|
...mapActions('socialnetwork', ['fetchUserProfile']),
|
|
openProfile(username) {
|
|
this.$router.push({ name: 'profile', params: { username } });
|
|
},
|
|
async loadGuestbookEntries(page) {
|
|
try {
|
|
const response = await apiClient.get(`/api/socialnetwork/guestbook/entries/${this.user.username}/${page}`);
|
|
this.guestbookEntries = response.data.entries;
|
|
this.currentPage = page;
|
|
this.totalPages = response.data.totalPages;
|
|
this.guestbookEntries.forEach((entry) => {
|
|
if (entry.withImage) {
|
|
this.fetchGuestbookImage(this.user.username, entry);
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error('Fehler beim Laden der Gästebucheinträge:', error);
|
|
}
|
|
},
|
|
async fetchGuestbookImage(guestbookOwnerName, entry) {
|
|
try {
|
|
const response = await apiClient.get(`/api/socialnetwork/guestbook/image/${this.user.username}/${entry.id}`, {
|
|
responseType: 'blob',
|
|
});
|
|
entry.image = { url: URL.createObjectURL(response.data) };
|
|
} catch (error) {
|
|
console.error('Error fetching image:', error);
|
|
}
|
|
},
|
|
sanitizedContent(entry) {
|
|
return DOMPurify.sanitize(entry.contentHtml);
|
|
},
|
|
},
|
|
mounted() {
|
|
this.loadGuestbookEntries(1);
|
|
},
|
|
}
|
|
</script>
|
|
|
|
<style lang="css" scoped>
|
|
.guestbook-view {
|
|
max-width: 820px;
|
|
margin: 0 auto;
|
|
padding-bottom: 24px;
|
|
}
|
|
|
|
.guestbook-hero,
|
|
.guestbook-empty {
|
|
padding: 22px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.guestbook-kicker {
|
|
display: inline-block;
|
|
margin-bottom: 10px;
|
|
padding: 4px 10px;
|
|
border-radius: 999px;
|
|
background: rgba(120, 195, 138, 0.14);
|
|
color: #42634e;
|
|
font-size: 0.75rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
}
|
|
|
|
.guestbook-hero p {
|
|
margin: 0;
|
|
color: var(--color-text-secondary);
|
|
}
|
|
|
|
.guestbook-entries {
|
|
display: grid;
|
|
gap: 12px;
|
|
}
|
|
|
|
.guestbook-entry {
|
|
padding: 18px 20px;
|
|
}
|
|
|
|
.guestbook-image {
|
|
max-width: 100%;
|
|
max-height: 400px;
|
|
border-radius: 14px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.entry-info {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
color: var(--color-text-muted);
|
|
}
|
|
|
|
.entry-user span {
|
|
cursor: pointer;
|
|
font-weight: 700;
|
|
color: var(--color-primary);
|
|
}
|
|
|
|
.pagination {
|
|
margin-top: 1em;
|
|
color: var(--color-text-secondary);
|
|
padding: 0.5em 0;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
</style>
|