Commit 4c8579a4 authored by Allan Juma's avatar Allan Juma

0.6.2

parent a57149cd
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
### Description
### Steps to reproduce the behavior
### Expected behavior
### Actual behavior
### Screenshot and/or logs if applicable
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
...@@ -85,8 +85,8 @@ ipcMain.on('logs-ready', () => { ...@@ -85,8 +85,8 @@ ipcMain.on('logs-ready', () => {
function createWindow() { function createWindow() {
console.log(path.join(__dirname, 'preload.js')); console.log(path.join(__dirname, 'preload.js'));
const options = { const options = {
width: 850, width: 650,
height: 705, height: 950,
backgroundColor: '#0f5f76', backgroundColor: '#0f5f76',
icon: path.join( icon: path.join(
__dirname, __dirname,
...@@ -107,7 +107,7 @@ console.log(path.join(__dirname, 'preload.js')); ...@@ -107,7 +107,7 @@ console.log(path.join(__dirname, 'preload.js'));
if (isDev) { if (isDev) {
// Add width for dev tools // Add width for dev tools
options.width += 720; options.width += 720;
options.height += 450; options.height += 0;
win = new BrowserWindow(options); win = new BrowserWindow(options);
win.loadURL('http://localhost:3000'); win.loadURL('http://localhost:3000');
// Open the DevTools. // Open the DevTools.
......
...@@ -112,11 +112,11 @@ module.exports.startLndProcess = async function({ ...@@ -112,11 +112,11 @@ module.exports.startLndProcess = async function({
if (isDev) { if (isDev) {
args = args.concat([ args = args.concat([
'--bitcoin.node=bitcoind', '--bitcoin.node=bitcoind',
'--bitcoind.rpchost=192.168.1.3', '--bitcoind.rpchost=btc-p2p.bitsoko.org',
'--bitcoind.rpcuser=bitsoko', '--bitcoind.rpcuser=bitsoko',
'--bitcoind.rpcpass=12Bitcoinsrus12', '--bitcoind.rpcpass=12Bitcoinsrus12',
'--bitcoind.zmqpubrawblock=tcp://192.168.1.3:28332', '--bitcoind.zmqpubrawblock=tcp://btc-p2p.bitsoko.org:28332',
'--bitcoind.zmqpubrawtx=tcp://192.168.1.3:28333' '--bitcoind.zmqpubrawtx=tcp://btc-p2p.bitsoko.org:28333'
]); ]);
} }
......
...@@ -17,6 +17,7 @@ import LogAction from './log'; ...@@ -17,6 +17,7 @@ import LogAction from './log';
import InfoAction from './info'; import InfoAction from './info';
import NotificationAction from './notification'; import NotificationAction from './notification';
import ChannelAction from './channel'; import ChannelAction from './channel';
import InvestmentAction from './investment';
import TransactionAction from './transaction'; import TransactionAction from './transaction';
import DaoAction from './dao'; import DaoAction from './dao';
import PoolAction from './pool'; import PoolAction from './pool';
...@@ -51,6 +52,7 @@ export const info = new InfoAction(store, grpc, nav, notify); ...@@ -51,6 +52,7 @@ export const info = new InfoAction(store, grpc, nav, notify);
export const pool = new PoolAction(store, grpc, nav, notify); export const pool = new PoolAction(store, grpc, nav, notify);
export const dao = new DaoAction(store, grpc, nav, notify); export const dao = new DaoAction(store, grpc, nav, notify);
export const promotion = new PromotionAction(store, grpc, nav, notify); export const promotion = new PromotionAction(store, grpc, nav, notify);
export const investment = new InvestmentAction(store, grpc, nav, notify);
export const transaction = new TransactionAction(store, grpc, nav, notify); export const transaction = new TransactionAction(store, grpc, nav, notify);
export const channel = new ChannelAction(store, grpc, nav, notify); export const channel = new ChannelAction(store, grpc, nav, notify);
export const invoice = new InvoiceAction(store, grpc, nav, notify, Clipboard); export const invoice = new InvoiceAction(store, grpc, nav, notify, Clipboard);
...@@ -123,29 +125,63 @@ when( ...@@ -123,29 +125,63 @@ when(
* the user can really begin to interact with the application and calls * the user can really begin to interact with the application and calls
* to and from lnd can be done. The contract chains are implemented * to and from lnd can be done. The contract chains are implemented
*/ */
function setChainAccount(chain, account) {
if (!store.settings.chains[chain]) {
throw new Error(`Invalid chain: `+chain);
}
if (!account) {
throw new Error(`Invalid seed: `+account);
}
store.settings.chains[chain].account = account;
db.save();
console.log('INFO! '+chain+' account '+account.address);
}
function setChainAddress(chain, addr) {
if (!store.settings.chains[chain]) {
throw new Error(`Invalid chain: `+chain);
}
if (!addr) {
throw new Error(`Invalid address: `+addr);
}
store.settings.chains[chain].addresses.push(addr);
db.save();
}
when( when(
() => store.lndReady, () => store.lndReady,
async () => { async () => {
console.log(store.settings.chains);
if(!store.chains.algo.account){ if(!store.settings.chains.algo.account){
var algoAccount = await Algorand.createWallet(); var algoAccount = await Algorand.createWallet();
store.chains.algo.account = algoAccount;
//var algoAccountInfo = await Algorand.getAccount('testnet',store.chains.algo.account.address); //var algoAccountInfo = await Algorand.getAccount('testnet',store.chains.algo.account.address);
setChainAccount('algo', algoAccount);
console.log('new algo account! '+store.settings.chains.algo.account.address);
}else{
console.log('old algo account! '+store.settings.chains.algo.account.address);
} }
console.log('INFO! algorand account '+store.chains.algo.account.address); /*
if(!store.chains.sol.account){ if(!store.chains.sol.account){
var solAccount = await Solana.createWallet(); var solAccount = await Solana.createWallet();
store.chains.sol.account = solAccount;
//var solAccountInfo = await Solana.getAccount('testnet',store.chains.sol.account.address); //var solAccountInfo = await Solana.getAccount('testnet',store.chains.sol.account.address);
setChainAccount({chain:'sol', account:solAccount});
} }
*/
console.log('INFO! solana account '+store.chains.sol.account.address);
} }
); );
......
/**
* @fileOverview actions to set Investments state within the app and to
* call the corresponding apis for listing transactions.
*/
import * as log from './log';
import { parseDate, toHex } from '../helper';
class InvestmentAction {
constructor(store, grpc, nav, notification) {
this._store = store;
this._grpc = grpc;
this._nav = nav;
this._notification = notification;
}
/**
* Initiate the transaction list view by navigating to the view and updating
* the app's transaction state by calling all necessary grpc apis.
* @return {undefined}
*/
init() {
this._nav.goInvestments();
this.update();
}
/**
* Select a transaction item from the transaction list view and then navigate
* to the detail view to list transaction parameters.
* @param {Object} options.item The selected transaction object
* @return {Promise<undefined>}
*/
async select({ item }) {
this._store.selectedTransaction = item;
if (item.paymentRequest) {
item.memo = await this.decodeMemo({ payReq: item.paymentRequest });
}
this._nav.goTransactionDetail();
this.update();
}
/**
* Update the on-chain transactions, invoice, and lighting payments in the
* app state by querying all required grpc apis.
* @return {Promise<undefined>}
*/
async update() {
await Promise.all([
this.getAlgoTransactions(),
]);
}
/**
* Get lock state.
* @return {Promise<undefined>}
*/
async updateLock(TransactionTime) {
let locked=true;
if(TransactionTime < new Date().setDate(new Date().getDate() - 1)){
locked=false;
}
return locked;
}
/**
* List the on-chain transactions by calling the respective grpc api and updating
* the transactions array in the global store.
* @return {Promise<undefined>}
*/
async getAlgoTransactions() {
try {
const { transactions } = await this._grpc.sendCommand('listInvoices');
this._store.transactions = transactions.map(transaction => ({
id: transaction.txHash,
type: this.updateLock(transaction.timeStamp) ? 'locked' : 'unlocked',
amount: transaction.amount,
fee: transaction.totalFees,
confirmations: transaction.numConfirmations,
status: transaction.numConfirmations < 3 ? 'rewarded' : 'confirmed',
date: parseDate(transaction.timeStamp),
}));
} catch (err) {
log.error('Listing transactions failed', err);
}
}
/**
* Subscribe to incoming on-chain transactions using the grpc streaming api.
* @return {Promise<undefined>}
*/
async subscribeTransactions() {
const stream = this._grpc.sendStreamCommand('subscribeTransactions');
await new Promise((resolve, reject) => {
stream.on('data', () => this.update());
stream.on('end', resolve);
stream.on('error', reject);
stream.on('status', status => log.info(`Transactions update: ${status}`));
});
}
}
export default InvestmentAction;
...@@ -167,6 +167,10 @@ class NavAction { ...@@ -167,6 +167,10 @@ class NavAction {
goTransactions() { goTransactions() {
this._store.route = 'Transactions'; this._store.route = 'Transactions';
} }
goInvestments() {
this._store.route = 'Investments';
}
goPools() { goPools() {
this._store.route = 'Pools'; this._store.route = 'Pools';
...@@ -189,6 +193,12 @@ class NavAction { ...@@ -189,6 +193,12 @@ class NavAction {
this._store.route = 'Notifications'; this._store.route = 'Notifications';
} }
goContractSettings(contract) {
this._store.selectedContractSetting = contract;
this._store.route = 'SetContract';
}
goSettings() { goSettings() {
this._store.route = 'Settings'; this._store.route = 'Settings';
} }
......
...@@ -139,7 +139,7 @@ class PoolAddAction { ...@@ -139,7 +139,7 @@ class PoolAddAction {
const { settings } = this._store; const { settings } = this._store;
var amount = toSatoshis(amount, settings); var amount = toSatoshis(amount, settings);
//get new pool quotation from server //get new pool quotation from server
var escrowInvoice = await sendToEscrow(amount, '{"state":"pool","action":"add","account":"algo1","pool":"pool1"}'); var escrowInvoice = await sendToEscrow(amount, '{"state":"pool", "action":"add", "account":"'+this._store.settings.chains.algo.account.address+'", "pool":"'+this._store.selectedPool.id+'", "type":"float"}');
console.log(escrowInvoice); console.log(escrowInvoice);
this.setAddress({ address: escrowInvoice }); this.setAddress({ address: escrowInvoice });
......
...@@ -60,20 +60,24 @@ class PoolAction { ...@@ -60,20 +60,24 @@ class PoolAction {
async getPools() { async getPools() {
try { try {
const uri = 'https://gateway.bitsoko.org/getEnterprise/?servEntID=1';
const uri = //const uri = 'https://gateway.bitsoko.org/getEnterpriseRoute';
'https://gateway.bitsoko.org/getEnterpriseRoute';
const response = checkHttpStatus(await fetch(uri)); const response = checkHttpStatus(await fetch(uri));
const pools = await response.json(); const svs = await response.json();
var pools = svs.services;
//const pools = (await response.json()).tickers; //const pools = (await response.json()).tickers;
//const rate = tickers.find(t => t.ticker.toLowerCase() === fiat).rate; //const rate = tickers.find(t => t.ticker.toLowerCase() === fiat).rate;
this._store.pools = pools.map(pool => ({ this._store.pools = pools.map(pool => ({
id: pool.url, id: pool.id,
cat: 'micro', cat: 'micro',
type: 'algorand', type: 'algorand',
title: pool.title ? pool.title : 'Sample merchant @ https://demo1.bitsoko.org', icon: pool.bannerPath,
desc: pool.desc ? pool.desc : '{name:"demo", desc:"a sample merchant", image:"",banner:"",link:"",url:"https://demo1.bitsoko.org"}', banner: pool.bannerPath,
url: 'https://demo1.bitsoko.org',
title: pool.name,
desc: pool.description,
amount: 0, amount: 0,
fee: 0, fee: 0,
confirmations: 5, confirmations: 5,
......
...@@ -115,22 +115,69 @@ const countStyles = StyleSheet.create({ ...@@ -115,22 +115,69 @@ const countStyles = StyleSheet.create({
paddingRight: 10, paddingRight: 10,
paddingLeft: 10, paddingLeft: 10,
borderRadius: 13, borderRadius: 13,
},
red: {
backgroundColor: color.pinkSig, backgroundColor: color.pinkSig,
}, },
orange: {
backgroundColor: color.orangeSig,
},
green: {
backgroundColor: color.greenSig,
},
grey: {
backgroundColor: color.greySig,
},
txt: { txt: {
fontSize: font.sizeXS, fontSize: font.sizeXS,
lineHeight: font.lineHeightXS, lineHeight: font.lineHeightXS,
}, },
}); });
export const CountBubble = ({ children, style }) => export const CountBubbleRed = ({ children, style }) =>
children && children !== '0' ? (
<View style={[countStyles.red, countStyles.bubble, style]}>
<H4Text style={countStyles.txt}>{children}</H4Text>
</View>
) : null;
export const CountBubbleGreen = ({ children, style }) =>
children && children !== '0' ? (
<View style={[countStyles.green, countStyles.bubble, style]}>
<H4Text style={countStyles.txt}>{children}</H4Text>
</View>
) : null;
export const CountBubbleOrange = ({ children, style }) =>
children && children !== '0' ? ( children && children !== '0' ? (
<View style={[countStyles.bubble, style]}> <View style={[countStyles.orange, countStyles.bubble, style]}>
<H4Text style={countStyles.txt}>{children}</H4Text> <H4Text style={countStyles.txt}>{children}</H4Text>
</View> </View>
) : null; ) : null;
CountBubble.propTypes = { export const CountBubbleGrey = ({ children, style }) =>
children && children !== '0' ? (
<View style={[countStyles.bubble, countStyles.grey, style]}>
<H4Text style={countStyles.txt}>{children}</H4Text>
</View>
) : null;
CountBubbleRed.propTypes = {
children: PropTypes.string.isRequired,
style: ViewPropTypes.style,
};
CountBubbleOrange.propTypes = {
children: PropTypes.string.isRequired,
style: ViewPropTypes.style,
};
CountBubbleGreen.propTypes = {
children: PropTypes.string.isRequired,
style: ViewPropTypes.style,
};
CountBubbleGrey.propTypes = {
children: PropTypes.string.isRequired, children: PropTypes.string.isRequired,
style: ViewPropTypes.style, style: ViewPropTypes.style,
}; };
......
...@@ -7,7 +7,7 @@ import { ...@@ -7,7 +7,7 @@ import {
} from 'react-native'; } from 'react-native';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { color, font } from './style'; import { color, font } from './style';
import LightningBoltIcon from '../asset/icon/lightning-bolt'; import BitcoinIcon from '../../src/asset/icon/bitcoin';
import Text from './text'; import Text from './text';
import Svg, { Path, Circle, Defs, Stop, LinearGradient } from './svg'; import Svg, { Path, Circle, Defs, Stop, LinearGradient } from './svg';
import { generateArc } from '../helper'; import { generateArc } from '../helper';
...@@ -53,7 +53,8 @@ export const LoadNetworkSpinner = ({ continuous, percentage, msg, style }) => ( ...@@ -53,7 +53,8 @@ export const LoadNetworkSpinner = ({ continuous, percentage, msg, style }) => (
progressWidth={3} progressWidth={3}
gradient="loadNetworkGrad" gradient="loadNetworkGrad"
> >
<LightningBoltIcon height={28} width={14.2222} />
<BitcoinIcon height={38} width={25} />
</ResizeableSpinner> </ResizeableSpinner>
<Text style={loadNetworkStyles.copy}>{msg}</Text> <Text style={loadNetworkStyles.copy}>{msg}</Text>
</View> </View>
......
...@@ -89,6 +89,23 @@ const ComputedChannel = store => { ...@@ -89,6 +89,23 @@ const ComputedChannel = store => {
? 'info' ? 'info'
: 'error'; : 'error';
}, },
get contractStatus() {
const {
channelBalanceOpenSatoshis: opened,
channelBalanceInactiveSatoshis: inactive,
channelBalancePendingSatoshis: pending,
} = store;
return 'info';
/*
return opened
? 'success'
: inactive
? 'inactive'
: pending
? 'info'
: 'error';
*/
},
}); });
}; };
......
...@@ -16,9 +16,9 @@ const ComputedPool = store => { ...@@ -16,9 +16,9 @@ const ComputedPool = store => {
all.sort((a, b) => b.date.getTime() - a.date.getTime()); all.sort((a, b) => b.date.getTime() - a.date.getTime());
all.forEach((t, i) => { all.forEach((t, i) => {
t.key = String(i); t.key = String(i);
t.idName = t.type === 'algorand' ? 'Algorand' : 'Ethereum'; //t.idName = t.type === 'algorand' ? '209:BITS:dooca-net' : 'Ethereum';
//t.icon = '../asset/icon/'+t.type+'.png'; t.idName = t.id+':BITS:dooca.net | '+t.title;
t.icon = '../asset/icon/lightning.svg'; t.icon = t.icon;
t.typeLabel = toCaps(t.type); t.typeLabel = toCaps(t.type);
t.statusLabel = toCaps(t.status); t.statusLabel = toCaps(t.status);
t.merchantLabel = t.title; t.merchantLabel = t.title;
......
...@@ -63,28 +63,6 @@ export class Store { ...@@ -63,28 +63,6 @@ export class Store {
restoreIndex: 0, restoreIndex: 0,
focusedRestoreInd: 0, focusedRestoreInd: 0,
}, },
chains: {
eth:{
account:'',
rpc:{mainnet: {server:'',port:'',key:''}, testnet: {server:'',port:'',key:''}}
},
matic:{
account:'',
rpc:{mainnet: {server:'',port:'',key:''}, testnet: {server:'',port:'',key:''}}
},
xml:{
account:'',
rpc:{mainnet: {server:'',port:'',key:''}, testnet: {server:'',port:'',key:''}}
},
sol:{
account:'',
rpc:{mainnet: {server:'',port:'',key:''}, testnet: {server:'',port:'',key:''}}
},
algo:{
account:'',
rpc:{mainnet: {server:'',port:'',key:''}, testnet: {server:'https://testnet-algorand.api.purestake.io/ps2',port:'',key:'qe3CNhIJ3C5DXrGHlfxAU1aIUt7SrYzNMwHz8gKb'}}
},
},
promotions: [], promotions: [],
selectedPromotion: null, selectedPromotion: null,
pools: [], pools: [],
...@@ -127,6 +105,7 @@ export class Store { ...@@ -127,6 +105,7 @@ export class Store {
// Persistent data // Persistent data
settings: { settings: {
contracts: ['algo','eth'],
unit: DEFAULT_UNIT, unit: DEFAULT_UNIT,
fiat: DEFAULT_FIAT, fiat: DEFAULT_FIAT,
displayFiat: true, displayFiat: true,
...@@ -134,6 +113,14 @@ export class Store { ...@@ -134,6 +113,14 @@ export class Store {
restoring: false, restoring: false,
autopilot: true, autopilot: true,
nodeScores: {}, nodeScores: {},
chains: {
algo:{
account:false,
chain: 'testnet',
addresses: [],
rpc:{mainnet: {server:'',port:'',key:''}, testnet: {server:'https://testnet-algorand.api.purestake.io/ps2',port:'',key:'qe3CNhIJ3C5DXrGHlfxAU1aIUt7SrYzNMwHz8gKb'}}
}
}
}, },
}); });
} }
......
...@@ -74,6 +74,8 @@ const HomeView = ({ ...@@ -74,6 +74,8 @@ const HomeView = ({
unitLabel, unitLabel,
channelStatus, channelStatus,
channelPercentageLabel, channelPercentageLabel,
contractStatus,
contractPercentageLabel,
} = store; } = store;
return ( return (
<Background image="purple-gradient-bg"> <Background image="purple-gradient-bg">
...@@ -89,6 +91,8 @@ const HomeView = ({ ...@@ -89,6 +91,8 @@ const HomeView = ({
unitLabel={unitLabel} unitLabel={unitLabel}
channelStatus={channelStatus} channelStatus={channelStatus}
channelPercentageLabel={channelPercentageLabel} channelPercentageLabel={channelPercentageLabel}
contractStatus={contractStatus}
contractPercentageLabel={contractPercentageLabel}
toggleDisplayFiat={() => wallet.toggleDisplayFiat()} toggleDisplayFiat={() => wallet.toggleDisplayFiat()}
goChannels={() => channel.init()} goChannels={() => channel.init()}
/> />
...@@ -137,6 +141,7 @@ const balanceStyles = StyleSheet.create({ ...@@ -137,6 +141,7 @@ const balanceStyles = StyleSheet.create({
}, },
alert: { alert: {
marginRight: 6, marginRight: 6,
marginLeft: '50%',
}, },
}); });
...@@ -146,6 +151,8 @@ const BalanceDisplay = ({ ...@@ -146,6 +151,8 @@ const BalanceDisplay = ({
unitLabel, unitLabel,
channelStatus, channelStatus,
channelPercentageLabel, channelPercentageLabel,
contractStatus,
contractPercentageLabel,
toggleDisplayFiat, toggleDisplayFiat,
goChannels, goChannels,
}) => ( }) => (
...@@ -159,8 +166,17 @@ const BalanceDisplay = ({ ...@@ -159,8 +166,17 @@ const BalanceDisplay = ({
<Button onPress={goChannels} style={balanceStyles.percentBtn}> <Button onPress={goChannels} style={balanceStyles.percentBtn}>
<View style={{flex:2,flexDirection:"column",justifyContent:"center",width:"100%",padding:10,paddingTop:50,textAlign:"center"}}>
<View style={{flex:1,padding:10,marginTop: "-10px"}}>
<Alert type={channelStatus} style={balanceStyles.alert} /> <Alert type={channelStatus} style={balanceStyles.alert} />
<H4Text>{channelPercentageLabel}</H4Text> <H4Text style={{paddingTop: "5px"}}>{channelPercentageLabel}{"\n"}</H4Text>
</View>
<View style={{flex:1,padding:10,marginTop: "-10px"}}>
<Alert type={contractStatus} style={balanceStyles.alert} />
<H4Text style={{paddingTop: "5px"}}>0% on Contracts</H4Text>
</View>
</View>
</Button> </Button>
</View> </View>
); );
...@@ -170,6 +186,8 @@ BalanceDisplay.propTypes = { ...@@ -170,6 +186,8 @@ BalanceDisplay.propTypes = {
unitLabel: PropTypes.string, unitLabel: PropTypes.string,
channelStatus: PropTypes.string.isRequired, channelStatus: PropTypes.string.isRequired,
channelPercentageLabel: PropTypes.string.isRequired, channelPercentageLabel: PropTypes.string.isRequired,
contractStatus: PropTypes.string.isRequired,
contractPercentageLabel: PropTypes.string.isRequired,
toggleDisplayFiat: PropTypes.func.isRequired, toggleDisplayFiat: PropTypes.func.isRequired,
goChannels: PropTypes.func.isRequired, goChannels: PropTypes.func.isRequired,
}; };
......
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { observer } from 'mobx-react';
import PropTypes from 'prop-types';
import Background from '../component/background';
import { Header, Title } from '../component/header';
import { Button, CancelButton } from '../component/button';
import { ListContent, List, ListItem, ListHeader } from '../component/list';
import { Alert } from '../component/notification';
import Text from '../component/text';
import BitcoinIcon from '../../src/asset/icon/bitcoin';
import LightningBoltIcon from '../../src/asset/icon/lightning-bolt';
import { color, font } from '../component/style';
//
// Investment View
//
const InvestmentView = ({ store, nav, transaction }) => {
const { computedTransactions: transactions } = store;
return (
<Background color={color.blackDark}>
<Header separator>
<Button disabled onPress={() => {}} />
<Title title="Investments" />
<CancelButton onPress={() => nav.goPools()} />
</Header>
<ListContent>
<List
data={transactions}
renderHeader={InvestmentListHeader}
renderItem={item => (
<InvestmentListItem
tx={item}
onSelect={() => transaction.select({ item })}
/>
)}
/>
</ListContent>
</Background>
);
};
InvestmentView.propTypes = {
store: PropTypes.object.isRequired,
nav: PropTypes.object.isRequired,
transaction: PropTypes.object.isRequired,
};
//
// Transaction List Item
//
const iStyles = StyleSheet.create({
item: {
paddingLeft: 10,
paddingRight: 10,
},
wrap: {
paddingRight: 50,
},
txt: {
color: color.white,
fontSize: font.sizeS,
},
alert: {
marginRight: 6,
},
group: {
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center',
},
l: { flex: 8 },
m: { flex: 4 },
s: { flex: 2 },
i: { flex: 1 },
});
const statusType = tx => {
if (tx.type === 'locked') {
return tx.status === 'rewarded' ? 'success' : 'error';
} else {
return tx.status === 'rewarded' ? 'success' : 'info';
}
};
const InvestmentListItem = ({ tx, onSelect }) => (
<ListItem style={iStyles.item} onSelect={onSelect}>
<View style={iStyles.i}>
{(tx.type === 'unlocked' && tx.status === 'rewarded') ? (
<LightningBoltIcon height={126 * 0.14} width={64 * 0.14} />
) : (
<BitcoinIcon height={170 * 0.08} width={135 * 0.08} />
)}
</View>
<View style={[iStyles.m, iStyles.group]}>
<Alert type={statusType(tx)} style={iStyles.alert} />
<Text style={iStyles.txt}>{tx.statusLabel}</Text>
</View>
<Text style={[iStyles.m, iStyles.txt]}>{tx.dateLabel}</Text>
<View style={iStyles.l}>
<Text style={[iStyles.txt, iStyles.wrap]} numberOfLines={1}>
{tx.id}
</Text>
</View>
<Text style={[iStyles.m, iStyles.txt]}>{tx.amountLabel}</Text>
<Text style={[iStyles.s, iStyles.txt]}>{tx.feeLabel}</Text>
</ListItem>
);
InvestmentListItem.propTypes = {
tx: PropTypes.object.isRequired,
onSelect: PropTypes.func.isRequired,
};
//
// Transaction List Header
//
const hStyles = StyleSheet.create({
txt: {
color: color.greyListHeader,
fontSize: font.sizeXS,
},
header: {
backgroundColor: color.blackDark,
},
});
const InvestmentListHeader = () => (
<ListHeader style={[iStyles.item, hStyles.header]}>
<View style={iStyles.i} />
<Text style={[iStyles.m, hStyles.txt]}>STATUS</Text>
<Text style={[iStyles.m, hStyles.txt]}>DATE</Text>
<Text style={[iStyles.l, hStyles.txt]}>CONTRACT ID</Text>
<Text style={[iStyles.m, hStyles.txt]}>AMOUNT</Text>
<Text style={[iStyles.s, hStyles.txt]}>FEE</Text>
</ListHeader>
);
export default observer(InvestmentView);
...@@ -40,12 +40,14 @@ import ChannelDetail from './channel-detail'; ...@@ -40,12 +40,14 @@ import ChannelDetail from './channel-detail';
import ChannelDelete from './channel-delete'; import ChannelDelete from './channel-delete';
import ChannelCreate from './channel-create'; import ChannelCreate from './channel-create';
import PoolAdd from './pool-add'; import PoolAdd from './pool-add';
import Investment from './investment';
import Transaction from './transaction'; import Transaction from './transaction';
import Promotion from './promotion'; import Promotion from './promotion';
import Pool from './pool'; import Pool from './pool';
import Setting from './setting'; import Setting from './setting';
import SettingUnit from './setting-unit'; import SettingUnit from './setting-unit';
import SettingFiat from './setting-fiat'; import SettingFiat from './setting-fiat';
import SetContract from './set-contract';
import Notification from './notification'; import Notification from './notification';
import CLI from './cli'; import CLI from './cli';
import TransactionDetail from './transaction-detail'; import TransactionDetail from './transaction-detail';
...@@ -57,6 +59,7 @@ import { ...@@ -57,6 +59,7 @@ import {
payment, payment,
invoice, invoice,
channel, channel,
investment,
transaction, transaction,
promotion, promotion,
setting, setting,
...@@ -144,6 +147,7 @@ class MainView extends Component { ...@@ -144,6 +147,7 @@ class MainView extends Component {
<SettingFiat store={store} nav={nav} setting={setting} /> <SettingFiat store={store} nav={nav} setting={setting} />
)} )}
{route === 'Notifications' && <Notification store={store} nav={nav} />} {route === 'Notifications' && <Notification store={store} nav={nav} />}
{route === 'SetContract' && <SetContract store={store} nav={nav} invoice={invoice} />}
{route === 'CLI' && <CLI store={store} nav={nav} />} {route === 'CLI' && <CLI store={store} nav={nav} />}
{route === 'Pay' && ( {route === 'Pay' && (
<Payment store={store} payment={payment} nav={nav} /> <Payment store={store} payment={payment} nav={nav} />
...@@ -200,6 +204,9 @@ class MainView extends Component { ...@@ -200,6 +204,9 @@ class MainView extends Component {
{route === 'PoolAdd' && ( {route === 'PoolAdd' && (
<PoolAdd store={store} channel={channel} nav={nav} /> <PoolAdd store={store} channel={channel} nav={nav} />
)} )}
{route === 'Investments' && (
<Investment store={store} transaction={transaction} nav={nav} />
)}
{route === 'Transactions' && ( {route === 'Transactions' && (
<Transaction store={store} transaction={transaction} nav={nav} /> <Transaction store={store} transaction={transaction} nav={nav} />
)} )}
......
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { observer } from 'mobx-react';
import PropTypes from 'prop-types';
import Background from '../component/background';
import { Header, Title } from '../component/header';
import { Button, BackButton, SmallPillButton } from '../component/button';
import { ListContent, List, ListItem, ListHeader } from '../component/list';
import { Alert } from '../component/notification';
import Text from '../component/text';
import { color, font } from '../component/style';
//
// ManageContract View
//
const ManageContractView = ({ store, nav }) => {
const { computedNotifications: notifications } = store;
return (
<Background color={color.blackDark}>
<Header separator>
<BackButton onPress={() => nav.goSettings()} />
<Title title="Notifications" />
<Button disabled onPress={() => {}} />
</Header>
<ListContent>
<List
data={notifications}
renderHeader={ManageContractListHeader}
renderItem={item => <ManageContractListItem item={item} />}
/>
</ListContent>
</Background>
);
};
ManageContractView.propTypes = {
store: PropTypes.object.isRequired,
nav: PropTypes.object.isRequired,
};
//
// Notification List Item
//
const iStyles = StyleSheet.create({
wrap: {
flex: 1,
paddingRight: 50,
},
txt: {
color: color.white,
fontSize: font.sizeS,
},
alert: {
marginRight: 6,
},
group: {
flexDirection: 'row',
alignItems: 'center',
},
l: { flex: 8 },
m: { flex: 3 },
s: { flex: 2 },
i: { flex: 1 },
});
const ManageContractListItem = ({ item }) => (
<ListItem>
<View style={[iStyles.s, iStyles.group]}>
<Alert type={item.type} style={iStyles.alert} />
<Text style={iStyles.txt}>{item.typeLabel}</Text>
</View>
<Text style={[iStyles.m, iStyles.txt]}>{item.dateTimeLabel}</Text>
<View style={[iStyles.l, iStyles.group]}>
<Text style={[iStyles.txt, iStyles.wrap]} numberOfLines={1}>
{item.message}
</Text>
{item.handler ? (
<SmallPillButton text={item.handlerLbl} onPress={item.handler} />
) : null}
</View>
</ListItem>
);
ManageContractListItem.propTypes = {
item: PropTypes.object.isRequired,
};
//
// Notification List Header
//
const hStyles = StyleSheet.create({
txt: {
color: color.greyListHeader,
fontSize: font.sizeXS,
},
header: {
backgroundColor: color.blackDark,
},
});
const ManageContractListHeader = () => (
<ListHeader style={hStyles.header}>
<Text style={[iStyles.s, hStyles.txt]}>TYPE</Text>
<Text style={[iStyles.m, hStyles.txt]}>TIME</Text>
<Text style={[iStyles.l, hStyles.txt]}>DESCRIPTION</Text>
</ListHeader>
);
export default observer(ManageContractView);
...@@ -12,6 +12,8 @@ import Modal from '../component/modal'; ...@@ -12,6 +12,8 @@ import Modal from '../component/modal';
import { color } from '../component/style'; import { color } from '../component/style';
import LightningBoltOrangeIcon from '../asset/icon/lightning-bolt-orange'; import LightningBoltOrangeIcon from '../asset/icon/lightning-bolt-orange';
import { GlasButton, ChannelButton } from '../component/button'; import { GlasButton, ChannelButton } from '../component/button';
import store from '../store';
import { DEFAULT_FIAT } from '../config';
import Icon from '../component/icon'; import Icon from '../component/icon';
...@@ -26,34 +28,35 @@ ChartJS.register(ArcElement, Tooltip, Legend, ...@@ -26,34 +28,35 @@ ChartJS.register(ArcElement, Tooltip, Legend,
Tooltip, Tooltip,
Legend); Legend);
const options = {
responsive: true,
plugins: {
legend: {
position: 'top',
},
title: {
display: true,
text: 'performance',
},
},
};
const labels = ['30', '29', '28', '27', '26', '25', '24', '23', '22', '21', '20', '19', '18', '17', '16', '15', '14', '13', '12', '11', '10', '9', '8', '7', '6', '5', '4', '3', '2', '1'];
function newPoolSize(day){
const labels = ['30', '29', '28', '27', '26', '25', '24', '23', '22', '21', '20', '19', '18', '17', '16', '15', '14', '13', '12', '11', '10', '9', '8', '7', '6', '5', '4', '3', '2', '1', 'Today']; var size = (faker.datatype.number({ min: 1000, max: 1500 })/(Math.log(10+parseInt(day))*faker.datatype.number({ min: 0.65, max: 0.95 })));
return size;
}
export const perfData = { export const perfData = {
labels, labels,
datasets: [ datasets: [
{ {
label: 'Sales', label: 'income',
data: labels.map(() => faker.datatype.number({ min: 0, max: 100 })), data: labels.map(() => faker.datatype.number({ min: 400, max: 1000 })),
borderColor: 'rgb(99, 255, 221)',
backgroundColor: 'rgba(99, 255, 221, 0.25)',
},
{
label: 'expenses',
data: labels.map(() => faker.datatype.number({ min: 200, max: 500 })),
borderColor: 'rgb(255, 99, 132)', borderColor: 'rgb(255, 99, 132)',
backgroundColor: 'rgba(255, 99, 132, 0.5)', backgroundColor: 'rgba(255, 99, 132, 0.4)',
}, },
{ {
label: 'Volume', label: 'pool (,000)',
data: labels.map(() => faker.datatype.number({ min: 0, max: 1000 })), data: labels.map(newPoolSize),
borderColor: 'rgb(53, 162, 235)', borderColor: 'rgb(53, 162, 235)',
backgroundColor: 'rgba(53, 162, 235, 0.5)', backgroundColor: 'rgba(53, 162, 235, 0.5)',
}, },
...@@ -103,38 +106,64 @@ const iconType = t => { ...@@ -103,38 +106,64 @@ const iconType = t => {
/> />
*/ */
return require('../asset/icon/'+t+'.png'); return require('../asset/icon/'+t+'.png');
}; };
function dataGen(store, options) {
perfData.datasets[0].data = labels.map(() => faker.datatype.number({ min: 400, max: 1000 }));
perfData.datasets[1].data = labels.map(() => faker.datatype.number({ min: 200, max: 500 }));
perfData.datasets[2].data = labels.map(newPoolSize);
options.plugins.title.text = '30d Volume ('+store.settings.fiat.toLowerCase()+')';
}
const options = {
responsive: true,
plugins: {
legend: {
position: 'top',
},
title: {
display: true,
text: '30d Volume ('+store.settings.fiat.toLowerCase()+')',
},
},
};
const PoolDetailView = ({ store, nav, pooladdliq, poolremoveliq}) => ( const PoolDetailView = ({ store, nav, pooladdliq, poolremoveliq}) => (
<Background color={color.blackDark}> <Background color={color.blackDark}>
<MainContent style={styles.content}> <MainContent style={styles.content}>
<Modal title="Merchant Pool Details" onClose={() => nav.goPools()}> <Modal title={store.selectedPool.idName} onClose={() => nav.goPools()}>
<Line options={options} data={perfData} /> <Line meta={ dataGen(store, options) } options={options} data={perfData} />
<DetailField name={store.selectedPool.idName}> <DetailField name={store.selectedPool.title}>
{store.selectedPool.id} {store.selectedPool.desc}
</DetailField>
<DetailField name="Type">
{store.selectedPool.typeLabel}
</DetailField> </DetailField>
<DetailField name="Date"> <DetailField name="Performance">
{store.selectedPool.dateTimeLabel} VALUATION: 0{DEFAULT_FIAT} | PRICE: 0{DEFAULT_FIAT} | ROI: 0%
</DetailField> </DetailField>
{store.selectedPool.memo ? ( {store.selectedPool.memo ? (
<DetailField name="Note"> <DetailField name="Note">
{store.selectedPool.memo} {store.selectedPool.memo}
</DetailField> </DetailField>
) : null} ) : null}
<DetailField name="Amount"> <DetailField name="Pool">
{store.selectedPool.amountLabel} {store.unitLabel} CAP: 0{store.unitLabel} | FUNDED: 0% | INVESTORS: 1 | ID: {store.selectedPool.id}:BITS:dooca.net
</DetailField> </DetailField>
<DetailField name="Rewards"> <DetailField name="Asset Supply">
{store.selectedPool.feeLabel} {store.unitLabel} TOTAL: 1,000 | CIRCULATING: 0 | ID: 234569876
</DetailField> </DetailField>
{store.selectedPool.confirmationsLabel ? ( {store.selectedPool.confirmationsLabel ? (
<DetailField name="Confirmations"> <DetailField name="Contract">
{store.selectedPool.confirmationsLabel} POOLERS: {store.selectedPool.confirmationsLabel} | CHAIN: {store.selectedPool.typeLabel}
</DetailField> </DetailField>
) : null} ) : null}
<DetailField name="Status"> <DetailField name="Status">
......
...@@ -179,8 +179,8 @@ const PoolView = ({ store, nav, pool, goPoolAdd }) => { ...@@ -179,8 +179,8 @@ const PoolView = ({ store, nav, pool, goPoolAdd }) => {
return ( return (
<Background color={color.blackDark}> <Background color={color.blackDark}>
<Header separator> <Header separator>
<ChannelButton onPress={() => nav.goURL('https://markets.bitsoko.org')} /> <ChannelButton onPress={() => nav.goInvestments()} />
<Title title="Investment Fund" /> <Title title="Investment Pools" />
<CancelButton onPress={() => nav.goHome()} /> <CancelButton onPress={() => nav.goHome()} />
</Header> </Header>
......
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { observer } from 'mobx-react';
import PropTypes from 'prop-types';
import Background from '../component/background';
import { Header, Title } from '../component/header';
import { CopyText } from '../component/text';
import { CopyButton, Button, BackButton, RadioButton } from '../component/button';
import { SettingContent, SettingList, SettingItem } from '../component/setting';
import { color, font } from '../component/style';
import { CopiedNotification, Alert } from '../component/notification';
import Text from '../component/text';
import LightningBoltIcon from '../../src/asset/icon/lightning-bolt';
import CopyDarkIcon from '../../src/asset/icon/copy-dark';
import BitcoinIcon from '../../src/asset/icon/bitcoin';
import Icon from '../component/icon';
//import ChartApp from './chart';
//
// Pool Summary
//
const summaryStyles = StyleSheet.create({
wrapper: {
flexDirection: 'row',
paddingBottom: 10,
paddingLeft: 50,
paddingRight: 50,
},
copyTxtX: {
textAlign: 'center',
marginTop: 35,
marginBottom: 25,
maxWidth: 450,
},
smlIcon: {
height: 24,
width: 24,
},
poolInfo: {
fontSize: 10,
lineHeight: 16,
textAlign: 'center',
width: '100%',
},
topIcon: {
height: 92,
width: 92,
marginLeft: 'calc( 50% - 46 )',
margin: 10,
marginRight: 3,
paddingTop: 50,
},
topPad: {
paddingTop: 50,
},
listIcon: {
height: 22,
width: 22,
justifyContent: 'left',
},
btnWrapper: {
flexDirection: 'row',
justifyContent: 'center',
},
box: {
flexDirection: 'row',
alignItems: 'center',
padding: 10,
marginRight: 20,
backgroundColor: color.glasDarker,
borderRadius: 5,
},
alert: {
marginRight: 10,
},
txt: {
fontSize: font.sizeXS,
lineHeight: font.lineHeightXS,
},
copyBtn: {
backgroundColor: color.glas,
marginBottom: 10,
},
total: {
marginLeft: 30,
},
});
const ContractSummary = ({
poolBalanceOpenLabel,
poolBalanceClosingLabel,
unitLabel,
}) => (
<View style={summaryStyles.wrapper}>
<View style={summaryStyles.box}>
<Alert type="success" style={summaryStyles.alert} />
<Text style={summaryStyles.txt}>Uptime</Text>
<Text style={[summaryStyles.txt, summaryStyles.total]}>
365 Days
</Text>
</View>
<View style={summaryStyles.box}>
<View style={summaryStyles.alert}>
<BitcoinIcon />
</View>
<Text style={summaryStyles.txt}> ID</Text>
<Text style={[summaryStyles.txt, summaryStyles.total]}>
1456789
</Text>
</View>
</View>
);
const ContractBalances = ({
balanceLabel,
unitLabel,
}) => (
<View style={summaryStyles.wrapper}>
<View style={summaryStyles.box}>
<View style={summaryStyles.alert}>
<LightningBoltIcon height={170 * 0.06} width={135 * 0.06} />
</View>
<Text style={summaryStyles.txt}>{balanceLabel}</Text>
<Text style={[summaryStyles.txt, summaryStyles.total]}>
{unitLabel}
</Text>
</View>
</View>
);
ContractSummary.propTypes = {
poolBalanceOpenLabel: PropTypes.string.isRequired,
poolBalanceClosingLabel: PropTypes.string.isRequired,
unitLabel: PropTypes.string,
};
ContractBalances.propTypes = {
balanceLabel: PropTypes.string.isRequired,
unitLabel: PropTypes.string,
};
//
// Setting Contract View
//
const SetContractView = ({ store, nav, setting, invoice }) => {
return (
<Background color={color.blackDark}>
<Header separator>
<BackButton onPress={() => nav.goSettings()} />
<Title title="Contract Settings" />
<Button disabled onPress={() => {}} />
</Header>
<Button style={summaryStyles.topBtn}>
<Icon
image={require('../asset/icon/algorand.png')}
style={summaryStyles.topIcon}
/>
<Title style={summaryStyles.poolInfo} title="Algorand" />
<Title style={summaryStyles.poolInfo} title="https://algorand.org" />
<CopyText style={summaryStyles.copyTxtX}>
A world where everyone creates and exchanges value efficiently, transparently, and securely.
</CopyText>
<ContractSummary style={summaryStyles.btnWrapper}
poolBalanceOpenLabel=""
poolBalanceClosingLabel=""
/>
<Title style={summaryStyles.poolInfo, summaryStyles.topPad} title="Account information" />
<ContractBalances style={summaryStyles.btnWrapper}
balanceLabel="Public"
unitLabel={store.settings.chains.algo.account.address}
/>
<View style={summaryStyles.box}>
<View style={summaryStyles.alert}>
<BitcoinIcon />
</View>
<Text style={summaryStyles.txt}> Balance</Text>
<Text style={[summaryStyles.txt, summaryStyles.total]}>
0.00001
</Text>
</View>
<ContractBalances style={summaryStyles.btnWrapper}
balanceLabel="Assets"
unitLabel="0"
/>
<CopyText style={summaryStyles.copyTxtX}>
Do not share this information or funds will be compromised
</CopyText>
<CopyButton
onPress={() => invoice.toClipboard({ text: store.settings.chains.algo.account.mnemonic })}
icon={<CopyDarkIcon height={17.5} width={14} />}
style={summaryStyles.copyBtn} >
private key
</CopyButton>
</Button>
<SettingContent>
<Title style={summaryStyles.poolInfo} title="How to connect" />
<SettingList>
<SettingItem
name="Remote"
label={store.settings.chains.algo.rpc[store.settings.chains.algo.chain].server}
onSelect={() => setting.contractConnection({ chain: 'algo', connect: 'remote' })}
>
<RadioButton selected={'local' != store.settings.chains.algo.chain} />
</SettingItem>
<SettingItem
name="Local"
onSelect={() => setting.contractConnection({ chain: 'algo', connect: 'local' })}
>
<RadioButton selected={'local' === store.settings.chains.algo.chain} />
</SettingItem>
</SettingList>
</SettingContent>
<CopiedNotification
display={store.displayCopied}
color={color.notifyLight}
/>
</Background>
);
};
SetContractView.propTypes = {
invoice: PropTypes.object.isRequired,
store: PropTypes.object.isRequired,
setting: PropTypes.object.isRequired,
nav: PropTypes.object.isRequired,
};
export default observer(SetContractView);
...@@ -10,7 +10,7 @@ import { ...@@ -10,7 +10,7 @@ import {
SettingItem, SettingItem,
SettingHeader, SettingHeader,
} from '../component/setting'; } from '../component/setting';
import { CountBubble } from '../component/notification'; import { CountBubbleRed, CountBubbleGreen, CountBubbleOrange, CountBubbleGrey } from '../component/notification';
import { createStyles, maxWidth } from '../component/media-query'; import { createStyles, maxWidth } from '../component/media-query';
import { color, breakWidth } from '../component/style'; import { color, breakWidth } from '../component/style';
...@@ -23,6 +23,7 @@ const baseStyles = { ...@@ -23,6 +23,7 @@ const baseStyles = {
justifyContent: 'flex-start', justifyContent: 'flex-start',
alignItems: 'stretch', alignItems: 'stretch',
paddingTop: 35, paddingTop: 35,
paddingBottom: 35,
}, },
advanced: { advanced: {
marginTop: 50, marginTop: 50,
...@@ -31,7 +32,6 @@ const baseStyles = { ...@@ -31,7 +32,6 @@ const baseStyles = {
const styles = createStyles( const styles = createStyles(
baseStyles, baseStyles,
maxWidth(breakWidth, { maxWidth(breakWidth, {
content: { content: {
paddingTop: 35, paddingTop: 35,
...@@ -54,7 +54,7 @@ const SettingView = ({ store, nav, wallet, autopilot, auth }) => { ...@@ -54,7 +54,7 @@ const SettingView = ({ store, nav, wallet, autopilot, auth }) => {
onSelect={() => nav.goNotifications()} onSelect={() => nav.goNotifications()}
arrow arrow
> >
<CountBubble>{store.notificationCountLabel}</CountBubble> <CountBubbleRed>{store.notificationCountLabel}</CountBubbleRed>
</SettingItem> </SettingItem>
<SettingItem <SettingItem
name="Bitcoin Unit" name="Bitcoin Unit"
...@@ -83,6 +83,28 @@ const SettingView = ({ store, nav, wallet, autopilot, auth }) => { ...@@ -83,6 +83,28 @@ const SettingView = ({ store, nav, wallet, autopilot, auth }) => {
onValueChange={() => autopilot.toggle()} onValueChange={() => autopilot.toggle()}
/> />
</SettingItem> </SettingItem>
<SettingHeader name="CONTRACTS" style={styles.content}/>
<SettingItem
name="Algorand"
onSelect={() => nav.goContractSettings('algo')}
arrow
>
<CountBubbleOrange>testnet</CountBubbleOrange>
</SettingItem>
<SettingItem
name="Ethereum"
arrow
>
<CountBubbleGrey>offline</CountBubbleGrey>
<CountBubbleGreen>mainnet</CountBubbleGreen>
</SettingItem>
<SettingItem
name="Solana"
arrow
>
<CountBubbleGrey>offline</CountBubbleGrey>
<CountBubbleOrange>testnet</CountBubbleOrange>
</SettingItem>
<SettingHeader name="ADVANCED" style={styles.advanced} /> <SettingHeader name="ADVANCED" style={styles.advanced} />
<SettingItem name="Logs" onSelect={() => nav.goCLI()} arrow /> <SettingItem name="Logs" onSelect={() => nav.goCLI()} arrow />
</SettingContent> </SettingContent>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment