From b132e3494b14d6683dcf097901116655245a6f2a Mon Sep 17 00:00:00 2001 From: balzack Date: Fri, 24 Feb 2023 00:27:09 -0800 Subject: [PATCH] refactoring contact screen --- app/mobile/src/session/Session.jsx | 12 +- app/mobile/src/session/cards/Cards.jsx | 5 +- .../src/session/cards/cardItem/CardItem.jsx | 4 +- app/mobile/src/session/cards/useCards.hook.js | 11 +- app/mobile/src/session/contact/Contact.jsx | 14 +- .../src/session/contact/useContact.hook.js | 159 ++++++++++++++++++ app/mobile/src/session/registry/Registry.jsx | 4 +- 7 files changed, 192 insertions(+), 17 deletions(-) create mode 100644 app/mobile/src/session/contact/useContact.hook.js diff --git a/app/mobile/src/session/Session.jsx b/app/mobile/src/session/Session.jsx index b669d096..52781e8c 100644 --- a/app/mobile/src/session/Session.jsx +++ b/app/mobile/src/session/Session.jsx @@ -11,8 +11,8 @@ import { styles } from './Session.styled'; import Colors from 'constants/Colors'; import { Profile, ProfileHeader, ProfileBody } from './profile/Profile'; import { CardsHeader, CardsBody, Cards } from './cards/Cards'; -import { RegistryTitle, RegistryBody, Registry } from './registry/Registry'; -import { Contact, ContactTitle } from './contact/Contact'; +import { RegistryHeader, RegistryBody, Registry } from './registry/Registry'; +import { ContactHeader, ContactBody, Contact } from './contact/Contact'; import { Details, DetailsHeader, DetailsBody } from './details/Details'; import { Conversation, ConversationHeader, ConversationBody } from './conversation/Conversation'; import { Welcome } from './welcome/Welcome'; @@ -108,16 +108,18 @@ export function Session() { (screenParams)} initialRouteName="cards"> ( - openRegistry(props.navigation)} /> + )}}> {(props) => openContact(props.navigation, contact)} />} - }}> + ( + + )}}> {(props) => } - }}> + }}> {(props) => openContact(props.navigation, contact)} />} diff --git a/app/mobile/src/session/cards/Cards.jsx b/app/mobile/src/session/cards/Cards.jsx index 15eda4fe..3f182e86 100644 --- a/app/mobile/src/session/cards/Cards.jsx +++ b/app/mobile/src/session/cards/Cards.jsx @@ -7,9 +7,10 @@ import AntIcons from 'react-native-vector-icons/AntDesign'; import MatIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import { Colors } from 'constants/Colors'; import { CardItem } from './cardItem/CardItem'; +import { useNavigation } from '@react-navigation/native'; export function CardsHeader({ filter, setFilter, sort, setSort, openRegistry }) { - const { state, actions } = useCards(filter, sort); + const navigation = useNavigation(); return ( @@ -29,7 +30,7 @@ export function CardsHeader({ filter, setFilter, sort, setSort, openRegistry }) autoCapitalize="none" placeholderTextColor={Colors.disabled} placeholder="Contacts" /> - + openRegistry(navigation)}> New diff --git a/app/mobile/src/session/cards/cardItem/CardItem.jsx b/app/mobile/src/session/cards/cardItem/CardItem.jsx index 5d46d8e9..f14d57f5 100644 --- a/app/mobile/src/session/cards/cardItem/CardItem.jsx +++ b/app/mobile/src/session/cards/cardItem/CardItem.jsx @@ -5,7 +5,9 @@ import { styles } from './CardItem.styled'; export function CardItem({ item, openContact }) { const select = () => { - openContact({ card: item.cardId }); + const { guid, name, handle, node, location, description } = item; + const contact = { guid, name, handle, node, location, description }; + openContact({ contact }); }; return ( diff --git a/app/mobile/src/session/cards/useCards.hook.js b/app/mobile/src/session/cards/useCards.hook.js index a3258d9b..fcb0f712 100644 --- a/app/mobile/src/session/cards/useCards.hook.js +++ b/app/mobile/src/session/cards/useCards.hook.js @@ -15,17 +15,22 @@ export function useCards(filter, sort) { const setCardItem = (item) => { const { profile, detail, cardId } = item.card || { profile: {}, detail: {} } + const { name, handle, node, guid, location, description, imageSet } = profile; return { cardId: cardId, - name: profile.name, - handle: `${profile.handle}@${profile.node}`, + name: name, + handle: handle, + node: node, + guid: guid, + location: location, + description: description, status: detail.status, offsync: item.offsync, blocked: item.blocked, offsync: item.offsync, updated: detail.statusUpdated, - logo: profile.imageSet ? card.actions.getCardImageUrl(cardId) : 'avatar', + logo: imageSet ? card.actions.getCardImageUrl(cardId) : 'avatar', } }; diff --git a/app/mobile/src/session/contact/Contact.jsx b/app/mobile/src/session/contact/Contact.jsx index 47c96385..4f1a2497 100644 --- a/app/mobile/src/session/contact/Contact.jsx +++ b/app/mobile/src/session/contact/Contact.jsx @@ -1,14 +1,20 @@ import { Text } from 'react-native'; -export function ContactTitle({ contact, closeContact }) { - ContactTitle +export function ContactHeader({ contact, closeContact }) { + return ( + ContactTitle + ); } export function ContactBody({ contact }) { - ContactBody; + return ( + ContactBody + ); } export function Contact({ contact, closeContact }) { - Contact + return ( + Contact + ); } diff --git a/app/mobile/src/session/contact/useContact.hook.js b/app/mobile/src/session/contact/useContact.hook.js new file mode 100644 index 00000000..b6caa916 --- /dev/null +++ b/app/mobile/src/session/contact/useContact.hook.js @@ -0,0 +1,159 @@ +import { useState, useEffect, useRef, useContext } from 'react'; +import { CardContext } from 'context/CardContext'; +import { getListingMessage } from 'api/getListingMessage'; +import { getListingImageUrl } from 'api/getListingImageUrl'; +import { addFlag } from 'api/addFlag'; +import { getCardByGuid } from 'context/cardUtils'; + +export function useContact(contact) { + + const [state, setState] = useState({ + name: null, + handle: null, + node: null, + location: null, + description: null, + logo: null, + status: null, + cardId: null, + guid: null, + busy: false, + offsync: false, + }); + + const card = useContext(CardContext); + + const updateState = (value) => { + setState((s) => ({ ...s, ...value })); + } + + useEffect(() => { + const contactCard = getCardByGuid(contact.guid); + if (contactCard) { + const { offsync, profile, detail, cardId } = selected.card; + const { name, handle, node, location, description, guid, imageSet, revision } = profile; + const logo = imageSet ? card.actions.getCardImageUrl(cardId) : 'avatar'; + updateState({ offsync, name, handle, node, location, description, logo, cardId, guid, status: detail.status }); + } + else { + const { guid, handle, node, name, location, description, imageSet } = contact; + const logo = imageSet ? getListingImageUrl(node, guid) : 'avatar'; + updateState({ guid, handle, node, name, location, description, logo, offsync: false, status: null }); + } + }, [contact, card.state]); + + const applyAction = async (action) => { + if (!state.busy) { + try { + updateState({ busy: true }); + await action(); + updateState({ busy: false }); + } + catch (err) { + console.log(err); + updateState({ busy: false }); + throw new Error("failed to update contact"); + } + } + else { + throw new Error("operation in progress"); + } + } + + const actions = { + saveAndConnect: async () => { + await applyAction(async () => { + let profile = await getListingMessage(state.node, state.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); + } + }); + }, + confirmAndConnect: async () => { + await applyAction(async () => { + await card.actions.setCardConfirmed(state.cardId); + await card.actions.setCardConnecting(state.cardId); + let open = await card.actions.getCardOpenMessage(state.cardId); + let contact = await card.actions.setCardOpenMessage(state.node, open); + if (contact.status === 'connected') { + await card.actions.setCardConnected(state.cardId, contact.token, contact); + } + }); + }, + saveContact: async () => { + await applyAction(async () => { + let message = await getListingMessage(state.node, state.guid); + await card.actions.addCard(message); + }); + }, + disconnectContact: 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); + } + }); + }, + confirmContact: async () => { + await applyAction(async () => { + await card.actions.setCardConfirmed(state.cardId); + }); + }, + ignoreContact: async () => { + await applyAction(async () => { + await card.actions.setCardConfirmed(state.cardId); + }); + }, + closeDelete: 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); + }); + }, + deleteContact: async () => { + await applyAction(async () => { + await card.actions.removeCard(state.cardId); + }); + }, + connectContact: 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); + } + }); + }, + blockContact: async () => { + await applyAction(async () => { + await card.actions.setCardBlocked(state.cardId); + }); + }, + reportContact: async () => { + await addFlag(state.node, state.guid); + }, + resync: () => { + card.actions.resync(contact.card); + }, + }; + + return { state, actions }; +} + + diff --git a/app/mobile/src/session/registry/Registry.jsx b/app/mobile/src/session/registry/Registry.jsx index a9f5f492..87b703c5 100644 --- a/app/mobile/src/session/registry/Registry.jsx +++ b/app/mobile/src/session/registry/Registry.jsx @@ -1,7 +1,7 @@ import { Text } from 'react-native'; -export function RegistryTitle({ state, actions }) { - return RegistryTitle +export function RegistryHeader({ state, actions }) { + return RegistryHeader } export function RegistryBody({ state, actions, openContact }) {