From 5ad73009e72fbc72be0564700b60e1282622d030 Mon Sep 17 00:00:00 2001 From: waelhanfi04 <79511539+waelhanfi04@users.noreply.github.com> Date: Mon, 18 Sep 2023 10:16:00 +0100 Subject: [PATCH] Feature: Implement Search Functionality for Crypto Market (#522) fix search token in token info --- .../wallet/cryptofetch-service.service.ts | 10 +- .../crypto-market-cap.component.html | 4 +- .../crypto-market-cap.component.ts | 409 ++++++++++-------- 3 files changed, 245 insertions(+), 178 deletions(-) diff --git a/src/app/core/services/wallet/cryptofetch-service.service.ts b/src/app/core/services/wallet/cryptofetch-service.service.ts index 12c40f9c4..b826f9a37 100755 --- a/src/app/core/services/wallet/cryptofetch-service.service.ts +++ b/src/app/core/services/wallet/cryptofetch-service.service.ts @@ -51,7 +51,15 @@ export class CryptofetchServiceService { const params = new HttpParams().set('cryptochunk', pageNumber); // Making the HTTP GET request - return this.http.get( sattUrl + '/wallet/getallCrypto', { params }); + return this.http.get(sattUrl + '/wallet/getallCrypto', { params }); + } + + searchCryptoMarket(value: string): Observable { + const requestBody = { value }; + return this.http.post( + sattUrl + '/wallet/searchCryptoMarket', + requestBody + ); } transactionHistory() { diff --git a/src/app/wallet/components/crypto-market-cap/crypto-market-cap.component.html b/src/app/wallet/components/crypto-market-cap/crypto-market-cap.component.html index 6d69759e1..b2fb3c86c 100644 --- a/src/app/wallet/components/crypto-market-cap/crypto-market-cap.component.html +++ b/src/app/wallet/components/crypto-market-cap/crypto-market-cap.component.html @@ -60,8 +60,8 @@

class="search-query d-flex mt-3" type="text" name="search" - placeholder="{{ 'searchToken' | translate }} -" + placeholder="{{ 'searchToken' | translate }}" + (input)="onInputChange($event)" /> x diff --git a/src/app/wallet/components/crypto-market-cap/crypto-market-cap.component.ts b/src/app/wallet/components/crypto-market-cap/crypto-market-cap.component.ts index eae637173..0f56a73dd 100644 --- a/src/app/wallet/components/crypto-market-cap/crypto-market-cap.component.ts +++ b/src/app/wallet/components/crypto-market-cap/crypto-market-cap.component.ts @@ -1,7 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; import { ChartOptions, ChartType } from 'chart.js'; import { Router } from '@angular/router'; -import { switchMap, takeUntil } from 'rxjs/operators'; +import { debounceTime, distinctUntilChanged, switchMap, takeUntil } from 'rxjs/operators'; import { Subject, forkJoin } from 'rxjs'; import { CryptofetchServiceService } from '@app/core/services/wallet/cryptofetch-service.service'; import { Title, Meta } from '@angular/platform-browser'; @@ -12,211 +12,270 @@ import { Title, Meta } from '@angular/platform-browser'; styleUrls: ['./crypto-market-cap.component.scss'] }) export class CryptoMarketCapComponent implements OnInit { -cryptoLists : any; -filteredCryptoListId: any[]=[]; -sparklineIn7dCryptoList: any[]=[] -currentPage: number= 1; -calculetPage: number= 1; -totalPages = 90; -pagesPerPage = 8; -pageWindows: number[]; -data: any -globalMarketCap:any; -searchQuery: string = ''; -public chart: any; -lineChartOptions: ChartOptions = { - aspectRatio:2.5, - responsive:true, - elements:{ - point:{ - radius:0, - } - }, - scales: { - scaleLabel:{ - fontColor:"red" - }, - - xAxes : [{ - display:false, - gridLines:{ - color:"transparent" - } - }], - yAxes : [{ - display:false, - - gridLines:{ - color:"transparent" - } - }], - } -}; -lineChartType: ChartType = 'line'; -lineChartLegend = false; -private ngUnsubscribe = new Subject(); - constructor( - private router: Router , + cryptoLists: any; + filteredCryptoListId: any[] = []; + sparklineIn7dCryptoList: any[] = []; + currentPage: number = 1; + calculetPage: number = 1; + totalPages = 90; + pagesPerPage = 8; + pageWindows: number[]; + data: any; + globalMarketCap: any; + public chart: any; + lineChartOptions: ChartOptions = { + aspectRatio: 2.5, + responsive: true, + elements: { + point: { + radius: 0 + } + }, + scales: { + scaleLabel: { + fontColor: 'red' + }, + + xAxes: [ + { + display: false, + gridLines: { + color: 'transparent' + } + } + ], + yAxes: [ + { + display: false, + + gridLines: { + color: 'transparent' + } + } + ] + } + }; + lineChartType: ChartType = 'line'; + lineChartLegend = false; + + searchQuery: string = ''; + private searchQueryChanged: Subject = new Subject(); + @ViewChild('searchInput') + searchInput!: ElementRef; + + private ngUnsubscribe = new Subject(); + onSearchQueryData: any; + constructor( + private router: Router, private fetchservice: CryptofetchServiceService, - private titleService: Title, private metaService: Meta - - ){ - - this.pageWindows = this.getPageWindow(this.currentPage); - } - + private titleService: Title, + private metaService: Meta + ) { + this.pageWindows = this.getPageWindow(this.currentPage); + + this.searchQueryChanged + .pipe(debounceTime(300), distinctUntilChanged()) + .subscribe((query) => { + this.onSearchQueryChange(query); + }); + } ngOnInit(): void { - this.titleService.setTitle('SaTT-Market Cap'); - this.metaService.updateTag({ name: 'description', content: 'Discover the best options in the cryptocurrency market and maximize your investments.' }); - this.metaService.addTag({ name: 'keywords', content: 'cryptocurrency, Coin, Market Cap, investment, crypto, earning' }); - this.metaService.addTag({ property: 'og:image', content: 'assets/Images/global-market-cap-cov.png' }); - this.metaService.addTag({ name: 'twitter:card', content: 'assets/Images/global-market-cap-cov.png' }); - this.getTable(this.currentPage) - - this.fetchservice.getGlobalCryptoMarketInfo().pipe(takeUntil(this.ngUnsubscribe)).subscribe((res: any) => { - this.globalMarketCap = res; - }, - (error) => { - console.error(error); - + this.titleService.setTitle('SaTT-Market Cap'); + this.metaService.updateTag({ + name: 'description', + content: + 'Discover the best options in the cryptocurrency market and maximize your investments.' }); - + this.metaService.addTag({ + name: 'keywords', + content: 'cryptocurrency, Coin, Market Cap, investment, crypto, earning' + }); + this.metaService.addTag({ + property: 'og:image', + content: 'assets/Images/global-market-cap-cov.png' + }); + this.metaService.addTag({ + name: 'twitter:card', + content: 'assets/Images/global-market-cap-cov.png' + }); + this.getTable(this.currentPage); + this.fetchservice + .getGlobalCryptoMarketInfo() + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (res: any) => { + this.globalMarketCap = res; + }, + (error) => { + console.error(error); + } + ); } /** - * Split an array into chunks of a specific size. - * @param arr The original array to split. - * @param chunkSize The size of each chunk. - * @returns A new array containing the chunks. - */ + * Split an array into chunks of a specific size. + * @param arr The original array to split. + * @param chunkSize The size of each chunk. + * @returns A new array containing the chunks. + */ getArrayChunks(arr: T[], chunkSize: number): T[][] { - let results: T[][] = []; - - for (let i = 0; i < arr.length; i += chunkSize) { - results.push(arr.slice(i, i + chunkSize)); - } - + let results: T[][] = []; + + for (let i = 0; i < arr.length; i += chunkSize) { + results.push(arr.slice(i, i + chunkSize)); + } + return results; } generatePageArray(totalPages: number): number[] { return Array.from({ length: totalPages }, (_, i) => i + 1); } - get pagesArray(): number[] { - return Array(this.totalPages).fill(0).map((_, i) => i + 1); + return Array(this.totalPages) + .fill(0) + .map((_, i) => i + 1); } filterCryptos() { if (!this.searchQuery) { return this.cryptoLists; } - - - const lowerCaseSearchQuery = this.searchQuery.toLowerCase(); - - return this.cryptoLists?.filter((crypto : any) => - crypto[0].toLowerCase().includes(lowerCaseSearchQuery) || - crypto[1].name.toLowerCase().includes(lowerCaseSearchQuery) - - ); + + return this.onSearchQueryData; } - cryptoDtlails(crypto: string, cryptoName:string){ + cryptoDtlails(crypto: string, cryptoName: string) { const cryptoUpperCase = crypto.toUpperCase(); - this.titleService.setTitle(cryptoName +' price today') - this.router.navigate(['/wallet/coin-detail'], { queryParams: { crypto: cryptoUpperCase } }); - + this.titleService.setTitle(cryptoName + ' price today'); + this.router.navigate(['/wallet/coin-detail'], { + queryParams: { crypto: cryptoUpperCase } + }); } - getColor(variation: number){ - return variation > 0 ? '#00CC9E' :'#F52079'; - } + getColor(variation: number) { + return variation > 0 ? '#00CC9E' : '#F52079'; + } getNumberWithLeadingZeros(i: number): string { return String(i).padStart(2, '0'); } - clear(){ - this.searchQuery=''; - } - tofixUsd(price: any){ - if (price < 0.1) { - return '8'; + clear() { + this.searchQuery = ''; } - if (price >= 0.1 && price <= 1.9) { - return '6'; - } - if (price >= 2 && price <= 9.9999) { - return '5'; - } - if (price >= 10.0 && price <= 9999.9) { - return '2'; - } - if (price >= 10000 && price <= 99999999999) { + tofixUsd(price: any) { + if (price < 0.1) { + return '8'; + } + if (price >= 0.1 && price <= 1.9) { + return '6'; + } + if (price >= 2 && price <= 9.9999) { + return '5'; + } + if (price >= 10.0 && price <= 9999.9) { + return '2'; + } + if (price >= 10000 && price <= 99999999999) { + return '0'; + } + return '0'; } - - return'0' - } - getTable(n: number){ - this.fetchservice.getAllCrypto(n).pipe( - takeUntil(this.ngUnsubscribe), - switchMap((data: any) => { - const cryptos = data?.data ? Object.entries(data.data) : []; - this.cryptoLists = cryptos.slice(0, 100); - this.cryptoLists?.forEach((crypto: any) => { - if (crypto && crypto[1]) { - - - this.filteredCryptoListId.push(crypto[1].id); + + onInputChange(event: Event): void { + const inputElement = event.target as HTMLInputElement; + if (inputElement) { + this.searchQueryChanged.next(inputElement.value); + } + } + + onSearchQueryChange(query: string): void { + if (query.length > 0) { + this.fetchservice.searchCryptoMarket(query).subscribe( + (response) => { + const dataWithoutSymbol = { ...response.data }; + delete dataWithoutSymbol.symbol; + + const result = [[response.data.symbol, dataWithoutSymbol]]; + + this.onSearchQueryData = result; + }, + () => { + this.onSearchQueryData = this.cryptoLists; + // Handle errors here } - }); - - const chunks = this.getArrayChunks(this.filteredCryptoListId, 50); - - - - return forkJoin(chunks.map(chunk => this.fetchservice.getCryptoPriceDetails(chunk))); - }) - ).subscribe( - (data: any) => { - - - const dataArray = Object.values(data) - - dataArray.forEach((response: any) => { - - const details = Object.values(response?.data) || []; - details.forEach((crypto: any) => { - if (crypto) { - this.sparklineIn7dCryptoList.push(crypto.sparkline_in_7d); - } - }); - }); - - }, - (error) => { - - - console.error(error); + ); + } else { + // If the query is empty, display the full list. + this.onSearchQueryData = this.cryptoLists; } - - ); - } - getPageWindow(currentPage: number): number[] { - const startPage = Math.max(1, currentPage - Math.floor(this.pagesPerPage / 2)); - const endPage = Math.min(this.totalPages, startPage + this.pagesPerPage - 1); - return Array.from({ length: endPage - startPage + 1 }, (_, i) => startPage + i); -} + } -onPageChanged(page: number) { - if (page >= 1 && page <= this.totalPages && page !== this.currentPage) { - this.currentPage = page; - this.calculetPage=((page-1)*100)+1 - this.pageWindows = this.getPageWindow(this.currentPage); - this.getTable( this.calculetPage) + getTable(n: number) { + this.fetchservice + .getAllCrypto(n) + .pipe( + takeUntil(this.ngUnsubscribe), + switchMap((data: any) => { + const cryptos = data?.data ? Object.entries(data.data) : []; + this.cryptoLists = cryptos.slice(0, 100); + this.cryptoLists?.forEach((crypto: any) => { + if (crypto && crypto[1]) { + this.filteredCryptoListId.push(crypto[1].id); + } + }); + + const chunks = this.getArrayChunks(this.filteredCryptoListId, 50); + + return forkJoin( + chunks.map((chunk) => + this.fetchservice.getCryptoPriceDetails(chunk) + ) + ); + }) + ) + .subscribe( + (data: any) => { + const dataArray = Object.values(data); + + dataArray.forEach((response: any) => { + const details = Object.values(response?.data) || []; + details.forEach((crypto: any) => { + if (crypto) { + this.sparklineIn7dCryptoList.push(crypto.sparkline_in_7d); + } + }); + }); + }, + (error) => { + console.error(error); + } + ); + } + getPageWindow(currentPage: number): number[] { + const startPage = Math.max( + 1, + currentPage - Math.floor(this.pagesPerPage / 2) + ); + const endPage = Math.min( + this.totalPages, + startPage + this.pagesPerPage - 1 + ); + return Array.from( + { length: endPage - startPage + 1 }, + (_, i) => startPage + i + ); + } + + onPageChanged(page: number) { + if (page >= 1 && page <= this.totalPages && page !== this.currentPage) { + this.currentPage = page; + this.calculetPage = (page - 1) * 100 + 1; + this.pageWindows = this.getPageWindow(this.currentPage); + this.getTable(this.calculetPage); + } + } + ngOnDestroy() { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); } -} - ngOnDestroy() { - this.ngUnsubscribe.next(); - this.ngUnsubscribe.complete(); -} }