mirror of
https://github.com/Permissionless-Software-Foundation/bch-dex-taker-v2.git
synced 2026-09-21 16:52:01 -07:00
Merge pull request #59 from Permissionless-Software-Foundation/dh-channel-pfp
feat(nostr): Added channel PFPs
This commit is contained in:
@@ -38,6 +38,7 @@ export default function ChannelItem (props) {
|
||||
>
|
||||
{chInfo?.name &&
|
||||
<div className='d-flex align-items-center'>
|
||||
{chInfo.picture && <img src={chInfo.picture} alt={chInfo.name} style={{ width: '30px', marginRight: '5px' }} />}
|
||||
<span
|
||||
className='fw-medium'
|
||||
style={{
|
||||
|
||||
@@ -26,9 +26,13 @@ function ChatHeader (props) {
|
||||
return (
|
||||
<div className='p-3 d-flex justify-content-between align-items-center' style={{ backgroundColor: '#ffffff' }}>
|
||||
{chInfo &&
|
||||
<div className='d-flex justify-content-center align-items-center'>
|
||||
{chInfo.picture && <img src={chInfo.picture} alt={chInfo.name} style={{ width: '50px', marginRight: '5px' }} />}
|
||||
<div className='flex-grow-1'>
|
||||
<h5 className='mb-1 text-dark'>{chInfo?.name || getShortName(selectedChannel)}</h5>
|
||||
<small className='text-muted'>{chInfo?.about || ''}</small>
|
||||
</div>
|
||||
|
||||
</div>}
|
||||
|
||||
{!chInfo &&
|
||||
|
||||
@@ -19,6 +19,7 @@ function NostrChat (props) {
|
||||
const [loadedMessages, setLoadedMessages] = useState(false)
|
||||
const [profiles, setProfiles] = useState({})
|
||||
const [channelsData, setChannelsData] = useState({})
|
||||
const [channelsLoaded, setChannelsLoaded] = useState(false)
|
||||
const [channels] = useState(config.chatsId)
|
||||
|
||||
const [selectedChannel, setSelectedChannel] = useState(config.chatsId[0])
|
||||
@@ -50,10 +51,14 @@ function NostrChat (props) {
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch profile.
|
||||
let profile = await appData.nostrQueries.getProfile(pubKey)
|
||||
if (!profile) profile = { name: pubKey }
|
||||
console.log(`Trying to get ${pubKey} profile.`)
|
||||
|
||||
const defaultProfile = { name: pubKey } // default profile
|
||||
profilesRef.current[pubKey] = defaultProfile // update ref , to prevent fetch this profile again.
|
||||
// Fetch profile
|
||||
const nostrProfile = await appData.nostrQueries.getProfile(pubKey)
|
||||
|
||||
const profile = nostrProfile || defaultProfile
|
||||
// Update profiles state
|
||||
setProfiles(currentProfiles => {
|
||||
const newProfiles = { ...currentProfiles }
|
||||
@@ -68,7 +73,8 @@ function NostrChat (props) {
|
||||
|
||||
// Handle nostr pool
|
||||
useEffect(() => {
|
||||
if (!selectedChannel) return
|
||||
// fetch messages when channel selected and channel metadata are loaded
|
||||
if (!selectedChannel || !channelsLoaded) return
|
||||
|
||||
const relays = nostrQueries.relays
|
||||
if (relays.length === 0) {
|
||||
@@ -96,7 +102,7 @@ function NostrChat (props) {
|
||||
console.log('Close existing pool')
|
||||
pool.close()
|
||||
}
|
||||
}, [onMsgRead, selectedChannel, nostrQueries])
|
||||
}, [onMsgRead, selectedChannel, nostrQueries, channelsLoaded])
|
||||
|
||||
// Load channels data
|
||||
useEffect(() => {
|
||||
@@ -120,6 +126,7 @@ function NostrChat (props) {
|
||||
newChs[ch] = channelData
|
||||
return newChs
|
||||
})
|
||||
setChannelsLoaded(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,17 +3,16 @@
|
||||
*/
|
||||
|
||||
// Global npm libraries
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faUser } from '@fortawesome/free-solid-svg-icons'
|
||||
import { Spinner } from 'react-bootstrap'
|
||||
import NostrFormat from '../../app-body/nostr/nostr-format'
|
||||
|
||||
function MessageItem (props) {
|
||||
const { message, profiles } = props
|
||||
const [profile, setProfile] = useState(null)
|
||||
|
||||
const msgRef = useRef(null)
|
||||
|
||||
// Format timestamp
|
||||
const formatTime = (timestamp) => {
|
||||
return new Date(timestamp).toLocaleTimeString([], {
|
||||
@@ -29,17 +28,8 @@ function MessageItem (props) {
|
||||
}
|
||||
}, [profiles, message, profile])
|
||||
|
||||
useEffect(() => {
|
||||
if (msgRef.current && message.latest) {
|
||||
msgRef.current.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'end'
|
||||
})
|
||||
}
|
||||
}, [message])
|
||||
|
||||
return (
|
||||
<div className='mb-3 d-flex align-items-start' ref={msgRef}>
|
||||
<div className='mb-3 d-flex align-items-start'>
|
||||
{/* Message Content */}
|
||||
<div className='flex-grow-1'>
|
||||
<div
|
||||
@@ -81,7 +71,7 @@ function MessageItem (props) {
|
||||
}}
|
||||
/>}
|
||||
</div>
|
||||
{!profile && <span className='fw-bold text-dark me-2'>{message.pubkey}</span>}
|
||||
{!profile && <span className='fw-bold text-dark me-2'>{message.pubkey}<Spinner animation='border' size='sm' /></span>}
|
||||
{profile && profile.name && <span className='fw-bold text-dark me-2'>{profile.name}</span>}
|
||||
|
||||
<small className='text-muted'>{formatTime(message.created_at * 1000)}</small>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
// Global npm libraries
|
||||
import React, { useEffect, useState, useCallback } from 'react'
|
||||
import React, { useEffect, useState, useCallback, useRef } from 'react'
|
||||
|
||||
// Local libraries
|
||||
import MessageItem from './message-item'
|
||||
@@ -13,12 +13,11 @@ import { Spinner } from 'react-bootstrap'
|
||||
function MessageList (props) {
|
||||
const { messages, loadedMessages } = props
|
||||
const [groupedMessages, setGroupedMessages] = useState([])
|
||||
|
||||
const msgContainerRef = useRef()
|
||||
// Group messages by date
|
||||
const groupMessagesByDate = useCallback((messages) => {
|
||||
const grouped = {}
|
||||
messages.forEach((message, i) => {
|
||||
if (i === messages.length - 1) message.latest = true
|
||||
const date = new Date(message.created_at * 1000).toDateString()
|
||||
if (!grouped[date]) {
|
||||
grouped[date] = []
|
||||
@@ -33,6 +32,18 @@ function MessageList (props) {
|
||||
const grouped = groupMessagesByDate(messages)
|
||||
|
||||
setGroupedMessages(grouped)
|
||||
|
||||
// Scroll to end of the message container.
|
||||
// Wait few seconds before load render.
|
||||
setTimeout(() => {
|
||||
if (msgContainerRef.current) {
|
||||
msgContainerRef.current.scrollTo({
|
||||
top: msgContainerRef.current.scrollHeight - msgContainerRef.current.clientHeight,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
msgContainerRef.current = null // scroll one time
|
||||
}
|
||||
}, 1000)
|
||||
}, [messages, groupMessagesByDate])
|
||||
|
||||
return (
|
||||
@@ -66,7 +77,7 @@ function MessageList (props) {
|
||||
)}
|
||||
|
||||
{loadedMessages && messages && messages.length > 0 && (
|
||||
<div className='p-3' style={{ overflowY: 'auto', maxHeight: '50vh' }}>
|
||||
<div ref={msgContainerRef} className='p-3' style={{ overflowY: 'auto', maxHeight: '50vh' }}>
|
||||
{Object.entries(groupedMessages).map(([date, dateMessages]) => (
|
||||
<div key={date}>
|
||||
<DateSeparator date={date} />
|
||||
|
||||
@@ -54,6 +54,7 @@ export default class NostrQueries {
|
||||
relay.close()
|
||||
})
|
||||
pool.on('error', (relay) => {
|
||||
console.log(`Error fetching ${pubHex} profile. relay connection error :${relay.url} `)
|
||||
relay.close()
|
||||
resolve(false)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user