From b1fa5c021d51dc9809f44598bf3acbcf23995cea Mon Sep 17 00:00:00 2001 From: Billy Brawner Date: Wed, 29 Aug 2018 19:20:49 -0500 Subject: [PATCH] Finish transaction persistence with basic CRUD ops --- .gitignore | 1 + package-lock.json | 5 ++ package.json | 1 + .../add-edit-transaction.component.css | 12 +++++ .../add-edit-transaction.component.html | 39 ++++++++++++++ .../add-edit-transaction.component.spec.ts | 25 +++++++++ .../add-edit-transaction.component.ts | 45 ++++++++++++++++ src/app/app.module.ts | 4 +- src/app/budget-database.ts | 37 ++++++++++++++ src/app/category.ts | 9 ++++ .../new-transaction.component.html | 35 +------------ .../new-transaction.component.ts | 16 ++---- .../transaction-details.component.html | 9 +--- .../transaction-details.component.ts | 17 +++++-- src/app/transaction.service.ts | 46 ++++++++--------- src/app/transaction.ts | 6 ++- .../transactions/transactions.component.css | 9 +--- .../transactions/transactions.component.html | 26 +++++----- src/styles.css | 51 +++++++++++-------- 19 files changed, 267 insertions(+), 126 deletions(-) create mode 100644 src/app/add-edit-transaction/add-edit-transaction.component.css create mode 100644 src/app/add-edit-transaction/add-edit-transaction.component.html create mode 100644 src/app/add-edit-transaction/add-edit-transaction.component.spec.ts create mode 100644 src/app/add-edit-transaction/add-edit-transaction.component.ts create mode 100644 src/app/budget-database.ts create mode 100644 src/app/category.ts diff --git a/.gitignore b/.gitignore index ee5c9d8..b91b5da 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ testem.log # System Files .DS_Store Thumbs.db +*.swp diff --git a/package-lock.json b/package-lock.json index 223bfd1..c909e46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2508,6 +2508,11 @@ "integrity": "sha1-ogM8CcyOFY03dI+951B4Mr1s4Sc=", "dev": true }, + "dexie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/dexie/-/dexie-2.0.4.tgz", + "integrity": "sha512-aQ/s1U2wHxwBKRrt2Z/mwFNHMQWhESerFsMYzE+5P5OsIe5o1kgpFMWkzKTtkvkyyEni6mWr/T4HUJuY9xIHLA==" + }, "di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", diff --git a/package.json b/package.json index 6b315aa..9ef9e21 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@angular/platform-browser-dynamic": "^6.1.0", "@angular/router": "^6.1.0", "core-js": "^2.5.4", + "dexie": "^2.0.4", "hammerjs": "^2.0.8", "rxjs": "^6.0.0", "zone.js": "~0.8.26" diff --git a/src/app/add-edit-transaction/add-edit-transaction.component.css b/src/app/add-edit-transaction/add-edit-transaction.component.css new file mode 100644 index 0000000..27c5310 --- /dev/null +++ b/src/app/add-edit-transaction/add-edit-transaction.component.css @@ -0,0 +1,12 @@ +.transaction-form { + padding: 1em; + color: #F1F1F1; +} + +.transaction-form * { + display: block; +} + +mat-radio-button { + padding-bottom: 15px; +} diff --git a/src/app/add-edit-transaction/add-edit-transaction.component.html b/src/app/add-edit-transaction/add-edit-transaction.component.html new file mode 100644 index 0000000..bf59689 --- /dev/null +++ b/src/app/add-edit-transaction/add-edit-transaction.component.html @@ -0,0 +1,39 @@ + + + + arrow_back + + + + {{ title }} + + + Save + + +
+

Select a transaction from the list to view details about it or edit it.

+
+
+ + + + + + + + + + + + + + + Expense + Income + + +
diff --git a/src/app/add-edit-transaction/add-edit-transaction.component.spec.ts b/src/app/add-edit-transaction/add-edit-transaction.component.spec.ts new file mode 100644 index 0000000..1ff2942 --- /dev/null +++ b/src/app/add-edit-transaction/add-edit-transaction.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AddEditTransactionComponent } from './add-edit-transaction.component'; + +describe('AddEditTransactionComponent', () => { + let component: AddEditTransactionComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AddEditTransactionComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AddEditTransactionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/add-edit-transaction/add-edit-transaction.component.ts b/src/app/add-edit-transaction/add-edit-transaction.component.ts new file mode 100644 index 0000000..dd0002c --- /dev/null +++ b/src/app/add-edit-transaction/add-edit-transaction.component.ts @@ -0,0 +1,45 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { Transaction } from '../transaction' +import { TransactionType } from '../transaction.type' +import { TransactionService } from '../transaction.service' +import { Location } from '@angular/common'; + +@Component({ + selector: 'app-add-edit-transaction', + templateUrl: './add-edit-transaction.component.html', + styleUrls: ['./add-edit-transaction.component.css'] +}) +export class AddEditTransactionComponent implements OnInit { + + @Input() title: string; + @Input() currentTransaction: Transaction; + public transactionType = TransactionType; + + constructor( + private transactionService: TransactionService, + private location: Location + ) { } + + ngOnInit() { + } + + goBack(): void { + this.location.back() + } + + save(): void { + if (this.currentTransaction.id) { + // This is an existing transaction, update it + this.transactionService.updateTransaction(this.currentTransaction); + } else { + // This is a new transaction, save it + this.transactionService.saveTransaction(this.currentTransaction); + } + this.goBack() + } + + delete(): void { + this.transactionService.deleteTransaction(this.currentTransaction); + this.goBack() + } +} diff --git a/src/app/app.module.ts b/src/app/app.module.ts index f348732..a371fd0 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -18,13 +18,15 @@ import { TransactionsComponent } from './transactions/transactions.component'; import { AppRoutingModule } from './app-routing.module'; import { TransactionDetailsComponent } from './transaction-details/transaction-details.component'; import { NewTransactionComponent } from './new-transaction/new-transaction.component'; +import { AddEditTransactionComponent } from './add-edit-transaction/add-edit-transaction.component'; @NgModule({ declarations: [ AppComponent, TransactionsComponent, TransactionDetailsComponent, - NewTransactionComponent + NewTransactionComponent, + AddEditTransactionComponent ], imports: [ BrowserModule, diff --git a/src/app/budget-database.ts b/src/app/budget-database.ts new file mode 100644 index 0000000..57dadb7 --- /dev/null +++ b/src/app/budget-database.ts @@ -0,0 +1,37 @@ +import Dexie from 'dexie'; +import { TransactionType } from './transaction.type'; +import { Category } from './category' +import { Transaction } from './transaction' + +export class BudgetDatabase extends Dexie { + transactions: Dexie.Table; + categories: Dexie.Table; + + constructor () { + super('BudgetDatabase') + this.version(1).stores({ + transactions: `++id, title, description, amount, date, category, type`, + categories: `++id, name, amount, repeat, color` + }) + this.transactions.mapToClass(Transaction) + this.categories.mapToClass(Category) + } +} + +export interface ITransaction { + id: number; + title: string; + description: string; + amount: number; + date: Date; + category: ICategory; + type: TransactionType; +} + +export interface ICategory{ + id: number; + name: string; + amount: number; + repeat: string; + color: string; +} diff --git a/src/app/category.ts b/src/app/category.ts new file mode 100644 index 0000000..e694475 --- /dev/null +++ b/src/app/category.ts @@ -0,0 +1,9 @@ +import { ICategory } from './budget-database' + +export class Category implements ICategory { + id: number; + name: string; + amount: number; + repeat: string; + color: string; +} diff --git a/src/app/new-transaction/new-transaction.component.html b/src/app/new-transaction/new-transaction.component.html index 47432a4..d3904c5 100644 --- a/src/app/new-transaction/new-transaction.component.html +++ b/src/app/new-transaction/new-transaction.component.html @@ -1,34 +1 @@ - - - - Add Transaction - - - Save - - -
- - - - - - - - - - - - - - - Expense - Income - - -
+ diff --git a/src/app/new-transaction/new-transaction.component.ts b/src/app/new-transaction/new-transaction.component.ts index 070a44a..76e241c 100644 --- a/src/app/new-transaction/new-transaction.component.ts +++ b/src/app/new-transaction/new-transaction.component.ts @@ -1,8 +1,5 @@ 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', @@ -11,19 +8,12 @@ import { Location } from '@angular/common'; }) export class NewTransactionComponent implements OnInit { - public transaction = new Transaction() - public transactionType = TransactionType; + transaction: Transaction; - constructor( - private transactionService: TransactionService, - private location: Location - ) { } + constructor() { } ngOnInit() { + this.transaction = new Transaction() } - save(): void { - this.transactionService.saveTransaction(this.transaction); - this.location.back() - } } diff --git a/src/app/transaction-details/transaction-details.component.html b/src/app/transaction-details/transaction-details.component.html index dfadeda..dcb7fdf 100644 --- a/src/app/transaction-details/transaction-details.component.html +++ b/src/app/transaction-details/transaction-details.component.html @@ -1,8 +1 @@ -
-
- - transaction-details works! - - - transaction-details works! - + diff --git a/src/app/transaction-details/transaction-details.component.ts b/src/app/transaction-details/transaction-details.component.ts index 2b1747f..3646d2f 100644 --- a/src/app/transaction-details/transaction-details.component.ts +++ b/src/app/transaction-details/transaction-details.component.ts @@ -1,4 +1,6 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, Input } from '@angular/core'; +import { TransactionService } from '../transaction.service' +import { ActivatedRoute } from '@angular/router'; import { Transaction } from '../transaction' @Component({ @@ -8,11 +10,20 @@ import { Transaction } from '../transaction' }) export class TransactionDetailsComponent implements OnInit { - public transaction: Transaction; + transaction: Transaction; - constructor() { } + constructor( + private route: ActivatedRoute, + private transactionService: TransactionService + ) { } ngOnInit() { + this.getTransaction() } + getTransaction(): void { + const id = +this.route.snapshot.paramMap.get('id') + this.transactionService.getTransaction(id) + .subscribe(transaction => this.transaction = transaction) + } } diff --git a/src/app/transaction.service.ts b/src/app/transaction.service.ts index 8cc7a9a..017c24d 100644 --- a/src/app/transaction.service.ts +++ b/src/app/transaction.service.ts @@ -1,41 +1,39 @@ import { Injectable } from '@angular/core'; -import { of, Observable } from 'rxjs'; +import { of, Observable, from } from 'rxjs'; import { Transaction } from './transaction'; import { TransactionType } from './transaction.type'; +import { BudgetDatabase } from './budget-database'; @Injectable({ providedIn: 'root' }) 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() { } + db: BudgetDatabase; + + constructor() { + this.db = new BudgetDatabase(); + } getTransactions(): Observable { - return of(this.transactions) + return from(this.db.transactions.toCollection().toArray()) + } + + getTransaction(id: number): Observable { + return from(this.db.transactions.where('id').equals(id).first()) } saveTransaction(transaction: Transaction): Observable { - // TODO: Replace this with a DB save method - var newId = 0; - for (let transaction of this.transactions) { - if (transaction.id > newId) { - newId = transaction.id + 1; - } - } - transaction.id = newId; - this.transactions.push(transaction) + this.db.transactions.put(transaction) return of(transaction) } + + updateTransaction(transaction: Transaction): Observable { + this.db.transactions.update(transaction.id, transaction) + return of([]) + } + + deleteTransaction(transaction: Transaction): Observable { + return from(this.db.transactions.delete(transaction.id)) + } } diff --git a/src/app/transaction.ts b/src/app/transaction.ts index c808345..f2af498 100644 --- a/src/app/transaction.ts +++ b/src/app/transaction.ts @@ -1,11 +1,13 @@ +import { ITransaction } from './budget-database' +import { ICategory } from './budget-database' import { TransactionType } from './transaction.type'; -export class Transaction { +export class Transaction implements ITransaction { id: number; title: string; description: string; amount: number; date: Date = new Date(); - categoryId: number; + category: ICategory; type: TransactionType = TransactionType.EXPENSE; } diff --git a/src/app/transactions/transactions.component.css b/src/app/transactions/transactions.component.css index 9ad4f42..48a3f16 100644 --- a/src/app/transactions/transactions.component.css +++ b/src/app/transactions/transactions.component.css @@ -1,5 +1,5 @@ -p { - margin: 0; +mat-toolbar { + justify-content: center; } .amount.income { @@ -15,8 +15,3 @@ p { justify-content: space-between; } -a.mat-fab { - position: fixed; - right: 2em; - bottom: 2em; -} diff --git a/src/app/transactions/transactions.component.html b/src/app/transactions/transactions.component.html index ae481a7..1151aba 100644 --- a/src/app/transactions/transactions.component.html +++ b/src/app/transactions/transactions.component.html @@ -1,14 +1,14 @@ - Transactions - - -
-

{{transaction.title}}

-

{{ - transaction.amount | currency }}

-
-

{{ transaction.date | date }}

-
-
- - add +Transactions + + +
+

{{transaction.title}}

+

{{ + transaction.amount | currency }}

+
+

{{ transaction.date | date }}

+ + + add + diff --git a/src/styles.css b/src/styles.css index 434af83..83a4907 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1,34 +1,43 @@ /* You can add global styles to this file, and also import other style files */ html, body { - background: #333333; - font-family: Roboto, "Helvetica Neue", sans-serif; - margin: 0; - padding: 0; + background: #333333; + font-family: Roboto, "Helvetica Neue", sans-serif; + margin: 0; + padding: 0; +} + +p { + margin: 0; +} + +a.mat-fab { + position: fixed; + right: 2em; + bottom: 2em; } .text-small { - font-size: 1em; - color: #BDBDBD + font-size: 1em; + color: #BDBDBD } .mat-toolbar { - box-shadow: 0px 3px 3px 1px #212121; + box-shadow: 0px 3px 3px 1px #212121; + display: flex; + justify-content: space-between; } -/* .page-title { - background: #333333; - color: #F1f1f1; - position: fixed; - left: 0; - top: 0; - right: 0; - z-index: 99; - padding: 1em; +mat-toolbar mat-icon { + vertical-align: middle; + cursor: pointer; } -.page-title h1 { - margin: 0; +mat-toolbar .action-item { + font-weight: normal; + cursor: pointer; + font-size: 0.9em; +} + +mat-toolbar .action-item a { + vertical-align: middle; } -.content { - padding-top: 68px; -} */ \ No newline at end of file