refactor of channel view

This commit is contained in:
Roland Osborne 2023-01-16 10:34:34 -08:00
parent f0134493db
commit 720537e3d5
5 changed files with 129 additions and 196 deletions

View File

@ -146,7 +146,6 @@ export function useCardContext() {
const syncCard = async (token, card) => { const syncCard = async (token, card) => {
const { cardProfile, cardDetail } = card.data; const { cardProfile, cardDetail } = card.data;
// sync profile // sync profile
if (card.data.setNotifiedProfile !== card.data.curNotifiedProfile) { if (card.data.setNotifiedProfile !== card.data.curNotifiedProfile) {
if (card.data.profileRevision !== card.data.curNotifiedProfile) { if (card.data.profileRevision !== card.data.curNotifiedProfile) {
@ -174,7 +173,7 @@ export function useCardContext() {
const syncCardChannels = async (card) => { const syncCardChannels = async (card) => {
const { cardProfile, cardDetail } = card.data; const { cardProfile, cardDetail } = card.data;
const { node } = cardProfile.node; const node = cardProfile.node;
const token = `${cardProfile.guid}.${cardDetail.token}`; const token = `${cardProfile.guid}.${cardDetail.token}`;
let delta; let delta;
if (card.data.setNotifiedView !== card.data.curNotifiedView) { if (card.data.setNotifiedView !== card.data.curNotifiedView) {
@ -183,7 +182,7 @@ export function useCardContext() {
} }
else { else {
const { setNotifiedView, setNotifiedChannel } = card.data; const { setNotifiedView, setNotifiedChannel } = card.data;
delta = await getContactChannels(node, setNotifiedView, setNotifiedChannel); delta = await getContactChannels(node, token, setNotifiedView, setNotifiedChannel);
} }
for (let channel of delta) { for (let channel of delta) {
if (channel.data) { if (channel.data) {
@ -206,7 +205,7 @@ export function useCardContext() {
cur.data.channelSummary = channel.data.channelSummary; cur.data.channelSummary = channel.data.channelSummary;
} }
else { else {
cur.data.channelSummary = getContactChannelSummary(node, token, channel.id); cur.data.channelSummary = await getContactChannelSummary(node, token, channel.id);
} }
cur.data.unsealedSummary = null; cur.data.unsealedSummary = null;
cur.data.topicRevision = channel.data.topicRevision; cur.data.topicRevision = channel.data.topicRevision;

View File

@ -47,10 +47,7 @@ export function Channels({ open, active }) {
</div> </div>
{ state.display === 'small' && ( { state.display === 'small' && (
<div class="inline"> <div class="inline">
<div class="add" onClick={actions.setShowAdd}> <Button type="primary" icon={<CommentOutlined />} onClick={actions.setShowAdd}>New</Button>
<CommentOutlined />
<div class="label">New</div>
</div>
</div> </div>
)} )}
</div> </div>
@ -68,10 +65,7 @@ export function Channels({ open, active }) {
</div> </div>
{ state.display !== 'small' && ( { state.display !== 'small' && (
<div class="bar"> <div class="bar">
<div class="add" onClick={actions.setShowAdd}> <Button type="primary" icon={<CommentOutlined />} onClick={actions.setShowAdd}>New Topic</Button>
<CommentOutlined />
<div class="label">New Topic</div>
</div>
</div> </div>
)} )}
<Modal title="New Topic" centered visible={state.showAdd} footer={addFooter} <Modal title="New Topic" centered visible={state.showAdd} footer={addFooter}

View File

@ -6,80 +6,35 @@ import { AppstoreFilled, SolutionOutlined, UnlockOutlined, LockFilled } from '@a
export function ChannelItem({ item, openChannel, active }) { export function ChannelItem({ item, openChannel, active }) {
const itemClass = () => { const itemClass = () => {
if (active.set && active.channel === item.id && active.card === item.cardId) { if (active.set && active.channel === item.channelId && active.card === item.cardId) {
return "active" return "active"
} }
return "idle" return "idle"
}; };
return ( return (
<ChannelItemWrapper onClick={() => openChannel(item.id, item.cardId)}> <ChannelItemWrapper onClick={() => openChannel(item.channelId, item.cardId)}>
<div class={itemClass()}> <div class={itemClass()}>
{ item.contacts.length === 0 && ( <div class="item">
<div class="item"> <div class="avatar">
<div class="logo"> <Logo url={item.logo} img={item.img} width={32} height={32} radius={8} />
<SolutionOutlined />
</div>
<div class="details">
<div class="subject">
{ item.locked && !item.unlocked && (
<LockFilled style={{ paddingRight: 8 }}/>
)}
{ item.locked && item.unlocked && (
<UnlockOutlined style={{ paddingRight: 8 }}/>
)}
<span>{ item.subject }</span>
</div>
<div class="message">{ item.message }</div>
</div>
</div> </div>
)} <div class="details">
{ item.contacts.length === 1 && ( <div class="subject">
<div class="item"> { item.locked && !item.unlocked && (
<div class="avatar"> <LockFilled style={{ paddingRight: 8 }}/>
<Logo url={item.logo} width={32} height={32} radius={8} /> )}
{ item.locked && item.unlocked && (
<UnlockOutlined style={{ paddingRight: 8 }}/>
)}
<span>{ item.subject }</span>
</div> </div>
<div class="details"> <div class="message">{ item.message }</div>
<div class="subject">
{ item.locked && !item.unlocked && (
<LockFilled style={{ paddingRight: 8 }}/>
)}
{ item.locked && item.unlocked && (
<UnlockOutlined style={{ paddingRight: 8 }}/>
)}
<span>{ item.subject }</span>
</div>
<div class="message">{ item.message }</div>
</div>
{ item.updated && (
<Markup />
)}
</div> </div>
)} { item.updatedFlag && (
{ item.contacts.length > 1 && ( <Markup />
<div class="item"> )}
<div class="logo"> </div>
<AppstoreFilled />
</div>
<div class="details">
<div class="subject">
{ item.locked && !item.unlocked && (
<LockFilled style={{ paddingRight: 8 }}/>
)}
{ item.locked && item.unlocked && (
<UnlockOutlined style={{ paddingRight: 8 }}/>
)}
<span>{ item.subject }</span>
</div>
<div class="message">{ item.message }</div>
</div>
{ item.updated && (
<Tooltip placement="right" title="new message">
<Markup />
</Tooltip>
)}
</div>
)}
</div> </div>
</ChannelItemWrapper> </ChannelItemWrapper>
) )

View File

@ -1,4 +1,4 @@
import { useContext, useState, useEffect } from 'react'; import { useContext, useState, useEffect, useRef } from 'react';
import { StoreContext } from 'context/StoreContext'; import { StoreContext } from 'context/StoreContext';
import { ChannelContext } from 'context/ChannelContext'; import { ChannelContext } from 'context/ChannelContext';
import { CardContext } from 'context/CardContext'; import { CardContext } from 'context/CardContext';
@ -118,162 +118,148 @@ export function useChannels() {
}, },
}; };
const setUpdated = (chan) => { // 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']; const login = store.state['login:timestamp'];
const update = chan?.data?.channelSummary?.lastTopic?.created; if (!chan.updated || !login || chan.updated < login) {
chan.updatedFlag = false;
if (!update || (login && update < login)) {
chan.updated = false;
return;
} }
else if (store.state[key] && store.state[key] === value.revision) {
let key = `${chan.id}::${chan.cardId}` chan.updatedFlag = false;
if (store.state[key] && store.state[key] === chan.revision) {
chan.updated = false;
} }
else { else {
chan.updated = true; chan.updatedFlag = true;
} }
}
const setContacts = (chan) => { // extract member info
let contacts = []; let memberCount = 0;
if (chan.guid != null && profile.state.identity.guid !== chan.guid) { let names = [];
const contact = getCardByGuid(card.state.cards, chan.guid); let img = null;
contacts.push(contact); 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 chan.data.channelDetail?.members) { for (let guid of value?.data?.channelDetail?.members) {
if (guid !== profile.state.identity.guid) { if (guid !== profile.state.identity.guid) {
const contact = getCardByGuid(card.state.cards, guid); const contact = getCardByGuid(card.state.cards, guid);
contacts.push(contact); 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++;
} }
} }
chan.contacts = contacts;
if (contacts.length === 1 && contacts[0]) {
chan.logo = card.actions.getCardImageUrl(contacts[0].id);
}
}
const setSubject = (chan) => { // set logo and label
let subject = ""; if (memberCount === 0) {
if (chan.data.channelDetail.dataType === 'sealed') { chan.img = 'solution';
chan.locked = chan.data.channelDetail.dataType === 'sealed' chan.label = 'Notes';
if (state.sealable) { }
try { else if (memberCount === 1) {
if (chan.data.unsealedChannel == null) { chan.logo = logo;
if (chan.cardId) { chan.img = img;
card.actions.unsealChannelSubject(chan.cardId, chan.id, account.state.sealKey); chan.label = names.join(',');
}
else {
channel.actions.unsealChannelSubject(chan.id, account.state.sealKey);
}
}
else {
if (chan.cardId) {
chan.unlocked = card.actions.isUnsealed(chan.cardId, chan.id, account.state.sealKey);
}
else {
chan.unlocked = channel.actions.isUnsealed(chan.id, account.state.sealKey);
}
subject = chan.data.unsealedChannel.subject;
}
}
catch (err) {
console.log(err)
}
}
} }
else { else {
if (chan.data.channelDetail?.data) { chan.img = 'appstore';
try { chan.label = names.join(',');
subject = JSON.parse(chan.data.channelDetail?.data).subject;
}
catch (err) {
console.log(err);
}
}
}
if (!subject) {
let names = [];
for (let contact of chan.contacts) {
names.push(contact?.data?.cardProfile?.name);
}
subject = names.join(", ");
}
if (!subject && !chan.contacts?.length) {
subject = "Notes";
} }
chan.subject = subject; // set subject
} const detail = value.data?.channelDetail;
if (detail?.dataType === 'sealedchannel') {
const setMessage = (chan) => { // handle sealed subject
let message = ''; chan.locked = true;
if (chan.data.channelSummary?.lastTopic?.dataType === 'superbasictopic') { chan.unlocked = false;
}
else if (detail?.dataType === 'superbasic') {
chan.locked = false;
chan.unlocked = true;
try { try {
message = JSON.parse(chan.data.channelSummary.lastTopic.data).text; const data = JSON.parse(detail.data);
chan.subject = data.subject;
} }
catch (err) { catch(err) {
console.log(err); console.log(err);
} }
} }
if (chan.data.channelSummary?.lastTopic?.dataType === 'sealedtopic') { 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 { try {
if (chan.unlocked) { const data = JSON.parse(topic.data);
message = "..."; chan.message = data.text;
if (chan.data.unsealedSummary == null) {
if (chan.cardId) {
card.actions.unsealChannelSummary(chan.cardId, chan.id, account.state.sealKey);
}
else {
channel.actions.unsealChannelSummary(chan.id, account.state.sealKey);
}
}
else {
if (typeof chan.data.unsealedSummary.message.text === 'string') {
message = chan.data.unsealedSummary.message.text;
}
}
}
} }
catch (err) { catch(err) {
console.log(err) console.log(err);
} }
} }
if (typeof message === 'string') { return chan;
chan.message = message; }
}
}
useEffect(() => { useEffect(() => {
let merged = []; const merged = [];
card.state.cards.forEach((value, key, map) => { card.state.cards.forEach((cardValue, cardKey) => {
merged.push(...Array.from(value.channels.values())); cardValue.channels.forEach((channelValue, channelKey) => {
const chan = getChannel(cardKey, channelKey, channelValue);
merged.push(chan);
});
});
channel.state.channels.forEach((channelValue, channelKey) => {
merged.push(getChannel(null, channelKey, channelValue));
}); });
merged.push(...Array.from(channel.state.channels.values()));
merged.sort((a, b) => { merged.sort((a, b) => {
const aCreated = a?.data?.channelSummary?.lastTopic?.created; const aUpdated = a.updated;
const bCreated = b?.data?.channelSummary?.lastTopic?.created; const bUpdated = b.updated;
if (aCreated === bCreated) { if (aUpdated === bUpdated) {
return 0; return 0;
} }
if (!aCreated || aCreated < bCreated) { if (!aUpdated || aUpdated < bUpdated) {
return 1; return 1;
} }
return -1; return -1;
}); });
merged.forEach(chan => {
setUpdated(chan);
setContacts(chan);
setSubject(chan);
setMessage(chan);
});
const filtered = merged.filter((chan) => { const filtered = merged.filter((chan) => {
let subject = chan?.subject?.toUpperCase(); const subject = chan?.subject?.toUpperCase();
return !filter || subject?.includes(filter); return !filter || subject?.includes(filter);
}); });

View File

@ -29,7 +29,6 @@ export function useSession() {
const card = useContext(CardContext); const card = useContext(CardContext);
const store = useContext(StoreContext); const store = useContext(StoreContext);
const viewport = useContext(ViewportContext); const viewport = useContext(ViewportContext);
const channel = useContext(ChannelContext);
const profile = useContext(ProfileContext); const profile = useContext(ProfileContext);
const navigate = useNavigate(); const navigate = useNavigate();
@ -48,7 +47,7 @@ export function useSession() {
else { else {
updateState({ loading: false }); updateState({ loading: false });
} }
}, [card, channel, profile]); }, [profile]);
useEffect(() => { useEffect(() => {
if (!app.state.status) { if (!app.state.status) {