adding contact controls

This commit is contained in:
Roland Osborne 2022-08-18 12:37:08 -07:00
parent 37978e65b7
commit 6d9b9fbc15
10 changed files with 223 additions and 25 deletions

View File

@ -335,8 +335,9 @@ export function useCardContext() {
setCardConnecting: async (cardId) => {
return await setCardConnecting(access.current, cardId);
},
setCardConnected: async (cardId, token, view, article, channel, profile) => {
return await setCardConnected(access.current, cardId, token, view, article, channel, profile);
setCardConnected: async (cardId, token, rev) => {
return await setCardConnected(access.current, cardId, token,
rev.viewRevision, rev.articleRevision, rev.channelRevision, rev.profileRevision);
},
setCardConfirmed: async (cardId) => {
return await setCardConfirmed(access.current, cardId);

View File

@ -72,7 +72,7 @@ export function Session() {
)}
{ state.contact && (
<div class="reframe">
<Contact close={actions.closeContact} guid={state.contactGuid} node={state.contactNode} />
<Contact close={actions.closeContact} guid={state.contactGuid} listing={state.contactListing} />
</div>
)}
{ state.profile && (

View File

@ -15,11 +15,13 @@ export function Account({ closeAccount, openProfile }) {
</div>
</div>
<div class="content">
<div class="link" onClick={openProfile}>
<SettingOutlined />
<div class="label">Update Profile</div>
</div>
<AccountAccess />
<div class="bottom">
<div class="link" onClick={openProfile}>
<SettingOutlined />
<div class="label">Update Profile</div>
</div>
</div>
</div>
</AccountWrapper>
);

View File

@ -41,18 +41,26 @@ export const AccountWrapper = styled.div`
justify-content: center;
padding-top: 32px;
align-items: center;
flex-grow: 1;
.link {
color: ${Colors.primary};
padding-top: 16px;
padding-bottom: 8px;
.bottom {
flex-grow: 1;
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
align-items: flex-end;
padding-bottom: 16px;
.label {
padding-left: 8px;
.link {
color: ${Colors.primary};
padding-top: 16px;
padding-bottom: 8px;
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
.label {
padding-left: 8px;
}
}
}
}

View File

@ -6,6 +6,7 @@ export const AccountAccessWrapper = styled.div`
flex-direction: column;
align-items: center;
justify-content: center;
padding-bottom: 8px;
.link {
display: flex;

View File

@ -16,7 +16,7 @@ export function useCardItem(item) {
useEffect(() => {
updateState({ logo: card.actions.getImageUrl(item.id) });
}, [card]);
}, [card, item]);
const actions = {
resync: async () => {

View File

@ -63,9 +63,9 @@ export function useCards() {
return 0;
}
if (!aUpdated || (aUpdated < bUpdated)) {
return -1;
return 1;
}
return 1;
return -1;
});
}

View File

@ -1,11 +1,12 @@
import { Modal } from 'antd';
import { ContactWrapper } from './Contact.styled';
import { useContact } from './useContact.hook';
import { Logo } from 'logo/Logo';
import { DatabaseOutlined, CloseOutlined, RightOutlined, BookOutlined, EnvironmentOutlined } from '@ant-design/icons';
import { DatabaseOutlined, LoadingOutlined, CloseOutlined, RightOutlined, BookOutlined, EnvironmentOutlined } from '@ant-design/icons';
export function Contact({ close, guid, listing }) {
const { state, actions } = useContact(guid, listing);
const { state, actions } = useContact(guid, listing, close);
const Image = (
<div class="logo">
@ -13,6 +14,19 @@ export function Contact({ close, guid, listing }) {
</div>
);
const updateContact = async (action) => {
try {
await action();
}
catch (err) {
console.log(err);
Modal.error({
title: 'Failed to Update Contact',
content: 'Please try again.',
});
}
}
const Details = (
<div class="details">
<div class="name">
@ -32,6 +46,49 @@ export function Contact({ close, guid, listing }) {
<BookOutlined />
<div class="data">{ state.description }</div>
</div>
{ state.status === 'connected' && (
<div class="controls">
<div class={ state.buttonStatus } onClick={() => updateContact(actions.disconnect)}>Disconnect</div>
<div class={ state.buttonStatus } onClick={() => updateContact(actions.disconnectRemove)}>Delete Contact</div>
</div>
)}
{ state.status === 'pending' && (
<div class="controls">
<div class={ state.buttonStatus } onClick={() => updateContact(actions.saveContact)}>Save Contact</div>
<div class={ state.buttonStatus } onClick={() => updateContact(actions.saveConnect)}>Save and Accept</div>
<div class={ state.buttonStatus } onClick={() => updateContact(actions.remove)}>Ignore Request</div>
</div>
)}
{ state.status === 'requested' && (
<div class="controls">
<div class={ state.buttonStatus } onClick={() => updateContact(actions.saveConnect)}>Accept Connection</div>
<div class={ state.buttonStatus } onClick={() => updateContact(actions.disconnect)}>Ignore Request</div>
</div>
)}
{ state.status === 'connecting' && (
<div class="controls">
<div class={ state.buttonStatus } onClick={() => updateContact(actions.disconnect)}>Cancel Request</div>
<div class={ state.buttonStatus } onClick={() => updateContact(actions.disconnectRemove)}>Delete Contact</div>
</div>
)}
{ state.status === 'confirmed' && (
<div class="controls">
<div class={ state.buttonStatus } onClick={() => updateContact(actions.connect)}>Request Connection</div>
<div class={ state.buttonStatus } onClick={() => updateContact(actions.remove)}>Delete Contact</div>
</div>
)}
{ state.status === 'disconnected' && (
<div class="controls">
<div class={ state.buttonStatus } onClick={() => updateContact(actions.saveContact)}>Save Contact</div>
<div class={ state.buttonStatus } onClick={() => updateContact(actions.saveConnect)}>Save and Request</div>
</div>
)}
</div>
);

View File

@ -85,7 +85,7 @@ export const ContactWrapper = styled.div`
.data {
padding-left: 8px;
}
}
}
}
}
@ -168,5 +168,40 @@ export const ContactWrapper = styled.div`
}
}
}
.controls {
padding-top: 16px;
padding-bottom: 16px;
.button {
width: 192px;
padding-top: 2px;
padding-bottom: 2px;
margin-top: 16px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
border-radius: 2px;
color: ${Colors.white};
background-color: ${Colors.primary};
}
.label {
flex-grow: 1;
display: flex;
justify-content: center;
}
.idle {
cursor: pointer;
opactiy: 0;
}
.busy {
cursor: not-allowed;
opacity: 0.5;
}
}
`

View File

@ -3,18 +3,23 @@ import { CardContext } from 'context/CardContext';
import { ProfileContext } from 'context/ProfileContext';
import { ViewportContext } from 'context/ViewportContext';
import { getListingImageUrl } from 'api/getListingImageUrl';
import { getListingMessage } from 'api/getListingMessage';
export function useContact(guid, listing) {
export function useContact(guid, listing, close) {
const [state, setState] = useState({
logo: null,
name: null,
cardId: null,
location: null,
description: null,
handle: null,
node: null,
removed: false,
init: false,
status: null,
busy: false,
buttonStatus: 'button idle',
});
const card = useContext(CardContext);
@ -26,36 +31,125 @@ export function useContact(guid, listing) {
}
useEffect(() => {
let logo, name, location, description, handle, node;
let logo, name, location, description, handle, node, status, cardId;
let contact = card.actions.getCardByGuid(guid);
if (contact) {
let cardProfile = contact?.data?.cardProfile;
let cardDetail = contact?.data?.cardDetail;
cardId = contact.id;
handle = cardProfile.handle;
node = cardProfile.node;
logo = card.actions.getImageUrl(contact.id);
name = cardProfile.name;
location = cardProfile.location;
description = cardProfile.description;
status = cardDetail.status;
}
else if (listing) {
handle = listing.handle;
cardId = null;
node = listing.node;
logo = listing.imageSet ? getListingImageUrl(listing.node, listing.guid) : null;
name = listing.name;
location = listing.location;
description = listing.description;
status = 'disconnected';
}
else {
updateState({ removed: true });
}
updateState({ init: true, logo, name, location, description, handle, node });
updateState({ init: true, logo, name, location, description, handle, node, status, cardId });
}, [card, guid, listing]);
useEffect(() => {
updateState({ display: viewport.state.display });
}, [viewport]);
const applyAction = async (action) => {
if (!state.busy) {
try {
updateState({ busy: true, buttonStatus: 'button busy', action });
await action();
updateState({ busy: false, buttonStatus: 'button idle' });
}
catch (err) {
console.log(err);
updateState({ busy: false, buttonStatus: 'button idle' });
throw new Error("failed to update contact");
}
}
else {
throw new Error("operation in progress");
}
}
const actions = {
saveContact: async () => {
await applyAction(async () => {
let message = await getListingMessage(state.node, guid);
await card.actions.addCard(message);
});
},
saveConnect: async () => {
await applyAction(async () => {
let profile = await getListingMessage(state.node, guid);
let added = await card.actions.addCard(profile);
await card.actions.setCardConnecting(added.id);
let open = await card.actions.getCardOpenMessage(added.id);
let contact = await card.actions.setCardOpenMessage(state.node, open);
if (contact.status === 'connected') {
await card.actions.setCardConnected(added.id, contact.token, contact);
}
});
},
deleteContact: async () => {
await applyAction(async () => {
await card.actions.removeCard(state.cardId);
close();
});
},
connect: async () => {
await applyAction(async () => {
await card.actions.setCardConnecting(state.cardId);
let message = await card.actions.getCardOpenMessage(state.cardId);
let contact = await card.actions.setCardOpenMessage(state.node, message);
if (contact.status === 'connected') {
await card.actions.setCardConnected(state.cardId, contact.token, contact);
}
});
},
disconnect: async () => {
await applyAction(async () => {
await card.actions.setCardConfirmed(state.cardId);
try {
let message = await card.actions.getCardCloseMessage(state.cardId);
await card.actions.setCardCloseMessage(state.node, message);
}
catch (err) {
console.log(err);
}
});
},
disconnectRemove: async () => {
await applyAction(async () => {
await card.actions.setCardConfirmed(state.cardId);
try {
let message = await card.actions.getCardCloseMessage(state.cardId);
await card.actions.setCardCloseMessage(state.node, message);
}
catch (err) {
console.log(err);
}
await card.actions.removeCard(state.cardId);
close();
});
},
remove: async () => {
await applyAction(async () => {
await card.actions.removeCard(state.cardId);
close();
});
},
};
return { state, actions };