mirror of
https://github.com/KoalaSat/nostros.git
synced 2024-09-29 06:30:47 +00:00
Better login process
This commit is contained in:
parent
7586c32306
commit
5738c2fbcb
@ -126,13 +126,13 @@ export const NoteCard: React.FC<NoteCardProps> = ({
|
|||||||
}, [database])
|
}, [database])
|
||||||
|
|
||||||
const publishReaction: (positive: boolean) => void = (positive) => {
|
const publishReaction: (positive: boolean) => void = (positive) => {
|
||||||
if (note && publicKey) {
|
if (note?.id && publicKey) {
|
||||||
const event: Event = {
|
const event: Event = {
|
||||||
content: positive ? '+' : '-',
|
content: positive ? '+' : '-',
|
||||||
created_at: getUnixTime(new Date()),
|
created_at: getUnixTime(new Date()),
|
||||||
kind: Kind.Reaction,
|
kind: Kind.Reaction,
|
||||||
pubkey: publicKey,
|
pubkey: publicKey,
|
||||||
tags: [...(note.tags ?? []), ['e', note.id], ['p', note.pubkey]],
|
tags: [...note.tags, ['e', note.id], ['p', note.pubkey]],
|
||||||
}
|
}
|
||||||
relayPool?.sendEvent(event)
|
relayPool?.sendEvent(event)
|
||||||
}
|
}
|
||||||
|
296
frontend/Components/ProfileActions/index.tsx
Normal file
296
frontend/Components/ProfileActions/index.tsx
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
import { t } from 'i18next'
|
||||||
|
import * as React from 'react'
|
||||||
|
import { StyleSheet, View, ListRenderItem, Switch, FlatList } from 'react-native'
|
||||||
|
import { IconButton, List, Snackbar, Text, useTheme } from 'react-native-paper'
|
||||||
|
import { AppContext } from '../../Contexts/AppContext'
|
||||||
|
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||||
|
import { UserContext } from '../../Contexts/UserContext'
|
||||||
|
import {
|
||||||
|
getUser,
|
||||||
|
updateUserBlock,
|
||||||
|
updateUserContact,
|
||||||
|
User,
|
||||||
|
} from '../../Functions/DatabaseFunctions/Users'
|
||||||
|
import { populatePets, username } from '../../Functions/RelayFunctions/Users'
|
||||||
|
import LnPayment from '../LnPayment'
|
||||||
|
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
|
||||||
|
import { navigate } from '../../lib/Navigation'
|
||||||
|
import RBSheet from 'react-native-raw-bottom-sheet'
|
||||||
|
import { getUserRelays, NoteRelay } from '../../Functions/DatabaseFunctions/NotesRelays'
|
||||||
|
import { relayToColor } from '../../Functions/NativeFunctions'
|
||||||
|
import { Relay } from '../../Functions/DatabaseFunctions/Relays'
|
||||||
|
import ProfileShare from '../ProfileShare'
|
||||||
|
|
||||||
|
interface ProfileActionsProps {
|
||||||
|
user: User
|
||||||
|
setUser: (user: User) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ProfileActions: React.FC<ProfileActionsProps> = ({ user, setUser }) => {
|
||||||
|
const theme = useTheme()
|
||||||
|
const { database } = React.useContext(AppContext)
|
||||||
|
const { publicKey } = React.useContext(UserContext)
|
||||||
|
const { relayPool, updateRelayItem } = React.useContext(RelayPoolContext)
|
||||||
|
const [isContact, setIsContact] = React.useState<boolean>()
|
||||||
|
const [showNotification, setShowNotification] = React.useState<undefined | string>()
|
||||||
|
const [showNotificationRelay, setShowNotificationRelay] = React.useState<undefined | string>()
|
||||||
|
const bottomSheetRelaysRef = React.useRef<RBSheet>(null)
|
||||||
|
const bottomSheetShareRef = React.useRef<RBSheet>(null)
|
||||||
|
const [userRelays, setUserRelays] = React.useState<NoteRelay[]>([])
|
||||||
|
const [openLn, setOpenLn] = React.useState<boolean>(false)
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
loadUser()
|
||||||
|
loadRelays()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const loadRelays: () => void = () => {
|
||||||
|
if (database) {
|
||||||
|
getUserRelays(database, user.id).then((results) => {
|
||||||
|
if (results) {
|
||||||
|
setUserRelays(results)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadUser: () => void = () => {
|
||||||
|
if (database) {
|
||||||
|
getUser(user.id, database).then((result) => {
|
||||||
|
if (result) {
|
||||||
|
setUser(result)
|
||||||
|
} else if (user.id === publicKey) {
|
||||||
|
setUser({
|
||||||
|
id: publicKey,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onChangeBlockUser: () => void = () => {
|
||||||
|
if (database && user?.blocked !== undefined) {
|
||||||
|
updateUserBlock(user.id, database, !user?.blocked).then(() => {
|
||||||
|
loadUser()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeContact: () => void = () => {
|
||||||
|
if (relayPool && database && publicKey) {
|
||||||
|
updateUserContact(user.id, database, false).then(() => {
|
||||||
|
populatePets(relayPool, database, publicKey)
|
||||||
|
setIsContact(false)
|
||||||
|
setShowNotification('contactRemoved')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const addContact: () => void = () => {
|
||||||
|
if (relayPool && database && publicKey) {
|
||||||
|
updateUserContact(user.id, database, true).then(() => {
|
||||||
|
populatePets(relayPool, database, publicKey)
|
||||||
|
setIsContact(true)
|
||||||
|
setShowNotification('contactAdded')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeRelay: (relay: Relay) => void = (relay) => {
|
||||||
|
relay.active = 1
|
||||||
|
updateRelayItem(relay).then(() => {
|
||||||
|
setShowNotificationRelay('active')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const desactiveRelay: (relay: Relay) => void = (relay) => {
|
||||||
|
relay.active = 0
|
||||||
|
relay.global_feed = 0
|
||||||
|
updateRelayItem(relay).then(() => {
|
||||||
|
setShowNotificationRelay('desactive')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const bottomSheetStyles = React.useMemo(() => {
|
||||||
|
return {
|
||||||
|
container: {
|
||||||
|
backgroundColor: theme.colors.background,
|
||||||
|
paddingTop: 16,
|
||||||
|
paddingBottom: 32,
|
||||||
|
paddingLeft: 16,
|
||||||
|
borderTopRightRadius: 28,
|
||||||
|
borderTopLeftRadius: 28,
|
||||||
|
height: 'auto',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const renderRelayItem: ListRenderItem<NoteRelay> = ({ index, item }) => {
|
||||||
|
return (
|
||||||
|
<List.Item
|
||||||
|
key={index}
|
||||||
|
title={item.url}
|
||||||
|
left={() => (
|
||||||
|
<MaterialCommunityIcons
|
||||||
|
style={styles.relayColor}
|
||||||
|
name='circle'
|
||||||
|
color={relayToColor(item.url)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
right={() => (
|
||||||
|
<Switch
|
||||||
|
style={styles.switch}
|
||||||
|
value={item.active !== undefined && item.active > 0}
|
||||||
|
onValueChange={() => (item.active ? desactiveRelay(item) : activeRelay(item))}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<View style={styles.mainLayout}>
|
||||||
|
<View style={styles.actionButton}>
|
||||||
|
<IconButton
|
||||||
|
icon={isContact ? 'account-multiple-remove-outline' : 'account-multiple-plus-outline'}
|
||||||
|
size={28}
|
||||||
|
onPress={() => {
|
||||||
|
isContact ? removeContact() : addContact()
|
||||||
|
}}
|
||||||
|
disabled={user.id === publicKey}
|
||||||
|
/>
|
||||||
|
<Text>{isContact ? t('profilePage.unfollow') : t('profilePage.follow')}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={styles.actionButton}>
|
||||||
|
<IconButton
|
||||||
|
icon='message-plus-outline'
|
||||||
|
size={28}
|
||||||
|
onPress={() => {
|
||||||
|
navigate('Conversation', {
|
||||||
|
pubKey: user.id,
|
||||||
|
title: username(user),
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Text>{t('profilePage.message')}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={styles.actionButton}>
|
||||||
|
<IconButton
|
||||||
|
icon='lightning-bolt'
|
||||||
|
size={28}
|
||||||
|
onPress={() => setOpenLn(true)}
|
||||||
|
disabled={!user?.lnurl}
|
||||||
|
iconColor='#F5D112'
|
||||||
|
/>
|
||||||
|
<Text>{t('profilePage.invoice')}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={styles.mainLayout}>
|
||||||
|
<View style={styles.actionButton}>
|
||||||
|
<IconButton
|
||||||
|
icon={user?.blocked && user?.blocked > 0 ? 'account-cancel' : 'account-cancel-outline'}
|
||||||
|
size={28}
|
||||||
|
onPress={onChangeBlockUser}
|
||||||
|
/>
|
||||||
|
<Text>
|
||||||
|
{t(user?.blocked && user?.blocked > 0 ? 'profileCard.unblock' : 'profileCard.block')}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View style={styles.actionButton}>
|
||||||
|
<IconButton
|
||||||
|
icon='share-variant-outline'
|
||||||
|
size={28}
|
||||||
|
onPress={() => bottomSheetShareRef.current?.open()}
|
||||||
|
/>
|
||||||
|
<Text>{t('profileCard.share')}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={styles.actionButton}>
|
||||||
|
<IconButton
|
||||||
|
icon='chart-timeline-variant'
|
||||||
|
size={28}
|
||||||
|
onPress={() => bottomSheetRelaysRef.current?.open()}
|
||||||
|
/>
|
||||||
|
<Text>{t('profilePage.relaysTitle')}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<RBSheet ref={bottomSheetRelaysRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
|
||||||
|
<View>
|
||||||
|
<Text variant='titleLarge'>{t('profilePage.relaysTitle')}</Text>
|
||||||
|
<Text variant='bodyMedium'>
|
||||||
|
{t('profilePage.relaysDescription', { username: username(user) })}
|
||||||
|
</Text>
|
||||||
|
<List.Item
|
||||||
|
title={t('relaysPage.relayName')}
|
||||||
|
right={() => (
|
||||||
|
<>
|
||||||
|
<Text style={styles.listHeader}>{t('relaysPage.active')}</Text>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FlatList
|
||||||
|
showsVerticalScrollIndicator={false}
|
||||||
|
data={userRelays}
|
||||||
|
renderItem={renderRelayItem}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
{showNotificationRelay && (
|
||||||
|
<Snackbar
|
||||||
|
style={styles.snackbar}
|
||||||
|
visible={showNotificationRelay !== undefined}
|
||||||
|
duration={Snackbar.DURATION_SHORT}
|
||||||
|
onIconPress={() => setShowNotificationRelay(undefined)}
|
||||||
|
onDismiss={() => setShowNotificationRelay(undefined)}
|
||||||
|
>
|
||||||
|
{t(`profilePage.${showNotificationRelay}`)}
|
||||||
|
</Snackbar>
|
||||||
|
)}
|
||||||
|
</RBSheet>
|
||||||
|
<RBSheet ref={bottomSheetShareRef} closeOnDragDown={true} customStyles={bottomSheetStyles}>
|
||||||
|
<ProfileShare user={user} />
|
||||||
|
</RBSheet>
|
||||||
|
<LnPayment setOpen={setOpenLn} open={openLn} user={user} />
|
||||||
|
{showNotification && (
|
||||||
|
<Snackbar
|
||||||
|
style={styles.snackbar}
|
||||||
|
visible={showNotification !== undefined}
|
||||||
|
duration={Snackbar.DURATION_SHORT}
|
||||||
|
onIconPress={() => setShowNotification(undefined)}
|
||||||
|
onDismiss={() => setShowNotification(undefined)}
|
||||||
|
>
|
||||||
|
{t(`profilePage.${showNotification}`)}
|
||||||
|
</Snackbar>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
relayColor: {
|
||||||
|
paddingTop: 9,
|
||||||
|
},
|
||||||
|
mainLayout: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
},
|
||||||
|
actionButton: {
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
snackbar: {
|
||||||
|
marginLeft: 16,
|
||||||
|
bottom: 16,
|
||||||
|
},
|
||||||
|
switch: {
|
||||||
|
marginLeft: 32,
|
||||||
|
},
|
||||||
|
listHeader: {
|
||||||
|
paddingRight: 5,
|
||||||
|
paddingLeft: 16,
|
||||||
|
textAlign: 'center',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export default ProfileActions
|
@ -1,23 +1,17 @@
|
|||||||
import { t } from 'i18next'
|
import { t } from 'i18next'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { StyleSheet, View } from 'react-native'
|
import { StyleSheet, View } from 'react-native'
|
||||||
import { Card, IconButton, Snackbar, Text, useTheme } from 'react-native-paper'
|
import { Divider, Snackbar, TouchableRipple, useTheme } from 'react-native-paper'
|
||||||
import { AppContext } from '../../Contexts/AppContext'
|
import { AppContext } from '../../Contexts/AppContext'
|
||||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
import { getUser, User } from '../../Functions/DatabaseFunctions/Users'
|
||||||
import { UserContext } from '../../Contexts/UserContext'
|
import { usernamePubKey } from '../../Functions/RelayFunctions/Users'
|
||||||
import {
|
|
||||||
getUser,
|
|
||||||
updateUserBlock,
|
|
||||||
updateUserContact,
|
|
||||||
User,
|
|
||||||
} from '../../Functions/DatabaseFunctions/Users'
|
|
||||||
import { populatePets, usernamePubKey } from '../../Functions/RelayFunctions/Users'
|
|
||||||
import LnPayment from '../LnPayment'
|
import LnPayment from '../LnPayment'
|
||||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
|
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
|
||||||
import { navigate, push } from '../../lib/Navigation'
|
import { push } from '../../lib/Navigation'
|
||||||
import RBSheet from 'react-native-raw-bottom-sheet'
|
import RBSheet from 'react-native-raw-bottom-sheet'
|
||||||
import { getNpub } from '../../lib/nostr/Nip19'
|
import { getNpub } from '../../lib/nostr/Nip19'
|
||||||
import ProfileData from '../ProfileData'
|
import ProfileData from '../ProfileData'
|
||||||
|
import ProfileActions from '../ProfileActions'
|
||||||
|
|
||||||
interface ProfileCardProps {
|
interface ProfileCardProps {
|
||||||
bottomSheetRef: React.RefObject<RBSheet>
|
bottomSheetRef: React.RefObject<RBSheet>
|
||||||
@ -27,13 +21,9 @@ interface ProfileCardProps {
|
|||||||
export const ProfileCard: React.FC<ProfileCardProps> = ({ bottomSheetRef, showImages = true }) => {
|
export const ProfileCard: React.FC<ProfileCardProps> = ({ bottomSheetRef, showImages = true }) => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const { displayUserDrawer } = React.useContext(AppContext)
|
const { displayUserDrawer } = React.useContext(AppContext)
|
||||||
const { database, setDisplayUserShareDrawer } = React.useContext(AppContext)
|
const { database } = React.useContext(AppContext)
|
||||||
const { publicKey } = React.useContext(UserContext)
|
|
||||||
const { relayPool } = React.useContext(RelayPoolContext)
|
|
||||||
const [user, setUser] = React.useState<User>()
|
const [user, setUser] = React.useState<User>()
|
||||||
const [blocked, setBlocked] = React.useState<number>()
|
|
||||||
const [openLn, setOpenLn] = React.useState<boolean>(false)
|
const [openLn, setOpenLn] = React.useState<boolean>(false)
|
||||||
const [isContact, setIsContact] = React.useState<boolean>()
|
|
||||||
const [showNotification, setShowNotification] = React.useState<undefined | string>()
|
const [showNotification, setShowNotification] = React.useState<undefined | string>()
|
||||||
const nPub = React.useMemo(() => getNpub(displayUserDrawer), [displayUserDrawer])
|
const nPub = React.useMemo(() => getNpub(displayUserDrawer), [displayUserDrawer])
|
||||||
const username = React.useMemo(() => usernamePubKey(user?.name ?? '', nPub), [nPub, user])
|
const username = React.useMemo(() => usernamePubKey(user?.name ?? '', nPub), [nPub, user])
|
||||||
@ -42,45 +32,13 @@ export const ProfileCard: React.FC<ProfileCardProps> = ({ bottomSheetRef, showIm
|
|||||||
loadUser()
|
loadUser()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const onChangeBlockUser: () => void = () => {
|
|
||||||
if (database && blocked !== undefined && displayUserDrawer) {
|
|
||||||
updateUserBlock(displayUserDrawer, database, !blocked).then(() => {
|
|
||||||
setBlocked(blocked === 0 ? 1 : 0)
|
|
||||||
loadUser()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const removeContact: () => void = () => {
|
|
||||||
if (relayPool && database && publicKey && displayUserDrawer) {
|
|
||||||
updateUserContact(displayUserDrawer, database, false).then(() => {
|
|
||||||
populatePets(relayPool, database, publicKey)
|
|
||||||
setIsContact(false)
|
|
||||||
setShowNotification('contactRemoved')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const addContact: () => void = () => {
|
|
||||||
if (relayPool && database && publicKey && displayUserDrawer) {
|
|
||||||
updateUserContact(displayUserDrawer, database, true).then(() => {
|
|
||||||
populatePets(relayPool, database, publicKey)
|
|
||||||
setIsContact(true)
|
|
||||||
setShowNotification('contactAdded')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadUser: () => void = () => {
|
const loadUser: () => void = () => {
|
||||||
if (database && displayUserDrawer) {
|
if (database && displayUserDrawer) {
|
||||||
getUser(displayUserDrawer, database).then((result) => {
|
getUser(displayUserDrawer, database).then((result) => {
|
||||||
if (result) {
|
if (result) {
|
||||||
setUser(result)
|
setUser(result)
|
||||||
setBlocked(result.blocked)
|
|
||||||
setIsContact(result?.contact)
|
|
||||||
} else {
|
} else {
|
||||||
setUser({ id: displayUserDrawer })
|
setUser({ id: displayUserDrawer })
|
||||||
setBlocked(0)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -93,9 +51,10 @@ export const ProfileCard: React.FC<ProfileCardProps> = ({ bottomSheetRef, showIm
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
<Card onPress={goToProfile}>
|
<Divider />
|
||||||
<Card.Content style={styles.card}>
|
<TouchableRipple onPress={goToProfile}>
|
||||||
<View style={styles.cardUser}>
|
<View style={styles.cardUser}>
|
||||||
|
<View>
|
||||||
<View style={styles.cardUserMain}>
|
<View style={styles.cardUserMain}>
|
||||||
<ProfileData
|
<ProfileData
|
||||||
username={user?.name}
|
username={user?.name}
|
||||||
@ -107,81 +66,18 @@ export const ProfileCard: React.FC<ProfileCardProps> = ({ bottomSheetRef, showIm
|
|||||||
avatarSize={54}
|
avatarSize={54}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
{user?.about && (
|
|
||||||
<View style={styles.about}>
|
|
||||||
<Text>
|
|
||||||
{`${user?.about ? user?.about?.slice(0, 75) : ''}${
|
|
||||||
user?.about && user?.about?.length > 75 ? ' ...' : ''
|
|
||||||
}`}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
<View>
|
<View style={styles.arrow}>
|
||||||
<MaterialCommunityIcons
|
<MaterialCommunityIcons
|
||||||
name='menu-right'
|
name='menu-right'
|
||||||
size={25}
|
size={25}
|
||||||
color={theme.colors.onPrimaryContainer}
|
color={theme.colors.onPrimaryContainer}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</Card.Content>
|
|
||||||
</Card>
|
|
||||||
<View style={styles.mainLayout}>
|
|
||||||
{displayUserDrawer !== publicKey && (
|
|
||||||
<View style={styles.actionButton}>
|
|
||||||
<IconButton
|
|
||||||
icon={isContact ? 'account-multiple-remove-outline' : 'account-multiple-plus-outline'}
|
|
||||||
size={28}
|
|
||||||
onPress={() => {
|
|
||||||
isContact ? removeContact() : addContact()
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Text>{isContact ? t('profileCard.unfollow') : t('profileCard.follow')}</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
<View style={styles.actionButton}>
|
|
||||||
<IconButton
|
|
||||||
icon='message-plus-outline'
|
|
||||||
size={28}
|
|
||||||
onPress={() => {
|
|
||||||
navigate('Conversation', { pubKey: displayUserDrawer, title: username })
|
|
||||||
bottomSheetRef.current?.close()
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Text>{t('profileCard.message')}</Text>
|
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.actionButton}>
|
</TouchableRipple>
|
||||||
<IconButton
|
<Divider />
|
||||||
icon='share-variant-outline'
|
{user && <ProfileActions user={user} setUser={setUser} />}
|
||||||
size={28}
|
|
||||||
onPress={() => {
|
|
||||||
setDisplayUserShareDrawer(user?.id)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Text>{t('profileCard.share')}</Text>
|
|
||||||
</View>
|
|
||||||
{user?.lnurl && (
|
|
||||||
<View style={styles.actionButton}>
|
|
||||||
<>
|
|
||||||
<IconButton
|
|
||||||
icon='lightning-bolt'
|
|
||||||
size={28}
|
|
||||||
onPress={() => setOpenLn(true)}
|
|
||||||
iconColor='#F5D112'
|
|
||||||
/>
|
|
||||||
<Text>{t('profileCard.invoice')}</Text>
|
|
||||||
</>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
<View style={styles.actionButton}>
|
|
||||||
<IconButton
|
|
||||||
icon={blocked && blocked > 0 ? 'account-cancel' : 'account-cancel-outline'}
|
|
||||||
size={28}
|
|
||||||
onPress={onChangeBlockUser}
|
|
||||||
/>
|
|
||||||
<Text>{t(blocked && blocked > 0 ? 'profileCard.unblock' : 'profileCard.block')}</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
{showNotification && (
|
{showNotification && (
|
||||||
<Snackbar
|
<Snackbar
|
||||||
style={styles.snackbar}
|
style={styles.snackbar}
|
||||||
@ -229,6 +125,11 @@ const styles = StyleSheet.create({
|
|||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
|
cardUser: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
paddingTop: 16,
|
||||||
|
},
|
||||||
card: {
|
card: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@ -258,13 +159,18 @@ const styles = StyleSheet.create({
|
|||||||
list: {
|
list: {
|
||||||
padding: 16,
|
padding: 16,
|
||||||
},
|
},
|
||||||
cardUser: {
|
|
||||||
flex: 1,
|
|
||||||
},
|
|
||||||
verifyIcon: {
|
verifyIcon: {
|
||||||
paddingTop: 6,
|
paddingTop: 6,
|
||||||
paddingLeft: 5,
|
paddingLeft: 5,
|
||||||
},
|
},
|
||||||
|
dividerTop: {
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
arrow: {
|
||||||
|
alignContent: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
marginTop: -16,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export default ProfileCard
|
export default ProfileCard
|
||||||
|
@ -3,37 +3,21 @@ import * as React from 'react'
|
|||||||
import { StyleSheet, View } from 'react-native'
|
import { StyleSheet, View } from 'react-native'
|
||||||
import Clipboard from '@react-native-clipboard/clipboard'
|
import Clipboard from '@react-native-clipboard/clipboard'
|
||||||
import { IconButton, Snackbar, Text, TouchableRipple } from 'react-native-paper'
|
import { IconButton, Snackbar, Text, TouchableRipple } from 'react-native-paper'
|
||||||
import { AppContext } from '../../Contexts/AppContext'
|
import { User } from '../../Functions/DatabaseFunctions/Users'
|
||||||
import { getUser, User } from '../../Functions/DatabaseFunctions/Users'
|
|
||||||
import Share from 'react-native-share'
|
import Share from 'react-native-share'
|
||||||
import RBSheet from 'react-native-raw-bottom-sheet'
|
import RBSheet from 'react-native-raw-bottom-sheet'
|
||||||
import { getNpub } from '../../lib/nostr/Nip19'
|
import { getNpub } from '../../lib/nostr/Nip19'
|
||||||
import QRCode from 'react-native-qrcode-svg'
|
import QRCode from 'react-native-qrcode-svg'
|
||||||
|
|
||||||
export const ProfileShare: React.FC = () => {
|
interface ProfileShareProps {
|
||||||
const { displayUserShareDrawer } = React.useContext(AppContext)
|
user: User
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ProfileShare: React.FC<ProfileShareProps> = ({ user }) => {
|
||||||
const bottomSheetShareRef = React.useRef<RBSheet>(null)
|
const bottomSheetShareRef = React.useRef<RBSheet>(null)
|
||||||
const { database } = React.useContext(AppContext)
|
|
||||||
const [user, setUser] = React.useState<User>()
|
|
||||||
const [qrCode, setQrCode] = React.useState<any>()
|
const [qrCode, setQrCode] = React.useState<any>()
|
||||||
const [showNotification, setShowNotification] = React.useState<undefined | string>()
|
const [showNotification, setShowNotification] = React.useState<undefined | string>()
|
||||||
const nPub = React.useMemo(() => getNpub(displayUserShareDrawer), [displayUserShareDrawer])
|
const nPub = React.useMemo(() => getNpub(user.id), [user])
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
loadUser()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const loadUser: () => void = () => {
|
|
||||||
if (database && displayUserShareDrawer) {
|
|
||||||
getUser(displayUserShareDrawer, database).then((result) => {
|
|
||||||
if (result) {
|
|
||||||
setUser(result)
|
|
||||||
} else {
|
|
||||||
setUser({ id: displayUserShareDrawer })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.mainLayout}>
|
<View style={styles.mainLayout}>
|
||||||
@ -73,20 +57,19 @@ export const ProfileShare: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
<Text>{t('profileShare.copyNPub')}</Text>
|
<Text>{t('profileShare.copyNPub')}</Text>
|
||||||
</View>
|
</View>
|
||||||
{user?.nip05 && (
|
<View style={styles.shareActionButton}>
|
||||||
<View style={styles.shareActionButton}>
|
<IconButton
|
||||||
<IconButton
|
icon='check-decagram-outline'
|
||||||
icon='check-decagram-outline'
|
size={28}
|
||||||
size={28}
|
onPress={() => {
|
||||||
onPress={() => {
|
setShowNotification('nip05Copied')
|
||||||
setShowNotification('copyNip05')
|
Clipboard.setString(user?.nip05 ?? '')
|
||||||
Clipboard.setString(user?.nip05 ?? '')
|
bottomSheetShareRef.current?.close()
|
||||||
bottomSheetShareRef.current?.close()
|
}}
|
||||||
}}
|
disabled={!user.nip05}
|
||||||
/>
|
/>
|
||||||
<Text>{t('profileShare.copyNip05')}</Text>
|
<Text>{t('profileShare.copyNip05')}</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
|
||||||
{showNotification && (
|
{showNotification && (
|
||||||
<Snackbar
|
<Snackbar
|
||||||
style={styles.snackbar}
|
style={styles.snackbar}
|
||||||
|
@ -35,8 +35,6 @@ export interface AppContextProps {
|
|||||||
checkClipboard: () => void
|
checkClipboard: () => void
|
||||||
displayUserDrawer?: string
|
displayUserDrawer?: string
|
||||||
setDisplayUserDrawer: (displayUserDrawer: string | undefined) => void
|
setDisplayUserDrawer: (displayUserDrawer: string | undefined) => void
|
||||||
displayUserShareDrawer?: string
|
|
||||||
setDisplayUserShareDrawer: (displayUserShareDrawer: string | undefined) => void
|
|
||||||
refreshBottomBarAt?: number
|
refreshBottomBarAt?: number
|
||||||
setRefreshBottomBarAt: (refreshBottomBarAt: number) => void
|
setRefreshBottomBarAt: (refreshBottomBarAt: number) => void
|
||||||
pushedTab?: string
|
pushedTab?: string
|
||||||
@ -78,7 +76,6 @@ export const initialAppContext: AppContextProps = {
|
|||||||
getSatoshiSymbol: () => <></>,
|
getSatoshiSymbol: () => <></>,
|
||||||
setClipboardNip21: () => {},
|
setClipboardNip21: () => {},
|
||||||
setDisplayUserDrawer: () => {},
|
setDisplayUserDrawer: () => {},
|
||||||
setDisplayUserShareDrawer: () => {},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AppContextProvider = ({ children }: AppContextProviderProps): JSX.Element => {
|
export const AppContextProvider = ({ children }: AppContextProviderProps): JSX.Element => {
|
||||||
@ -103,7 +100,6 @@ export const AppContextProvider = ({ children }: AppContextProviderProps): JSX.E
|
|||||||
const [clipboardLoads, setClipboardLoads] = React.useState<string[]>([])
|
const [clipboardLoads, setClipboardLoads] = React.useState<string[]>([])
|
||||||
const [clipboardNip21, setClipboardNip21] = React.useState<string>()
|
const [clipboardNip21, setClipboardNip21] = React.useState<string>()
|
||||||
const [displayUserDrawer, setDisplayUserDrawer] = React.useState<string>()
|
const [displayUserDrawer, setDisplayUserDrawer] = React.useState<string>()
|
||||||
const [displayUserShareDrawer, setDisplayUserShareDrawer] = React.useState<string>()
|
|
||||||
const [pushedTab, setPushedTab] = useState<string>()
|
const [pushedTab, setPushedTab] = useState<string>()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -229,8 +225,6 @@ export const AppContextProvider = ({ children }: AppContextProviderProps): JSX.E
|
|||||||
satoshi,
|
satoshi,
|
||||||
setSatoshi,
|
setSatoshi,
|
||||||
getSatoshiSymbol,
|
getSatoshiSymbol,
|
||||||
setDisplayUserShareDrawer,
|
|
||||||
displayUserShareDrawer,
|
|
||||||
refreshBottomBarAt,
|
refreshBottomBarAt,
|
||||||
setRefreshBottomBarAt,
|
setRefreshBottomBarAt,
|
||||||
pushedTab,
|
pushedTab,
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import React, { useContext, useEffect, useMemo, useState } from 'react'
|
import React, { useContext, useEffect, useMemo, useState } from 'react'
|
||||||
import RelayPool from '../lib/nostr/RelayPool/intex'
|
import RelayPool, { fallbackRelays } from '../lib/nostr/RelayPool/intex'
|
||||||
import { AppContext } from './AppContext'
|
import { AppContext } from './AppContext'
|
||||||
import { DeviceEventEmitter } from 'react-native'
|
import { DeviceEventEmitter } from 'react-native'
|
||||||
import debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
import { getRelays, Relay } from '../Functions/DatabaseFunctions/Relays'
|
import { getActiveRelays, getRelays, Relay } from '../Functions/DatabaseFunctions/Relays'
|
||||||
import { UserContext } from './UserContext'
|
import { UserContext } from './UserContext'
|
||||||
|
import { randomInt } from '../Functions/NativeFunctions'
|
||||||
|
|
||||||
export interface RelayPoolContextProps {
|
export interface RelayPoolContextProps {
|
||||||
relayPoolReady: boolean
|
relayPoolReady: boolean
|
||||||
@ -69,15 +70,25 @@ export const RelayPoolContextProvider = ({
|
|||||||
[setLastConfirmationId],
|
[setLastConfirmationId],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const createRandomRelays: () => Promise<void> = async () => {
|
||||||
|
const randomrelays: string[] = []
|
||||||
|
while (randomrelays.length < 5) {
|
||||||
|
const index = randomInt(0, fallbackRelays.length - 1)
|
||||||
|
const url = fallbackRelays[index]
|
||||||
|
if (!randomrelays.includes(url)) {
|
||||||
|
randomrelays.push(fallbackRelays[index])
|
||||||
|
await addRelayItem({ url })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const loadRelayPool: () => void = async () => {
|
const loadRelayPool: () => void = async () => {
|
||||||
if (database && publicKey) {
|
if (database && publicKey) {
|
||||||
DeviceEventEmitter.addListener('WebsocketEvent', debouncedEventIdHandler)
|
|
||||||
DeviceEventEmitter.addListener('WebsocketConfirmation', debouncedConfirmationHandler)
|
|
||||||
const initRelayPool = new RelayPool(privateKey)
|
const initRelayPool = new RelayPool(privateKey)
|
||||||
await initRelayPool.resilientMode(database, publicKey)
|
initRelayPool.connect(publicKey, () => {
|
||||||
initRelayPool.connect(publicKey, () => setRelayPoolReady(true))
|
initRelayPool.resilientMode(database, publicKey)
|
||||||
setRelayPool(initRelayPool)
|
setRelayPool(initRelayPool)
|
||||||
loadRelays()
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,10 +148,23 @@ export const RelayPoolContextProvider = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (publicKey && publicKey !== '') {
|
if (publicKey && publicKey !== '') {
|
||||||
|
DeviceEventEmitter.addListener('WebsocketEvent', debouncedEventIdHandler)
|
||||||
|
DeviceEventEmitter.addListener('WebsocketConfirmation', debouncedConfirmationHandler)
|
||||||
loadRelayPool()
|
loadRelayPool()
|
||||||
}
|
}
|
||||||
}, [publicKey])
|
}, [publicKey])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (database && relayPool) {
|
||||||
|
getActiveRelays(database).then((results) => {
|
||||||
|
if (results.length < 1) {
|
||||||
|
createRandomRelays()
|
||||||
|
}
|
||||||
|
loadRelays().then(() => setRelayPoolReady(true))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [relayPool])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RelayPoolContext.Provider
|
<RelayPoolContext.Provider
|
||||||
value={{
|
value={{
|
||||||
|
@ -53,7 +53,7 @@ export const initialUserContext: UserContextProps = {
|
|||||||
|
|
||||||
export const UserContextProvider = ({ children }: UserContextProviderProps): JSX.Element => {
|
export const UserContextProvider = ({ children }: UserContextProviderProps): JSX.Element => {
|
||||||
const { database, loadingDb, init } = useContext(AppContext)
|
const { database, loadingDb, init } = useContext(AppContext)
|
||||||
const { relayPool } = useContext(RelayPoolContext)
|
const { relayPool, relayPoolReady } = useContext(RelayPoolContext)
|
||||||
const [userState, setUserState] = useState<'loading' | 'access' | 'ready'>('loading')
|
const [userState, setUserState] = useState<'loading' | 'access' | 'ready'>('loading')
|
||||||
const [publicKey, setPublicKey] = useState<string>()
|
const [publicKey, setPublicKey] = useState<string>()
|
||||||
const [nPub, setNpub] = useState<string>()
|
const [nPub, setNpub] = useState<string>()
|
||||||
@ -123,10 +123,10 @@ export const UserContextProvider = ({ children }: UserContextProviderProps): JSX
|
|||||||
}, [publicKey])
|
}, [publicKey])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (userState === 'ready' && publicKey) {
|
if (userState === 'ready' && publicKey && relayPoolReady) {
|
||||||
navigate('Feed')
|
navigate('Feed')
|
||||||
}
|
}
|
||||||
}, [userState, publicKey])
|
}, [userState, publicKey, relayPoolReady])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!loadingDb) {
|
if (!loadingDb) {
|
||||||
|
@ -1,10 +1,34 @@
|
|||||||
import { QuickSQLiteConnection } from 'react-native-quick-sqlite'
|
import { QuickSQLiteConnection } from 'react-native-quick-sqlite'
|
||||||
|
import { getItems } from '..'
|
||||||
|
import { Relay } from '../Relays'
|
||||||
|
|
||||||
export interface NoteRelay {
|
export interface NoteRelay extends Relay {
|
||||||
relay_url: string
|
relay_url: string
|
||||||
pubkey: string
|
pubkey: string
|
||||||
note_id: number
|
note_id: number
|
||||||
}
|
}
|
||||||
|
const databaseToEntity: (object: object) => NoteRelay = (object) => {
|
||||||
|
return object as NoteRelay
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getUserRelays: (
|
||||||
|
db: QuickSQLiteConnection,
|
||||||
|
pubKey: string,
|
||||||
|
) => Promise<NoteRelay[]> = async (db, pubKey) => {
|
||||||
|
const query = `
|
||||||
|
SELECT * FROM nostros_notes_relays LEFT JOIN
|
||||||
|
nostros_relays ON nostros_relays.url = nostros_notes_relays.relay_url
|
||||||
|
WHERE pubkey = ? GROUP BY relay_url
|
||||||
|
`
|
||||||
|
const resultSet = db.execute(query, [pubKey])
|
||||||
|
if (resultSet.rows && resultSet.rows.length > 0) {
|
||||||
|
const items: object[] = getItems(resultSet)
|
||||||
|
const users: NoteRelay[] = items.map((object) => databaseToEntity(object))
|
||||||
|
return users
|
||||||
|
} else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const getNoteRelaysUsage: (
|
export const getNoteRelaysUsage: (
|
||||||
db: QuickSQLiteConnection,
|
db: QuickSQLiteConnection,
|
||||||
|
@ -33,8 +33,8 @@ export const searchRelays: (
|
|||||||
const searchQuery = `SELECT * FROM nostros_relays WHERE url = '${relayUrl}';`
|
const searchQuery = `SELECT * FROM nostros_relays WHERE url = '${relayUrl}';`
|
||||||
const results = await db.execute(searchQuery)
|
const results = await db.execute(searchQuery)
|
||||||
const items: object[] = getItems(results)
|
const items: object[] = getItems(results)
|
||||||
const notes: Relay[] = items.map((object) => databaseToEntity(object))
|
const relays: Relay[] = items.map((object) => databaseToEntity(object))
|
||||||
return notes
|
return relays
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getRelays: (db: QuickSQLiteConnection) => Promise<Relay[]> = async (db) => {
|
export const getRelays: (db: QuickSQLiteConnection) => Promise<Relay[]> = async (db) => {
|
||||||
@ -45,6 +45,14 @@ export const getRelays: (db: QuickSQLiteConnection) => Promise<Relay[]> = async
|
|||||||
return relays
|
return relays
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getActiveRelays: (db: QuickSQLiteConnection) => Promise<Relay[]> = async (db) => {
|
||||||
|
const notesQuery = 'SELECT * FROM nostros_relays WHERE active = 1;'
|
||||||
|
const resultSet = await db.execute(notesQuery)
|
||||||
|
const items: object[] = getItems(resultSet)
|
||||||
|
const relays: Relay[] = items.map((object) => databaseToEntity(object))
|
||||||
|
return relays
|
||||||
|
}
|
||||||
|
|
||||||
export const getRelay: (db: QuickSQLiteConnection, url: string) => Promise<Relay> = async (
|
export const getRelay: (db: QuickSQLiteConnection, url: string) => Promise<Relay> = async (
|
||||||
db,
|
db,
|
||||||
url,
|
url,
|
||||||
|
@ -8,7 +8,7 @@ export interface User {
|
|||||||
picture?: string
|
picture?: string
|
||||||
about?: string
|
about?: string
|
||||||
contact?: boolean
|
contact?: boolean
|
||||||
follower?: boolean
|
follower?: number
|
||||||
lnurl?: string
|
lnurl?: string
|
||||||
nip05?: string
|
nip05?: string
|
||||||
created_at?: number
|
created_at?: number
|
||||||
|
@ -51,7 +51,7 @@ export const pickRandomItems = <T extends unknown>(arr: T[], n: number): T[] =>
|
|||||||
|
|
||||||
export const validImageUrl: (url: string | undefined) => boolean = (url) => {
|
export const validImageUrl: (url: string | undefined) => boolean = (url) => {
|
||||||
if (url) {
|
if (url) {
|
||||||
const regexp = /^(https?:\/\/.*\.(?:png|jpg|jpeg|gif|webp))$/
|
const regexp = /^(https?:\/\/.*\.(?:png|jpg|jpeg|gif|webp)(\?.*)?)$/
|
||||||
return regexp.test(url)
|
return regexp.test(url)
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
|
@ -38,7 +38,13 @@ export const formatPubKey: (pubKey: string | undefined) => string = (pubKey) =>
|
|||||||
|
|
||||||
const uniqueCode = pubKey.replace('npub1', '')
|
const uniqueCode = pubKey.replace('npub1', '')
|
||||||
|
|
||||||
return `${uniqueCode.slice(0, 8)}:${uniqueCode.slice(-8)}`
|
return formatId(uniqueCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const formatId: (key: string | undefined) => string = (key) => {
|
||||||
|
if (!key) return ''
|
||||||
|
|
||||||
|
return `${key.slice(0, 8)}:${key.slice(-8)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getNip05Domain: (nip05: string | undefined) => string | null = (nip05) => {
|
export const getNip05Domain: (nip05: string | undefined) => string | null = (nip05) => {
|
||||||
|
@ -41,7 +41,8 @@
|
|||||||
"home": "Start",
|
"home": "Start",
|
||||||
"searchingProfile": "Durchsuche Profil",
|
"searchingProfile": "Durchsuche Profil",
|
||||||
"foundProfile": "Profil gefunden",
|
"foundProfile": "Profil gefunden",
|
||||||
"foundContacts": "{{contactsCount}} Kontakte gefunden"
|
"foundContacts": "{{contactsCount}} Kontakte gefunden",
|
||||||
|
"storing": "Storing {{lastEventId}} on database."
|
||||||
},
|
},
|
||||||
"sendPage": {
|
"sendPage": {
|
||||||
"isContact": "Folge ich",
|
"isContact": "Folge ich",
|
||||||
@ -257,13 +258,18 @@
|
|||||||
"notifications": {
|
"notifications": {
|
||||||
"contactAdded": "Kontakt hinzugefügt",
|
"contactAdded": "Kontakt hinzugefügt",
|
||||||
"contactRemoved": "Entfernt ",
|
"contactRemoved": "Entfernt ",
|
||||||
"npubCopied": "Öffentlicher Schlüssel kopiert."
|
"npubCopied": "Öffentlicher Schlüssel kopiert.",
|
||||||
|
"active": "Relay aktiviert.",
|
||||||
|
"desactive": "Relay deaktiviert."
|
||||||
},
|
},
|
||||||
"invoice": "Zap",
|
"invoice": "Zap",
|
||||||
"message": "Nachricht",
|
"message": "Nachricht",
|
||||||
"follow": "Folgen",
|
"follow": "Folgen",
|
||||||
|
"isFollower": "follows you",
|
||||||
"unfollow": "Nicht mehr folgen",
|
"unfollow": "Nicht mehr folgen",
|
||||||
"copyNPub": "Schlüssel kopieren"
|
"copyNPub": "Schlüssel kopieren",
|
||||||
|
"relaysTitle": "Relays",
|
||||||
|
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
||||||
},
|
},
|
||||||
"homePage": {
|
"homePage": {
|
||||||
"clipboardTitle": "Nostr Schlüssel entdeckt",
|
"clipboardTitle": "Nostr Schlüssel entdeckt",
|
||||||
|
@ -40,8 +40,9 @@
|
|||||||
"relays": "See relays",
|
"relays": "See relays",
|
||||||
"home": "Go Home",
|
"home": "Go Home",
|
||||||
"searchingProfile": "Searching for your profile",
|
"searchingProfile": "Searching for your profile",
|
||||||
"foundProfile": "Found profile",
|
"foundProfile": "Profile found",
|
||||||
"foundContacts": "{{contactsCount}} contacts found"
|
"foundContacts": "{{contactsCount}} contacts found",
|
||||||
|
"storing": "Storing {{lastEventId}} on database."
|
||||||
},
|
},
|
||||||
"sendPage": {
|
"sendPage": {
|
||||||
"isContact": "Following",
|
"isContact": "Following",
|
||||||
@ -175,9 +176,9 @@
|
|||||||
},
|
},
|
||||||
"relaysPage": {
|
"relaysPage": {
|
||||||
"resilienceTitle": "Resilience (experimental)",
|
"resilienceTitle": "Resilience (experimental)",
|
||||||
"resilienceDescription": "The nostr protocol provides a good amount of tools to build a desentralized network, but unlike other desentralized protocols such as Bitcoin, it's not inherent by defaul on his usage.\n\nTo ahcieve such goal, clients and relays should activally colaborate. Nostros resiliense mode tries to, first, expose these concerns to their users, and secondly, start experimening with new pattern and way to help on network' resilency.\n\nFunctional implementation will soon endup appearing on Nostros by default.",
|
"resilienceDescription": "The Nostr protocol provides a good number of tools to build a decentralized network, but unlike other decentralized protocols such as Bitcoin, it is not inherently bound to its use. To achieve the goal of a decentralized network, clients (e.g., Nostros) and relays (content servers) should actively cooperate. The Nostros resilience mode seeks first to raise awareness of this among users, and second to test new patterns and methods to improve the resilience of the network.\nA working implementation for this will soon be applied in Nostros.",
|
||||||
"resilienceCategories": "Resilience exposure",
|
"resilienceCategories": "Resilience exposure",
|
||||||
"resilienceCategoriesDescription": "A first approach Nostros is testing is randomly calculate (based on received contats' events) what are the most resilient relays. It tries to avoid both relays with too much events (centralization) and relays with almost no events (battery draining).\n\nThe goal is to generate a list of 5 relays and cover all contacts. But if this is not possible, it will search among other relays, warning to the user about it.\n\nKeep into consideration relays flaged as 'Centralized'/'Small' doesn't means they are to the network, but just to your data.",
|
"resilienceCategoriesDescription": "An initial approach that Nostros is testing is to randomly calculate (based on received contact events) which relays are most balanced. This tries to avoid both relays with too many events (centralization) and relays with almost no events (battery discharge).\n\nThe goal is to create a list of 5 relays that cover all contacts. However, if this is not possible, Nostros will search among other relays and warn the user about it.",
|
||||||
"centralized": "Centralized",
|
"centralized": "Centralized",
|
||||||
"small": "Small",
|
"small": "Small",
|
||||||
"contacts": "# Contacts",
|
"contacts": "# Contacts",
|
||||||
@ -269,13 +270,18 @@
|
|||||||
"notifications": {
|
"notifications": {
|
||||||
"contactAdded": "Profile followed",
|
"contactAdded": "Profile followed",
|
||||||
"contactRemoved": "Profile unfollowed",
|
"contactRemoved": "Profile unfollowed",
|
||||||
"npubCopied": "Public key copied."
|
"npubCopied": "Public key copied.",
|
||||||
|
"active": "Relay activated.",
|
||||||
|
"desactive": "Relay desactivated."
|
||||||
},
|
},
|
||||||
"invoice": "Tip",
|
"invoice": "Tip",
|
||||||
"message": "Message",
|
"message": "Message",
|
||||||
"follow": "Follow",
|
"follow": "Follow",
|
||||||
"unfollow": "Following",
|
"unfollow": "Following",
|
||||||
"copyNPub": "Copy key"
|
"copyNPub": "Copy key",
|
||||||
|
"relaysTitle": "Relays",
|
||||||
|
"isFollower": "follows you",
|
||||||
|
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
||||||
},
|
},
|
||||||
"homePage": {
|
"homePage": {
|
||||||
"clipboardTitle": "Nostr key detected",
|
"clipboardTitle": "Nostr key detected",
|
||||||
|
@ -41,7 +41,8 @@
|
|||||||
"home": "Acceder",
|
"home": "Acceder",
|
||||||
"searchingProfile": "Buscando tu perfil",
|
"searchingProfile": "Buscando tu perfil",
|
||||||
"foundProfile": "Perfil encontrado",
|
"foundProfile": "Perfil encontrado",
|
||||||
"foundContacts": "{{contactsCount}} contactos encontrados"
|
"foundContacts": "{{contactsCount}} contactos encontrados",
|
||||||
|
"storing": "Guardando {{lastEventId}} en base de datos."
|
||||||
},
|
},
|
||||||
"sendPage": {
|
"sendPage": {
|
||||||
"isContact": "Siguiendo",
|
"isContact": "Siguiendo",
|
||||||
@ -251,13 +252,18 @@
|
|||||||
"notifications": {
|
"notifications": {
|
||||||
"contactAdded": "Siguiendo",
|
"contactAdded": "Siguiendo",
|
||||||
"contactRemoved": "Dejando de seguir ",
|
"contactRemoved": "Dejando de seguir ",
|
||||||
"npubCopied": "Clave pública copiada."
|
"npubCopied": "Clave pública copiada.",
|
||||||
|
"active": "Relay activado.",
|
||||||
|
"desactive": "Relay desactivado."
|
||||||
},
|
},
|
||||||
"invoice": "Propina",
|
"invoice": "Propina",
|
||||||
"message": "Mensaje",
|
"message": "Mensaje",
|
||||||
|
"isFollower": "te sigue",
|
||||||
"follow": "Seguir",
|
"follow": "Seguir",
|
||||||
"unfollow": "Siguiendo",
|
"unfollow": "Siguiendo",
|
||||||
"copyNPub": "Copiar clave"
|
"copyNPub": "Copiar clave",
|
||||||
|
"relaysTitle": "Relays",
|
||||||
|
"relaysDescription": "Estos son los relays de {{username}}, activa aquellos a los que quieras estar conectado."
|
||||||
},
|
},
|
||||||
"homePage": {
|
"homePage": {
|
||||||
"clipboardTitle": "Se ha detectado una clave Nostr",
|
"clipboardTitle": "Se ha detectado una clave Nostr",
|
||||||
|
@ -41,7 +41,8 @@
|
|||||||
"home": "Accès",
|
"home": "Accès",
|
||||||
"searchingProfile": "A la recherche de votre profil",
|
"searchingProfile": "A la recherche de votre profil",
|
||||||
"foundProfile": "Profil trouvé",
|
"foundProfile": "Profil trouvé",
|
||||||
"foundContacts": "{{contactsCount}} contacts trouvés"
|
"foundContacts": "{{contactsCount}} contacts trouvés",
|
||||||
|
"storing": "Storing {{lastEventId}} on database."
|
||||||
},
|
},
|
||||||
"sendPage": {
|
"sendPage": {
|
||||||
"isContact": "Abonné",
|
"isContact": "Abonné",
|
||||||
@ -252,13 +253,18 @@
|
|||||||
"notifications": {
|
"notifications": {
|
||||||
"contactAdded": "Abonné",
|
"contactAdded": "Abonné",
|
||||||
"contactRemoved": "Vous ne suivez plus ce profil",
|
"contactRemoved": "Vous ne suivez plus ce profil",
|
||||||
"npubCopied": "Clé publique copiée"
|
"npubCopied": "Clé publique copiée",
|
||||||
|
"active": "Actif",
|
||||||
|
"share": "Partager"
|
||||||
},
|
},
|
||||||
"invoice": "Facture",
|
"invoice": "Facture",
|
||||||
"message": "Message",
|
"message": "Message",
|
||||||
"follow": "Suivre",
|
"follow": "Suivre",
|
||||||
|
"isFollower": "follows you",
|
||||||
"unfollow": "Abonné",
|
"unfollow": "Abonné",
|
||||||
"copyNPub": "Copier la clé"
|
"copyNPub": "Copier la clé",
|
||||||
|
"relaysTitle": "Relays",
|
||||||
|
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
||||||
},
|
},
|
||||||
"profileShare": {
|
"profileShare": {
|
||||||
"notifications": {
|
"notifications": {
|
||||||
|
@ -41,7 +41,8 @@
|
|||||||
"home": "На главную",
|
"home": "На главную",
|
||||||
"searchingProfile": "Ищем Ваш профиль.",
|
"searchingProfile": "Ищем Ваш профиль.",
|
||||||
"foundProfile": "Профиль найден.",
|
"foundProfile": "Профиль найден.",
|
||||||
"foundContacts": "{{contactsCount}} контакта(ов) найдено"
|
"foundContacts": "{{contactsCount}} контакта(ов) найдено",
|
||||||
|
"storing": "Storing {{lastEventId}} on database."
|
||||||
},
|
},
|
||||||
"sendPage": {
|
"sendPage": {
|
||||||
"isContact": "Подписаны",
|
"isContact": "Подписаны",
|
||||||
@ -219,7 +220,9 @@
|
|||||||
"lud06Published": "LUD-06 published.\n\n{{lud06}}",
|
"lud06Published": "LUD-06 published.\n\n{{lud06}}",
|
||||||
"nip05Published": "NIP-05 published.\n\n{{nip05}}",
|
"nip05Published": "NIP-05 published.\n\n{{nip05}}",
|
||||||
"picturePublished": "Picture published.",
|
"picturePublished": "Picture published.",
|
||||||
"connectionError": "Ошибка с подключением"
|
"connectionError": "Ошибка с подключением",
|
||||||
|
"active": "Relay actived.",
|
||||||
|
"desactive": "Relay desactivated."
|
||||||
},
|
},
|
||||||
"publishLud06": "Опубликовть",
|
"publishLud06": "Опубликовть",
|
||||||
"lud06Label": "LNURL / Lightning Address",
|
"lud06Label": "LNURL / Lightning Address",
|
||||||
@ -257,7 +260,10 @@
|
|||||||
"message": "Сообщение",
|
"message": "Сообщение",
|
||||||
"follow": "Follow",
|
"follow": "Follow",
|
||||||
"unfollow": "Following",
|
"unfollow": "Following",
|
||||||
"copyNPub": "Скопировать ключ"
|
"isFollower": "follows you",
|
||||||
|
"copyNPub": "Скопировать ключ",
|
||||||
|
"relaysTitle": "Relays",
|
||||||
|
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
||||||
},
|
},
|
||||||
"homePage": {
|
"homePage": {
|
||||||
"clipboardTitle": "Se ha detectado una clave Nostr",
|
"clipboardTitle": "Se ha detectado una clave Nostr",
|
||||||
|
@ -40,7 +40,8 @@
|
|||||||
"home": "去首页",
|
"home": "去首页",
|
||||||
"searchingProfile": "搜索用户",
|
"searchingProfile": "搜索用户",
|
||||||
"foundProfile": "已找到的用户",
|
"foundProfile": "已找到的用户",
|
||||||
"foundContacts": "已找到 {{contactsCount}} 个联系人"
|
"foundContacts": "已找到 {{contactsCount}} 个联系人",
|
||||||
|
"storing": "Storing {{lastEventId}} on database."
|
||||||
},
|
},
|
||||||
"sendPage": {
|
"sendPage": {
|
||||||
"isContact": "正在关注",
|
"isContact": "正在关注",
|
||||||
@ -232,7 +233,9 @@
|
|||||||
"lud06Published": "LUD-06 已发布 \n\n{{lud06}}",
|
"lud06Published": "LUD-06 已发布 \n\n{{lud06}}",
|
||||||
"nip05Published": "NIP-05 已发布 \n\n{{nip05}}",
|
"nip05Published": "NIP-05 已发布 \n\n{{nip05}}",
|
||||||
"picturePublished": "头像已发布",
|
"picturePublished": "头像已发布",
|
||||||
"connectionError": "连接错误"
|
"connectionError": "连接错误",
|
||||||
|
"active": "中继已启用",
|
||||||
|
"desactive": "中继已停用"
|
||||||
},
|
},
|
||||||
"publishLud06": "发布",
|
"publishLud06": "发布",
|
||||||
"lud06Label": "LNURL / Lightning 地址",
|
"lud06Label": "LNURL / Lightning 地址",
|
||||||
@ -269,8 +272,11 @@
|
|||||||
"invoice": "赞赏",
|
"invoice": "赞赏",
|
||||||
"message": "私信",
|
"message": "私信",
|
||||||
"follow": "关注",
|
"follow": "关注",
|
||||||
|
"isFollower": "follows you",
|
||||||
"unfollow": "关注中",
|
"unfollow": "关注中",
|
||||||
"copyNPub": "复制公钥"
|
"copyNPub": "复制公钥",
|
||||||
|
"relaysTitle": "Relays",
|
||||||
|
"relaysDescription": "These are {{username}}'s relays, activate the ones you want to be connected."
|
||||||
},
|
},
|
||||||
"homePage": {
|
"homePage": {
|
||||||
"clipboardTitle": "检测到 Nostr 公钥",
|
"clipboardTitle": "检测到 Nostr 公钥",
|
||||||
|
@ -18,7 +18,6 @@ import ConfigPage from '../ConfigPage'
|
|||||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||||
import { AppContext } from '../../Contexts/AppContext'
|
import { AppContext } from '../../Contexts/AppContext'
|
||||||
import RelayCard from '../../Components/RelayCard'
|
import RelayCard from '../../Components/RelayCard'
|
||||||
import ProfileShare from '../../Components/ProfileShare'
|
|
||||||
import { updateAllRead } from '../../Functions/DatabaseFunctions/DirectMessages'
|
import { updateAllRead } from '../../Functions/DatabaseFunctions/DirectMessages'
|
||||||
import { getUnixTime } from 'date-fns'
|
import { getUnixTime } from 'date-fns'
|
||||||
|
|
||||||
@ -26,18 +25,11 @@ export const HomeNavigator: React.FC = () => {
|
|||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const { t } = useTranslation('common')
|
const { t } = useTranslation('common')
|
||||||
const { displayRelayDrawer, setDisplayrelayDrawer } = React.useContext(RelayPoolContext)
|
const { displayRelayDrawer, setDisplayrelayDrawer } = React.useContext(RelayPoolContext)
|
||||||
const {
|
const { displayUserDrawer, setDisplayUserDrawer, setRefreshBottomBarAt, database } =
|
||||||
displayUserDrawer,
|
React.useContext(AppContext)
|
||||||
setDisplayUserDrawer,
|
|
||||||
displayUserShareDrawer,
|
|
||||||
setDisplayUserShareDrawer,
|
|
||||||
setRefreshBottomBarAt,
|
|
||||||
database,
|
|
||||||
} = React.useContext(AppContext)
|
|
||||||
const bottomSheetRef = React.useRef<RBSheet>(null)
|
const bottomSheetRef = React.useRef<RBSheet>(null)
|
||||||
const bottomSheetProfileRef = React.useRef<RBSheet>(null)
|
const bottomSheetProfileRef = React.useRef<RBSheet>(null)
|
||||||
const bottomSheetRelayRef = React.useRef<RBSheet>(null)
|
const bottomSheetRelayRef = React.useRef<RBSheet>(null)
|
||||||
const bottomSheetShareRef = React.useRef<RBSheet>(null)
|
|
||||||
const Stack = React.useMemo(() => createStackNavigator(), [])
|
const Stack = React.useMemo(() => createStackNavigator(), [])
|
||||||
const cardStyleInterpolator = React.useMemo(
|
const cardStyleInterpolator = React.useMemo(
|
||||||
() =>
|
() =>
|
||||||
@ -78,10 +70,6 @@ export const HomeNavigator: React.FC = () => {
|
|||||||
if (displayUserDrawer) bottomSheetProfileRef.current?.open()
|
if (displayUserDrawer) bottomSheetProfileRef.current?.open()
|
||||||
}, [displayUserDrawer])
|
}, [displayUserDrawer])
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (displayUserShareDrawer) bottomSheetShareRef.current?.open()
|
|
||||||
}, [displayUserShareDrawer])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Stack.Navigator
|
<Stack.Navigator
|
||||||
@ -174,14 +162,6 @@ export const HomeNavigator: React.FC = () => {
|
|||||||
<Text variant='bodyMedium'>{t('drawers.relaysDescription')}</Text>
|
<Text variant='bodyMedium'>{t('drawers.relaysDescription')}</Text>
|
||||||
</View>
|
</View>
|
||||||
</RBSheet>
|
</RBSheet>
|
||||||
<RBSheet
|
|
||||||
ref={bottomSheetShareRef}
|
|
||||||
closeOnDragDown={true}
|
|
||||||
customStyles={bottomSheetStyles}
|
|
||||||
onClose={() => setDisplayUserShareDrawer(undefined)}
|
|
||||||
>
|
|
||||||
<ProfileShare />
|
|
||||||
</RBSheet>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,6 @@ export const ProfileCreatePage: React.FC<ProfileCreatePageProps> = ({ navigation
|
|||||||
|
|
||||||
const onPress: () => void = () => {
|
const onPress: () => void = () => {
|
||||||
if (step > 1) {
|
if (step > 1) {
|
||||||
console.log(validConfirmation())
|
|
||||||
if (validConfirmation()) {
|
if (validConfirmation()) {
|
||||||
setPrivateKey(key)
|
setPrivateKey(key)
|
||||||
setUserState('ready')
|
setUserState('ready')
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useContext, useEffect, useState } from 'react'
|
import React, { useContext, useEffect, useState } from 'react'
|
||||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
import { RelayPoolContext, WebsocketEvent } from '../../Contexts/RelayPoolContext'
|
||||||
import { Kind } from 'nostr-tools'
|
import { Kind } from 'nostr-tools'
|
||||||
import { AppContext } from '../../Contexts/AppContext'
|
import { AppContext } from '../../Contexts/AppContext'
|
||||||
import { UserContext } from '../../Contexts/UserContext'
|
import { UserContext } from '../../Contexts/UserContext'
|
||||||
@ -7,28 +7,32 @@ import { getUsers, User } from '../../Functions/DatabaseFunctions/Users'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import getUnixTime from 'date-fns/getUnixTime'
|
import getUnixTime from 'date-fns/getUnixTime'
|
||||||
import debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
import { StyleSheet, View } from 'react-native'
|
import { DeviceEventEmitter, StyleSheet, View } from 'react-native'
|
||||||
import Logo from '../../Components/Logo'
|
import Logo from '../../Components/Logo'
|
||||||
import { Button, Text, useTheme } from 'react-native-paper'
|
import { Button, Text, useTheme } from 'react-native-paper'
|
||||||
import { navigate } from '../../lib/Navigation'
|
import { navigate } from '../../lib/Navigation'
|
||||||
import { useFocusEffect } from '@react-navigation/native'
|
import { useFocusEffect } from '@react-navigation/native'
|
||||||
|
import { formatId } from '../../Functions/RelayFunctions/Users'
|
||||||
|
|
||||||
export const ProfileLoadPage: React.FC = () => {
|
export const ProfileLoadPage: React.FC = () => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const { database } = useContext(AppContext)
|
const { database } = useContext(AppContext)
|
||||||
const { relayPool, lastEventId, relayPoolReady } = useContext(RelayPoolContext)
|
const { relayPool, relayPoolReady } = useContext(RelayPoolContext)
|
||||||
const { publicKey, reloadUser, setUserState, name } = useContext(UserContext)
|
const { publicKey, reloadUser, setUserState, name } = useContext(UserContext)
|
||||||
const { t } = useTranslation('common')
|
const { t } = useTranslation('common')
|
||||||
const [profileFound, setProfileFound] = useState<boolean>(false)
|
const [profileFound, setProfileFound] = useState<boolean>(false)
|
||||||
const [contactsCount, setContactsCount] = useState<number>(0)
|
const [contactsCount, setContactsCount] = useState<number>(0)
|
||||||
|
const [lastEventId, setLastEventId] = useState<string>('')
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
React.useCallback(() => {
|
React.useCallback(() => {
|
||||||
|
DeviceEventEmitter.addListener('WebsocketEvent', (event: WebsocketEvent) =>
|
||||||
|
setLastEventId(event.eventId),
|
||||||
|
)
|
||||||
debounce(() => {
|
debounce(() => {
|
||||||
loadMeta()
|
loadMeta()
|
||||||
loadPets()
|
reloadUser()
|
||||||
}, 1000)
|
}, 1000)
|
||||||
|
|
||||||
return () =>
|
return () =>
|
||||||
relayPool?.unsubscribe([
|
relayPool?.unsubscribe([
|
||||||
'profile-load-meta',
|
'profile-load-meta',
|
||||||
@ -39,14 +43,16 @@ export const ProfileLoadPage: React.FC = () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadMeta()
|
if (!name) reloadUser()
|
||||||
loadPets()
|
}, [lastEventId, publicKey, relayPoolReady])
|
||||||
reloadUser()
|
|
||||||
if (name) {
|
useEffect(() => {
|
||||||
setProfileFound(true)
|
if (name) setProfileFound(true)
|
||||||
loadPets()
|
}, [name])
|
||||||
}
|
|
||||||
}, [lastEventId, name])
|
useEffect(() => {
|
||||||
|
if (profileFound) loadPets()
|
||||||
|
}, [profileFound, publicKey, relayPoolReady])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (publicKey && relayPoolReady) loadMeta()
|
if (publicKey && relayPoolReady) loadMeta()
|
||||||
@ -56,23 +62,17 @@ export const ProfileLoadPage: React.FC = () => {
|
|||||||
if (publicKey && relayPoolReady) {
|
if (publicKey && relayPoolReady) {
|
||||||
relayPool?.subscribe('profile-load-meta', [
|
relayPool?.subscribe('profile-load-meta', [
|
||||||
{
|
{
|
||||||
kinds: [Kind.Text, Kind.Contacts, Kind.Metadata],
|
kinds: [Kind.Contacts, Kind.Metadata],
|
||||||
authors: [publicKey],
|
authors: [publicKey],
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
relayPool?.subscribe('profile-load-meta-pets', [
|
|
||||||
{
|
|
||||||
kinds: [Kind.Contacts],
|
|
||||||
'#p': [publicKey],
|
|
||||||
},
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadPets: () => void = () => {
|
const loadPets: () => void = () => {
|
||||||
if (database && publicKey && relayPoolReady) {
|
if (database && publicKey && relayPoolReady) {
|
||||||
getUsers(database, {}).then((results) => {
|
getUsers(database, {}).then((results) => {
|
||||||
if (results && results.length > 0) {
|
if (results.length > 0) {
|
||||||
setContactsCount(results.filter((user) => user.contact).length)
|
setContactsCount(results.filter((user) => user.contact).length)
|
||||||
const authors = [...results.map((user: User) => user.id), publicKey]
|
const authors = [...results.map((user: User) => user.id), publicKey]
|
||||||
relayPool?.subscribe('profile-load-notes', [
|
relayPool?.subscribe('profile-load-notes', [
|
||||||
@ -103,6 +103,9 @@ export const ProfileLoadPage: React.FC = () => {
|
|||||||
<Text variant='titleMedium' style={styles.center}>
|
<Text variant='titleMedium' style={styles.center}>
|
||||||
{t('profileLoadPage.foundContacts', { contactsCount })}
|
{t('profileLoadPage.foundContacts', { contactsCount })}
|
||||||
</Text>
|
</Text>
|
||||||
|
<Text variant='titleMedium' style={styles.center}>
|
||||||
|
{t('profileLoadPage.storing', { lastEventId: formatId(lastEventId) })}
|
||||||
|
</Text>
|
||||||
<Button mode='contained' onPress={() => setUserState('ready')}>
|
<Button mode='contained' onPress={() => setUserState('ready')}>
|
||||||
{t('profileLoadPage.home')}
|
{t('profileLoadPage.home')}
|
||||||
</Button>
|
</Button>
|
||||||
@ -114,6 +117,7 @@ export const ProfileLoadPage: React.FC = () => {
|
|||||||
style={styles.warningAction}
|
style={styles.warningAction}
|
||||||
mode='text'
|
mode='text'
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
|
reloadUser()
|
||||||
navigate('Relays')
|
navigate('Relays')
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -7,30 +7,28 @@ import {
|
|||||||
StyleSheet,
|
StyleSheet,
|
||||||
View,
|
View,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import { Surface, Text, IconButton, ActivityIndicator, Snackbar } from 'react-native-paper'
|
import { Surface, Text, ActivityIndicator, Snackbar, Divider } from 'react-native-paper'
|
||||||
import { FlashList, ListRenderItem } from '@shopify/flash-list'
|
import { FlashList, ListRenderItem } from '@shopify/flash-list'
|
||||||
import { AppContext } from '../../Contexts/AppContext'
|
import { AppContext } from '../../Contexts/AppContext'
|
||||||
import { UserContext } from '../../Contexts/UserContext'
|
import { UserContext } from '../../Contexts/UserContext'
|
||||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||||
import { getNotes, Note } from '../../Functions/DatabaseFunctions/Notes'
|
import { getNotes, Note } from '../../Functions/DatabaseFunctions/Notes'
|
||||||
import { getUser, updateUserContact, User } from '../../Functions/DatabaseFunctions/Users'
|
import { getUser, User } from '../../Functions/DatabaseFunctions/Users'
|
||||||
import { Kind } from 'nostr-tools'
|
import { Kind } from 'nostr-tools'
|
||||||
import { populatePets, username } from '../../Functions/RelayFunctions/Users'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { RelayFilters } from '../../lib/nostr/RelayPool/intex'
|
import { RelayFilters } from '../../lib/nostr/RelayPool/intex'
|
||||||
import NoteCard from '../../Components/NoteCard'
|
import NoteCard from '../../Components/NoteCard'
|
||||||
import LnPayment from '../../Components/LnPayment'
|
|
||||||
import { handleInfinityScroll } from '../../Functions/NativeFunctions'
|
import { handleInfinityScroll } from '../../Functions/NativeFunctions'
|
||||||
import { navigate } from '../../lib/Navigation'
|
|
||||||
import { useFocusEffect } from '@react-navigation/native'
|
import { useFocusEffect } from '@react-navigation/native'
|
||||||
import ProfileData from '../../Components/ProfileData'
|
import ProfileData from '../../Components/ProfileData'
|
||||||
|
import ProfileActions from '../../Components/ProfileActions'
|
||||||
|
|
||||||
interface ProfilePageProps {
|
interface ProfilePageProps {
|
||||||
route: { params: { pubKey: string } }
|
route: { params: { pubKey: string } }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProfilePage: React.FC<ProfilePageProps> = ({ route }) => {
|
export const ProfilePage: React.FC<ProfilePageProps> = ({ route }) => {
|
||||||
const { database, setDisplayUserShareDrawer } = useContext(AppContext)
|
const { database } = useContext(AppContext)
|
||||||
const { publicKey } = useContext(UserContext)
|
const { publicKey } = useContext(UserContext)
|
||||||
const { lastEventId, relayPool } = useContext(RelayPoolContext)
|
const { lastEventId, relayPool } = useContext(RelayPoolContext)
|
||||||
const { t } = useTranslation('common')
|
const { t } = useTranslation('common')
|
||||||
@ -38,9 +36,7 @@ export const ProfilePage: React.FC<ProfilePageProps> = ({ route }) => {
|
|||||||
const [showNotification, setShowNotification] = useState<undefined | string>()
|
const [showNotification, setShowNotification] = useState<undefined | string>()
|
||||||
const [notes, setNotes] = useState<Note[]>()
|
const [notes, setNotes] = useState<Note[]>()
|
||||||
const [user, setUser] = useState<User>()
|
const [user, setUser] = useState<User>()
|
||||||
const [openLn, setOpenLn] = React.useState<boolean>(false)
|
|
||||||
const [pageSize, setPageSize] = useState<number>(initialPageSize)
|
const [pageSize, setPageSize] = useState<number>(initialPageSize)
|
||||||
const [isContact, setIsContact] = useState<boolean>()
|
|
||||||
const [refreshing, setRefreshing] = useState(false)
|
const [refreshing, setRefreshing] = useState(false)
|
||||||
const [firstLoad, setFirstLoad] = useState(true)
|
const [firstLoad, setFirstLoad] = useState(true)
|
||||||
|
|
||||||
@ -84,7 +80,6 @@ export const ProfilePage: React.FC<ProfilePageProps> = ({ route }) => {
|
|||||||
getUser(route.params.pubKey, database).then((result) => {
|
getUser(route.params.pubKey, database).then((result) => {
|
||||||
if (result) {
|
if (result) {
|
||||||
setUser(result)
|
setUser(result)
|
||||||
setIsContact(result?.contact)
|
|
||||||
} else if (route.params.pubKey === publicKey) {
|
} else if (route.params.pubKey === publicKey) {
|
||||||
setUser({
|
setUser({
|
||||||
id: publicKey,
|
id: publicKey,
|
||||||
@ -133,26 +128,6 @@ export const ProfilePage: React.FC<ProfilePageProps> = ({ route }) => {
|
|||||||
relayPool?.subscribe(`profile${route.params.pubKey}`, [message])
|
relayPool?.subscribe(`profile${route.params.pubKey}`, [message])
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeContact: () => void = () => {
|
|
||||||
if (relayPool && database && publicKey) {
|
|
||||||
updateUserContact(route.params.pubKey, database, false).then(() => {
|
|
||||||
populatePets(relayPool, database, publicKey)
|
|
||||||
setIsContact(false)
|
|
||||||
setShowNotification('contactRemoved')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const addContact: () => void = () => {
|
|
||||||
if (relayPool && database && publicKey) {
|
|
||||||
updateUserContact(route.params.pubKey, database, true).then(() => {
|
|
||||||
populatePets(relayPool, database, publicKey)
|
|
||||||
setIsContact(true)
|
|
||||||
setShowNotification('contactAdded')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void = (event) => {
|
const onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void = (event) => {
|
||||||
if (handleInfinityScroll(event)) {
|
if (handleInfinityScroll(event)) {
|
||||||
setPageSize(pageSize + initialPageSize)
|
setPageSize(pageSize + initialPageSize)
|
||||||
@ -174,70 +149,24 @@ export const ProfilePage: React.FC<ProfilePageProps> = ({ route }) => {
|
|||||||
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}
|
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />}
|
||||||
>
|
>
|
||||||
<Surface style={styles.container} elevation={1}>
|
<Surface style={styles.container} elevation={1}>
|
||||||
<ProfileData
|
<View style={styles.profileData}>
|
||||||
username={user?.name}
|
<ProfileData
|
||||||
publicKey={route.params.pubKey}
|
username={user?.name}
|
||||||
validNip05={user?.valid_nip05}
|
publicKey={route.params.pubKey}
|
||||||
nip05={user?.nip05}
|
validNip05={user?.valid_nip05}
|
||||||
lud06={user?.lnurl}
|
nip05={user?.nip05}
|
||||||
picture={user?.picture}
|
lud06={user?.lnurl}
|
||||||
avatarSize={56}
|
picture={user?.picture}
|
||||||
/>
|
avatarSize={56}
|
||||||
|
/>
|
||||||
|
<Text>{user?.follower && user.follower > 0 ? t('profilePage.isFollower') : ''}</Text>
|
||||||
|
</View>
|
||||||
<View>
|
<View>
|
||||||
<Text>{user?.about}</Text>
|
<Text>{user?.about}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.mainLayout}>
|
<Divider style={styles.divider} />
|
||||||
{route.params.pubKey !== publicKey && (
|
<View style={styles.profileActions}>
|
||||||
<View style={styles.actionButton}>
|
{user && <ProfileActions user={user} setUser={setUser} />}
|
||||||
<IconButton
|
|
||||||
icon={
|
|
||||||
isContact ? 'account-multiple-remove-outline' : 'account-multiple-plus-outline'
|
|
||||||
}
|
|
||||||
size={28}
|
|
||||||
onPress={() => {
|
|
||||||
isContact ? removeContact() : addContact()
|
|
||||||
}}
|
|
||||||
disabled={route.params.pubKey === publicKey}
|
|
||||||
/>
|
|
||||||
<Text>{isContact ? t('profilePage.unfollow') : t('profilePage.follow')}</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
<View style={styles.actionButton}>
|
|
||||||
<IconButton
|
|
||||||
icon='message-plus-outline'
|
|
||||||
size={28}
|
|
||||||
onPress={() => {
|
|
||||||
navigate('Conversation', {
|
|
||||||
pubKey: route.params.pubKey,
|
|
||||||
title: user ? username(user) : route.params.pubKey,
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Text>{t('profilePage.message')}</Text>
|
|
||||||
</View>
|
|
||||||
<View style={styles.actionButton}>
|
|
||||||
<IconButton
|
|
||||||
icon='share-variant-outline'
|
|
||||||
size={28}
|
|
||||||
onPress={() => {
|
|
||||||
setDisplayUserShareDrawer(user?.id)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Text>{t('profileCard.share')}</Text>
|
|
||||||
</View>
|
|
||||||
<View style={styles.actionButton}>
|
|
||||||
{user?.lnurl && (
|
|
||||||
<>
|
|
||||||
<IconButton
|
|
||||||
icon='lightning-bolt'
|
|
||||||
size={28}
|
|
||||||
onPress={() => setOpenLn(true)}
|
|
||||||
iconColor='#F5D112'
|
|
||||||
/>
|
|
||||||
<Text>{t('profilePage.invoice')}</Text>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
</Surface>
|
</Surface>
|
||||||
<View style={styles.list}>
|
<View style={styles.list}>
|
||||||
@ -265,7 +194,6 @@ export const ProfilePage: React.FC<ProfilePageProps> = ({ route }) => {
|
|||||||
{t(`profilePage.${showNotification}`)}
|
{t(`profilePage.${showNotification}`)}
|
||||||
</Snackbar>
|
</Snackbar>
|
||||||
)}
|
)}
|
||||||
<LnPayment setOpen={setOpenLn} open={openLn} user={user} />
|
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -274,26 +202,6 @@ const styles = StyleSheet.create({
|
|||||||
container: {
|
container: {
|
||||||
padding: 16,
|
padding: 16,
|
||||||
},
|
},
|
||||||
contacts: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'space-around',
|
|
||||||
},
|
|
||||||
mainLayout: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
userData: {
|
|
||||||
paddingLeft: 16,
|
|
||||||
},
|
|
||||||
userName: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
},
|
|
||||||
actionButton: {
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
width: 100,
|
|
||||||
},
|
|
||||||
snackbar: {
|
snackbar: {
|
||||||
margin: 16,
|
margin: 16,
|
||||||
bottom: 70,
|
bottom: 70,
|
||||||
@ -301,12 +209,19 @@ const styles = StyleSheet.create({
|
|||||||
list: {
|
list: {
|
||||||
padding: 16,
|
padding: 16,
|
||||||
},
|
},
|
||||||
|
divider: {
|
||||||
|
marginTop: 16,
|
||||||
|
},
|
||||||
|
profileActions: {
|
||||||
|
marginRight: 16,
|
||||||
|
marginLeft: 16,
|
||||||
|
},
|
||||||
noteCard: {
|
noteCard: {
|
||||||
marginBottom: 16,
|
marginBottom: 16,
|
||||||
},
|
},
|
||||||
verifyIcon: {
|
profileData: {
|
||||||
paddingTop: 6,
|
flexDirection: 'row',
|
||||||
paddingLeft: 5,
|
justifyContent: 'space-between',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { FlatList, ListRenderItem, ScrollView, StyleSheet, View } from 'react-na
|
|||||||
import Clipboard from '@react-native-clipboard/clipboard'
|
import Clipboard from '@react-native-clipboard/clipboard'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
import { RelayPoolContext } from '../../Contexts/RelayPoolContext'
|
||||||
import { Relay } from '../../Functions/DatabaseFunctions/Relays'
|
import { getRelays, Relay } from '../../Functions/DatabaseFunctions/Relays'
|
||||||
import { REGEX_SOCKET_LINK } from '../../Constants/Relay'
|
import { REGEX_SOCKET_LINK } from '../../Constants/Relay'
|
||||||
import {
|
import {
|
||||||
List,
|
List,
|
||||||
@ -21,6 +21,7 @@ import RBSheet from 'react-native-raw-bottom-sheet'
|
|||||||
import { relayToColor } from '../../Functions/NativeFunctions'
|
import { relayToColor } from '../../Functions/NativeFunctions'
|
||||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
|
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'
|
||||||
import { useFocusEffect } from '@react-navigation/native'
|
import { useFocusEffect } from '@react-navigation/native'
|
||||||
|
import { AppContext } from '../../Contexts/AppContext'
|
||||||
|
|
||||||
export const defaultRelays = [
|
export const defaultRelays = [
|
||||||
'wss://brb.io',
|
'wss://brb.io',
|
||||||
@ -39,13 +40,14 @@ export const defaultRelays = [
|
|||||||
|
|
||||||
export const RelaysPage: React.FC = () => {
|
export const RelaysPage: React.FC = () => {
|
||||||
const defaultRelayInput = React.useMemo(() => 'wss://', [])
|
const defaultRelayInput = React.useMemo(() => 'wss://', [])
|
||||||
const { updateRelayItem, addRelayItem, removeRelayItem, relays, relayPool } =
|
const { updateRelayItem, addRelayItem, removeRelayItem, relayPool } = useContext(RelayPoolContext)
|
||||||
useContext(RelayPoolContext)
|
const { database } = useContext(AppContext)
|
||||||
const { t } = useTranslation('common')
|
const { t } = useTranslation('common')
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const bottomSheetAddRef = React.useRef<RBSheet>(null)
|
const bottomSheetAddRef = React.useRef<RBSheet>(null)
|
||||||
const bottomSheetEditRef = React.useRef<RBSheet>(null)
|
const bottomSheetEditRef = React.useRef<RBSheet>(null)
|
||||||
const bottomSheetResilenseRef = React.useRef<RBSheet>(null)
|
const bottomSheetResilenseRef = React.useRef<RBSheet>(null)
|
||||||
|
const [relays, setRelays] = React.useState<Relay[]>([])
|
||||||
const [selectedRelay, setSelectedRelay] = useState<Relay>()
|
const [selectedRelay, setSelectedRelay] = useState<Relay>()
|
||||||
const [addRelayInput, setAddRelayInput] = useState<string>(defaultRelayInput)
|
const [addRelayInput, setAddRelayInput] = useState<string>(defaultRelayInput)
|
||||||
const [showNotification, setShowNotification] = useState<string>()
|
const [showNotification, setShowNotification] = useState<string>()
|
||||||
@ -53,17 +55,23 @@ export const RelaysPage: React.FC = () => {
|
|||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
React.useCallback(() => {
|
React.useCallback(() => {
|
||||||
relayPool?.unsubscribeAll()
|
relayPool?.unsubscribeAll()
|
||||||
|
updateRelays()
|
||||||
|
|
||||||
return () => {}
|
return () => {}
|
||||||
}, []),
|
}, []),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const updateRelays: () => void = () => {
|
||||||
|
if (database) getRelays(database).then(setRelays)
|
||||||
|
}
|
||||||
|
|
||||||
const addRelay: (url: string) => void = (url) => {
|
const addRelay: (url: string) => void = (url) => {
|
||||||
addRelayItem({
|
addRelayItem({
|
||||||
url,
|
url,
|
||||||
active: 1,
|
active: 1,
|
||||||
global_feed: 1,
|
global_feed: 1,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
updateRelays()
|
||||||
setShowNotification('add')
|
setShowNotification('add')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -72,6 +80,7 @@ export const RelaysPage: React.FC = () => {
|
|||||||
removeRelayItem({
|
removeRelayItem({
|
||||||
url,
|
url,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
updateRelays()
|
||||||
setShowNotification('remove')
|
setShowNotification('remove')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -79,6 +88,7 @@ export const RelaysPage: React.FC = () => {
|
|||||||
const activeRelay: (relay: Relay) => void = (relay) => {
|
const activeRelay: (relay: Relay) => void = (relay) => {
|
||||||
relay.active = 1
|
relay.active = 1
|
||||||
updateRelayItem(relay).then(() => {
|
updateRelayItem(relay).then(() => {
|
||||||
|
updateRelays()
|
||||||
setShowNotification('active')
|
setShowNotification('active')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -87,6 +97,7 @@ export const RelaysPage: React.FC = () => {
|
|||||||
relay.active = 0
|
relay.active = 0
|
||||||
relay.global_feed = 0
|
relay.global_feed = 0
|
||||||
updateRelayItem(relay).then(() => {
|
updateRelayItem(relay).then(() => {
|
||||||
|
updateRelays()
|
||||||
setShowNotification('desactive')
|
setShowNotification('desactive')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -95,6 +106,7 @@ export const RelaysPage: React.FC = () => {
|
|||||||
relay.active = 1
|
relay.active = 1
|
||||||
relay.global_feed = 1
|
relay.global_feed = 1
|
||||||
updateRelayItem(relay).then(() => {
|
updateRelayItem(relay).then(() => {
|
||||||
|
updateRelays()
|
||||||
setShowNotification('globalFeedActive')
|
setShowNotification('globalFeedActive')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -102,6 +114,7 @@ export const RelaysPage: React.FC = () => {
|
|||||||
const desactiveGlobalFeedRelay: (relay: Relay) => void = (relay) => {
|
const desactiveGlobalFeedRelay: (relay: Relay) => void = (relay) => {
|
||||||
relay.global_feed = 0
|
relay.global_feed = 0
|
||||||
updateRelayItem(relay).then(() => {
|
updateRelayItem(relay).then(() => {
|
||||||
|
updateRelays()
|
||||||
setShowNotification('globalFeedActiveUnactive')
|
setShowNotification('globalFeedActiveUnactive')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -229,7 +242,7 @@ export const RelaysPage: React.FC = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
<IconButton
|
<IconButton
|
||||||
style={styles.titleAction}
|
style={styles.titleAction}
|
||||||
icon='question'
|
icon='help'
|
||||||
size={20}
|
size={20}
|
||||||
onPress={() => bottomSheetResilenseRef.current?.open()}
|
onPress={() => bottomSheetResilenseRef.current?.open()}
|
||||||
/>
|
/>
|
||||||
|
@ -126,15 +126,11 @@ export const SendPage: React.FC<SendPageProps> = ({ route }) => {
|
|||||||
let tags: string[][] = []
|
let tags: string[][] = []
|
||||||
|
|
||||||
let rawContent = content
|
let rawContent = content
|
||||||
|
|
||||||
if (note?.id) {
|
if (note?.id) {
|
||||||
|
tags = note.tags
|
||||||
if (route.params?.type === 'reply') {
|
if (route.params?.type === 'reply') {
|
||||||
tags = note.tags
|
const eTags = getETags(note)
|
||||||
if (getETags(note).length === 0) {
|
tags.push(['e', note.id, '', eTags.length > 0 ? 'reply' : 'root'])
|
||||||
tags.push(['e', note.id, '', 'root'])
|
|
||||||
} else {
|
|
||||||
tags.push(['e', note.id, '', 'reply'])
|
|
||||||
}
|
|
||||||
tags.push(['p', note.pubkey, ''])
|
tags.push(['p', note.pubkey, ''])
|
||||||
} else if (route.params?.type === 'repost') {
|
} else if (route.params?.type === 'repost') {
|
||||||
rawContent = `#[${tags.length}] ${rawContent}`
|
rawContent = `#[${tags.length}] ${rawContent}`
|
||||||
@ -149,7 +145,7 @@ export const SendPage: React.FC<SendPageProps> = ({ route }) => {
|
|||||||
const userText = mentionText(user)
|
const userText = mentionText(user)
|
||||||
if (rawContent.includes(userText)) {
|
if (rawContent.includes(userText)) {
|
||||||
rawContent = rawContent.replace(userText, `#[${tags.length}]`)
|
rawContent = rawContent.replace(userText, `#[${tags.length}]`)
|
||||||
tags.push(['p', user.id])
|
tags.push(['p', user.id, ''])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user