added remainder of details

This commit is contained in:
Roland Osborne 2022-08-20 21:17:25 -07:00
parent a0bb8d5c6c
commit 1317c6f6d7
12 changed files with 237 additions and 50 deletions

BIN
net/web/src/images/team.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,10 +1,14 @@
import avatar from 'images/avatar.png'; import avatar from 'images/avatar.png';
import appstore from 'images/appstore.png'; import appstore from 'images/appstore.png';
import solution from 'images/solution.png'; import solution from 'images/solution.png';
import team from 'images/team.png';
export function Logo({ url, width, height, radius, img }) { export function Logo({ url, width, height, radius, img }) {
return ( return (
<div style={{ borderRadius: radius, overflow: 'hidden' }}> <div style={{ borderRadius: radius, overflow: 'hidden' }}>
{ img === 'team' && (
<img src={team} alt="direct logo" width={width} height={height} />
)}
{ img === 'appstore' && ( { img === 'appstore' && (
<img src={appstore} alt="group logo" width={width} height={height} /> <img src={appstore} alt="group logo" width={width} height={height} />
)} )}

View File

@ -4,7 +4,7 @@ import { CardSelectWrapper } from './CardSelect.styled';
import { SelectItem } from './selectItem/SelectItem'; import { SelectItem } from './selectItem/SelectItem';
import { useCardSelect } from './useCardSelect.hook'; import { useCardSelect } from './useCardSelect.hook';
export function CardSelect({ filter, unknown, select, selected }) { export function CardSelect({ filter, unknown, select, selected, markup }) {
const { state, actions } = useCardSelect(filter); const { state, actions } = useCardSelect(filter);
@ -12,7 +12,7 @@ export function CardSelect({ filter, unknown, select, selected }) {
<CardSelectWrapper> <CardSelectWrapper>
<List local={{ emptyText: '' }} itemLayout="horizontal" dataSource={state.cards} gutter="0" <List local={{ emptyText: '' }} itemLayout="horizontal" dataSource={state.cards} gutter="0"
renderItem={item => ( renderItem={item => (
<SelectItem item={item} select={select} selected={selected} /> <SelectItem item={item} select={select} selected={selected} markup={markup} />
)} )}
/> />
</CardSelectWrapper> </CardSelectWrapper>

View File

@ -1,11 +1,11 @@
import { Switch } from 'antd'; import { Switch, Tooltip } from 'antd';
import { SelectItemWrapper } from './SelectItem.styled'; import { SelectItemWrapper, Markup } from './SelectItem.styled';
import { useSelectItem } from './useSelectItem.hook'; import { useSelectItem } from './useSelectItem.hook';
import { Logo } from 'logo/Logo'; import { Logo } from 'logo/Logo';
export function SelectItem({ item, select, selected }) { export function SelectItem({ item, select, selected, markup }) {
const { state, actions } = useSelectItem(item, selected); const { state, actions } = useSelectItem(item, selected, markup);
const profile = item?.data?.cardProfile; const profile = item?.data?.cardProfile;
const detail = item?.data?.cardDetail; const detail = item?.data?.cardDetail;
@ -16,18 +16,31 @@ export function SelectItem({ item, select, selected }) {
return profile?.handle; return profile?.handle;
} }
const onSelect = () => {
if (select) {
select(item.id);
}
}
return ( return (
<SelectItemWrapper onClick={() => select(item.id)}> <SelectItemWrapper onClick={onSelect}>
<Logo url={state.logo} width={32} height={32} radius={8} /> <div class={ state.className }>
<div class="details"> <Logo url={state.logo} width={32} height={32} radius={8} />
<div class="name">{ profile?.name }</div> <div class="details">
<div class="handle">{ handle() }</div> <div class="name">{ profile?.name }</div>
</div> <div class="handle">{ handle() }</div>
{ select && (
<div class="switch">
<Switch checked={state.selected} onChange={() => select(item.id)} size="small" />
</div> </div>
)} { select && (
<div class="switch">
<Switch checked={state.selected} onChange={onSelect} size="small" />
</div>
)}
{ state.markup && (
<Tooltip placement="left" title="channel host">
<Markup />
</Tooltip>
)}
</div>
</SelectItemWrapper> </SelectItemWrapper>
); );
} }

View File

@ -2,16 +2,27 @@ import styled from 'styled-components';
import Colors from 'constants/Colors'; import Colors from 'constants/Colors';
export const SelectItemWrapper = styled.div` export const SelectItemWrapper = styled.div`
height: 48px; .active {
width: 100%; cursor: pointer;
display: flex; height: 48px;
align-items: center; width: 100%;
padding-left: 8px; padding-left: 8px;
padding-right: 8px; padding-right: 8px;
cursor: pointer; display: flex;
align-items: center;
&:hover { &:hover {
background-color: ${Colors.selectHover}; background-color: ${Colors.selectHover};
}
}
.passive {
height: 48px;
width: 100%;
padding-left: 8px;
padding-right: 8px;
display: flex;
align-items: center;
} }
.details { .details {
@ -41,3 +52,12 @@ export const SelectItemWrapper = styled.div`
flex-shrink: 0; flex-shrink: 0;
} }
` `
export const Markup = styled.div`
background-color: ${Colors.connected};
border-radius: 8px;
width: 8px;
height: 8px;
margin-right: 8px;
`;

View File

@ -1,12 +1,14 @@
import { useContext, useState, useEffect } from 'react'; import { useContext, useState, useEffect } from 'react';
import { CardContext } from 'context/CardContext'; import { CardContext } from 'context/CardContext';
export function useSelectItem(item, selected) { export function useSelectItem(item, selected, markup) {
const [state, setState] = useState({ const [state, setState] = useState({
logo: null, logo: null,
selected: false, selected: false,
busy: false, busy: false,
className: 'passive',
markup: false,
}); });
const card = useContext(CardContext); const card = useContext(CardContext);
@ -16,7 +18,12 @@ export function useSelectItem(item, selected) {
} }
useEffect(() => { useEffect(() => {
updateState({ selected: selected.has(item.id) }); if (selected) {
updateState({ className: 'active', selected: selected.has(item.id) });
}
else {
updateState({ className: 'passive', markup: item.id === markup });
}
}, [selected]); }, [selected]);
useEffect(() => { useEffect(() => {

View File

@ -17,7 +17,7 @@ export function useCardSelect(filter) {
let contacts = Array.from(card.state.cards.values()); let contacts = Array.from(card.state.cards.values());
let filtered = contacts.filter(filter); let filtered = contacts.filter(filter);
updateState({ cards: filtered }); updateState({ cards: filtered });
}, [card]); }, [card, filter]);
const actions = { const actions = {
}; };

View File

@ -1,4 +1,5 @@
import { ChannelItemWrapper } from './ChannelItem.styled'; import { Tooltip } from 'antd';
import { ChannelItemWrapper, Markup } from './ChannelItem.styled';
import { Logo } from 'logo/Logo'; import { Logo } from 'logo/Logo';
import { AppstoreFilled, SolutionOutlined } from '@ant-design/icons'; import { AppstoreFilled, SolutionOutlined } from '@ant-design/icons';
@ -39,7 +40,9 @@ export function ChannelItem({ item, openChannel }) {
<div class="message">{ item.message }</div> <div class="message">{ item.message }</div>
</div> </div>
{ item.updated && ( { item.updated && (
<div class="markup"></div> <Tooltip placement="right" title="new message">
<Markup />
</Tooltip>
)} )}
</div> </div>
)} )}

View File

@ -55,15 +55,15 @@ export const ChannelItemWrapper = styled.div`
color: ${Colors.disabled}; color: ${Colors.disabled};
} }
} }
.markup {
position: absolute;
right: 0;
border-radius: 8px;
background-color: ${Colors.background};
width: 8px;
height: 8px;
margin-right: 16px;
}
} }
`
export const Markup = styled.div`
position: absolute;
right: 0;
border-radius: 8px;
background-color: ${Colors.background};
width: 8px;
height: 8px;
margin-right: 16px;
`; `;

View File

@ -1,12 +1,17 @@
import { Space } from 'antd';
import { DetailsWrapper } from './Details.styled'; import { DetailsWrapper } from './Details.styled';
import { DoubleRightOutlined } from '@ant-design/icons'; import { DoubleRightOutlined } from '@ant-design/icons';
import { useDetails } from './useDetails.hook'; import { useDetails } from './useDetails.hook';
import { Logo } from 'logo/Logo'; import { Logo } from 'logo/Logo';
import { EditOutlined } from '@ant-design/icons';
import { CardSelect } from '../cardSelect/CardSelect';
export function Details({ cardId, channelId, closeDetails, closeConversation, openContact }) { export function Details({ cardId, channelId, closeDetails, closeConversation, openContact }) {
const { state, actions } = useDetails(cardId, channelId); const { state, actions } = useDetails(cardId, channelId);
console.log(state.contacts);
return ( return (
<DetailsWrapper> <DetailsWrapper>
<div class="header"> <div class="header">
@ -16,8 +21,51 @@ export function Details({ cardId, channelId, closeDetails, closeConversation, op
</div> </div>
</div> </div>
<div class="content" onClick={closeDetails}> <div class="content" onClick={closeDetails}>
<div class="details"> <div class="description">
<Logo url={state.logo} width={48} height={48} radius={4} img={state.img} /> <div class="logo">
<Logo width={72} height={72} radius={4} img={state.img} />
</div>
<div class="stats">
{ state.host && (
<div class="subject edit">
<Space>
<div>{ state.subject }</div>
<EditOutlined />
</Space>
</div>
)}
{ !state.host && (
<div class="subject">{ state.subject }</div>
)}
{ state.host && (
<div class="host">host</div>
)}
{ !state.host && (
<div class="host">guest</div>
)}
<div class="created">{ state.started }</div>
</div>
</div>
{ state.host && (
<div class="button">Delete Channel</div>
)}
{ state.host && (
<div class="button">Edit Membership</div>
)}
{ !state.host && (
<div class="button">Leave Channel</div>
)}
<div class="label">Members</div>
<div class="members">
<CardSelect filter={(item) => {
console.log("CHECK: ", item.id, state.contacts);
if(state.contacts.includes(item.id)) {
console.log("YES");
return true;
}
return false;
}} unknown={0}
markup={cardId} />
</div> </div>
</div> </div>
</DetailsWrapper> </DetailsWrapper>

View File

@ -38,9 +38,77 @@ export const DetailsWrapper = styled.div`
overflow: scroll; overflow: scroll;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center;
padding-top: 32px; padding-top: 32px;
align-items: center; align-items: center;
flex-grow: 1; flex-grow: 1;
position: relative;
.label {
padding-top: 16px;
width: 100%;
border-bottom: 1px solid ${Colors.divider};
padding-left: 16px;
}
.members {
width: 100%;
min-height: 0;
overflow: scroll;
padding-left: 16px;
}
.button {
width: 144px;
padding: 4px;
border-radius: 4px;
color: ${Colors.white};
background-color: ${Colors.primary};
cursor: pointer;
margin-bottom: 8px;
display: flex;
align-items: center;
justify-content: center;
}
.description {
display: flex;
flex-direction: row;
margin-bottom: 32px;
width: 100%;
.logo {
flex-shrink: 0;
width: 40%;
display: flex;
flex-direction: row;
justify-content: flex-end;
}
.stats {
display: flex;
flex-direction: column;
padding-left: 16px;
.edit {
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
}
.subject {
font-size: 18px;
font-weight: bold;
padding-right: 8px;
}
.host {
font-size: 16px;
}
.created {
font-size: 14px;
}
}
} }
` `

View File

@ -7,6 +7,12 @@ export function useDetails(cardId, channelId) {
const [state, setState] = useState({ const [state, setState] = useState({
logo: null, logo: null,
img: null, img: null,
subject: null,
server: null,
startedDate: null,
startedTime: null,
host: null,
contacts: [],
}); });
const card = useContext(CardContext); const card = useContext(CardContext);
@ -17,7 +23,7 @@ export function useDetails(cardId, channelId) {
} }
useEffect(() => { useEffect(() => {
let logo, img; let img, subject, host, started;
let chan; let chan;
if (cardId) { if (cardId) {
const cardChan = card.state.cards.get(cardId); const cardChan = card.state.cards.get(cardId);
@ -28,23 +34,41 @@ export function useDetails(cardId, channelId) {
else { else {
chan = channel.state.channels.get(channelId); chan = channel.state.channels.get(channelId);
} }
console.log(chan);
if (chan) { if (chan) {
if (chan.contacts?.length == 0) { if (chan.contacts?.length == 0) {
img = 'solution'; img = 'solution';
logo = null; subject = 'Private';
} }
else if (chan.contacts?.length > 1) { else if (chan.contacts?.length > 1) {
img = 'appstore' img = 'appstore'
logo = null; subject = 'Group';
} }
else { else {
img = null; img = 'team';
logo = card.actions.getImageUrl(chan.contacts[0]?.id); subject = 'Direct'
}
const parsed = JSON.parse(chan.data.channelDetail.data);
if (parsed.subject) {
subject = parsed.subject;
}
const date = new Date(chan.data.channelDetail.created * 1000);
const now = new Date();
if(now.getTime() - date.getTime() < 86400000) {
started = date.toLocaleTimeString([], {hour: 'numeric', minute:'2-digit'});
}
else {
started = date.toLocaleDateString("en-US");
}
if (chan.cardId) {
host = false;
}
else {
host = true;
} }
} }
updateState({ logo, img }); updateState({ img, subject, host, started,
contacts: chan.contacts.map((contact) => contact?.id) });
}, [cardId, channelId, card, channel]); }, [cardId, channelId, card, channel]);
const actions = { const actions = {