Advertisement

#43 Displaying The Securities On The Home Screen

In this video we are going to start by implementing a fix for the problem of editing the percentage of a portfolio category and having that change be persisted in our store even if it is cancelled. This fix could then be extended to cover similar problems with other objects being saved in our store. Once that is done we will proceed to modifying our home screen to display a select input for our different plans as well as all of the securities contained in each of our accounts.

Code Snippets

portfolio-category-model.ts (1:46)

...
export class PortfolioCategoryModel {
    ...
    public get category() {
        if (this._category === null) {
            throw new Error("The category has not been defined.");
        }
        return this._category;
    }
    ...
    public get plan() {
        if (this._plan === null) {
            throw new Error("The plan has not been defined.");
        }
        return this._plan;
    }
    ...
    public clone() {
        const model = new PortfolioCategoryModel({
            categoryId: this.categoryId,
            id: this.id,
            percent: this.percent,
            planId: this.planId,
        });
        if (this._category !== null) {
            model.setCategory(this.category);
        }
        if (this._plan !== null) {
            model.setPlan(this.plan);
        }
        return model;
    }
    ...
}
src ⟩ store ⟩ portfolio-category-model.ts

portfolio-module.ts (3:50)

...
export const portfolioGetters: StoreGetterTree = {
    ...
    [GETTER_PORTFOLIO_CATEGORY]: (storeState, getters: IStoreGetters) => {
        return (id: number) => {
            ...
            return portfolioCategory.clone();
        };
    },
    ...
};
...
export const portfolioMutations: StoreMutationTree = {
    ...
    [MUTATION_UPDATE_PORTFOLIO_PLAN](storeState, payload: PayloadUpdatePortfolioPlan) {
        ...
        portfolioCategories.forEach((x) => {
            ...
            x.percent = category.percent;
        });
    },
};
...
src ⟩ store ⟩ portfolio-module.ts

portfolio-initial-state.ts (5:57)

...
if (process.env.NODE_ENV === "development") {
    ...
    const value = new PortfolioPlanModel({ categories, id: 2, name: "Value" });
    ...
    plans.push(value);
    ...
    const growthCatDelc = new PortfolioCategoryModel({ categoryId: delc.id, id: 1, percent: 38, planId: growth.id });
    const growthCatDemc = new PortfolioCategoryModel({ categoryId: demc.id, id: 2, percent: 12, planId: growth.id });
    const growthCatDesc = new PortfolioCategoryModel({ categoryId: desc.id, id: 3, percent: 6, planId: growth.id });
    const growthCatIedm = new PortfolioCategoryModel({ categoryId: iedm.id, id: 4, percent: 18, planId: growth.id });
    const growthCatIeem = new PortfolioCategoryModel({ categoryId: ieem.id, id: 5, percent: 7, planId: growth.id });
    const growthCatDfdm = new PortfolioCategoryModel({ categoryId: dfdm.id, id: 6, percent: 13, planId: growth.id });
    const growthCatIfdm = new PortfolioCategoryModel({ categoryId: ifdm.id, id: 7, percent: 3, planId: growth.id });
    const growthCatDsdm = new PortfolioCategoryModel({ categoryId: dsdm.id, id: 8, percent: 3, planId: growth.id });

    const valueCatDelc = new PortfolioCategoryModel({ categoryId: delc.id, id: 9, percent: 30, planId: value.id });
    const valueCatDemc = new PortfolioCategoryModel({ categoryId: demc.id, id: 10, percent: 8, planId: value.id });
    const valueCatDesc = new PortfolioCategoryModel({ categoryId: desc.id, id: 11, percent: 2, planId: value.id });
    const valueCatIedm = new PortfolioCategoryModel({ categoryId: iedm.id, id: 12, percent: 10, planId: value.id });
    const valueCatIeem = new PortfolioCategoryModel({ categoryId: ieem.id, id: 13, percent: 3, planId: value.id });
    const valueCatDfdm = new PortfolioCategoryModel({ categoryId: dfdm.id, id: 14, percent: 33, planId: value.id });
    const valueCatIfdm = new PortfolioCategoryModel({ categoryId: ifdm.id, id: 15, percent: 11, planId: value.id });
    const valueCatDsdm = new PortfolioCategoryModel({ categoryId: dsdm.id, id: 16, percent: 3, planId: value.id });

    categories.push(growthCatDelc);
    categories.push(growthCatDemc);
    categories.push(growthCatDesc);
    categories.push(growthCatIedm);
    categories.push(growthCatIeem);
    categories.push(growthCatDfdm);
    categories.push(growthCatIfdm);
    categories.push(growthCatDsdm);

    categories.push(valueCatDelc);
    categories.push(valueCatDemc);
    categories.push(valueCatDesc);
    categories.push(valueCatIedm);
    categories.push(valueCatIeem);
    categories.push(valueCatDfdm);
    categories.push(valueCatIfdm);
    categories.push(valueCatDsdm);
}

export const categoryState: IPortfolioCategoryModelState = {
    index: categories.length + 1,
    items: categories,
};

export const planState: IPortfolioPlanModelState = {
    index: plans.length + 1,
    items: plans,
};
src ⟩ store ⟩ portfolio-initial-state.ts

Advertisement

Home.vue (7:16)

<template lang="pug">
div Hello World
</template>
src ⟩ views ⟩ Home.vue

Home.vue (7:28)

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";

@Component
export default class Home extends Vue {}
</script>
src ⟩ views ⟩ Home.vue

Home.vue (7:48)

<script lang="ts">
...
import { currencyFormatter } from "@/functions";
import {
    AccountModel,
    AccountSecurityModel,
    GETTER_ACCOUNTS,
    GETTER_PORTFOLIO_PLANS,
    Getter,
    PortfolioPlanModel,
} from "@/store";
...
export default class Home extends Vue {
    @Getter(GETTER_ACCOUNTS) private readonly accounts!: AccountModel[];
    @Getter(GETTER_PORTFOLIO_PLANS) private readonly plans!: PortfolioPlanModel[];

    private readonly currency = currencyFormatter();

    private accountSecurities: Array<[string, AccountSecurityModel[]]> = [];
    private selectedPlan: PortfolioPlanModel | null = null;

    private mounted() {
        if (this.plans.length > 0) {
            this.selectedPlan = this.plans[0];
        }

        if (this.selectedPlan === null) {
            return;
        }

        const groups: { [key: string]: AccountSecurityModel[] } = {};
        this.selectedPlan.categories.forEach((x) => {
            this.accounts.forEach((y) => {
                const filteredSecurities = y.securities
                    .filter((z) => z.security.categoryId === x.categoryId)
                    .map((z) => {
                        const accountSecurity = new AccountSecurityModel({
                            accountId: z.accountId,
                            id: z.id,
                            security: z.security,
                            securityId: z.securityId,
                            shares: z.shares,
                        });
                        accountSecurity.account = y;
                        return accountSecurity;
                    });
                if (groups[x.category.abbreviation]) {
                    groups[x.category.abbreviation].push(...filteredSecurities);
                } else {
                    groups[x.category!.abbreviation] = filteredSecurities;
                }
            });
        });
        Object.keys(groups).forEach((x) => this.accountSecurities.push([x, groups[x]]));
    }
}
</script>
src ⟩ views ⟩ Home.vue

Home.vue (18:28)

<template lang="pug">
div.home
    select(v-model="selectedPlan")
        option(
            v-for="plan in plans"
            v-bind:key="plan.id"
            v-bind:value="plan") {{plan.name}}
    ul.account-securities
        li.row
            label Symbol
            label Account
            label Shares
            label Last
        li(
            v-for="acctSecurityArray in accountSecurities"
            v-bind:key="acctSecurityArray[0]")
            ul
                li(
                    v-for="acctSecurity in acctSecurityArray[1]"
                    v-bind:key="acctSecurity.id")
                    div.row
                        div {{acctSecurity.security.symbol}} 
                        div {{acctSecurity.account.name}}
                        div {{acctSecurity.shares}}
                        div {{currency.format(acctSecurity.security.last)}}
</template>
src ⟩ views ⟩ Home.vue

Home.vue (22:38)

<style lang="sass" scoped>
@import "../bourbon/bourbon"
@import "../bitters/functions"
@import "../bitters/variables"

.home
    @include padding(0.25rem)

.row
    display: flex
    align-items: center

    & > *
        flex: 1
</style>
src ⟩ views ⟩ Home.vue

Exciton Interactive LLC
Advertisement