updating channel membership

This commit is contained in:
balzack 2025-01-09 20:14:35 -08:00
parent 040f7171ab
commit 130032dc80
2 changed files with 166 additions and 13 deletions

View File

@ -67,10 +67,17 @@ export const styles = StyleSheet.create({
fontSize: 16,
paddingLeft: 8,
},
itemSubject: {
itemHeader: {
fontSize: 22,
paddingLeft: 8,
},
guestSubject: {
paddingBottom: 8,
display: 'flex',
alignItems: 'center',
flexDirection: 'row',
paddingRight: 4,
},
subject: {
width: '100%',
height: 52,
@ -79,6 +86,7 @@ export const styles = StyleSheet.create({
flexDirection: 'row',
paddingRight: 4,
marginTop: 16,
marginBottom: 16,
borderRadius: 8,
},
input: {
@ -137,7 +145,81 @@ export const styles = StyleSheet.create({
paddingTop: 8,
paddingLeft: 16,
paddingRight: 16,
height: 48,
width: '100%',
borderBottomWidth: 1,
},
blur: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
},
memberModal: {
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
},
memberSurface: {
width: '80%',
maxWidth: 400,
},
modalHeader: {
display: 'flex',
flexDirection: 'row',
width: '100%',
alignItems: 'center',
},
modalTitle: {
flexGrow: 1,
paddingLeft: 16,
fontSize: 20,
},
modalClose: {
backgroundColor: 'transparent',
},
modalMembers: {
minHeight: 128,
maxHeight: 256,
width: '100%',
},
modalArea: {
marginLeft: 16,
marginRight: 16,
borderRadius: 4,
},
modalButtons: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
},
modalButton: {
borderRadius: 4,
margin: 16,
},
noContacts: {
width: '100%',
height: 128,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
noContactsLabel: {
color: Colors.placeholder,
fontSize: 20,
},
memberSwitch: {
transform: [{scaleX: 0.7}, {scaleY: 0.7}],
},
error: {
flexGrow: 1,
paddingLeft: 32,
color: Colors.offsync,
},
});

View File

@ -1,10 +1,11 @@
import React, { useState } from 'react';
import { SafeAreaView, ScrollView, View } from 'react-native';
import {useTheme, Surface, Icon, Divider, IconButton, Text, TextInput} from 'react-native-paper';
import { SafeAreaView, Modal, ScrollView, View } from 'react-native';
import {useTheme, Switch, Surface, Icon, Divider, Button, IconButton, Text, TextInput} from 'react-native-paper';
import {styles} from './Details.styled';
import {useDetails} from './useDetails.hook';
import { Confirm } from '../confirm/Confirm';
import { Card } from '../card/Card';
import {BlurView} from '@react-native-community/blur';
export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}) {
const { state, actions } = useDetails();
@ -16,9 +17,13 @@ export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}
const [busy, setBusy] = useState(false);
const [confirmParams, setConfirmParams] = useState({});
const [confirm, setConfirm] = useState(false);
const [memberModal, setMemberModal] = useState(false);
const [error, setError] = useState(false);
const theme = useTheme();
const members = () => {
const membership = () => {
setError(false);
setMemberModal(true);
}
const remove = () => {
@ -126,10 +131,45 @@ export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}
}
const cards = state.channelCards.map((card, index) => (
<Card containerStyle={styles.card} key={index} imageUrl={card.imageUrl} name={card.name} placeholder={state.strings.name}
<Card containerStyle={{...styles.card, borderColor: theme.colors.outlineVariant }} key={index} imageUrl={card.imageUrl} name={card.name} placeholder={state.strings.name}
handle={card.handle} node={card.node} actions={[]} />
))
const members = state.cards.filter(card => {
if (state.detail && state.detail.members.find(member => member.guid === card.guid)) {
return true;
} else if(state.sealed && !card.sealable) {
return false;
} else {
return true;
}
}).map((card, index) => {
const enable = !state.detail ? [] : [
<Switch
key="enable"
style={styles.memberSwitch}
value={Boolean(state.detail.members.find(member => member.guid === card.guid))}
onValueChange={async (flag) => {
try {
setError(false);
if (flag) {
await actions.setMember(card.cardId);
} else {
await actions.clearMember(card.cardId);
}
} catch (err) {
console.log(err);
setError(true);
}
}}
/>
];
return (
<Card containerStyle={{ ...styles.card, borderColor: theme.colors.outlineVariant }} key={index} imageUrl={card.imageUrl} name={card.name} placeholder={state.strings.name} handle={card.handle} node={card.node} actions={enable} />
)
});
return (
<View style={styles.details}>
<SafeAreaView style={styles.header}>
@ -176,36 +216,36 @@ export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}
</Surface>
)}
{ !state.host && !state.locked && (
<View style={styles.item}>
<IconButton style={styles.icon} size={28} icon="label-outline" />
<View style={styles.guestSubject}>
<Icon size={28} source="label-outline" />
<Text style={styles.itemHeader}>{ state.subject }</Text>
</View>
)}
<View style={styles.item}>
<Icon source="calendar-month-outline" size={22} />
<Icon source="calendar-month-outline" size={20} />
<Text style={styles.itemLabel}>{ state.created }</Text>
</View>
{ state.host && (
<View style={styles.item}>
<Icon source="home-outline" size={22} />
<Icon source="home-outline" size={20} />
<Text style={styles.itemLabel}>{ state.strings.channelHost }</Text>
</View>
)}
{ !state.host && (
<View style={styles.item}>
<Icon source="server" size={22} />
<Icon source="server" size={20} />
<Text style={styles.itemLabel}>{ state.strings.channelGuest }</Text>
</View>
)}
{ state.sealed && (
<View style={styles.item}>
<Icon source="shield-outline" size={22} />
<Icon source="shield-outline" size={20} />
<Text style={styles.itemLabel}>{ state.strings.sealed }</Text>
</View>
)}
{ !state.sealed && (
<View style={styles.item}>
<Icon source="shield-off-outline" size={22} />
<Icon source="shield-off-outline" size={20} />
<Text style={styles.itemLabel}>{ state.strings.notSealed }</Text>
</View>
)}
@ -273,7 +313,7 @@ export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}
mode="contained"
icon="account-cog-outline"
size={32}
onPress={members}
onPress={membership}
/>
<Text style={styles.actionLabel}>{state.strings.members}</Text>
</View>
@ -296,6 +336,37 @@ export function Details({close, closeAll}: {close: ()=>void, closeAll: ()=>void}
)}
</ScrollView>
<Confirm show={confirm} busy={busy} params={confirmParams} />
<Modal animationType="fade" transparent={true} supportedOrientations={['portrait', 'landscape']} visible={memberModal} onRequestClose={() => setMemberModal(false)}>
<View style={styles.memberModal}>
<BlurView style={styles.blur} blurType="dark" blurAmount={2} reducedTransparencyFallbackColor="dark" />
<Surface elevation={5} mode="flat" style={styles.memberSurface}>
<View style={styles.modalHeader}>
<Text style={styles.modalTitle}>{state.strings.editMembership}</Text>
<IconButton style={styles.modalClose} icon="close" size={24} onPress={() => setMemberModal(false)} />
</View>
<Surface eleveation={2} style={styles.modalArea}>
{ members.length === 0 && (
<View style={styles.noContacts}>
<Text style={styles.noContactsLabel}>{ state.strings.noContacts }</Text>
</View>
)}
{ members.length > 0 && (
<ScrollView style={styles.modalMembers}>
{ members }
</ScrollView>
)}
</Surface>
<View style={styles.modalButtons}>
{ error && (
<Text style={styles.error}>{ state.strings.operationFailed }</Text>
)}
<Button style={styles.modalButton} compact={true} mode="outlined" onPress={() => setMemberModal(false)}>
{state.strings.close}
</Button>
</View>
</Surface>
</View>
</Modal>
</View>
)
}