refactor: event delegation, unified subscription cleanup, centralized listing status helpers
This commit is contained in:
@@ -2,12 +2,14 @@ import { getCurrentLanguage, i18n } from '../../i18n.js'
|
||||
|
||||
class PageAbout extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this._unsubs = []
|
||||
this.render()
|
||||
this.unsubscribe = i18n.subscribe(() => this.render())
|
||||
this._unsubs.push(i18n.subscribe(() => this.render()))
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.unsubscribe) this.unsubscribe()
|
||||
this._unsubs.forEach(fn => fn())
|
||||
this._unsubs = []
|
||||
}
|
||||
|
||||
getContent(lang) {
|
||||
|
||||
@@ -2,12 +2,14 @@ import { getCurrentLanguage, i18n } from '../../i18n.js'
|
||||
|
||||
class PageContact extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this._unsubs = []
|
||||
this.render()
|
||||
this.unsubscribe = i18n.subscribe(() => this.render())
|
||||
this._unsubs.push(i18n.subscribe(() => this.render()))
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.unsubscribe) this.unsubscribe()
|
||||
this._unsubs.forEach(fn => fn())
|
||||
this._unsubs = []
|
||||
}
|
||||
|
||||
getContent(lang) {
|
||||
|
||||
@@ -72,6 +72,8 @@ class PageCreate extends HTMLElement {
|
||||
}
|
||||
|
||||
async connectedCallback() {
|
||||
this._unsubs = []
|
||||
|
||||
// Check if logged in
|
||||
if (!auth.isLoggedIn()) {
|
||||
this.showLoginRequired()
|
||||
@@ -90,7 +92,7 @@ class PageCreate extends HTMLElement {
|
||||
await this.loadCategories()
|
||||
await this.checkAccountStatus()
|
||||
this.render()
|
||||
this.unsubscribe = i18n.subscribe(() => this.render())
|
||||
this._unsubs.push(i18n.subscribe(() => this.render()))
|
||||
}
|
||||
|
||||
async loadExistingListing() {
|
||||
@@ -165,7 +167,7 @@ class PageCreate extends HTMLElement {
|
||||
this.hasDraft = !!localStorage.getItem(STORAGE_KEY)
|
||||
await this.loadCategories()
|
||||
this.render()
|
||||
this.unsubscribe = i18n.subscribe(() => this.render())
|
||||
this._unsubs.push(i18n.subscribe(() => this.render()))
|
||||
}, { once: true })
|
||||
authModal.addEventListener('close', () => {
|
||||
// If closed without login, go back
|
||||
@@ -206,7 +208,8 @@ class PageCreate extends HTMLElement {
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.unsubscribe) this.unsubscribe()
|
||||
this._unsubs.forEach(fn => fn())
|
||||
this._unsubs = []
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -15,15 +15,16 @@ class PageFavorites extends HTMLElement {
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this._unsubs = []
|
||||
this.render()
|
||||
this.loadFavorites()
|
||||
this.unsubscribe = i18n.subscribe(() => this.render())
|
||||
this.favUnsubscribe = favoritesService.subscribe(() => this.loadFavorites())
|
||||
this._unsubs.push(i18n.subscribe(() => this.render()))
|
||||
this._unsubs.push(favoritesService.subscribe(() => this.loadFavorites()))
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.unsubscribe) this.unsubscribe()
|
||||
if (this.favUnsubscribe) this.favUnsubscribe()
|
||||
this._unsubs.forEach(fn => fn())
|
||||
this._unsubs = []
|
||||
}
|
||||
|
||||
async loadFavorites() {
|
||||
|
||||
@@ -40,25 +40,26 @@ class PageHome extends HTMLElement {
|
||||
this.setupEventListeners()
|
||||
this.setupPullToRefresh()
|
||||
this.loadListings()
|
||||
this.unsubscribe = i18n.subscribe(() => {
|
||||
this._unsubs = []
|
||||
this._unsubs.push(i18n.subscribe(() => {
|
||||
this.updateTextContent()
|
||||
})
|
||||
}))
|
||||
|
||||
// Re-render listings on auth change to show owner badges
|
||||
this.authUnsubscribe = auth.subscribe(() => {
|
||||
this._unsubs.push(auth.subscribe(() => {
|
||||
const container = this.querySelector('#listings-container')
|
||||
if (container) {
|
||||
container.innerHTML = this.renderListings()
|
||||
}
|
||||
})
|
||||
}))
|
||||
|
||||
// Listen for URL changes (back/forward navigation)
|
||||
window.addEventListener('hashchange', this._onHashChange)
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.unsubscribe) this.unsubscribe()
|
||||
if (this.authUnsubscribe) this.authUnsubscribe()
|
||||
this._unsubs.forEach(fn => fn())
|
||||
this._unsubs = []
|
||||
window.removeEventListener('hashchange', this._onHashChange)
|
||||
}
|
||||
|
||||
|
||||
@@ -23,14 +23,16 @@ class PageListing extends HTMLElement {
|
||||
|
||||
connectedCallback() {
|
||||
this.listingId = this.dataset.id
|
||||
this._unsubs = []
|
||||
this.render()
|
||||
this.loadListing()
|
||||
this.unsubscribe = i18n.subscribe(() => this.render())
|
||||
this._unsubs.push(i18n.subscribe(() => this.render()))
|
||||
window.addEventListener('currency-changed', this.handleCurrencyChange)
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.unsubscribe) this.unsubscribe()
|
||||
this._unsubs.forEach(fn => fn())
|
||||
this._unsubs = []
|
||||
window.removeEventListener('currency-changed', this.handleCurrencyChange)
|
||||
this.resetMetaTags()
|
||||
}
|
||||
|
||||
@@ -23,19 +23,20 @@ class PageMessages extends HTMLElement {
|
||||
this.render()
|
||||
this.loadConversations()
|
||||
|
||||
this.unsubscribe = i18n.subscribe(() => this.render())
|
||||
this.authUnsubscribe = auth.subscribe(() => {
|
||||
this._unsubs = []
|
||||
this._unsubs.push(i18n.subscribe(() => this.render()))
|
||||
this._unsubs.push(auth.subscribe(() => {
|
||||
this.isLoggedIn = auth.isLoggedIn()
|
||||
|
||||
if (!this.isLoggedIn) {
|
||||
window.location.hash = '#/'
|
||||
}
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.unsubscribe) this.unsubscribe()
|
||||
if (this.authUnsubscribe) this.authUnsubscribe()
|
||||
this._unsubs.forEach(fn => fn())
|
||||
this._unsubs = []
|
||||
}
|
||||
|
||||
async loadConversations() {
|
||||
|
||||
@@ -13,6 +13,7 @@ class PageMyListings extends HTMLElement {
|
||||
this.loading = true
|
||||
this.error = null
|
||||
this.isLoggedIn = false
|
||||
this._handleClick = this.handleDelegatedClick.bind(this)
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
@@ -25,23 +26,42 @@ class PageMyListings extends HTMLElement {
|
||||
|
||||
this.render()
|
||||
this.loadMyListings()
|
||||
this.addEventListener('click', this._handleClick)
|
||||
|
||||
this.unsubscribe = i18n.subscribe(() => this.render())
|
||||
this.authUnsubscribe = auth.subscribe(() => {
|
||||
this._unsubs = []
|
||||
this._unsubs.push(i18n.subscribe(() => this.render()))
|
||||
this._unsubs.push(auth.subscribe(() => {
|
||||
this.isLoggedIn = auth.isLoggedIn()
|
||||
|
||||
if (!this.isLoggedIn) {
|
||||
window.location.hash = '#/'
|
||||
}
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.unsubscribe) this.unsubscribe()
|
||||
if (this.authUnsubscribe) this.authUnsubscribe()
|
||||
this._unsubs.forEach(fn => fn())
|
||||
this._unsubs = []
|
||||
this.removeEventListener('click', this._handleClick)
|
||||
this.stopPolling()
|
||||
}
|
||||
|
||||
handleDelegatedClick(e) {
|
||||
const toggleBtn = e.target.closest('.btn-toggle-status')
|
||||
if (toggleBtn) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
this.toggleListingStatus(toggleBtn.dataset.id, toggleBtn.dataset.status)
|
||||
return
|
||||
}
|
||||
const deleteBtn = e.target.closest('.btn-delete-listing')
|
||||
if (deleteBtn) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
this.deleteListing(deleteBtn.dataset.id)
|
||||
}
|
||||
}
|
||||
|
||||
startPolling() {
|
||||
this.stopPolling()
|
||||
const hasPending = this.listings.some(l =>
|
||||
@@ -221,11 +241,9 @@ class PageMyListings extends HTMLElement {
|
||||
const locationName = listing.location?.name || ''
|
||||
const statusBadge = this.getStatusBadge(listing)
|
||||
|
||||
const paidActive = listingsService.isPaidAndActive(listing)
|
||||
const isPublished = listing.status === 'published'
|
||||
const isDraftPaid = listing.status === 'draft' && paidActive
|
||||
let toggleBtn = ''
|
||||
if (isPublished || isDraftPaid) {
|
||||
if (listingsService.canTogglePublish(listing)) {
|
||||
const label = isPublished ? t('myListings.unpublish') : t('myListings.republish')
|
||||
toggleBtn = /* html */`
|
||||
<button class="btn-toggle-status" data-id="${listing.id}" data-status="${isPublished ? 'draft' : 'published'}">
|
||||
@@ -235,7 +253,7 @@ class PageMyListings extends HTMLElement {
|
||||
}
|
||||
|
||||
let deleteBtn = ''
|
||||
if (listing.status === 'deleted') {
|
||||
if (listingsService.isSoftDeleted(listing)) {
|
||||
deleteBtn = /* html */`
|
||||
<p class="deleted-hint">${t('myListings.deletedHint')}</p>
|
||||
`
|
||||
@@ -248,7 +266,7 @@ class PageMyListings extends HTMLElement {
|
||||
}
|
||||
|
||||
return /* html */`
|
||||
<div class="listing-wrapper${listing.status === 'deleted' ? ' is-deleted' : ''}">
|
||||
<div class="listing-wrapper${listingsService.isSoftDeleted(listing) ? ' is-deleted' : ''}">
|
||||
${statusBadge}
|
||||
<listing-card
|
||||
listing-id="${listing.id}"
|
||||
@@ -267,30 +285,9 @@ class PageMyListings extends HTMLElement {
|
||||
`
|
||||
}).join('')
|
||||
|
||||
setTimeout(() => this.setupToggleListeners(), 0)
|
||||
return html
|
||||
}
|
||||
|
||||
setupToggleListeners() {
|
||||
this.querySelectorAll('.btn-toggle-status').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
const id = btn.dataset.id
|
||||
const newStatus = btn.dataset.status
|
||||
this.toggleListingStatus(id, newStatus)
|
||||
})
|
||||
})
|
||||
this.querySelectorAll('.btn-delete-listing').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
const id = btn.dataset.id
|
||||
this.deleteListing(id)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async toggleListingStatus(id, newStatus) {
|
||||
try {
|
||||
await directus.updateListing(id, { status: newStatus })
|
||||
|
||||
@@ -2,12 +2,14 @@ import { t, i18n } from '../../i18n.js'
|
||||
|
||||
class PageNotFound extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this._unsubs = []
|
||||
this.render()
|
||||
this.unsubscribe = i18n.subscribe(() => this.render())
|
||||
this._unsubs.push(i18n.subscribe(() => this.render()))
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.unsubscribe) this.unsubscribe()
|
||||
this._unsubs.forEach(fn => fn())
|
||||
this._unsubs = []
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -10,18 +10,19 @@ class PageNotifications extends HTMLElement {
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this._unsubs = []
|
||||
this.render()
|
||||
this.loadNotifications()
|
||||
this.unsubscribe = i18n.subscribe(() => this.render())
|
||||
this.notifUnsubscribe = notificationsService.subscribe(() => {
|
||||
this._unsubs.push(i18n.subscribe(() => this.render()))
|
||||
this._unsubs.push(notificationsService.subscribe(() => {
|
||||
this.loading = false
|
||||
this.updateContent()
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.unsubscribe) this.unsubscribe()
|
||||
if (this.notifUnsubscribe) this.notifUnsubscribe()
|
||||
this._unsubs.forEach(fn => fn())
|
||||
this._unsubs = []
|
||||
}
|
||||
|
||||
async loadNotifications() {
|
||||
|
||||
@@ -2,12 +2,14 @@ import { getCurrentLanguage, i18n } from '../../i18n.js'
|
||||
|
||||
class PagePrivacy extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this._unsubs = []
|
||||
this.render()
|
||||
this.unsubscribe = i18n.subscribe(() => this.render())
|
||||
this._unsubs.push(i18n.subscribe(() => this.render()))
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.unsubscribe) this.unsubscribe()
|
||||
this._unsubs.forEach(fn => fn())
|
||||
this._unsubs = []
|
||||
}
|
||||
|
||||
getContent(lang) {
|
||||
|
||||
@@ -23,23 +23,24 @@ class PageSettings extends HTMLElement {
|
||||
this.render()
|
||||
this.setupEventListeners()
|
||||
|
||||
this.unsubscribe = i18n.subscribe(() => {
|
||||
this._unsubs = []
|
||||
this._unsubs.push(i18n.subscribe(() => {
|
||||
this.render()
|
||||
this.setupEventListeners()
|
||||
})
|
||||
}))
|
||||
|
||||
this.authUnsubscribe = auth.subscribe(() => {
|
||||
this._unsubs.push(auth.subscribe(() => {
|
||||
this.isLoggedIn = auth.isLoggedIn()
|
||||
|
||||
if (!this.isLoggedIn) {
|
||||
window.location.hash = '#/'
|
||||
}
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.unsubscribe) this.unsubscribe()
|
||||
if (this.authUnsubscribe) this.authUnsubscribe()
|
||||
this._unsubs.forEach(fn => fn())
|
||||
this._unsubs = []
|
||||
}
|
||||
|
||||
setupEventListeners() {
|
||||
|
||||
@@ -2,12 +2,14 @@ import { getCurrentLanguage, i18n } from '../../i18n.js'
|
||||
|
||||
class PageTerms extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this._unsubs = []
|
||||
this.render()
|
||||
this.unsubscribe = i18n.subscribe(() => this.render())
|
||||
this._unsubs.push(i18n.subscribe(() => this.render()))
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
if (this.unsubscribe) this.unsubscribe()
|
||||
this._unsubs.forEach(fn => fn())
|
||||
this._unsubs = []
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
Reference in New Issue
Block a user