fix: auto-open chat with conversation ID, show listing title and time in messages
This commit is contained in:
@@ -12,7 +12,7 @@ import { reputationService } from '../services/reputation.js'
|
|||||||
|
|
||||||
class ChatWidget extends HTMLElement {
|
class ChatWidget extends HTMLElement {
|
||||||
static get observedAttributes() {
|
static get observedAttributes() {
|
||||||
return ['listing-id', 'recipient-name', 'seller-public-key']
|
return ['listing-id', 'recipient-name', 'seller-public-key', 'conversation-id']
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -33,6 +33,7 @@ class ChatWidget extends HTMLElement {
|
|||||||
this.listingId = this.getAttribute('listing-id')
|
this.listingId = this.getAttribute('listing-id')
|
||||||
this.recipientName = this.getAttribute('recipient-name') || 'Seller'
|
this.recipientName = this.getAttribute('recipient-name') || 'Seller'
|
||||||
this.sellerPublicKey = this.getAttribute('seller-public-key')
|
this.sellerPublicKey = this.getAttribute('seller-public-key')
|
||||||
|
this.conversationId = this.getAttribute('conversation-id')
|
||||||
this.render()
|
this.render()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,6 +46,7 @@ class ChatWidget extends HTMLElement {
|
|||||||
if (this._initialized) return
|
if (this._initialized) return
|
||||||
this._initialized = true
|
this._initialized = true
|
||||||
|
|
||||||
|
this.conversationId = this.getAttribute('conversation-id') || this.conversationId
|
||||||
await cryptoService.ready
|
await cryptoService.ready
|
||||||
|
|
||||||
if (!cryptoService.getPublicKey()) {
|
if (!cryptoService.getPublicKey()) {
|
||||||
@@ -68,26 +70,39 @@ class ChatWidget extends HTMLElement {
|
|||||||
|
|
||||||
async initConversation() {
|
async initConversation() {
|
||||||
try {
|
try {
|
||||||
if (!this.sellerPublicKey) {
|
if (this.conversationId) {
|
||||||
this.error = 'no-seller-key'
|
this.conversation = await conversationsService.getConversation(this.conversationId)
|
||||||
this.loading = false
|
if (!this.conversation) {
|
||||||
this.render()
|
this.error = 'init-failed'
|
||||||
return
|
this.loading = false
|
||||||
}
|
this.render()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.mySecretKey = await conversationsService.getMySecretKeyForConversation(this.conversation)
|
||||||
|
await this.loadMessages()
|
||||||
|
await this.loadDealState()
|
||||||
|
} else {
|
||||||
|
if (!this.sellerPublicKey) {
|
||||||
|
this.error = 'no-seller-key'
|
||||||
|
this.loading = false
|
||||||
|
this.render()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const pinStatus = keyPinningService.check(this.listingId, this.sellerPublicKey)
|
const pinStatus = keyPinningService.check(this.listingId, this.sellerPublicKey)
|
||||||
if (pinStatus === 'changed') {
|
if (pinStatus === 'changed') {
|
||||||
this.keyWarning = true
|
this.keyWarning = true
|
||||||
this.loading = false
|
this.loading = false
|
||||||
this.render()
|
this.render()
|
||||||
this.setupEventListeners()
|
this.setupEventListeners()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.conversation = await conversationsService.startOrGetConversation(this.listingId, this.sellerPublicKey)
|
this.conversation = await conversationsService.startOrGetConversation(this.listingId, this.sellerPublicKey)
|
||||||
this.mySecretKey = await conversationsService.getMySecretKeyForConversation(this.conversation)
|
this.mySecretKey = await conversationsService.getMySecretKeyForConversation(this.conversation)
|
||||||
await this.loadMessages()
|
await this.loadMessages()
|
||||||
await this.loadDealState()
|
await this.loadDealState()
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to init conversation:', e)
|
console.error('Failed to init conversation:', e)
|
||||||
this.error = 'init-failed'
|
this.error = 'init-failed'
|
||||||
|
|||||||
@@ -75,6 +75,16 @@ class PageListing extends HTMLElement {
|
|||||||
this.render()
|
this.render()
|
||||||
this.setupEventListeners()
|
this.setupEventListeners()
|
||||||
this.updateMetaTags()
|
this.updateMetaTags()
|
||||||
|
|
||||||
|
if (this.dataset.chat && auth.isLoggedIn()) {
|
||||||
|
const chatWidget = this.querySelector('chat-widget')
|
||||||
|
if (this.dataset.chat !== '1') {
|
||||||
|
chatWidget?.setAttribute('conversation-id', this.dataset.chat)
|
||||||
|
}
|
||||||
|
const dialog = this.querySelector('#contact-dialog')
|
||||||
|
dialog?.showModal()
|
||||||
|
chatWidget?.activate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateMetaTags() {
|
updateMetaTags() {
|
||||||
|
|||||||
@@ -51,6 +51,17 @@ class PageMessages extends HTMLElement {
|
|||||||
|
|
||||||
const conversations = await conversationsService.getMyConversations()
|
const conversations = await conversationsService.getMyConversations()
|
||||||
this.conversations = conversations || []
|
this.conversations = conversations || []
|
||||||
|
|
||||||
|
const missing = this.conversations.filter(c => typeof c.listing_id !== 'object')
|
||||||
|
if (missing.length > 0) {
|
||||||
|
await Promise.all(missing.map(async conv => {
|
||||||
|
try {
|
||||||
|
const listing = await directus.getListing(conv.listing_id)
|
||||||
|
if (listing) conv.listing_id = listing
|
||||||
|
} catch { /* listing may not be accessible */ }
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
this.loading = false
|
this.loading = false
|
||||||
this.updateContent()
|
this.updateContent()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -139,11 +150,13 @@ class PageMessages extends HTMLElement {
|
|||||||
const listingId = listing?.id || conv.listing_id
|
const listingId = listing?.id || conv.listing_id
|
||||||
const imageId = listing?.images?.[0]?.directus_files_id?.id
|
const imageId = listing?.images?.[0]?.directus_files_id?.id
|
||||||
const imageUrl = imageId ? directus.getThumbnailUrl(imageId, 80) : ''
|
const imageUrl = imageId ? directus.getThumbnailUrl(imageId, 80) : ''
|
||||||
const title = listing?.status === 'deleted' ? t('messages.listingRemoved') : (listing?.title || t('messages.unknownListing'))
|
const title = listing?.status === 'deleted'
|
||||||
|
? t('messages.listingRemoved')
|
||||||
|
: (listing?.title || t('messages.listing'))
|
||||||
const dateStr = this.formatDate(conv.date_updated || conv.date_created)
|
const dateStr = this.formatDate(conv.date_updated || conv.date_created)
|
||||||
|
|
||||||
return /* html */`
|
return /* html */`
|
||||||
<a href="#/listing/${listingId}" class="conversation-item" data-conv-id="${conv.id}">
|
<a href="#/listing/${listingId}?chat=${conv.id}" class="conversation-item" data-conv-id="${conv.id}">
|
||||||
<div class="conversation-image">
|
<div class="conversation-image">
|
||||||
${imageUrl
|
${imageUrl
|
||||||
? `<img src="${imageUrl}" alt="" loading="lazy">`
|
? `<img src="${imageUrl}" alt="" loading="lazy">`
|
||||||
@@ -165,7 +178,7 @@ class PageMessages extends HTMLElement {
|
|||||||
const diffMs = now - date
|
const diffMs = now - date
|
||||||
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24))
|
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24))
|
||||||
|
|
||||||
if (diffDays === 0) return t('messages.today')
|
if (diffDays === 0) return `${t('messages.today')}, ${date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}`
|
||||||
if (diffDays === 1) return t('messages.yesterday')
|
if (diffDays === 1) return t('messages.yesterday')
|
||||||
if (diffDays < 7) return t('messages.daysAgo', { days: diffDays })
|
if (diffDays < 7) return t('messages.daysAgo', { days: diffDays })
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,12 @@ class ConversationsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
conversations.sort((a, b) => {
|
||||||
|
const da = new Date(b.date_updated || b.date_created)
|
||||||
|
const db = new Date(a.date_updated || a.date_created)
|
||||||
|
return da - db
|
||||||
|
})
|
||||||
|
|
||||||
return conversations.map(conv => {
|
return conversations.map(conv => {
|
||||||
const isP1 = allHashes.has(conv.participant_hash_1)
|
const isP1 = allHashes.has(conv.participant_hash_1)
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -257,6 +257,7 @@
|
|||||||
"loginHint": "Melde dich an, um deine Nachrichten zu sehen.",
|
"loginHint": "Melde dich an, um deine Nachrichten zu sehen.",
|
||||||
"login": "Anmelden",
|
"login": "Anmelden",
|
||||||
"unknownListing": "Unbekannte Anzeige",
|
"unknownListing": "Unbekannte Anzeige",
|
||||||
|
"listing": "Anzeige",
|
||||||
"today": "Heute",
|
"today": "Heute",
|
||||||
"yesterday": "Gestern",
|
"yesterday": "Gestern",
|
||||||
"daysAgo": "Vor {{days}} Tagen",
|
"daysAgo": "Vor {{days}} Tagen",
|
||||||
|
|||||||
@@ -257,6 +257,7 @@
|
|||||||
"loginHint": "Log in to see your messages.",
|
"loginHint": "Log in to see your messages.",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"unknownListing": "Unknown listing",
|
"unknownListing": "Unknown listing",
|
||||||
|
"listing": "Listing",
|
||||||
"today": "Today",
|
"today": "Today",
|
||||||
"yesterday": "Yesterday",
|
"yesterday": "Yesterday",
|
||||||
"daysAgo": "{{days}} days ago",
|
"daysAgo": "{{days}} days ago",
|
||||||
|
|||||||
@@ -257,6 +257,7 @@
|
|||||||
"loginHint": "Inicia sesión para ver tus mensajes.",
|
"loginHint": "Inicia sesión para ver tus mensajes.",
|
||||||
"login": "Iniciar sesión",
|
"login": "Iniciar sesión",
|
||||||
"unknownListing": "Anuncio desconocido",
|
"unknownListing": "Anuncio desconocido",
|
||||||
|
"listing": "Anuncio",
|
||||||
"today": "Hoy",
|
"today": "Hoy",
|
||||||
"yesterday": "Ayer",
|
"yesterday": "Ayer",
|
||||||
"daysAgo": "Hace {{days}} días",
|
"daysAgo": "Hace {{days}} días",
|
||||||
|
|||||||
@@ -257,6 +257,7 @@
|
|||||||
"loginHint": "Connectez-vous pour voir vos messages.",
|
"loginHint": "Connectez-vous pour voir vos messages.",
|
||||||
"login": "Connexion",
|
"login": "Connexion",
|
||||||
"unknownListing": "Annonce inconnue",
|
"unknownListing": "Annonce inconnue",
|
||||||
|
"listing": "Annonce",
|
||||||
"today": "Aujourd'hui",
|
"today": "Aujourd'hui",
|
||||||
"yesterday": "Hier",
|
"yesterday": "Hier",
|
||||||
"daysAgo": "Il y a {{days}} jours",
|
"daysAgo": "Il y a {{days}} jours",
|
||||||
|
|||||||
@@ -257,6 +257,7 @@
|
|||||||
"loginHint": "Accedi per vedere i tuoi messaggi.",
|
"loginHint": "Accedi per vedere i tuoi messaggi.",
|
||||||
"login": "Accedi",
|
"login": "Accedi",
|
||||||
"unknownListing": "Annuncio sconosciuto",
|
"unknownListing": "Annuncio sconosciuto",
|
||||||
|
"listing": "Annuncio",
|
||||||
"today": "Oggi",
|
"today": "Oggi",
|
||||||
"yesterday": "Ieri",
|
"yesterday": "Ieri",
|
||||||
"daysAgo": "{{days}} giorni fa",
|
"daysAgo": "{{days}} giorni fa",
|
||||||
|
|||||||
@@ -257,6 +257,7 @@
|
|||||||
"loginHint": "Faça login para ver suas mensagens.",
|
"loginHint": "Faça login para ver suas mensagens.",
|
||||||
"login": "Entrar",
|
"login": "Entrar",
|
||||||
"unknownListing": "Anúncio desconhecido",
|
"unknownListing": "Anúncio desconhecido",
|
||||||
|
"listing": "Anúncio",
|
||||||
"today": "Hoje",
|
"today": "Hoje",
|
||||||
"yesterday": "Ontem",
|
"yesterday": "Ontem",
|
||||||
"daysAgo": "{{days}} dias atrás",
|
"daysAgo": "{{days}} dias atrás",
|
||||||
|
|||||||
@@ -257,6 +257,7 @@
|
|||||||
"loginHint": "Войдите, чтобы увидеть свои сообщения.",
|
"loginHint": "Войдите, чтобы увидеть свои сообщения.",
|
||||||
"login": "Войти",
|
"login": "Войти",
|
||||||
"unknownListing": "Неизвестное объявление",
|
"unknownListing": "Неизвестное объявление",
|
||||||
|
"listing": "Объявление",
|
||||||
"today": "Сегодня",
|
"today": "Сегодня",
|
||||||
"yesterday": "Вчера",
|
"yesterday": "Вчера",
|
||||||
"daysAgo": "{{days}} дн. назад",
|
"daysAgo": "{{days}} дн. назад",
|
||||||
|
|||||||
Reference in New Issue
Block a user