mirror of
https://github.com/balzack/databag.git
synced 2025-02-11 19:19:16 +00:00
rendering basic channel list
This commit is contained in:
parent
3188385e75
commit
489239b10b
@ -3495,7 +3495,9 @@ components:
|
||||
contacts:
|
||||
$ref: '#/components/schemas/ChannelContacts'
|
||||
members:
|
||||
$ref: '#/components/schemas/ChannelMembers'
|
||||
type: array
|
||||
item:
|
||||
type: string
|
||||
|
||||
ChannelContacts:
|
||||
type: object
|
||||
|
@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
4
net/web/src/Api/getCardImageUrl.js
Normal file
4
net/web/src/Api/getCardImageUrl.js
Normal file
@ -0,0 +1,4 @@
|
||||
export function getCardImageUrl(token, cardId, revision) {
|
||||
return `/contact/cards/${cardId}/profile/image?agent=${token}&revision=${revision}`
|
||||
}
|
||||
|
@ -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') {
|
||||
|
@ -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 (
|
||||
<ChannelItemWrapper onClick={() => onSelect()}>
|
||||
<ChannelLogo item={item} />
|
||||
<ChannelLabel item={item} />
|
||||
</ChannelItemWrapper>
|
||||
)
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
`;
|
||||
|
@ -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 (<div><DatabaseOutlined /> { host.data.cardProfile.handle }</div>)
|
||||
}
|
||||
return <HomeOutlined />
|
||||
}
|
||||
|
||||
return (
|
||||
<LabelWrapper>
|
||||
<div class="subject">{subject}</div>
|
||||
<div class="host"><Host /></div>
|
||||
</LabelWrapper>
|
||||
)
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
`;
|
@ -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 };
|
||||
}
|
||||
|
@ -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 <ChannelImage src={ imageUrl } alt='' />
|
||||
}
|
||||
return <UserOutlined />
|
||||
}
|
||||
|
||||
if (members.length == 0 && home) {
|
||||
return (
|
||||
<LogoWrapper>
|
||||
<div class="container">
|
||||
<div class="large contact"><DisconnectOutlined /></div>
|
||||
</div>
|
||||
</LogoWrapper>
|
||||
)
|
||||
}
|
||||
else if (members.length == 0 && !home) {
|
||||
return (
|
||||
<LogoWrapper>
|
||||
<div class="container">
|
||||
<div class="large host"><Logo card={host} /></div>
|
||||
</div>
|
||||
</LogoWrapper>
|
||||
)
|
||||
}
|
||||
else if (members.length == 1 && home) {
|
||||
return (
|
||||
<LogoWrapper>
|
||||
<div class="container">
|
||||
<div class="large contact"><Logo card={members[0]} /></div>
|
||||
</div>
|
||||
</LogoWrapper>
|
||||
)
|
||||
}
|
||||
else if (members.length == 1 && !home) {
|
||||
return (
|
||||
<LogoWrapper>
|
||||
<div class="grid">
|
||||
<div class="medium host topleft"><Logo card={host} /></div>
|
||||
<div class="medium contact bottomright"><Logo card={members[0]} /></div>
|
||||
</div>
|
||||
</LogoWrapper>
|
||||
)
|
||||
}
|
||||
else if (members.length == 2 && home) {
|
||||
return (
|
||||
<LogoWrapper>
|
||||
<div class="grid">
|
||||
<div class="medium host topleft"><Logo card={members[0]} /></div>
|
||||
<div class="medium contact bottomright"><Logo card={members[1]} /></div>
|
||||
</div>
|
||||
</LogoWrapper>
|
||||
)
|
||||
}
|
||||
else if (members.length == 2 && !home) {
|
||||
return (
|
||||
<LogoWrapper>
|
||||
<div class="grid">
|
||||
<div class="small host topleft"><Logo card={host} /></div>
|
||||
<div class="small contact topright"><Logo card={members[0]} /></div>
|
||||
<div class="small contact bottom"><Logo card={members[1]} /></div>
|
||||
</div>
|
||||
</LogoWrapper>
|
||||
)
|
||||
}
|
||||
else if (members.length == 3 && home) {
|
||||
return (
|
||||
<LogoWrapper>
|
||||
<div class="grid">
|
||||
<div class="small contact topleft"><Logo card={members[0]} /></div>
|
||||
<div class="small contact topright"><Logo card={members[1]} /></div>
|
||||
<div class="small contact bottom"><Logo card={members[2]} /></div>
|
||||
</div>
|
||||
</LogoWrapper>
|
||||
)
|
||||
}
|
||||
else if (members.length > 2 && !home) {
|
||||
return (
|
||||
<LogoWrapper>
|
||||
<div class="grid">
|
||||
<div class="medium host topleft"><Logo card={host} /></div>
|
||||
<div class="medium contact bottomright">{members.length}</div>
|
||||
</div>
|
||||
</LogoWrapper>
|
||||
)
|
||||
}
|
||||
else if (members.length > 3 && home) {
|
||||
return (
|
||||
<LogoWrapper>
|
||||
<div class="container">
|
||||
<div class="large contact">{members.length}</div>
|
||||
</div>
|
||||
</LogoWrapper>
|
||||
)
|
||||
}
|
||||
return <></>
|
||||
}
|
||||
|
@ -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%;
|
||||
`;
|
@ -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 };
|
||||
}
|
@ -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 (
|
||||
<ChannelsWrapper>
|
||||
<List
|
||||
@ -28,8 +23,7 @@ console.log(state.channels);
|
||||
dataSource={state.channels}
|
||||
gutter="0"
|
||||
renderItem={item => (
|
||||
<ChannelItem onClick={() => onSelect(item)}>
|
||||
</ChannelItem>
|
||||
<ChannelItem item={item} />
|
||||
)}
|
||||
/>
|
||||
<Modal title="Start Conversation" visible={showAdd} centered
|
||||
|
@ -5,20 +5,8 @@ export const ChannelsWrapper = styled.div`
|
||||
position: relative;
|
||||
height: calc(100vh - 127px);
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
overflow: auto;
|
||||
text-align: center;
|
||||
border-radius: 2px;
|
||||
`;
|
||||
|
||||
export const ChannelItem = styled(List.Item)`
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
height: 64px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
`;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user