diff --git a/net/web/src/session/channels/Channels.jsx b/net/web/src/session/channels/Channels.jsx index d6d65cfd..ab4361a4 100644 --- a/net/web/src/session/channels/Channels.jsx +++ b/net/web/src/session/channels/Channels.jsx @@ -55,7 +55,7 @@ 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 e350f55a..13c8ecc9 100644 --- a/net/web/src/session/channels/channelItem/ChannelItem.jsx +++ b/net/web/src/session/channels/channelItem/ChannelItem.jsx @@ -1,38 +1,37 @@ import { Tooltip } from 'antd'; import { ChannelItemWrapper, Markup } from './ChannelItem.styled'; import { Logo } from 'logo/Logo'; -import { AppstoreFilled, SolutionOutlined, UnlockOutlined, LockFilled } from '@ant-design/icons'; +import { UnlockOutlined, LockFilled } from '@ant-design/icons'; +import { useChannelItem } from './useChannelItem.hook'; -export function ChannelItem({ cardId, channelId, openChannel, active }) { +export function ChannelItem({ cardId, channelId, filter, openChannel, active }) { - const itemClass = () => { - if (active.set && active.channel === item.channelId && active.card === item.cardId) { - return "active" - } - return "idle" - }; + const { state } = useChannelItem(cardId, channelId, filter, active); return ( - openChannel(item.channelId, item.cardId)}> -
+ openChannel(channelId, cardId)}> +
- +
- { item.locked && !item.unlocked && ( + { state.locked && !state.unlocked && ( )} - { item.locked && item.unlocked && ( + { state.locked && state.unlocked && ( )} - { item.subject } + { state.subject }
-
{ item.message }
+
{ state.message }
- { item.updatedFlag && ( - + { state.updatedFlag && ( + + + )}
diff --git a/net/web/src/session/channels/channelItem/useChannelItem.hook.js b/net/web/src/session/channels/channelItem/useChannelItem.hook.js index a5c07041..5ab28ef1 100644 --- a/net/web/src/session/channels/channelItem/useChannelItem.hook.js +++ b/net/web/src/session/channels/channelItem/useChannelItem.hook.js @@ -6,10 +6,19 @@ import { AccountContext } from 'context/AccountContext'; import { ProfileContext } from 'context/ProfileContext'; import { getCardByGuid } from 'context/cardUtil'; -export function useChannelItem(cardId, channelId, filter) { +export function useChannelItem(cardId, channelId, filter, active) { const [state, setState] = useState({ set: false, + visible: false, + active: false, + locked: false, + unlocked: false, + updateFlag: false, + img: null, + logo: null, + subject: null, + message: null, }); const card = useContext(CardContext); @@ -34,8 +43,31 @@ export function useChannelItem(cardId, channelId, filter) { useEffect(() => { sync(); - }, [card, channel, store, account, filter]); + // eslint-disable-next-line + }, [card.state, channel.state, store.state, account.state]); + useEffect(() => { + if (cardId === active?.card && channelId === active?.channel) { + updateState({ active: true }); + } + else { + updateState({ active: false }); + } + }, [cardId, channelId, active]); + + useEffect(() => { + if (filter) { + if (state.subject) { + updateState({ visible: state.subject.toUpperCase().includes(filter) }); + } + else { + updateState({ visible: false }); + } + } + else { + updateState({ visible: true }); + } + }, [filter, state.subject]); const sync = async () => { if (!syncing.current) { @@ -87,35 +119,34 @@ export function useChannelItem(cardId, channelId, filter) { const setChannel = (cardId, channelId) => { if (cardId) { const cardItem = card.state.cards.get(cardId); - setChannelItem(cardItem?.channels?.get(channelId)); + const channelItem = cardItem?.channels?.get(channelId); + setChannelItem(cardItem, channelItem); + setCardRevision.current = cardItem?.revision; + setChannelRevision.current = channelItem?.revision; } else { - setChannelItem(channel.state.channels.get(channelId); + const channelItem = channel.state.channels.get(channelId); + setChannelItem(null, channelItem); + setChannelRevision.current = channelItem?.revision; } + setSealKey.current = account.state.sealKey; }; - const setChannelItem = (item) => { + const setChannelItem = (cardItem, channelItem) => { - if (!item) { + if (!channelItem) { updateState({ set: false }); return; } - } - + const chan = { set: true }; - 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) { + else if (store.state[key] && store.state[key] === channelItem.revision) { chan.updatedFlag = false; } else { @@ -127,15 +158,14 @@ export function useChannelItem(cardId, channelId, filter) { let names = []; let img = null; let logo = null; - if (cardId) { - const contact = card.state.cards.get(cardId); - const profile = contact?.data?.cardProfile; + if (cardItem) { + const profile = cardItem?.data?.cardProfile; if (profile?.name) { names.push(profile.name); } if (profile?.imageSet) { img = null; - logo = card.actions.getCardImageUrl(contact.id); + logo = card.actions.getCardImageUrl(cardId); } else { img = 'avatar'; @@ -143,7 +173,7 @@ export function useChannelItem(cardId, channelId, filter) { } memberCount++; } - for (let guid of value?.data?.channelDetail?.members) { + for (let guid of channelItem?.data?.channelDetail?.members) { if (guid !== profile.state.identity.guid) { const contact = getCardByGuid(card.state.cards, guid); const profile = contact?.data?.cardProfile; @@ -178,7 +208,7 @@ export function useChannelItem(cardId, channelId, filter) { } // set subject - const detail = value.data?.channelDetail; + const detail = channelItem.data?.channelDetail; if (detail?.dataType === 'sealedchannel') { // handle sealed subject chan.locked = true; @@ -200,7 +230,7 @@ export function useChannelItem(cardId, channelId, filter) { } // set message - const topic = value.data?.channelSummary?.lastTopic; + const topic = channel.data?.channelSummary?.lastTopic; if (topic?.dataType === 'sealedtopic') { // handle sealed topic } @@ -214,12 +244,8 @@ export function useChannelItem(cardId, channelId, filter) { } } - return chan; + updateState({ ...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 726ab858..25613d99 100644 --- a/net/web/src/session/channels/useChannels.hook.js +++ b/net/web/src/session/channels/useChannels.hook.js @@ -1,46 +1,78 @@ -import { useContext, useState, useEffect, useRef } from 'react'; +import { useContext, useState, useEffect } 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 { ViewportContext } from 'context/ViewportContext'; -import { getCardByGuid } from 'context/cardUtil'; export function useChannels() { const [state, setState] = useState({ display: null, channels: [], - showAdd: false, - busy: false, - members: new Set(), - subject: null, - seal: false, sealable: false, filter: null, + busy: false, + + showAdd: false, + subject: null, + members: new Set(), + seal: false, }); const card = useContext(CardContext); const channel = useContext(ChannelContext); const account = useContext(AccountContext); const store = useContext(StoreContext); - const profile = useContext(ProfileContext); const viewport = useContext(ViewportContext); + const updateState = (value) => { + setState((s) => ({ ...s, ...value })); + } + useEffect(() => { const { seal, sealKey } = account.state; if (seal?.publicKey && sealKey?.public && sealKey?.private && seal.publicKey === sealKey.public) { - updateState({ sealable: true }); + updateState({ seal: false, sealable: true }); } else { updateState({ seal: false, sealable: false }); } }, [account]); - const updateState = (value) => { - setState((s) => ({ ...s, ...value })); - } + useEffect(() => { + const merged = []; + card.state.cards.forEach((cardValue, cardId) => { + cardValue.channels.forEach((channelValue, channelId) => { + const updated = channelValue.data?.channelSummary?.lastTopic?.created; + merged.push({ updated, cardId, channelId }); + }); + }); + channel.state.channels.forEach((channelValue, channelId) => { + const updated = channelValue.data?.channelSummary?.lastTopic?.created; + merged.push({ updated, channelId }); + }); + + merged.sort((a, b) => { + const aUpdated = a.updated; + const bUpdated = b.updated; + if (aUpdated === bUpdated) { + return 0; + } + if (!aUpdated || aUpdated < bUpdated) { + return 1; + } + return -1; + }); + + updateState({ channels: merged }); + + // eslint-disable-next-line + }, [channel, card]); + + useEffect(() => { + updateState({ display: viewport.state.display }); + }, [viewport]); const actions = { addChannel: async () => { @@ -48,9 +80,9 @@ export function useChannels() { if (!state.busy) { try { updateState({ busy: true }); - let cards = Array.from(state.members.values()); + const cards = Array.from(state.members.values()); if (state.seal) { - let keys = [ account.state.sealKey.public ]; + const keys = [ account.state.sealKey.public ]; cards.forEach(id => { keys.push(card.state.cards.get(id).data.cardProfile.seal); }); @@ -74,8 +106,8 @@ export function useChannels() { }, setSeal: (seal) => { if (seal) { - let cards = Array.from(state.members.values()); - let members = new Set(state.members); + const cards = Array.from(state.members.values()); + const members = new Set(state.members); cards.forEach(id => { if (!(card.state.cards.get(id)?.data?.cardProfile?.seal)) { members.delete(id); @@ -91,13 +123,13 @@ export function useChannels() { updateState({ filter: value.toUpperCase() }); }, setShowAdd: () => { - updateState({ showAdd: true, seal: false }); + updateState({ showAdd: true, seal: false, members: new Set(), subject: null }); }, clearShowAdd: () => { - updateState({ showAdd: false, members: new Set(), subject: null }); + updateState({ showAdd: false }); }, onMember: (string) => { - let members = new Set(state.members); + const members = new Set(state.members); if (members.has(string)) { members.delete(string); } @@ -117,155 +149,5 @@ export function useChannels() { }, }; - // TODO optimize (avoid rebuild object when not needed) - const getChannel = (cardId, channelId, value) => { - 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(() => { - const merged = []; - 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, channelId) => { - const updated = value.data?.channelSummary?.lastTopic?.created; - merged.push{ updated, channelId }; - }); - - merged.sort((a, b) => { - const aUpdated = a.updated; - const bUpdated = b.updated; - if (aUpdated === bUpdated) { - return 0; - } - if (!aUpdated || aUpdated < bUpdated) { - return 1; - } - return -1; - }); - - updateState({ channels: merged }); - - // eslint-disable-next-line - }, [account, channel, card, store, filter, state.sealable]); - - useEffect(() => { - updateState({ display: viewport.state.display }); - }, [viewport]); - return { state, actions }; } diff --git a/net/web/src/session/useSession.hook.js b/net/web/src/session/useSession.hook.js index c659655e..c8d69d5f 100644 --- a/net/web/src/session/useSession.hook.js +++ b/net/web/src/session/useSession.hook.js @@ -5,7 +5,6 @@ import { CardContext } from 'context/CardContext'; import { StoreContext } from 'context/StoreContext'; import { ViewportContext } from 'context/ViewportContext'; import { ProfileContext } from 'context/ProfileContext'; -import { ChannelContext } from 'context/ChannelContext'; export function useSession() {