#32 Using Our List View And Tab Components To Display Account Details
Sunday, January 12, 2020
In this article we will finally start displaying some useful information on our account details page. Along with displaying the cash, which is a new property, associated with the account we will also show the securities and deposits. We will leverage the tabs and list view components that we created in previous videos to give us a more polished and compact way of displaying both the deposits and the securities.
Parts
- Part 45: Adjusting Shares
- Part 44: Plan Percentages
- Part 43: Home Securities
- Part 42: Updating Plans
- Part 41: Plan Details View
- Part 40: Portfolio Getters
- Part 39: Portfolio Plan
- Part 38: Portfolio Category
- Part 37: Account Securities
- Part 36: Account Transfer
- Part 35: View Account Security
- Part 34: Updating Deposit
- Part 33: View Account Deposit
- Part 32: Display Account Details
- Part 31: Account Getters
- Part 30: Deposits And Securities
- Part 29: Add Accounts Details
- Part 28: Refactoring Accounts
- Part 27: Add Security Models
- Part 26: Edit Security Details
- Part 25: View Security Details
- Part 24: Navigating To Details
- Part 23: Getters Validation
- Part 22: Query Parameters
- Part 21: Tab Entries
- Part 20: Tab Header
- Part 19: List View
- Part 18: Vuex Getters
- Part 17: End Domain Model
- Part 16: Start Domain Model
- Part 15: Pop Routes
- Part 14: Push Routes
- Part 13: Removing Accounts
- Part 12: Vuex (Decorators)
- Part 11: Vuex (Accounts)
- Part 10: The App Bar (Settings)
- Part 9: Remove Consumer Rxjs
- Part 8: The App Bar (Back)
- Part 7: Structuring Our App
- Part 6: Animation Between Views
- Part 5: Navigation Fade
- Part 4: Navigation Requests
- Part 3: Fade Animations (cont.)
- Part 2: Fade Animations
- Part 1: Splash Screen
Code Snippets
account-model.ts (1:31)
...
export interface IAccountModelConfig {
cash: number;
...
}
export class AccountModel {
private _cash = 0;
...
public get cash() {
return this._cash;
}
public set cash(value: number) {
this._cash = value;
}
...
constructor(config: IAccountModelConfig) {
this._cash = config.cash;
...
}
}
account-initial-state.ts (2:30)
...
if (process.env.NODE_ENV === "development") {
index = createAccount(index, { cash: 5684, name: "name-1" });
index = createAccount(index, { cash: 0, name: "name-2" });
}
...
functions.ts (3:07)
export function currencyFormatter(minimumFractionDigits: number = 2, maximumFractionDigits: number = 2) {
return new Intl.NumberFormat("en-US", {
currency: "USD",
maximumFractionDigits,
minimumFractionDigits,
style: "currency",
});
}
AccountsDetails.vue (4:27)
<script lang="ts">...
import { currencyFormatter } from "@/functions";
import {
AccountDepositModel,
AccountSecurityModel,
...,
} from "@/store";
...
export default class AccountsDetails extends Vue {
...
private readonly currency = currencyFormatter();
...
private accountDeposits: AccountDepositModel[] = [];
private accountSecurities: AccountSecurityModel[] = [];
private cash = 0;
private depositTotal = 0;
...
private get profit() {
return this.value - (this.depositTotal - this.cash);
}
private get roi() {
const roi = this.depositTotal === 0 ? 0 : (this.profit / this.depositTotal) * 100;
return `${roi.toFixed(2)} %`;
}
private get value() {
return this.accountSecurities.reduce((prev, cur) => prev + cur.value, 0);
}
...
private load() {
const account = this.getterAccount(this.id);
this.accountDeposits = account.deposits;
this.accountSecurities = account.securities;
this.cash = account.cash;
this.name = account.name;
this.depositTotal = account.deposits.reduce((prev, cur) => prev + cur.amount, 0);
}
...
}
</script>
AccountsDetails.vue (8:58)
<template lang="pug">
div
form
div.inputs
...
label Cash
input(
type="number"
v-model="cash")
...
div(class="account-stats")
div
label Value
div {{currency.format(value)}}
div
label Total Deposits
div {{currency.format(depositTotal)}}
div
label Profit
div {{currency.format(profit)}}
div
label ROI
div {{roi}}
</template>
AccountsDetails.vue (11:43)
<style lang="sass" scoped>
...
.account-stats
display: flex
flex-wrap: wrap
border: 1px solid $light-gray
padding-top: 0.75rem
> *
flex: 1
min-width: 150px
text-align: center
margin-bottom: 0.75rem
</style>
Advertisement
ListView.vue (14:38)
<script lang="tsx">
...
export default class ListView extends Vue {
@Prop() private readonly headings?: string[];
...
private render() {
...
return (
<ul>
...
{this.headings && (
<li class="list-item-content">
{this.headings.map((x) => (
<div class="list-item-text list-item-heading">{x}</div>
))}
<div style="opacity: 0;">⟩</div>
</li>
)}
...
</ul>
);
}
}
</script>
AccountsDetails.vue (17:14)
<script lang="tsx">
...
import ListView from "@/components/ListView.vue";
import { TabContainer } from "@/components/tabs";
...
@Component({
components: {
...,
ListView,
TabContainer,
},
})
export default class AccountsDetails extends Vue {
...
private readonly accountSecurityHeadings = ["Symbol", "Value", "Shares"];
private readonly accountDepositHeadings = ["Date", "Amount"];
...
private readonly tabs = ["Securities", "Deposits"];
...
private handleClickAccountDeposit(deposit: AccountDepositModel) {
console.log(deposit);
}
private handleClickAccountSecurity(accountSecurity: AccountSecurityModel) {
console.log(accountSecurity);
}
private handleClickCreateAccountDeposit() {
console.log("handleClickCreateAccountDeposit");
}
private handleClickCreateAccountSecurity() {
console.log("handleClickCreateAccountSecurity");
}
...
private renderDeposit(accountDeposit: AccountDepositModel) {
return (
<div class="account-deposit">
<span>{accountDeposit.date.toDateString()}</span>
<span>{this.currency.format(accountDeposit.amount)}</span>
</div>
);
}
private renderSecurity(accountSecurity: AccountSecurityModel) {
return (
<div class="account-security">
<span>{accountSecurity.security.symbol}</span>
<span>{this.currency.format(accountSecurity.value)}</span>
<span>{accountSecurity.shares}</span>
</div>
);
}
}
</script>
AccountsDetails.vue (21:42)
<template lang="pug">
div
...
TabContainer(v-bind:tabs="tabs")
ListView(
v-bind:headings="accountSecurityHeadings"
v-bind:items="accountSecurities"
v-bind:onClick="handleClickAccountSecurity"
v-bind:onClickCreate="handleClickCreateAccountSecurity"
v-bind:renderFn="renderSecurity")
ListView(
v-bind:headings="accountDepositHeadings"
v-bind:items="accountDeposits"
v-bind:onClick="handleClickAccountDeposit"
v-bind:onClickCreate="handleClickCreateAccountDeposit"
v-bind:renderFn="renderDeposit")
</template>
AccountsDetails.vue (23:50)
<style lang="sass" scoped>
...
.account-deposit, .account-security
display: flex
> *
flex: 1
</style>
ListView.vue (24:33)
<style lang="sass" scoped>
...
.list-item-heading
font-weight: 600
...
</style>
Exciton Interactive LLC