You've already forked openaccounting-web
mirror of
https://github.com/openaccounting/oa-web.git
synced 2025-12-12 07:00:42 +13:00
initial commit
This commit is contained in:
78
src/app/dashboard/dashboard.html
Normal file
78
src/app/dashboard/dashboard.html
Normal file
@@ -0,0 +1,78 @@
|
||||
<h1>Dashboard</h1>
|
||||
<p class="description">
|
||||
<a href="/docs/getting-started" target="_blank">Click here</a> for help getting started.
|
||||
</p>
|
||||
<div class="section">
|
||||
<!-- <div class="card getting-started">
|
||||
<button type="button" class="close" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<div class="card-body">
|
||||
<p><a href="/docs/getting-started" target="_blank">Click here</a> for help getting started.</p>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="card budget">
|
||||
<div class="card-body">
|
||||
<div class="container-fluid" [ngClass]="{expanded: budgetExpanded}">
|
||||
<div class="row">
|
||||
<div class="col-8">
|
||||
<h5>Current spending</h5>
|
||||
</div>
|
||||
<div class="col-4 amount">
|
||||
<h5>{{expenseAmount | currencyFormat:org.precision}}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" *ngFor="let expense of expenseAccounts" [routerLink]="'/accounts/'+expense.id+'/transactions'" [ngClass]="{hidden: hiddenExpenses[expense.id]}">
|
||||
<div class="col-8 name">
|
||||
{{expense.fullName | accountName:2}}
|
||||
</div>
|
||||
<div class="col-4 amount">
|
||||
{{expense.nativeBalanceCost | currencyFormat:org.precision}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-8">
|
||||
<a [routerLink]="" (click)="toggleExpandedBudget()">
|
||||
<span *ngIf="budgetExpanded">Less</span>
|
||||
<span *ngIf="!budgetExpanded">More</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-4 amount">
|
||||
<a routerLink="/reports/income">See all expenses</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card recent">
|
||||
<div class="card-body">
|
||||
<div class="container-fluid" [ngClass]="{expanded: recentExpanded}">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h5>Recent transactions</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" *ngFor="let recentTx of recentTxs" [routerLink]="'/accounts/'+recentTx.account.id+'/transactions'" [ngClass]="{hidden: recentTx.hidden}">
|
||||
<div class="col-2 date">
|
||||
{{recentTx.tx.date | date:"M/d"}}
|
||||
</div>
|
||||
<div class="col-6 description">
|
||||
{{recentTx.tx.description}}
|
||||
</div>
|
||||
<div class="col-4 amount" [ngClass]="{'negative': recentTx.split.amount > 0}">
|
||||
{{-recentTx.split.amount | currencyFormat:recentTx.account.precision}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<a [routerLink]="" (click)="toggleExpandedRecent()">
|
||||
<span *ngIf="recentExpanded">Less</span>
|
||||
<span *ngIf="!recentExpanded">More</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
19
src/app/dashboard/dashboard.module.ts
Normal file
19
src/app/dashboard/dashboard.module.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { AppRoutingModule } from '../app-routing.module';
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { DashboardPage } from './dashboard';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
DashboardPage
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
AppRoutingModule,
|
||||
SharedModule
|
||||
],
|
||||
providers: []
|
||||
})
|
||||
export class DashboardModule { }
|
||||
44
src/app/dashboard/dashboard.scss
Normal file
44
src/app/dashboard/dashboard.scss
Normal file
@@ -0,0 +1,44 @@
|
||||
@import '../../sass/variables';
|
||||
|
||||
.row {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.getting-started {
|
||||
position: relative;
|
||||
.close {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
.card-body {
|
||||
padding: 0
|
||||
}
|
||||
}
|
||||
|
||||
.budget {
|
||||
.hidden {
|
||||
display: none
|
||||
}
|
||||
.expanded .hidden {
|
||||
display: flex
|
||||
}
|
||||
.amount {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.recent {
|
||||
.amount {
|
||||
text-align: right;
|
||||
}
|
||||
.amount.negative {
|
||||
color: $negative;
|
||||
}
|
||||
.hidden {
|
||||
display: none
|
||||
}
|
||||
.expanded .hidden {
|
||||
display: flex
|
||||
}
|
||||
}
|
||||
129
src/app/dashboard/dashboard.ts
Normal file
129
src/app/dashboard/dashboard.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Logger } from '../core/logger';
|
||||
import { TransactionService } from '../core/transaction.service';
|
||||
import { AccountService } from '../core/account.service';
|
||||
import { OrgService } from '../core/org.service';
|
||||
import { SessionService } from '../core/session.service';
|
||||
import { Transaction, Split } from '../shared/transaction';
|
||||
import { Org } from '../shared/org';
|
||||
import { Account, AccountTree } from '../shared/account';
|
||||
import { TxListPage } from '../transaction/list';
|
||||
import { IncomeReport } from '../reports/income';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/operator/take';
|
||||
|
||||
class RecentTx {
|
||||
split: Split;
|
||||
account: Account;
|
||||
tx: Transaction;
|
||||
hidden: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard',
|
||||
templateUrl: 'dashboard.html',
|
||||
styleUrls: ['./dashboard.scss']
|
||||
})
|
||||
export class DashboardPage implements OnInit {
|
||||
public org: Org;
|
||||
public expenseAmount: number;
|
||||
public budgetExpanded: boolean = false;
|
||||
public recentExpanded: boolean = false;
|
||||
public expenseAccounts: Account[] = [];
|
||||
public hiddenExpenses: any = {};
|
||||
public recentTxs: RecentTx[];
|
||||
private numBudgetItems: number = 5;
|
||||
private numSplits: number = 5;
|
||||
|
||||
constructor(
|
||||
private log: Logger,
|
||||
private txService: TransactionService,
|
||||
private accountService: AccountService,
|
||||
private orgService: OrgService,
|
||||
private sessionService: SessionService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.sessionService.setLoading(true);
|
||||
this.log.debug('dashboard init');
|
||||
let periodStart = this.accountService.getPeriodStart();
|
||||
|
||||
this.org = this.orgService.getCurrentOrg();
|
||||
this.log.debug('org', this.org);
|
||||
|
||||
let tree$ = this.accountService.getAccountTreeWithPeriodBalance(periodStart);
|
||||
|
||||
tree$.do(tree => {
|
||||
let expenses = tree.getAccountByName('Expenses', 1);
|
||||
|
||||
this.expenseAmount = expenses.totalNativeBalanceCost;
|
||||
|
||||
this.expenseAccounts = tree.getFlattenedAccounts().filter(account => {
|
||||
return tree.accountIsChildOf(account, expenses) && account.recentTxCount;
|
||||
}).sort((a, b) => {
|
||||
return b.recentTxCount - a.recentTxCount;
|
||||
}).slice(0, this.numBudgetItems * 2);
|
||||
|
||||
this.hiddenExpenses = {};
|
||||
|
||||
this.expenseAccounts.forEach((account, index) => {
|
||||
if(index >= this.numBudgetItems) {
|
||||
this.hiddenExpenses[account.id] = true;
|
||||
}
|
||||
});
|
||||
})
|
||||
.switchMap(tree => {
|
||||
let expenses = tree.getAccountByName('Expenses', 1);
|
||||
let income = tree.getAccountByName('Income', 1);
|
||||
|
||||
return this.txService.getLastTransactions(this.numSplits * 4).take(1)
|
||||
.map(txs => {
|
||||
this.log.debug('lastTxs');
|
||||
this.log.debug(txs);
|
||||
return txs.map(tx => {
|
||||
let splits = tx.splits.filter(split => {
|
||||
let account = tree.accountMap[split.accountId];
|
||||
if(!account || !split.amount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tree.accountIsChildOf(account, expenses) || tree.accountIsChildOf(account, income);
|
||||
});
|
||||
|
||||
return splits.map(split => {
|
||||
let recentTx = new RecentTx();
|
||||
recentTx.split = split;
|
||||
recentTx.account = tree.accountMap[split.accountId];
|
||||
recentTx.tx = tx;
|
||||
return recentTx;
|
||||
});
|
||||
}).reduce((acc, recentTxs) => {
|
||||
return acc.concat(recentTxs);
|
||||
}, [])
|
||||
}).map(recentTxs => {
|
||||
return recentTxs.slice(0, this.numSplits * 2);
|
||||
}).map(recentTxs => {
|
||||
return recentTxs.map((recentTx, index) => {
|
||||
if(index >= this.numSplits) {
|
||||
recentTx.hidden = true;
|
||||
}
|
||||
|
||||
return recentTx;
|
||||
})
|
||||
});
|
||||
})
|
||||
.subscribe(recentTxs => {
|
||||
this.log.debug('recentTxs', recentTxs);
|
||||
this.recentTxs = recentTxs;
|
||||
this.sessionService.setLoading(false);
|
||||
});
|
||||
}
|
||||
|
||||
toggleExpandedBudget() {
|
||||
this.budgetExpanded = !this.budgetExpanded;
|
||||
}
|
||||
|
||||
toggleExpandedRecent() {
|
||||
this.recentExpanded = !this.recentExpanded;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user