From 6d9b9fbc150caec468edf56beb4aa3568e31ee24 Mon Sep 17 00:00:00 2001 From: Roland Osborne Date: Thu, 18 Aug 2022 12:37:08 -0700 Subject: [PATCH] adding contact controls --- net/web/src/context/useCardContext.hook.js | 5 +- net/web/src/session/Session.jsx | 2 +- net/web/src/session/account/Account.jsx | 10 +- net/web/src/session/account/Account.styled.js | 26 +++-- .../accountAccess/AccountAccess.styled.js | 1 + .../cards/cardItem/useCardItem.hook.js | 2 +- net/web/src/session/cards/useCards.hook.js | 4 +- net/web/src/session/contact/Contact.jsx | 61 ++++++++++- net/web/src/session/contact/Contact.styled.js | 37 ++++++- .../src/session/contact/useContact.hook.js | 100 +++++++++++++++++- 10 files changed, 223 insertions(+), 25 deletions(-) diff --git a/net/web/src/context/useCardContext.hook.js b/net/web/src/context/useCardContext.hook.js index 9c055728..82bbfd23 100644 --- a/net/web/src/context/useCardContext.hook.js +++ b/net/web/src/context/useCardContext.hook.js @@ -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); diff --git a/net/web/src/session/Session.jsx b/net/web/src/session/Session.jsx index 4e245035..41e693e1 100644 --- a/net/web/src/session/Session.jsx +++ b/net/web/src/session/Session.jsx @@ -72,7 +72,7 @@ export function Session() { )} { state.contact && (
- +
)} { state.profile && ( diff --git a/net/web/src/session/account/Account.jsx b/net/web/src/session/account/Account.jsx index 0eab8fd5..d384e3d0 100644 --- a/net/web/src/session/account/Account.jsx +++ b/net/web/src/session/account/Account.jsx @@ -15,11 +15,13 @@ export function Account({ closeAccount, openProfile }) {
- +
+ +
); diff --git a/net/web/src/session/account/Account.styled.js b/net/web/src/session/account/Account.styled.js index d3be6bff..a17ba46d 100644 --- a/net/web/src/session/account/Account.styled.js +++ b/net/web/src/session/account/Account.styled.js @@ -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; + } } } } diff --git a/net/web/src/session/accountAccess/AccountAccess.styled.js b/net/web/src/session/accountAccess/AccountAccess.styled.js index 6b7a270a..20a2b6ba 100644 --- a/net/web/src/session/accountAccess/AccountAccess.styled.js +++ b/net/web/src/session/accountAccess/AccountAccess.styled.js @@ -6,6 +6,7 @@ export const AccountAccessWrapper = styled.div` flex-direction: column; align-items: center; justify-content: center; + padding-bottom: 8px; .link { display: flex; diff --git a/net/web/src/session/cards/cardItem/useCardItem.hook.js b/net/web/src/session/cards/cardItem/useCardItem.hook.js index 72e96158..2cbbbe04 100644 --- a/net/web/src/session/cards/cardItem/useCardItem.hook.js +++ b/net/web/src/session/cards/cardItem/useCardItem.hook.js @@ -16,7 +16,7 @@ export function useCardItem(item) { useEffect(() => { updateState({ logo: card.actions.getImageUrl(item.id) }); - }, [card]); + }, [card, item]); const actions = { resync: async () => { diff --git a/net/web/src/session/cards/useCards.hook.js b/net/web/src/session/cards/useCards.hook.js index 1fc1ba43..e871c55f 100644 --- a/net/web/src/session/cards/useCards.hook.js +++ b/net/web/src/session/cards/useCards.hook.js @@ -63,9 +63,9 @@ export function useCards() { return 0; } if (!aUpdated || (aUpdated < bUpdated)) { - return -1; + return 1; } - return 1; + return -1; }); } diff --git a/net/web/src/session/contact/Contact.jsx b/net/web/src/session/contact/Contact.jsx index 1add3714..483d63db 100644 --- a/net/web/src/session/contact/Contact.jsx +++ b/net/web/src/session/contact/Contact.jsx @@ -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 = ( ); + 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 = (
@@ -32,6 +46,49 @@ export function Contact({ close, guid, listing }) {
{ state.description }
+ + { state.status === 'connected' && ( +
+
updateContact(actions.disconnect)}>Disconnect
+
updateContact(actions.disconnectRemove)}>Delete Contact
+
+ )} + + { state.status === 'pending' && ( +
+
updateContact(actions.saveContact)}>Save Contact
+
updateContact(actions.saveConnect)}>Save and Accept
+
updateContact(actions.remove)}>Ignore Request
+
+ )} + + { state.status === 'requested' && ( +
+
updateContact(actions.saveConnect)}>Accept Connection
+
updateContact(actions.disconnect)}>Ignore Request
+
+ )} + + { state.status === 'connecting' && ( +
+
updateContact(actions.disconnect)}>Cancel Request
+
updateContact(actions.disconnectRemove)}>Delete Contact
+
+ )} + + { state.status === 'confirmed' && ( +
+
updateContact(actions.connect)}>Request Connection
+
updateContact(actions.remove)}>Delete Contact
+
+ )} + + { state.status === 'disconnected' && ( +
+
updateContact(actions.saveContact)}>Save Contact
+
updateContact(actions.saveConnect)}>Save and Request
+
+ )}
); diff --git a/net/web/src/session/contact/Contact.styled.js b/net/web/src/session/contact/Contact.styled.js index 4f9d0597..a98df5c2 100644 --- a/net/web/src/session/contact/Contact.styled.js +++ b/net/web/src/session/contact/Contact.styled.js @@ -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; + } + } ` diff --git a/net/web/src/session/contact/useContact.hook.js b/net/web/src/session/contact/useContact.hook.js index 8ea118ef..ceea27de 100644 --- a/net/web/src/session/contact/useContact.hook.js +++ b/net/web/src/session/contact/useContact.hook.js @@ -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 };