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

Settings: Payments: allow the user to change their default fee limit #1256

Merged
4 changes: 4 additions & 0 deletions Navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import Sponsors from './views/Settings/Sponsors';
import Olympians from './views/Settings/Olympians';
import Gods from './views/Settings/Gods';
import Mortals from './views/Settings/Mortals';
import PaymentsSettings from './views/Settings/PaymentsSettings';

// Routing
import Routing from './views/Routing/Routing';
Expand Down Expand Up @@ -239,6 +240,9 @@ const AppScenes = {
},
SparkQRScanner: {
screen: SparkQRScanner
},
PaymentsSettings: {
screen: PaymentsSettings
}
};

Expand Down
3 changes: 3 additions & 0 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,10 @@
"views.Settings.Display.defaultView": "Default view",
"views.Settings.Display.displayNickname": "Display node nickname on main views",
"views.Settings.privacy": "Privacy",
"views.Settings.payments": "Payments",
"views.Settings.Privacy.title": "Privacy settings",
"views.Settings.Payments.title": "Payments settings",
"views.Settings.Payments.defaultFeeLimit": "Default Fee Limit",
"views.Settings.Privacy.blockExplorer": "Default Block explorer",
"views.Settings.Privacy.customBlockExplorer": "Custom Block explorer",
"views.Settings.Privacy.lurkerMode": "Lurker mode",
Expand Down
12 changes: 12 additions & 0 deletions stores/SettingsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ interface DisplaySettings {
displayNickname?: boolean;
}

interface PaymentSettings {
defaultFeeMethod?: string;
defaultFeePercentage?: string;
defaultFeeFixed?: string;
}

interface Settings {
nodes?: Array<Node>;
selectedNode?: number;
Expand All @@ -53,6 +59,7 @@ interface Settings {
locale?: string;
privacy: PrivacySettings;
display: DisplaySettings;
payments: PaymentSettings;
}

export const BLOCK_EXPLORER_KEYS = [
Expand Down Expand Up @@ -185,6 +192,11 @@ export default class SettingsStore {
defaultView: 'Keypad',
displayNickname: false
},
payments: {
defaultFeeMethod: 'fixed',
defaultFeePercentage: '0.5',
defaultFeeFixed: '100'
},
scramblePin: true,
loginBackground: false,
fiat: DEFAULT_FIAT
Expand Down
22 changes: 17 additions & 5 deletions views/PaymentRequest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,24 @@ export default class PaymentRequest extends React.Component<
maxParts: '16',
maxShardAmt: '',
feeLimitSat: '100',
feeOption: 'sats',
feeOption: 'fixed',
Copy link
Contributor

@otech47 otech47 Jan 10, 2023

Choose a reason for hiding this comment

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

For improved type-safety, maybe we should use an enum for this and update the InvoiceState and PaymentSettings interfaces

Copy link
Contributor

@kaloudis kaloudis Jan 18, 2023

Choose a reason for hiding this comment

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

Agree with this. Spoke with Ovidio and agreed to tackle enums more broadly - throughout the app - in another issue.

Copy link
Contributor

Choose a reason for hiding this comment

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

Tracking here: #1262

maxFeePercent: '0.5',
outgoingChanId: null,
lastHopPubkey: null
};

async UNSAFE_componentWillMount() {
const { SettingsStore } = this.props;
const { getSettings } = SettingsStore;
const settings = await getSettings();

this.setState({
feeOption: settings.payments.defaultFeeMethod || 'fixed',
feeLimitSat: settings.payments.defaultFeeFixed || '100',
maxFeePercent: settings.payments.defaultFeePercentage || '0.5'
});
}

subscribePayment = (streamingCall: string) => {
const { handlePayment, handlePaymentError } =
this.props.TransactionsStore;
Expand Down Expand Up @@ -148,7 +160,7 @@ export default class PaymentRequest extends React.Component<
this.props;
let feeLimitSat = fee_limit_sat;

if (feeOption == 'sats') {
if (feeOption == 'fixed') {
// If the fee limit is not set, use a default routing fee calculation
if (!fee_limit_sat) {
const { pay_req } = InvoicesStore;
Expand Down Expand Up @@ -469,7 +481,7 @@ export default class PaymentRequest extends React.Component<
style={{
width: '50%',
opacity:
feeOption == 'sats'
feeOption == 'fixed'
? 1
: 0.25
}}
Expand All @@ -482,7 +494,7 @@ export default class PaymentRequest extends React.Component<
}
onPressIn={() =>
this.setState({
feeOption: 'sats'
feeOption: 'fixed'
})
}
/>
Expand All @@ -493,7 +505,7 @@ export default class PaymentRequest extends React.Component<
top: 28,
right: 30,
opacity:
feeOption == 'sats'
feeOption == 'fixed'
? 1
: 0.25
}}
Expand Down
213 changes: 213 additions & 0 deletions views/Settings/PaymentsSettings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
import * as React from 'react';
import { Text, View } from 'react-native';
import { Header, Icon } from 'react-native-elements';
import { inject, observer } from 'mobx-react';
import SettingsStore from '../../stores/SettingsStore';
import { localeString } from '../../utils/LocaleUtils';
import { themeColor } from '../../utils/ThemeUtils';

import LoadingIndicator from '../../components/LoadingIndicator';
import TextInput from '../../components/TextInput';

interface PaymentsSettingsProps {
navigation: any;
SettingsStore: SettingsStore;
}

interface PaymentsSettingsState {
feeLimitMethod: string;
feeLimit: string;
feePercentage: string;
}

@inject('SettingsStore')
@observer
export default class PaymentsSettings extends React.Component<
PaymentsSettingsProps,
PaymentsSettingsState
> {
state = {
feeLimitMethod: 'fixed',
feeLimit: '100',
feePercentage: '0.5'
};

async UNSAFE_componentWillMount() {
const { SettingsStore } = this.props;
const { getSettings } = SettingsStore;
const settings = await getSettings();

this.setState({
feeLimitMethod: settings.payments.defaultFeeMethod || 'fixed',
feeLimit: settings.payments.defaultFeeFixed || '100',
feePercentage: settings.payments.defaultFeePercentage || '0.5'
});
}

handleSave = async () => {
const { feeLimitMethod, feeLimit, feePercentage } = this.state;
const { SettingsStore } = this.props;
const { updateSettings } = SettingsStore;
await updateSettings({
payments: {
defaultFeeMethod: feeLimitMethod,
defaultFeePercentage: feePercentage,
defaultFeeFixed: feeLimit
}
});
};

renderSeparator = () => (
<View
style={{
height: 1,
backgroundColor: themeColor('separator')
}}
/>
);

render() {
const { navigation, SettingsStore } = this.props;
const { feeLimit, feeLimitMethod, feePercentage } = this.state;
const { loading }: any = SettingsStore;

const BackButton = () => (
<Icon
name="arrow-back"
onPress={() => {
this.handleSave();
navigation.navigate('Settings', {
refresh: true
});
}}
color={themeColor('text')}
underlayColor="transparent"
/>
);

return (
<View
style={{
flex: 1,
backgroundColor: themeColor('background')
}}
>
<Header
leftComponent={<BackButton />}
centerComponent={{
text: localeString('views.Settings.Payments.title'),
style: {
color: themeColor('text'),
fontFamily: 'Lato-Regular'
}
}}
backgroundColor={themeColor('background')}
containerStyle={{
borderBottomWidth: 0
}}
/>
{loading ? (
<LoadingIndicator />
) : (
<View
style={{
padding: 20
}}
>
<Text
style={{
fontFamily: 'Lato-Regular',
paddingTop: 5,
color: themeColor('text')
}}
>
{`${localeString(
'views.Settings.Payments.defaultFeeLimit'
)}`}
</Text>
<View
style={{
flex: 1,
flexWrap: 'wrap',
flexDirection: 'row',
justifyContent: 'flex-end',
opacity: feeLimitMethod == 'percent' ? 1 : 0.25
}}
></View>
<View
style={{
flexDirection: 'row',
width: '95%'
}}
>
<TextInput
style={{
width: '50%',
opacity:
feeLimitMethod == 'fixed' ? 1 : 0.25
}}
keyboardType="numeric"
value={feeLimit}
onChangeText={(text: string) =>
this.setState({
feeLimit: text
})
}
onPressIn={() =>
this.setState({
feeLimitMethod: 'fixed'
})
}
/>
<Text
style={{
fontFamily: 'Lato-Regular',
paddingTop: 5,
color: themeColor('text'),
top: 28,
right: 30,
opacity:
feeLimitMethod == 'fixed' ? 1 : 0.25
}}
>
{`${localeString('general.sats')}`}
</Text>
<TextInput
style={{
width: '50%',
opacity:
feeLimitMethod == 'percent' ? 1 : 0.25
}}
keyboardType="numeric"
value={feePercentage}
onChangeText={(text: string) =>
this.setState({
feePercentage: text
})
}
onPressIn={() =>
this.setState({
feeLimitMethod: 'percent'
})
}
/>
<Text
style={{
fontFamily: 'Lato-Regular',
paddingTop: 5,
color: themeColor('text'),
top: 28,
right: 18,
opacity:
feeLimitMethod == 'percent' ? 1 : 0.25
}}
>
{'%'}
</Text>
</View>
</View>
)}
</View>
);
}
}
Loading