Files
kashilo/js/components/pages/page-my-listings.js

234 lines
6.9 KiB
JavaScript

import { t, i18n } from '../../i18n.js'
import { directus } from '../../services/directus.js'
import { auth } from '../../services/auth.js'
import '../listing-card.js'
import '../skeleton-card.js'
class PageMyListings extends HTMLElement {
constructor() {
super()
this.listings = []
this.loading = true
this.error = null
this.isLoggedIn = false
}
connectedCallback() {
this.isLoggedIn = auth.isLoggedIn()
if (!this.isLoggedIn) {
window.location.hash = '#/'
return
}
this.render()
this.loadMyListings()
this.unsubscribe = i18n.subscribe(() => this.render())
this.authUnsubscribe = auth.subscribe(() => {
this.isLoggedIn = auth.isLoggedIn()
if (!this.isLoggedIn) {
window.location.hash = '#/'
}
})
}
disconnectedCallback() {
if (this.unsubscribe) this.unsubscribe()
if (this.authUnsubscribe) this.authUnsubscribe()
}
async loadMyListings() {
try {
const user = await auth.getUser()
if (!user) {
this.loading = false
this.updateContent()
return
}
const response = await directus.getListings({
filter: {
user_created: { _eq: user.id }
},
sort: ['-date_created'],
limit: 50
})
this.listings = response.items || []
this.loading = false
this.updateContent()
} catch (err) {
console.error('Failed to load my listings:', err)
this.error = err.message
this.loading = false
this.updateContent()
}
}
showAuthModal() {
document.querySelector('auth-modal')?.show()
}
render() {
this.innerHTML = /* html */`
<div class="my-listings-page">
<header class="page-header">
<h1>${t('myListings.title')}</h1>
<p class="page-subtitle">${t('myListings.subtitle')}</p>
</header>
<div id="my-listings-content" class="listings-grid">
${this.renderContent()}
</div>
</div>
`
this.querySelector('#login-btn')?.addEventListener('click', () => this.showAuthModal())
}
updateContent() {
const container = this.querySelector('#my-listings-content')
if (container) {
container.innerHTML = this.renderContent()
this.querySelector('#login-btn')?.addEventListener('click', () => this.showAuthModal())
}
}
renderContent() {
if (!this.isLoggedIn) {
return /* html */`
<div class="empty-state">
<div class="empty-icon">🔐</div>
<h3>${t('myListings.loginRequired')}</h3>
<p>${t('myListings.loginHint')}</p>
<button id="login-btn" class="btn btn-primary">${t('myListings.login')}</button>
</div>
`
}
if (this.loading) {
return Array(4).fill(0).map(() => '<skeleton-card></skeleton-card>').join('')
}
if (this.error) {
return /* html */`
<div class="empty-state">
<div class="empty-icon">⚠️</div>
<p>${t('common.error')}</p>
</div>
`
}
if (this.listings.length === 0) {
return /* html */`
<div class="empty-state">
<div class="empty-icon">📦</div>
<h3>${t('myListings.empty')}</h3>
<p>${t('myListings.emptyHint')}</p>
<a href="#/create" class="btn btn-primary">${t('myListings.create')}</a>
</div>
`
}
return this.listings.map(listing => {
const imageId = listing.images?.[0]?.directus_files_id?.id || listing.images?.[0]?.directus_files_id
const imageUrl = imageId ? directus.getThumbnailUrl(imageId, 300) : ''
const locationName = listing.location?.name || ''
const statusBadge = listing.status !== 'published'
? `<span class="status-badge status-${listing.status}">${t(`myListings.status.${listing.status}`)}</span>`
: ''
return /* html */`
<div class="listing-wrapper">
${statusBadge}
<listing-card
listing-id="${listing.id}"
title="${this.escapeHtml(listing.title || '')}"
price="${listing.price || ''}"
currency="${listing.currency || 'EUR'}"
location="${this.escapeHtml(locationName)}"
image="${imageUrl}"
></listing-card>
</div>
`
}).join('')
}
escapeHtml(text) {
const div = document.createElement('div')
div.textContent = text
return div.innerHTML
}
}
customElements.define('page-my-listings', PageMyListings)
const style = document.createElement('style')
style.textContent = /* css */`
page-my-listings .my-listings-page {
padding: var(--space-lg) 0;
}
page-my-listings .page-header {
margin-bottom: var(--space-xl);
}
page-my-listings .page-header h1 {
margin: 0 0 var(--space-xs);
}
page-my-listings .page-subtitle {
color: var(--color-text-muted);
margin: 0;
}
page-my-listings .listing-wrapper {
position: relative;
}
page-my-listings .status-badge {
position: absolute;
top: var(--space-sm);
left: var(--space-sm);
padding: var(--space-xs) var(--space-sm);
font-size: var(--font-size-xs);
font-weight: var(--font-weight-medium);
border-radius: var(--radius-sm);
z-index: 2;
}
page-my-listings .status-draft {
background: var(--color-bg-tertiary);
color: var(--color-text-muted);
}
page-my-listings .status-archived {
background: var(--color-bg-tertiary);
color: var(--color-text-muted);
text-decoration: line-through;
}
page-my-listings .empty-state {
grid-column: 1 / -1;
text-align: center;
padding: var(--space-3xl);
}
page-my-listings .empty-icon {
font-size: 4rem;
margin-bottom: var(--space-md);
filter: grayscale(1);
}
page-my-listings .empty-state h3 {
margin: 0 0 var(--space-sm);
}
page-my-listings .empty-state p {
color: var(--color-text-muted);
margin: 0 0 var(--space-lg);
}
`
document.head.appendChild(style)