diff --git a/doc/api.oa3 b/doc/api.oa3
index 4f4063f3..3c96fbe0 100644
--- a/doc/api.oa3
+++ b/doc/api.oa3
@@ -3495,7 +3495,9 @@ components:
contacts:
$ref: '#/components/schemas/ChannelContacts'
members:
- $ref: '#/components/schemas/ChannelMembers'
+ type: array
+ item:
+ type: string
ChannelContacts:
type: object
diff --git a/net/server/internal/modelUtil.go b/net/server/internal/modelUtil.go
index 7638bb6c..c4c20e55 100644
--- a/net/server/internal/modelUtil.go
+++ b/net/server/internal/modelUtil.go
@@ -204,7 +204,7 @@ func getChannelModel(slot *store.ChannelSlot, showData bool, showList bool) *Cha
Created: slot.Channel.Created,
Updated: slot.Channel.Updated,
Contacts: contacts,
- Members: &ChannelMembers{ members },
+ Members: members,
},
},
}
diff --git a/net/server/internal/models.go b/net/server/internal/models.go
index d5bb272a..a7f3673b 100644
--- a/net/server/internal/models.go
+++ b/net/server/internal/models.go
@@ -190,12 +190,7 @@ type ChannelDetail struct {
Contacts *ChannelContacts `json:"contacts,omitempty"`
- Members *ChannelMembers `json:"members,omitempty"`
-}
-
-type ChannelMembers struct {
-
- Members []string `json:"members,omitempty"`
+ Members []string `json:"members"`
}
type ChannelParams struct {
diff --git a/net/server/internal/ucChannelShare_test.go b/net/server/internal/ucChannelShare_test.go
index e3fdde59..3151e9e8 100644
--- a/net/server/internal/ucChannelShare_test.go
+++ b/net/server/internal/ucChannelShare_test.go
@@ -83,8 +83,8 @@ func TestChannelShare(t *testing.T) {
assert.NoError(t, ApiTestMsg(GetChannel, "GET", "/content/channels/{channelId}",
¶ms, nil, APP_TOKENCONTACT, set.B.A.Token, channel, nil))
assert.Equal(t, "channeldatatype", channel.Data.ChannelDetail.DataType)
- assert.Equal(t, 1, len(channel.Data.ChannelDetail.Members.Members))
- assert.Equal(t, set.B.Guid, channel.Data.ChannelDetail.Members.Members[0])
+ assert.Equal(t, 1, len(channel.Data.ChannelDetail.Members))
+ assert.Equal(t, set.B.Guid, channel.Data.ChannelDetail.Members[0])
assert.Nil(t, channel.Data.ChannelDetail.Contacts)
// get revision
@@ -154,7 +154,7 @@ func TestChannelShare(t *testing.T) {
assert.NoError(t, ApiTestMsg(GetChannel, "GET", "/content/channels/{channelId}",
¶ms, nil, APP_TOKENCONTACT, set.C.A.Token, channel, nil))
assert.Equal(t, "channeldatatype", channel.Data.ChannelDetail.DataType)
- assert.Equal(t, 2, len(channel.Data.ChannelDetail.Members.Members))
+ assert.Equal(t, 2, len(channel.Data.ChannelDetail.Members))
assert.Nil(t, channel.Data.ChannelDetail.Contacts)
// reset notification
diff --git a/net/web/src/Api/getCardImageUrl.js b/net/web/src/Api/getCardImageUrl.js
new file mode 100644
index 00000000..40e130e6
--- /dev/null
+++ b/net/web/src/Api/getCardImageUrl.js
@@ -0,0 +1,4 @@
+export function getCardImageUrl(token, cardId, revision) {
+ return `/contact/cards/${cardId}/profile/image?agent=${token}&revision=${revision}`
+}
+
diff --git a/net/web/src/AppContext/useAppContext.hook.js b/net/web/src/AppContext/useAppContext.hook.js
index 766f260f..bcdbd525 100644
--- a/net/web/src/AppContext/useAppContext.hook.js
+++ b/net/web/src/AppContext/useAppContext.hook.js
@@ -223,6 +223,7 @@ export function useAppContext() {
profileRevision.current = null;
groupRevision.current = null;
cardRevision.current = null;
+ channels.current = new Map();
cards.current = new Map();
groups.current = new Map();
setState({});
@@ -376,6 +377,7 @@ export function useAppContext() {
}, []);
if (!state) {
+console.log("STATE IS NULL");
return {}
}
if (state.access === 'user') {
diff --git a/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelItem.jsx b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelItem.jsx
new file mode 100644
index 00000000..67d4afc4
--- /dev/null
+++ b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelItem.jsx
@@ -0,0 +1,25 @@
+import React, { useEffect, useState } from 'react'
+import { ChannelItemWrapper } from './ChannelItem.styled';
+import { ChannelLogo } from './ChannelLogo/ChannelLogo';
+import { ChannelLabel } from './ChannelLabel/ChannelLabel';
+
+export function ChannelItem({ item }) {
+
+ // if 0 or 5+ render number in big border
+ // if 2 renber other in big border
+ // if 3 or 4 render others in small borders
+
+ // subject, hosting, username list, last msg, updated time, unread flag
+
+ const onSelect = () => {
+ console.log(item);
+ }
+
+ return (
+ onSelect()}>
+
+
+
+ )
+}
+
diff --git a/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelItem.styled.js b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelItem.styled.js
new file mode 100644
index 00000000..f306a1ff
--- /dev/null
+++ b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelItem.styled.js
@@ -0,0 +1,18 @@
+import styled from 'styled-components';
+import { List } from 'antd';
+
+export const ChannelItemWrapper = styled(List.Item)`
+ padding-left: 16px;
+ padding-right: 16px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+ height: 48px;
+ cursor: pointer;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ &:hover {
+ background-color: #eeeeee;
+ }
+`;
+
diff --git a/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLabel/ChannelLabel.jsx b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLabel/ChannelLabel.jsx
new file mode 100644
index 00000000..01474ffb
--- /dev/null
+++ b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLabel/ChannelLabel.jsx
@@ -0,0 +1,72 @@
+import React, { useState, useEffect } from 'react';
+import { useChannelLabel } from './useChannelLabel.hook';
+import { LabelWrapper } from './ChannelLabel.styled';
+import { HomeOutlined, DatabaseOutlined } from '@ant-design/icons';
+
+export function ChannelLabel({ item }) {
+
+ const [host, setHost] = useState(null);
+ const [members, setMembers] = useState([]);
+ const [subject, setSubject] = useState('');
+
+ const { state, actions } = useChannelLabel();
+
+ useEffect(() => {
+
+ let contacts = [];
+ if (item?.guid) {
+ setHost(actions.getCard(item.guid));
+ for (let member of item.channel.data.channelDetail.members) {
+ if (member != state.guid) {
+ contacts.push(actions.getCard(member));
+ }
+ }
+ setMembers(contacts);
+ }
+ else {
+ setHost(null);
+ for (let member of item.channel.data.channelDetail.members) {
+ contacts.push(actions.getCard(member));
+ }
+ setMembers(contacts);
+ }
+
+ if (item?.channel?.data?.channelDetail?.data) {
+ let data = JSON.parse(item.channel.data.channelDetail.data);
+ if (data.subject != '' && data.subject != null) {
+ setSubject(data.subject);
+ return
+ }
+ }
+
+ let names = ''
+ for (let contact of contacts) {
+ if (contact != null) {
+ if (names != '') {
+ names += ', ';
+ }
+ names += contact.data.cardProfile.handle;
+ }
+ }
+ if (names != '') {
+ names = '[' + names + ']';
+ }
+ setSubject(names)
+
+ }, [item, state]);
+
+ const Host = () => {
+ if (host) {
+ return (
{ host.data.cardProfile.handle }
)
+ }
+ return
+ }
+
+ return (
+
+ {subject}
+
+
+ )
+}
+
diff --git a/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLabel/ChannelLabel.styled.js b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLabel/ChannelLabel.styled.js
new file mode 100644
index 00000000..bea82789
--- /dev/null
+++ b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLabel/ChannelLabel.styled.js
@@ -0,0 +1,22 @@
+import styled from 'styled-components';
+
+export const LabelWrapper = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ flex-grow: 1;
+ padding-right: 8px;
+ overflow: hidden;
+ color: #444444;
+
+ .subject {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ text-align: right;
+ }
+
+ .host {
+ text-align: right;
+ }
+`;
diff --git a/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLabel/useChannelLabel.hook.js b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLabel/useChannelLabel.hook.js
new file mode 100644
index 00000000..f04a9061
--- /dev/null
+++ b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLabel/useChannelLabel.hook.js
@@ -0,0 +1,27 @@
+import { useContext, useState, useEffect } from 'react';
+import { AppContext } from '../../../../../../AppContext/AppContext';
+import { getCardImageUrl } from '../../../../../../Api/getCardImageUrl';
+
+export function useChannelLabel() {
+
+ const [state, setState] = useState({
+ guid: null
+ });
+
+ const app = useContext(AppContext);
+
+ const actions = {
+ getCard: app?.actions?.getCard,
+ };
+
+ const updateState = (value) => {
+ setState((s) => ({ ...s, ...value }));
+ }
+
+ useEffect(() => {
+ updateState({ guid: app?.state?.Data?.profile?.guid })
+ }, [app])
+
+ return { state, actions };
+}
+
diff --git a/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLogo/ChannelLogo.jsx b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLogo/ChannelLogo.jsx
new file mode 100644
index 00000000..749946e9
--- /dev/null
+++ b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLogo/ChannelLogo.jsx
@@ -0,0 +1,136 @@
+import React, { useEffect, useState, useContext } from 'react'
+import { DisconnectOutlined, UserOutlined } from '@ant-design/icons';
+import { LogoWrapper, Contact, Host, ChannelImage } from './ChannelLogo.styled';
+import { useChannelLogo } from './useChannelLogo.hook';
+
+export function ChannelLogo({ item }) {
+
+ const [home, setHome] = useState(false);
+ const [host, setHost] = useState(null);
+ const [members, setMembers] = useState([]);
+
+ const { state, actions } = useChannelLogo();
+
+ useEffect(() => {
+
+ if (item?.guid) {
+ setHome(false);
+ setHost(actions.getCard(item.guid));
+ let contacts = [];
+ for (let member of item.channel.data.channelDetail.members) {
+ if (member != state.guid) {
+ contacts.push(actions.getCard(member));
+ }
+ }
+ setMembers(contacts);
+ }
+ else {
+ setHome(true);
+ let contacts = [];
+ for (let member of item.channel.data.channelDetail.members) {
+ contacts.push(actions.getCard(member));
+ }
+ setMembers(contacts);
+ }
+
+ }, [item, state]);
+
+ const Logo = ({card}) => {
+ if (card?.data?.cardProfile?.imageSet) {
+ let imageUrl = actions.getCardImageUrl(card?.id, card?.revision);
+ return
+ }
+ return
+ }
+
+ if (members.length == 0 && home) {
+ return (
+
+
+
+ )
+ }
+ else if (members.length == 0 && !home) {
+ return (
+
+
+
+ )
+ }
+ else if (members.length == 1 && home) {
+ return (
+
+
+
+ )
+ }
+ else if (members.length == 1 && !home) {
+ return (
+
+
+
+ )
+ }
+ else if (members.length == 2 && home) {
+ return (
+
+
+
+ )
+ }
+ else if (members.length == 2 && !home) {
+ return (
+
+
+
+ )
+ }
+ else if (members.length == 3 && home) {
+ return (
+
+
+
+ )
+ }
+ else if (members.length > 2 && !home) {
+ return (
+
+
+
+ )
+ }
+ else if (members.length > 3 && home) {
+ return (
+
+
+
+ )
+ }
+ return <>>
+}
+
diff --git a/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLogo/ChannelLogo.styled.js b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLogo/ChannelLogo.styled.js
new file mode 100644
index 00000000..309106b7
--- /dev/null
+++ b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLogo/ChannelLogo.styled.js
@@ -0,0 +1,90 @@
+import styled from 'styled-components';
+
+export const LogoWrapper = styled.div`
+ height: 48px;
+ width: 48px;
+ display: flex;
+ flex-shrink: 0;
+ align-items: center;
+ justify-content: center;
+
+ .container {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .grid {
+ position: relative;
+ margin-left: 2px;
+ margin-right: 2px;
+ width: 44px;
+ height: 40px;
+ }
+
+ .large {
+ border-radius: 18px;
+ width: 32px;
+ height: 32px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .medium {
+ border-radius: 16px;
+ width: 24px;
+ height: 24px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .small {
+ border-radius: 16px;
+ width: 20px;
+ height: 20px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .host {
+ overflow: hidden;
+ border: 2px solid #88cc88;
+ }
+
+ .contact {
+ overflow: hidden;
+ border: 1px solid #777777;
+ }
+
+ .topleft {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ }
+
+ .topright {
+ position: absolute;
+ top: 0px;
+ right: 0px;
+ }
+
+ .bottomright {
+ position: absolute;
+ bottom: 0px;
+ right: 0px;
+ }
+
+ .bottom {
+ position: absolute;
+ bottom: 0px;
+ left: 12px;
+ }
+`;
+
+export const ChannelImage = styled.img`
+ width: 100%;
+ height: 100%;
+`;
diff --git a/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLogo/useChannelLogo.hook.js b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLogo/useChannelLogo.hook.js
new file mode 100644
index 00000000..d5f467b5
--- /dev/null
+++ b/net/web/src/User/SideBar/Contacts/Channels/ChannelItem/ChannelLogo/useChannelLogo.hook.js
@@ -0,0 +1,32 @@
+import { useContext, useState, useEffect } from 'react';
+import { AppContext } from '../../../../../../AppContext/AppContext';
+import { getCardImageUrl } from '../../../../../../Api/getCardImageUrl';
+
+export function useChannelLogo() {
+
+ const [state, setState] = useState({
+ guid: null
+ });
+
+ const app = useContext(AppContext);
+
+ const actions = {
+ getCardImageUrl: (cardId, revision) => {
+ if (app?.state?.token) {
+ return getCardImageUrl(app.state.token, cardId, revision)
+ }
+ return null;
+ },
+ getCard: app?.actions?.getCard,
+ };
+
+ const updateState = (value) => {
+ setState((s) => ({ ...s, ...value }));
+ }
+
+ useEffect(() => {
+ updateState({ guid: app?.state?.Data?.profile?.guid })
+ }, [app])
+
+ return { state, actions };
+}
diff --git a/net/web/src/User/SideBar/Contacts/Channels/Channels.jsx b/net/web/src/User/SideBar/Contacts/Channels/Channels.jsx
index aa2bbe6a..0a037133 100644
--- a/net/web/src/User/SideBar/Contacts/Channels/Channels.jsx
+++ b/net/web/src/User/SideBar/Contacts/Channels/Channels.jsx
@@ -1,25 +1,20 @@
import React, { useEffect, useState } from 'react'
-import { ChannelsWrapper, ChannelItem } from './Channels.styled';
+import { ChannelsWrapper } from './Channels.styled';
import { List, Button, Select, Modal } from 'antd';
import { useChannels } from './useChannels.hook';
import { AddChannel } from './AddChannel/AddChannel';
+import { ChannelItem } from './ChannelItem/ChannelItem';
export function Channels({ showAdd, setShowAdd }) {
const { state, actions } = useChannels();
-console.log(state.channels);
-
const onStart = async () => {
if (await actions.addChannel()) {
setShowAdd(false);
}
}
- const onSelect = (item) => {
- console.log(item);
- }
-
return (
(
- onSelect(item)}>
-
+
)}
/>