Completed Cache
This commit is contained in:
parent
f6735a38fe
commit
d875c033d9
BIN
API/wwwroot/images/products/ABS-Gladiator-Gaming-PC-1749.jpg
Normal file
BIN
API/wwwroot/images/products/ABS-Gladiator-Gaming-PC-1749.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 100 KiB |
Binary file not shown.
After Width: | Height: | Size: 77 KiB |
Binary file not shown.
After Width: | Height: | Size: 96 KiB |
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
Binary file not shown.
After Width: | Height: | Size: 107 KiB |
Binary file not shown.
After Width: | Height: | Size: 80 KiB |
@ -1,26 +1,26 @@
|
||||
[
|
||||
{
|
||||
"Id": 1,
|
||||
"Name": "Angular"
|
||||
"Name": "ABS"
|
||||
},
|
||||
{
|
||||
"Id": 2,
|
||||
"Name": "NetCore"
|
||||
"Name": "Cyberpower"
|
||||
},
|
||||
{
|
||||
"Id": 3,
|
||||
"Name": "VS Code"
|
||||
"Name": "Skytech"
|
||||
},
|
||||
{
|
||||
"Id": 4,
|
||||
"Name": "React"
|
||||
"Name": "Velztorm"
|
||||
},
|
||||
{
|
||||
"Id": 5,
|
||||
"Name": "Typescript"
|
||||
"Name": "Bose"
|
||||
},
|
||||
{
|
||||
"Id": 6,
|
||||
"Name": "Redis"
|
||||
"Name": "Beats"
|
||||
}
|
||||
]
|
@ -1,51 +1,51 @@
|
||||
[
|
||||
{
|
||||
"Name": "Angular Speedster Board 2000",
|
||||
"Name": "ABS Gladiator Gaming PC",
|
||||
"Description": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.",
|
||||
"Price": 200,
|
||||
"PictureUrl": "images/products/sb-ang1.png",
|
||||
"Price": 1749,
|
||||
"PictureUrl": "images/products/ABS-Gladiator-Gaming-PC-1749.jpg",
|
||||
"ProductTypeId": 1,
|
||||
"ProductBrandId": 1
|
||||
},
|
||||
{
|
||||
"Name": "Green Angular Board 3000",
|
||||
"Name": "CyberpowerPC Gaming Desktop Gamer Master",
|
||||
"Description": "Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.",
|
||||
"Price": 150,
|
||||
"PictureUrl": "images/products/sb-ang2.png",
|
||||
"Price": 1699,
|
||||
"PictureUrl": "images/products/CyberpowerPC-Gaming-Desktop-Gamer-Master-1699.jpg",
|
||||
"ProductTypeId": 1,
|
||||
"ProductBrandId": 1
|
||||
"ProductBrandId": 2
|
||||
},
|
||||
{
|
||||
"Name": "Core Board Speed Rush 3",
|
||||
"Name": "Skytech Archangel 3.0 Gaming Computer PC Desktop",
|
||||
"Description": "Suspendisse dui purus, scelerisque at, vulputate vitae, pretium mattis, nunc. Mauris eget neque at sem venenatis eleifend. Ut nonummy.",
|
||||
"Price": 180,
|
||||
"PictureUrl": "images/products/sb-core1.png",
|
||||
"Price": 1199,
|
||||
"PictureUrl": "images/products/Skytech-Archangel-3.0-Gaming-Computer-PC-Desktop-1199.jpg",
|
||||
"ProductTypeId": 1,
|
||||
"ProductBrandId": 2
|
||||
"ProductBrandId": 3
|
||||
},
|
||||
{
|
||||
"Name": "Net Core Super Board",
|
||||
"Name": "Velztorm Nix Custom Built Gaming Desktop PC",
|
||||
"Description": "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin pharetra nonummy pede. Mauris et orci.",
|
||||
"Price": 300,
|
||||
"PictureUrl": "images/products/sb-core2.png",
|
||||
"ProductTypeId": 1,
|
||||
"ProductBrandId": 2
|
||||
},
|
||||
{
|
||||
"Name": "React Board Super Whizzy Fast",
|
||||
"Description": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.",
|
||||
"Price": 250,
|
||||
"PictureUrl": "images/products/sb-react1.png",
|
||||
"Price": 1449,
|
||||
"PictureUrl": "images/products/Velztorm-Nix-Custom-Built-Gaming-Desktop-PC-1449.jpg",
|
||||
"ProductTypeId": 1,
|
||||
"ProductBrandId": 4
|
||||
},
|
||||
{
|
||||
"Name": "Typescript Entry Board",
|
||||
"Description": "Aenean nec lorem. In porttitor. Donec laoreet nonummy augue.",
|
||||
"Price": 120,
|
||||
"PictureUrl": "images/products/sb-ts1.png",
|
||||
"Name": "ABS Legend Gaming PC - Intel i9 12900K",
|
||||
"Description": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.",
|
||||
"Price": 4149,
|
||||
"PictureUrl": "images/products/ABS-Legend-Gaming-PC-Intel-i9-12900K.jpg",
|
||||
"ProductTypeId": 1,
|
||||
"ProductBrandId": 5
|
||||
"ProductBrandId": 1
|
||||
},
|
||||
{
|
||||
"Name": "Skytech Chronos Gaming PC Desktop",
|
||||
"Description": "Aenean nec lorem. In porttitor. Donec laoreet nonummy augue.",
|
||||
"Price": 1599,
|
||||
"PictureUrl": "images/products/Skytech-Chronos-Gaming-PC-Desktop.jpg",
|
||||
"ProductTypeId": 1,
|
||||
"ProductBrandId": 3
|
||||
},
|
||||
{
|
||||
"Name": "Core Blue Hat",
|
||||
|
@ -1,18 +1,18 @@
|
||||
[
|
||||
{
|
||||
"Id": 1,
|
||||
"Name": "Boards"
|
||||
"Name": "Computers"
|
||||
},
|
||||
{
|
||||
"Id": 2,
|
||||
"Name": "Hats"
|
||||
"Name": "Headphones"
|
||||
},
|
||||
{
|
||||
"Id": 3,
|
||||
"Name": "Boots"
|
||||
"Name": "Gadgets"
|
||||
},
|
||||
{
|
||||
"Id": 4,
|
||||
"Name": "Gloves"
|
||||
"Name": "Accessories"
|
||||
}
|
||||
]
|
@ -1,3 +1,3 @@
|
||||
# SkiNet
|
||||
# SkyNet
|
||||
|
||||
Built upon ASP.NET, Angular, Bootstrap, and Stripe for Credit Card Processing!
|
@ -8,7 +8,7 @@ import { AccountService } from './account/account.service';
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
title = 'SkiNet';
|
||||
title = 'SkyNet';
|
||||
|
||||
constructor(private basketService: BasketService, private accountService: AccountService) {}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
[boundaryLinks]="true"
|
||||
[totalItems]="totalCount"
|
||||
(pageChanged)="onPagerChange($event)"
|
||||
[ngModel]="pageNumber"
|
||||
[itemsPerPage]="pageSize"
|
||||
previousText="‹"
|
||||
nextText="›"
|
||||
|
@ -8,6 +8,7 @@ import { Component, EventEmitter, Input, Output, OnInit } from '@angular/core';
|
||||
export class PagerComponent implements OnInit {
|
||||
@Input() totalCount: number;
|
||||
@Input() pageSize: number;
|
||||
@Input() pageNumber: number;
|
||||
@Output() pageChanged = new EventEmitter<number>();
|
||||
|
||||
constructor() { }
|
||||
|
@ -1,8 +1,15 @@
|
||||
import { IProduct } from "./product"
|
||||
|
||||
export interface IPagination {
|
||||
pageIndex: number
|
||||
pageSize: number
|
||||
count: number
|
||||
data: IProduct[]
|
||||
}
|
||||
pageIndex: number;
|
||||
pageSize: number;
|
||||
count: number;
|
||||
data: IProduct[];
|
||||
}
|
||||
|
||||
export class Pagination implements IPagination {
|
||||
pageIndex: number;
|
||||
pageSize: number;
|
||||
count: number;
|
||||
data: IProduct[] = [];
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import { RouterModule } from '@angular/router';
|
||||
CarouselModule.forRoot(),
|
||||
BsDropdownModule.forRoot(),
|
||||
ReactiveFormsModule,
|
||||
FormsModule,
|
||||
CdkStepperModule,
|
||||
RouterModule
|
||||
],
|
||||
@ -40,6 +41,7 @@ import { RouterModule } from '@angular/router';
|
||||
OrderTotalsComponent,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
FormsModule,
|
||||
BsDropdownModule,
|
||||
TextInputsComponent,
|
||||
CdkStepperModule,
|
||||
|
@ -5,6 +5,7 @@
|
||||
<h5 class="text-warning ml-3">Sort</h5>
|
||||
<select class="form-select mb-3" style="width: 100%;" (change)="onSortSelected($event.target.value)">
|
||||
<option *ngFor="let sort of sortOptions"
|
||||
[selected]="shopParams.sort === sort.value"
|
||||
[value]="sort.value"
|
||||
>
|
||||
{{sort.name}}
|
||||
@ -57,6 +58,7 @@
|
||||
<app-pager
|
||||
[pageSize]="shopParams.pageSize"
|
||||
[totalCount]="totalCount"
|
||||
[pageNumber]="shopParams.pageNumber"
|
||||
(pageChanged)="onPageChange($event)"
|
||||
></app-pager>
|
||||
</div>
|
||||
|
@ -15,7 +15,7 @@ export class ShopComponent implements OnInit {
|
||||
products: IProduct[];
|
||||
brands: IBrand[];
|
||||
productType: IType[];
|
||||
shopParams = new ShopParams();
|
||||
shopParams: ShopParams;
|
||||
totalCount: number;
|
||||
sortOptions = [
|
||||
{name: 'Name', value: 'name'},
|
||||
@ -23,21 +23,21 @@ export class ShopComponent implements OnInit {
|
||||
{name: 'Price: High to Low', value: 'priceDesc'}
|
||||
];
|
||||
|
||||
constructor(private shopService: ShopService) { }
|
||||
constructor(private shopService: ShopService) {
|
||||
this.shopParams = this.shopService.getShopParams();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.getProducts();
|
||||
this.getProducts(true);
|
||||
this.getBrands();
|
||||
this.getTypes();
|
||||
}
|
||||
|
||||
getProducts(){
|
||||
this.shopService.getProducts(this.shopParams).subscribe(
|
||||
getProducts(useCache = false){
|
||||
this.shopService.getProducts(useCache).subscribe(
|
||||
{
|
||||
next: (response) => {
|
||||
this.products = response.data;
|
||||
this.shopParams.pageNumber = response.pageIndex;
|
||||
this.shopParams.pageSize = response.pageSize;
|
||||
this.totalCount = response.count;
|
||||
},
|
||||
error: (e: any) => { console.log(e); },
|
||||
@ -67,38 +67,49 @@ export class ShopComponent implements OnInit {
|
||||
}
|
||||
|
||||
onBrandSelected(brandId: number){
|
||||
this.shopParams.brandId = brandId;
|
||||
this.shopParams.pageNumber = 1;
|
||||
const params = this.shopService.getShopParams();
|
||||
params.brandId = brandId;
|
||||
params.pageNumber = 1;
|
||||
this.shopService.setShopParams(params);
|
||||
this.getProducts();
|
||||
}
|
||||
|
||||
onTypeSelected(typeId: number){
|
||||
this.shopParams.typeId = typeId;
|
||||
this.shopParams.pageNumber = 1;
|
||||
const params = this.shopService.getShopParams();
|
||||
params.typeId = typeId;
|
||||
params.pageNumber = 1;
|
||||
this.shopService.setShopParams(params);
|
||||
this.getProducts();
|
||||
}
|
||||
|
||||
onSortSelected(sort: string){
|
||||
this.shopParams.sort = sort;
|
||||
const params = this.shopService.getShopParams();
|
||||
params.sort = sort;
|
||||
this.shopService.setShopParams(params);
|
||||
this.getProducts();
|
||||
}
|
||||
|
||||
onPageChange(e: any){
|
||||
if (this.shopParams.pageNumber !== e){
|
||||
this.shopParams.pageNumber = e;
|
||||
this.getProducts();
|
||||
const params = this.shopService.getShopParams();
|
||||
if (params.pageNumber !== e){
|
||||
params.pageNumber = e;
|
||||
this.shopService.setShopParams(params);
|
||||
this.getProducts(true);
|
||||
}
|
||||
}
|
||||
|
||||
onSearch(){
|
||||
this.shopParams.search = this.searchTerm.nativeElement.value;
|
||||
this.shopParams.pageNumber = 1;
|
||||
const params = this.shopService.getShopParams()
|
||||
params.search = this.searchTerm.nativeElement.value;
|
||||
params.pageNumber = 1;
|
||||
this.shopService.setShopParams(params);
|
||||
this.getProducts();
|
||||
}
|
||||
|
||||
OnReset(){
|
||||
this.searchTerm.nativeElement.value = '';
|
||||
this.shopParams = new ShopParams();
|
||||
this.shopService.setShopParams(this.shopParams);
|
||||
this.getProducts();
|
||||
}
|
||||
|
||||
|
@ -1,56 +1,108 @@
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { IBrand } from '../shared/models/brand';
|
||||
import { IPagination } from '../shared/models/pagination';
|
||||
import { IPagination, Pagination } from '../shared/models/pagination';
|
||||
import { IType } from '../shared/models/producttype';
|
||||
import { map } from 'rxjs/operators'
|
||||
import { ShopParams } from '../shared/models/shopparams';
|
||||
import { IProduct } from '../shared/models/product';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ShopService {
|
||||
baseURL = 'https://localhost:5001/api/'
|
||||
baseURL = 'https://localhost:5001/api/';
|
||||
products: IProduct[] = [];
|
||||
brands: IBrand[] = [];
|
||||
types: IType[] = [];
|
||||
pagination = new Pagination();
|
||||
shopParams = new ShopParams();
|
||||
productCache = new Map();
|
||||
|
||||
constructor(private http: HttpClient) { }
|
||||
|
||||
getProducts(shopParams: ShopParams){
|
||||
getProducts(useCache: boolean){
|
||||
if (useCache === false){
|
||||
this.productCache = new Map();
|
||||
}
|
||||
|
||||
if(this.productCache.size > 0 && useCache === true){
|
||||
if(this.productCache.has(Object.values(this.shopParams).join('-'))) {
|
||||
this.pagination.data = this.productCache.get(Object.values(this.shopParams).join('-'));
|
||||
return of(this.pagination);
|
||||
}
|
||||
}
|
||||
|
||||
let params = new HttpParams();
|
||||
|
||||
if (shopParams.brandId !== 0){
|
||||
params = params.append('brandId', shopParams.brandId.toString());
|
||||
if (this.shopParams.brandId !== 0){
|
||||
params = params.append('brandId', this.shopParams.brandId.toString());
|
||||
}
|
||||
|
||||
if(shopParams.typeId !== 0){
|
||||
params = params.append('typeId', shopParams.typeId.toString());
|
||||
if(this.shopParams.typeId !== 0){
|
||||
params = params.append('typeId', this.shopParams.typeId.toString());
|
||||
}
|
||||
|
||||
if (shopParams.search){
|
||||
params = params.append('search', shopParams.search);
|
||||
if (this.shopParams.search){
|
||||
params = params.append('search', this.shopParams.search);
|
||||
}
|
||||
|
||||
params = params.append('sort', shopParams.sort);
|
||||
params = params.append('pageIndex', shopParams.pageNumber.toString());
|
||||
params = params.append('pageIndex', shopParams.pageSize.toString());
|
||||
params = params.append('sort', this.shopParams.sort);
|
||||
params = params.append('pageIndex', this.shopParams.pageNumber.toString());
|
||||
params = params.append('pageIndex', this.shopParams.pageSize.toString());
|
||||
|
||||
return this.http.get<IPagination>(this.baseURL + 'products', {observe: 'response', params})
|
||||
.pipe(
|
||||
map(response => {
|
||||
return response.body;
|
||||
this.productCache.set(Object.values(this.shopParams).join('-'), response.body.data);
|
||||
this.pagination = response.body;
|
||||
return this.pagination;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
setShopParams(params: ShopParams){
|
||||
this.shopParams = params;
|
||||
}
|
||||
|
||||
getShopParams(){
|
||||
return this.shopParams;
|
||||
}
|
||||
|
||||
getProduct(id: number){
|
||||
let product: IProduct;
|
||||
this.productCache.forEach((products: IProduct[]) => {
|
||||
product = products.find(p => p.id === id);
|
||||
})
|
||||
|
||||
if(product){
|
||||
return of(product);
|
||||
}
|
||||
return this.http.get<IProduct>(this.baseURL + 'products/' + id);
|
||||
}
|
||||
|
||||
getBrands(){
|
||||
return this.http.get<IBrand[]>(this.baseURL + 'products/brands');
|
||||
if(this.brands.length > 0){
|
||||
return of(this.brands);
|
||||
}
|
||||
return this.http.get<IBrand[]>(this.baseURL + 'products/brands').pipe(
|
||||
map(response => {
|
||||
this.brands = response;
|
||||
return response;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
getTypes(){
|
||||
return this.http.get<IType[]>(this.baseURL + 'products/types');
|
||||
if(this.types.length > 0){
|
||||
return of(this.types);
|
||||
}
|
||||
return this.http.get<IType[]>(this.baseURL + 'products/types').pipe(
|
||||
map(response => {
|
||||
this.types = response;
|
||||
return response;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>SkiNet</title>
|
||||
<title>SkyNet</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
|
Loading…
Reference in New Issue
Block a user