diff --git a/frontend/Components/MenuItems/index.tsx b/frontend/Components/MenuItems/index.tsx index 0a5cf4b..a2f8e13 100644 --- a/frontend/Components/MenuItems/index.tsx +++ b/frontend/Components/MenuItems/index.tsx @@ -66,14 +66,14 @@ export const MenuItems: React.FC = () => { {user?.name} - {formatPubKey(nPub)} + {formatPubKey(user?.id ?? '')} diff --git a/frontend/Components/NostrosAvatar/index.tsx b/frontend/Components/NostrosAvatar/index.tsx index afe680f..5db6e5b 100644 --- a/frontend/Components/NostrosAvatar/index.tsx +++ b/frontend/Components/NostrosAvatar/index.tsx @@ -18,7 +18,7 @@ export const NostrosAvatar: React.FC = ({ lud06, }) => { const theme = useTheme() - const displayName = name && name !== '' ? name : pubKey + const displayName = name && name !== '' ? name : pubKey ?? '' const hasLud06 = lud06 && lud06 !== '' const lud06IconSize = size / 2.85 const validImage: () => boolean = () => { diff --git a/frontend/Components/NostrosNotification/index.tsx b/frontend/Components/NostrosNotification/index.tsx deleted file mode 100644 index a977a33..0000000 --- a/frontend/Components/NostrosNotification/index.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react' -import { StyleSheet } from 'react-native' -import { Snackbar } from 'react-native-paper' - -interface NostrosNotificationProps { - children: React.ReactNode - showNotification: string | undefined - setShowNotification: (showNotification: string | undefined) => void -} - -export const NostrosNotification: React.FC = ({ - children, - showNotification, - setShowNotification, -}) => { - return ( - setShowNotification(undefined)} - onDismiss={() => setShowNotification(undefined)} - > - {children} - - ) -} - -const styles = StyleSheet.create({ - snackbar: { - margin: 16, - bottom: 70, - }, -}) - -export default NostrosNotification diff --git a/frontend/Components/ProfileCard/index.tsx b/frontend/Components/ProfileCard/index.tsx index 2890b6c..3a98fa7 100644 --- a/frontend/Components/ProfileCard/index.tsx +++ b/frontend/Components/ProfileCard/index.tsx @@ -2,14 +2,13 @@ import { t } from 'i18next' import { npubEncode } from 'nostr-tools/nip19' import * as React from 'react' import { Clipboard, StyleSheet, View } from 'react-native' -import { Card, IconButton, Text } from 'react-native-paper' +import { Card, IconButton, Snackbar, Text } from 'react-native-paper' import { AppContext } from '../../Contexts/AppContext' import { RelayPoolContext } from '../../Contexts/RelayPoolContext' import { UserContext } from '../../Contexts/UserContext' import { getUser, updateUserContact, User } from '../../Functions/DatabaseFunctions/Users' import { populatePets } from '../../Functions/RelayFunctions/Users' import NostrosAvatar from '../NostrosAvatar' -import NostrosNotification from '../NostrosNotification' import LnPayment from '../LnPayment' import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons' import { navigate, push } from '../../lib/Navigation' @@ -94,7 +93,7 @@ export const ProfileCard: React.FC = ({ userPubKey, bottomShee - {`${user?.about?.slice(0, 75)}${ + {`${user?.about ? user?.about?.slice(0, 75) : ''}${ user?.about && user?.about?.length > 75 ? ' ...' : '' }`} @@ -156,12 +155,15 @@ export const ProfileCard: React.FC = ({ userPubKey, bottomShee {showNotification && ( - setShowNotification(undefined)} + onDismiss={() => setShowNotification(undefined)} > - {t(`profileCard.notifications.${showNotification}`)} - + {t(`profileCard.notifications.${showNotification}`)} + )} @@ -172,6 +174,10 @@ const styles = StyleSheet.create({ container: { padding: 16, }, + snackbar: { + margin: 16, + width: '100%', + }, contacts: { flexDirection: 'row', alignItems: 'center', diff --git a/frontend/Constants/Theme/theme-dark.json b/frontend/Constants/Theme/theme-dark.json index 4de8300..ee31cc1 100644 --- a/frontend/Constants/Theme/theme-dark.json +++ b/frontend/Constants/Theme/theme-dark.json @@ -43,6 +43,5 @@ "success": "#369734", "successContainer": "#369734", "onSuccessContainer": "#96FA89" - } } diff --git a/frontend/Contexts/UserContext.tsx b/frontend/Contexts/UserContext.tsx index e5f36d3..d701fc9 100644 --- a/frontend/Contexts/UserContext.tsx +++ b/frontend/Contexts/UserContext.tsx @@ -60,7 +60,13 @@ export const UserContextProvider = ({ children }: UserContextProviderProps): JSX const reloadUser: () => void = () => { if (database && publicKey) { getUser(publicKey, database).then((result) => { - if (result) setUser(result) + if (result) { + setUser(result) + } else { + setUser({ + id: publicKey, + }) + } }) getContactsCount(database).then(setContantsCount) getFollowersCount(database).then(setFollowersCount) diff --git a/frontend/Locales/en.json b/frontend/Locales/en.json index b488436..831e3aa 100644 --- a/frontend/Locales/en.json +++ b/frontend/Locales/en.json @@ -66,6 +66,11 @@ "generateInvoice": "Generate invoice", "cancel": "Cancel" }, + "notificationsFeed": { + "emptyTitle": "You don't have notifications", + "emptyDescription": "Write a message to get replies and reactions.", + "emptyButton": "Write a message" + }, "profileCreatePage": { "notifications": { "copied": "Private key copied.\n\nSave this key on a safe place." @@ -90,10 +95,17 @@ }, "contactsFeed": { "notifications": { + "keyCopied": "Public key copied.", "contactAdded": "Profile followed.", "addContactError": "There was an error publishing your changes.", "contactRemoved": "Profile unfollowed." }, + "emptyTitleFollowing": "You are not following no one", + "emptyDescriptionFollowing": "Follow other profiles to see content.", + "emptyButtonFollowing": "Paste public key", + "emptyTitleFollower": "You have no followers", + "emptyDescriptionFollower": "Share your public key so people can start following you.", + "emptyButtonFollower": "Copy public key", "cancel": "Cancelar", "addContact": "Añadir contacto", "addContactDescription": "Pega la clave pública de quien desees añadir.", @@ -108,6 +120,11 @@ "nostr": "nostr", "nips": "NIPs" }, + "homeFeed": { + "emptyTitle": "You are not following no one", + "emptyDescription": "Follow other profiles to see content.", + "emptyButton": "Go to contacts" + }, "relaysPage": { "labelAdd": "Dirección de relay", "cancel": "Cancelar", @@ -125,8 +142,8 @@ "nsecCopied": "Clave secreta copiada.", "npubCopied": "Clave pública copiada.", "profilePublished": "Perfil publicado.", - "lud06Published": "LUD-06 publicado.", - "nip05Published": "NIP-05 publicado.", + "lud06Published": "LUD-06 publicado.\n\n{{lud06}}", + "nip05Published": "NIP-05 publicado.\n\n{{nip05}}", "picturePublished": "Picture publicado.", "connectionError": "Error de conexión" }, @@ -181,12 +198,15 @@ "copyNPub": "Copiar clave" }, "conversationsFeed": { - "openMessage": "Iniciar conversación", - "openMessageLabel": "Clave pública", - "openMessageDescription": "Pega una clave pública para iniciar una conversación.", - "openMessageTitle": "Iniciar conversación con clave pública", - "addPubKey": "Iniciar conversación con clave pública", - "newMessageContact": "Iniciar conversación con contacto" + "openMessage": "Start conversation", + "openMessageLabel": "Public key", + "openMessageDescription": "Paste a public key to start a conversation.", + "openMessageTitle": "Start conversation with public key", + "addPubKey": "Start conversation with public key", + "newMessageContact": "Start conversation with contact", + "emptyTitle": "You don't have any message", + "emptyDescription": "Write direct messages to your contacts or others.", + "emptyButton": "Open a conversation" } } } diff --git a/frontend/Pages/ContactsFeed/index.tsx b/frontend/Pages/ContactsFeed/index.tsx index 18d1060..cb49087 100644 --- a/frontend/Pages/ContactsFeed/index.tsx +++ b/frontend/Pages/ContactsFeed/index.tsx @@ -24,6 +24,7 @@ import { AnimatedFAB, Button, Divider, + Snackbar, Text, TextInput, TouchableRipple, @@ -33,11 +34,11 @@ import { Tabs, TabScreen } from 'react-native-paper-tabs' import NostrosAvatar from '../../Components/NostrosAvatar' import { navigate } from '../../lib/Navigation' import RBSheet from 'react-native-raw-bottom-sheet' -import NostrosNotification from '../../Components/NostrosNotification' +import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons' export const ContactsFeed: React.FC = () => { const { database } = useContext(AppContext) - const { publicKey, setContantsCount, setFollowersCount } = React.useContext(UserContext) + const { publicKey, setContantsCount, setFollowersCount, nPub } = React.useContext(UserContext) const { relayPool, lastEventId } = useContext(RelayPoolContext) const theme = useTheme() const bottomSheetAddContactRef = React.useRef(null) @@ -192,28 +193,77 @@ export const ContactsFeed: React.FC = () => { > - - - 0 ? ( + + + + + + ) : ( + + + + {t('contactsFeed.emptyTitleFollowing')} + + + {t('contactsFeed.emptyDescriptionFollowing')} + + - + )} - - - 0 ? ( + + + + + + ) : ( + + + + {t('contactsFeed.emptyTitleFollower')} + + + {t('contactsFeed.emptyDescriptionFollower')} + + - + )} @@ -269,12 +319,15 @@ export const ContactsFeed: React.FC = () => { {showNotification && ( - setShowNotification(undefined)} + onDismiss={() => setShowNotification(undefined)} > - {t(`contactsFeed.notifications.${showNotification}`)} - + {t(`contactsFeed.notifications.${showNotification}`)} + )} ) @@ -284,6 +337,10 @@ const styles = StyleSheet.create({ container: { flex: 1, }, + snackbar: { + margin: 16, + marginBottom: 95, + }, contactRow: { paddingLeft: 16, paddingRight: 16, @@ -306,6 +363,16 @@ const styles = StyleSheet.create({ right: 16, position: 'absolute', }, + center: { + alignContent: 'center', + textAlign: 'center', + }, + blank: { + justifyContent: 'space-between', + height: 232, + marginTop: 12, + padding: 16, + }, }) export default ContactsFeed diff --git a/frontend/Pages/ConversationsFeed/index.tsx b/frontend/Pages/ConversationsFeed/index.tsx index 0a46158..e9a6845 100644 --- a/frontend/Pages/ConversationsFeed/index.tsx +++ b/frontend/Pages/ConversationsFeed/index.tsx @@ -158,6 +158,7 @@ export const ConversationsFeed: React.FC = () => { /> ), onPress: async () => bottomSheetUserListRef.current?.open(), + disabled: users?.length === 0, }, { key: 2, @@ -168,6 +169,7 @@ export const ConversationsFeed: React.FC = () => { /> ), onPress: async () => bottomSheetPubKeyRef.current?.open(), + disabled: false, }, ] }, []) @@ -199,14 +201,29 @@ export const ConversationsFeed: React.FC = () => { ) return ( - - - - + + {directMessages.length > 0 ? ( + + + + ) : ( + + + + {t('conversationsFeed.emptyTitle')} + + + {t('conversationsFeed.emptyDescription')} + + + + )} { title={item.title} onPress={item.onPress} left={item.left} + disabled={item.disabled} /> ) }} @@ -290,6 +308,7 @@ export const ConversationsFeed: React.FC = () => { const styles = StyleSheet.create({ container: { flex: 1, + padding: 16, }, contactRow: { paddingLeft: 16, @@ -317,6 +336,15 @@ const styles = StyleSheet.create({ right: 16, position: 'absolute', }, + center: { + alignContent: 'center', + textAlign: 'center', + }, + blank: { + justifyContent: 'space-between', + height: 200, + marginTop: 60, + }, }) export default ConversationsFeed diff --git a/frontend/Pages/HomeFeed/index.tsx b/frontend/Pages/HomeFeed/index.tsx index 04dbda0..20b2169 100644 --- a/frontend/Pages/HomeFeed/index.tsx +++ b/frontend/Pages/HomeFeed/index.tsx @@ -16,14 +16,20 @@ import { UserContext } from '../../Contexts/UserContext' import { RelayPoolContext } from '../../Contexts/RelayPoolContext' import { EventKind } from '../../lib/nostr/Events' import { RelayFilters } from '../../lib/nostr/RelayPool/intex' -import { ActivityIndicator, AnimatedFAB } from 'react-native-paper' +import { ActivityIndicator, AnimatedFAB, Button, Text } from 'react-native-paper' import NoteCard from '../../Components/NoteCard' import RBSheet from 'react-native-raw-bottom-sheet' import ProfileCard from '../../Components/ProfileCard' import { useTheme } from '@react-navigation/native' import { navigate } from '../../lib/Navigation' +import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons' +import { t } from 'i18next' -export const HomeFeed: React.FC = () => { +interface HomeFeedProps { + jumpTo: (tabName: string) => void +} + +export const HomeFeed: React.FC = ({ jumpTo }) => { const theme = useTheme() const { database } = useContext(AppContext) const { publicKey } = useContext(UserContext) @@ -139,8 +145,8 @@ export const HomeFeed: React.FC = () => { }, []) return ( - <> - {notes && notes.length > 0 && ( + + {notes && notes.length > 0 ? ( { {notes.map((note) => renderItem(note))} {notes.length >= 10 && } + ) : ( + + + + {t('homeFeed.emptyTitle')} + + + {t('homeFeed.emptyDescription')} + + + )} { > - + ) } @@ -184,6 +203,19 @@ const styles = StyleSheet.create({ right: 16, position: 'absolute', }, + container: { + padding: 16, + flex: 1, + }, + center: { + alignContent: 'center', + textAlign: 'center', + }, + blank: { + justifyContent: 'space-between', + height: 200, + marginTop: 60, + }, }) export default HomeFeed diff --git a/frontend/Pages/NotificationsFeed/index.tsx b/frontend/Pages/NotificationsFeed/index.tsx index 2f97bf8..500add5 100644 --- a/frontend/Pages/NotificationsFeed/index.tsx +++ b/frontend/Pages/NotificationsFeed/index.tsx @@ -15,11 +15,15 @@ import { EventKind } from '../../lib/nostr/Events' import { handleInfinityScroll } from '../../Functions/NativeFunctions' import { UserContext } from '../../Contexts/UserContext' import RBSheet from 'react-native-raw-bottom-sheet' -import { ActivityIndicator, useTheme } from 'react-native-paper' +import { ActivityIndicator, Button, Text, useTheme } from 'react-native-paper' import ProfileCard from '../../Components/ProfileCard' +import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons' +import { useTranslation } from 'react-i18next' +import { navigate } from '../../lib/Navigation' export const NotificationsFeed: React.FC = () => { const theme = useTheme() + const { t } = useTranslation('common') const { database } = useContext(AppContext) const { publicKey } = useContext(UserContext) const initialPageSize = 10 @@ -134,18 +138,30 @@ export const NotificationsFeed: React.FC = () => { }, []) return ( - <> - {notes && notes.length > 0 && ( + + {notes && notes.length > 0 ? ( } - style={styles.list} > {notes.map((note) => renderItem(note))} {notes.length >= 10 && } + ) : ( + + + + {t('notificationsFeed.emptyTitle')} + + + {t('notificationsFeed.emptyDescription')} + + + )} { > - + ) } const styles = StyleSheet.create({ - list: { + container: { + flex: 1, padding: 16, }, noteCard: { marginBottom: 16, }, + center: { + alignContent: 'center', + textAlign: 'center', + }, + blank: { + justifyContent: 'space-between', + height: 200, + marginTop: 60, + }, }) export default NotificationsFeed diff --git a/frontend/Pages/ProfileConfigPage/index.tsx b/frontend/Pages/ProfileConfigPage/index.tsx index 17bd116..4be4e37 100644 --- a/frontend/Pages/ProfileConfigPage/index.tsx +++ b/frontend/Pages/ProfileConfigPage/index.tsx @@ -15,10 +15,10 @@ import { Text, TouchableRipple, TextInput, + Snackbar, } from 'react-native-paper' import { RelayPoolContext } from '../../Contexts/RelayPoolContext' import RBSheet from 'react-native-raw-bottom-sheet' -import NostrosNotification from '../../Components/NostrosNotification' import NostrosAvatar from '../../Components/NostrosAvatar' export const ProfileConfigPage: React.FC = () => { @@ -478,14 +478,15 @@ export const ProfileConfigPage: React.FC = () => { {showNotification && ( - setShowNotification(undefined)} + onDismiss={() => setShowNotification(undefined)} > - {t(`profileConfigPage.notifications.${showNotification}`)} - {showNotification === 'nip05Published' && {nip05}} - {showNotification === 'lud06Published' && {lnurl}} - + {t(`profileConfigPage.notifications.${showNotification}`, { nip05, lnurl })} + )} ) diff --git a/frontend/Pages/ProfileCreatePage/index.tsx b/frontend/Pages/ProfileCreatePage/index.tsx index ecd3785..be092a0 100644 --- a/frontend/Pages/ProfileCreatePage/index.tsx +++ b/frontend/Pages/ProfileCreatePage/index.tsx @@ -65,7 +65,12 @@ export const ProfileCreatePage: React.FC = ({ navigation {t('profileCreatePage.warningDescription')} - @@ -97,7 +102,7 @@ const styles = StyleSheet.create({ }, snackbar: { margin: 16, - width: '100%' + width: '100%', }, warning: { borderRadius: 4, diff --git a/frontend/Pages/ProfilePage/index.tsx b/frontend/Pages/ProfilePage/index.tsx index 1242186..0f4a39b 100644 --- a/frontend/Pages/ProfilePage/index.tsx +++ b/frontend/Pages/ProfilePage/index.tsx @@ -8,7 +8,14 @@ import { StyleSheet, View, } from 'react-native' -import { Surface, Text, IconButton, ActivityIndicator, useTheme } from 'react-native-paper' +import { + Surface, + Text, + IconButton, + ActivityIndicator, + useTheme, + Snackbar, +} from 'react-native-paper' import NostrosAvatar from '../../Components/NostrosAvatar' import { AppContext } from '../../Contexts/AppContext' import { UserContext } from '../../Contexts/UserContext' @@ -16,9 +23,8 @@ import { RelayPoolContext } from '../../Contexts/RelayPoolContext' import { getNotes, Note } from '../../Functions/DatabaseFunctions/Notes' import { getUser, updateUserContact, User } from '../../Functions/DatabaseFunctions/Users' import { EventKind } from '../../lib/nostr/Events' -import { populatePets } from '../../Functions/RelayFunctions/Users' +import { populatePets, username } from '../../Functions/RelayFunctions/Users' import { useTranslation } from 'react-i18next' -import NostrosNotification from '../../Components/NostrosNotification' import { npubEncode } from 'nostr-tools/nip19' import { RelayFilters } from '../../lib/nostr/RelayPool/intex' import NoteCard from '../../Components/NoteCard' @@ -86,6 +92,10 @@ export const ProfilePage: React.FC = ({ route }) => { if (result) { setUser(result) setIsContact(result?.contact) + } else if (route.params.pubKey === publicKey) { + setUser({ + id: publicKey, + }) } }) } @@ -97,12 +107,14 @@ export const ProfilePage: React.FC = ({ route }) => { (results) => { setNotes(results) setRefreshing(false) - relayPool?.subscribe('answers-profile', [ - { - kinds: [EventKind.reaction, EventKind.textNote, EventKind.recommendServer], - '#e': results.map((note) => note.id ?? ''), - }, - ]) + if (results.length > 0) { + relayPool?.subscribe('answers-profile', [ + { + kinds: [EventKind.reaction, EventKind.textNote, EventKind.recommendServer], + '#e': results.map((note) => note.id ?? ''), + }, + ]) + } }, ) } @@ -189,7 +201,7 @@ export const ProfilePage: React.FC = ({ route }) => { - {user?.name} + {user && username(user)} {/* */} {user?.nip05} @@ -265,12 +277,15 @@ export const ProfilePage: React.FC = ({ route }) => { )} {showNotification && ( - setShowNotification(undefined)} + onDismiss={() => setShowNotification(undefined)} > - {t(`profilePage.${showNotification}`)} - + {t(`profilePage.${showNotification}`)} + )} { const defaultRelayInput = React.useMemo(() => 'wss://', []) @@ -111,12 +111,15 @@ export const RelaysPage: React.FC = () => { extended={false} /> {showNotification && ( - setShowNotification(undefined)} + onDismiss={() => setShowNotification(undefined)} > {t(`relaysPage.notifications.${showNotification}`)} - + )}