diff --git a/src/app/components/add-expense/add-expense.component.html b/src/app/components/add-expense/add-expense.component.html deleted file mode 100644 index fb755ac..0000000 --- a/src/app/components/add-expense/add-expense.component.html +++ /dev/null @@ -1,56 +0,0 @@ -
- - - Track new Expense - - - - - - Date - - - - - - - Cents - - - - - Category - - - @for (category of categories(); track category.id) { - {{ category.name }} - } - - - - - Merchant - - - @for (merchant of merchants(); track merchant.id) { - {{ merchant.name }} - } - - - - - Tags - - @for (tag of tags(); track tag.id) { - {{ tag.name }} - } - - - - - Note - - - - -
diff --git a/src/app/components/expense-list/expense-list.component.html b/src/app/components/expense-list/expense-list.component.html index bed23d2..080cafc 100644 --- a/src/app/components/expense-list/expense-list.component.html +++ b/src/app/components/expense-list/expense-list.component.html @@ -1,34 +1,37 @@
- - - Tracked Expenses - + @for (expense of expenses(); track expense.id) { + + } + + + + - - - - - - + + + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - -
Date{{ `${expense.year}/${expense.month}/${expense.day}` | date }}Amount{{ (expense.cents / 100) | currency: 'USD' }}Category{{ expense.category.name }}Merchant{{ expense.merchant?.name ?? '--' }}
-
-
+ + + + +
diff --git a/src/app/components/expense-list/expense-list.component.scss b/src/app/components/expense-list/expense-list.component.scss index e69de29..818821c 100644 --- a/src/app/components/expense-list/expense-list.component.scss +++ b/src/app/components/expense-list/expense-list.component.scss @@ -0,0 +1,4 @@ +.expense-list-container { + display: grid; + gap: 1rem; +} diff --git a/src/app/components/expense-list/expense-list.component.ts b/src/app/components/expense-list/expense-list.component.ts index 08864c8..6ebaf88 100644 --- a/src/app/components/expense-list/expense-list.component.ts +++ b/src/app/components/expense-list/expense-list.component.ts @@ -3,10 +3,11 @@ import { ExpenseService } from '../../services/expense.service'; import { MatTableModule } from '@angular/material/table'; import { CurrencyPipe, DatePipe } from '@angular/common'; import { MatCardModule } from '@angular/material/card'; +import {ExpenseComponent} from '../expense/expense.component'; @Component({ selector: 'app-expense-list', - imports: [MatTableModule, MatCardModule, DatePipe, CurrencyPipe], + imports: [MatTableModule, MatCardModule, DatePipe, CurrencyPipe, ExpenseComponent], templateUrl: './expense-list.component.html', styleUrl: './expense-list.component.scss', }) diff --git a/src/app/components/expense/expense.component.html b/src/app/components/expense/expense.component.html new file mode 100644 index 0000000..66f6e56 --- /dev/null +++ b/src/app/components/expense/expense.component.html @@ -0,0 +1,96 @@ +
+ + + @if (state() === 'add') { +
+ Track new Expense + +
+ } + @if (state() === 'view') { +
+ {{ `${expense()?.year}-${expense()?.month}-${expense()?.day}` | date }} + + +
+ } +
+ + + @if (state() === 'add') { +
+ + Date + + + + + + + Cents + + + + + Category + + + @for (category of categories(); track category.id) { + {{ category.name }} + } + + + + + Merchant + + + @for (merchant of merchants(); track merchant.id) { + {{ merchant.name }} + } + + + + + Note + + + + + Tags + + @for (tag of tags(); track tag.id) { + {{ tag.name }} + } + + +
+ } + @if (state() === 'view') { +
+
+ Amount: {{ expense()?.cents! / 100 | currency}} +
+ +
+ Category: {{ expense()?.category!.name }} +
+ +
+ Merchant: {{ expense()?.merchant?.name ?? '--' }} +
+
+ +
+ Note: {{ expense()?.note ?? '--' }} +
+ +
+ Tags: +
+ } +
+
+
diff --git a/src/app/components/add-expense/add-expense.component.scss b/src/app/components/expense/expense.component.scss similarity index 57% rename from src/app/components/add-expense/add-expense.component.scss rename to src/app/components/expense/expense.component.scss index 790f538..08a52af 100644 --- a/src/app/components/add-expense/add-expense.component.scss +++ b/src/app/components/expense/expense.component.scss @@ -1,23 +1,27 @@ -.add-expense-container { +.expense-container { width: 100%; display: flex; flex-direction: column; align-items: center; -} -mat-card { - max-width: 800px; - width: 100%; + mat-card { + max-width: 800px; + width: 100%; + } } mat-card-header { padding-bottom: 1rem; - display: flex; - align-items: center; - justify-content: space-between; + + .expense-header { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + } } -mat-card-content { +.expense-content { display: grid; } @@ -26,14 +30,14 @@ mat-form-field { } @media (min-width: 550px) { - mat-card-content { + .expense-content { grid-template-columns: 1fr 1fr; gap: 1rem; } } @media (min-width: 800px) { - mat-card-content { + .expense-content { grid-template-columns: 1fr 1fr 1fr; } } diff --git a/src/app/components/add-expense/add-expense.component.ts b/src/app/components/expense/expense.component.ts similarity index 69% rename from src/app/components/add-expense/add-expense.component.ts rename to src/app/components/expense/expense.component.ts index 8bdbefc..11dd70a 100644 --- a/src/app/components/add-expense/add-expense.component.ts +++ b/src/app/components/expense/expense.component.ts @@ -1,4 +1,4 @@ -import { Component, computed, signal } from '@angular/core'; +import { Component, computed, input, signal } from '@angular/core'; import { Category, CategoryService } from '../../services/category.service'; import { Merchant, MerchantService } from '../../services/merchant.service'; import { Tag, TagService } from '../../services/tag.service'; @@ -11,8 +11,9 @@ 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'; +import { CreateExpense, Expense, ExpenseService } from '../../services/expense.service'; +import {CurrencyPipe, DatePipe} from '@angular/common'; +import {MatIcon} from '@angular/material/icon'; interface ExpenseForm { date: Date | string; @@ -24,13 +25,17 @@ interface ExpenseForm { } @Component({ - selector: 'app-add-expense', - imports: [MatDatepickerModule, MatFormFieldModule, MatInputModule, MatCardModule, MatAutocompleteModule, MatSelectModule, MatButtonModule, FormField], + selector: 'app-expense', + imports: [MatDatepickerModule, MatFormFieldModule, MatInputModule, MatCardModule, MatAutocompleteModule, MatSelectModule, MatButtonModule, FormField, DatePipe, MatIcon, CurrencyPipe], providers: [provideNativeDateAdapter(), DatePipe], - templateUrl: './add-expense.component.html', - styleUrl: './add-expense.component.scss', + templateUrl: './expense.component.html', + styleUrl: './expense.component.scss', }) -export class AddExpenseComponent { +export class ExpenseComponent { + public expense = input(); + protected expenseMode = signal<'view' | 'edit'>('view'); + protected state = computed<'add' | 'view' | 'edit'>(() => this.expense() ? this.expenseMode() : 'add'); + protected saving = signal(false); protected categories = computed(() => this.categoryService.categories()); protected merchants = computed(() => this.merchantService.merchants()); protected tags = computed(() => this.tagService.tags()); @@ -41,19 +46,24 @@ export class AddExpenseComponent { const merchantValid = this.expenseForm.merchant().valid(); const noteValid = this.expenseForm.note().valid(); - return dateValid && centsValid && categoryValid && merchantValid && noteValid; + return dateValid && centsValid && categoryValid && merchantValid && noteValid && !this.saving(); }); - protected saving = signal(false); - private defaultFormState: ExpenseForm = { - date: '', - cents: NaN, - category: '', - merchant: '', - note: '', - tags: [] + private lastSelectedDate: Date | undefined; + private expenseDate = computed(() => { + return this.expense() + ? new Date(`${this.expense()?.year}-${this.expense()?.month}-${this.expense()?.day}`) + : this.lastSelectedDate ?? ''; + }); + private defaultForm: ExpenseForm = { + date: this.expenseDate(), + cents: this.expense()?.cents ?? NaN, + category: this.expense()?.category ?? '', + merchant: this.expense()?.merchant ?? '', + note: this.expense()?.note ?? '', + tags: this.expense()?.tags ?? [] }; - private expenseModel = signal(this.defaultFormState); + private expenseModel = signal(this.defaultForm); public expenseForm = form(this.expenseModel, (schema) => { required(schema.date); required(schema.cents); @@ -84,7 +94,8 @@ export class AddExpenseComponent { this.saving.set(true); try { await this.expenseService.postExpense(expense); - this.expenseModel.set({ ...this.defaultFormState, date: saveExpenseModel.date }); + this.lastSelectedDate = saveExpenseModel.date ? saveExpenseModel.date as Date : undefined; + this.expenseModel.set({ ...this.defaultForm, date: saveExpenseModel.date }); this.expenseForm().reset(this.expenseModel()); } catch (error) { diff --git a/src/app/pages/expenses/expenses.html b/src/app/pages/expenses/expenses.html index 7d8dce9..2add09d 100644 --- a/src/app/pages/expenses/expenses.html +++ b/src/app/pages/expenses/expenses.html @@ -1,4 +1,4 @@
- +
diff --git a/src/app/pages/expenses/expenses.ts b/src/app/pages/expenses/expenses.ts index 90bd738..3132b93 100644 --- a/src/app/pages/expenses/expenses.ts +++ b/src/app/pages/expenses/expenses.ts @@ -1,12 +1,12 @@ import { Component } from '@angular/core'; import { ExpenseListComponent } from '../../components/expense-list/expense-list.component'; -import { AddExpenseComponent } from '../../components/add-expense/add-expense.component'; +import { ExpenseComponent } from '../../components/expense/expense.component'; @Component({ selector: 'app-expenses', imports: [ ExpenseListComponent, - AddExpenseComponent + ExpenseComponent ], templateUrl: './expenses.html', styleUrl: './expenses.scss'