diff --git a/src/app/components/expense/expense-form/expense-form.component.ts b/src/app/components/expense/expense-form/expense-form.component.ts index 61d3fcb..07bc3a6 100644 --- a/src/app/components/expense/expense-form/expense-form.component.ts +++ b/src/app/components/expense/expense-form/expense-form.component.ts @@ -10,7 +10,7 @@ import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; import { provideNativeDateAdapter } from '@angular/material/core'; -interface ExpenseForm { +export interface ExpenseForm { date: Date; cents: number; category: Category; @@ -29,13 +29,13 @@ interface ExpenseForm { export class ExpenseFormComponent implements OnInit { public expense = input(); public disabled = input(false); - public lastDate = input(undefined); public valid = output(); public dirty = output() - public value = output(); + public value = output(); + private lastDate = signal(undefined); private formValid = computed(() => this.form().valid() && this.form().dirty()); - private formDirty = computed(() => this.form().dirty() && this.form().touched()); + private formDirty = computed(() => this.form().dirty() || this.form().touched()); private formData = computed(() => this.buildForm(this.expense())); private formModel = signal(this.formData()); @@ -48,8 +48,14 @@ export class ExpenseFormComponent implements OnInit { private readonly merchantService: MerchantService, private readonly tagService: TagService) { effect(() => { - this.valid.emit(this.formValid()); - this.dirty.emit(this.formDirty()); + const valid = this.formValid(); + const dirty = this.formDirty(); + const value = this.form().value(); + + this.valid.emit(valid); + this.dirty.emit(dirty); + this.value.emit(value); + this.lastDate.set(value.date); }); } @@ -57,9 +63,12 @@ export class ExpenseFormComponent implements OnInit { this.reset(); } - public reset(): void { + public reset(clearDate = false): void { + if (clearDate) { + this.lastDate.set(undefined); + this.form().reset(); + } this.formModel.set(this.formData()); - this.form().reset(); } public autocompleteDisplay(value: Merchant | Category) { @@ -67,7 +76,7 @@ export class ExpenseFormComponent implements OnInit { } private buildForm(expense?: Expense): ExpenseForm { - let formData = { date: this.lastDate() ?? '', cents: '', category: '', merchant: '', note: '', tags: ''} as unknown as ExpenseForm + let formData = { date: this.lastDate() ?? '', cents: NaN, category: {}, merchant: {}, note: '', tags: [] } as unknown as ExpenseForm if (expense) { formData = { date: new Date(expense.date.toString()), @@ -78,6 +87,7 @@ export class ExpenseFormComponent implements OnInit { tags: expense.tags ?? [] } as ExpenseForm; } + return formData; } diff --git a/src/app/components/expense/expense.component.html b/src/app/components/expense/expense.component.html index b3916d4..e6c6cdd 100644 --- a/src/app/components/expense/expense.component.html +++ b/src/app/components/expense/expense.component.html @@ -21,9 +21,10 @@ + (dirty)="formDirty.set($event)" + (value)="formData.set($event)" /> diff --git a/src/app/components/expense/expense.component.ts b/src/app/components/expense/expense.component.ts index 85506b4..32f28a8 100644 --- a/src/app/components/expense/expense.component.ts +++ b/src/app/components/expense/expense.component.ts @@ -1,10 +1,11 @@ import { Component, input, model, signal, viewChild } from '@angular/core'; import { MatCardModule } from '@angular/material/card'; import { MatButtonModule } from '@angular/material/button'; -import { Expense, ExpenseService } from '../../services/expense.service'; +import { CreateExpense, Expense, ExpenseService, UpdateExpense } from '../../services/expense.service'; import { MatIcon } from '@angular/material/icon'; -import { ExpenseFormComponent } from './expense-form/expense-form.component'; +import { ExpenseForm, ExpenseFormComponent } from './expense-form/expense-form.component'; import { CurrencyPipe, DatePipe } from '@angular/common'; +import { Temporal } from '@js-temporal/polyfill'; @Component({ selector: 'app-expense', @@ -18,8 +19,11 @@ export class ExpenseComponent { public expense = input(); public editingExpense = signal(false); + public savingExpense = signal(false); + public formValid = model(false); public formDirty = model(false); + public formData = model(); public constructor(private readonly expenseService: ExpenseService) { } @@ -28,25 +32,47 @@ export class ExpenseComponent { } public async addClick(): Promise { - console.log('Adding new expense'); + const form = this.formData()!; + const postExpense: CreateExpense = { + date: new Temporal.PlainDate(form.date.getFullYear(), form.date.getMonth(), form.date.getDate()), + cents: form.cents, + categoryId: form.category.id, + note: !!form.note ? form.note : undefined, + merchantId: !!form.merchant ? form.merchant.id : undefined, + tagIds: form.tags.map(tag => tag.id) + }; + await this.expenseService.postExpense(postExpense); + this.resetForm(); } public resetAddClick(): void { - this.resetForm(); + this.resetForm(true); } public async updateClick(): Promise { - console.log('Updating expense') - this.editingExpense.set(false); - } - - public cancelUpdateClick(): void { - this.editingExpense.set(false); + const form = this.formData()!; + const updateExpense: UpdateExpense = { + id: this.expense()!.id, + date: Temporal.PlainDate.from(form.date.toString()), + cents: form.cents, + categoryId: form.category.id, + note: !!form.note ? form.note : undefined, + merchantId: !!form.merchant ? form.merchant.id : undefined, + tagIds: form.tags.map(tag => tag.id) + }; + console.log('update:', updateExpense); + // post update dto + // set expense this.resetForm(); } - private resetForm(): void { - this.form()?.reset(); + public cancelUpdateClick(): void { + this.resetForm(); + } + + private resetForm(clearDate = false): void { + this.form()?.reset(clearDate); + this.editingExpense.set(false); } // const saveExpenseModel = this.expenseModel();