Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AddNotes: Add notes after payment #1447

Merged
merged 11 commits into from
May 30, 2023
4 changes: 4 additions & 0 deletions Navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import ImportAccount from './views/Accounts/ImportAccount';
import ImportAccountQRScanner from './views/Accounts/ImportAccountQRScanner';
import BumpFee from './views/BumpFee';
import QR from './views/QR';
import AddNotes from './views/AddNotes';

// POS
import Order from './views/Order';
Expand Down Expand Up @@ -258,6 +259,9 @@ const AppScenes = {
},
QR: {
screen: QR
},
AddNotes: {
screen: AddNotes
}
};

Expand Down
3 changes: 3 additions & 0 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@
"views.Payment.creationDate": "Creation Date",
"views.Payment.path": "Path",
"views.Payment.paths": "Paths",
"views.Payment.notes": "Notes",
"views.PaymentRequest.title": "Lightning Invoice",
"views.PaymentRequest.error": "Error loading invoice",
"views.PaymentRequest.customAmt": "Custom Amount",
Expand Down Expand Up @@ -444,6 +445,8 @@
"views.SendingLightning.sending": "Sending Transaction",
"views.SendingLightning.success": "Transaction successfully sent",
"views.SendingLightning.paymentHash": "Payment Hash",
"views.SendingLightning.AddANote": "Add a note",
"views.SendingLightning.UpdateNote": "Update note",
"views.SendingLightning.goToWallet": "Go to Wallet",
"views.SendingLightning.lowFeeLimitMessage": "This payment may have failed due to a low fee limit. Try again with a higher fee limit",
"views.SendingLightning.tryAgain": "Try Again",
Expand Down
123 changes: 123 additions & 0 deletions views/AddNotes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import * as React from 'react';
import { View, TextInput } from 'react-native';
import EncryptedStorage from 'react-native-encrypted-storage';

import Header from '../components/Header';
import Screen from '../components/Screen';
import Button from '../components/Button';

import { localeString } from '../utils/LocaleUtils';
import { themeColor } from '../utils/ThemeUtils';

interface AddNotesProps {
navigation: any;
}
interface AddNotesState {
notes?: string;
payment_hash?: string;
txid?: string;
RPreimage?: string;
}
const noteKeys: string[] = [];

export default class AddNotes extends React.Component<
AddNotesProps,
AddNotesState
> {
constructor(props: any) {
super(props);
const payment_hash: string = this.props.navigation.getParam(
'payment_hash',
null
);
const txid: string = this.props.navigation.getParam('txid', null);
const RPreimage: string = this.props.navigation.getParam(
'getRPreimage',
null
);

this.state = {
notes: '',
payment_hash,
txid,
RPreimage
};
}
async componentDidMount() {
const key: any =
'note-' +
(this.state.txid ||
this.state.payment_hash ||
this.state.RPreimage);
const storedNotes = await EncryptedStorage.getItem(key);
if (storedNotes) {
this.setState({ notes: storedNotes });
}
}

render() {
const { navigation } = this.props;
const { payment_hash, txid, RPreimage } = this.state;
const { notes } = this.state;
return (
<Screen>
<Header
leftComponent="Back"
centerComponent={{
text: notes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this text shouldn't be dependent on whether the note in the state is set, rather if a previous note has been saved

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same with the button at the bottom of this view

? localeString('views.SendingLightning.UpdateNote')
: localeString('views.SendingLightning.AddANote'),
style: {
color: themeColor('text'),
fontFamily: 'Lato-Regular',
fontSize: 20
}
}}
navigation={navigation}
/>
<View style={{ padding: 20 }}>
<TextInput
onChangeText={(text: string) => {
this.setState({ notes: text });
if (!text) {
const key: any =
Copy link
Contributor

@kaloudis kaloudis May 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type is string here

'note-' +
(payment_hash || txid || RPreimage);
const index = noteKeys.indexOf(key);
if (index !== -1) {
noteKeys.splice(index, 1);
}
}
}}
multiline
numberOfLines={0}
style={{ fontSize: 20, color: themeColor('text') }}
value={notes}
/>
</View>
<Button
title={
notes
? localeString('views.SendingLightning.UpdateNote')
: localeString('views.SendingLightning.AddANote')
}
onPress={async () => {
navigation.goBack();
const key: any =
'note-' + (payment_hash || txid || RPreimage);
await EncryptedStorage.setItem(key, notes);
if (!noteKeys.includes(key)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be populated when you load the note, or perhaps in a a separate note store.

You also need to add logic to remove it from the index if the user deletes the note

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added the logic to remove keys from noteKeys array, in onChangeText prop

noteKeys.push(key);
await EncryptedStorage.setItem(
'note-Keys',
JSON.stringify(noteKeys)
);
}
}}
containerStyle={{ position: 'absolute', bottom: 40 }}
buttonStyle={{ padding: 15 }}
/>
</Screen>
);
}
}
96 changes: 86 additions & 10 deletions views/Invoice.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,47 @@
import * as React from 'react';
import { StyleSheet, ScrollView, View } from 'react-native';
import EncryptedStorage from 'react-native-encrypted-storage';

import { StyleSheet, ScrollView, View, TouchableOpacity } from 'react-native';
import { Icon } from 'react-native-elements';

import Amount from '../components/Amount';
import Header from '../components/Header';
import KeyValue from '../components/KeyValue';
import Screen from '../components/Screen';
import Button from '../components/Button';
import { Row } from '../components/layout/Row';

import Invoice from '../models/Invoice';

import { localeString } from '../utils/LocaleUtils';
import { themeColor } from '../utils/ThemeUtils';

import EditNotes from '../assets/images/SVG/Pen.svg';

interface InvoiceProps {
navigation: any;
}

export default class InvoiceView extends React.Component<InvoiceProps> {
state = {
storedNotes: ''
};
async componentDidMount() {
const { navigation } = this.props;
const invoice: Invoice = navigation.getParam('invoice', null);
navigation.addListener('didFocus', () => {
EncryptedStorage.getItem('note-' + invoice.getRPreimage)
.then((storedNotes) => {
this.setState({ storedNotes });
})
.catch((error) => {
console.error('Error retrieving notes:', error);
});
});
}
render() {
const { navigation } = this.props;
const { storedNotes } = this.state;
const invoice: Invoice = navigation.getParam('invoice', null);
const {
fallback_addr,
Expand All @@ -37,14 +60,26 @@ export default class InvoiceView extends React.Component<InvoiceProps> {
const privateInvoice = invoice.private;

const QRButton = () => (
<Icon
name="qr-code"
onPress={() => {
navigation.navigate('QR', { value: getPaymentRequest });
}}
color={themeColor('text')}
underlayColor="transparent"
/>
<View style={{ marginTop: -12 }}>
<Icon
name="qr-code"
onPress={() => {
navigation.navigate('QR', { value: getPaymentRequest });
}}
color={themeColor('text')}
underlayColor="transparent"
/>
</View>
);
const EditNotesButton = () => (
<TouchableOpacity
onPress={() =>
navigation.navigate('AddNotes', { getRPreimage })
}
style={{ marginTop: -12, alignSelf: 'center', marginRight: 6 }}
>
<EditNotes height={40} width={40} />
</TouchableOpacity>
);

return (
Expand All @@ -58,7 +93,12 @@ export default class InvoiceView extends React.Component<InvoiceProps> {
fontFamily: 'Lato-Regular'
}
}}
rightComponent={!!getPaymentRequest && <QRButton />}
rightComponent={
<Row>
<EditNotesButton />
{!!getPaymentRequest && <QRButton />}
</Row>
}
navigation={navigation}
/>
<ScrollView>
Expand Down Expand Up @@ -163,6 +203,42 @@ export default class InvoiceView extends React.Component<InvoiceProps> {
sensitive
/>
)}
{storedNotes && (
<TouchableOpacity
onPress={() =>
navigation.navigate('AddNotes', {
getRPreimage
})
}
>
<KeyValue
keyValue={localeString(
'views.Payment.notes'
)}
value={storedNotes}
sensitive
/>
</TouchableOpacity>
)}
{getRPreimage && (
<Button
title={
storedNotes
? localeString(
'views.SendingLightning.UpdateNote'
)
: localeString(
'views.SendingLightning.AddANote'
)
}
onPress={() =>
navigation.navigate('AddNotes', {
getRPreimage
})
}
containerStyle={{ marginTop: 15 }}
/>
)}

{!!getDescriptionHash && (
<KeyValue
Expand Down