feat: implement seller-join flow for E2E chat with pending conversation discovery

This commit is contained in:
2026-02-08 14:50:23 +01:00
parent 2f1ef2e725
commit d1375b2dcf
12 changed files with 317 additions and 96 deletions

View File

@@ -1,6 +1,7 @@
import { t, i18n } from '../../i18n.js'
import { directus } from '../../services/directus.js'
import { auth } from '../../services/auth.js'
import { conversationsService } from '../../services/conversations.js'
import { favoritesService } from '../../services/favorites.js'
import { getXmrRates, formatPrice as formatCurrencyPrice } from '../../services/currency.js'
import { escapeHTML } from '../../utils/helpers.js'
@@ -18,6 +19,7 @@ class PageListing extends HTMLElement {
this.isFavorite = false
this.rates = null
this.isOwner = false
this.hasPendingChats = false
this.handleCurrencyChange = this.handleCurrencyChange.bind(this)
}
@@ -58,6 +60,11 @@ class PageListing extends HTMLElement {
}
}
// Check for pending chats if owner
if (this.isOwner) {
this.hasPendingChats = await this.checkPendingChats()
}
// Load other listings from same seller
if (this.listing?.user_created) {
await this.loadSellerListings()
@@ -138,6 +145,23 @@ class PageListing extends HTMLElement {
}
}
async checkPendingChats() {
try {
const response = await directus.get('/items/conversations', {
fields: ['id'],
filter: {
listing_id: { _eq: this.listingId },
status: { _eq: 'pending' },
participant_hash_2: { _null: true }
},
limit: 1
})
return (response.data?.length || 0) > 0
} catch {
return false
}
}
async loadSellerListings() {
try {
const response = await directus.getListings({
@@ -348,6 +372,15 @@ class PageListing extends HTMLElement {
</svg>
${t('listing.edit')}
</a>
${this.hasPendingChats ? /* html */`
<button class="btn btn-outline btn-lg sidebar-btn" id="contact-btn">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
</svg>
${t('listing.newMessages')}
</button>
` : ''}
<div class="sidebar-actions">
<button class="action-btn" id="share-btn" title="${t('listing.share')}">
@@ -450,7 +483,6 @@ class PageListing extends HTMLElement {
<div class="tab-content" id="tab-chat">
<chat-widget
listing-id="${this.listing?.id || ''}"
seller-public-key="${this.listing?.seller_public_key || ''}"
recipient-name="${t('listing.anonymousSeller')}"
></chat-widget>
</div>
@@ -501,11 +533,19 @@ class PageListing extends HTMLElement {
setupEventListeners() {
// Contact dialog
const contactBtn = this.querySelector('#contact-btn')
const dialog = this.querySelector('#contact-dialog')
const closeBtn = this.querySelector('#dialog-close')
contactBtn?.addEventListener('click', () => dialog?.showModal())
this.querySelectorAll('#contact-btn').forEach(btn => {
btn.addEventListener('click', () => {
if (!auth.isLoggedIn()) {
document.querySelector('auth-modal')?.show()
return
}
dialog?.showModal()
this.querySelector('chat-widget')?.activate()
})
})
closeBtn?.addEventListener('click', () => dialog?.close())
dialog?.addEventListener('click', (e) => {
if (e.target === dialog) dialog.close()