1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-12-02 05:57:29 +01:00

revisions

This commit is contained in:
marcoelissa 2023-01-10 04:51:22 +07:00
parent 9c364e34e6
commit 06b0244172
10 changed files with 176 additions and 131 deletions

View File

@ -11,14 +11,13 @@ import { useInterval } from '@hooks/useInterval'
import { Orbis } from '@orbisclub/orbis-sdk'
import { useWeb3 } from './Web3'
import { accountTruncate } from '@utils/web3'
import { didToAddress } from '@utils/orbis'
import { didToAddress, sleep } from '@utils/orbis'
import { getEnsName } from '@utils/ens'
import usePrevious from '@hooks/usePrevious'
import useLocalStorage from '@hooks/useLocalStorage'
import DirectMessages from '@shared/Orbis/DirectMessages'
interface INewConversation {
name: string | null
recipients: string[]
}
@ -51,8 +50,8 @@ type IOrbisProvider = {
setNewConversation: (newConversation: INewConversation) => void
setOpenConversations: (open: boolean) => void
setConversationId: (conversationId: string) => void
getConversation: (userDid: string) => Promise<IOrbisConversation>
createConversation: (userDid: string) => Promise<void>
getConversationByDid: (userDid: string) => Promise<IOrbisConversation>
createConversation: (recipients: string[]) => Promise<IOrbisConversation>
clearMessageNotifs: (conversationId: string) => void
getConversationTitle: (conversationId: string) => Promise<string>
getDid: (address: string) => Promise<string>
@ -62,7 +61,8 @@ const OrbisContext = createContext({} as IOrbisProvider)
const orbis: IOrbis = new Orbis()
const NOTIFICATION_REFRESH_INTERVAL = 5000
const CONVERSATION_CONTEXT = 'ocean_market' // Can be changed to whatever
const CONVERSATION_CONTEXT =
process.env.NEXT_PUBLIC_ORBIS_CONTEXT || 'ocean_market' // Can be changed to whatever
function OrbisProvider({ children }: { children: ReactNode }): ReactElement {
const { web3Provider, accountId } = useWeb3()
@ -312,16 +312,23 @@ function OrbisProvider({ children }: { children: ReactNode }): ReactElement {
return filteredConversations
}
const getConversation = async (userDid: string) => {
if (!account || !userDid) return null
const getConversation = async (conversationId: string) => {
if (!conversationId) return null
const { data, error } = await orbis.getConversation(conversationId)
if (error || !data) {
await sleep(2000)
await getConversation(conversationId)
} else {
return data
}
}
console.log('has account and target userDid')
const getConversationByDid = async (userDid: string) => {
if (!account || !userDid) return null
const _conversations = await getConversations(account?.did)
if (!_conversations.length) return null
console.log('has conversations')
const filteredConversations = _conversations.filter(
(conversation: IOrbisConversation) => {
return (
@ -333,67 +340,28 @@ function OrbisProvider({ children }: { children: ReactNode }): ReactElement {
if (!filteredConversations.length) return null
console.log('has filtered conversations')
return filteredConversations[0]
}
const createConversation = async (userDid: string) => {
let _account = account
if (!_account) {
// Check connection and force connect
_account = await checkOrbisConnection({
address: accountId,
autoConnect: true
})
}
const createConversation = async (recipients: string[]) => {
if (!recipients.length) return null
if (!hasLit) {
const res = await connectLit()
if (res.status !== 200) {
alert('Error connecting to Lit.')
return
}
}
const res = await orbis.createConversation({
recipients,
context: CONVERSATION_CONTEXT
})
let existingConversation = conversations.find(
(conversation: IOrbisConversation) => {
return conversation.recipients.includes(userDid)
}
)
// Refetch to make sure we have the latest conversations
if (!existingConversation) {
const _conversations = await getConversations(_account?.did)
existingConversation = _conversations.find(
(conversation: IOrbisConversation) => {
return conversation.recipients.includes(userDid)
}
)
}
if (existingConversation) {
setConversationId(existingConversation.stream_id)
setOpenConversations(true)
} else {
const res = await orbis.createConversation({
recipients: [userDid],
context: CONVERSATION_CONTEXT
})
if (res.status === 200) {
setTimeout(async () => {
const { data, error } = await orbis.getConversation(res.doc)
if (!error && data) {
setConversations([data, ...conversations])
}
setConversationId(res.doc)
setOpenConversations(true)
}, 2000)
if (res.status === 200) {
await sleep(2000)
const _newConversation = await getConversation(res.doc)
if (_newConversation) {
setConversations([_newConversation, ...conversations])
return _newConversation
}
}
}
// const createConversationV2 = async (userDid: string) => {
// const createConversation = async (userDid: string) => {
// let _account = account
// if (!_account) {
// // Check connection and force connect
@ -411,14 +379,22 @@ function OrbisProvider({ children }: { children: ReactNode }): ReactElement {
// }
// }
// // Refetch to make sure we have the latest conversations
// const _conversations = await getConversations(_account?.did)
// const existingConversation = _conversations.find(
// let existingConversation = conversations.find(
// (conversation: IOrbisConversation) => {
// return conversation.recipients.includes(userDid)
// }
// )
// // Refetch to make sure we have the latest conversations
// if (!existingConversation) {
// const _conversations = await getConversations(_account?.did)
// existingConversation = _conversations.find(
// (conversation: IOrbisConversation) => {
// return conversation.recipients.includes(userDid)
// }
// )
// }
// if (existingConversation) {
// setConversationId(existingConversation.stream_id)
// setOpenConversations(true)
@ -492,10 +468,6 @@ function OrbisProvider({ children }: { children: ReactNode }): ReactElement {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [account])
useEffect(() => {
console.log({ newConversation, activeConversationTitle })
}, [newConversation, activeConversationTitle])
return (
<OrbisContext.Provider
value={{
@ -516,7 +488,7 @@ function OrbisProvider({ children }: { children: ReactNode }): ReactElement {
setNewConversation,
setOpenConversations,
setConversationId,
getConversation,
getConversationByDid,
createConversation,
clearMessageNotifs,
getConversationTitle,

View File

@ -91,3 +91,6 @@ export function formatMessage(
return body
}
export const sleep = (ms: number) =>
new Promise((resolve) => setTimeout(resolve, ms))

View File

@ -45,6 +45,10 @@
font-size: var(--font-size-mini);
}
.btnOptions {
cursor: pointer;
}
.blockies {
aspect-ratio: 1/1;
flex-shrink: 0;

View File

@ -142,8 +142,8 @@ export default function Post({
<Avatar accountId={address} className={styles.blockies} />
<div className={styles.content}>
<div className={styles.profile}>
<Link href={`/profile/${address}`}>
<a className={styles.name}>{accountTruncate(address)}</a>
<Link href={`/profile/${address}`} className={styles.name}>
{accountTruncate(address)}
</Link>
<span>&bull;</span>
<div className={styles.metadata}>
@ -168,6 +168,7 @@ export default function Post({
context={postClone?.context}
editPost={postClone}
callback={callbackEdit}
cancelEdit={() => setIsEditing(false)}
/>
)}
{hideOverflow && (
@ -219,15 +220,12 @@ export default function Post({
</button>
</div>
}
trigger="click"
zIndex={21}
placement={'top'}
className={styles.btnOptions}
>
<button
title="Options"
onClick={() => console.log('clicked')}
>
<Ellipsis role="img" aria-label="Options" />
</button>
<Ellipsis role="img" aria-label="Options" />
</Tooltip>
</div>
)}

View File

@ -38,6 +38,27 @@
text-align: right;
}
.postbox .editActions {
display: flex;
gap: calc(var(--spacer) / 4);
}
.postbox .editActions button {
background: transparent;
border: 0;
padding: 0;
cursor: pointer;
outline: none;
}
.postbox .cancelEdit {
color: var(--color-secondary);
}
.postbox .saveEdit {
color: var(--color-primary);
}
.connectWallet {
width: 100%;
display: flex;

View File

@ -1,4 +1,4 @@
import React, { useRef, useState, KeyboardEvent } from 'react'
import React, { useRef, useState, useEffect, KeyboardEvent } from 'react'
import styles from './Postbox.module.css'
import walletStyles from '../../../Header/Wallet/Account.module.css'
import { EmojiClickData } from 'emoji-picker-react'
@ -16,6 +16,7 @@ export default function Postbox({
editPost = null,
enterToSend = false,
cancelReplyTo,
cancelEdit,
callback
}: {
context: string
@ -24,6 +25,7 @@ export default function Postbox({
editPost?: IOrbisPost
enterToSend?: boolean
cancelReplyTo?: () => void
cancelEdit?: () => void
callback: (value: IOrbisPost | IOrbisPost['content']) => void
}) {
const { orbis, account, checkOrbisConnection } = useOrbis()
@ -135,6 +137,12 @@ export default function Postbox({
}
}
useEffect(() => {
if (editPost) {
postBoxArea.current.innerText = editPost.content.body
}
}, [editPost])
if (!accountId) {
return (
<div className={styles.postbox}>
@ -194,17 +202,33 @@ export default function Postbox({
/>
<EmojiPicker onEmojiClick={onEmojiClick} />
</div>
<div className={styles.sendButtonWrap}>
<Button
style="primary"
type="submit"
size="small"
disabled={false}
onClick={share}
>
Send
</Button>
</div>
{editPost ? (
<div className={styles.editActions}>
<button
type="button"
className={styles.cancelEdit}
onClick={cancelEdit}
>
Cancel
</button>
<span>&middot;</span>
<button type="submit" className={styles.saveEdit} onClick={share}>
Save
</button>
</div>
) : (
<div className={styles.sendButtonWrap}>
<Button
style="primary"
type="submit"
size="small"
disabled={false}
onClick={share}
>
Send
</Button>
</div>
)}
</div>
)
}

View File

@ -1,6 +1,5 @@
import React, { useState, useEffect, useRef } from 'react'
import { useOrbis } from '@context/Orbis'
import { useIsMounted } from '@hooks/useIsMounted'
import { useInterval } from '@hooks/useInterval'
import { throttle } from '@utils/throttle'
import Time from '@shared/atoms/Time'
@ -18,9 +17,9 @@ export default function DmConversation() {
connectLit,
clearMessageNotifs
} = useOrbis()
const isMounted = useIsMounted()
const messagesWrapper = useRef(null)
const [isInitialized, setIsInitialized] = useState(false)
const [isLoading, setIsLoading] = useState(false)
const [messages, setMessages] = useState<IOrbisMessage[]>([])
const [currentPage, setCurrentPage] = useState(0)
@ -36,12 +35,16 @@ export default function DmConversation() {
}, 300)
}
const getMessages = async (polling = false) => {
const getMessages: (options?: {
polling?: boolean
reset?: boolean
}) => Promise<void> = async ({ polling = false, reset = false }) => {
if (isLoading || !hasLit) return
if (!polling) setIsLoading(true)
const _page = polling ? 0 : currentPage
const _page = polling || reset ? 0 : currentPage
let _messages = reset ? [] : [...messages]
const { data, error } = await orbis.getMessages(conversationId, _page)
if (error) {
@ -52,30 +55,34 @@ export default function DmConversation() {
data.reverse()
if (!polling) {
setHasMore(data.length >= 50)
const _messages = [...data, ...messages]
_messages = [...data, ..._messages]
setMessages(_messages)
if (currentPage === 0) {
clearMessageNotifs(conversationId)
scrollToBottom()
}
setCurrentPage((prev) => prev + 1)
setCurrentPage(_page + 1)
} else {
const unique = data.filter(
(a) => !messages.some((b) => a.stream_id === b.stream_id)
(a) => !_messages.some((b) => a.stream_id === b.stream_id)
)
setNewMessages(unique.length)
setMessages([...messages, ...unique])
setMessages([..._messages, ...unique])
const el = messagesWrapper.current
if (el && el.scrollHeight > el.offsetHeight) {
setNewMessages((prev) => prev + unique.length)
}
}
}
setIsInitialized(true)
setIsLoading(false)
}
useInterval(
async () => {
getMessages(true)
getMessages({ polling: true })
},
isLoading || !hasLit || !messages.length ? false : 15000
!isLoading && hasLit && isInitialized ? 5000 : false
)
const showTime = (streamId: string): boolean => {
@ -122,20 +129,18 @@ export default function DmConversation() {
}, 1000)
useEffect(() => {
if (isMounted) {
if (
conversationId &&
!conversationId.startsWith('new-') &&
orbis &&
hasLit
) {
getMessages()
} else {
setMessages([])
}
setIsInitialized(false)
setMessages([])
if (
conversationId &&
!conversationId.startsWith('new-') &&
orbis &&
hasLit
) {
getMessages({ reset: true })
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [conversationId, orbis, hasLit, isMounted])
}, [conversationId, orbis, hasLit])
useEffect(() => {
const el = messagesWrapper.current
@ -210,7 +215,7 @@ export default function DmConversation() {
</button>
)}
</div>
<Postbox conversationId={conversationId} callback={callback} />
<Postbox callback={callback} />
</>
)}
</div>

View File

@ -29,7 +29,6 @@ export default function Header() {
) => {
e.preventDefault()
const target = e.target as HTMLElement
console.log(target)
const { role } = target.dataset
if (role) {
if (role === 'back-button') {
@ -38,17 +37,14 @@ export default function Header() {
} else {
let _address = ''
if (newConversation) {
console.log(newConversation.recipients)
_address = didToAddress(newConversation.recipients[0])
} else {
console.log(accountId)
const conversation = conversations.find(
(c) => c.stream_id === conversationId
)
const recipients = conversation.recipients.filter(
(r) => didToAddress(r) !== accountId.toLowerCase()
)
console.log(recipients)
_address = didToAddress(recipients[0])
}
navigator.clipboard.writeText(_address)
@ -96,7 +92,6 @@ export default function Header() {
aria-label="button"
data-role="back-button"
className={styles.btnBack}
onClick={handleClick}
>
<ArrowBack
role="img"
@ -109,7 +104,7 @@ export default function Header() {
<>
<span>{activeConversationTitle}</span>
<button
onClick={handleClick}
type="button"
data-role="copy-address"
title="Copy Address"
className={styles.btnCopy}

View File

@ -4,24 +4,31 @@ import { EmojiClickData } from 'emoji-picker-react'
import { useOrbis } from '@context/Orbis'
import EmojiPicker from '../EmojiPicker'
import { accountTruncate } from '@utils/web3'
import { didToAddress } from '@utils/orbis'
import { didToAddress, sleep } from '@utils/orbis'
export default function Postbox({
conversationId,
replyTo = null,
cancelReplyTo,
callback
}: {
conversationId: string
replyTo?: IOrbisMessage
cancelReplyTo?: () => void
callback: (value: IOrbisMessage) => void
}) {
const [focusOffset, setFocusOffset] = useState<number | undefined>()
const [focusNode, setFocusNode] = useState<Node | undefined>()
const [isSending, setIsSending] = useState<boolean>(false)
const postBoxArea = useRef(null)
const { orbis, account } = useOrbis()
const {
orbis,
account,
conversationId,
newConversation,
createConversation,
setConversationId,
setNewConversation
} = useOrbis()
const saveCaretPos = () => {
const sel = document.getSelection()
@ -38,7 +45,22 @@ export default function Postbox({
}
const share = async () => {
if (!account) return false
if (!account || isSending) return false
setIsSending(true)
let _conversationId = conversationId
if (_conversationId.startsWith('new-') && newConversation) {
const _newConversation = await createConversation(
newConversation.recipients
)
if (_newConversation) {
_conversationId = _newConversation.stream_id
setConversationId(_conversationId)
setNewConversation(null)
await sleep(1000)
}
}
const body = postBoxArea.current.innerText
@ -72,7 +94,7 @@ export default function Postbox({
postBoxArea.current.innerText = ''
const res = await orbis.sendMessage({
conversation_id: conversationId,
conversation_id: _conversationId,
body
})
@ -80,12 +102,14 @@ export default function Postbox({
_callbackContent.stream_id = res.doc
if (callback) callback(_callbackContent)
}
setIsSending(false)
}
const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {
if (!e.key) return
if (e.key === 'Enter' && !e.shiftKey) {
if (e.key === 'Enter' && !e.shiftKey && !isSending) {
// Don't generate a new line
e.preventDefault()
share()

View File

@ -28,7 +28,7 @@ const DmButton = ({ accountId }: { accountId: string }) => {
const { accountId: ownAccountId, connect } = useWeb3()
const {
checkOrbisConnection,
getConversation,
getConversationByDid,
setNewConversation,
setConversationId,
setOpenConversations,
@ -72,7 +72,7 @@ const DmButton = ({ accountId }: { accountId: string }) => {
handleActivation()
} else {
setIsCreatingConversation(true)
const conversation = await getConversation(userDid)
const conversation = await getConversationByDid(userDid)
if (conversation) {
setConversationId(conversation.stream_id)
} else {
@ -80,11 +80,10 @@ const DmButton = ({ accountId }: { accountId: string }) => {
const suffix =
profile && profile?.name
? profile?.name
: accountTruncate(accountId)
: accountTruncate(accountId.toLowerCase())
setConversationId(`new-${suffix}`)
setNewConversation({
name: suffix,
recipients: [userDid]
})
}