From 8a1531bcee73015205982cb23962b82289677827 Mon Sep 17 00:00:00 2001 From: Roland Osborne Date: Tue, 9 Aug 2022 11:14:36 -0700 Subject: [PATCH] rendering channels --- net/web/src/session/Session.styled.js | 2 + net/web/src/session/channels/Channels.jsx | 16 ++++- .../src/session/channels/Channels.styled.js | 5 ++ .../channels/channelItem/ChannelItem.jsx | 31 ++++++++++ .../channelItem/ChannelItem.styled.js | 29 +++++++++ .../channelItem/useChannelItem.hook.js | 36 +++++++++++ .../src/session/channels/useChannels.hook.js | 61 +++++++++++++++++++ 7 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 net/web/src/session/channels/channelItem/ChannelItem.jsx create mode 100644 net/web/src/session/channels/channelItem/ChannelItem.styled.js create mode 100644 net/web/src/session/channels/channelItem/useChannelItem.hook.js create mode 100644 net/web/src/session/channels/useChannels.hook.js diff --git a/net/web/src/session/Session.styled.js b/net/web/src/session/Session.styled.js index 38503c7a..35f4fd73 100644 --- a/net/web/src/session/Session.styled.js +++ b/net/web/src/session/Session.styled.js @@ -25,6 +25,7 @@ export const SessionWrapper = styled.div` display: flex; flex-direction: column; position: relative; + min-height: 0; } .center { flex-grow: 1; @@ -57,6 +58,7 @@ export const SessionWrapper = styled.div` display: flex; flex-direction: column; position: relative; + min-height: 0; } .center { flex-grow: 1; diff --git a/net/web/src/session/channels/Channels.jsx b/net/web/src/session/channels/Channels.jsx index f974c9b4..3f7d4858 100644 --- a/net/web/src/session/channels/Channels.jsx +++ b/net/web/src/session/channels/Channels.jsx @@ -1,8 +1,15 @@ -import { Input } from 'antd'; +import { Input, List } from 'antd'; import { ChannelsWrapper } from './Channels.styled'; import { SearchOutlined } from '@ant-design/icons'; +import { useChannels } from './useChannels.hook'; +import { ChannelItem } from './channelItem/ChannelItem'; export function Channels() { + + const { state, actions } = useChannels(); + +console.log(state); + return ( +
+ ( + + )} + /> +
); } diff --git a/net/web/src/session/channels/Channels.styled.js b/net/web/src/session/channels/Channels.styled.js index 7c392087..02ab8aab 100644 --- a/net/web/src/session/channels/Channels.styled.js +++ b/net/web/src/session/channels/Channels.styled.js @@ -7,6 +7,7 @@ export const ChannelsWrapper = styled.div` display: flex; flex-direction: column; background-color: ${Colors.formBackground}; + min-height: 0; .search { padding: 8px; @@ -17,4 +18,8 @@ export const ChannelsWrapper = styled.div` border-radius: 8px; } } + + .results { + min-height: 0; + overflow: scroll; `; diff --git a/net/web/src/session/channels/channelItem/ChannelItem.jsx b/net/web/src/session/channels/channelItem/ChannelItem.jsx new file mode 100644 index 00000000..211ba2c3 --- /dev/null +++ b/net/web/src/session/channels/channelItem/ChannelItem.jsx @@ -0,0 +1,31 @@ +import { ChannelItemWrapper } from './ChannelItem.styled'; +import { useChannelItem } from './useChannelItem.hook'; +import { SolutionOutlined } from '@ant-design/icons'; + +export function ChannelItem({ item }) { + + const { state, actions } = useChannelItem(item); + + return ( + + { state.contacts.length === 0 && ( +
+ +
+
+
+
+
+ )} + { state.contacts.length === 1 && ( +
PERSONAL
+ )} + { state.contacts.length > 1 && ( +
GROUP
+ )} +
+ ) +} + diff --git a/net/web/src/session/channels/channelItem/ChannelItem.styled.js b/net/web/src/session/channels/channelItem/ChannelItem.styled.js new file mode 100644 index 00000000..bcc986fc --- /dev/null +++ b/net/web/src/session/channels/channelItem/ChannelItem.styled.js @@ -0,0 +1,29 @@ +import styled from 'styled-components'; +import Colors from 'constants/Colors'; + +export const ChannelItemWrapper = styled.div` + height: 48px; + width: 100%; + display: flex; + flex-direction: row; + flex-align: center; + border-bottom: 1px solid ${Colors.divider}; + + .logo { + display: flex; + align-items: center; + justify-content: center; + border: 1px solid ${Colors.grey}; + width: 32px; + height: 32px; + border-radius: 8px; + font-size: 18px; + } + + .subject { + flex-grow: 1; + } + + .markup { + } +`; 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..b13e00ae --- /dev/null +++ b/net/web/src/session/channels/channelItem/useChannelItem.hook.js @@ -0,0 +1,36 @@ +import { useContext, useState, useEffect } from 'react'; +import { ProfileContext } from 'context/ProfileContext'; +import { CardContext } from 'context/CardContext'; + +export function useChannelItem(item) { + + const [state, setState] = useState({ + contacts: [], + }); + + const profile = useContext(ProfileContext); + const card = useContext(CardContext); + + const updateState = (value) => { + setState((s) => ({ ...s, ...value })); + } + + const actions = { + }; + + + useEffect(() => { + let contacts = []; + if (item.guid != null && profile.state.profile.guid != item.guid) { + contacts.push(card.actions.getCardByGuid(item.guid)); + } + for (let guid of item.data.channelDetail?.members) { + if (guid != profile.state.profile.guid) { + contacts.push(card.actions.getCardByGuid(guid)); + } + } + updateState({ contacts }); + }, [profile, item]); + + return { state, actions }; +} diff --git a/net/web/src/session/channels/useChannels.hook.js b/net/web/src/session/channels/useChannels.hook.js new file mode 100644 index 00000000..1a220007 --- /dev/null +++ b/net/web/src/session/channels/useChannels.hook.js @@ -0,0 +1,61 @@ +import { useContext, useState, useEffect } from 'react'; +import { StoreContext } from 'context/StoreContext'; +import { ChannelContext } from 'context/ChannelContext'; +import { CardContext } from 'context/CardContext'; + +export function useChannels() { + + const [state, setState] = useState({ + channels: [], + busy: false } + ); + + const card = useContext(CardContext); + const channel = useContext(ChannelContext); + const store = useContext(StoreContext); + + const updateState = (value) => { + setState((s) => ({ ...s, ...value })); + } + + const actions = { + }; + + const setUpdated = (chan) => { + const login = store.state['login:timestamp']; + const update = chan?.data?.channelSummary?.lastTopic?.created; + + if (!update || (login && update < login)) { + chan.updated = false; + return; + } + + let key = `${chan.id}::${chan.cardId}` + if (store.state[key] && store.state[key] == chan.revision) { + chan.updated = false; + } + else { + chan.updated = true; + } + } + + useEffect(() => { + let merged = []; + card.state.cards.forEach((value, key, map) => { + merged.push(...Array.from(value.channels.values())); + }); + merged.push(...Array.from(channel.state.channels.values())); + + merged.sort((a, b) => { + if (a?.data?.channelSummary?.lastTopic?.created > b?.data?.channelSummary?.lastTopic?.created) { + return -1; + } + return 1; + }); + + merged.forEach(chan => { setUpdated(chan) }); + updateState({ channels: merged }); + }, [channel, card, store]); + + return { state, actions }; +}