diff --git a/js/components/chat-widget.js b/js/components/chat-widget.js index eed092e..dcf76cb 100644 --- a/js/components/chat-widget.js +++ b/js/components/chat-widget.js @@ -12,7 +12,7 @@ import { reputationService } from '../services/reputation.js' class ChatWidget extends HTMLElement { static get observedAttributes() { - return ['listing-id', 'recipient-name', 'seller-public-key'] + return ['listing-id', 'recipient-name', 'seller-public-key', 'conversation-id'] } constructor() { @@ -33,6 +33,7 @@ class ChatWidget extends HTMLElement { this.listingId = this.getAttribute('listing-id') this.recipientName = this.getAttribute('recipient-name') || 'Seller' this.sellerPublicKey = this.getAttribute('seller-public-key') + this.conversationId = this.getAttribute('conversation-id') this.render() } @@ -45,6 +46,7 @@ class ChatWidget extends HTMLElement { if (this._initialized) return this._initialized = true + this.conversationId = this.getAttribute('conversation-id') || this.conversationId await cryptoService.ready if (!cryptoService.getPublicKey()) { @@ -68,26 +70,39 @@ class ChatWidget extends HTMLElement { async initConversation() { try { - if (!this.sellerPublicKey) { - this.error = 'no-seller-key' - this.loading = false - this.render() - return - } + if (this.conversationId) { + this.conversation = await conversationsService.getConversation(this.conversationId) + if (!this.conversation) { + this.error = 'init-failed' + 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) - if (pinStatus === 'changed') { - this.keyWarning = true - this.loading = false - this.render() - this.setupEventListeners() - return - } + const pinStatus = keyPinningService.check(this.listingId, this.sellerPublicKey) + if (pinStatus === 'changed') { + this.keyWarning = true + this.loading = false + this.render() + this.setupEventListeners() + return + } - this.conversation = await conversationsService.startOrGetConversation(this.listingId, this.sellerPublicKey) - this.mySecretKey = await conversationsService.getMySecretKeyForConversation(this.conversation) - await this.loadMessages() - await this.loadDealState() + this.conversation = await conversationsService.startOrGetConversation(this.listingId, this.sellerPublicKey) + this.mySecretKey = await conversationsService.getMySecretKeyForConversation(this.conversation) + await this.loadMessages() + await this.loadDealState() + } } catch (e) { console.error('Failed to init conversation:', e) this.error = 'init-failed' diff --git a/js/components/pages/page-listing.js b/js/components/pages/page-listing.js index a28fcec..923603a 100644 --- a/js/components/pages/page-listing.js +++ b/js/components/pages/page-listing.js @@ -75,6 +75,16 @@ class PageListing extends HTMLElement { this.render() this.setupEventListeners() 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() { diff --git a/js/components/pages/page-messages.js b/js/components/pages/page-messages.js index 753d461..ae81029 100644 --- a/js/components/pages/page-messages.js +++ b/js/components/pages/page-messages.js @@ -51,6 +51,17 @@ class PageMessages extends HTMLElement { const conversations = await conversationsService.getMyConversations() 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.updateContent() } catch (err) { @@ -139,11 +150,13 @@ class PageMessages extends HTMLElement { const listingId = listing?.id || conv.listing_id const imageId = listing?.images?.[0]?.directus_files_id?.id 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) return /* html */` - +
${imageUrl ? `` @@ -165,7 +178,7 @@ class PageMessages extends HTMLElement { const diffMs = now - date 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 < 7) return t('messages.daysAgo', { days: diffDays }) diff --git a/js/services/conversations.js b/js/services/conversations.js index c7981cf..09510cd 100644 --- a/js/services/conversations.js +++ b/js/services/conversations.js @@ -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 => { const isP1 = allHashes.has(conv.participant_hash_1) return { diff --git a/locales/de.json b/locales/de.json index c971a35..1e95584 100644 --- a/locales/de.json +++ b/locales/de.json @@ -257,6 +257,7 @@ "loginHint": "Melde dich an, um deine Nachrichten zu sehen.", "login": "Anmelden", "unknownListing": "Unbekannte Anzeige", + "listing": "Anzeige", "today": "Heute", "yesterday": "Gestern", "daysAgo": "Vor {{days}} Tagen", diff --git a/locales/en.json b/locales/en.json index 62e0e6b..3da7279 100644 --- a/locales/en.json +++ b/locales/en.json @@ -257,6 +257,7 @@ "loginHint": "Log in to see your messages.", "login": "Login", "unknownListing": "Unknown listing", + "listing": "Listing", "today": "Today", "yesterday": "Yesterday", "daysAgo": "{{days}} days ago", diff --git a/locales/es.json b/locales/es.json index 1ba3fe3..29c3c23 100644 --- a/locales/es.json +++ b/locales/es.json @@ -257,6 +257,7 @@ "loginHint": "Inicia sesión para ver tus mensajes.", "login": "Iniciar sesión", "unknownListing": "Anuncio desconocido", + "listing": "Anuncio", "today": "Hoy", "yesterday": "Ayer", "daysAgo": "Hace {{days}} días", diff --git a/locales/fr.json b/locales/fr.json index 14daee3..a9d3a9a 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -257,6 +257,7 @@ "loginHint": "Connectez-vous pour voir vos messages.", "login": "Connexion", "unknownListing": "Annonce inconnue", + "listing": "Annonce", "today": "Aujourd'hui", "yesterday": "Hier", "daysAgo": "Il y a {{days}} jours", diff --git a/locales/it.json b/locales/it.json index 9fd1b63..5704dcc 100644 --- a/locales/it.json +++ b/locales/it.json @@ -257,6 +257,7 @@ "loginHint": "Accedi per vedere i tuoi messaggi.", "login": "Accedi", "unknownListing": "Annuncio sconosciuto", + "listing": "Annuncio", "today": "Oggi", "yesterday": "Ieri", "daysAgo": "{{days}} giorni fa", diff --git a/locales/pt.json b/locales/pt.json index b10e07c..101938e 100644 --- a/locales/pt.json +++ b/locales/pt.json @@ -257,6 +257,7 @@ "loginHint": "Faça login para ver suas mensagens.", "login": "Entrar", "unknownListing": "Anúncio desconhecido", + "listing": "Anúncio", "today": "Hoje", "yesterday": "Ontem", "daysAgo": "{{days}} dias atrás", diff --git a/locales/ru.json b/locales/ru.json index d8e340d..47004e8 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -257,6 +257,7 @@ "loginHint": "Войдите, чтобы увидеть свои сообщения.", "login": "Войти", "unknownListing": "Неизвестное объявление", + "listing": "Объявление", "today": "Сегодня", "yesterday": "Вчера", "daysAgo": "{{days}} дн. назад",