merging back refactor contact screen

This commit is contained in:
Roland Osborne 2023-02-24 14:32:18 -08:00
parent 848f2580ee
commit d1d5431fbd
8 changed files with 426 additions and 26 deletions

View File

@ -1,7 +1,7 @@
export function getCardByGuid(cards, guid) {
let card = null;
cards.forEach((value, key, map) => {
if(value?.data?.cardProfile?.guid === guid) {
if(value?.card.profile?.guid === guid) {
card = value;
}
});
@ -9,12 +9,7 @@ export function getCardByGuid(cards, guid) {
}
export function getProfileByGuid(cards, guid) {
const card = getCardByGuid(cards, guid);
if (card?.data?.cardProfile) {
const { name, handle, imageSet, node } = card.data.cardProfile;
const cardId = card.id;
const { cardId, name, handle, imageSet, node } = getCardByGuid(cards, guid) || {}
return { cardId, name, handle, imageSet, node }
}
return {};
}

View File

@ -126,7 +126,7 @@ export function Session() {
<ContactStack.Screen name="contact" options={{ ...stackParams, headerTitle: (props) => (
<ContactHeader contact={contact} />
)}}>
{(props) => <ContactBody contact={contact} />}
{(props) => <ScrollView><ContactBody contact={contact} /></ScrollView>}
</ContactStack.Screen>
<ContactStack.Screen name="registry" options={{ ...stackParams, headerTitle: (props) => (
@ -237,8 +237,13 @@ export function Session() {
const [contact, setContact] = useState(null);
return (
<ContactDrawer.Navigator screenOptions={{ ...drawerParams, drawerStyle: { width: '44%' } }}
drawerContent={(props) => <Contact contact={contact} />}>
<ContactDrawer.Navigator screenOptions={{ ...drawerParams, drawerStyle: { width: '44%' } }} drawerContent={(props) => (
<ScrollView style={styles.drawer}>
<SafeAreaView edges={['top', 'bottom', 'right']}>
<Contact contact={contact} />
</SafeAreaView>
</ScrollView>
)}>
<ContactDrawer.Screen name="registry">
{(props) => <RegistryDrawerScreen navParams={{...navParams, setContact, contactNav: props.navigation }} />}
</ContactDrawer.Screen>

View File

@ -7,7 +7,7 @@ export function CardItem({ item, openContact }) {
const select = () => {
const { guid, name, handle, node, location, description, imageSet } = item;
const contact = { guid, name, handle, node, location, description, imageSet };
openContact({ contact });
openContact(contact);
};
return (

View File

@ -1,20 +1,303 @@
import { Text } from 'react-native';
import { Alert, View, Text, TouchableOpacity } from 'react-native';
import { styles } from './Contact.styled';
import { useContact } from './useContact.hook';
import Ionicons from 'react-native-vector-icons/AntDesign';
import { Logo } from 'utils/Logo';
import { Colors } from 'constants/Colors';
export function ContactHeader({ contact, closeContact }) {
export function ContactHeader({ contact }) {
return (
<Text>ContactTitle</Text>
);
<Text style={styles.headerText}>{ `${contact?.handle}@${contact?.node}` }</Text>
)
}
export function ContactBody({ contact }) {
const { state, actions } = useContact(contact);
const getStatusText = (status) => {
if (status === 'confirmed') {
return 'saved';
}
if (status === 'pending') {
return 'unknown contact request';
}
if (status === 'connecting') {
return 'request sent';
}
if (status === 'connected') {
return 'connected';
}
if (status === 'requested') {
return 'request received';
}
return 'unsaved';
}
const setContact = async (action) => {
try {
await action();
}
catch (err) {
console.log(err);
Alert.alert(
'Failed to Update Contact',
'Please try again.',
);
}
}
const cancelRequest = () => {
Alert.alert(
"Closing Request",
"Confirm?",
[
{ text: "Cancel",
onPress: () => {},
},
{ text: "Close", onPress: () => {
setContact(actions.disconnectContact);
}}
]
);
}
const disconnectContact = () => {
Alert.alert(
"Disconnecting Contact",
"Confirm?",
[
{ text: "Cancel",
onPress: () => {},
},
{ text: "Disconnect", onPress: () => {
setContact(actions.disconnectContact);
}}
]
);
}
const saveAndConnect = () => {
setContact(actions.saveAndConnect);
}
const confirmAndConnect = () => {
setContact(actions.confirmAndConnect);
}
const saveContact = () => {
setContact(actions.saveContact);
}
const confirmContact = () => {
setContact(actions.confirmContact);
}
const ignoreContact = () => {
setContact(actions.ignoreContact);
}
const deleteContact = () => {
Alert.alert(
"Deleting Contact",
"Confirm?",
[
{ text: "Cancel",
onPress: () => {},
},
{ text: "Delete", onPress: () => {
setContact(actions.deleteContact);
}}
]
);
}
const closeDelete = () => {
Alert.alert(
"Deleting Contact",
"Confirm?",
[
{ text: "Cancel",
onPress: () => {},
},
{ text: "Delete", onPress: () => {
setContact(actions.closeDelete);
}}
]
);
}
const blockContact = () => {
Alert.alert(
"Blocking Contact",
"Confirm?",
[
{ text: "Cancel",
onPress: () => {},
},
{ text: "Block", onPress: () => {
setContact(actions.blockContact);
}}
]
);
}
const reportContact = () => {
Alert.alert(
"Report Contact",
"Confirm?",
[
{ text: "Cancel",
onPress: () => {},
},
{ text: "Report", onPress: () => {
setContact(actions.reportContact);
}}
]
);
}
const connectContact = () => {
setContact(actions.connectContact);
}
return (
<Text>ContactBody</Text>
<View style={styles.container}>
<Text style={styles.status}>{ `[${getStatusText(state.status)}]` }</Text>
<View style={{ width: 128 }}>
<Logo src={state.logo} width={128} height={128} radius={8} />
</View>
<View style={styles.detail}>
<View style={styles.attribute}>
<Text style={styles.nametext}>{ state.name }</Text>
</View>
<View style={styles.attribute}>
<View style={styles.glyph}>
<Ionicons name="enviromento" size={14} color={Colors.text} />
</View>
<Text style={styles.locationtext}>{ state.location }</Text>
</View>
<View style={styles.attribute}>
<View style={styles.glyph}>
<Ionicons name="book" size={14} color={Colors.text} />
</View>
<Text style={styles.descriptiontext}>{ state.description }</Text>
</View>
</View>
<View style={styles.controls}>
{ state.status === 'connected' && (
<>
<TouchableOpacity style={styles.button} onPress={disconnectContact}>
<Text style={styles.buttonText}>Disconnect</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={closeDelete}>
<Text style={styles.buttonText}>Delete Contact</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={blockContact}>
<Text style={styles.buttonText}>Block Contact</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={reportContact}>
<Text style={styles.buttonText}>Report Contact</Text>
</TouchableOpacity>
</>
)}
{ state.status === 'connecting' && (
<>
<TouchableOpacity style={styles.button} onPress={cancelRequest}>
<Text style={styles.buttonText}>Close Request</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={closeDelete}>
<Text style={styles.buttonText}>Delete Contact</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={blockContact}>
<Text style={styles.buttonText}>Block Contact</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={reportContact}>
<Text style={styles.buttonText}>Report Contact</Text>
</TouchableOpacity>
</>
)}
{ state.status === 'confirmed' && (
<>
<TouchableOpacity style={styles.button} onPress={connectContact}>
<Text style={styles.buttonText}>Request Connection</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={deleteContact}>
<Text style={styles.buttonText}>Delete Contact</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={blockContact}>
<Text style={styles.buttonText}>Block Contact</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={reportContact}>
<Text style={styles.buttonText}>Report Contact</Text>
</TouchableOpacity>
</>
)}
{ state.status === 'pending' && (
<>
<TouchableOpacity style={styles.button} onPress={confirmAndConnect}>
<Text style={styles.buttonText}>Save and Connect</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={confirmContact}>
<Text style={styles.buttonText}>Save Contact</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={deleteContact}>
<Text style={styles.buttonText}>Ignore Request</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={blockContact}>
<Text style={styles.buttonText}>Block Contact</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={reportContact}>
<Text style={styles.buttonText}>Report Contact</Text>
</TouchableOpacity>
</>
)}
{ state.status === 'requested' && (
<>
<TouchableOpacity style={styles.button} onPress={connectContact}>
<Text style={styles.buttonText}>Accept Connection</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={ignoreContact}>
<Text style={styles.buttonText}>Ignore Request</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={disconnectContact}>
<Text style={styles.buttonText}>Deny Request</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={deleteContact}>
<Text style={styles.buttonText}>Delete Contact</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={blockContact}>
<Text style={styles.buttonText}>Block Contact</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={reportContact}>
<Text style={styles.buttonText}>Report Contact</Text>
</TouchableOpacity>
</>
)}
{ state.status == null && (
<>
<TouchableOpacity style={styles.button} onPress={saveAndConnect}>
<Text style={styles.buttonText}>Save and Connect</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={saveContact}>
<Text style={styles.buttonText}>Save Contact</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={reportContact}>
<Text style={styles.buttonText}>Report Contact</Text>
</TouchableOpacity>
</>
)}
</View>
</View>
);
}
export function Contact({ contact, closeContact }) {
export function Contact({ contact }) {
return (
<Text>Contact</Text>
<View>
<ContactHeader contact={contact} />
<ContactBody contact={contact} />
</View>
);
}

View File

@ -0,0 +1,117 @@
import { StyleSheet } from 'react-native';
import { Colors } from 'constants/Colors';
export const styles = StyleSheet.create({
container: {
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
paddingBottom: 32,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: Colors.formBackground,
},
wrapper: {
backgroundColor: Colors.formBackground,
},
title: {
fontSize: 18,
},
resync: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
glyph: {
paddingTop: 2,
},
icon: {
width: 32,
paddingLeft: 8
},
drawer: {
paddingTop: 16,
},
close: {
width: '100%',
display: 'flex',
alignItems: 'flex-end',
paddingRight: 32,
},
header: {
display: 'flex',
flexDirection: 'row',
alignItems: 'flex-end',
justifyContent: 'center',
},
status: {
color: Colors.grey,
paddingBottom: 20,
paddingTop: 4,
},
headerText: {
fontSize: 18,
overflow: 'hidden',
textAlign: 'center',
},
camera: {
position: 'absolute',
bottom: 0,
left: 0,
padding: 8,
backgroundColor: Colors.lightgrey,
borderBottomLeftRadius: 8,
borderTopRightRadius: 8,
},
gallery: {
position: 'absolute',
bottom: 0,
right: 0,
padding: 8,
backgroundColor: Colors.lightgrey,
borderBottomRightRadius: 8,
borderTopLeftRadius: 8,
},
detail: {
paddingTop: 32,
paddingLeft: 32,
paddingRight: 32,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
color: Colors.text,
},
attribute: {
display: 'flex',
flexDirection: 'row',
paddingBottom: 8,
},
nametext: {
fontSize: 18,
paddingRight: 8,
fontWeight: 'bold',
},
locationtext: {
fontSize: 16,
paddingLeft: 8,
},
descriptiontext: {
fontSize: 16,
paddingLeft: 8
},
button: {
width: 192,
padding: 6,
backgroundColor: Colors.primary,
borderRadius: 4,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
marginTop: 16,
},
buttonText: {
color: Colors.white,
},
})

View File

@ -3,7 +3,7 @@ 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';
import { getCardByGuid } from 'context/cardUtil';
export function useContact(contact) {
@ -28,15 +28,15 @@ export function useContact(contact) {
}
useEffect(() => {
const contactCard = getCardByGuid(contact.guid);
const contactCard = getCardByGuid(card.state.cards, contact?.guid);
if (contactCard) {
const { offsync, profile, detail, cardId } = selected.card;
const { offsync, profile, detail, cardId } = contactCard.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 { 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 });
}

View File

@ -201,13 +201,13 @@ export function ProfileBody() {
</TouchableOpacity>
<TouchableOpacity style={styles.logout} onPress={actions.showEditLogin}>
<Ionicons name="lock" size={20} color={Colors.primary} />
<Ionicons name="user" size={20} color={Colors.primary} />
<Text style={styles.logoutText}>Change Login</Text>
</TouchableOpacity>
{ state.sealable && (
<TouchableOpacity style={styles.logout} onPress={actions.showEditSeal}>
<MatIcons name="account-key-outline" size={22} color={Colors.primary} />
<Ionicons name="lock" size={22} color={Colors.primary} />
<Text style={styles.logoutText}>Sealed Topics</Text>
</TouchableOpacity>
)}

View File

@ -10,7 +10,7 @@ export function RegistryItem({ item, openContact }) {
const select = () => {
const { guid, name, handle, node, location, description, imageSet } = item;
const contact = { guid, name, handle, node, location, description, imageSet };
openContact({ contact });
openContact(contact);
}
return (