diff --git a/package-lock.json b/package-lock.json index 37680ab..79f7ee8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,12 +8,10 @@ "name": "common-cents-web", "version": "0.0.0", "dependencies": { - "@angular/cdk": "~21.1.4", "@angular/common": "^21.1.0", "@angular/compiler": "^21.1.0", "@angular/core": "^21.1.0", "@angular/forms": "^21.1.0", - "@angular/material": "~21.1.4", "@angular/platform-browser": "^21.1.0", "@angular/router": "^21.1.0", "rxjs": "~7.8.0", @@ -23,7 +21,6 @@ "@angular/build": "^21.1.3", "@angular/cli": "^21.1.3", "@angular/compiler-cli": "^21.1.0", - "@angular/material": "^21.1.4", "jsdom": "^27.1.0", "typescript": "~5.9.2", "vitest": "^4.0.8" @@ -425,22 +422,6 @@ } } }, - "node_modules/@angular/cdk": { - "version": "21.1.4", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.1.4.tgz", - "integrity": "sha512-PElA4Ww4TIa3+B/ND+fm8ZPDKONTIqc9a/s0qNxhcAD9IpDqjaBVi/fyg+ZWBtS+x0DQgJtKeCsSZ6sr2aFQaQ==", - "license": "MIT", - "dependencies": { - "parse5": "^8.0.0", - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/common": "^21.0.0 || ^22.0.0", - "@angular/core": "^21.0.0 || ^22.0.0", - "@angular/platform-browser": "^21.0.0 || ^22.0.0", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, "node_modules/@angular/cli": { "version": "21.1.3", "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.1.3.tgz", @@ -582,24 +563,6 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@angular/material": { - "version": "21.1.4", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-21.1.4.tgz", - "integrity": "sha512-Vte+4os5JexhtaPk7Duk5bIC+zU5SYF7ZHUnpmAJxW0u4D4C9lpTVepm2bfMVV2AxHjHVAnW+/anINIS401UsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/cdk": "21.1.4", - "@angular/common": "^21.0.0 || ^22.0.0", - "@angular/core": "^21.0.0 || ^22.0.0", - "@angular/forms": "^21.0.0 || ^22.0.0", - "@angular/platform-browser": "^21.0.0 || ^22.0.0", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, "node_modules/@angular/platform-browser": { "version": "21.1.3", "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.1.3.tgz", @@ -6882,6 +6845,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", + "dev": true, "license": "MIT", "dependencies": { "entities": "^6.0.0" @@ -6935,6 +6899,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" diff --git a/package.json b/package.json index e3c47c6..6c41d2b 100644 --- a/package.json +++ b/package.json @@ -23,12 +23,10 @@ "private": true, "packageManager": "npm@10.9.2", "dependencies": { - "@angular/cdk": "~21.1.4", "@angular/common": "^21.1.0", "@angular/compiler": "^21.1.0", "@angular/core": "^21.1.0", "@angular/forms": "^21.1.0", - "@angular/material": "~21.1.4", "@angular/platform-browser": "^21.1.0", "@angular/router": "^21.1.0", "rxjs": "~7.8.0", @@ -38,7 +36,6 @@ "@angular/build": "^21.1.3", "@angular/cli": "^21.1.3", "@angular/compiler-cli": "^21.1.0", - "@angular/material": "^21.1.4", "jsdom": "^27.1.0", "typescript": "~5.9.2", "vitest": "^4.0.8" diff --git a/src/app/components/add-expense/add-expense.component.html b/src/app/components/add-expense/add-expense.component.html index 8d16c98..e810435 100644 --- a/src/app/components/add-expense/add-expense.component.html +++ b/src/app/components/add-expense/add-expense.component.html @@ -1,96 +1,18 @@
- - - Track new Expense - + +
+
Date
+
Amount
+
Category
+
Merchant
+
+
+ Note +
- -
-
- Date: -
- -
- Cents (required): - -
- -
- Category (required): - -
-
- -
- Merchant (optional): - -
- -
- Note (optional): -
- + +
diff --git a/src/app/components/add-expense/add-expense.component.scss b/src/app/components/add-expense/add-expense.component.scss index 9bf429e..92fce1a 100644 --- a/src/app/components/add-expense/add-expense.component.scss +++ b/src/app/components/add-expense/add-expense.component.scss @@ -1,5 +1,5 @@ -//.add-expense-body { -// display: flex; -// justify-content: flex-start; -// gap: 0.5rem; -//} +.add-expense-body { + display: flex; + justify-content: space-between; + gap: 0.5rem; +} diff --git a/src/app/components/add-expense/add-expense.component.ts b/src/app/components/add-expense/add-expense.component.ts index b0d0ccb..86c8279 100644 --- a/src/app/components/add-expense/add-expense.component.ts +++ b/src/app/components/add-expense/add-expense.component.ts @@ -1,44 +1,14 @@ -import {Component, computed, signal} from '@angular/core'; -import {Category, CategoryService} from '../../services/category.service'; -import {Merchant, MerchantService} from '../../services/merchant.service'; -import { Tag } from '../../services/tag.service'; -import {form, FormField} from '@angular/forms/signals'; -import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from '@angular/material/card'; - -interface AddExpenseForm { - date: Date, - amount: number | string, - categoryId: string, - merchantId: string, - note: string, - tags: Tag[] -} +import { Component } from '@angular/core'; +import {CardComponent} from '../card/card.component'; @Component({ selector: 'app-add-expense', imports: [ - FormField, - MatCard, - MatCardHeader, - MatCardTitle, - MatCardContent + CardComponent ], templateUrl: './add-expense.component.html', styleUrl: './add-expense.component.scss', }) export class AddExpenseComponent { - protected categories = computed(() => this.categoryService.categories()); - protected merchants = computed(() => this.merchantService.merchants()); - private addExpenseModel = signal({ - date: new Date(), - amount: '', - categoryId: '', - merchantId: '', - note: '', - tags: [] - }); - public expenseForm = form(this.addExpenseModel); - public constructor(private readonly categoryService: CategoryService, - private readonly merchantService: MerchantService) { } } diff --git a/src/app/components/card/card.component.html b/src/app/components/card/card.component.html new file mode 100644 index 0000000..7826017 --- /dev/null +++ b/src/app/components/card/card.component.html @@ -0,0 +1,15 @@ +
+ @if (header()) { +
{{ header() }}
+ } @else { + + } + + + + @if (footer()) { + + } @else { + + } +
diff --git a/src/app/components/card/card.component.scss b/src/app/components/card/card.component.scss new file mode 100644 index 0000000..8256ece --- /dev/null +++ b/src/app/components/card/card.component.scss @@ -0,0 +1,14 @@ +.card-container { + border-radius: 5px; + padding: 1rem; + box-shadow: rgba(99, 99, 99, 0.2) 0 2px 8px 0; + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.card-header { + font-size: 1.25rem; + font-weight: 700; + font-family: sans-serif; +} diff --git a/src/app/components/card/card.component.ts b/src/app/components/card/card.component.ts new file mode 100644 index 0000000..3e45981 --- /dev/null +++ b/src/app/components/card/card.component.ts @@ -0,0 +1,12 @@ +import { Component, input } from '@angular/core'; + +@Component({ + selector: 'app-card', + imports: [], + templateUrl: './card.component.html', + styleUrl: './card.component.scss', +}) +export class CardComponent { + public header = input(''); + public footer = input(''); +} diff --git a/src/app/components/expense-list/expense-list.component.html b/src/app/components/expense-list/expense-list.component.html index bed23d2..c5fb02f 100644 --- a/src/app/components/expense-list/expense-list.component.html +++ b/src/app/components/expense-list/expense-list.component.html @@ -1,34 +1,7 @@
- - - Tracked Expenses - - - - - - - - - - - - - - - - - - - - - - - - - - -
Date{{ `${expense.year}/${expense.month}/${expense.day}` | date }}Amount{{ (expense.cents / 100) | currency: 'USD' }}Category{{ expense.category.name }}Merchant{{ expense.merchant?.name ?? '--' }}
-
-
+ @for (expense of expenses(); track expense.id) { +
+ +
+ }
diff --git a/src/app/components/expense-list/expense-list.component.scss b/src/app/components/expense-list/expense-list.component.scss index e69de29..afbad75 100644 --- a/src/app/components/expense-list/expense-list.component.scss +++ b/src/app/components/expense-list/expense-list.component.scss @@ -0,0 +1,3 @@ +.expense-item { + padding-bottom: 1rem; +} diff --git a/src/app/components/expense-list/expense-list.component.ts b/src/app/components/expense-list/expense-list.component.ts index 5a7d57d..15cc613 100644 --- a/src/app/components/expense-list/expense-list.component.ts +++ b/src/app/components/expense-list/expense-list.component.ts @@ -1,43 +1,17 @@ import { Component, computed } from '@angular/core'; import { ExpenseService } from '../../services/expense.service'; -import { - MatCell, - MatCellDef, - MatColumnDef, - MatHeaderCell, - MatHeaderCellDef, - MatHeaderRow, MatHeaderRowDef, MatRow, MatRowDef, - MatTable -} from '@angular/material/table'; -import {CurrencyPipe, DatePipe} from '@angular/common'; -import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from '@angular/material/card'; +import { ExpenseComponent } from '../expense/expense.component'; @Component({ selector: 'app-expense-list', imports: [ - MatTable, - MatColumnDef, - MatHeaderCell, - MatHeaderCellDef, - DatePipe, - MatCell, - MatCellDef, - CurrencyPipe, - MatHeaderRow, - MatHeaderRowDef, - MatRow, - MatRowDef, - MatCard, - MatCardHeader, - MatCardTitle, - MatCardContent + ExpenseComponent ], templateUrl: './expense-list.component.html', styleUrl: './expense-list.component.scss', }) export class ExpenseListComponent { protected expenses = computed(() => this.expensesService.expenses()) - protected columns = ['date', 'amount', 'category', 'merchant']; public constructor(private readonly expensesService: ExpenseService) { } } diff --git a/src/app/components/expense/expense.component.html b/src/app/components/expense/expense.component.html new file mode 100644 index 0000000..45ab8ab --- /dev/null +++ b/src/app/components/expense/expense.component.html @@ -0,0 +1,27 @@ +
+ +
+ {{ `${expense().year}/${expense().month}/${expense().day}` | date }}: {{ (expense().cents / 100) | currency: 'USD' }} +
+ +
+
Merchant: {{ expense().merchant?.name ?? '--' }}
+ +
Category: {{ expense().category.name }}
+ +
Note: {{ expense().note ?? '--' }}
+
+ + +
+
diff --git a/src/app/components/expense/expense.component.scss b/src/app/components/expense/expense.component.scss new file mode 100644 index 0000000..e27f306 --- /dev/null +++ b/src/app/components/expense/expense.component.scss @@ -0,0 +1,26 @@ +.expense-header { + font-family: sans-serif; + font-weight: bold; +} + +.expense-body { + display: flex; + flex-direction: column; + gap: 0.25rem; +} + +.expense-footer { + font-family: sans-serif; + font-size: 0.8rem; + font-weight: lighter; + display: flex; + align-items: center; + gap: 0.5rem; + color: #515151; +} + +.expense-tag { + border-radius: 0.5rem; + background-color: #f1f1f1; + padding: 0.1rem 0.5rem; +} diff --git a/src/app/components/expense/expense.component.ts b/src/app/components/expense/expense.component.ts new file mode 100644 index 0000000..647ed96 --- /dev/null +++ b/src/app/components/expense/expense.component.ts @@ -0,0 +1,18 @@ +import { Component, input } from '@angular/core'; +import { Expense } from '../../services/expense.service'; +import { CurrencyPipe, DatePipe } from '@angular/common'; +import { CardComponent } from '../card/card.component'; + +@Component({ + selector: 'app-expense', + imports: [ + CurrencyPipe, + DatePipe, + CardComponent + ], + templateUrl: './expense.component.html', + styleUrl: './expense.component.scss', +}) +export class ExpenseComponent { + public expense = input.required(); +} diff --git a/src/index.html b/src/index.html index 1da5b0f..81d82d7 100644 --- a/src/index.html +++ b/src/index.html @@ -6,10 +6,6 @@ - - - - diff --git a/src/styles.scss b/src/styles.scss index cf6f56c..90d4ee0 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -1,38 +1 @@ - -// Include theming for Angular Material with `mat.theme()`. -// This Sass mixin will define CSS variables that are used for styling Angular Material -// components according to the Material 3 design spec. -// Learn more about theming and how to use it for your application's -// custom components at https://material.angular.dev/guide/theming -@use '@angular/material' as mat; - -html { - height: 100%; - @include mat.theme(( - color: ( - primary: mat.$cyan-palette, - tertiary: mat.$orange-palette, - ), - typography: Roboto, - density: 0 - )); -} - -body { - // Default the application to a light color theme. This can be changed to - // `dark` to enable the dark color theme, or to `light dark` to defer to the - // user's system settings. - color-scheme: light; // TODO: choose 'light dark' - - // Set a default background, font and text colors for the application using - // Angular Material's system-level CSS variables. Learn more about these - // variables at https://material.angular.dev/guide/system-variables - background-color: var(--mat-sys-surface); - color: var(--mat-sys-on-surface); - font: var(--mat-sys-body-medium); - - // Reset the user agent margin. - margin: 0; - height: 100%; -} /* You can add global styles to this file, and also import other style files */