feat: handle expired listings via expires_at, optimize polling to query only pending IDs, filter expired from public listings

This commit is contained in:
2026-02-07 09:58:30 +01:00
parent a3d2a3327a
commit 7505ce5555
3 changed files with 44 additions and 15 deletions

View File

@@ -7,7 +7,7 @@ let cachedRates = null
class ListingCard extends HTMLElement { class ListingCard extends HTMLElement {
static get observedAttributes() { static get observedAttributes() {
return ['listing-id', 'title', 'price', 'currency', 'location', 'image', 'owner-id', 'payment-status'] return ['listing-id', 'title', 'price', 'currency', 'location', 'image', 'owner-id', 'payment-status', 'expires-at']
} }
constructor() { constructor() {
@@ -130,8 +130,13 @@ class ListingCard extends HTMLElement {
` : '' ` : ''
const paymentStatus = this.getAttribute('payment-status') const paymentStatus = this.getAttribute('payment-status')
const expiresAt = this.getAttribute('expires-at')
const isExpired = expiresAt && new Date(expiresAt) < new Date()
let paymentBadge = '' let paymentBadge = ''
if (paymentStatus === 'processing' || paymentStatus === 'pending') { if (isExpired) {
paymentBadge = /* html */`<span class="payment-badge payment-expired">${t('myListings.status.expired')}</span>`
} else if (paymentStatus === 'processing' || paymentStatus === 'pending') {
paymentBadge = /* html */`<span class="payment-badge payment-processing"><span class="pulse-dot"></span>${t('myListings.status.processing')}</span>` paymentBadge = /* html */`<span class="payment-badge payment-processing"><span class="pulse-dot"></span>${t('myListings.status.processing')}</span>`
} else if (paymentStatus === 'expired') { } else if (paymentStatus === 'expired') {
paymentBadge = /* html */`<span class="payment-badge payment-expired">${t('myListings.status.expired')}</span>` paymentBadge = /* html */`<span class="payment-badge payment-expired">${t('myListings.status.expired')}</span>`

View File

@@ -63,21 +63,37 @@ class PageMyListings extends HTMLElement {
const user = await auth.getUser() const user = await auth.getUser()
if (!user) return if (!user) return
const pendingIds = this.listings
.filter(l => l.payment_status === 'processing' || l.payment_status === 'pending')
.map(l => l.id)
if (pendingIds.length === 0) {
this.stopPolling()
return
}
const response = await directus.getListings({ const response = await directus.getListings({
fields: [ fields: ['id', 'status', 'payment_status'],
'id', 'status', 'title', 'slug', 'price', 'currency',
'condition', 'payment_status', 'date_created', 'user_created',
'images.directus_files_id.id',
'location.id', 'location.name'
],
filter: { filter: {
user_created: { _eq: user.id } id: { _in: pendingIds }
}, },
sort: ['-date_created'], limit: pendingIds.length
limit: 50
}) })
this.listings = response.items || []
this.updateContent() const updated = response.items || []
let changed = false
for (const item of updated) {
const existing = this.listings.find(l => l.id === item.id)
if (existing && (existing.payment_status !== item.payment_status || existing.status !== item.status)) {
existing.payment_status = item.payment_status
existing.status = item.status
changed = true
}
}
if (changed) {
this.updateContent()
}
this.startPolling() this.startPolling()
} catch (err) { } catch (err) {
console.error('Polling failed:', err) console.error('Polling failed:', err)
@@ -96,7 +112,7 @@ class PageMyListings extends HTMLElement {
const response = await directus.getListings({ const response = await directus.getListings({
fields: [ fields: [
'id', 'status', 'title', 'slug', 'price', 'currency', 'id', 'status', 'title', 'slug', 'price', 'currency',
'condition', 'payment_status', 'date_created', 'user_created', 'condition', 'payment_status', 'expires_at', 'date_created', 'user_created',
'images.directus_files_id.id', 'images.directus_files_id.id',
'location.id', 'location.name' 'location.id', 'location.name'
], ],
@@ -211,6 +227,7 @@ class PageMyListings extends HTMLElement {
image="${imageUrl}" image="${imageUrl}"
owner-id="${listing.user_created || ''}" owner-id="${listing.user_created || ''}"
payment-status="${listing.payment_status || ''}" payment-status="${listing.payment_status || ''}"
expires-at="${listing.expires_at || ''}"
></listing-card> ></listing-card>
</div> </div>
` `

View File

@@ -327,6 +327,7 @@ class DirectusService {
'price', 'price',
'currency', 'currency',
'condition', 'condition',
'expires_at',
'date_created', 'date_created',
'user_created', 'user_created',
'images.directus_files_id.id', 'images.directus_files_id.id',
@@ -341,7 +342,13 @@ class DirectusService {
'location.latitude', 'location.latitude',
'location.longitude' 'location.longitude'
], ],
filter: options.filter || { status: { _eq: 'published' } }, filter: options.filter || {
status: { _eq: 'published' },
_or: [
{ expires_at: { _null: true } },
{ expires_at: { _gt: '$NOW' } }
]
},
sort: options.sort || ['-date_created'], sort: options.sort || ['-date_created'],
limit: options.limit || 20, limit: options.limit || 20,
page: options.page || 1 page: options.page || 1