Add HttpClient

This commit is contained in:
Mat Rawi
2025-08-20 15:16:29 +08:00
parent bc51279aa9
commit 152d7d2378
12 changed files with 200 additions and 26 deletions

2
.vscode/launch.json vendored
View File

@@ -4,7 +4,7 @@
"configurations": [
{
"name": "ng serve",
"type": "chrome",
"type": "msedge",
"request": "launch",
"preLaunchTask": "npm: start",
"url": "http://localhost:4200/"

28
package-lock.json generated
View File

@@ -3947,9 +3947,9 @@
}
},
"node_modules/browserslist": {
"version": "4.25.2",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.2.tgz",
"integrity": "sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA==",
"version": "4.25.3",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.3.tgz",
"integrity": "sha512-cDGv1kkDI4/0e5yON9yM5G/0A5u8sf5TnmdX5C9qHzI9PPu++sQ9zjm1k9NiOrf3riY4OkK0zSGqfvJyJsgCBQ==",
"dev": true,
"funding": [
{
@@ -3967,8 +3967,8 @@
],
"license": "MIT",
"dependencies": {
"caniuse-lite": "^1.0.30001733",
"electron-to-chromium": "^1.5.199",
"caniuse-lite": "^1.0.30001735",
"electron-to-chromium": "^1.5.204",
"node-releases": "^2.0.19",
"update-browserslist-db": "^1.1.3"
},
@@ -4708,9 +4708,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
"version": "1.5.203",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.203.tgz",
"integrity": "sha512-uz4i0vLhfm6dLZWbz/iH88KNDV+ivj5+2SA+utpgjKaj9Q0iDLuwk6Idhe9BTxciHudyx6IvTvijhkPvFGUQ0g==",
"version": "1.5.204",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.204.tgz",
"integrity": "sha512-s9VbBXWxfDrl67PlO4avwh0/GU2vcwx8Fph3wlR8LJl7ySGYId59EFE17VWVcuC3sLWNPENm6Z/uGqKbkPCcXA==",
"dev": true,
"license": "ISC"
},
@@ -5013,9 +5013,9 @@
}
},
"node_modules/eventsource-parser": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.3.tgz",
"integrity": "sha512-nVpZkTMM9rF6AQ9gPJpFsNAMt48wIzB5TQgiTLdHiuO8XEDhUgZEhqKlZWXbIzo9VmJ/HvysHqEaVeD5v9TPvA==",
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.5.tgz",
"integrity": "sha512-bSRG85ZrMdmWtm7qkF9He9TNRzc/Bm99gEJMaQoHJ9E6Kv9QBbsldh2oMj7iXmYNEAVvNgvv5vPorG6W+XtBhQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -5930,9 +5930,9 @@
}
},
"node_modules/istanbul-reports": {
"version": "3.1.7",
"resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz",
"integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==",
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz",
"integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {

View File

@@ -1,13 +1,14 @@
import { ApplicationConfig, provideBrowserGlobalErrorListeners, provideZonelessChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { routes } from './app.routes'; // Ensure this matches the export in app.routes.ts
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
providers: [
provideBrowserGlobalErrorListeners(),
provideZonelessChangeDetection(),
provideRouter(routes), provideClientHydration(withEventReplay())
provideRouter(routes),
provideClientHydration(withEventReplay())
]
};

View File

@@ -1,3 +1,7 @@
import { Routes } from '@angular/router';
import { HomepageComponent } from './features/homepage/homepage.component';
export const routes: Routes = [];
export const routes: Routes = [
{ path: '', component: HomepageComponent },
// Add other routes here
];

View File

@@ -1,12 +1,13 @@
import { Component, signal } from '@angular/core';
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet],
templateUrl: './app.html',
styleUrl: './app.css'
template: `<router-outlet></router-outlet>`,
styleUrls: ['./app.css']
})
export class App {
protected readonly title = signal('insurance-fe');
protected readonly title = 'insurance-fe';
}

View File

@@ -0,0 +1,11 @@
.card-container {
display: flex;
flex-wrap: wrap;
}
.card {
margin: 10px;
padding: 20px;
border: 1px solid #ccc;
cursor: pointer;
}

View File

@@ -0,0 +1,6 @@
<div>Homepage Component Loaded</div>
<div *ngFor="let card of cards" class="card">
<h2>{{ card.title }}</h2>
<p>{{ card.description }}</p>
<button (click)="navigate(card.link)">View Details</button>
</div>

View File

@@ -0,0 +1,52 @@
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Router } from '@angular/router';
import { InsuranceService } from '../../shared/services/insurance.service';
import { Observable } from 'rxjs';
interface Card {
title: string;
description: string;
link: string;
}
@Component({
selector: 'app-homepage',
standalone: true,
imports: [CommonModule], // Remove HttpClientModule here
templateUrl: './homepage.component.html',
styleUrls: ['./homepage.component.css']
})
export class HomepageComponent implements OnInit {
cards: Card[] = [];
constructor(private router: Router, private insuranceService: InsuranceService) {
console.log('HomepageComponent constructor');
}
ngOnInit() {
console.log('HomepageComponent ngOnInit');
this.fetchInsurances();
}
fetchInsurances() {
console.log('Fetching insurances');
this.insuranceService.getInsurances().subscribe(
insurances => {
console.log('Insurances fetched:', insurances);
this.cards = insurances.map(insurance => ({
title: insurance.name,
description: `Category: ${insurance.category}, Price: $${insurance.price}`,
link: `/insurance/${insurance.id}`
}));
},
error => {
console.error('Error fetching insurances:', error);
}
);
}
navigate(link: string) {
this.router.navigate([link]);
}
}

View File

@@ -0,0 +1,62 @@
import { TestBed } from '@angular/core/testing';
import { InsuranceService } from './insurance.service';
import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting, HttpTestingController } from '@angular/common/http/testing';
describe('InsuranceService', () => {
let service: InsuranceService;
let httpTestingController: HttpTestingController;
beforeEach(async () => {
await TestBed.configureTestingModule({
providers: [
InsuranceService,
provideHttpClient(),
provideHttpClientTesting(),
]
}).compileComponents();
service = TestBed.inject(InsuranceService);
httpTestingController = TestBed.inject(HttpTestingController);
});
afterEach(() => {
// Ensure that there are no outstanding requests
httpTestingController.verify();
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should return expected insurances (HttpClient called once)', () => {
const expectedInsurances = [
{ id: 1, name: 'Comprehensive Health Plan', category: 'Health', price: 1200.0 },
{ id: 2, name: 'Standard Auto Coverage', category: 'Auto', price: 800.0 },
];
service.getInsurances().subscribe(insurances => {
expect(insurances).toEqual(expectedInsurances);
});
const req = httpTestingController.expectOne('https://your-api-url.com/insurances');
expect(req.request.method).toEqual('GET');
req.flush(expectedInsurances);
});
// it('should return expected insurance by ID (HttpClient called once)', () => {
// const expectedInsurance = { id: 1, name: 'Comprehensive Health Plan', category: 'Health', price: 1200.0 };
// service.getInsuranceById(1).subscribe(insurance => {
// expect(insurance).toEqual(expectedInsurance);
// });
// const req = httpTestingController.expectOne('https://your-api-url.com/insurances/1');
// expect(req.request.method).toEqual('GET');
// req.flush(expectedInsurance);
// });
// Add more tests for other methods and scenarios as needed
});

View File

@@ -0,0 +1,31 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
interface Insurance {
id: number;
name: string;
category: string;
price: number;
}
@Injectable({
providedIn: 'root' // Use 'root' to make the service available globally
})
export class InsuranceService {
private apiUrl = 'http://localhost:1204/api/insurance';
constructor(private http: HttpClient) {}
getInsurances(): Observable<Insurance[]> {
return this.http.post<Insurance[]>(`${this.apiUrl}/all`, {}).pipe(
catchError(this.handleError)
);
}
private handleError(error: HttpErrorResponse) {
console.error('An error occurred:', error.message);
return throwError('Something went wrong; please try again later.');
}
}

View File

@@ -1,6 +1,12 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { App } from './app/app';
import { provideRouter } from '@angular/router';
import { provideHttpClient } from '@angular/common/http'; // Import provideHttpClient
import { HomepageComponent } from './app/features/homepage/homepage.component';
import { routes } from './app/app.routes'; // Adjust the path to your routes file
bootstrapApplication(App, appConfig)
.catch((err) => console.error(err));
bootstrapApplication(HomepageComponent, {
providers: [
provideRouter(routes),
provideHttpClient(), // Use provideHttpClient to provide HttpClient
],
}).catch(err => console.error(err));