Basic API consumption support and refactored UI to use material #1
6 changed files with 61 additions and 7 deletions
|
|
@ -6,6 +6,7 @@ import { MatIcon } from '@angular/material/icon';
|
|||
import { ExpenseForm, ExpenseFormComponent } from './expense-form/expense-form.component';
|
||||
import { CurrencyPipe, DatePipe } from '@angular/common';
|
||||
import { Temporal } from '@js-temporal/polyfill';
|
||||
import { SnackBarService } from '../../services/snack-bar';
|
||||
|
||||
@Component({
|
||||
selector: 'app-expense',
|
||||
|
|
@ -25,7 +26,8 @@ export class ExpenseComponent {
|
|||
public formDirty = model(false);
|
||||
public formData = model<ExpenseForm>();
|
||||
|
||||
public constructor(private readonly expenseService: ExpenseService) { }
|
||||
public constructor(private readonly expenseService: ExpenseService,
|
||||
private readonly snackBar: SnackBarService) { }
|
||||
|
||||
public editClick(): void {
|
||||
this.editingExpense.set(true);
|
||||
|
|
@ -42,12 +44,16 @@ export class ExpenseComponent {
|
|||
tagIds: form.tags.map(tag => tag.id)
|
||||
};
|
||||
this.savingExpense.set(true);
|
||||
const snackId = this.snackBar.staticBar('Tracking new expense...');
|
||||
try {
|
||||
await this.expenseService.postExpense(postExpense);
|
||||
this.resetForm();
|
||||
this.snackBar.dismiss(snackId);
|
||||
this.snackBar.autoBar('Expense tracked!');
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error); // TODO: Add error processing
|
||||
this.snackBar.dismiss(snackId);
|
||||
this.snackBar.dismissableBar('Error: '); // TODO
|
||||
}
|
||||
finally {
|
||||
this.savingExpense.set(false);
|
||||
|
|
@ -70,14 +76,18 @@ export class ExpenseComponent {
|
|||
tagIds: form.tags.map(tag => tag.id)
|
||||
};
|
||||
this.savingExpense.set(true);
|
||||
const snackId = this.snackBar.staticBar('Updating expense...');
|
||||
try {
|
||||
const expense = await this.expenseService.updateExpense(putExpense);
|
||||
this.expense.set(expense);
|
||||
this.form()?.refresh(expense);
|
||||
this.editingExpense.set(false);
|
||||
this.snackBar.dismiss(snackId);
|
||||
this.snackBar.autoBar('Expense updated!');
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error); // TODO: Add error processing
|
||||
this.snackBar.dismiss(snackId);
|
||||
this.snackBar.dismissableBar('Error: '); // TODO
|
||||
}
|
||||
finally {
|
||||
this.savingExpense.set(false);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { Injectable, signal } from '@angular/core';
|
|||
import { HttpService } from './http.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class CategoryService {
|
||||
private internalCategories = signal<Category[]>([]);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { HttpClient } from '@angular/common/http';
|
|||
import { firstValueFrom } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class HttpService {
|
||||
public constructor(private httpClient: HttpClient) { }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { Injectable, signal } from '@angular/core';
|
|||
import { HttpService } from './http.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MerchantService {
|
||||
private internalMerchants = signal<Merchant[]>([]);
|
||||
|
|
|
|||
44
src/app/services/snack-bar.ts
Normal file
44
src/app/services/snack-bar.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import { Injectable, signal } from '@angular/core';
|
||||
import { MatSnackBar, MatSnackBarRef, TextOnlySnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
interface SnackBar {
|
||||
id: string;
|
||||
ref: MatSnackBarRef<TextOnlySnackBar>;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class SnackBarService {
|
||||
protected TIMEOUT = 3000;
|
||||
|
||||
private snackBars = signal<SnackBar[]>([]);
|
||||
|
||||
public constructor(private snackBar: MatSnackBar) { }
|
||||
|
||||
public autoBar(msg: string, milliseconds = this.TIMEOUT): void {
|
||||
const timeout = milliseconds ?? this.TIMEOUT;
|
||||
this.snackBar.open(msg, undefined, { duration: timeout });
|
||||
}
|
||||
public dismissableBar(msg: string, dismissMsg = 'Dismiss'): void {
|
||||
this.snackBar.open(msg, dismissMsg);
|
||||
}
|
||||
|
||||
public staticBar(msg: string): string {
|
||||
const snackBar: SnackBar = {
|
||||
id: crypto.randomUUID().toString(),
|
||||
ref: this.snackBar.open(msg)
|
||||
};
|
||||
this.snackBars.update((bars) => [...bars, snackBar]);
|
||||
|
||||
return snackBar.id;
|
||||
}
|
||||
|
||||
public dismiss(id: string): void {
|
||||
const snackBar = this.snackBars().find((snackBar) => snackBar.id === id);
|
||||
if (snackBar) {
|
||||
snackBar.ref.dismiss();
|
||||
this.snackBars.update((bars) => bars.filter((bar) => bar.id !== snackBar.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@ import { Injectable, signal } from '@angular/core';
|
|||
import { HttpService } from './http.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class TagService {
|
||||
private internalTags = signal<Tag[]>([]);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue