added snackbar for status updates

This commit is contained in:
Joe Arndt 2026-02-23 00:19:30 -06:00
parent 49af11d7b8
commit eab674db3f
6 changed files with 61 additions and 7 deletions

View file

@ -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);

View file

@ -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[]>([]);

View file

@ -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) { }

View file

@ -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[]>([]);

View 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));
}
}
}

View file

@ -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[]>([]);