diff --git a/src/app/components/add-expense/add-expense.component.html b/src/app/components/add-expense/add-expense.component.html index bcfe018..afc5f76 100644 --- a/src/app/components/add-expense/add-expense.component.html +++ b/src/app/components/add-expense/add-expense.component.html @@ -20,10 +20,10 @@ Category - - + + @for (category of categories(); track category.id) { - {{ category.name }} + {{ category.name }} } @@ -31,9 +31,9 @@ Merchant - + @for (merchant of merchants(); track merchant.id) { - {{ merchant.name }} + {{ merchant.name }} } @@ -44,7 +44,7 @@ Tags @for (tag of tags(); track tag.id) { - {{ tag.name }} + {{ tag.name }} } @@ -60,6 +60,12 @@ + + @if (errorSaving()) { + + {{ errorSaving() }} + + } diff --git a/src/app/components/add-expense/add-expense.component.ts b/src/app/components/add-expense/add-expense.component.ts index 5931c7a..e3f0d4e 100644 --- a/src/app/components/add-expense/add-expense.component.ts +++ b/src/app/components/add-expense/add-expense.component.ts @@ -1,7 +1,7 @@ import { Component, computed, signal } from '@angular/core'; -import { CategoryService } from '../../services/category.service'; -import { MerchantService } from '../../services/merchant.service'; -import { TagService } from '../../services/tag.service'; +import { Category, CategoryService } from '../../services/category.service'; +import { Merchant, MerchantService } from '../../services/merchant.service'; +import { Tag, TagService } from '../../services/tag.service'; import { form, FormField, min, required } from '@angular/forms/signals'; import { MatCardModule } from '@angular/material/card'; import { MatInputModule } from '@angular/material/input'; @@ -11,20 +11,22 @@ import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatSelectModule } from '@angular/material/select'; import { MatButtonModule } from '@angular/material/button'; import { provideNativeDateAdapter } from '@angular/material/core'; +import { CreateExpense, ExpenseService } from '../../services/expense.service'; +import { DatePipe } from '@angular/common'; interface ExpenseForm { date: Date; cents: number; - category: string; - merchant: string; + category: Category | string; + merchant: Merchant | string; note: string; - tags: string[]; + tags: Tag[]; } @Component({ selector: 'app-add-expense', imports: [MatDatepickerModule, MatFormFieldModule, MatInputModule, MatCardModule, MatAutocompleteModule, MatSelectModule, MatButtonModule, FormField], - providers: [provideNativeDateAdapter()], + providers: [provideNativeDateAdapter(), DatePipe], templateUrl: './add-expense.component.html', styleUrl: './add-expense.component.scss', }) @@ -41,6 +43,8 @@ export class AddExpenseComponent { return dateValid && centsValid && categoryValid && merchantValid && noteValid; }); + protected saving = signal(false); + protected errorSaving = signal(''); private defaultFormState: ExpenseForm = { date: new Date(), @@ -60,12 +64,40 @@ export class AddExpenseComponent { public constructor(private readonly categoryService: CategoryService, private readonly merchantService: MerchantService, - private readonly tagService: TagService) { } + private readonly tagService: TagService, + private readonly expenseService: ExpenseService, + private readonly datePipe: DatePipe) { } - public saveClick(): void { - const saveExpense = this.expenseModel(); - console.log(saveExpense); - this.expenseModel.set({ ...this.defaultFormState, date: saveExpense.date }); - this.expenseForm().reset(this.expenseModel()); + public async saveClick(): Promise { + this.errorSaving.set(''); + const saveExpenseModel = this.expenseModel(); + const date = this.datePipe.transform(saveExpenseModel.date, 'yyyy-MM-dd')?.split('-') ?? []; + const expense: CreateExpense = { + year: date[0], + month: date[1], + day: date[2], + cents: saveExpenseModel.cents, + category: saveExpenseModel.category as Category, + merchant: saveExpenseModel.merchant ? saveExpenseModel.merchant as Merchant : undefined, + note: saveExpenseModel.note ? saveExpenseModel.note : undefined, + tags: saveExpenseModel.tags + }; + + this.saving.set(true); + try { + await this.expenseService.postExpense(expense); + this.expenseModel.set({ ...this.defaultFormState, date: saveExpenseModel.date }); + this.expenseForm().reset(this.expenseModel()); + } + catch (error) { + this.errorSaving.set(`Error saving expense: ${error}`) + } + finally { + this.saving.set(false); + } + } + + public display(value: Merchant | Category | Tag) { + return value.name ?? null; } } diff --git a/src/app/services/expense.service.ts b/src/app/services/expense.service.ts index 993d225..2814357 100644 --- a/src/app/services/expense.service.ts +++ b/src/app/services/expense.service.ts @@ -19,6 +19,13 @@ export class ExpenseService { public async fetchExpenses(): Promise { this.internalExpenses.set(await this.http.get(this.expensePath)); } + + public async postExpense(expense: CreateExpense): Promise { + const createdExpense = await this.http.post(this.expensePath, expense); + await this.fetchExpenses(); + + return createdExpense; + } } export interface Expense { @@ -32,3 +39,14 @@ export interface Expense { merchant?: Merchant; tags: Tag[]; } + +export interface CreateExpense { + year: string; + month: string; + day: string; + cents: number; + category: Category; + note?: string; + merchant?: Merchant; + tags: Tag[]; +}