From 093f4478073d37c27d282bb7756b56aee39d867c Mon Sep 17 00:00:00 2001 From: shubham Date: Thu, 18 Jul 2024 21:47:47 +0530 Subject: [PATCH 1/5] Load noteKey on start + display if the notes are available or not on Activity view --- stores/NotesStore.ts | 20 +++++++++ views/Activity/Activity.tsx | 88 ++++++++++++++++++++++++++++++++++++- views/Wallet/Wallet.tsx | 10 ++++- 3 files changed, 115 insertions(+), 3 deletions(-) diff --git a/stores/NotesStore.ts b/stores/NotesStore.ts index 930fc7f18..5d01f4178 100644 --- a/stores/NotesStore.ts +++ b/stores/NotesStore.ts @@ -6,6 +6,10 @@ const NOTES_KEY = 'note-Keys'; export default class NotesStore { @observable public noteKeys: string[] = []; + constructor() { + this.loadNoteKeys(); + } + @action public storeNoteKeys = async (key: string, notes: string) => { if (!this.noteKeys.includes(key)) { @@ -26,6 +30,22 @@ export default class NotesStore { } }; + @action + public async loadNoteKeys() { + console.log('Loading note keys...'); + try { + const storedKeys = await EncryptedStorage.getItem(NOTES_KEY); + if (storedKeys) { + this.noteKeys = JSON.parse(storedKeys); + } + } catch (error) { + console.error( + 'Error loading note keys from encrypted storage', + error + ); + } + } + writeNoteKeysToLocalStorage = async () => { try { await EncryptedStorage.setItem( diff --git a/views/Activity/Activity.tsx b/views/Activity/Activity.tsx index 61f8d9c05..cb31870d6 100644 --- a/views/Activity/Activity.tsx +++ b/views/Activity/Activity.tsx @@ -27,6 +27,7 @@ import ActivityStore from '../../stores/ActivityStore'; import FiatStore from '../../stores/FiatStore'; import PosStore from '../../stores/PosStore'; import SettingsStore from '../../stores/SettingsStore'; +import NotesStore from '../../stores/NotesStore'; import { SATS_PER_BTC } from '../../stores/UnitsStore'; import Filter from '../../assets/images/SVG/Filter On.svg'; @@ -38,6 +39,7 @@ interface ActivityProps { FiatStore: FiatStore; PosStore: PosStore; SettingsStore: SettingsStore; + NotesStore: NotesStore; route: Route<'Activity', { order: any }>; } @@ -45,7 +47,7 @@ interface ActivityState { selectedPaymentForOrder: any; } -@inject('ActivityStore', 'FiatStore', 'PosStore', 'SettingsStore') +@inject('ActivityStore', 'FiatStore', 'PosStore', 'SettingsStore', 'NotesStore') @observer export default class Activity extends React.PureComponent< ActivityProps, @@ -139,6 +141,7 @@ export default class Activity extends React.PureComponent< FiatStore, PosStore, SettingsStore, + NotesStore, route } = this.props; const { selectedPaymentForOrder } = this.state; @@ -225,6 +228,51 @@ export default class Activity extends React.PureComponent< ); + const hasMatchingNoteKey = (item: any, noteKeys: string[]): boolean => { + const strippedNoteKeys = noteKeys.map((key) => + key.replace(/^note-/, '') + ); + + const isMatchingValue = ( + value: any, + strippedNoteKeys: string[] + ): boolean => { + if ( + (typeof value === 'string' || typeof value === 'number') && + value.toString().length === 64 + ) { + const valueString = value.toString(); + for (let key of strippedNoteKeys) { + console.log( + `Comparing item value: ${valueString} with noteKey: ${key}` + ); + if (key === valueString) { + console.log(`Match found: ${valueString}`); + return true; + } + } + } + return false; + }; + + let valuesToCompare: string[] = []; + if (item.model === 'Invoice') { + valuesToCompare = [item.getRPreimage, item.payment_hash]; + } else if (item.model === 'Payment') { + valuesToCompare = [item.paymentHash, item.getPreimage]; + } else if (item.model === 'Transaction') { + valuesToCompare = [item.tx]; + } + + for (let value of valuesToCompare) { + if (isMatchingValue(value, strippedNoteKeys)) { + return true; + } + } + + return false; + }; + return (
{ + const noteKeys = NotesStore?.noteKeys; + const hasNotes = hasMatchingNoteKey(item, noteKeys); + let displayName = item.model; let subTitle = item.model; @@ -563,6 +614,41 @@ export default class Activity extends React.PureComponent< )} + + + Notes + + + + {hasNotes + ? 'Notes Available' + : 'No Notes'} + + diff --git a/views/Wallet/Wallet.tsx b/views/Wallet/Wallet.tsx index 64df5f943..671a8e6bd 100644 --- a/views/Wallet/Wallet.tsx +++ b/views/Wallet/Wallet.tsx @@ -69,6 +69,7 @@ import SettingsStore, { import SyncStore from '../../stores/SyncStore'; import UnitsStore from '../../stores/UnitsStore'; import UTXOsStore from '../../stores/UTXOsStore'; +import NotesStore from '../../stores/NotesStore'; import Bitcoin from '../../assets/images/SVG/Bitcoin.svg'; import CaretUp from '../../assets/images/SVG/Caret Up.svg'; @@ -93,6 +94,7 @@ interface WalletProps { ModalStore: ModalStore; SyncStore: SyncStore; LSPStore: LSPStore; + NotesStore: NotesStore; ChannelBackupStore: ChannelBackupStore; LightningAddressStore: LightningAddressStore; LnurlPayStore: LnurlPayStore; @@ -118,7 +120,8 @@ interface WalletState { 'LSPStore', 'LnurlPayStore', 'ChannelBackupStore', - 'LightningAddressStore' + 'LightningAddressStore', + 'NotesStore' ) @observer export default class Wallet extends React.Component { @@ -299,7 +302,8 @@ export default class Wallet extends React.Component { ChannelBackupStore, SyncStore, LightningAddressStore, - LnurlPayStore + LnurlPayStore, + NotesStore } = this.props; const { settings, @@ -345,6 +349,8 @@ export default class Wallet extends React.Component { LnurlPayStore.reset(); + NotesStore?.loadNoteKeys(); + if ( pos?.posEnabled && pos.posEnabled !== PosEnabled.Disabled && From b1316e6ad74e68ee0d9af52f37b1c96be2f61619 Mon Sep 17 00:00:00 2001 From: shubham Date: Tue, 23 Jul 2024 20:23:52 +0530 Subject: [PATCH 2/5] Refactor NotesStore to add notes and improve note retrieval in Activity view --- stores/NotesStore.ts | 16 +++++- views/Activity/Activity.tsx | 108 ++++++++++++++---------------------- 2 files changed, 56 insertions(+), 68 deletions(-) diff --git a/stores/NotesStore.ts b/stores/NotesStore.ts index 5d01f4178..f88236050 100644 --- a/stores/NotesStore.ts +++ b/stores/NotesStore.ts @@ -5,6 +5,7 @@ const NOTES_KEY = 'note-Keys'; export default class NotesStore { @observable public noteKeys: string[] = []; + @observable public notes: { [key: string]: string } = {}; constructor() { this.loadNoteKeys(); @@ -12,6 +13,8 @@ export default class NotesStore { @action public storeNoteKeys = async (key: string, notes: string) => { + this.notes[key] = notes; + if (!this.noteKeys.includes(key)) { if (notes) { this.noteKeys.push(key); @@ -25,18 +28,27 @@ export default class NotesStore { const index = this.noteKeys.indexOf(key); if (index !== -1) { this.noteKeys.splice(index, 1); - // write updated keys to storage + delete this.notes[key]; await this.writeNoteKeysToLocalStorage(); } }; @action public async loadNoteKeys() { - console.log('Loading note keys...'); + console.log('Loading notes...'); try { const storedKeys = await EncryptedStorage.getItem(NOTES_KEY); if (storedKeys) { this.noteKeys = JSON.parse(storedKeys); + // Load all notes + await Promise.all( + this.noteKeys.map(async (key) => { + const note = await EncryptedStorage.getItem(key); + if (note) { + this.notes[key] = note; + } + }) + ); } } catch (error) { console.error( diff --git a/views/Activity/Activity.tsx b/views/Activity/Activity.tsx index cb31870d6..97658186b 100644 --- a/views/Activity/Activity.tsx +++ b/views/Activity/Activity.tsx @@ -141,7 +141,6 @@ export default class Activity extends React.PureComponent< FiatStore, PosStore, SettingsStore, - NotesStore, route } = this.props; const { selectedPaymentForOrder } = this.state; @@ -228,33 +227,12 @@ export default class Activity extends React.PureComponent< ); - const hasMatchingNoteKey = (item: any, noteKeys: string[]): boolean => { - const strippedNoteKeys = noteKeys.map((key) => + const getMatchingNote = (item: any) => { + const { NotesStore } = this.props; + const strippedNoteKeys = NotesStore.noteKeys.map((key) => key.replace(/^note-/, '') ); - const isMatchingValue = ( - value: any, - strippedNoteKeys: string[] - ): boolean => { - if ( - (typeof value === 'string' || typeof value === 'number') && - value.toString().length === 64 - ) { - const valueString = value.toString(); - for (let key of strippedNoteKeys) { - console.log( - `Comparing item value: ${valueString} with noteKey: ${key}` - ); - if (key === valueString) { - console.log(`Match found: ${valueString}`); - return true; - } - } - } - return false; - }; - let valuesToCompare: string[] = []; if (item.model === 'Invoice') { valuesToCompare = [item.getRPreimage, item.payment_hash]; @@ -265,12 +243,15 @@ export default class Activity extends React.PureComponent< } for (let value of valuesToCompare) { - if (isMatchingValue(value, strippedNoteKeys)) { - return true; + const matchKey = `note-${value}`; + if ( + strippedNoteKeys.includes(value) && + NotesStore.notes[matchKey] + ) { + return NotesStore.notes[matchKey]; } } - - return false; + return null; }; return ( @@ -303,8 +284,7 @@ export default class Activity extends React.PureComponent< { - const noteKeys = NotesStore?.noteKeys; - const hasNotes = hasMatchingNoteKey(item, noteKeys); + const note = getMatchingNote(item); let displayName = item.model; let subTitle = item.model; @@ -614,41 +594,37 @@ export default class Activity extends React.PureComponent< )} - - - Notes - - - - {hasNotes - ? 'Notes Available' - : 'No Notes'} - - + {note && ( + + + {localeString( + 'general.note' + )} + + + + {note} + + + )} From 4739416b428125d8c6bb7bbd3c9d9bdff06708fe Mon Sep 17 00:00:00 2001 From: shubham Date: Tue, 3 Sep 2024 16:58:59 +0530 Subject: [PATCH 3/5] Fix note overlapping and limit display to 100 chars --- views/Activity/Activity.tsx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/views/Activity/Activity.tsx b/views/Activity/Activity.tsx index 97658186b..93627a59f 100644 --- a/views/Activity/Activity.tsx +++ b/views/Activity/Activity.tsx @@ -603,8 +603,13 @@ export default class Activity extends React.PureComponent< 'text' ), fontFamily: - 'Lato-Regular' + 'Lato-Regular', + flexShrink: 0, + flex: 0, + width: 'auto', + overflow: 'hidden' }} + numberOfLines={1} > {localeString( 'general.note' @@ -618,10 +623,18 @@ export default class Activity extends React.PureComponent< 'secondaryText' ), fontFamily: - 'Lato-Regular' + 'Lato-Regular', + flexWrap: 'wrap', + flexShrink: 1 }} + ellipsizeMode="tail" > - {note} + {note.length > 150 + ? `${note.substring( + 0, + 150 + )}...` + : note} )} From 468ba57dd8b80325b277148126e624bca11a5d45 Mon Sep 17 00:00:00 2001 From: shubham Date: Tue, 10 Sep 2024 17:41:54 +0530 Subject: [PATCH 4/5] Using getNoteKeys function and refactoring for notes on separate views --- views/Activity/Activity.tsx | 1 - views/AddNotes.tsx | 17 +++++++---------- views/Invoice.tsx | 18 ++++++++++-------- views/Payment.tsx | 16 +++++++++------- views/Transaction.tsx | 19 +++++++++++++------ 5 files changed, 39 insertions(+), 32 deletions(-) diff --git a/views/Activity/Activity.tsx b/views/Activity/Activity.tsx index 131f0c069..d0ba9ca99 100644 --- a/views/Activity/Activity.tsx +++ b/views/Activity/Activity.tsx @@ -234,7 +234,6 @@ export default class Activity extends React.PureComponent< // Use the getNoteKey from the model const noteKey = item.getNoteKey; - // for (let matchKey of noteKeys) { if (noteKey && notes[noteKey]) { return notes[noteKey]; } diff --git a/views/AddNotes.tsx b/views/AddNotes.tsx index b91cffe70..663152e6a 100644 --- a/views/AddNotes.tsx +++ b/views/AddNotes.tsx @@ -53,11 +53,10 @@ export default class AddNotes extends React.Component< }; } async componentDidMount() { - const key: string = - 'note-' + - (this.state.txid || - this.state.payment_hash || - this.state.getRPreimage); + const key: any = + this.state.txid || + this.state.payment_hash || + this.state.getRPreimage; const storedNotes = await EncryptedStorage.getItem(key); if (storedNotes) { this.setState({ notes: storedNotes, isNoteStored: true }); @@ -71,8 +70,7 @@ export default class AddNotes extends React.Component< const { notes } = this.state; const saveNote = async () => { - const key: string = - 'note-' + (payment_hash || txid || getRPreimage); + const key: any = payment_hash || txid || getRPreimage; EncryptedStorage.setItem(key, notes); await storeNoteKeys(key, notes); navigation.goBack(); @@ -119,9 +117,8 @@ export default class AddNotes extends React.Component< onChangeText={(text: string) => { this.setState({ notes: text }); if (!text) { - const key: string = - 'note-' + - (payment_hash || txid || getRPreimage); + const key: any = + payment_hash || txid || getRPreimage; removeNoteKeys(key); } }} diff --git a/views/Invoice.tsx b/views/Invoice.tsx index b5734b34d..cfb7955f0 100644 --- a/views/Invoice.tsx +++ b/views/Invoice.tsx @@ -38,8 +38,8 @@ export default class InvoiceView extends React.Component { const { navigation, route } = this.props; const invoice = route.params?.invoice; navigation.addListener('focus', () => { - const noteKey = invoice.getRPreimage || invoice.payment_hash; - EncryptedStorage.getItem('note-' + noteKey) + const noteKey = invoice.getNoteKey; + EncryptedStorage.getItem(noteKey) .then((storedNotes) => { this.setState({ storedNotes }); }) @@ -72,10 +72,10 @@ export default class InvoiceView extends React.Component { getPaymentRequest, getKeysendMessage, is_amp, - value + value, + getNoteKey } = invoice; const privateInvoice = invoice.private; - const noteKey = getRPreimage || payment_hash; const QRButton = () => ( { const EditNotesButton = () => ( - navigation.navigate('AddNotes', { getRPreimage: noteKey }) + navigation.navigate('AddNotes', { + getRPreimage: getNoteKey + }) } style={{ marginRight: 15 }} > @@ -295,7 +297,7 @@ export default class InvoiceView extends React.Component { sensitive mempoolLink={() => navigation.navigate('AddNotes', { - getRPreimage: noteKey + getRPreimage: getNoteKey }) } /> @@ -303,7 +305,7 @@ export default class InvoiceView extends React.Component { - {noteKey && ( + {getNoteKey && (