mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
adding profile settings drawer for tablet
This commit is contained in:
parent
4e380a8e05
commit
10925079bf
@ -17,6 +17,7 @@ const LightColors = {
|
||||
descriptionText: '#888888',
|
||||
text: '#444444',
|
||||
screenBase: '#dddddd',
|
||||
drawerBase: '#eeeeee',
|
||||
areaBase: '#ffffff',
|
||||
modalBase: '#ffffff',
|
||||
modalOverlay: 'rgba(52,52,52,0.8)',
|
||||
@ -69,6 +70,7 @@ const DarkColors = {
|
||||
descriptionText: '#bbbbbb',
|
||||
text: '#ffffff',
|
||||
screenBase: '#222222',
|
||||
drawerBase: '#333333',
|
||||
areaBase: '#444444',
|
||||
modalBase: '#111111',
|
||||
modalOverlay: 'rgba(88,88,88,0.8)',
|
||||
@ -124,6 +126,7 @@ export const Colors = {
|
||||
descriptionText: getColor('descriptionText'),
|
||||
text: getColor('text'),
|
||||
screenBase: getColor('screenBase'),
|
||||
drawerBase: getColor('drawerBase'),
|
||||
areaBase: getColor('areaBase'),
|
||||
modalOverlay: getColor('modalOverlay'),
|
||||
modalBase: getColor('modalBase'),
|
||||
|
@ -11,6 +11,7 @@ import { useSession } from './useSession.hook';
|
||||
import { styles } from './Session.styled';
|
||||
import Colors from 'constants/Colors';
|
||||
import { Profile } from './profile/Profile';
|
||||
import { ProfileSettings } from './profileSettings/ProfileSettings';
|
||||
import { CardsHeader, CardsBody, Cards } from './cards/Cards';
|
||||
import { RegistryHeader, RegistryBody, Registry } from './registry/Registry';
|
||||
import { ContactHeader, ContactBody, Contact } from './contact/Contact';
|
||||
@ -433,7 +434,7 @@ export function Session({ sharing, clearSharing }) {
|
||||
<View style={styles.container}>
|
||||
{ state.tabbed === false && (
|
||||
<ProfileDrawer.Navigator screenOptions={{ ...drawerParams, drawerStyle: { width: '45%' } }} drawerContent={(props) => (
|
||||
<ScrollView style={styles.drawer}><SafeAreaView edges={['top', 'bottom', 'right']}><Profile /></SafeAreaView></ScrollView>
|
||||
<ProfileSettings />
|
||||
)}>
|
||||
<ProfileDrawer.Screen name="detail">
|
||||
{(props) => <DetailDrawerScreen navParams={{ profileNav: props.navigation, state, actions, addChannel, dmChannel, shareChannel, shareIntent, setShareIntent }} />}
|
||||
|
@ -95,7 +95,7 @@ export const styles = StyleSheet.create({
|
||||
paddingTop: 8,
|
||||
paddingLeft: 8,
|
||||
paddingRight: 8,
|
||||
backgroundColor: Colors.formBackground,
|
||||
backgroundColor: Colors.drawerBase,
|
||||
},
|
||||
options: {
|
||||
display: 'flex',
|
||||
|
@ -13,7 +13,7 @@ import { useProfile } from './useProfile.hook';
|
||||
import { styles } from './Profile.styled';
|
||||
import avatar from 'images/avatar.png';
|
||||
|
||||
export function Profile() {
|
||||
export function Profile({ drawer }) {
|
||||
|
||||
const [busyDetail, setBusyDetail] = useState(false);
|
||||
const { state, actions } = useProfile();
|
||||
@ -71,79 +71,87 @@ export function Profile() {
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Image source={state.imageSource} style={{ ...styles.logo, width: state.imageWidth, height: state.imageHeight }} resizeMode={'contain'} />
|
||||
|
||||
<View style={styles.content}>
|
||||
<View style={{ width: state.imageWidth, height: state.imageHeight - OVERLAP }} />
|
||||
|
||||
<View style={styles.control}>
|
||||
<Menu>
|
||||
<MenuTrigger customStyles={styles.trigger}>
|
||||
<View style={styles.edit}>
|
||||
<Text style={styles.editLabel}>{ state.strings.edit }</Text>
|
||||
<MatIcons name="square-edit-outline" size={14} color={Colors.linkText} />
|
||||
</View>
|
||||
</MenuTrigger>
|
||||
<MenuOptions optionsContainerStyle={{ width: 'auto' }} style={styles.options}>
|
||||
<MenuOption onSelect={onGallery}>
|
||||
<Text style={styles.option}>{ state.strings.editImage }</Text>
|
||||
</MenuOption>
|
||||
<MenuOption onSelect={actions.showDetails}>
|
||||
<Text style={styles.option}>{ state.strings.editDetails }</Text>
|
||||
</MenuOption>
|
||||
</MenuOptions>
|
||||
</Menu>
|
||||
</View>
|
||||
|
||||
|
||||
<View style={{ ...styles.details, width: state.detailWidth }}>
|
||||
|
||||
{ state.name && (
|
||||
<Text style={styles.nameSet} numberOfLines={1} adjustsFontSizeToFit={true}>{ state.name }</Text>
|
||||
)}
|
||||
{ !state.name && (
|
||||
<Text style={styles.nameUnset}>{ state.strings.name }</Text>
|
||||
)}
|
||||
|
||||
<Text style={styles.username} numberOfLines={1}>{ state.username }</Text>
|
||||
|
||||
<View style={styles.attributes}>
|
||||
<View style={styles.entry}>
|
||||
<AntIcons name="enviromento" style={styles.icon} size={20} color={Colors.text} />
|
||||
{ state.location && (
|
||||
<Text style={styles.locationSet}>{ state.location }</Text>
|
||||
)}
|
||||
{ !state.location && (
|
||||
<Text style={styles.locationUnset}>Location</Text>
|
||||
)}
|
||||
</View>
|
||||
<View style={styles.divider} />
|
||||
<ScrollView style={styles.description}>
|
||||
<View style={styles.entry}>
|
||||
<MatIcons name="book-open-outline" style={styles.descriptionIcon} size={20} color={Colors.text} />
|
||||
{ state.description && (
|
||||
<Text style={styles.descriptionSet}>{ state.description }</Text>
|
||||
)}
|
||||
{ !state.description && (
|
||||
<Text style={styles.descriptionUnset}>Description</Text>
|
||||
)}
|
||||
<>
|
||||
{ drawer && (
|
||||
<View style={styles.drawerContainer}>
|
||||
<Text style={styles.drawerHeader} adjustsFontSizeToFit={true}>{ state.username }</Text>
|
||||
<View style={styles.drawerFrame}>
|
||||
<Image source={state.imageSource} style={styles.drawerLogo} resizeMode={'contain'} />
|
||||
<View style={styles.drawerLogoEdit}>
|
||||
<Text style={styles.editLabel}>{ state.strings.edit }</Text>
|
||||
<MatIcons name="square-edit-outline" size={14} color={Colors.linkText} />
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.group}>
|
||||
<TouchableOpacity style={styles.entry} activeOpacity={1}>
|
||||
<MatIcons name="eye-outline" style={styles.icon} size={20} color={Colors.text} />
|
||||
<TouchableOpacity activeOpacity={1} onPress={() => setVisible(!state.searchable)}>
|
||||
<Text style={styles.visibleLabel}>{ state.strings.visibleRegistry }</Text>
|
||||
</TouchableOpacity>
|
||||
<Switch value={state.searchable} style={Platform.OS==='ios' ? styles.visibleSwitch : {}} thumbColor={Colors.sliderGrip} ios_backgroundColor={Colors.disabledIndicator}
|
||||
trackColor={styles.track} onValueChange={setVisible} />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{ !drawer && (
|
||||
<View style={styles.container}>
|
||||
<Image source={state.imageSource} style={{ ...styles.logo, width: state.imageWidth, height: state.imageHeight }} resizeMode={'contain'} />
|
||||
<View style={styles.content}>
|
||||
<View style={{ width: state.imageWidth, height: state.imageHeight - OVERLAP }} />
|
||||
<View style={styles.control}>
|
||||
<Menu>
|
||||
<MenuTrigger customStyles={styles.trigger}>
|
||||
<View style={styles.edit}>
|
||||
<Text style={styles.editLabel}>{ state.strings.edit }</Text>
|
||||
<MatIcons name="square-edit-outline" size={14} color={Colors.linkText} />
|
||||
</View>
|
||||
</MenuTrigger>
|
||||
<MenuOptions optionsContainerStyle={{ width: 'auto' }} style={styles.options}>
|
||||
<MenuOption onSelect={onGallery}>
|
||||
<Text style={styles.option}>{ state.strings.editImage }</Text>
|
||||
</MenuOption>
|
||||
<MenuOption onSelect={actions.showDetails}>
|
||||
<Text style={styles.option}>{ state.strings.editDetails }</Text>
|
||||
</MenuOption>
|
||||
</MenuOptions>
|
||||
</Menu>
|
||||
</View>
|
||||
<View style={{ ...styles.details, width: state.detailWidth }}>
|
||||
{ state.name && (
|
||||
<Text style={styles.nameSet} numberOfLines={1} adjustsFontSizeToFit={true}>{ state.name }</Text>
|
||||
)}
|
||||
{ !state.name && (
|
||||
<Text style={styles.nameUnset}>{ state.strings.name }</Text>
|
||||
)}
|
||||
<Text style={styles.username} numberOfLines={1}>{ state.username }</Text>
|
||||
<View style={styles.attributes}>
|
||||
<View style={styles.entry}>
|
||||
<AntIcons name="enviromento" style={styles.icon} size={20} color={Colors.text} />
|
||||
{ state.location && (
|
||||
<Text style={styles.locationSet}>{ state.location }</Text>
|
||||
)}
|
||||
{ !state.location && (
|
||||
<Text style={styles.locationUnset}>Location</Text>
|
||||
)}
|
||||
</View>
|
||||
<View style={styles.divider} />
|
||||
<ScrollView style={styles.description}>
|
||||
<View style={styles.entry}>
|
||||
<MatIcons name="book-open-outline" style={styles.descriptionIcon} size={20} color={Colors.text} />
|
||||
{ state.description && (
|
||||
<Text style={styles.descriptionSet}>{ state.description }</Text>
|
||||
)}
|
||||
{ !state.description && (
|
||||
<Text style={styles.descriptionUnset}>Description</Text>
|
||||
)}
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
<View style={styles.group}>
|
||||
<TouchableOpacity style={styles.entry} activeOpacity={1}>
|
||||
<MatIcons name="eye-outline" style={styles.icon} size={20} color={Colors.text} />
|
||||
<TouchableOpacity activeOpacity={1} onPress={() => setVisible(!state.searchable)}>
|
||||
<Text style={styles.visibleLabel}>{ state.strings.visibleRegistry }</Text>
|
||||
</TouchableOpacity>
|
||||
<Switch value={state.searchable} style={Platform.OS==='ios' ? styles.visibleSwitch : {}} thumbColor={Colors.sliderGrip} ios_backgroundColor={Colors.disabledIndicator}
|
||||
trackColor={styles.track} onValueChange={setVisible} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
)}
|
||||
|
||||
<Modal
|
||||
animationType="fade"
|
||||
@ -212,8 +220,7 @@ export function Profile() {
|
||||
</View>
|
||||
</Modal>
|
||||
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,43 @@ import { StyleSheet } from 'react-native';
|
||||
import { Colors } from 'constants/Colors';
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
drawerContainer: {
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
drawerHeader: {
|
||||
fontFamily: 'roboto',
|
||||
color: Colors.text,
|
||||
fontSize: 20,
|
||||
padding: 16,
|
||||
},
|
||||
drawerFrame: {
|
||||
width: '50%',
|
||||
maxWidth: 400,
|
||||
paddingBottom: 16,
|
||||
},
|
||||
drawerLogo: {
|
||||
aspectRatio: 1,
|
||||
resizeMode: 'contain',
|
||||
borderRadius: 8,
|
||||
width: null,
|
||||
height: null,
|
||||
},
|
||||
drawerLogoEdit: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
alignSelf: 'center',
|
||||
backgroundColor: 'rgba(255,255,255,0.6)',
|
||||
paddingLeft: 8,
|
||||
paddingRight: 8,
|
||||
borderBottomLeftRadius: 6,
|
||||
borderBottomRightRadius: 6,
|
||||
},
|
||||
|
||||
container: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
|
@ -1,48 +0,0 @@
|
||||
import { FlatList, View, Alert, TouchableOpacity, Text } from 'react-native';
|
||||
import { styles } from './BlockedContacts.styled';
|
||||
import { useBlockedContacts } from './useBlockedContacts.hook';
|
||||
import { Logo } from 'utils/Logo';
|
||||
|
||||
export function BlockedContacts() {
|
||||
|
||||
const { state, actions } = useBlockedContacts();
|
||||
|
||||
const unblock = (cardId) => {
|
||||
Alert.alert(
|
||||
'Unblocking Contact',
|
||||
'Confirm?',
|
||||
[
|
||||
{ text: "Cancel", onPress: () => {}, },
|
||||
{ text: "Unblock", onPress: () => actions.unblock(cardId) },
|
||||
],
|
||||
);
|
||||
};
|
||||
|
||||
const BlockedItem = ({ item }) => {
|
||||
return (
|
||||
<TouchableOpacity style={styles.item} onPress={() => unblock(item.cardId)}>
|
||||
<Logo src={item.logo} width={32} height={32} radius={6} />
|
||||
<View style={styles.detail}>
|
||||
<Text style={styles.name} numberOfLines={1} ellipsizeMode={'tail'}>{ item.name }</Text>
|
||||
<Text style={styles.handle} numberOfLines={1} ellipsizeMode={'tail'}>{ item.handle }</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{ state.cards.length === 0 && (
|
||||
<Text style={styles.default}>No Blocked Contacts</Text>
|
||||
)}
|
||||
{ state.cards.length !== 0 && (
|
||||
<FlatList
|
||||
data={state.cards}
|
||||
renderItem={({item}) => <BlockedItem item={item} />}
|
||||
keyExtractor={item => item.cardId}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
import { StyleSheet } from 'react-native';
|
||||
import { Colors } from 'constants/Colors';
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: Colors.white,
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
justifyContent: 'center',
|
||||
fontSize: 14,
|
||||
height: 200,
|
||||
},
|
||||
default: {
|
||||
textAlign: 'center',
|
||||
color: Colors.grey,
|
||||
},
|
||||
item: {
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
height: 48,
|
||||
paddingLeft: 16,
|
||||
alignItems: 'center',
|
||||
borderBottomWidth: 1,
|
||||
borderColor: Colors.itemDivider,
|
||||
},
|
||||
detail: {
|
||||
paddingLeft: 12,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
},
|
||||
name: {
|
||||
color: Colors.text,
|
||||
fontSize: 14,
|
||||
},
|
||||
handle: {
|
||||
color: Colors.text,
|
||||
fontSize: 12,
|
||||
},
|
||||
});
|
@ -1,53 +0,0 @@
|
||||
import { useState, useEffect, useContext } from 'react';
|
||||
import { CardContext } from 'context/CardContext';
|
||||
|
||||
export function useBlockedContacts() {
|
||||
|
||||
const [state, setState] = useState({
|
||||
cards: [],
|
||||
});
|
||||
|
||||
const card = useContext(CardContext);
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }));
|
||||
}
|
||||
|
||||
const setCardItem = (item) => {
|
||||
const { profile } = item;
|
||||
return {
|
||||
cardId: item.cardId,
|
||||
name: profile?.name,
|
||||
handle: `${profile?.handle}@${profile?.node}`,
|
||||
blocked: item.blocked,
|
||||
logo: profile?.imageSet ? card.actions.getCardImageUrl(item.cardId) : 'avatar',
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const cards = Array.from(card.state.cards.values());
|
||||
const items = cards.map(setCardItem);
|
||||
const filtered = items.filter(item => {
|
||||
return item.blocked;
|
||||
});
|
||||
filtered.sort((a, b) => {
|
||||
if (a.name === b.name) {
|
||||
return 0;
|
||||
}
|
||||
if (!a.name || (a.name < b.name)) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
updateState({ cards: filtered });
|
||||
}, [card.state]);
|
||||
|
||||
const actions = {
|
||||
unblock: async (cardId) => {
|
||||
await card.actions.clearCardFlag(cardId);
|
||||
}
|
||||
};
|
||||
|
||||
return { state, actions };
|
||||
}
|
||||
|
@ -1,47 +0,0 @@
|
||||
import { FlatList, View, Alert, TouchableOpacity, Text } from 'react-native';
|
||||
import { styles } from './BlockedMessages.styled';
|
||||
import { useBlockedMessages } from './useBlockedMessages.hook';
|
||||
import { Logo } from 'utils/Logo';
|
||||
|
||||
export function BlockedMessages() {
|
||||
|
||||
const { state, actions } = useBlockedMessages();
|
||||
|
||||
const unblock = (cardId, channelId, topicId) => {
|
||||
Alert.alert(
|
||||
'Unblocking Message',
|
||||
'Confirm?',
|
||||
[
|
||||
{ text: "Cancel", onPress: () => {}, },
|
||||
{ text: "Unblock", onPress: () => actions.unblock(cardId, channelId, topicId) },
|
||||
],
|
||||
);
|
||||
};
|
||||
|
||||
const BlockedItem = ({ item }) => {
|
||||
return (
|
||||
<TouchableOpacity style={styles.item} onPress={() => unblock(item.cardId, item.channelId, item.topicId)}>
|
||||
<View style={styles.detail}>
|
||||
<Text style={styles.name} numberOfLines={1} ellipsizeMode={'tail'}>{ item.name }</Text>
|
||||
<Text style={styles.created} numberOfLines={1} ellipsizeMode={'tail'}>{ item.timestamp }</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{ state.messages.length === 0 && (
|
||||
<Text style={styles.default}>No Blocked Messages</Text>
|
||||
)}
|
||||
{ state.messages.length !== 0 && (
|
||||
<FlatList
|
||||
data={state.messages}
|
||||
renderItem={({item}) => <BlockedItem item={item} />}
|
||||
keyExtractor={item => item.id}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
@ -1,46 +0,0 @@
|
||||
import { StyleSheet } from 'react-native';
|
||||
import { Colors } from 'constants/Colors';
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: Colors.white,
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
justifyContent: 'center',
|
||||
fontSize: 14,
|
||||
height: 200,
|
||||
},
|
||||
default: {
|
||||
textAlign: 'center',
|
||||
color: Colors.grey,
|
||||
},
|
||||
item: {
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
height: 32,
|
||||
paddingLeft: 16,
|
||||
alignItems: 'center',
|
||||
borderBottomWidth: 1,
|
||||
borderColor: Colors.itemDivider,
|
||||
},
|
||||
detail: {
|
||||
paddingLeft: 12,
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
},
|
||||
name: {
|
||||
color: Colors.text,
|
||||
fontSize: 14,
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
minWidth: 0,
|
||||
},
|
||||
created: {
|
||||
color: Colors.text,
|
||||
fontSize: 12,
|
||||
paddingRight: 16,
|
||||
},
|
||||
});
|
@ -1,121 +0,0 @@
|
||||
import { useState, useEffect, useContext } from 'react';
|
||||
import { StoreContext } from 'context/StoreContext';
|
||||
import { ChannelContext } from 'context/ChannelContext';
|
||||
import { CardContext } from 'context/CardContext';
|
||||
import { ProfileContext } from 'context/ProfileContext';
|
||||
import { getCardByGuid } from 'context/cardUtil';
|
||||
import moment from 'moment';
|
||||
|
||||
export function useBlockedMessages() {
|
||||
|
||||
const [state, setState] = useState({
|
||||
messages: []
|
||||
});
|
||||
|
||||
const store = useContext(StoreContext);
|
||||
const card = useContext(CardContext);
|
||||
const channel = useContext(ChannelContext);
|
||||
const profile = useContext(ProfileContext);
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }));
|
||||
}
|
||||
|
||||
const setTopicItem = (cardId, channelId, topic) => {
|
||||
let name, nameSet
|
||||
if (topic.detail.guid === profile.state.identity.guid) {
|
||||
const identity = profile.state.identity;
|
||||
if (identity.name) {
|
||||
name = identity.name;
|
||||
}
|
||||
else {
|
||||
name = `${identity.handle}@${identity.node}`;
|
||||
}
|
||||
nameSet = true;
|
||||
}
|
||||
else {
|
||||
const contact = getCardByGuid(card.state.cards, topic.detail.guid);
|
||||
if (contact) {
|
||||
if (contact?.card?.profile?.name) {
|
||||
name = contact.card.profile.name;
|
||||
}
|
||||
else {
|
||||
name = `${contact.card.profile.handle}@${contact.card.profile.node}`;
|
||||
}
|
||||
nameSet = true;
|
||||
}
|
||||
else {
|
||||
name = 'unknown';
|
||||
nameSet = false;
|
||||
}
|
||||
}
|
||||
|
||||
let timestamp;
|
||||
const date = new Date(topic.detail.created * 1000);
|
||||
const now = new Date();
|
||||
const offset = now.getTime() - date.getTime();
|
||||
if(offset < 86400000) {
|
||||
timestamp = moment(date).format('h:mma');
|
||||
}
|
||||
else if (offset < 31449600000) {
|
||||
timestamp = moment(date).format('M/DD');
|
||||
}
|
||||
else {
|
||||
timestamp = moment(date).format('M/DD/YYYY');
|
||||
}
|
||||
|
||||
const { topicId } = topic;
|
||||
return { name, nameSet, timestamp, cardId, channelId, topicId, id: `${cardId}:${channelId}:${topicId}` };
|
||||
};
|
||||
|
||||
const loadBlocked = async () => {
|
||||
const channels = [];
|
||||
channel.state.channels.forEach((channelItem, channelId, map) => {
|
||||
channels.push({ channelId });
|
||||
});
|
||||
card.state.cards.forEach((cardItem, cardId, map) => {
|
||||
cardItem.channels.forEach((channelItem, channelId, map) => {
|
||||
channels.push({ cardId, channelId });
|
||||
});
|
||||
});
|
||||
|
||||
const merged = [];
|
||||
for(let i = 0; i < channels.length; i++) {
|
||||
let topics;
|
||||
const { cardId, channelId } = channels[i];
|
||||
if (cardId) {
|
||||
topics = await card.actions.getTopicItems(cardId, channelId);
|
||||
}
|
||||
else {
|
||||
topics = await channel.actions.getTopicItems(channelId);
|
||||
}
|
||||
topics.forEach((topic) => {
|
||||
if (topic.blocked) {
|
||||
merged.push(setTopicItem(cardId, channelId, topic));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateState({ messages: merged });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadBlocked();
|
||||
}, []);
|
||||
|
||||
const actions = {
|
||||
unblock: async (cardId, channelId, topicId) => {
|
||||
const id = `${cardId}:${channelId}:${topicId}`;
|
||||
if (cardId) {
|
||||
card.actions.clearTopicFlag(cardId, channelId, topicId);
|
||||
}
|
||||
else {
|
||||
channel.actions.clearTopicFlag(channelId, topicId);
|
||||
}
|
||||
updateState({ messages: state.messages.filter(item => item.id !== id) });
|
||||
}
|
||||
};
|
||||
|
||||
return { state, actions };
|
||||
}
|
||||
|
@ -1,47 +0,0 @@
|
||||
import { FlatList, View, Alert, TouchableOpacity, Text } from 'react-native';
|
||||
import { styles } from './BlockedTopics.styled';
|
||||
import { useBlockedTopics } from './useBlockedTopics.hook';
|
||||
import { Logo } from 'utils/Logo';
|
||||
|
||||
export function BlockedTopics() {
|
||||
|
||||
const { state, actions } = useBlockedTopics();
|
||||
|
||||
const unblock = (cardId, channelId) => {
|
||||
Alert.alert(
|
||||
'Unblocking Contact',
|
||||
'Confirm?',
|
||||
[
|
||||
{ text: "Cancel", onPress: () => {}, },
|
||||
{ text: "Unblock", onPress: () => actions.unblock(cardId, channelId) },
|
||||
],
|
||||
);
|
||||
};
|
||||
|
||||
const BlockedItem = ({ item }) => {
|
||||
return (
|
||||
<TouchableOpacity style={styles.item} onPress={() => unblock(item.cardId, item.channelId)}>
|
||||
<View style={styles.detail}>
|
||||
<Text style={styles.name} numberOfLines={1} ellipsizeMode={'tail'}>{ item.name }</Text>
|
||||
<Text style={styles.created} numberOfLines={1} ellipsizeMode={'tail'}>{ item.created }</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{ state.channels.length === 0 && (
|
||||
<Text style={styles.default}>No Blocked Topics</Text>
|
||||
)}
|
||||
{ state.channels.length !== 0 && (
|
||||
<FlatList
|
||||
data={state.channels}
|
||||
renderItem={({item}) => <BlockedItem item={item} />}
|
||||
keyExtractor={item => item.id}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
@ -1,46 +0,0 @@
|
||||
import { StyleSheet } from 'react-native';
|
||||
import { Colors } from 'constants/Colors';
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: Colors.white,
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
justifyContent: 'center',
|
||||
fontSize: 14,
|
||||
height: 200,
|
||||
},
|
||||
default: {
|
||||
textAlign: 'center',
|
||||
color: Colors.grey,
|
||||
},
|
||||
item: {
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
height: 32,
|
||||
paddingLeft: 16,
|
||||
alignItems: 'center',
|
||||
borderBottomWidth: 1,
|
||||
borderColor: Colors.itemDivider,
|
||||
},
|
||||
detail: {
|
||||
paddingLeft: 12,
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
},
|
||||
name: {
|
||||
color: Colors.text,
|
||||
fontSize: 14,
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
minWidth: 0,
|
||||
},
|
||||
created: {
|
||||
color: Colors.text,
|
||||
fontSize: 12,
|
||||
paddingRight: 16,
|
||||
},
|
||||
});
|
@ -1,92 +0,0 @@
|
||||
import { useState, useEffect, useContext } from 'react';
|
||||
import { CardContext } from 'context/CardContext';
|
||||
import { ChannelContext } from 'context/ChannelContext';
|
||||
import { ProfileContext } from 'context/ProfileContext';
|
||||
import { getCardByGuid } from 'context/cardUtil';
|
||||
import { getChannelSubjectLogo } from 'context/channelUtil';
|
||||
import moment from 'moment';
|
||||
|
||||
export function useBlockedTopics() {
|
||||
|
||||
const [state, setState] = useState({
|
||||
channels: []
|
||||
});
|
||||
|
||||
const profile = useContext(ProfileContext);
|
||||
const card = useContext(CardContext);
|
||||
const channel = useContext(ChannelContext);
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }));
|
||||
}
|
||||
|
||||
const getCard = (guid) => {
|
||||
let contact = null
|
||||
card.state.cards.forEach((card, cardId, map) => {
|
||||
if (card?.profile?.guid === guid) {
|
||||
contact = card;
|
||||
}
|
||||
});
|
||||
return contact;
|
||||
}
|
||||
|
||||
const setChannelItem = (item) => {
|
||||
let timestamp;
|
||||
const date = new Date(item.channel.detail.created * 1000);
|
||||
const now = new Date();
|
||||
const offset = now.getTime() - date.getTime();
|
||||
if(offset < 86400000) {
|
||||
timestamp = moment(date).format('h:mma');
|
||||
}
|
||||
else if (offset < 31449600000) {
|
||||
timestamp = moment(date).format('M/DD');
|
||||
}
|
||||
else {
|
||||
timestamp = moment(date).format('M/DD/YYYY');
|
||||
}
|
||||
|
||||
|
||||
const profileGuid = profile.state?.identity?.guid;
|
||||
const { logo, subject } = getChannelSubjectLogo(item.cardId, profileGuid, item.channel, card.state.cards, card.actions.getCardImageUrl);
|
||||
|
||||
return {
|
||||
id: `${item.cardId}:${item.channel.channelId}`,
|
||||
cardId: item.cardId,
|
||||
channelId: item.channel.channelId,
|
||||
name: subject,
|
||||
created: timestamp,
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let merged = [];
|
||||
card.state.cards.forEach((cardItem, cardId, map) => {
|
||||
cardItem.channels.forEach((channelItem) => {
|
||||
if (channelItem.blocked) {
|
||||
merged.push({ cardId, channel: channelItem });
|
||||
}
|
||||
});
|
||||
});
|
||||
channel.state.channels.forEach((channelItem, channelId, map) => {
|
||||
if (channelItem.blocked) {
|
||||
merged.push({ channel: channelItem });
|
||||
}
|
||||
});
|
||||
const items = merged.map(setChannelItem);
|
||||
updateState({ channels: items });
|
||||
}, [card.state, channel.state]);
|
||||
|
||||
const actions = {
|
||||
unblock: async (cardId, channelId) => {
|
||||
if (cardId) {
|
||||
await card.actions.clearChannelFlag(cardId, channelId);
|
||||
}
|
||||
else {
|
||||
await channel.actions.clearChannelFlag(channelId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return { state, actions };
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ export function useProfile() {
|
||||
useEffect(() => {
|
||||
const { name, handle, node, location, description, image } = profile.state.identity;
|
||||
const imageSource = image ? { uri: profile.state.imageUrl } : avatar;
|
||||
const username = `${handle} / ${node}`
|
||||
const username = `${handle}/${node}`
|
||||
updateState({ name, username, location, description, imageSource });
|
||||
}, [profile.state]);
|
||||
|
||||
|
18
app/mobile/src/session/profileSettings/ProfileSettings.jsx
Normal file
18
app/mobile/src/session/profileSettings/ProfileSettings.jsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { ScrollView, View } from 'react-native';
|
||||
import { Profile } from '../profile/Profile';
|
||||
import { Settings } from '../settings/Settings';
|
||||
import { styles } from './ProfileSettings.styled';
|
||||
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
|
||||
|
||||
export function ProfileSettings() {
|
||||
|
||||
return (
|
||||
<ScrollView style={styles.drawer}>
|
||||
<SafeAreaView style={styles.container} edges={['top', 'right']}>
|
||||
<Profile drawer={true} />
|
||||
<Settings drawer={true} />
|
||||
</SafeAreaView>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
import { StyleSheet } from 'react-native';
|
||||
import { Colors } from 'constants/Colors';
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
drawer: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: Colors.drawerBase,
|
||||
},
|
||||
container: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
});
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user