mirror of
https://github.com/balzack/databag.git
synced 2025-02-12 03:29:16 +00:00
support blocking and unblocking topics
This commit is contained in:
parent
445b364365
commit
edcffa6a67
@ -190,6 +190,17 @@ export function useCardContext() {
|
||||
}
|
||||
}
|
||||
}
|
||||
const setCardChannelBlocked = (cardId, channelId, blocked) => {
|
||||
let card = cards.current.get(cardId);
|
||||
if (card) {
|
||||
let channel = card.channels.get(channelId);
|
||||
if (channel) {
|
||||
channel.blocked = blocked;
|
||||
card.channels.set(channelId, channel);
|
||||
cards.current.set(cardId, card);
|
||||
}
|
||||
}
|
||||
}
|
||||
const clearCardChannel = (cardId, channelId) => {
|
||||
let card = cards.current.get(cardId);
|
||||
if (card) {
|
||||
@ -438,6 +449,18 @@ export function useCardContext() {
|
||||
setCardChannelSyncRevision(cardId, channelId, revision);
|
||||
updateState({ cards: cards.current });
|
||||
},
|
||||
setChannelBlocked: async (cardId, channelId) => {
|
||||
const { guid } = session.current;
|
||||
await store.actions.setCardChannelItemBlocked(guid, cardId, channelId);
|
||||
setCardChannelBlocked(cardId, channelId, true);
|
||||
updateState({ cards: cards.current });
|
||||
},
|
||||
clearChannelBlocked: async (cardId, channelId) => {
|
||||
const { guid } = session.current;
|
||||
await store.actions.clearCardChannelItemBlocked(guid, cardId, channelId);
|
||||
setCardChannelBlocked(cardId, channelId, false);
|
||||
updateState({ cards: cards.current });
|
||||
},
|
||||
getChannelTopicItems: async (cardId, channelId) => {
|
||||
const { guid } = session.current;
|
||||
return await store.actions.getCardChannelTopicItems(guid, cardId, channelId);
|
||||
|
@ -83,6 +83,13 @@ export function useChannelContext() {
|
||||
channels.current.set(channelId, channel);
|
||||
}
|
||||
}
|
||||
const setChannelBlocked = (channelId, blocked) => {
|
||||
let channel = channels.current.get(channelId);
|
||||
if (channel) {
|
||||
channel.blocked = blocked;
|
||||
channels.current.set(channelId, channel);
|
||||
}
|
||||
}
|
||||
|
||||
const sync = async () => {
|
||||
|
||||
@ -182,6 +189,18 @@ export function useChannelContext() {
|
||||
setChannelSyncRevision(channelId, revision);
|
||||
updateState({ channels: channels.current });
|
||||
},
|
||||
setBlocked: async (channelId) => {
|
||||
const { guid } = session.current;
|
||||
await store.actions.setChannelItemBlocked(guid, channelId);
|
||||
setChannelBlocked(channelId, 1);
|
||||
updateState({ channels: channels.current });
|
||||
},
|
||||
clearBlocked: async (channelId) => {
|
||||
const { guid } = session.current;
|
||||
await store.actions.clearChannelItemBlocked(guid, channelId);
|
||||
setChannelBlocked(channelId, 0);
|
||||
updateState({ channels: channels.current });
|
||||
},
|
||||
getTopicItems: async (channelId) => {
|
||||
const { guid } = session.current;
|
||||
return await store.actions.getChannelTopicItems(guid, channelId);
|
||||
|
@ -375,6 +375,17 @@ export function useConversationContext() {
|
||||
await channel.actions.clearCard(channelId, id);
|
||||
}
|
||||
},
|
||||
setBlocked: async () => {
|
||||
if (conversationId.current) {
|
||||
const { cardId, channelId } = conversationId.current;
|
||||
if (cardId) {
|
||||
await card.actions.setChannelBlocked(cardId, channelId);
|
||||
}
|
||||
else {
|
||||
await channel.actions.setBlocked(channelId);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return { state, actions }
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useEffect, useState, useRef, useContext } from 'react';
|
||||
import SQLite from "react-native-sqlite-storage";
|
||||
|
||||
const DATABAG_DB = 'databag_v038.db';
|
||||
const DATABAG_DB = 'databag_v039.db';
|
||||
|
||||
export function useStoreContext() {
|
||||
const [state, setState] = useState({});
|
||||
@ -12,7 +12,7 @@ export function useStoreContext() {
|
||||
}
|
||||
|
||||
const initSession = async (guid) => {
|
||||
await db.current.executeSql(`CREATE TABLE IF NOT EXISTS channel_${guid} (channel_id text, revision integer, detail_revision integer, topic_revision integer, sync_revision integer, detail text, summary text, offsync integer, read_revision integer, unique(channel_id))`);
|
||||
await db.current.executeSql(`CREATE TABLE IF NOT EXISTS channel_${guid} (channel_id text, revision integer, detail_revision integer, topic_revision integer, blocked integer, sync_revision integer, detail text, summary text, offsync integer, read_revision integer, unique(channel_id))`);
|
||||
await db.current.executeSql(`CREATE TABLE IF NOT EXISTS channel_topic_${guid} (channel_id text, topic_id text, revision integer, detail_revision integer, detail text, unique(channel_id, topic_id))`);
|
||||
await db.current.executeSql(`CREATE TABLE IF NOT EXISTS card_${guid} (card_id text, revision integer, detail_revision integer, profile_revision integer, detail text, profile text, notified_view integer, notified_article integer, notified_profile integer, notified_channel integer, offsync integer, blocked integer, unique(card_id))`);
|
||||
await db.current.executeSql(`CREATE TABLE IF NOT EXISTS card_channel_${guid} (card_id text, channel_id text, revision integer, detail_revision integer, topic_revision integer, sync_revision integer, detail text, summary text, offsync integer, blocked integer, read_revision integer, unique(card_id, channel_id))`);
|
||||
@ -189,6 +189,12 @@ export function useStoreContext() {
|
||||
setChannelItemSyncRevision: async (guid, channelId, revision) => {
|
||||
await db.current.executeSql(`UPDATE channel_${guid} set sync_revision=? where channel_id=?`, [revision, channelId]);
|
||||
},
|
||||
setChannelItemBlocked: async (guid, channelId) => {
|
||||
await db.current.executeSql(`UPDATE channel_${guid} set blocked=? where channel_id=?`, [1, channelId]);
|
||||
},
|
||||
clearChannelItemBlocked: async (guid, channelId) => {
|
||||
await db.current.executeSql(`UPDATE channel_${guid} set blocked=? where channel_id=?`, [0, channelId]);
|
||||
},
|
||||
setChannelItemDetail: async (guid, channelId, revision, detail) => {
|
||||
await db.current.executeSql(`UPDATE channel_${guid} set detail_revision=?, detail=? where channel_id=?`, [revision, encodeObject(detail), channelId]);
|
||||
},
|
||||
@ -207,7 +213,7 @@ export function useStoreContext() {
|
||||
};
|
||||
},
|
||||
getChannelItems: async (guid) => {
|
||||
const values = await getAppValues(db.current, `SELECT channel_id, read_revision, revision, sync_revision, detail_revision, topic_revision, detail, summary FROM channel_${guid}`, []);
|
||||
const values = await getAppValues(db.current, `SELECT channel_id, read_revision, revision, sync_revision, blocked, detail_revision, topic_revision, detail, summary FROM channel_${guid}`, []);
|
||||
return values.map(channel => ({
|
||||
channelId: channel.channel_id,
|
||||
revision: channel.revision,
|
||||
@ -215,6 +221,7 @@ export function useStoreContext() {
|
||||
detailRevision: channel.detail_revision,
|
||||
topicRevision: channel.topic_revision,
|
||||
syncRevision: channel.sync_revision,
|
||||
blocked: channel.blocked,
|
||||
detail: decodeObject(channel.detail),
|
||||
summary: decodeObject(channel.summary),
|
||||
}));
|
||||
|
@ -126,7 +126,7 @@ export function useChannels() {
|
||||
|
||||
const timestamp = item?.summary?.lastTopic?.created;
|
||||
|
||||
return { cardId: item.cardId, channelId: item.channelId, contacts, logo, subject, message, updated, revision: item.revision, timestamp };
|
||||
return { cardId: item.cardId, channelId: item.channelId, contacts, logo, subject, message, updated, revision: item.revision, timestamp, blocked: item.blocked === 1 };
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@ -141,6 +141,10 @@ export function useChannels() {
|
||||
const items = merged.map(setChannelEntry);
|
||||
|
||||
const filtered = items.filter(item => {
|
||||
if (item.blocked === true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!state.filter) {
|
||||
return true;
|
||||
}
|
||||
|
@ -28,18 +28,58 @@ export function DetailsBody({ channel, clearConversation }) {
|
||||
}
|
||||
}
|
||||
|
||||
const remove = async () => {
|
||||
try {
|
||||
await actions.remove();
|
||||
clearConversation();
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
Alert.alert(
|
||||
'Failed to Delete Topic',
|
||||
'Please try again.'
|
||||
)
|
||||
}
|
||||
const remove = () => {
|
||||
Alert.alert(
|
||||
"Removing Topic",
|
||||
"Confirm?",
|
||||
[
|
||||
{ text: "Cancel",
|
||||
onPress: () => {},
|
||||
},
|
||||
{ text: "Remove",
|
||||
onPress: async () => {
|
||||
try {
|
||||
await actions.remove();
|
||||
clearConversation();
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
Alert.alert(
|
||||
'Failed to Delete Topic',
|
||||
'Please try again.'
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
const block = () => {
|
||||
Alert.alert(
|
||||
"Blocking Topic",
|
||||
"Confirm?",
|
||||
[
|
||||
{ text: "Cancel",
|
||||
onPress: () => {},
|
||||
},
|
||||
{ text: "Block",
|
||||
onPress: async () => {
|
||||
try {
|
||||
await actions.block();
|
||||
clearConversation();
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
Alert.alert(
|
||||
'Failed to Block Topic',
|
||||
'Please try again.'
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@ -64,16 +104,19 @@ export function DetailsBody({ channel, clearConversation }) {
|
||||
<Text style={styles.buttonText}>Delete Topic</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{ !state.hostId && (
|
||||
<TouchableOpacity style={styles.button} onPress={actions.showEditMembers}>
|
||||
<Text style={styles.buttonText}>Edit Membership</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{ state.hostId && (
|
||||
<TouchableOpacity style={styles.button} onPress={remove}>
|
||||
<Text style={styles.buttonText}>Leave Topic</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
<TouchableOpacity style={styles.button} onPress={block}>
|
||||
<Text style={styles.buttonText}>Block Topic</Text>
|
||||
</TouchableOpacity>
|
||||
{ !state.hostId && (
|
||||
<TouchableOpacity style={styles.button} onPress={actions.showEditMembers}>
|
||||
<Text style={styles.buttonText}>Edit Membership</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<View style={styles.members}>
|
||||
|
@ -36,6 +36,8 @@ export const styles = StyleSheet.create({
|
||||
fontSize: 18,
|
||||
flexShrink: 1,
|
||||
minWidth: 0,
|
||||
color: Colors.text,
|
||||
paddingRight: 4,
|
||||
},
|
||||
created: {
|
||||
fontSize: 16,
|
||||
|
@ -58,6 +58,9 @@ export function useDetails() {
|
||||
remove: async () => {
|
||||
await conversation.actions.remove();
|
||||
},
|
||||
block: async() => {
|
||||
await conversation.actions.setBlocked();
|
||||
},
|
||||
};
|
||||
|
||||
return { state, actions };
|
||||
|
@ -1,6 +1,47 @@
|
||||
import { Text } from 'react-native';
|
||||
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() {
|
||||
return <Text>TOPICS</Text>
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,46 @@
|
||||
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,
|
||||
},
|
||||
});
|
@ -0,0 +1,122 @@
|
||||
import { useState, useEffect, useContext } from 'react';
|
||||
import { CardContext } from 'context/CardContext';
|
||||
import { ChannelContext } from 'context/ChannelContext';
|
||||
import { ProfileContext } from 'context/ProfileContext';
|
||||
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.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');
|
||||
}
|
||||
|
||||
let contacts = [];
|
||||
if (item.cardId) {
|
||||
contacts.push(card.state.cards.get(item.cardId));
|
||||
}
|
||||
if (item?.detail?.members) {
|
||||
const profileGuid = profile.state.profile.guid;
|
||||
item.detail.members.forEach(guid => {
|
||||
if (profileGuid !== guid) {
|
||||
const contact = getCard(guid);
|
||||
contacts.push(contact);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let subject;
|
||||
if (item?.detail?.data) {
|
||||
try {
|
||||
topic = JSON.parse(item?.detail?.data).subject;
|
||||
subject = topic;
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
if (!subject) {
|
||||
if (contacts.length) {
|
||||
let names = [];
|
||||
for (let contact of contacts) {
|
||||
if (contact?.profile?.name) {
|
||||
names.push(contact.profile.name);
|
||||
}
|
||||
else if (contact?.profile?.handle) {
|
||||
names.push(contact?.profile?.handle);
|
||||
}
|
||||
}
|
||||
subject = names.join(', ');
|
||||
}
|
||||
else {
|
||||
subject = "Notes";
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: `${item.cardId}:${item.channelId}`,
|
||||
cardId: item.cardId,
|
||||
channelId: item.channelId,
|
||||
name: subject,
|
||||
blocked: item.blocked,
|
||||
created: timestamp,
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let merged = [];
|
||||
card.state.cards.forEach((card, cardId, map) => {
|
||||
merged.push(...Array.from(card.channels.values()));
|
||||
});
|
||||
merged.push(...Array.from(channel.state.channels.values()));
|
||||
const items = merged.map(setChannelItem);
|
||||
const filtered = items.filter(item => item.blocked);
|
||||
updateState({ channels: filtered });
|
||||
}, [card, channel]);
|
||||
|
||||
const actions = {
|
||||
unblock: async (cardId, channelId) => {
|
||||
if (cardId) {
|
||||
await card.actions.clearChannelBlocked(cardId, channelId);
|
||||
}
|
||||
else {
|
||||
await channel.actions.clearBlocked(channelId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return { state, actions };
|
||||
}
|
||||
|
@ -69,9 +69,9 @@ export function useProfile() {
|
||||
app.actions.logout();
|
||||
navigate('/');
|
||||
},
|
||||
setVisible: async (visible) => {
|
||||
updateState({ visible });
|
||||
await account.actions.setSearchable(visible);
|
||||
setVisible: async (searchable) => {
|
||||
updateState({ searchable });
|
||||
await account.actions.setSearchable(searchable);
|
||||
},
|
||||
setProfileImage: async (data) => {
|
||||
await profile.actions.setProfileImage(data);
|
||||
|
Loading…
Reference in New Issue
Block a user