diff --git a/net/web/src/session/channels/Channels.jsx b/net/web/src/session/channels/Channels.jsx index d613c076..d6d65cfd 100644 --- a/net/web/src/session/channels/Channels.jsx +++ b/net/web/src/session/channels/Channels.jsx @@ -55,7 +55,8 @@ export function Channels({ open, active }) { { state.channels.length > 0 && ( ( - + )} /> )} diff --git a/net/web/src/session/channels/channelItem/ChannelItem.jsx b/net/web/src/session/channels/channelItem/ChannelItem.jsx index f8690e75..e350f55a 100644 --- a/net/web/src/session/channels/channelItem/ChannelItem.jsx +++ b/net/web/src/session/channels/channelItem/ChannelItem.jsx @@ -3,7 +3,7 @@ import { ChannelItemWrapper, Markup } from './ChannelItem.styled'; import { Logo } from 'logo/Logo'; import { AppstoreFilled, SolutionOutlined, UnlockOutlined, LockFilled } from '@ant-design/icons'; -export function ChannelItem({ item, openChannel, active }) { +export function ChannelItem({ cardId, channelId, openChannel, active }) { const itemClass = () => { if (active.set && active.channel === item.channelId && active.card === item.cardId) { diff --git a/net/web/src/session/channels/channelItem/useChannelItem.hook.js b/net/web/src/session/channels/channelItem/useChannelItem.hook.js new file mode 100644 index 00000000..a5c07041 --- /dev/null +++ b/net/web/src/session/channels/channelItem/useChannelItem.hook.js @@ -0,0 +1,225 @@ +import { useContext, useState, useEffect, useRef } from 'react'; +import { StoreContext } from 'context/StoreContext'; +import { ChannelContext } from 'context/ChannelContext'; +import { CardContext } from 'context/CardContext'; +import { AccountContext } from 'context/AccountContext'; +import { ProfileContext } from 'context/ProfileContext'; +import { getCardByGuid } from 'context/cardUtil'; + +export function useChannelItem(cardId, channelId, filter) { + + const [state, setState] = useState({ + set: false, + }); + + const card = useContext(CardContext); + const channel = useContext(ChannelContext); + const account = useContext(AccountContext); + const store = useContext(StoreContext); + const profile = useContext(ProfileContext); + + const updateState = (value) => { + setState((s) => ({ ...s, ...value })); + } + + const syncing = useRef(false); + const setCardId = useRef(); + const setChannelId = useRef(); + const setCardRevision = useRef(); + const setChannelRevision = useRef(); + const setSealKey = useRef(); + + const actions = { + }; + + useEffect(() => { + sync(); + }, [card, channel, store, account, filter]); + + + const sync = async () => { + if (!syncing.current) { + syncing.current = true; + + if (cardId !== setCardId.current || channelId !== setChannelId.current) { + await setChannel(cardId, channelId); + syncing.current = false; + await sync(); + return; + } + if (cardId) { + const contact = card.state.cards.get(cardId); + if (contact?.revision !== setCardRevision.current) { + await setChannel(cardId, channelId); + syncing.current = false; + await sync(); + return; + } + const conversation = contact.channels.get(channelId); + if (conversation?.revision !== setChannelRevision.current) { + await setChannel(cardId, channelId); + syncing.current = false; + await sync(); + return; + } + } + else { + const conversation = channel.state.channels.get(channelId); + if (conversation?.revision !== setChannelRevision.current) { + await setChannel(cardId, channelId); + syncing.current = false; + await sync(); + return; + } + } + const key = account.state.sealKey; + if (key?.pulic !== setSealKey.current?.public || key?.private !== setSealKey.current?.private) { + await setChannel(cardId, channelId); + syncing.current = false; + await sync(); + return; + } + + syncing.current = false; + } + } + + const setChannel = (cardId, channelId) => { + if (cardId) { + const cardItem = card.state.cards.get(cardId); + setChannelItem(cardItem?.channels?.get(channelId)); + } + else { + setChannelItem(channel.state.channels.get(channelId); + } + }; + + const setChannelItem = (item) => { + + if (!item) { + updateState({ set: false }); + return; + } + } + + + const chan = {}; + chan.cardId = cardId; + chan.channelId = channelId; + chan.revision = value.revision; + chan.updated = value.data?.channelSummary?.lastTopic?.created; + + // set updated flag + const key = `${cardId}:${channelId}` + const login = store.state['login:timestamp']; + if (!chan.updated || !login || chan.updated < login) { + chan.updatedFlag = false; + } + else if (store.state[key] && store.state[key] === value.revision) { + chan.updatedFlag = false; + } + else { + chan.updatedFlag = true; + } + + // extract member info + let memberCount = 0; + let names = []; + let img = null; + let logo = null; + if (cardId) { + const contact = card.state.cards.get(cardId); + const profile = contact?.data?.cardProfile; + if (profile?.name) { + names.push(profile.name); + } + if (profile?.imageSet) { + img = null; + logo = card.actions.getCardImageUrl(contact.id); + } + else { + img = 'avatar'; + logo = null; + } + memberCount++; + } + for (let guid of value?.data?.channelDetail?.members) { + if (guid !== profile.state.identity.guid) { + const contact = getCardByGuid(card.state.cards, guid); + const profile = contact?.data?.cardProfile; + if (profile?.name) { + names.push(profile.name); + } + if (profile?.imageSet) { + img = null; + logo = card.actions.getCardImageUrl(contact.id); + } + else { + img = 'avatar'; + logo = null; + } + memberCount++; + } + } + + // set logo and label + if (memberCount === 0) { + chan.img = 'solution'; + chan.label = 'Notes'; + } + else if (memberCount === 1) { + chan.logo = logo; + chan.img = img; + chan.label = names.join(','); + } + else { + chan.img = 'appstore'; + chan.label = names.join(','); + } + + // set subject + const detail = value.data?.channelDetail; + if (detail?.dataType === 'sealedchannel') { + // handle sealed subject + chan.locked = true; + chan.unlocked = false; + } + else if (detail?.dataType === 'superbasic') { + chan.locked = false; + chan.unlocked = true; + try { + const data = JSON.parse(detail.data); + chan.subject = data.subject; + } + catch(err) { + console.log(err); + } + } + if (chan.subject == null) { + chan.subject = chan.label; + } + + // set message + const topic = value.data?.channelSummary?.lastTopic; + if (topic?.dataType === 'sealedtopic') { + // handle sealed topic + } + else if (topic?.dataType === 'superbasictopic') { + try { + const data = JSON.parse(topic.data); + chan.message = data.text; + } + catch(err) { + console.log(err); + } + } + + return chan; + } + + useEffect(() => { + // eslint-disable-next-line + }, [account, channel, card, store, filter, state.sealable]); + + return { state, actions }; +} diff --git a/net/web/src/session/channels/useChannels.hook.js b/net/web/src/session/channels/useChannels.hook.js index 11dda2a7..726ab858 100644 --- a/net/web/src/session/channels/useChannels.hook.js +++ b/net/web/src/session/channels/useChannels.hook.js @@ -9,8 +9,6 @@ import { getCardByGuid } from 'context/cardUtil'; export function useChannels() { - const [filter, setFilter] = useState(null); - const [state, setState] = useState({ display: null, channels: [], @@ -20,6 +18,7 @@ export function useChannels() { subject: null, seal: false, sealable: false, + filter: null, }); const card = useContext(CardContext); @@ -89,7 +88,7 @@ export function useChannels() { } }, onFilter: (value) => { - setFilter(value.toUpperCase()); + updateState({ filter: value.toUpperCase() }); }, setShowAdd: () => { updateState({ showAdd: true, seal: false }); @@ -236,14 +235,15 @@ export function useChannels() { useEffect(() => { const merged = []; - card.state.cards.forEach((cardValue, cardKey) => { - cardValue.channels.forEach((channelValue, channelKey) => { - const chan = getChannel(cardKey, channelKey, channelValue); - merged.push(chan); + card.state.cards.forEach((cardValue, cardId) => { + cardValue.channels.forEach((channelValue, channelId) => { + const updated = value.data?.channelSummary?.lastTopic?.created; + merged.push{ updated, cardId, channelId }; }); }); - channel.state.channels.forEach((channelValue, channelKey) => { - merged.push(getChannel(null, channelKey, channelValue)); + channel.state.channels.forEach((channelValue, channelId) => { + const updated = value.data?.channelSummary?.lastTopic?.created; + merged.push{ updated, channelId }; }); merged.sort((a, b) => { @@ -258,12 +258,7 @@ export function useChannels() { return -1; }); - const filtered = merged.filter((chan) => { - const subject = chan?.subject?.toUpperCase(); - return !filter || subject?.includes(filter); - }); - - updateState({ channels: filtered }); + updateState({ channels: merged }); // eslint-disable-next-line }, [account, channel, card, store, filter, state.sealable]);