Skip to content

Commit f2ec68a

Browse files
committed
lab 4
1 parent f8343e1 commit f2ec68a

21 files changed

Lines changed: 374 additions & 78 deletions

src/Interfaces/IProduct.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
export interface IProduct
2-
{
3-
id : number;
1+
import { IRating } from "./IRating";
2+
3+
export interface IProduct {
4+
id: number;
45
title: string;
56
price: number;
67
description: string;
78
category: string;
89
image: string;
10+
rating: IRating;
911
}

src/Interfaces/IRating.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface IRating {
2+
rate: number;
3+
count: number;
4+
}

src/app/app.config.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ import { provideRouter } from '@angular/router';
33

44
import { routes } from './app.routes';
55
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
6+
import { provideHttpClient } from '@angular/common/http';
67

78
export const appConfig: ApplicationConfig = {
8-
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideClientHydration(withEventReplay())]
9+
providers: [provideZoneChangeDetection({ eventCoalescing: true }),
10+
provideRouter(routes),
11+
provideClientHydration(withEventReplay()),
12+
provideHttpClient()]
913
};

src/app/app.routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const routes: Routes = [
77
{path:'products', loadComponent: ()=> import('./pages/all-products/all-products.component').then(m => m.AllProductsComponent), title: 'Products'},
88
{path: 'products/:id', loadComponent: () => import('./pages/details/details.component').then(m => m.DetailsComponent), title: 'Product Details'},
99
{path: 'categories', loadComponent: () => import('./pages/category/category.component').then(m => m.CategoryComponent), title: 'Categories'},
10+
{path: 'jewelery', loadComponent: () => import('./pages/jewelery/jewelery.component').then(m => m.JeweleryComponent), title: 'Jewelery'},
1011
{path: '**', redirectTo: 'not_found', pathMatch: 'full'},
1112
{path: 'not_found', loadComponent: () => import('./pages/not-found/not-found.component').then(m => m.NotFoundComponent), title: 'Not Found'}
1213
];
Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,33 @@
1-
import { Component, inject} from '@angular/core';
1+
import { Component, OnInit, OnDestroy } from '@angular/core';
22
import { ProductService } from '../../services/product.service';
33
import { IProduct } from '../../../Interfaces/IProduct';
44
import { RouterLink } from '@angular/router';
5+
import { Subscription } from 'rxjs';
56

67
@Component({
78
selector: 'app-feature-product',
89
imports: [RouterLink],
910
templateUrl: './feature-product.component.html',
1011
styleUrl: './feature-product.component.scss'
1112
})
12-
export class FeatureProductComponent {
13-
readonly _products = inject(ProductService);
14-
products : IProduct[] = this._products.products; // Display only the first two products
13+
export class FeatureProductComponent implements OnInit, OnDestroy {
14+
products: IProduct[] = [];
15+
private productSubscription?: Subscription;
16+
17+
constructor(private productService: ProductService) {}
18+
19+
ngOnInit(): void {
20+
this.productSubscription = this.productService.getAllProducts().subscribe({
21+
next: (products: IProduct[]) => {
22+
this.products = products;
23+
},
24+
error: (err) => {
25+
console.error('Error fetching products:', err);
26+
}
27+
});
28+
}
29+
30+
ngOnDestroy(): void {
31+
this.productSubscription?.unsubscribe();
32+
}
1533
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<div class="container mt-4">
2+
<h2 class="mb-4 text-center">Jewelry Collection</h2>
3+
<div class="row row-cols-1 row-cols-md-3 g-4">
4+
@for (product of jewelryProducts; track product.id) {
5+
<div class="col">
6+
<div class="card h-100 shadow-sm">
7+
<a [routerLink]="['/products', product.id]" class="text-decoration-none">
8+
<img [src]="product.image" [alt]="product.title" class="card-img-top" style="height: 250px; object-fit: cover;">
9+
</a>
10+
<div class="card-body d-flex flex-column">
11+
<h5 class="card-title">{{ product.title }}</h5>
12+
<p class="text-muted">{{ product.category }}</p>
13+
<p class="card-text">{{ product.description }}</p>
14+
<div class="mt-auto fw-bold text-success">${{ product.price }}</div>
15+
<a class="btn btn-outline-primary mt-3 w-100" [routerLink]="['/products', product.id]">Details</a>
16+
</div>
17+
</div>
18+
</div>
19+
} @empty {
20+
<div class="alert alert-warning w-100 text-center">No jewelry items found.</div>
21+
}
22+
</div>
23+
</div>
24+

src/app/components/jewelry/jewelry.component.scss

Whitespace-only changes.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { JewelryComponent } from './jewelry.component';
4+
5+
describe('JewelryComponent', () => {
6+
let component: JewelryComponent;
7+
let fixture: ComponentFixture<JewelryComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
imports: [JewelryComponent]
12+
})
13+
.compileComponents();
14+
15+
fixture = TestBed.createComponent(JewelryComponent);
16+
component = fixture.componentInstance;
17+
fixture.detectChanges();
18+
});
19+
20+
it('should create', () => {
21+
expect(component).toBeTruthy();
22+
});
23+
});
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { Component, OnInit, OnDestroy } from '@angular/core';
2+
import { CommonModule } from '@angular/common';
3+
import { IProduct } from '../../../Interfaces/IProduct';
4+
import { ProductService } from '../../services/product.service';
5+
import { RouterLink } from '@angular/router';
6+
import { Subscription } from 'rxjs';
7+
import { map } from 'rxjs/operators';
8+
9+
10+
11+
@Component({
12+
standalone: true,
13+
selector: 'app-jewelry',
14+
imports: [CommonModule, RouterLink],
15+
templateUrl: './jewelry.component.html',
16+
styleUrls: ['./jewelry.component.scss']
17+
})
18+
export class JewelryComponent implements OnInit, OnDestroy {
19+
jewelryProducts: IProduct[] = [];
20+
private productSubscription?: Subscription;
21+
22+
constructor(private productService: ProductService) {}
23+
24+
ngOnInit(): void {
25+
this.productSubscription = this.productService.getAllProducts()
26+
.pipe(
27+
map(data => data.filter(p => p.category === 'jewelery'))
28+
)
29+
.subscribe({
30+
next: filtered => this.jewelryProducts = filtered,
31+
error: err => console.error('Failed to fetch jewelry products', err)
32+
});
33+
}
34+
35+
36+
37+
ngOnDestroy(): void {
38+
this.productSubscription?.unsubscribe();
39+
}
40+
}
41+

src/app/components/nav-bar/nav-bar.component.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
<li class="nav-item">
2424
<a class="nav-link" routerLinkActive="active" routerLink="categories">Categories</a>
2525
</li>
26+
<li class="nav-item">
27+
<a class="nav-link" routerLinkActive="active" routerLink="jewelery">Jewelery</a>
28+
</li>
2629
</ul>
2730
</div>
2831
</div>

0 commit comments

Comments
 (0)