cleanup webapp cards component

This commit is contained in:
Roland Osborne 2023-01-20 17:54:10 -08:00
parent 8c343a7f60
commit d21473e76b
4 changed files with 84 additions and 115 deletions

View File

@ -10,53 +10,54 @@ export function Cards({ closeCards, openContact, openListing }) {
return (
<CardsWrapper>
<div class="search">
<div className="search">
{ !state.sorted && (
<div class="unsorted" onClick={() => actions.setSort(true)}>
<div className="unsorted" onClick={() => actions.setSort(true)}>
<SortAscendingOutlined />
</div>
)}
{ state.sorted && (
<div class="sorted" onClick={() => actions.setSort(false)}>
<div className="sorted" onClick={() => actions.setSort(false)}>
<SortAscendingOutlined />
</div>
)}
<div class="filter">
<div className="filter">
<Input bordered={false} allowClear={true} placeholder="Contacts" prefix={<SearchOutlined />}
spellCheck="false" onChange={(e) => actions.onFilter(e.target.value)} />
</div>
{ state.display === 'small' && (
<div class="inline">
<div class="add" onClick={openListing}>
<div className="inline">
<div className="add" onClick={openListing}>
<UserOutlined />
<div class="label">New</div>
<div className="label">New</div>
</div>
</div>
)}
{ state.display !== 'small' && (
<div class="inline">
<div class="dismiss" onClick={closeCards} >
<div className="inline">
<div className="dismiss" onClick={closeCards} >
<DoubleRightOutlined />
</div>
</div>
)}
</div>
<div class="view">
<div className="view">
{ state.cards.length > 0 && (
<List local={{ emptyText: '' }} itemLayout="horizontal" dataSource={state.cards} gutter="0"
renderItem={item => (
<CardItem item={item} open={openContact} />
<CardItem item={item} tooltip={state.tooltip} resync={() => actions.resync(item.cardId)}
open={() => openContact(item.guid)} />
)} />
)}
{ state.cards.length === 0 && (
<div class="empty">No Contacts</div>
<div className="empty">No Contacts</div>
)}
</div>
{ state.display !== 'small' && (
<div class="bar">
<div class="add" onClick={openListing}>
<div className="bar">
<div className="add" onClick={openListing}>
<UpOutlined />
<div class="label">Find New Contact</div>
<div className="label">Find New Contact</div>
</div>
</div>
)}

View File

@ -2,70 +2,58 @@ import { CardItemWrapper, StatusError,
StatusConnected, StatusConnecting,
StatusRequested, StatusPending,
StatusConfirmed} from './CardItem.styled';
import { useCardItem } from './useCardItem.hook';
import { Logo } from 'logo/Logo';
import { Tooltip } from 'antd';
import { ExclamationCircleOutlined } from '@ant-design/icons';
export function CardItem({ item, open }) {
export function CardItem({ item, tooltip, resync, open }) {
const { state, actions } = useCardItem(item);
const profile = item?.data?.cardProfile;
const detail = item?.data?.cardDetail;
const handle = () => {
if (profile?.node) {
return profile.handle + '@' + profile.node;
}
return profile?.handle;
}
const resync = (e) => {
const onResync = (e) => {
e.stopPropagation();
actions.resync();
resync();
};
return (
<CardItemWrapper onClick={() => open(profile.guid)}>
<Logo url={state.logo} width={32} height={32} radius={8} />
<div class="details">
<div class="name">{ profile?.name }</div>
<div class="handle">{ handle() }</div>
<CardItemWrapper onClick={open}>
<Logo url={item.logo} width={32} height={32} radius={8} />
<div className="details">
<div className="name">{ item.name }</div>
<div className="handle">{ item.handle }</div>
</div>
<div class="markup">
{ !state.resync && item.error && state.display === 'small' && (
<StatusError onClick={resync}>
<div className="markup">
{ item.offsync && !item.tooltip && (
<StatusError onClick={onResync}>
<ExclamationCircleOutlined />
</StatusError>
)}
{ !state.resync && item.error && state.display !== 'small' && (
{ item.offsync && item.tooltip && (
<Tooltip placement="left" title="sync error">
<StatusError onClick={resync}>
<StatusError onClick={onResync}>
<ExclamationCircleOutlined />
</StatusError>
</Tooltip>
)}
{ detail?.status === 'connected' && (
{ item.status === 'connected' && (
<Tooltip placement="left" title="connected contact">
<StatusConnected />
</Tooltip>
)}
{ detail?.status === 'requested' && (
{ item.status === 'requested' && (
<Tooltip placement="left" title="connection requested by contact">
<StatusRequested />
</Tooltip>
)}
{ detail?.status === 'connecting' && (
{ item.status === 'connecting' && (
<Tooltip placement="left" title="requested contact connection">
<StatusConnecting />
</Tooltip>
)}
{ detail?.status === 'pending' && (
{ item.status === 'pending' && (
<Tooltip placement="left" title="unknwon contact connection request">
<StatusPending />
</Tooltip>
)}
{ detail?.status === 'confirmed' && (
{ item.status === 'confirmed' && (
<Tooltip placement="left" title="disconnected contact">
<StatusConfirmed />
</Tooltip>

View File

@ -1,39 +0,0 @@
import { useContext, useState, useEffect } from 'react';
import { CardContext } from 'context/CardContext';
import { ViewportContext } from 'context/ViewportContext';
export function useCardItem(item) {
const [state, setState] = useState({
logo: null,
resync: false,
});
const card = useContext(CardContext);
const viewport = useContext(ViewportContext);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
}
useEffect(() => {
updateState({ logo: card.actions.getCardImageUrl(item.id) });
}, [card, item]);
useEffect(() => {
updateState({ display: viewport.state.display });
}, [viewport]);
const actions = {
resync: async () => {
if (!state.resync) {
updateState({ resync: true });
await card.actions.resync(item.id);
updateState({ resync: false });
}
},
};
return { state, actions };
}

View File

@ -8,10 +8,10 @@ export function useCards() {
const [filter, setFilter] = useState(null);
const [state, setState] = useState({
tooltip: false,
sorted: false,
display: null,
cards: [],
busy: false
});
const card = useContext(CardContext);
@ -22,44 +22,45 @@ export function useCards() {
setState((s) => ({ ...s, ...value }));
}
const actions = {
onFilter: (value) => {
setFilter(value.toUpperCase());
},
setSort: (value) => {
updateState({ sorted: value });
},
};
useEffect(() => {
let updated = 0;
const contacts = Array.from(card.state.cards.values());
const contacts = Array.from(card.state.cards.values()).map(item => {
const profile = item?.data?.cardProfile;
const detail = item?.data?.cardDetail;
const cardId = item.id;
const updated = detail?.statusUpdated;
const status = detail?.status;
const offsync = item.offsync;
const guid = profile?.guid;
const name = profile?.name;
const handle = profile?.node ? `${profile.handle}@${profile.node}` : profile.handle;
const logo = profile?.imageSet ? card.actions.getCardImageUrl(item.id) : null;
return { cardId, guid, updated, offsync, status, name, handle, logo };
});
let latest = 0;
contacts.forEach(contact => {
if (!updated || updated < contact?.data?.cardDetail?.statusUpdated) {
updated = contact?.data?.cardDetail?.statusUpdated;
if (latest < contact.updated) {
latest = contact.updated;
}
});
store.actions.setValue('cards:updated', updated);
// eslint-disable-next-line
}, [card]);
useEffect(() => {
const contacts = Array.from(card.state.cards.values());
let filtered = contacts.filter((contact) => {
store.actions.setValue('cards:updated', latest);
let filtered = contacts.filter(contact => {
if (!filter) {
return true;
}
if (!contact?.data?.cardProfile?.name) {
if (!contact.name) {
return false;
}
return contact.data.cardProfile.name.toUpperCase().includes(filter);
return contact.name.toUpperCase().includes(filter);
});
if (state.sorted) {
filtered.sort((a, b) => {
let aName = a?.data?.cardProfile?.name;
let bName = b?.data?.cardProfile?.name;
let aName = a?.name;
let bName = b?.name;
if (aName === bName) {
return 0;
}
@ -71,8 +72,8 @@ export function useCards() {
}
else {
filtered.sort((a, b) => {
const aUpdated = a?.data?.cardDetail?.statusUpdated;
const bUpdated = b?.data?.cardDetail?.statusUpdated;
const aUpdated = a?.updated;
const bUpdated = b?.updated;
if (aUpdated === bUpdated) {
return 0;
}
@ -85,11 +86,29 @@ export function useCards() {
updateState({ cards: filtered });
}, [card, filter, state.sorted]);
// eslint-disable-next-line
}, [card.state, state.sorted, filter]);
useEffect(() => {
updateState({ display: viewport.state.display });
}, [viewport]);
if (viewport.state.display === 'small') {
updateState({ tooltip: false });
}
else {
updateState({ tooltip: true });
}
}, [viewport.state]);
const actions = {
onFilter: (value) => {
setFilter(value.toUpperCase());
},
setSort: (value) => {
updateState({ sorted: value });
},
resync: async (cardId) => {
await card.actions.resync(cardId);
},
};
return { state, actions };
}