Merge pull request #2764 from ecency/feat/GU-2746/recurrent-transfer

feat: 2746 add recurrent transfer feature for hive
This commit is contained in:
Feruz M 2023-11-01 18:04:29 +02:00 committed by GitHub
commit 6e7d13d66f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 391 additions and 54 deletions

View File

@ -20,7 +20,7 @@ PODS:
- boost (1.76.0)
- BugsnagReactNative (7.19.0):
- React-Core
- BVLinearGradient (2.6.2):
- BVLinearGradient (2.8.3):
- React-Core
- CocoaAsyncSocket (7.6.5)
- DoubleConversion (1.1.6)
@ -998,7 +998,7 @@ SPEC CHECKSUMS:
AppCenterReactNativeShared: f395caeabde0dc3a11609dbcb737d0f14cd40e79
boost: a7c83b31436843459a1961bfd74b96033dc77234
BugsnagReactNative: fa312f53a83ca21c0afdfeaec98a9c5eeb8fc4ed
BVLinearGradient: 34a999fda29036898a09c6a6b728b0b4189e1a44
BVLinearGradient: 880f91a7854faff2df62518f0281afb1c60d49a3
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
FBLazyVector: a6454570f573a0f6f1d397e5a95c13e8e45d1700
@ -1112,4 +1112,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 6b212d63236c21489948e9b73b59fcff2feeeb08
COCOAPODS: 1.11.3
COCOAPODS: 1.13.0

View File

@ -126,7 +126,7 @@
"react-native-iphone-x-helper": "Norcy/react-native-iphone-x-helper",
"react-native-keyboard-aware-scroll-view": "^0.9.1",
"react-native-level-fs": "^3.0.0",
"react-native-linear-gradient": "^2.4.2",
"react-native-linear-gradient": "^2.8.3",
"react-native-media-controls": "^2.3.0",
"react-native-modal": "13.0.1",
"react-native-modal-dropdown": "^1.0.2",
@ -220,11 +220,6 @@
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"jest": {
"preset": "react-native"
},

View File

@ -15,3 +15,8 @@ const reactotron = Reactotron.setAsyncStorageHandler(AsyncStorage) // AsyncStora
.connect(); // let's connect!
export default reactotron;
export const log = (...rest) => {
Reactotron.log(...rest);
console.log(...rest);
};

View File

@ -78,7 +78,7 @@ const DropdownButtonView = ({
}}
style={[!style ? styles.button : style]}
textStyle={[textStyle || styles.buttonText]}
dropdownStyle={[styles.dropdown, dropdownStyle, { height: 32 * (options.length + 1.5) }]}
dropdownStyle={[styles.dropdown, dropdownStyle, { height: 32 * (options.length + 0.8) }]}
dropdownTextStyle={[dropdownTextStyle || styles.dropdownText]}
dropdownTextHighlightStyle={styles.dropdownTextHighlight}
options={options}

View File

@ -107,7 +107,7 @@ class SettingsItemView extends PureComponent {
return (
<View style={styles.wrapper}>
<Text style={[styles.text, titleStyle]}>{title}</Text>
{!!title && <Text style={[styles.text, titleStyle]}>{title}</Text>}
{this._renderItem()}
</View>
);

View File

@ -19,7 +19,7 @@ export const calculateTimeLeftForPostCheck = (firstPost: any) => {
// filter posts that are not present in top 5 posts currently in list.
export const filterLatestPosts = (fetchedPosts: any[], cachedPosts: any[]) => {
console.log('Comparing: ', fetchedPosts, cachedPosts);
// console.log('Comparing: ', fetchedPosts, cachedPosts);
const latestPosts = [];
fetchedPosts.forEach((post) => {

View File

@ -31,6 +31,7 @@ export interface TransferAccountSelectorProps {
memo: string;
setMemo: (value: string) => void;
spkMarkets: Market[];
getRecurrentTransferOfUser: (username: string) => string;
}
const TransferAccountSelector = ({
@ -50,6 +51,7 @@ const TransferAccountSelector = ({
memo,
setMemo,
spkMarkets,
getRecurrentTransferOfUser,
}: TransferAccountSelectorProps) => {
const intl = useIntl();
const destinationRef = useRef('');
@ -91,10 +93,16 @@ const TransferAccountSelector = ({
return;
}
const isValid = res.includes(username);
if (isValid) {
getRecurrentTransferOfUser(username);
}
setIsUsernameValid(isValid);
});
}, 300),
[],
[getRecurrentTransferOfUser],
);
const _handleOnChange = (state: string, val: string) => {

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useIntl } from 'react-intl';
import { Text, TouchableOpacity, View } from 'react-native';
import TextInput from '../textInput';
@ -7,6 +7,8 @@ import { TransferFormItem } from '../transferFormItem';
// Styles
import styles from './transferAmountInputSectionStyles';
import TransferTypes from '../../constants/transferTypes';
import DropdownButton from '../dropdownButton';
import { dateToFormatted } from '../../utils/time';
export interface TransferAmountInputSectionProps {
balance: number;
@ -18,6 +20,10 @@ export interface TransferAmountInputSectionProps {
setMemo: (value: string) => void;
amount: string;
setAmount: (value: string) => void;
recurrence: string;
setRecurrence: (value: string) => void;
executions: string;
setExecutions: (value: string) => void;
hsTransfer: boolean;
transferType: string;
selectedAccount: any;
@ -26,6 +32,24 @@ export interface TransferAmountInputSectionProps {
disableMinimum?: boolean;
}
export const RECURRENCE_TYPES = [
{
key: 'daily',
hours: 24,
intlId: 'leaderboard.daily',
},
{
key: 'weekly',
hours: 168,
intlId: 'leaderboard.weekly',
},
{
key: 'monthly',
hours: 731,
intlId: 'leaderboard.monthly',
},
];
const TransferAmountInputSection = ({
balance,
getAccountsWithUsername,
@ -36,39 +60,50 @@ const TransferAmountInputSection = ({
setMemo,
amount,
setAmount,
transferType,
fundType,
disableMinimum,
transferType,
recurrence,
setRecurrence,
executions,
setExecutions,
startDate,
onNext,
}) => {
const intl = useIntl();
const dpRef = useRef();
const _handleOnChange = (state, val) => {
let _amount = val.toString();
if (_amount.includes(',')) {
_amount = val.replace(',', '.');
let newValue = val.toString();
if (newValue.includes(',')) {
newValue = val.replace(',', '.');
}
if (state === 'amount') {
if (parseFloat(Number(_amount)) <= parseFloat(balance)) {
setAmount(_amount);
if (parseFloat(Number(newValue)) <= parseFloat(balance)) {
setAmount(newValue);
}
}
if (state === 'destination') {
} else if (state === 'destination') {
getAccountsWithUsername(val).then((res) => {
console.log(res);
const isValid = res.includes(val);
setIsUsernameValid(isValid);
});
setDestination(_amount);
}
if (state === 'memo') {
setMemo(_amount);
setDestination(newValue);
} else if (state === 'memo') {
setMemo(newValue);
} else if (state === 'executions') {
setExecutions(val);
}
};
const _renderInput = (placeholder, state, keyboardType, isTextArea) => (
<TextInput
style={[isTextArea ? styles.textarea : styles.input]}
onChangeText={(amount) => _handleOnChange(state, amount)}
onChangeText={(newVal) => _handleOnChange(state, newVal)}
value={
state === 'destination'
? destination
@ -76,6 +111,8 @@ const TransferAmountInputSection = ({
? amount
: state === 'memo'
? memo
: state === 'executions'
? executions
: ''
}
placeholder={placeholder}
@ -87,8 +124,38 @@ const TransferAmountInputSection = ({
/>
);
const [recurrenceIndex, setRecurrenceIndex] = useState(
RECURRENCE_TYPES.findIndex((r) => r.hours === recurrence),
);
useEffect(() => {
const newSelectedIndex = RECURRENCE_TYPES.findIndex((r) => r.hours === +recurrence);
setRecurrenceIndex(newSelectedIndex);
if (newSelectedIndex > -1) {
setRecurrence(RECURRENCE_TYPES[newSelectedIndex].hours);
}
if (dpRef?.current) {
dpRef.current.select(newSelectedIndex);
}
}, [recurrence, dpRef]);
const _handleRecurrenceChange = useCallback((index: number) => {
setRecurrenceIndex(index);
setRecurrence(RECURRENCE_TYPES[index].hours);
}, []);
const _onDelete = () => {
onNext(true);
}
const _renderDescription = (text) => <Text style={styles.description}>{text}</Text>;
const _renderCenterDescription = (text) => <Text style={styles.centerDescription}>{text}</Text>;
const _renderCenterDescription = (text, extraStyles = {}) => (
<Text style={[styles.centerDescription, extraStyles]}>{text}</Text>
);
const amountLimitText = disableMinimum
? ''
@ -105,6 +172,16 @@ const TransferAmountInputSection = ({
{ suffix: amountLimitText },
)}
</Text>
{startDate && startDate !== '' && (
<TouchableOpacity onPress={_onDelete}>
<Text style={[styles.sectionSubheading, styles.dangerDescription]}>
{intl.formatMessage({ id: 'transfer.delete_recurrent_transfer' }) +
dateToFormatted(startDate, 'LL')}
</Text>
</TouchableOpacity>
)}
<TransferFormItem
label={intl.formatMessage({ id: 'transfer.amount' })}
rightComponent={() =>
@ -124,8 +201,41 @@ const TransferAmountInputSection = ({
</TouchableOpacity>
)}
/>
{transferType === TransferTypes.RECURRENT_TRANSFER && (
<>
<TransferFormItem
label={intl.formatMessage({ id: 'transfer.recurrence' })}
rightComponent={() => (
<DropdownButton
dropdownButtonStyle={styles.dropdownButtonStyle}
rowTextStyle={styles.rowTextStyle}
style={styles.dropdown}
dropdownStyle={styles.dropdownStyle}
textStyle={styles.dropdownText}
options={RECURRENCE_TYPES.map((k) => intl.formatMessage({ id: k.intlId }))}
defaultText={intl.formatMessage({ id: 'transfer.recurrence_placeholder' })}
selectedOptionIndex={recurrenceIndex}
onSelect={(index) => _handleRecurrenceChange(index)}
dropdownRef={dpRef}
/>
)}
/>
<TransferFormItem
label={intl.formatMessage({ id: 'transfer.executions' })}
rightComponent={() =>
_renderInput(
intl.formatMessage({ id: 'transfer.executions_placeholder' }),
'executions',
'numeric',
false,
)
}
/>
</>
)}
{(transferType === TransferTypes.POINTS ||
transferType === TransferTypes.TRANSFER_TOKEN ||
transferType === TransferTypes.RECURRENT_TRANSFER ||
transferType === TransferTypes.TRANSFER_TO_SAVINGS ||
transferType === TransferTypes.TRANSFER_ENGINE ||
transferType === TransferTypes.TRANSFER_SPK ||
@ -143,6 +253,7 @@ const TransferAmountInputSection = ({
containerStyle={{ height: 80 }}
/>
)}
{(transferType === TransferTypes.POINTS || transferType === TransferTypes.TRANSFER_TOKEN) && (
<TransferFormItem
rightComponentStyle={styles.transferItemRightStyle}

View File

@ -59,6 +59,10 @@ export default EStyleSheet.create({
color: '$primaryBlack',
fontWeight: '600',
},
dangerDescription: {
color: 'red',
fontWeight: '700',
},
transferItemContainer: {
height: 20,
},
@ -82,4 +86,28 @@ export default EStyleSheet.create({
fontWeight: '600',
textAlign: 'left',
},
dropdownText: {
fontSize: 14,
paddingLeft: 12,
paddingHorizontal: 14,
// color: '$primaryDarkGray',
color: '$primaryBlack',
},
dropdownStyle: {
marginTop: 15,
minWidth: 192,
width: 192,
maxHeight: 300,
},
dropdownButtonStyle: {
borderColor: '$borderColor',
borderWidth: 1,
height: 44,
width: '100%',
borderRadius: 8,
},
dropdown: {
flexGrow: 1,
width: 150,
},
});

View File

@ -11,12 +11,12 @@ const api = axios.create({
});
api.interceptors.request.use((request) => {
console.log('Starting api Request', request);
// console.log('Starting api Request', request);
return request;
});
api.interceptors.response.use((response) => {
console.log('Response:', response);
// console.log('Response:', response);
return response;
});

View File

@ -18,7 +18,7 @@ const ecencyApi = axios.create({
});
ecencyApi.interceptors.request.use((request) => {
console.log('Starting ecency Request', request);
// console.log(`Starting ecency Request`, request);
// skip code addition is register and token refresh endpoint is triggered
if (
@ -68,7 +68,7 @@ ecencyApi.interceptors.request.use((request) => {
});
ecencyApi.interceptors.response.use((response) => {
console.log('Response:', response);
// console.log('Response:', response);
return response;
});

View File

@ -12,12 +12,12 @@ function upload(fd, username, signature, uploadProgress) {
});
image.interceptors.request.use((request) => {
console.log('Starting image Request', request);
// console.log('Starting image Request', request);
return request;
});
image.interceptors.response.use((response) => {
console.log('Response:', response);
// console.log('Response:', response);
return response;
});

View File

@ -7,6 +7,7 @@
"claim_reward_balance": "Claim Reward ",
"points_activity":"Activity",
"transfer": "Transfer",
"recurrent_transfer": "Recurrent Transfer",
"power_up": "To Vesting",
"transfer_from_savings": "From Savings",
"withdraw_savings":"Withdraw Savings",
@ -770,13 +771,19 @@
"to": "To",
"amount_information": "Drag the slider to adjust the amount",
"amount": "Amount",
"executions": "Executions",
"recurrence": "Recurrence",
"memo": "Memo",
"recurrent_transfer": "Recurrent Transfer",
"delete_recurrent_transfer": "Delete Recurrent Transfer ",
"information": "Continue transaction?",
"amount_desc": "Balance",
"memo_desc": "This memo is public",
"convert_desc": "Convert takes 3.5 days and NOT recommended IF HBD price is higher than $1",
"to_placeholder": "Username",
"memo_placeholder": "Enter your notes here",
"recurrence_placeholder": "Choose Recurrence",
"executions_placeholder": "Number of Repeats",
"transfer_token": "Transfer",
"purchase_estm": "Purchase Points",
"convert": "Convert HBD to HIVE",

View File

@ -10,12 +10,12 @@ const slist = axios.create({
});
slist.interceptors.request.use((request) => {
console.log('Starting server list Request', request);
// console.log('Starting server list Request', request);
return request;
});
slist.interceptors.response.use((response) => {
console.log('Response:', response);
// console.log('Response:', response);
return response;
});

View File

@ -12,6 +12,7 @@ const TransferTypes = {
POWER_DOWN: 'power_down',
ADDRESS_VIEW: 'address_view',
DELEGATE_VESTING_SHARES: 'delegate_vesting_shares',
RECURRENT_TRANSFER: 'recurrent_transfer',
// Engine Transfer types
WITHDRAW_VESTING: 'withdraw_vesting',

View File

@ -16,6 +16,8 @@ import {
withdrawVesting,
delegateVestingShares,
setWithdrawVestingRoute,
recurrentTransferToken,
getRecurrentTransfers,
} from '../providers/hive/dhive';
import { toastNotification } from '../redux/actions/uiAction';
import { getUserDataWithUsername } from '../realm/realm';
@ -63,6 +65,7 @@ class TransferContainer extends Component {
spkMarkets: [],
initialAmount: props.route.params?.initialAmount,
initialMemo: props.route.params?.initialMemo,
recurrentTransfers: [],
};
}
@ -74,6 +77,8 @@ class TransferContainer extends Component {
this.fetchBalance(name);
this._fetchRecurrentTransfers(name);
if (this.state.transferType === TransferTypes.DELEGATE_SPK) {
this._fetchSpkMarkets();
}
@ -181,6 +186,16 @@ class TransferContainer extends Component {
return validUsers;
};
_fetchRecurrentTransfers = async (username) => {
const recTransfers = await getRecurrentTransfers(username);
this.setState({
recurrentTransfers: recTransfers,
});
return recTransfers;
};
_delayedRefreshCoinsData = () => {
const { dispatch } = this.props;
setTimeout(() => {
@ -188,7 +203,14 @@ class TransferContainer extends Component {
}, 3000);
};
_transferToAccount = async (from, destination, amount, memo) => {
_transferToAccount = async (
from,
destination,
amount,
memo,
recurrence = null,
executions = 0,
) => {
const { pinCode, navigation, dispatch, intl, route } = this.props;
let { currentAccount } = this.props;
const { selectedAccount } = this.state;
@ -205,6 +227,11 @@ class TransferContainer extends Component {
fundType,
};
if (recurrence && executions) {
data.recurrence = +recurrence;
data.executions = +executions;
}
if (countDecimals(Number(data.amount)) < 3) {
data.amount = Number(data.amount).toFixed(3);
}
@ -214,6 +241,9 @@ class TransferContainer extends Component {
case 'transfer_token':
func = transferToken;
break;
case TransferTypes.RECURRENT_TRANSFER:
func = recurrentTransferToken;
break;
case 'purchase_estm':
func = transferToken;
break;
@ -344,6 +374,7 @@ class TransferContainer extends Component {
spkMarkets,
initialAmount,
initialMemo,
recurrentTransfers,
} = this.state;
const transferType = route.params?.transferType ?? '';
@ -371,6 +402,8 @@ class TransferContainer extends Component {
setWithdrawVestingRoute: this._setWithdrawVestingRoute,
initialAmount,
initialMemo,
fetchRecurrentTransfers: this._fetchRecurrentTransfers,
recurrentTransfers,
})
);
}

View File

@ -42,7 +42,7 @@ import { SERVER_LIST } from '../../constants/options/api';
import { b64uEnc } from '../../utils/b64';
import bugsnagInstance from '../../config/bugsnag';
import bugsnapInstance from '../../config/bugsnag';
import { makeJsonMetadataReply } from '../../utils/editor';
import TransferTypes from '../../constants/transferTypes';
const hiveuri = require('hive-uri');
global.Buffer = global.Buffer || require('buffer').Buffer;
@ -987,6 +987,51 @@ export const transferToken = (currentAccount, pin, data) => {
);
};
export const recurrentTransferToken = (currentAccount, pin, data) => {
const digitPinCode = getDigitPinCode(pin);
const key = getAnyPrivateKey(
{
activeKey: get(currentAccount, 'local.activeKey'),
},
digitPinCode,
);
if (key) {
const privateKey = PrivateKey.fromString(key);
const args = {
from: get(data, 'from'),
to: get(data, 'destination'),
amount: get(data, 'amount'),
memo: get(data, 'memo'),
recurrence: get(data, 'recurrence'),
executions: get(data, 'executions'),
extensions: [],
};
const opArray = [[TransferTypes.RECURRENT_TRANSFER, args]];
return new Promise((resolve, reject) => {
sendHiveOperations(opArray, privateKey)
.then((result) => {
if (result) {
resolve(result);
}
})
.catch((err) => {
console.log('====================================');
console.log('error on recurrent transfer token');
console.log('====================================');
console.log(err);
reject(err);
});
});
}
return Promise.reject(
new Error('Check private key permission! Required private active key or above.'),
);
};
export const convert = (currentAccount, pin, data) => {
const digitPinCode = getDigitPinCode(pin);
const key = getAnyPrivateKey(
@ -1456,6 +1501,19 @@ export const getTrendingTags = async (tag, number = 20) => {
}
};
export const getRecurrentTransfers = async (username) => {
try {
const rawData = await client.call('condenser_api', 'find_recurrent_transfers', [username]);
if (!rawData || !rawData.length) {
return [];
}
return rawData;
} catch (err) {
console.warn('Failed to get recurrent transfers', err);
return [];
}
};
export const postContent = (
account,
pin,

View File

@ -26,7 +26,7 @@ export const useNotificationsQuery = (filter: NotificationFilters) => {
const _fetchNotifications = async (pageParam: string) => {
console.log('fetching page since:', pageParam);
const response = await getNotifications({ filter, since: pageParam, limit: FETCH_LIMIT });
console.log('new page fetched', response);
// console.log('new page fetched', response);
return response || [];
};

View File

@ -259,7 +259,7 @@ export const useInjectVotesCache = (_data: any | any[]) => {
};
const _cData = isArray(_data) ? _data.map(_itemFunc) : _itemFunc({ ..._data });
console.log('data received', _cData.length, _cData);
// console.log('data received', _cData.length, _cData);
setRetData(_cData);
}, [_data]);

View File

@ -278,7 +278,7 @@ export const useActivitiesQuery = (assetId: string) => {
isEngine: assetData.isEngine,
});
console.log('new page fetched', _activites);
// console.log('new page fetched', _activites);
return _activites || [];
};

View File

@ -12,7 +12,7 @@ const initialState: State = {
walkthroughMap: new Map(),
};
export default function (state = initialState, action) {
console.log('action : ', action);
// console.log('action : ', action);
const { type, payload } = action;
switch (type) {

View File

@ -59,6 +59,8 @@ export interface CoinActivity {
details: string | null;
memo: string;
cancelable: boolean;
recurrence: string;
executions: string;
}
export interface QuoteItem {

View File

@ -15,6 +15,7 @@ import { DelegationsModal, MODES } from '../children/delegationsModal';
import TransferTypes from '../../../constants/transferTypes';
import { walletQueries } from '../../../providers/queries';
import parseToken from '../../../utils/parseToken';
import { log } from '../../../../reactotron-config';
export interface AssetDetailsScreenParams {
coinId: string;

View File

@ -30,6 +30,8 @@ const Transfer = ({ navigation, route }) => (
spkMarkets,
initialAmount,
initialMemo,
recurrentTransfers,
fetchRecurrentTransfers,
}) => {
switch (transferType) {
case 'delegate':
@ -98,6 +100,8 @@ const Transfer = ({ navigation, route }) => (
referredUsername={referredUsername || ''}
initialAmount={initialAmount || ''}
initialMemo={initialMemo || ''}
recurrentTransfers={recurrentTransfers || []}
fetchRecurrentTransfers={fetchRecurrentTransfers}
/>
);
}

View File

@ -1,4 +1,4 @@
import React, { useState, useMemo } from 'react';
import React, { useState, useMemo, useEffect, useCallback } from 'react';
import { Alert, Text, View } from 'react-native';
import { WebView } from 'react-native-webview';
import { injectIntl } from 'react-intl';
@ -26,6 +26,7 @@ import {
getSpkTransactionId,
SPK_NODE_ECENCY,
} from '../../../providers/hive-spk/hiveSpk';
import parseToken from '../../../utils/parseToken';
const TransferView = ({
currentAccountName,
@ -44,7 +45,8 @@ const TransferView = ({
referredUsername,
initialAmount,
initialMemo,
transactionData,
fetchRecurrentTransfers,
recurrentTransfers,
}) => {
const dispatch = useAppDispatch();
@ -75,6 +77,10 @@ const TransferView = ({
const [memo, setMemo] = useState(
transferType === 'purchase_estm' ? 'estm-purchase' : initialMemo,
);
const [recurrence, setRecurrence] = useState('');
const [executions, setExecutions] = useState('');
const [startDate, setStartDate] = useState('');
const [isUsernameValid, setIsUsernameValid] = useState(
!!(
transferType === 'purchase_estm' ||
@ -96,6 +102,8 @@ const TransferView = ({
const [hsTransfer, setHsTransfer] = useState(false);
const [isTransfering, setIsTransfering] = useState(false);
const isRecurrentTransfer = transferType === TransferTypes.RECURRENT_TRANSFER;
const isEngineToken = useMemo(() => transferType.endsWith('_engine'), [transferType]);
const isSpkToken = useMemo(() => transferType.endsWith('_spk'), [transferType]);
@ -105,7 +113,27 @@ const TransferView = ({
if (accountType === AUTH_TYPE.STEEM_CONNECT) {
setHsTransfer(true);
} else {
transferToAccount(from, destination, amount, memo);
transferToAccount(
from,
destination,
amount,
memo,
isRecurrentTransfer ? recurrence : null,
isRecurrentTransfer ? executions : null,
);
}
},
300,
{ trailing: true },
);
const _handleDeleteRecurrentTransfer = debounce(
() => {
setIsTransfering(true);
if (accountType === AUTH_TYPE.STEEM_CONNECT) {
setHsTransfer(true);
} else {
transferToAccount(from, destination, '0', memo, 24, 2);
}
},
300,
@ -133,7 +161,11 @@ const TransferView = ({
// )}`;
// } else
if (transferType === TransferTypes.TRANSFER_TO_SAVINGS) {
if (transferType === TransferTypes.RECURRENT_TRANSFER) {
path = `sign/recurrent_transfer?from=${currentAccountName}&to=${destination}&amount=${encodeURIComponent(
`${amount} ${fundType}`,
)}&memo=${encodeURIComponent(memo)}&recurrence=${recurrence}&executions=${executions}`;
} else if (transferType === TransferTypes.TRANSFER_TO_SAVINGS) {
path = `sign/transfer_to_savings?from=${currentAccountName}&to=${destination}&amount=${encodeURIComponent(
`${amount} ${fundType}`,
)}&memo=${encodeURIComponent(memo)}`;
@ -200,9 +232,10 @@ const TransferView = ({
`${amount} ${fundType}`,
)}&memo=${encodeURIComponent(memo)}`;
}
console.log('path is: ', path);
}
const _onNextPress = () => {
const _onNextPress = (deleteTransfer = false) => {
if (balance < amount) {
Alert.alert(intl.formatMessage({ id: 'wallet.low_liquidity' }));
@ -218,7 +251,7 @@ const TransferView = ({
},
{
text: intl.formatMessage({ id: 'alert.confirm' }),
onPress: _handleTransferAction,
onPress: deleteTransfer ? _handleDeleteRecurrentTransfer : _handleTransferAction,
},
],
}),
@ -228,6 +261,49 @@ const TransferView = ({
const nextBtnDisabled = !((isEngineToken ? amount > 0 : amount >= 0.001) && isUsernameValid);
useEffect(() => {
if (isRecurrentTransfer) {
fetchRecurrentTransfers(currentAccountName);
}
}, [isRecurrentTransfer]);
const _findRecurrentTransferOfUser = useCallback(
(userToFind) => {
if (!isRecurrentTransfer) {
return false;
}
const existingRecurrentTransfer = recurrentTransfers.find((rt) => rt.to === userToFind);
let newMemo,
newAmount,
newRecurrence,
newStartDate,
newExecutions = '';
if (existingRecurrentTransfer) {
newMemo = existingRecurrentTransfer.memo;
newAmount = parseToken(existingRecurrentTransfer.amount).toString();
newRecurrence = existingRecurrentTransfer.recurrence.toString();
newExecutions = `${existingRecurrentTransfer.remaining_executions}`;
newStartDate = existingRecurrentTransfer.trigger_date;
console.log('====================================');
console.log('existingRecurrentTransfer');
console.log('====================================');
console.log(existingRecurrentTransfer);
}
setMemo(newMemo);
setAmount(newAmount);
setRecurrence(newRecurrence);
setExecutions(newExecutions);
setStartDate(newStartDate);
return existingRecurrentTransfer;
},
[recurrentTransfers],
);
return (
<View style={styles.container}>
<BasicHeader
@ -257,6 +333,7 @@ const TransferView = ({
memo={memo}
setMemo={setMemo}
spkMarkets={spkMarkets}
getRecurrentTransferOfUser={_findRecurrentTransferOfUser}
/>
<TransferAmountInputSection
balance={balance}
@ -274,6 +351,12 @@ const TransferView = ({
fundType={fundType}
currentAccountName={currentAccountName}
disableMinimum={isEngineToken}
recurrence={recurrence}
setRecurrence={setRecurrence}
executions={executions}
setExecutions={setExecutions}
startDate={startDate}
onNext={_onNextPress}
/>
<View style={styles.bottomContent}>
<MainButton

View File

@ -151,7 +151,7 @@ export const daysTillDate = (dateObj) => {
*
* */
export const dateToFormatted = (d, format = 'LLLL') => {
const isTimeZoned = d.indexOf('.') !== -1 || d.indexOf('+') !== -1 ? d : `${d}.000Z`;
const isTimeZoned = d?.indexOf('.') !== -1 || d?.indexOf('+') !== -1 ? d : `${d}.000Z`;
const dm = moment(new Date(isTimeZoned));
return dm.format(format);
};

View File

@ -68,7 +68,8 @@ const HIVE_ACTIONS = [
'transfer_to_savings',
'transfer_to_vesting',
'withdraw_hive',
'swap_token'
'swap_token',
TransferTypes.RECURRENT_TRANSFER
];
const HBD_ACTIONS = [
'transfer_token',

View File

@ -9131,10 +9131,10 @@ react-native-level-fs@^3.0.0:
level-filesystem "^1.0.1"
levelup "^0.18.2"
react-native-linear-gradient@^2.4.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/react-native-linear-gradient/-/react-native-linear-gradient-2.6.2.tgz#56598a76832724b2afa7889747635b5c80948f38"
integrity sha512-Z8Xxvupsex+9BBFoSYS87bilNPWcRfRsGC0cpJk72Nxb5p2nEkGSBv73xZbEHnW2mUFvP+huYxrVvjZkr/gRjQ==
react-native-linear-gradient@^2.8.3:
version "2.8.3"
resolved "https://registry.yarnpkg.com/react-native-linear-gradient/-/react-native-linear-gradient-2.8.3.tgz#9a116649f86d74747304ee13db325e20b21e564f"
integrity sha512-KflAXZcEg54PXkLyflaSZQ3PJp4uC4whM7nT/Uot9m0e/qxFV3p6uor1983D1YOBJbJN7rrWdqIjq0T42jOJyA==
react-native-media-controls@^2.3.0:
version "2.3.0"