Move actionable buttons from app component to specific components

Signed-off-by: William Brawner <me@wbrawner.com>
This commit is contained in:
William Brawner 2020-02-24 19:34:35 -06:00
parent b73c59deca
commit 3ab5413c43
17 changed files with 48 additions and 82 deletions

View file

@ -1,4 +0,0 @@
export interface Actionable {
doAction(): void;
getActionLabel(): string;
}

View file

@ -1,4 +1,7 @@
<mat-sidenav-container class="sidenav-container"> <p *ngIf="!online" class="error-offline">
You appear to be offline. Twigs unfortunately doesn't currently support offline use at the moment though it may be implemented in a future release!
</p>
<mat-sidenav-container *ngIf="online" class="sidenav-container">
<mat-sidenav #sidenav mode="over" closed> <mat-sidenav #sidenav mode="over" closed>
<mat-nav-list (click)="sidenav.close()"> <mat-nav-list (click)="sidenav.close()">
<a mat-list-item *ngIf="isLoggedIn()" routerLink="">{{ getUsername() }}</a> <a mat-list-item *ngIf="isLoggedIn()" routerLink="">{{ getUsername() }}</a>
@ -21,9 +24,6 @@
<span> <span>
{{ title }} {{ title }}
</span> </span>
<span class="action-item">
<a mat-button *ngIf="actionable" (click)="actionable.doAction()">{{ actionable.getActionLabel() }}</a>
</span>
</mat-toolbar> </mat-toolbar>
<router-outlet></router-outlet> <router-outlet></router-outlet>
</mat-sidenav-content> </mat-sidenav-content>

View file

@ -1,6 +1,5 @@
import { Component, Inject } from '@angular/core'; import { Component, Inject } from '@angular/core';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { Actionable } from './actionable';
import { User } from './users/user'; import { User } from './users/user';
import { TWIGS_SERVICE, TwigsService } from './shared/twigs.service'; import { TWIGS_SERVICE, TwigsService } from './shared/twigs.service';
@ -12,8 +11,8 @@ import { TWIGS_SERVICE, TwigsService } from './shared/twigs.service';
export class AppComponent { export class AppComponent {
public title = 'Twigs'; public title = 'Twigs';
public backEnabled = false; public backEnabled = false;
public actionable: Actionable;
public user: User; public user: User;
public online = window.navigator.onLine;
constructor( constructor(
@Inject(TWIGS_SERVICE) private twigsService: TwigsService, @Inject(TWIGS_SERVICE) private twigsService: TwigsService,

View file

@ -14,6 +14,7 @@ import {
MatSelectModule, MatSelectModule,
MatToolbarModule, MatToolbarModule,
MatSidenavModule, MatSidenavModule,
MatProgressSpinnerModule,
} from '@angular/material'; } from '@angular/material';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
@ -92,6 +93,7 @@ export const CustomCurrencyMaskConfig: CurrencyMaskConfig = {
MatSelectModule, MatSelectModule,
MatToolbarModule, MatToolbarModule,
MatSidenavModule, MatSidenavModule,
MatProgressSpinnerModule,
AppRoutingModule, AppRoutingModule,
FormsModule, FormsModule,
ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }), ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }),

View file

@ -8,5 +8,6 @@
<mat-form-field> <mat-form-field>
<textarea matInput [(ngModel)]="budget.description" placeholder="Description"></textarea> <textarea matInput [(ngModel)]="budget.description" placeholder="Description"></textarea>
</mat-form-field> </mat-form-field>
<button mat-button color="accent" (click)="save()">Save</button>
<button class="button-delete" mat-button color="warn" *ngIf="budget.id" (click)="delete()">Delete</button> <button class="button-delete" mat-button color="warn" *ngIf="budget.id" (click)="delete()">Delete</button>
</div> </div>

View file

@ -1,7 +1,6 @@
import { Component, OnInit, Input, Inject, OnDestroy } from '@angular/core'; import { Component, OnInit, Input, Inject, OnDestroy } from '@angular/core';
import { Budget } from '../budget'; import { Budget } from '../budget';
import { AppComponent } from 'src/app/app.component'; import { AppComponent } from 'src/app/app.component';
import { Actionable } from 'src/app/actionable';
import { User } from 'src/app/users/user'; import { User } from 'src/app/users/user';
import { TWIGS_SERVICE, TwigsService } from 'src/app/shared/twigs.service'; import { TWIGS_SERVICE, TwigsService } from 'src/app/shared/twigs.service';
@ -10,7 +9,7 @@ import { TWIGS_SERVICE, TwigsService } from 'src/app/shared/twigs.service';
templateUrl: './add-edit-budget.component.html', templateUrl: './add-edit-budget.component.html',
styleUrls: ['./add-edit-budget.component.css'] styleUrls: ['./add-edit-budget.component.css']
}) })
export class AddEditBudgetComponent implements OnInit, OnDestroy, Actionable { export class AddEditBudgetComponent {
@Input() title: string; @Input() title: string;
@Input() budget: Budget; @Input() budget: Budget;
public userIds: number[]; public userIds: number[];
@ -22,18 +21,10 @@ export class AddEditBudgetComponent implements OnInit, OnDestroy, Actionable {
) { ) {
this.app.title = this.title; this.app.title = this.title;
this.app.backEnabled = true; this.app.backEnabled = true;
this.app.actionable = this;
this.userIds = [this.app.user.id]; this.userIds = [this.app.user.id];
} }
ngOnInit() { save(): void {
}
ngOnDestroy(): void {
this.app.actionable = null;
}
doAction(): void {
let observable; let observable;
if (this.budget.id) { if (this.budget.id) {
// This is an existing transaction, update it // This is an existing transaction, update it
@ -52,10 +43,6 @@ export class AddEditBudgetComponent implements OnInit, OnDestroy, Actionable {
}); });
} }
getActionLabel(): string {
return 'Save';
}
delete(): void { delete(): void {
this.twigsService.deleteBudget(this.budget.id); this.twigsService.deleteBudget(this.budget.id);
this.app.goBack(); this.app.goBack();

View file

@ -1,4 +1,5 @@
<div class="dashboard" *ngIf="!isLoggedIn()"> <mat-progress-spinner *ngIf="loading" diameter="50" mode="indeterminate"></mat-progress-spinner>
<div class="dashboard" *ngIf="!loading && !isLoggedIn()">
<h2 class="log-in">Welcome to Twigs!</h2> <h2 class="log-in">Welcome to Twigs!</h2>
<p>To begin tracking your finances, login or create an account!</p> <p>To begin tracking your finances, login or create an account!</p>
<div class="auth-button-container"> <div class="auth-button-container">
@ -6,7 +7,7 @@
<a routerLink="/login" mat-raised-button color="accent">Login</a> <a routerLink="/login" mat-raised-button color="accent">Login</a>
</div> </div>
</div> </div>
<mat-nav-list class="budgets" *ngIf="isLoggedIn()"> <mat-nav-list class="budgets" *ngIf="!loading && isLoggedIn()">
<a mat-list-item *ngFor="let budget of budgets" routerLink="/budgets/{{ budget.id }}"> <a mat-list-item *ngFor="let budget of budgets" routerLink="/budgets/{{ budget.id }}">
<p matLine class="budget-list-title"> <p matLine class="budget-list-title">
{{ budget.name }} {{ budget.name }}
@ -16,12 +17,12 @@
</p> </p>
</a> </a>
</mat-nav-list> </mat-nav-list>
<div class="no-budgets" *ngIf="isLoggedIn() && (!budgets || budgets.length === 0)"> <div class="no-budgets" *ngIf="!loading && isLoggedIn() && (!budgets || budgets.length === 0)">
<a mat-button routerLink="/budgets/new"> <a mat-button routerLink="/budgets/new">
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
<p>Add budgets to begin tracking your finances.</p> <p>Add budgets to begin tracking your finances.</p>
</a> </a>
</div> </div>
<a mat-fab routerLink="/budgets/new" *ngIf="isLoggedIn()"> <a mat-fab routerLink="/budgets/new" *ngIf="!loading && isLoggedIn()">
<mat-icon aria-label="Add">add</mat-icon> <mat-icon aria-label="Add">add</mat-icon>
</a> </a>

View file

@ -12,6 +12,7 @@ export class BudgetsComponent implements OnInit {
@Input() budgetId: string; @Input() budgetId: string;
public budgets: Budget[]; public budgets: Budget[];
public loading = true;
constructor( constructor(
private app: AppComponent, private app: AppComponent,
@ -21,9 +22,15 @@ export class BudgetsComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.app.backEnabled = this.isLoggedIn(); this.app.backEnabled = this.isLoggedIn();
this.app.title = 'Budgets'; this.app.title = 'Budgets';
this.twigsService.getBudgets().subscribe(budgets => { this.twigsService.getBudgets().subscribe(
this.budgets = budgets; budgets => {
}); this.budgets = budgets;
this.loading = false;
},
error => {
this.loading = false;
}
);
} }
isLoggedIn(): boolean { isLoggedIn(): boolean {

View file

@ -17,5 +17,6 @@
<input type="color" matInput [(ngModel)]="currentCategory.color" placeholder="Color"> <input type="color" matInput [(ngModel)]="currentCategory.color" placeholder="Color">
</mat-form-field> </mat-form-field>
--> -->
<button mat-button color="accent" (click)="save()">Save</button>
<button class="button-delete" mat-button color="warn" *ngIf="currentCategory.id" (click)="delete()">Delete</button> <button class="button-delete" mat-button color="warn" *ngIf="currentCategory.id" (click)="delete()">Delete</button>
</div> </div>

View file

@ -1,6 +1,5 @@
import { Component, OnInit, Input, OnDestroy, Inject } from '@angular/core'; import { Component, OnInit, Input, OnDestroy, Inject } from '@angular/core';
import { Category } from '../category'; import { Category } from '../category';
import { Actionable } from 'src/app/actionable';
import { AppComponent } from 'src/app/app.component'; import { AppComponent } from 'src/app/app.component';
import { TWIGS_SERVICE, TwigsService } from 'src/app/shared/twigs.service'; import { TWIGS_SERVICE, TwigsService } from 'src/app/shared/twigs.service';
@ -9,7 +8,7 @@ import { TWIGS_SERVICE, TwigsService } from 'src/app/shared/twigs.service';
templateUrl: './add-edit-category.component.html', templateUrl: './add-edit-category.component.html',
styleUrls: ['./add-edit-category.component.css'] styleUrls: ['./add-edit-category.component.css']
}) })
export class AddEditCategoryComponent implements OnInit, Actionable, OnDestroy { export class AddEditCategoryComponent implements OnInit {
@Input() budgetId: number; @Input() budgetId: number;
@Input() title: string; @Input() title: string;
@ -21,16 +20,11 @@ export class AddEditCategoryComponent implements OnInit, Actionable, OnDestroy {
) { } ) { }
ngOnInit() { ngOnInit() {
this.app.actionable = this;
this.app.backEnabled = true; this.app.backEnabled = true;
this.app.title = this.title; this.app.title = this.title;
} }
ngOnDestroy() { save(): void {
this.app.actionable = null;
}
doAction(): void {
let observable; let observable;
if (this.currentCategory.id) { if (this.currentCategory.id) {
// This is an existing category, update it // This is an existing category, update it
@ -57,10 +51,6 @@ export class AddEditCategoryComponent implements OnInit, Actionable, OnDestroy {
}); });
} }
getActionLabel(): string {
return 'Save';
}
delete(): void { delete(): void {
this.twigsService.deleteCategory(this.budgetId, this.currentCategory.id).subscribe(() => { this.twigsService.deleteCategory(this.budgetId, this.currentCategory.id).subscribe(() => {
this.app.goBack(); this.app.goBack();

View file

@ -28,5 +28,6 @@
<mat-radio-button [value]="true">Expense</mat-radio-button> <mat-radio-button [value]="true">Expense</mat-radio-button>
<mat-radio-button [value]="false">Income</mat-radio-button> <mat-radio-button [value]="false">Income</mat-radio-button>
</mat-radio-group> </mat-radio-group>
<button mat-button color="accent" (click)="save()">Save</button>
<button class="button-delete" mat-button color="warn" *ngIf="currentTransaction.id" (click)="delete()">Delete</button> <button class="button-delete" mat-button color="warn" *ngIf="currentTransaction.id" (click)="delete()">Delete</button>
</div> </div>

View file

@ -2,7 +2,6 @@ import { Component, OnInit, Input, OnChanges, OnDestroy, Inject, SimpleChanges }
import { Transaction } from '../transaction'; import { Transaction } from '../transaction';
import { TransactionType } from '../transaction.type'; import { TransactionType } from '../transaction.type';
import { Category } from 'src/app/categories/category'; import { Category } from 'src/app/categories/category';
import { Actionable } from 'src/app/actionable';
import { AppComponent } from 'src/app/app.component'; import { AppComponent } from 'src/app/app.component';
import { TWIGS_SERVICE, TwigsService } from 'src/app/shared/twigs.service'; import { TWIGS_SERVICE, TwigsService } from 'src/app/shared/twigs.service';
@ -11,7 +10,7 @@ import { TWIGS_SERVICE, TwigsService } from 'src/app/shared/twigs.service';
templateUrl: './add-edit-transaction.component.html', templateUrl: './add-edit-transaction.component.html',
styleUrls: ['./add-edit-transaction.component.css'] styleUrls: ['./add-edit-transaction.component.css']
}) })
export class AddEditTransactionComponent implements OnInit, OnChanges, OnDestroy, Actionable { export class AddEditTransactionComponent implements OnInit, OnChanges {
@Input() title: string; @Input() title: string;
@Input() currentTransaction: Transaction; @Input() currentTransaction: Transaction;
@Input() budgetId: number; @Input() budgetId: number;
@ -29,7 +28,6 @@ export class AddEditTransactionComponent implements OnInit, OnChanges, OnDestroy
ngOnInit() { ngOnInit() {
this.app.title = this.title; this.app.title = this.title;
this.app.backEnabled = true; this.app.backEnabled = true;
this.app.actionable = this;
this.getCategories(); this.getCategories();
let d: Date; let d: Date;
if (this.currentTransaction) { if (this.currentTransaction) {
@ -51,11 +49,7 @@ export class AddEditTransactionComponent implements OnInit, OnChanges, OnDestroy
this.currentTime = `${d.getHours()}:${d.getMinutes()}`; this.currentTime = `${d.getHours()}:${d.getMinutes()}`;
} }
ngOnDestroy() { save(): void {
this.app.actionable = null;
}
doAction(): void {
// The amount will be input as a decimal value so we need to convert it // The amount will be input as a decimal value so we need to convert it
// to an integer // to an integer
let observable; let observable;
@ -98,10 +92,6 @@ export class AddEditTransactionComponent implements OnInit, OnChanges, OnDestroy
}); });
} }
getActionLabel(): string {
return 'Save';
}
delete(): void { delete(): void {
this.twigsService.deleteTransaction(this.budgetId, this.currentTransaction.id).subscribe(() => { this.twigsService.deleteTransaction(this.budgetId, this.currentTransaction.id).subscribe(() => {
this.app.goBack(); this.app.goBack();

View file

@ -5,4 +5,5 @@
<mat-form-field> <mat-form-field>
<input matInput type="password" placeholder="Password" [(ngModel)]="password" (keyup.enter)="doAction()"/> <input matInput type="password" placeholder="Password" [(ngModel)]="password" (keyup.enter)="doAction()"/>
</mat-form-field> </mat-form-field>
<button mat-raised-button color="accent" (click)="login()">Login</button>
</div> </div>

View file

@ -1,7 +1,6 @@
import { Component, OnInit, OnDestroy, Inject, ChangeDetectorRef } from '@angular/core'; import { Component, OnInit, OnDestroy, Inject, ChangeDetectorRef } from '@angular/core';
import { TwigsService, TWIGS_SERVICE } from '../../shared/twigs.service'; import { TwigsService, TWIGS_SERVICE } from '../../shared/twigs.service';
import { User } from '../user'; import { User } from '../user';
import { Actionable } from 'src/app/actionable';
import { AppComponent } from 'src/app/app.component'; import { AppComponent } from 'src/app/app.component';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
@ -10,7 +9,7 @@ import { Router } from '@angular/router';
templateUrl: './login.component.html', templateUrl: './login.component.html',
styleUrls: ['./login.component.css'] styleUrls: ['./login.component.css']
}) })
export class LoginComponent implements OnInit, OnDestroy, Actionable { export class LoginComponent implements OnInit {
public email: string; public email: string;
public password: string; public password: string;
@ -23,15 +22,10 @@ export class LoginComponent implements OnInit, OnDestroy, Actionable {
ngOnInit() { ngOnInit() {
this.app.title = 'Login'; this.app.title = 'Login';
this.app.actionable = this;
this.app.backEnabled = true; this.app.backEnabled = true;
} }
ngOnDestroy() { login(): void {
this.app.actionable = null;
}
doAction(): void {
this.twigsService.login(this.email, this.password) this.twigsService.login(this.email, this.password)
.subscribe(user => { .subscribe(user => {
this.app.user = user; this.app.user = user;
@ -42,8 +36,4 @@ export class LoginComponent implements OnInit, OnDestroy, Actionable {
alert("Login failed. Please verify you have the correct credentials"); alert("Login failed. Please verify you have the correct credentials");
}) })
} }
getActionLabel() {
return 'Submit';
}
} }

View file

@ -1,4 +1,5 @@
<div class="form register-form"> <mat-progress-spinner *ngIf="isLoading" mode="indeterminate" diameter="50"></mat-progress-spinner>
<div *ngIf="!isLoading" class="form register-form">
<mat-form-field> <mat-form-field>
<input matInput placeholder="Username" [(ngModel)]="username" /> <input matInput placeholder="Username" [(ngModel)]="username" />
</mat-form-field> </mat-form-field>
@ -11,4 +12,5 @@
<mat-form-field> <mat-form-field>
<input matInput type="password" placeholder="Confirm Password" [(ngModel)]="confirmedPassword" /> <input matInput type="password" placeholder="Confirm Password" [(ngModel)]="confirmedPassword" />
</mat-form-field> </mat-form-field>
</div> <button mat-raised-button color="accent" (click)="register()">Register</button>
</div>

View file

@ -1,6 +1,5 @@
import { Component, OnInit, OnDestroy, Inject } from '@angular/core'; import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
import { TwigsService, TWIGS_SERVICE } from '../../shared/twigs.service'; import { TwigsService, TWIGS_SERVICE } from '../../shared/twigs.service';
import { Actionable } from 'src/app/actionable';
import { AppComponent } from 'src/app/app.component'; import { AppComponent } from 'src/app/app.component';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
@ -9,12 +8,13 @@ import { Router } from '@angular/router';
templateUrl: './register.component.html', templateUrl: './register.component.html',
styleUrls: ['./register.component.css'] styleUrls: ['./register.component.css']
}) })
export class RegisterComponent implements OnInit, OnDestroy, Actionable { export class RegisterComponent implements OnInit {
public username: string; public username: string;
public email: string; public email: string;
public password: string; public password: string;
public confirmedPassword: string; public confirmedPassword: string;
public isLoading = false;
constructor( constructor(
private app: AppComponent, private app: AppComponent,
@ -24,29 +24,22 @@ export class RegisterComponent implements OnInit, OnDestroy, Actionable {
ngOnInit() { ngOnInit() {
this.app.title = 'Register'; this.app.title = 'Register';
this.app.actionable = this;
this.app.backEnabled = true; this.app.backEnabled = true;
} }
ngOnDestroy() { register(): void {
this.app.actionable = null;
}
doAction(): void {
if (this.password !== this.confirmedPassword) { if (this.password !== this.confirmedPassword) {
alert('Passwords don\'t match'); alert('Passwords don\'t match');
return; return;
} }
this.isLoading = true;
this.twigsService.register(this.username, this.email, this.password).subscribe(user => { this.twigsService.register(this.username, this.email, this.password).subscribe(user => {
console.log(user); console.log(user);
this.router.navigate(['/']) this.router.navigate(['/'])
}, error => { }, error => {
console.error(error); console.error(error);
alert("Registration failed!") alert("Registration failed!")
this.isLoading = false;
}) })
} }
getActionLabel() {
return 'Submit';
}
} }

View file

@ -94,6 +94,11 @@ mat-sidenav {
min-width: 300px; min-width: 300px;
} }
.mat-progress-spinner {
top: 5em;
left: calc(50% - 25px);
}
.income { .income {
color: #81C784; color: #81C784;
} }