updating membership

This commit is contained in:
balzack 2022-10-10 22:05:15 -07:00
parent 40eb654f82
commit 3cf037775e
9 changed files with 127 additions and 10 deletions

View File

@ -1,7 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setChannelCard(token, channelId, cardId ) {
let channel = await fetchWithTimeout(`/content/channels/${channelId}/cards/${cardId}?agent=${token}`, {method: 'PUT'});
export async function setChannelCard(server, token, channelId, cardId ) {
console.log("SETTING");
let channel = await fetchWithTimeout(`https://${server}/content/channels/${channelId}/cards/${cardId}?agent=${token}`, {method: 'PUT'});
checkResponse(channel);
return await channel.json();
}

View File

@ -246,6 +246,14 @@ export function useChannelContext() {
const { server, appToken } = session.current;
return await removeChannelTopic(server, appToken, channelId, topicId);
},
setCard: async (channelId, cardId) => {
const { server, appToken } = session.current;
return await setChannelCard(server, appToken, channelId, cardId);
},
clearCard: async (channelId, cardId) => {
const { server, appToken } = session.current;
return await clearChannelCard(server, appToken, channelId, cardId);
},
}
return { state, actions }

View File

@ -357,6 +357,24 @@ export function useConversationContext() {
await remove(cardId, channelId);
}
},
setCard: async (id) => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
if (cardId) {
throw new Error("can only set members on hosted channel");
}
await channel.actions.setCard(channelId, id);
}
},
clearCard: async (id) => {
if (conversationId.current) {
const { cardId, channelId } = conversationId.current;
if (cardId) {
throw new Error("can only clear members on hosted channel");
}
await channel.actions.clearCard(channelId, id);
}
},
}
return { state, actions }

View File

@ -65,7 +65,7 @@ export function DetailsBody({ channel, clearConversation }) {
</TouchableOpacity>
)}
{ !state.hostId && (
<TouchableOpacity style={styles.button}>
<TouchableOpacity style={styles.button} onPress={actions.showEditMembers}>
<Text style={styles.buttonText}>Edit Membership</Text>
</TouchableOpacity>
)}
@ -85,7 +85,7 @@ export function DetailsBody({ channel, clearConversation }) {
<FlatList style={styles.cards}
data={state.contacts}
renderItem={({ item }) => <MemberItem hostId={state.hostId} item={item} />}
renderItem={({ item }) => <MemberItem hostId={state.hostId} editable={false} members={[]} item={item} />}
keyExtractor={item => item.cardId}
/>
@ -115,6 +115,30 @@ export function DetailsBody({ channel, clearConversation }) {
</KeyboardAvoidingView>
</Modal>
<Modal
animationType="fade"
transparent={true}
visible={state.editMembers}
supportedOrientations={['portrait', 'landscape']}
onRequestClose={actions.hideEditMembers}
>
<KeyboardAvoidingView behavior="height" style={styles.editWrapper}>
<View style={styles.editContainer}>
<Text style={styles.editHeader}>Channel Members:</Text>
<FlatList style={styles.editMembers}
data={state.connected}
renderItem={({ item }) => <MemberItem editable={true} members={state.contacts} item={item} />}
keyExtractor={item => item.cardId}
/>
<View style={styles.editControls}>
<TouchableOpacity style={styles.cancel} onPress={actions.hideEditMembers}>
<Text>Done</Text>
</TouchableOpacity>
</View>
</View>
</KeyboardAvoidingView>
</Modal>
</View>
)
}

View File

@ -147,6 +147,14 @@ export const styles = StyleSheet.create({
fontSize: 18,
paddingBottom: 16,
},
editMembers: {
width: '100%',
borderWidth: 1,
borderColor: Colors.lightgrey,
borderRadius: 4,
padding: 8,
marginBottom: 8,
height: 250,
},
})

View File

@ -1,13 +1,26 @@
import { Text, TouchableOpacity, View } from 'react-native';
import { Alert, Text, Switch, TouchableOpacity, View } from 'react-native';
import { Logo } from 'utils/Logo';
import { styles } from './MemberItem.styled';
import { useMemberItem } from './useMemberItem.hook';
import Ionicons from '@expo/vector-icons/MaterialCommunityIcons';
import Colors from 'constants/Colors';
export function MemberItem({ hostId, item }) {
export function MemberItem({ hostId, editable, members, item }) {
const { state, actions } = useMemberItem(item);
const { state, actions } = useMemberItem(item, members);
const setMember = async (member) => {
try {
actions.setMember(member);
}
catch (err) {
console.log(err);
Alert.alert(
'Failed to Update Membership',
'Please try again.'
);
}
};
return (
<View style={styles.container}>
@ -16,9 +29,13 @@ export function MemberItem({ hostId, item }) {
<Text style={styles.name} numberOfLines={1} ellipsizeMode={'tail'}>{ state.name }</Text>
<Text style={styles.handle} numberOfLines={1} ellipsizeMode={'tail'}>{ state.handle }</Text>
</View>
{ hostId === state.cardId && (
{ !editable && hostId === state.cardId && (
<Ionicons name="server" size={16} color={Colors.grey} />
)}
{ editable && (
<Switch style={styles.switch} trackColor={styles.track}
value={state.member} onValueChange={setMember} />
)}
</View>
);
}

View File

@ -62,5 +62,13 @@ export const styles = StyleSheet.create({
borderRadius: 4,
backgroundColor: Colors.confirmed,
},
track: {
false: Colors.grey,
true: Colors.background,
},
switch: {
transform: [{ scaleX: .7 }, { scaleY: .7 }],
},
})

View File

@ -1,22 +1,30 @@
import { useState, useEffect, useRef, useContext } from 'react';
import { useNavigate } from 'react-router-dom';
import { CardContext } from 'context/CardContext';
import { ConversationContext } from 'context/ConversationContext';
export function useMemberItem(item) {
export function useMemberItem(item, members) {
const [state, setState] = useState({
name: null,
handle: null,
logo: null,
cardId: null,
member: false,
});
const conversation = useContext(ConversationContext);
const card = useContext(CardContext);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
}
useEffect(() => {
const member = members.filter(contact => item.cardId === contact.cardId);
updateState({ member: member.length > 0 });
}, [members]);
useEffect(() => {
const { cardId, revision, profile } = item;
const { name, handle, node } = profile;
@ -25,6 +33,16 @@ export function useMemberItem(item) {
}, [card]);
const actions = {
setMember: (member) => {
updateState({ member });
if (member) {
console.log("SET CARD:", item.cardId);
conversation.actions.setCard(item.cardId);
}
else {
conversation.actions.clearCard(item.cardId);
}
},
};
return { state, actions };

View File

@ -1,6 +1,7 @@
import { useState, useEffect, useRef, useContext } from 'react';
import { useNavigate } from 'react-router-dom';
import { ConversationContext } from 'context/ConversationContext';
import { CardContext } from 'context/CardContext';
export function useDetails() {
@ -10,10 +11,13 @@ export function useDetails() {
logo: null,
hostId: null,
contacts: [],
connected: [],
editSubject: false,
editMembers: false,
subjectUpdate: null,
});
const card = useContext(CardContext);
const conversation = useContext(ConversationContext);
const navigate = useNavigate();
@ -21,6 +25,11 @@ export function useDetails() {
setState((s) => ({ ...s, ...value }));
}
useEffect(() => {
const contacts = Array.from(card.state.cards.values());
updateState({ connected: contacts.filter(contact => contact.detail.status === 'connected') });
}, [card]);
useEffect(() => {
const { topic, subject, created, logo, host, contacts } = conversation.state;
updateState({ subject, created, logo, hostId: host, subjectUpdate: topic,
@ -28,6 +37,12 @@ export function useDetails() {
}, [conversation]);
const actions = {
showEditMembers: () => {
updateState({ editMembers: true });
},
hideEditMembers: () => {
updateState({ editMembers: false });
},
showEditSubject: () => {
updateState({ editSubject: true });
},