cleaned up transaction history, added header subnav style
This commit is contained in:
parent
f538c9a775
commit
b4dac55d26
8 changed files with 227 additions and 79 deletions
45
js/app.js
45
js/app.js
|
@ -4,14 +4,11 @@ var App = React.createClass({
|
|||
var match, param, val, viewingPage,
|
||||
drawerOpenRaw = sessionStorage.getItem('drawerOpen');
|
||||
|
||||
[match, param, val] = window.location.search.match(/\??([^=]*)(?:=(.*))?/);
|
||||
[match, viewingPage, val] = window.location.search.match(/\??([^=]*)(?:=(.*))?/);
|
||||
|
||||
if (param && ['settings', 'discover', 'help', 'start', 'watch', 'report', 'files', 'claim', 'show', 'wallet', 'publish'].indexOf(param) != -1) {
|
||||
viewingPage = param;
|
||||
}
|
||||
|
||||
return {
|
||||
viewingPage: viewingPage ? viewingPage : 'discover',
|
||||
viewingPage: viewingPage,
|
||||
drawerOpen: drawerOpenRaw !== null ? JSON.parse(drawerOpenRaw) : true,
|
||||
pageArgs: val,
|
||||
};
|
||||
|
@ -72,12 +69,28 @@ var App = React.createClass({
|
|||
pageArgs: term
|
||||
});
|
||||
},
|
||||
getHeaderLinks: function()
|
||||
{
|
||||
switch(this.state.viewingPage)
|
||||
{
|
||||
case 'wallet':
|
||||
case 'send':
|
||||
case 'receive':
|
||||
case 'claim':
|
||||
return {
|
||||
'?wallet' : 'Overview',
|
||||
'?send' : 'Send',
|
||||
'?receive' : 'Receive',
|
||||
'?claim' : 'Claim Beta Code'
|
||||
};
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
getMainContent: function()
|
||||
{
|
||||
switch(this.state.viewingPage)
|
||||
{
|
||||
case 'discover':
|
||||
return <DiscoverPage query={this.state.pageArgs} />;
|
||||
case 'settings':
|
||||
return <SettingsPage />;
|
||||
case 'help':
|
||||
|
@ -93,23 +106,33 @@ var App = React.createClass({
|
|||
case 'claim':
|
||||
return <ClaimCodePage />;
|
||||
case 'wallet':
|
||||
return <WalletPage />;
|
||||
case 'send':
|
||||
case 'receive':
|
||||
return <WalletPage viewingPage={this.state.viewingPage} />;
|
||||
case 'send':
|
||||
return <SendPage />;
|
||||
case 'receive':
|
||||
return <ReceivePage />;
|
||||
case 'show':
|
||||
return <DetailPage name={this.state.pageArgs} />;
|
||||
case 'publish':
|
||||
return <PublishPage />;
|
||||
case 'discover':
|
||||
default:
|
||||
return <DiscoverPage query={this.state.pageArgs} />;
|
||||
}
|
||||
},
|
||||
render: function() {
|
||||
var mainContent = this.getMainContent();
|
||||
var mainContent = this.getMainContent(),
|
||||
headerLinks = this.getHeaderLinks();
|
||||
|
||||
return (
|
||||
this.state.viewingPage == 'watch' ?
|
||||
mainContent :
|
||||
<div id="window" className={ this.state.drawerOpen ? 'drawer-open' : 'drawer-closed' }>
|
||||
<Drawer onCloseDrawer={this.closeDrawer} viewingPage={this.state.viewingPage} />
|
||||
<div id="main-content">
|
||||
<Header onOpenDrawer={this.openDrawer} onSearch={this.onSearch} />
|
||||
<div id="main-content" className={ headerLinks ? 'with-sub-nav' : 'no-sub-nav' }>
|
||||
<Header onOpenDrawer={this.openDrawer} onSearch={this.onSearch} links={headerLinks} viewingPage={this.state.viewingPage} />
|
||||
{mainContent}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -77,9 +77,10 @@ var CurrencySymbol = React.createClass({
|
|||
var CreditAmount = React.createClass({
|
||||
propTypes: {
|
||||
amount: React.PropTypes.number,
|
||||
precision: React.PropTypes.number
|
||||
},
|
||||
render: function() {
|
||||
var formattedAmount = lbry.formatCredits(this.props.amount);
|
||||
var formattedAmount = lbry.formatCredits(this.props.amount, this.props.precision ? this.props.precision : 1);
|
||||
return (
|
||||
<span className="credit-amount">
|
||||
<span style={creditAmountStyle}>{formattedAmount} {parseFloat(formattedAmount) == 1.0 ? 'credit' : 'credits'}</span>
|
||||
|
|
|
@ -44,14 +44,41 @@ var Header = React.createClass({
|
|||
},
|
||||
render: function() {
|
||||
return (
|
||||
<header id="header" className={this.state.isScrolled ? 'header-scrolled' : 'header-unscrolled'}>
|
||||
<Link onClick={this.props.onOpenDrawer} icon="icon-bars" className="open-drawer-link" />
|
||||
<h1>{ this.state.title }</h1>
|
||||
<div className="header-search">
|
||||
<input type="search" onChange={this.onQueryChange}
|
||||
placeholder="Find movies, music, games, and more"/>
|
||||
<header id="header" className={ (this.state.isScrolled ? 'header-scrolled' : 'header-unscrolled') + ' ' + (this.props.links ? 'header-with-subnav' : 'header-no-subnav') }>
|
||||
<div className="header-top-bar">
|
||||
<Link onClick={this.props.onOpenDrawer} icon="icon-bars" className="open-drawer-link" />
|
||||
<h1>{ this.state.title }</h1>
|
||||
<div className="header-search">
|
||||
<input type="search" onChange={this.onQueryChange}
|
||||
placeholder="Find movies, music, games, and more"/>
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
this.props.links ?
|
||||
<SubHeader links={this.props.links} viewingPage={this.props.viewingPage} /> :
|
||||
''
|
||||
}
|
||||
</header>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var SubHeader = React.createClass({
|
||||
render: function() {
|
||||
var links = [],
|
||||
viewingUrl = '?' + this.props.viewingPage;
|
||||
|
||||
for (let link of Object.keys(this.props.links)) {
|
||||
links.push(
|
||||
<a href={link} key={link} className={ viewingUrl == link ? 'sub-header-selected' : 'sub-header-unselected' }>
|
||||
{this.props.links[link]}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<nav className="sub-header">
|
||||
{links}
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
});
|
|
@ -65,7 +65,7 @@ var ClaimCodePage = React.createClass({
|
|||
});
|
||||
},
|
||||
handleSkip: function() {
|
||||
alert('Welcome to LBRY! You can visit the Settings page to redeem an invite code at any time.');
|
||||
alert('Welcome to LBRY! You can visit the Wallet page to redeem an invite code at any time.');
|
||||
window.location = '?landing';
|
||||
},
|
||||
render: function() {
|
||||
|
|
|
@ -106,7 +106,94 @@ var SendToAddressSection = React.createClass({
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
var TransactionList = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
transactionItems: null,
|
||||
}
|
||||
},
|
||||
componentWillMount: function() {
|
||||
lbry.call('get_transaction_history', {}, (results) => {
|
||||
if (results.length == 0) {
|
||||
this.setState({ transactionItems: [] })
|
||||
} else {
|
||||
var transactionItems = [],
|
||||
condensedTransactions = {};
|
||||
|
||||
results.forEach(function(tx) {
|
||||
var txid = tx["txid"];
|
||||
if (!(txid in condensedTransactions)) {
|
||||
condensedTransactions[txid] = 0;
|
||||
}
|
||||
condensedTransactions[txid] += parseFloat(tx["value"]);
|
||||
});
|
||||
|
||||
results.reverse().forEach(function(tx) {
|
||||
var txid = tx["txid"];
|
||||
if (condensedTransactions[txid] && condensedTransactions[txid] > 0)
|
||||
{
|
||||
transactionItems.push({
|
||||
id: txid,
|
||||
date: new Date(parseInt(tx["timestamp"]) * 1000),
|
||||
amount: condensedTransactions[txid]
|
||||
});
|
||||
delete condensedTransactions[txid];
|
||||
}
|
||||
});
|
||||
|
||||
this.setState({ transactionItems: transactionItems });
|
||||
}
|
||||
});
|
||||
},
|
||||
render: function() {
|
||||
var rows = [];
|
||||
if (this.state.transactionItems && this.state.transactionItems.length > 0)
|
||||
{
|
||||
this.state.transactionItems.forEach(function(item) {
|
||||
rows.push(
|
||||
<tr key={item.id}>
|
||||
<td>{ (item.amount > 0 ? '+' : '' ) + item.amount }</td>
|
||||
<td>{ item.date.toLocaleDateString() }</td>
|
||||
<td>{ item.date.toLocaleTimeString() }</td>
|
||||
<td>
|
||||
<a className="button-text" href={"https://explorer.lbry.io/tx/"+item.id} target="_blank">{item.id.substr(0, 7)}</a>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
}
|
||||
return (
|
||||
<section className="card">
|
||||
<h3>Transaction History</h3>
|
||||
{ this.state.transactionItems === null ? <BusyMessage message="Loading transactions" /> : '' }
|
||||
{ this.state.transactionItems && rows.length === 0 ? <div className="empty">You have no transactions.</div> : '' }
|
||||
{ this.state.transactionItems && rows.length > 0 ?
|
||||
<table className="table-standard table-stretch">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Amount</th>
|
||||
<th>Date</th>
|
||||
<th>Time</th>
|
||||
<th>Transaction</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows}
|
||||
</tbody>
|
||||
</table>
|
||||
: ''
|
||||
}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var WalletPage = React.createClass({
|
||||
propTypes: {
|
||||
viewingPage: React.PropTypes.string,
|
||||
},
|
||||
componentDidMount: function() {
|
||||
document.title = "My Wallet";
|
||||
},
|
||||
|
@ -116,8 +203,7 @@ var WalletPage = React.createClass({
|
|||
*/
|
||||
getInitialState: function() {
|
||||
return {
|
||||
balance: <BusyMessage message="Checking balance" />,
|
||||
txlog: <BusyMessage message="Loading transactions" />,
|
||||
balance: null,
|
||||
}
|
||||
},
|
||||
componentWillMount: function() {
|
||||
|
@ -126,66 +212,18 @@ var WalletPage = React.createClass({
|
|||
balance: results,
|
||||
})
|
||||
});
|
||||
lbry.call('get_transaction_history', {}, (results) => {
|
||||
var out = '(You should never see this message. -- wallet.js WalletPage componentWillMount)'
|
||||
if (results.length == 0) {
|
||||
out = 'No transactions yet.';
|
||||
} else {
|
||||
var condensedTransactions = {};
|
||||
var rows = [];
|
||||
rows.push(<tr>
|
||||
<th>Amount</th>
|
||||
<th>Time</th>
|
||||
<th>Date</th>
|
||||
<th>Transaction</th>
|
||||
</tr>);
|
||||
results.forEach(function(tx) {
|
||||
var txid = tx["txid"];
|
||||
if (!(txid in condensedTransactions)) {
|
||||
condensedTransactions[txid] = 0;
|
||||
}
|
||||
condensedTransactions[txid] += parseFloat(tx["amount"]);
|
||||
});
|
||||
results.reverse().forEach(function(tx) {
|
||||
var txid = tx["txid"];
|
||||
var txval = condensedTransactions[txid];
|
||||
var txdate = new Date(parseInt(tx["time"])*1000);
|
||||
if (txid in condensedTransactions && txval != 0) {
|
||||
rows.push(<tr key={txid}>
|
||||
<td>{ (txval>0 ? '+' : '' ) + txval }</td>
|
||||
<td>{ txdate.toLocaleTimeString() }</td>
|
||||
<td>{ txdate.toLocaleDateString() }</td>
|
||||
<td>
|
||||
<a className="transaction_explorer_link" href={"https://explorer.lbry.io/tx/"+txid}>{txid}</a>
|
||||
</td>
|
||||
</tr>);
|
||||
delete condensedTransactions[tx["txid"]];
|
||||
}
|
||||
});
|
||||
out = <table className="table-standard"><tbody>{rows}</tbody></table>
|
||||
}
|
||||
this.setState({
|
||||
txlog: out,
|
||||
})
|
||||
});
|
||||
},
|
||||
render: function() {
|
||||
return (
|
||||
<main className="page">
|
||||
<section className="card">
|
||||
<h3>Balance</h3>
|
||||
{this.state.balance} <CurrencySymbol />
|
||||
</section>
|
||||
<SendToAddressSection />
|
||||
<NewAddressSection />
|
||||
<section className="card">
|
||||
<h3>Claim Invite Code</h3>
|
||||
<Link href="?claim" label="Claim a LBRY beta invite code" button="alt" />
|
||||
</section>
|
||||
<section className="card" style={{'overflowX': 'auto'}}>
|
||||
<h3>Transaction History</h3>
|
||||
{this.state.txlog}
|
||||
{ this.state.balance === null ? <BusyMessage message="Checking balance" /> : ''}
|
||||
{ this.state.balance !== null ? <CreditAmount amount={this.state.balance} precision={8} /> : '' }
|
||||
</section>
|
||||
{ this.props.viewingPage === 'wallet' ? <TransactionList /> : '' }
|
||||
{ this.props.viewingPage === 'send' ? <SendToAddressSection /> : '' }
|
||||
{ this.props.viewingPage === 'receive' ? <NewAddressSection /> : '' }
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ $drawer-width: 240px;
|
|||
#window.drawer-open
|
||||
{
|
||||
#main-content { margin-left: $drawer-width; }
|
||||
.open-drawer-link { visibility: hidden; }
|
||||
.open-drawer-link { display: none }
|
||||
#header { padding-left: $drawer-width + $spacing-vertical / 2; }
|
||||
}
|
||||
|
||||
|
@ -75,8 +75,12 @@ $drawer-width: 240px;
|
|||
{
|
||||
background: $color-primary;
|
||||
color: white;
|
||||
height: $header-height;
|
||||
padding: $spacing-vertical / 2;
|
||||
&.header-no-subnav {
|
||||
height: $header-height;
|
||||
}
|
||||
&.header-with-subnav {
|
||||
height: $header-height * 2;
|
||||
}
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
@ -89,6 +93,10 @@ $drawer-width: 240px;
|
|||
box-shadow: $default-box-shadow;
|
||||
}
|
||||
}
|
||||
.header-top-bar
|
||||
{
|
||||
padding: $spacing-vertical / 2;
|
||||
}
|
||||
.header-search
|
||||
{
|
||||
margin-left: 60px;
|
||||
|
@ -101,13 +109,54 @@ $drawer-width: 240px;
|
|||
}
|
||||
}
|
||||
|
||||
nav.sub-header
|
||||
{
|
||||
background: $color-primary;
|
||||
text-transform: uppercase;
|
||||
padding: $spacing-vertical / 2;
|
||||
> a
|
||||
{
|
||||
$sub-header-selected-underline-height: 2px;
|
||||
display: inline-block;
|
||||
margin: 0 15px;
|
||||
padding: 0 5px;
|
||||
line-height: $header-height - $spacing-vertical - $sub-header-selected-underline-height;
|
||||
color: #e8e8e8;
|
||||
&:first-child
|
||||
{
|
||||
margin-left: 0;
|
||||
}
|
||||
&:last-child
|
||||
{
|
||||
margin-right: 0;
|
||||
}
|
||||
&.sub-header-selected
|
||||
{
|
||||
border-bottom: $sub-header-selected-underline-height solid #fff;
|
||||
color: #fff;
|
||||
}
|
||||
&:hover
|
||||
{
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#main-content
|
||||
{
|
||||
background: $color-canvas;
|
||||
min-height: calc(100vh - 60px); //should be -$header-height, but I'm dumb I guess? It wouldn't work
|
||||
&.no-sub-nav
|
||||
{
|
||||
min-height: calc(100vh - 60px); //should be -$header-height, but I'm dumb I guess? It wouldn't work
|
||||
main { margin-top: $header-height; }
|
||||
}
|
||||
&.with-sub-nav
|
||||
{
|
||||
min-height: calc(100vh - 120px); //should be -$header-height, but I'm dumb I guess? It wouldn't work
|
||||
main { margin-top: $header-height * 2; }
|
||||
}
|
||||
main
|
||||
{
|
||||
margin-top: $header-height;
|
||||
padding: $spacing-vertical;
|
||||
}
|
||||
h2
|
||||
|
|
|
@ -201,6 +201,12 @@ input[type="text"], input[type="search"], textarea
|
|||
color: $color-meta-light;
|
||||
}
|
||||
|
||||
.empty
|
||||
{
|
||||
color: $color-meta-light;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.form-row
|
||||
{
|
||||
+ .form-row
|
||||
|
|
|
@ -47,4 +47,8 @@ table.table-standard {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
table.table-stretch {
|
||||
width: 100%;
|
||||
}
|
Loading…
Reference in a new issue