diff --git a/App.tsx b/App.tsx
index 8925c5324..5511129bd 100644
--- a/App.tsx
+++ b/App.tsx
@@ -214,6 +214,7 @@ export default class App extends React.PureComponent {
InventoryStore={Stores.inventoryStore}
ModalStore={Stores.modalStore}
NotesStore={Stores.notesStore}
+ ContactStore={Stores.contactStore}
SyncStore={Stores.syncStore}
LSPStore={Stores.lspStore}
LightningAddressStore={Stores.lightningAddressStore}
diff --git a/stores/ContactStore.ts b/stores/ContactStore.ts
new file mode 100644
index 000000000..8fa70f46c
--- /dev/null
+++ b/stores/ContactStore.ts
@@ -0,0 +1,151 @@
+import { action, observable } from 'mobx';
+import { v4 as uuidv4 } from 'uuid';
+import Contact from '../models/Contact';
+import EncryptedStorage from 'react-native-encrypted-storage';
+
+export default class ContactStore {
+ @observable public loading: boolean = true;
+ @observable public contacts: any = [];
+ @observable public prefillContact: any = {};
+
+ @action
+ public loadContacts = async () => {
+ try {
+ this.loading = true;
+ console.log('LOADING CONTACTS.....');
+ const contactsString = await EncryptedStorage.getItem(
+ 'zeus-contacts'
+ );
+ if (contactsString) {
+ const allContacts: Contact[] = JSON.parse(contactsString);
+ this.contacts = allContacts;
+ this.loading = false;
+ } else {
+ this.loading = false;
+ }
+ } catch (error) {
+ console.log('Error loading contacts:', error);
+ this.loading = false;
+ }
+ };
+
+ @action
+ public saveContact = async (
+ contactDetails: any,
+ isEdit: boolean,
+ isNostrContact: boolean,
+ navigation: any
+ ) => {
+ try {
+ const contactsString = await EncryptedStorage.getItem(
+ 'zeus-contacts'
+ );
+ const existingContacts: Contact[] = contactsString
+ ? JSON.parse(contactsString)
+ : [];
+
+ if (isEdit && this.prefillContact && !isNostrContact) {
+ const updatedContacts = existingContacts.map((contact) =>
+ contact.contactId === this.prefillContact.contactId
+ ? { ...contact, ...contactDetails }
+ : contact
+ );
+
+ // Sort the updated contacts alphabetically
+ updatedContacts.sort((a, b) => a.name.localeCompare(b.name));
+
+ // Save the updated contacts to encrypted storage
+ await EncryptedStorage.setItem(
+ 'zeus-contacts',
+ JSON.stringify(updatedContacts)
+ );
+
+ console.log('Contact updated successfully!', updatedContacts);
+
+ this.loadContacts();
+ navigation.popTo('Contacts');
+ } else {
+ // Creating a new contact
+ const contactId = uuidv4();
+
+ const newContact: Contact = { contactId, ...contactDetails };
+
+ const updatedContacts = [...existingContacts, newContact].sort(
+ (a, b) => a.name.localeCompare(b.name)
+ );
+
+ // Save the updated contacts to encrypted storage
+ await EncryptedStorage.setItem(
+ 'zeus-contacts',
+ JSON.stringify(updatedContacts)
+ );
+
+ console.log('Contact saved successfully!');
+
+ this.loadContacts();
+ navigation.popTo('Contacts');
+ }
+ // Clear the prefillContact after saving
+ this.clearPrefillContact();
+ } catch (error) {
+ console.log('Error saving contacts:', error);
+ }
+ };
+
+ @action
+ public deleteContact = async (navigation: any) => {
+ if (this.prefillContact) {
+ try {
+ const contactsString = await EncryptedStorage.getItem(
+ 'zeus-contacts'
+ );
+ const existingContacts: Contact[] = contactsString
+ ? JSON.parse(contactsString)
+ : [];
+
+ const updatedContacts = existingContacts.filter(
+ (contact) =>
+ contact.contactId !== this.prefillContact.contactId
+ );
+
+ await EncryptedStorage.setItem(
+ 'zeus-contacts',
+ JSON.stringify(updatedContacts)
+ );
+
+ console.log('Contact deleted successfully!');
+
+ this.loadContacts();
+ navigation.popTo('Contacts');
+ } catch (error) {
+ console.log('Error deleting contact:', error);
+ }
+ }
+ };
+
+ @action
+ public setPrefillContact = (prefillContact: Contact | null) => {
+ if (prefillContact) {
+ this.prefillContact = {
+ lnAddress: prefillContact.lnAddress,
+ bolt12Address: prefillContact.bolt12Address,
+ onchainAddress: prefillContact.onchainAddress,
+ nip05: prefillContact.nip05,
+ nostrNpub: prefillContact.nostrNpub,
+ pubkey: prefillContact.pubkey,
+ name: prefillContact.name,
+ description: prefillContact.description,
+ photo: prefillContact.photo,
+ isFavourite: prefillContact.isFavourite,
+ contactId: prefillContact?.contactId
+ };
+ } else {
+ this.prefillContact = null;
+ }
+ };
+
+ @action
+ public clearPrefillContact = () => {
+ this.prefillContact = null;
+ };
+}
diff --git a/stores/Stores.ts b/stores/Stores.ts
index 8ca702269..cd64e0f69 100644
--- a/stores/Stores.ts
+++ b/stores/Stores.ts
@@ -16,6 +16,7 @@ import ActivityStore from './ActivityStore';
import PosStore from './PosStore';
import ModalStore from './ModalStore';
import NotesStore from './NotesStore';
+import ContactStore from './ContactStore';
import SyncStore from './SyncStore';
import LSPStore from './LSPStore';
import LightningAddressStore from './LightningAddressStore';
@@ -42,6 +43,7 @@ class Stores {
public posStore: PosStore;
public modalStore: ModalStore;
public notesStore: NotesStore;
+ public contactStore: ContactStore;
public syncStore: SyncStore;
public lspStore: LSPStore;
public lightningAddressStore: LightningAddressStore;
@@ -101,6 +103,7 @@ class Stores {
this.utxosStore = new UTXOsStore(this.settingsStore);
this.messageSignStore = new MessageSignStore();
this.notesStore = new NotesStore();
+ this.contactStore = new ContactStore();
this.syncStore = new SyncStore(this.settingsStore);
this.activityStore = new ActivityStore(
this.settingsStore,
diff --git a/views/ContactDetails.tsx b/views/ContactDetails.tsx
index bcc93ff80..33e92c3eb 100644
--- a/views/ContactDetails.tsx
+++ b/views/ContactDetails.tsx
@@ -7,6 +7,7 @@ import {
TouchableOpacity,
ScrollView
} from 'react-native';
+import { inject, observer } from 'mobx-react';
import EncryptedStorage from 'react-native-encrypted-storage';
import { Route } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
@@ -17,6 +18,8 @@ import LoadingIndicator from '../components/LoadingIndicator';
import Header from '../components/Header';
import { Row } from '../components/layout/Row';
+import ContactStore from '../stores/ContactStore';
+
import LightningBolt from '../assets/images/SVG/Lightning Bolt.svg';
import BitcoinIcon from '../assets/images/SVG/BitcoinIcon.svg';
import KeySecurity from '../assets/images/SVG/Key Security.svg';
@@ -41,6 +44,7 @@ interface ContactDetailsProps {
nostrContact: any;
}
>;
+ ContactStore: ContactStore;
}
interface ContactDetailsState {
@@ -48,6 +52,9 @@ interface ContactDetailsState {
isLoading: boolean;
isNostrContact: boolean;
}
+
+@inject('ContactStore')
+@observer
export default class ContactDetails extends React.Component<
ContactDetailsProps,
ContactDetailsState
@@ -136,6 +143,7 @@ export default class ContactDetails extends React.Component<
};
saveUpdatedContact = async (updatedContact: Contact) => {
+ const { ContactStore } = this.props;
try {
const contactsString = await EncryptedStorage.getItem(
'zeus-contacts'
@@ -160,6 +168,7 @@ export default class ContactDetails extends React.Component<
);
console.log('Contact updated successfully!');
+ ContactStore?.loadContacts();
}
}
} catch (error) {
@@ -212,7 +221,8 @@ export default class ContactDetails extends React.Component<
render() {
const { isLoading, isNostrContact } = this.state;
- const { navigation } = this.props;
+ const { navigation, ContactStore } = this.props;
+ const { setPrefillContact } = ContactStore;
const contact = new Contact(this.state.contact);
const nostrContact = this.props.route.params?.nostrContact;
@@ -229,12 +239,12 @@ export default class ContactDetails extends React.Component<
const EditContactButton = () => (
+ onPress={() => {
+ setPrefillContact(contact);
navigation.navigate('AddContact', {
- prefillContact: contact,
isEdit: true
- })
- }
+ });
+ }}
>
{
navigation.goBack();
+ setPrefillContact(nostrContact);
navigation.navigate('AddContact', {
- prefillContact: nostrContact,
isEdit: true,
isNostrContact
});
diff --git a/views/NostrContacts.tsx b/views/NostrContacts.tsx
index 961393068..03c0fe4f9 100644
--- a/views/NostrContacts.tsx
+++ b/views/NostrContacts.tsx
@@ -9,6 +9,7 @@ import {
Animated,
Easing
} from 'react-native';
+import { inject, observer } from 'mobx-react';
import { CheckBox, Icon } from 'react-native-elements';
import EncryptedStorage from 'react-native-encrypted-storage';
import { relayInit, nip05, nip19 } from 'nostr-tools';
@@ -28,12 +29,14 @@ import { localeString } from '../utils/LocaleUtils';
import { themeColor } from '../utils/ThemeUtils';
import { DEFAULT_NOSTR_RELAYS } from '../stores/SettingsStore';
+import ContactStore from '../stores/ContactStore';
import SelectOff from '../assets/images/SVG/Select Off.svg';
import SelectOn from '../assets/images/SVG/Select On.svg';
interface NostrContactsProps {
navigation: StackNavigationProp;
+ ContactStore: ContactStore;
}
interface NostrContactsState {
@@ -49,6 +52,8 @@ interface NostrContactsState {
error: string;
}
+@inject('ContactStore')
+@observer
export default class NostrContacts extends React.Component<
NostrContactsProps,
NostrContactsState
@@ -367,6 +372,7 @@ export default class NostrContacts extends React.Component<
};
importContacts = async () => {
+ const { ContactStore } = this.props;
this.setState({
loading: true
});
@@ -420,6 +426,8 @@ export default class NostrContacts extends React.Component<
);
console.log('Contacts imported successfully!');
+
+ ContactStore?.loadContacts();
this.setState({
loading: false
});
diff --git a/views/Settings/AddContact.tsx b/views/Settings/AddContact.tsx
index 97c0b2809..6394bb01e 100644
--- a/views/Settings/AddContact.tsx
+++ b/views/Settings/AddContact.tsx
@@ -11,8 +11,7 @@ import {
Text,
TextInput
} from 'react-native';
-import { v4 as uuidv4 } from 'uuid';
-import EncryptedStorage from 'react-native-encrypted-storage';
+import { inject, observer } from 'mobx-react';
import { Icon, Divider } from 'react-native-elements';
import { launchImageLibrary } from 'react-native-image-picker';
import RNFS from 'react-native-fs';
@@ -29,6 +28,8 @@ import AddressUtils from '../../utils/AddressUtils';
import { getPhoto } from '../../utils/PhotoUtils';
import { themeColor } from '../../utils/ThemeUtils';
+import ContactStore from '../../stores/ContactStore';
+
import LightningBolt from '../../assets/images/SVG/Lightning Bolt.svg';
import BitcoinIcon from '../../assets/images/SVG/BitcoinIcon.svg';
import KeySecurity from '../../assets/images/SVG/Key Security.svg';
@@ -39,10 +40,8 @@ import Star from '../../assets/images/SVG/Star.svg';
interface AddContactProps {
navigation: StackNavigationProp;
- route: Route<
- 'AddContact',
- { isEdit: boolean; prefillContact: Contact; isNostrContact: boolean }
- >;
+ route: Route<'AddContact', { isEdit: boolean; isNostrContact: boolean }>;
+ ContactStore: ContactStore;
}
interface Contact {
@@ -84,6 +83,8 @@ interface AddContactState {
isValidPubkey: boolean;
}
+@inject('ContactStore')
+@observer
export default class AddContact extends React.Component<
AddContactProps,
AddContactState
@@ -128,144 +129,21 @@ export default class AddContact extends React.Component<
};
saveContact = async () => {
- const { navigation, route } = this.props;
- const {
- lnAddress,
- bolt12Address,
- bolt12Offer,
- onchainAddress,
- nip05,
- nostrNpub,
- pubkey,
- name,
- description,
- photo,
- isFavourite
- } = this.state;
-
- const { isEdit, prefillContact, isNostrContact } = route.params ?? {};
-
- try {
- // Retrieve existing contacts from storage
- const contactsString = await EncryptedStorage.getItem(
- 'zeus-contacts'
- );
- const existingContacts: Contact[] = contactsString
- ? JSON.parse(contactsString)
- : [];
-
- if (isEdit && prefillContact && !isNostrContact) {
- // Editing an existing contact
- const updatedContacts = existingContacts.map((contact) =>
- contact.contactId === prefillContact.contactId
- ? {
- ...contact,
- lnAddress,
- bolt12Address,
- bolt12Offer,
- onchainAddress,
- nip05,
- nostrNpub,
- pubkey,
- name,
- description,
- photo,
- isFavourite
- }
- : contact
- );
-
- // Sort the updated contacts alphabetically
- updatedContacts.sort((a, b) => a.name.localeCompare(b.name));
-
- // Save the updated contacts to encrypted storage
- await EncryptedStorage.setItem(
- 'zeus-contacts',
- JSON.stringify(updatedContacts)
- );
-
- console.log('Contact updated successfully!');
- navigation.popTo('Contacts');
- } else {
- // Creating a new contact
- const contactId = uuidv4();
-
- const newContact: Contact = {
- contactId,
- lnAddress,
- bolt12Address,
- bolt12Offer,
- onchainAddress,
- nip05,
- nostrNpub,
- pubkey,
- name,
- description,
- photo,
- isFavourite
- };
-
- const updatedContacts = [...existingContacts, newContact].sort(
- (a, b) => a.name.localeCompare(b.name)
- );
-
- // Save the updated contacts to encrypted storage
- await EncryptedStorage.setItem(
- 'zeus-contacts',
- JSON.stringify(updatedContacts)
- );
-
- console.log('Contact saved successfully!');
- navigation.popTo('Contacts');
-
- // Reset the input fields after saving the contact
- this.setState({
- contacts: updatedContacts,
- lnAddress: [],
- bolt12Address: [],
- bolt12Offer: [],
- onchainAddress: [],
- nip05: [],
- nostrNpub: [],
- pubkey: [],
- name: '',
- description: '',
- photo: null
- });
- }
- } catch (error) {
- console.log('Error saving contacts:', error);
- }
+ const { navigation, route, ContactStore } = this.props;
+ const { isEdit, isNostrContact } = route.params ?? {};
+ const contactDetails = { ...this.state };
+ await ContactStore.saveContact(
+ contactDetails,
+ isEdit,
+ isNostrContact,
+ navigation
+ );
};
deleteContact = async () => {
- const { navigation, route } = this.props;
- const prefillContact = route.params?.prefillContact;
+ const { navigation, ContactStore } = this.props;
- if (prefillContact) {
- try {
- const contactsString = await EncryptedStorage.getItem(
- 'zeus-contacts'
- );
- const existingContacts: Contact[] = contactsString
- ? JSON.parse(contactsString)
- : [];
-
- const updatedContacts = existingContacts.filter(
- (contact) => contact.contactId !== prefillContact.contactId
- );
-
- await EncryptedStorage.setItem(
- 'zeus-contacts',
- JSON.stringify(updatedContacts)
- );
-
- console.log('Contact deleted successfully!');
- navigation.popTo('Contacts');
- } catch (error) {
- console.log('Error deleting contact:', error);
- }
- }
+ await ContactStore?.deleteContact(navigation);
};
selectPhoto = () => {
@@ -373,37 +251,25 @@ export default class AddContact extends React.Component<
}
componentDidUpdate(prevProps: AddContactProps) {
- const prefillContact = this.props.route.params?.prefillContact;
- const prevPrefillContact = prevProps.route.params?.prefillContact;
-
- // Check if the prefillContact prop has changed
- if (prefillContact !== prevPrefillContact) {
+ const { ContactStore } = this.props;
+ if (
+ ContactStore.prefillContact !==
+ prevProps.ContactStore.prefillContact
+ ) {
this.handlePrefillContact();
}
}
- handlePrefillContact() {
- const prefillContact = this.props.route.params?.prefillContact;
+ handlePrefillContact = () => {
+ const { ContactStore } = this.props;
- if (prefillContact) {
- this.setState({
- lnAddress: prefillContact.lnAddress,
- bolt12Address: prefillContact.bolt12Address,
- bolt12Offer: prefillContact.bolt12Offer,
- onchainAddress: prefillContact.onchainAddress,
- nip05: prefillContact.nip05,
- nostrNpub: prefillContact.nostrNpub,
- pubkey: prefillContact.pubkey,
- name: prefillContact.name,
- description: prefillContact.description,
- photo: prefillContact.photo,
- isFavourite: prefillContact.isFavourite
- });
+ if (ContactStore.prefillContact) {
+ this.setState({ ...ContactStore.prefillContact });
}
- }
+ };
render() {
- const { navigation } = this.props;
+ const { navigation, ContactStore } = this.props;
const {
lnAddress,
bolt12Address,
@@ -481,7 +347,7 @@ export default class AddContact extends React.Component<
/>
);
- const { isEdit, prefillContact } = this.props.route.params ?? {};
+ const { isEdit } = this.props.route.params ?? {};
const ScanBadge = ({
navigation
@@ -521,6 +387,9 @@ export default class AddContact extends React.Component<
}
+ onBack={() => {
+ ContactStore?.clearPrefillContact();
+ }}
containerStyle={{
borderBottomWidth: 0
}}
@@ -1555,7 +1424,7 @@ export default class AddContact extends React.Component<
}
/>
- {isEdit && prefillContact && (
+ {isEdit && ContactStore?.prefillContact && (