mirror of
https://github.com/balzack/databag.git
synced 2025-02-15 21:19:16 +00:00
cleanup webapp cards component
This commit is contained in:
parent
8c343a7f60
commit
d21473e76b
@ -10,53 +10,54 @@ export function Cards({ closeCards, openContact, openListing }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<CardsWrapper>
|
<CardsWrapper>
|
||||||
<div class="search">
|
<div className="search">
|
||||||
{ !state.sorted && (
|
{ !state.sorted && (
|
||||||
<div class="unsorted" onClick={() => actions.setSort(true)}>
|
<div className="unsorted" onClick={() => actions.setSort(true)}>
|
||||||
<SortAscendingOutlined />
|
<SortAscendingOutlined />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{ state.sorted && (
|
{ state.sorted && (
|
||||||
<div class="sorted" onClick={() => actions.setSort(false)}>
|
<div className="sorted" onClick={() => actions.setSort(false)}>
|
||||||
<SortAscendingOutlined />
|
<SortAscendingOutlined />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div class="filter">
|
<div className="filter">
|
||||||
<Input bordered={false} allowClear={true} placeholder="Contacts" prefix={<SearchOutlined />}
|
<Input bordered={false} allowClear={true} placeholder="Contacts" prefix={<SearchOutlined />}
|
||||||
spellCheck="false" onChange={(e) => actions.onFilter(e.target.value)} />
|
spellCheck="false" onChange={(e) => actions.onFilter(e.target.value)} />
|
||||||
</div>
|
</div>
|
||||||
{ state.display === 'small' && (
|
{ state.display === 'small' && (
|
||||||
<div class="inline">
|
<div className="inline">
|
||||||
<div class="add" onClick={openListing}>
|
<div className="add" onClick={openListing}>
|
||||||
<UserOutlined />
|
<UserOutlined />
|
||||||
<div class="label">New</div>
|
<div className="label">New</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{ state.display !== 'small' && (
|
{ state.display !== 'small' && (
|
||||||
<div class="inline">
|
<div className="inline">
|
||||||
<div class="dismiss" onClick={closeCards} >
|
<div className="dismiss" onClick={closeCards} >
|
||||||
<DoubleRightOutlined />
|
<DoubleRightOutlined />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div class="view">
|
<div className="view">
|
||||||
{ state.cards.length > 0 && (
|
{ state.cards.length > 0 && (
|
||||||
<List local={{ emptyText: '' }} itemLayout="horizontal" dataSource={state.cards} gutter="0"
|
<List local={{ emptyText: '' }} itemLayout="horizontal" dataSource={state.cards} gutter="0"
|
||||||
renderItem={item => (
|
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 && (
|
{ state.cards.length === 0 && (
|
||||||
<div class="empty">No Contacts</div>
|
<div className="empty">No Contacts</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{ state.display !== 'small' && (
|
{ state.display !== 'small' && (
|
||||||
<div class="bar">
|
<div className="bar">
|
||||||
<div class="add" onClick={openListing}>
|
<div className="add" onClick={openListing}>
|
||||||
<UpOutlined />
|
<UpOutlined />
|
||||||
<div class="label">Find New Contact</div>
|
<div className="label">Find New Contact</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -2,70 +2,58 @@ import { CardItemWrapper, StatusError,
|
|||||||
StatusConnected, StatusConnecting,
|
StatusConnected, StatusConnecting,
|
||||||
StatusRequested, StatusPending,
|
StatusRequested, StatusPending,
|
||||||
StatusConfirmed} from './CardItem.styled';
|
StatusConfirmed} from './CardItem.styled';
|
||||||
import { useCardItem } from './useCardItem.hook';
|
|
||||||
import { Logo } from 'logo/Logo';
|
import { Logo } from 'logo/Logo';
|
||||||
import { Tooltip } from 'antd';
|
import { Tooltip } from 'antd';
|
||||||
import { ExclamationCircleOutlined } from '@ant-design/icons';
|
import { ExclamationCircleOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
export function CardItem({ item, open }) {
|
export function CardItem({ item, tooltip, resync, open }) {
|
||||||
|
|
||||||
const { state, actions } = useCardItem(item);
|
const onResync = (e) => {
|
||||||
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) => {
|
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
actions.resync();
|
resync();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CardItemWrapper onClick={() => open(profile.guid)}>
|
<CardItemWrapper onClick={open}>
|
||||||
<Logo url={state.logo} width={32} height={32} radius={8} />
|
<Logo url={item.logo} width={32} height={32} radius={8} />
|
||||||
<div class="details">
|
<div className="details">
|
||||||
<div class="name">{ profile?.name }</div>
|
<div className="name">{ item.name }</div>
|
||||||
<div class="handle">{ handle() }</div>
|
<div className="handle">{ item.handle }</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="markup">
|
<div className="markup">
|
||||||
{ !state.resync && item.error && state.display === 'small' && (
|
{ item.offsync && !item.tooltip && (
|
||||||
<StatusError onClick={resync}>
|
<StatusError onClick={onResync}>
|
||||||
<ExclamationCircleOutlined />
|
<ExclamationCircleOutlined />
|
||||||
</StatusError>
|
</StatusError>
|
||||||
)}
|
)}
|
||||||
{ !state.resync && item.error && state.display !== 'small' && (
|
{ item.offsync && item.tooltip && (
|
||||||
<Tooltip placement="left" title="sync error">
|
<Tooltip placement="left" title="sync error">
|
||||||
<StatusError onClick={resync}>
|
<StatusError onClick={onResync}>
|
||||||
<ExclamationCircleOutlined />
|
<ExclamationCircleOutlined />
|
||||||
</StatusError>
|
</StatusError>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{ detail?.status === 'connected' && (
|
{ item.status === 'connected' && (
|
||||||
<Tooltip placement="left" title="connected contact">
|
<Tooltip placement="left" title="connected contact">
|
||||||
<StatusConnected />
|
<StatusConnected />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{ detail?.status === 'requested' && (
|
{ item.status === 'requested' && (
|
||||||
<Tooltip placement="left" title="connection requested by contact">
|
<Tooltip placement="left" title="connection requested by contact">
|
||||||
<StatusRequested />
|
<StatusRequested />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{ detail?.status === 'connecting' && (
|
{ item.status === 'connecting' && (
|
||||||
<Tooltip placement="left" title="requested contact connection">
|
<Tooltip placement="left" title="requested contact connection">
|
||||||
<StatusConnecting />
|
<StatusConnecting />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{ detail?.status === 'pending' && (
|
{ item.status === 'pending' && (
|
||||||
<Tooltip placement="left" title="unknwon contact connection request">
|
<Tooltip placement="left" title="unknwon contact connection request">
|
||||||
<StatusPending />
|
<StatusPending />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{ detail?.status === 'confirmed' && (
|
{ item.status === 'confirmed' && (
|
||||||
<Tooltip placement="left" title="disconnected contact">
|
<Tooltip placement="left" title="disconnected contact">
|
||||||
<StatusConfirmed />
|
<StatusConfirmed />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
@ -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 };
|
|
||||||
}
|
|
||||||
|
|
@ -8,10 +8,10 @@ export function useCards() {
|
|||||||
const [filter, setFilter] = useState(null);
|
const [filter, setFilter] = useState(null);
|
||||||
|
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
|
tooltip: false,
|
||||||
sorted: false,
|
sorted: false,
|
||||||
display: null,
|
display: null,
|
||||||
cards: [],
|
cards: [],
|
||||||
busy: false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const card = useContext(CardContext);
|
const card = useContext(CardContext);
|
||||||
@ -22,44 +22,45 @@ export function useCards() {
|
|||||||
setState((s) => ({ ...s, ...value }));
|
setState((s) => ({ ...s, ...value }));
|
||||||
}
|
}
|
||||||
|
|
||||||
const actions = {
|
|
||||||
onFilter: (value) => {
|
|
||||||
setFilter(value.toUpperCase());
|
|
||||||
},
|
|
||||||
setSort: (value) => {
|
|
||||||
updateState({ sorted: value });
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
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 => {
|
contacts.forEach(contact => {
|
||||||
if (!updated || updated < contact?.data?.cardDetail?.statusUpdated) {
|
if (latest < contact.updated) {
|
||||||
updated = contact?.data?.cardDetail?.statusUpdated;
|
latest = contact.updated;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
store.actions.setValue('cards:updated', updated);
|
store.actions.setValue('cards:updated', latest);
|
||||||
// eslint-disable-next-line
|
|
||||||
}, [card]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
let filtered = contacts.filter(contact => {
|
||||||
const contacts = Array.from(card.state.cards.values());
|
|
||||||
|
|
||||||
let filtered = contacts.filter((contact) => {
|
|
||||||
if (!filter) {
|
if (!filter) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!contact?.data?.cardProfile?.name) {
|
if (!contact.name) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return contact.data.cardProfile.name.toUpperCase().includes(filter);
|
return contact.name.toUpperCase().includes(filter);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (state.sorted) {
|
if (state.sorted) {
|
||||||
filtered.sort((a, b) => {
|
filtered.sort((a, b) => {
|
||||||
let aName = a?.data?.cardProfile?.name;
|
let aName = a?.name;
|
||||||
let bName = b?.data?.cardProfile?.name;
|
let bName = b?.name;
|
||||||
if (aName === bName) {
|
if (aName === bName) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -71,8 +72,8 @@ export function useCards() {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
filtered.sort((a, b) => {
|
filtered.sort((a, b) => {
|
||||||
const aUpdated = a?.data?.cardDetail?.statusUpdated;
|
const aUpdated = a?.updated;
|
||||||
const bUpdated = b?.data?.cardDetail?.statusUpdated;
|
const bUpdated = b?.updated;
|
||||||
if (aUpdated === bUpdated) {
|
if (aUpdated === bUpdated) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -85,11 +86,29 @@ export function useCards() {
|
|||||||
|
|
||||||
updateState({ cards: filtered });
|
updateState({ cards: filtered });
|
||||||
|
|
||||||
}, [card, filter, state.sorted]);
|
// eslint-disable-next-line
|
||||||
|
}, [card.state, state.sorted, filter]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateState({ display: viewport.state.display });
|
if (viewport.state.display === 'small') {
|
||||||
}, [viewport]);
|
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 };
|
return { state, actions };
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user