Merge pull request #69 from andrerfneves/feature/list-shielded-transactions

Feature/list shielded transactions
This commit is contained in:
George Lima 2019-02-11 17:20:17 -03:00 committed by GitHub
commit 3019f0182c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 103 additions and 27 deletions

View File

@ -0,0 +1,13 @@
// @flow
import 'jest-dom/extend-expect';
import { sortByDescend } from '../../app/utils/sort-by-descend';
describe('truncateAddress', () => {
test('should truncate ZEC address', () => {
expect(
sortByDescend('id')([{ id: 5 }, { id: 2 }, { id: 1 }, { id: 0 }, { id: 1 }, { id: 1 }]),
).toEqual([{ id: 5 }, { id: 2 }, { id: 1 }, { id: 1 }, { id: 1 }, { id: 0 }]);
});
});

View File

@ -0,0 +1,13 @@
// @flow
import 'jest-dom/extend-expect';
import { sortBy } from '../../app/utils/sort-by';
describe('truncateAddress', () => {
test('should truncate ZEC address', () => {
expect(
sortBy('id')([{ id: 5 }, { id: 2 }, { id: 1 }, { id: 0 }, { id: 1 }, { id: 1 }]),
).toEqual([{ id: 0 }, { id: 1 }, { id: 1 }, { id: 1 }, { id: 2 }, { id: 5 }]);
});
});

View File

@ -32,7 +32,7 @@ const StyledLink = styled.a`
display: flex;
align-items: center;
outline: none;
border-right: ${(props: StyledLinkProps) => (props.isActive ? `3px solid ${props.theme.colors.sidebarItemActive}` : 'none')};
border-right: ${(props: StyledLinkProps) => (props.isActive ? `3px solid ${props.theme.colors.sidebarItemActive(props)}` : 'none')};
cursor: pointer;
transition: all 0.03s ${(props: StyledLinkProps) => props.theme.transitionEase};

View File

@ -17,6 +17,7 @@ const AddressWrapper = styled.div`
background-color: #000;
border-radius: 6px;
padding: 7px 13px;
margin-bottom: 10px;
width: 100%;
`;
@ -41,7 +42,7 @@ const QRCodeWrapper = styled.div`
background-color: #000;
border-radius: 6px;
padding: 20px;
margin-top: 10px;
margin-bottom: 10px;
width: 100%;
`;

View File

@ -8,13 +8,14 @@ import dateFns from 'date-fns';
import { BigNumber } from 'bignumber.js';
import { DashboardView } from '../views/dashboard';
import rpc from '../../services/api';
import { listShieldedTransactions } from '../../services/shielded-transactions';
import store from '../../config/electron-store';
import {
loadWalletSummary,
loadWalletSummarySuccess,
loadWalletSummaryError,
} from '../redux/modules/wallet';
import { sortBy } from '../utils/sort-by';
import { sortByDescend } from '../utils/sort-by-descend';
import type { AppState } from '../types/app-state';
import type { Dispatch } from '../types/redux';
@ -47,7 +48,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
);
}
const formattedTransactions = flow([
const formattedTransactions: Array<Object> = flow([
arr => arr.map(transaction => ({
transactionId: transaction.txid,
type: transaction.category,
@ -58,10 +59,11 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
arr => groupBy(arr, obj => dateFns.format(obj.date, 'MMM DD, YYYY')),
obj => Object.keys(obj).map(day => ({
day,
list: sortBy('date')(obj[day]),
jsDay: new Date(day),
list: sortByDescend('date')(obj[day]),
})),
sortBy('day'),
])(transactions);
sortByDescend('jsDay'),
])([...transactions, ...listShieldedTransactions()]);
if (!zAddresses.length) {
const [, newZAddress] = await eres(rpc.z_getnewaddress());

View File

@ -21,6 +21,7 @@ import {
} from '../redux/modules/send';
import { filterObjectNullKeys } from '../utils/filter-object-null-keys';
import { saveShieldedTransaction } from '../../services/shielded-transactions';
import type { AppState } from '../types/app-state';
import type { Dispatch } from '../types/redux';
@ -92,6 +93,15 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
if (operationStatus && operationStatus.status === 'success') {
clearInterval(interval);
if (from.startsWith('z')) {
saveShieldedTransaction({
category: 'send',
time: Date.now() / 1000,
address: '(Shielded)',
amount: new BigNumber(amount).toNumber(),
memo,
});
}
dispatch(sendTransactionSuccess({ operationId: operationStatus.result.txid }));
}

View File

@ -14,9 +14,10 @@ import {
loadTransactionsError,
} from '../redux/modules/transactions';
import rpc from '../../services/api';
import { listShieldedTransactions } from '../../services/shielded-transactions';
import store from '../../config/electron-store';
import { sortBy } from '../utils/sort-by';
import { sortByDescend } from '../utils/sort-by-descend';
import type { AppState } from '../types/app-state';
import type { Dispatch } from '../types/redux';
@ -32,7 +33,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
getTransactions: async () => {
dispatch(loadTransactions());
const [transactionsErr, transactions = []] = await eres(rpc.listtransactions());
const [transactionsErr, transactions = []] = await eres(rpc.listtransactions('', 200));
if (transactionsErr) {
return dispatch(loadTransactionsError({ error: transactionsErr.message }));
@ -49,10 +50,11 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
arr => groupBy(arr, obj => dateFns.format(obj.date, 'MMM DD, YYYY')),
obj => Object.keys(obj).map(day => ({
day,
list: sortBy('date')(obj[day]),
jsDay: new Date(day),
list: sortByDescend('date')(obj[day]),
})),
sortBy('day'),
])(transactions);
sortByDescend('jsDay'),
])([...transactions, ...listShieldedTransactions()]);
dispatch(
loadTransactionsSuccess({

View File

@ -0,0 +1,5 @@
// @flow
/* eslint-disable max-len */
// $FlowFixMe
export const sortByDescend = <T>(field: string) => (arr: T[]): T[] => arr.sort((a, b) => (a[field] < b[field] ? 1 : -1));

View File

@ -1,5 +1,5 @@
// @flow
/* eslint-disable max-len */
// $FlowFixMe
export const sortBy = <T>(field: string) => (arr: T[]): T[] => arr.sort((a, b) => (a[field] < b[field] ? 1 : -1));
export const sortBy = <T>(field: string) => (arr: T[]): T[] => arr.sort((a, b) => (a[field] > b[field] ? 1 : -1));

View File

@ -1,6 +1,4 @@
// @flow
export const truncateAddress = (address: string = '') => `${address.substr(0, 20)}...${address.substr(
address.length - 10,
address.length,
)}`;
export const truncateAddress = (address: string = '') => (address.length < 20
? address
: `${address.substr(0, 20)}...${address.substr(address.length - 10, address.length)}`);

View File

@ -159,11 +159,9 @@ const ConfirmItemWrapper = styled(RowComponent)`
width: 100%;
`;
type ItemLabelProps =
| {
color: string,
}
| Object;
type ItemLabelProps = {
color: string,
};
/* eslint-disable max-len */
const ItemLabel = styled(TextComponent)`
font-weight: ${(props: PropsWithTheme<ItemLabelProps>) => String(props.theme.fontWeight.bold)};
@ -227,7 +225,7 @@ const MaxAvailableAmount = styled.button`
background: none;
color: white;
cursor: pointer;
border-left: ${props => `1px solid ${props.theme.colors.background}`};
border-left: ${props => `1px solid ${props.theme.colors.background(props)}`};
opacity: 0.8;
&:hover {

View File

@ -10,9 +10,9 @@ declare module 'electron-store' {
fileExtension?: string,
}): ElectronStore;
set(key: string, value: string): void;
set(key: string, value: any): void;
set(payload: Object): void;
get(key: string): string;
get(key: string): any;
has(key: string): boolean;
delete(key: string): void;
clear(): void;

View File

@ -0,0 +1,34 @@
// @flow
import electronStore from '../config/electron-store';
const STORE_KEY = 'SHIELDED_TRANSACTIONS';
type ShieldedTransaction = {|
category: 'send' | 'receive',
time: number,
address: string,
amount: number,
memo: ?string,
|};
// eslint-disable-next-line
export const listShieldedTransactions = (): Array<ShieldedTransaction> => electronStore.has(STORE_KEY) ? electronStore.get(STORE_KEY) : [];
export const saveShieldedTransaction = ({
category,
time,
address,
amount,
memo,
}: ShieldedTransaction): void => {
electronStore.set(
STORE_KEY,
listShieldedTransactions().concat({
category,
time,
address,
amount,
memo: memo || '',
}),
);
};