Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions src/app/app.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/* General app layout */
.app-container {
max-width: 1000px;
margin: 0 auto;
padding: 20px;
font-family: Arial, sans-serif;
}

/* Header */
header {
text-align: center;
margin-bottom: 30px;
}

header h1 {
font-size: 2rem;
color: #2d3748;
}

/* Main content layout */
main {
display: flex;
gap: 20px;
}

/* Left panel (Transactions) */
.left-panel {
flex: 1;
display: flex;
flex-direction: column;
}

/* Right panel (Balance + Saving) */
.right-panel {
flex: 1;
display: flex;
flex-direction: column;
gap: 20px;
}
356 changes: 20 additions & 336 deletions src/app/app.component.html

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { Component, computed, signal, WritableSignal } from '@angular/core';
import { TransactionComponent } from './components/transaction/transaction.component';
import { BalanceComponent } from './components/balance/balance.component';
import { SavingComponent } from './components/saving/saving.component';

@Component({
selector: 'app-root',
imports: [RouterOutlet],
imports: [TransactionComponent, BalanceComponent, SavingComponent],
templateUrl: './app.component.html',
styleUrl: './app.component.css'
styleUrl: './app.component.css',
})
export class AppComponent {
title = 'angular-budget-app';
}
export class AppComponent {}
40 changes: 40 additions & 0 deletions src/app/components/balance/balance.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
.balance-card {
border: 2px solid #4a5568;
padding: 15px;
border-radius: 8px;
width: 300px;
margin-bottom: 15px;
}

.balance-card h3 {
text-align: center;
margin-bottom: 10px;
}

.balance-card p {
text-align: center;
font-size: 1.5rem;
margin-bottom: 10px;
}

.balance-card input {
width: 100%;
padding: 5px;
margin-bottom: 10px;
border-radius: 4px;
border: 1px solid #4a5568;
}

.balance-card button {
width: 100%;
padding: 7px;
background-color: #4a5568;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}

.balance-card button:hover {
background-color: #2d3748;
}
9 changes: 9 additions & 0 deletions src/app/components/balance/balance.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div class="balance-card">
<h3>Current Balance</h3>
<p>€{{ bal() }}</p>

<label>Transfer to Savings:</label>
<input type="number" [formControl]="savings" />

<button (click)="transferToSavings()">TransferToSavings</button>
</div>
23 changes: 23 additions & 0 deletions src/app/components/balance/balance.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { BalanceComponent } from './balance.component';

describe('BalanceComponent', () => {
let component: BalanceComponent;
let fixture: ComponentFixture<BalanceComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [BalanceComponent]
})
.compileComponents();

fixture = TestBed.createComponent(BalanceComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
33 changes: 33 additions & 0 deletions src/app/components/balance/balance.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Component, computed, inject } from '@angular/core';
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TransactionService } from '../../services/transaction.service';

@Component({
selector: 'app-balance',
imports: [ReactiveFormsModule],
templateUrl: './balance.component.html',
styleUrl: './balance.component.css',
})
export class BalanceComponent {
transaction = inject(TransactionService);
bal = computed(() => this.transaction.balance());

savings = new FormControl(0);

transferToSavings() {
console.log(this.savings.value);
if ((this.savings.value as number) <= 0) {
alert(`Invalid transfer amount! ${this.savings.value as number}`);
this.savings.setValue(0);
return;
}
if (this.bal() <= 0 || this.bal() < (this.savings.value as number)) {
alert(`Insufficient funds! Current Bal: €${this.bal()}`);
this.savings.setValue(0);
return;
}

this.transaction.transferToSavings(this.savings.value as number);
this.savings.setValue(0);
}
}
1 change: 1 addition & 0 deletions src/app/components/model/transaction.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type TransactionType = 'income' | 'expense';
53 changes: 53 additions & 0 deletions src/app/components/saving/saving.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
.saving-card {
border: 2px solid #2f855a;
padding: 15px;
border-radius: 8px;
width: 300px;
margin-bottom: 15px;
}

.saving-card h3 {
text-align: center;
margin-bottom: 10px;
}

.saving-card p {
margin: 5px 0;
}

.saving-card input {
width: 100%;
padding: 5px;
margin-bottom: 10px;
border-radius: 4px;
border: 1px solid #2f855a;
}

.saving-card button {
width: 100%;
padding: 7px;
background-color: #2f855a;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
margin-bottom: 10px;
}

.saving-card button:hover {
background-color: #276749;
}

/* Progress Bar */
.progress-bar {
background-color: #c6f6d5;
border-radius: 5px;
height: 20px;
width: 100%;
}

.progress {
background-color: #2f855a;
height: 100%;
border-radius: 5px;
}
23 changes: 23 additions & 0 deletions src/app/components/saving/saving.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<div class="saving-card">
<h3>Saving Goal</h3>
<p>Target: €{{ savingTarget() }}</p>
<p>Saved: €{{ savings() }}</p>

<label>Set New Target:</label>
<input type="number" min="1" [formControl]="targetControl" />
<button (click)="updateSavingsTraget(targetControl.value)">
Update Target
</button>
<div class="progress-bar">
<div
appSavingsTarget
[savings]="savings()"
[savingsTarget]="savingTarget()"
class="progress"
></div>
</div>
<p>
Achieved {{ ((savings() / savingTarget()) * 100).toFixed(0) }}% of Savings
Goal:😎
</p>
</div>
23 changes: 23 additions & 0 deletions src/app/components/saving/saving.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { SavingComponent } from './saving.component';

describe('SavingComponent', () => {
let component: SavingComponent;
let fixture: ComponentFixture<SavingComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [SavingComponent]
})
.compileComponents();

fixture = TestBed.createComponent(SavingComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
33 changes: 33 additions & 0 deletions src/app/components/saving/saving.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {
Component,
computed,
inject,
input,
output,
signal,
} from '@angular/core';
import { TransactionService } from '../../services/transaction.service';
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { SavingsTargetDirective } from '../../directives/savings-target.directive';

@Component({
selector: 'app-saving',
imports: [ReactiveFormsModule, SavingsTargetDirective],
templateUrl: './saving.component.html',
styleUrl: './saving.component.css',
})
export class SavingComponent {
transaction = inject(TransactionService);
savings = computed(() => this.transaction.saved());
savingTarget = computed(() => this.transaction.savingsTarget());

targetControl = new FormControl(1);

updateSavingsTraget(value: number | null) {
if (!value) {
alert('Invalid input for savings target!');
return;
}
this.transaction.savingsTarget.set(value);
}
}
47 changes: 47 additions & 0 deletions src/app/components/transaction/transaction.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
.transaction-card {
border: 2px solid #2c7a7b;
padding: 15px;
border-radius: 8px;
width: 250px;
margin-bottom: 15px;
}

.select {
display: flex;
flex-direction: column;
gap: 4px;
margin-bottom: 1rem;
width: 100%;
}

.select select {
padding: 5px;
width: 100%;
border-radius: 5px;
}
.transaction-card h3 {
text-align: center;
margin-bottom: 10px;
}

.transaction-card input {
width: 100%;
padding: 5px;
margin-bottom: 10px;
border-radius: 4px;
border: 1px solid #2c7a7b;
}

.transaction-card button {
width: 100%;
padding: 7px;
background-color: #2c7a7b;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}

.transaction-card button:hover {
background-color: #285e61;
}
22 changes: 22 additions & 0 deletions src/app/components/transaction/transaction.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<div class="transaction-card">
<form [formGroup]="transForm" (ngSubmit)="onSubmit()">
<h3>Transaction</h3>
<div class="select">
<label for="abc">Transaction Type</label>
<select formControlName="type" id="abc">
<option value="expense">Expense</option>
<option value="income">Income</option>
</select>
</div>
<div>
<label>Amount:</label>
<input
type="number"
[value]="transForm.value.amount"
formControlName="amount"
/>
</div>

<button>Add Income</button>
</form>
</div>
Loading