WIP: Implement add transaction page

This commit is contained in:
William Brawner 2018-08-29 09:11:07 -05:00
parent 344ebbf31b
commit d678eecddd
14 changed files with 199 additions and 23 deletions

View file

@ -1,10 +1,14 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router'; import { RouterModule, Routes } from '@angular/router';
import { TransactionsComponent } from './transactions/transactions.component'; import { TransactionsComponent } from './transactions/transactions.component';
import { TransactionDetailsComponent } from './transaction-details/transaction-details.component';
import { NewTransactionComponent } from './new-transaction/new-transaction.component';
const routes: Routes = [ const routes: Routes = [
{ path: '', redirectTo: '/transactions', pathMatch: 'full' }, { path: '', redirectTo: '/transactions', pathMatch: 'full' },
{ path: 'transactions', component: TransactionsComponent }, { path: 'transactions', component: TransactionsComponent },
{ path: 'transactions/new', component: NewTransactionComponent },
{ path: 'transactions/:id', component: TransactionDetailsComponent },
] ]
@NgModule({ @NgModule({

View file

@ -1,25 +1,44 @@
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import { FormsModule } from '@angular/forms';
import {MatButtonModule, MatIconModule, MatListModule, MatToolbarModule} from '@angular/material'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {
MatButtonModule,
MatDatepickerModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatListModule,
MatRadioModule,
MatToolbarModule,
} from '@angular/material';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { TransactionsComponent } from './transactions/transactions.component'; import { TransactionsComponent } from './transactions/transactions.component';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { TransactionDetailsComponent } from './transaction-details/transaction-details.component';
import { NewTransactionComponent } from './new-transaction/new-transaction.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
AppComponent, AppComponent,
TransactionsComponent TransactionsComponent,
TransactionDetailsComponent,
NewTransactionComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
BrowserAnimationsModule, BrowserAnimationsModule,
MatButtonModule, MatButtonModule,
MatFormFieldModule,
MatDatepickerModule,
MatIconModule, MatIconModule,
MatInputModule,
MatListModule, MatListModule,
MatRadioModule,
MatToolbarModule, MatToolbarModule,
AppRoutingModule AppRoutingModule,
FormsModule
], ],
providers: [], providers: [],
bootstrap: [AppComponent] bootstrap: [AppComponent]

View file

@ -0,0 +1,34 @@
<mat-toolbar>
<span>
<button (click)="goBack()">
<mat-icon>arrow_back</mat-icon>
</button>
Add Transaction
</span>
<span>
<a (click)="save()">Save</a>
</span>
</mat-toolbar>
<div class="transaction-form">
<mat-form-field>
<input matInput [(ngModel)]="transaction.title" placeholder="Name" required>
</mat-form-field>
<mat-form-field>
<textarea matInput [(ngModel)]="transaction.description" placeholder="Description"></textarea>
</mat-form-field>
<mat-form-field>
<input matInput type="number" [(ngModel)]="transaction.amount" placeholder="Amount" required>
</mat-form-field>
<mat-form-field>
<input matInput type="date" [(ngModel)]="transaction.date" placeholder="Date" required>
<!--
<input matInput [matDatePicker]="transactionDatePicker" [(ngModel)]="transaction.date" placeholder="Date" required>
<mat-datepicker #transactionDatePicker></mat-datepicker>
-->
</mat-form-field>
<mat-radio-group [(ngModel)]="transaction.type">
<mat-radio-button [value]="transactionType.EXPENSE">Expense</mat-radio-button>
<mat-radio-button [value]="transactionType.INCOME">Income</mat-radio-button>
</mat-radio-group>
</div>

View file

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NewTransactionComponent } from './new-transaction.component';
describe('NewTransactionComponent', () => {
let component: NewTransactionComponent;
let fixture: ComponentFixture<NewTransactionComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ NewTransactionComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(NewTransactionComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,29 @@
import { Component, OnInit } from '@angular/core';
import { TransactionService } from '../transaction.service'
import { Transaction } from '../transaction'
import { TransactionType } from '../transaction.type'
import { Location } from '@angular/common';
@Component({
selector: 'app-new-transaction',
templateUrl: './new-transaction.component.html',
styleUrls: ['./new-transaction.component.css']
})
export class NewTransactionComponent implements OnInit {
public transaction = new Transaction()
public transactionType = TransactionType;
constructor(
private transactionService: TransactionService,
private location: Location
) { }
ngOnInit() {
}
save(): void {
this.transactionService.saveTransaction(this.transaction);
this.location.back()
}
}

View file

@ -0,0 +1,8 @@
<div *ngIf="transaction; then transactionBlock else noTransactionBlock">
</div>
<ng-template #transactionBlock>
transaction-details works!
</ng-template>
<ng-template #noTransactionBlock>
transaction-details works!
</ng-template>

View file

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TransactionDetailsComponent } from './transaction-details.component';
describe('TransactionDetailsComponent', () => {
let component: TransactionDetailsComponent;
let fixture: ComponentFixture<TransactionDetailsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ TransactionDetailsComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TransactionDetailsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,18 @@
import { Component, OnInit } from '@angular/core';
import { Transaction } from '../transaction'
@Component({
selector: 'app-transaction-details',
templateUrl: './transaction-details.component.html',
styleUrls: ['./transaction-details.component.css']
})
export class TransactionDetailsComponent implements OnInit {
public transaction: Transaction;
constructor() { }
ngOnInit() {
}
}

View file

@ -7,21 +7,35 @@ import { TransactionType } from './transaction.type';
providedIn: 'root' providedIn: 'root'
}) })
export class TransactionService { export class TransactionService {
transactions: Transaction[] = [
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Spent some money", title: "An Expense", type: TransactionType.EXPENSE, categoryId: 0},
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Earned some money", title: "Some Income", type: TransactionType.INCOME, categoryId: 0},
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Spent some money", title: "An Expense", type: TransactionType.EXPENSE, categoryId: 0},
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Earned some money", title: "Some Income", type: TransactionType.INCOME, categoryId: 0},
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Spent some money", title: "An Expense", type: TransactionType.EXPENSE, categoryId: 0},
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Earned some money", title: "Some Income", type: TransactionType.INCOME, categoryId: 0},
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Spent some money", title: "An Expense", type: TransactionType.EXPENSE, categoryId: 0},
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Earned some money", title: "Some Income", type: TransactionType.INCOME, categoryId: 0},
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Spent some money", title: "An Expense", type: TransactionType.EXPENSE, categoryId: 0},
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Earned some money", title: "Some Income", type: TransactionType.INCOME, categoryId: 0},
]
constructor() { } constructor() { }
getTransactions(): Observable<Transaction[]> { getTransactions(): Observable<Transaction[]> {
return of([ return of(this.transactions)
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Spent some money", title: "An Expense", type: TransactionType.EXPENSE, categoryId: 0}, }
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Earned some money", title: "Some Income", type: TransactionType.INCOME, categoryId: 0},
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Spent some money", title: "An Expense", type: TransactionType.EXPENSE, categoryId: 0}, saveTransaction(transaction: Transaction): Observable<Transaction> {
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Earned some money", title: "Some Income", type: TransactionType.INCOME, categoryId: 0}, // TODO: Replace this with a DB save method
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Spent some money", title: "An Expense", type: TransactionType.EXPENSE, categoryId: 0}, var newId = 0;
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Earned some money", title: "Some Income", type: TransactionType.INCOME, categoryId: 0}, for (let transaction of this.transactions) {
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Spent some money", title: "An Expense", type: TransactionType.EXPENSE, categoryId: 0}, if (transaction.id > newId) {
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Earned some money", title: "Some Income", type: TransactionType.INCOME, categoryId: 0}, newId = transaction.id + 1;
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Spent some money", title: "An Expense", type: TransactionType.EXPENSE, categoryId: 0}, }
{id: 0, amount: Math.random() * 100, date: new Date(), description: "Earned some money", title: "Some Income", type: TransactionType.INCOME, categoryId: 0}, }
]) transaction.id = newId;
this.transactions.push(transaction)
return of(transaction)
} }
} }

View file

@ -5,7 +5,7 @@ export class Transaction {
title: string; title: string;
description: string; description: string;
amount: number; amount: number;
date: Date; date: Date = new Date();
categoryId: number; categoryId: number;
type: TransactionType; type: TransactionType = TransactionType.EXPENSE;
} }

View file

@ -15,8 +15,8 @@ p {
justify-content: space-between; justify-content: space-between;
} }
button.mat-fab { a.mat-fab {
position: fixed; position: fixed;
right: 2em; right: 2em;
bottom: 2em; bottom: 2em;
} }

View file

@ -9,6 +9,6 @@
<p matLine class="text-small">{{ transaction.date | date }}</p> <p matLine class="text-small">{{ transaction.date | date }}</p>
</mat-list-item> </mat-list-item>
</mat-list> </mat-list>
<button mat-fab> <a mat-fab routerLink="/transactions/new">
<mat-icon aria-label="Add">add</mat-icon> <mat-icon aria-label="Add">add</mat-icon>
</button> </a>