From 554abc1c9b1de89af7ec1267d35312a25c055078 Mon Sep 17 00:00:00 2001 From: waelhanfi04 Date: Tue, 19 Sep 2023 13:58:54 +0100 Subject: [PATCH 1/2] add ngrx and fix the chart and search in token info --- src/app/app-routing.module.ts | 7 + src/app/app.module.ts | 2 + src/app/core/services/crypto-data.guard.ts | 45 ++ src/app/models/crypto-data.model.ts | 8 + .../buy-token/buy-token.component.ts | 4 +- .../crypto-market-cap.component.html | 189 ++++--- .../crypto-market-cap.component.ts | 470 +++++++++++------- .../header-send-receive-buy.component.ts | 3 +- .../send-receive-block.component.ts | 3 +- .../wallet/store/actions/crypto.actions.ts | 13 + .../wallet/store/effects/crypto.effects.ts | 33 ++ .../wallet/store/reducers/crypto.reducer.ts | 34 ++ .../store/selectors/crypto.selectors.ts | 18 + src/app/wallet/wallet.module.ts | 18 +- 14 files changed, 561 insertions(+), 286 deletions(-) create mode 100644 src/app/core/services/crypto-data.guard.ts create mode 100644 src/app/models/crypto-data.model.ts create mode 100644 src/app/wallet/store/actions/crypto.actions.ts create mode 100644 src/app/wallet/store/effects/crypto.effects.ts create mode 100644 src/app/wallet/store/reducers/crypto.reducer.ts create mode 100644 src/app/wallet/store/selectors/crypto.selectors.ts diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 7e6c5269d..04f86d8a6 100755 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -6,6 +6,8 @@ import { ServerErrorComponent } from './components/server-error/server-error.com import { MaintenanceComponent } from './maintenance/maintenance.component'; import { PrivacyPolicyComponent } from './privacy-policy/privacy-policy.component'; import { CguComponent } from './cgu/cgu.component'; +import { CryptoDataGuard } from './core/services/crypto-data.guard'; +import { CryptoMarketCapComponent } from './wallet/components/crypto-market-cap/crypto-market-cap.component'; const routes: Routes = [ { @@ -13,6 +15,11 @@ const routes: Routes = [ loadChildren: () => import('./auth/authentication.module').then((m) => m.AuthenticationModule) }, + { + path: 'crypto-market-cap', + component: CryptoMarketCapComponent, + canActivate: [CryptoDataGuard], + }, { path: 'cgu', component: CguComponent, diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 992c760a0..943bf97c4 100755 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -18,6 +18,7 @@ import { TransferHttpCacheModule } from '@nguniversal/common'; import { translateBrowserLoaderFactory } from '@core/loaders/translate-browser.loader'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { HttpInterceptorService } from './http-interceptor.service'; +import { ChartsModule } from 'ng2-charts'; @NgModule({ declarations: [ @@ -30,6 +31,7 @@ import { HttpInterceptorService } from './http-interceptor.service'; imports: [ BrowserModule.withServerTransition({ appId: 'satt-token-atayen' }), BrowserAnimationsModule, + ChartsModule, AppRoutingModule, HttpClientModule, TransferHttpCacheModule, diff --git a/src/app/core/services/crypto-data.guard.ts b/src/app/core/services/crypto-data.guard.ts new file mode 100644 index 000000000..b0400469c --- /dev/null +++ b/src/app/core/services/crypto-data.guard.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@angular/core'; +import { + CanActivate, + ActivatedRouteSnapshot, + RouterStateSnapshot, + Router +} from '@angular/router'; +import { Store } from '@ngrx/store'; +import { Observable, of } from 'rxjs'; +import { catchError, switchMap, take, tap } from 'rxjs/operators'; +import * as CryptoActions from '../../wallet/store/actions/crypto.actions'; +import { selectCryptoData } from '@app/wallet/store/selectors/crypto.selectors'; + +@Injectable({ + providedIn: 'root', +}) +export class CryptoDataGuard implements CanActivate { + constructor(private store: Store, private router: Router) {} + + canActivate( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Observable { + return this.store.select(selectCryptoData).pipe( + take(1), + switchMap((cryptoData) => { + if (cryptoData && cryptoData.length > 0) { + + return of(true); + } else { + + this.store.dispatch(CryptoActions.loadCryptoData()); + + return of(true).pipe( + catchError(() => { + + console.error('Failed to load crypto data.'); + return of(false); + }) + ); + } + }) + ); + } +} \ No newline at end of file diff --git a/src/app/models/crypto-data.model.ts b/src/app/models/crypto-data.model.ts new file mode 100644 index 000000000..959cb8845 --- /dev/null +++ b/src/app/models/crypto-data.model.ts @@ -0,0 +1,8 @@ +export interface CryptoData { + id: string; + name: string; + symbol: string; + price: number; + marketCap: number; + } + \ No newline at end of file diff --git a/src/app/wallet/components/buy-token/buy-token.component.ts b/src/app/wallet/components/buy-token/buy-token.component.ts index a40148ea5..6f9f6fac1 100755 --- a/src/app/wallet/components/buy-token/buy-token.component.ts +++ b/src/app/wallet/components/buy-token/buy-token.component.ts @@ -26,6 +26,7 @@ import { Location } from '@angular/common'; import * as _ from 'lodash'; import { Console } from 'console'; +import { TranslateService } from '@ngx-translate/core'; enum EBlockchainNetwork { ERC20 = 'ERC20', @@ -151,7 +152,8 @@ export class BuyTokenComponent implements OnInit, OnChanges { private tokenStorageService: TokenStorageService, @Inject(PLATFORM_ID) private platformId: string, private _location: Location, - private activatedRoute: ActivatedRoute + private activatedRoute: ActivatedRoute, + private translateService: TranslateService ) { this.convertform = new UntypedFormGroup({ Amount: new UntypedFormControl( 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..d7c97a41f 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 @@ -2,67 +2,49 @@
-
- +
+

{{ 'Cryptolist.title' | translate }}

{{ - globalMarketCap?.data?.total_market_cap - | currency: 'USD':'symbol':'1.0-0' + globalMarketCap?.data?.total_market_cap + | currency: 'USD':'symbol':'1.0-0' }}
-
+ ">
{{ 'Cryptolist.title.mobile' | translate }}
-
+ "> {{ 'Cryptolist.description.mobile' | translate }}
- + + x
@@ -86,23 +68,16 @@

- + {{ getNumberWithLeadingZeros(crypto[1]?.cmc_rank) }} - logo de la crypto-monnaie {{ crypto[1]?.name }} + logo de la crypto-monnaie {{ crypto[1]?.name }} {{ crypto[1]?.name }} {{ crypto[0] }} @@ -110,39 +85,45 @@

{{ - crypto[1].price - | currency: 'USD':'symbol':'1.0-' + tofixUsd(crypto[1]?.price) + crypto[1].price + | currency: 'USD':'symbol':'1.0-' + tofixUsd(crypto[1]?.price) }} - + }"> + {{ crypto[1]?.percent_change_1h | number: '1.0-2' }}% - + + {{ crypto[1]?.percent_change_24h | number: '1.0-2' }}% - + }"> + {{ crypto[1]?.percent_change_7d | number: '1.0-2' }}% {{ crypto[1]?.market_cap | currency: 'USD':'symbol':'1.0-0' }} - + + + + + +

- +
@@ -180,42 +161,29 @@

- + -
{{ getNumberWithLeadingZeros(crypto[1]?.cmc_rank) }} - + {{ crypto[0] }} {{ - crypto[1].price - | currency: 'USD':'symbol':'1.0-' + tofixUsd(crypto[1]?.price) + crypto[1].price + | currency: 'USD':'symbol':'1.0-' + tofixUsd(crypto[1]?.price) }} -
+
+ }"> + {{ crypto[1]?.percent_change_24h | number: '1.0-2' }}%
@@ -225,28 +193,43 @@

- -
- -
+
+ +
+
+ + + +
-
+ \ No newline at end of file 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..7a8e79a1c 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,10 +1,14 @@ import { Component, OnInit } from '@angular/core'; import { ChartOptions, ChartType } from 'chart.js'; import { Router } from '@angular/router'; -import { switchMap, takeUntil } from 'rxjs/operators'; -import { Subject, forkJoin } from 'rxjs'; +import { switchMap, take, takeUntil } from 'rxjs/operators'; +import { Observable, Subject, forkJoin, of } from 'rxjs'; import { CryptofetchServiceService } from '@app/core/services/wallet/cryptofetch-service.service'; import { Title, Meta } from '@angular/platform-browser'; +import { Store } from '@ngrx/store'; +import * as CryptoActions from '../../store/actions/crypto.actions'; +import { selectCryptoData } from '@app/wallet/store/selectors/crypto.selectors'; +import { CryptoData } from '@app/models/crypto-data.model'; @Component({ selector: 'app-crypto-market-cap', @@ -12,211 +16,319 @@ 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; + cryptoData$ = this.store.select(selectCryptoData); + filteredCryptoListId: any[] = []; + sparklineIn7dCryptoList: any[] = []; + virtualScrollerData: any[] = []; + filteredCryptoList: any[] | undefined; + currentPage = 1; + itemsPerPage = 100; + totalItems = 0; + paginatedCryptoList: any[] = []; + pagesPerPage = 8; + data: any; + globalMarketCap: any; + searchQuery: string = ''; + public chart: any; + + maxButtonsPerPage = 15; + currentPageRangeStart = 1; + currentPageRangeEnd: number = this.maxButtonsPerPage; + + 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(); + prices: any[] | undefined; + cryptoIds: 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, + private store: Store + ) { + this.cryptoIds = []; + // this.pageWindows = this.getPageWindow(this.currentPage); + } 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.paginatedCryptoList = []; + 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.cryptoData$ = this.store.select(selectCryptoData); + + this.cryptoData$ + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe((cryptoData) => { + if (!cryptoData || cryptoData.length === 0) { + console.log('Dispatching loadCryptoData action...'); + this.store.dispatch(CryptoActions.loadCryptoData()); + } else { + const dataArray = Object.values(cryptoData); + this.cryptoLists = dataArray.slice(0, 100)[2]; + this.filterCryptos(); + + } + }); + + // this.cryptoData$ + // .pipe( + // takeUntil(this.ngUnsubscribe), + // switchMap(() => this.filterCryptos()) + // ) + // .subscribe((cryptoIds: number[]) => { + // // cryptoIds is now available + // this.getTable(cryptoIds); + // }); + + + + } + + /** - * 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); - } - filterCryptos() { + // 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); + // } + filterCryptos(): Observable { + this.totalItems = this.cryptoLists?.length; + // Check if the search query is empty if (!this.searchQuery) { - return this.cryptoLists; - } - + if (Array.isArray(this.cryptoLists)) { + this.cryptoLists.sort((a, b) => Number(a[1].cmc_rank) - Number(b[1].cmc_rank)); - const lowerCaseSearchQuery = this.searchQuery.toLowerCase(); - - return this.cryptoLists?.filter((crypto : any) => - crypto[0].toLowerCase().includes(lowerCaseSearchQuery) || - crypto[1].name.toLowerCase().includes(lowerCaseSearchQuery) - - ); + + const startIndex = (this.currentPage - 1) * this.itemsPerPage; + const endIndex = startIndex + this.itemsPerPage; + this.paginatedCryptoList = this.cryptoLists.slice(startIndex, endIndex); + this.cryptoIds = this.paginatedCryptoList.map((crypto) => crypto[1].id); + + } else if ( + this.cryptoLists !== null && + typeof this.cryptoLists === 'object' + ) { + this.cryptoLists = Object.keys(this.cryptoLists).map((key) => ({ + 0: key, + 1: this.cryptoLists[key] + })); + + const startIndex = (this.currentPage - 1) * this.itemsPerPage; + const endIndex = startIndex + this.itemsPerPage; + this.paginatedCryptoList = this.cryptoLists.slice(startIndex, endIndex); + } else { + this.paginatedCryptoList = []; + } + } else { + const result = this.cryptoLists.filter((crypto: { name: string }[]) => + crypto[1].name.toLowerCase().includes(this.searchQuery.toLowerCase()) + ); + + this.totalItems = result.length; + + this.currentPage = 1; + + const startIndex = (this.currentPage - 1) * this.itemsPerPage; + const endIndex = startIndex + this.itemsPerPage; + this.paginatedCryptoList = result.slice(startIndex, endIndex); + + this.cryptoIds = this.paginatedCryptoList.map((crypto) => crypto[1].id); + + } + + return of(this.cryptoIds); } - cryptoDtlails(crypto: string, cryptoName:string){ - const cryptoUpperCase = crypto.toUpperCase(); - this.titleService.setTitle(cryptoName +' price today') - this.router.navigate(['/wallet/coin-detail'], { queryParams: { crypto: cryptoUpperCase } }); + + // getTable(cryptoIds: number[] ) { + // const chunks = this.getArrayChunks(cryptoIds, 50); + // 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); + // } + // ); + // } + + + cryptoDtlails(crypto: string, cryptoName: string) { + const cryptoUpperCase = crypto.toUpperCase(); + this.titleService.setTitle(cryptoName + ' price today'); + this.router.navigate(['/wallet/coin-detail'], { + queryParams: { crypto: cryptoUpperCase } + }); } - getColor(variation: number){ - return variation > 0 ? '#00CC9E' :'#F52079'; - } + + getCryptoLabels(): string[] { + return this.paginatedCryptoList.map((crypto) => crypto[0]); + } + + 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'; + 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'; } - if (price >= 2 && price <= 9.9999) { - return '5'; + + totalPages(): number { + return Math.ceil(this.totalItems / this.itemsPerPage); } - if (price >= 10.0 && price <= 9999.9) { - return '2'; + + goToPage(pageNumber: number): void { + if (pageNumber >= 1 && pageNumber <= this.totalPages()) { + this.currentPage = pageNumber; + this.filterCryptos(); + } } - if (price >= 10000 && price <= 99999999999) { - return '0'; + + nextPage() { + if (this.currentPageRangeEnd < this.totalPages()) { + this.currentPageRangeStart = this.currentPageRangeEnd + 1; + this.currentPageRangeEnd = Math.min( + this.currentPageRangeEnd + this.maxButtonsPerPage, + this.totalPages() + ); + } + this.currentPage++; + this.filterCryptos(); } - 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); - } - }); - - 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) => { + prevPage() { + if (this.currentPageRangeStart > 1) { + this.currentPageRangeEnd = this.currentPageRangeStart - 1; + this.currentPageRangeStart = Math.max( + this.currentPageRangeStart - this.maxButtonsPerPage, + 1 + ); + } + this.currentPage--; + this.filterCryptos(); + } - - console.error(error); + + pageNumbers(): number[] { + const pageRange = []; + for ( + let i = this.currentPageRangeStart; + i <= this.currentPageRangeEnd; + i++ + ) { + pageRange.push(i); } - - ); - } - 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); -} + return pageRange; + } + -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(); -} -} diff --git a/src/app/wallet/components/header-send-receive-buy/header-send-receive-buy.component.ts b/src/app/wallet/components/header-send-receive-buy/header-send-receive-buy.component.ts index 93d7e9418..5a0362551 100755 --- a/src/app/wallet/components/header-send-receive-buy/header-send-receive-buy.component.ts +++ b/src/app/wallet/components/header-send-receive-buy/header-send-receive-buy.component.ts @@ -1,5 +1,6 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'app-header-send-receive-buy', @@ -9,7 +10,7 @@ import { Router } from '@angular/router'; export class HeaderSendReceiveBuyComponent implements OnInit { @Input() title: string = ''; @Output() clickedBack: EventEmitter = new EventEmitter(); - constructor(private router: Router) {} + constructor(private router: Router,private translateService: TranslateService) {} ngOnInit(): void {} back() { diff --git a/src/app/wallet/components/send-receive-block/send-receive-block.component.ts b/src/app/wallet/components/send-receive-block/send-receive-block.component.ts index bec87296f..ace77f155 100755 --- a/src/app/wallet/components/send-receive-block/send-receive-block.component.ts +++ b/src/app/wallet/components/send-receive-block/send-receive-block.component.ts @@ -1,4 +1,5 @@ import { Component, EventEmitter, Output } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'app-send-receive-block', @@ -13,7 +14,7 @@ export class SendReceiveBlockComponent { // @Output() // onReceiveClick = new EventEmitter(); - constructor() { } + constructor(private translateService: TranslateService) { } // onSend() { // this.onSendClick.emit(); diff --git a/src/app/wallet/store/actions/crypto.actions.ts b/src/app/wallet/store/actions/crypto.actions.ts new file mode 100644 index 000000000..9a1305858 --- /dev/null +++ b/src/app/wallet/store/actions/crypto.actions.ts @@ -0,0 +1,13 @@ + +import { CryptoData } from '@app/models/crypto-data.model'; +import { createAction, props } from '@ngrx/store'; + +export const loadCryptoData = createAction('[Crypto] Load Crypto Data'); +export const loadCryptoDataSuccess = createAction( + '[Crypto] Load Crypto Data Success', + props<{ data: CryptoData[] }>() +); +export const loadCryptoDataFailure = createAction( + '[Crypto] Load Crypto Data Failure', + props<{ error: any }>() +); diff --git a/src/app/wallet/store/effects/crypto.effects.ts b/src/app/wallet/store/effects/crypto.effects.ts new file mode 100644 index 000000000..1fd139cfc --- /dev/null +++ b/src/app/wallet/store/effects/crypto.effects.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@angular/core'; +import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { catchError, map, switchMap } from 'rxjs/operators'; +import { of } from 'rxjs'; +import * as CryptoActions from '../../store/actions/crypto.actions'; +import { CryptofetchServiceService } from '@app/core/services/wallet/cryptofetch-service.service'; +import { CryptoData } from '@app/models/crypto-data.model'; + +@Injectable() +export class CryptoEffects { + constructor( + private actions$: Actions, + private fetchservice: CryptofetchServiceService + ) {} + + loadCryptoData$ = createEffect(() => + this.actions$.pipe( + ofType(CryptoActions.loadCryptoData), + switchMap(() => { + console.log('loadCryptoData effect triggered'); + return this.fetchservice.getAllCrypto(1).pipe( + map((data) => { + return CryptoActions.loadCryptoDataSuccess({ data: data as CryptoData[] }); + }), + catchError((error) => { + console.error('Error:', error); + return of(CryptoActions.loadCryptoDataFailure({ error })); + }) + ); + }) + ) + ); +} diff --git a/src/app/wallet/store/reducers/crypto.reducer.ts b/src/app/wallet/store/reducers/crypto.reducer.ts new file mode 100644 index 000000000..6df65f270 --- /dev/null +++ b/src/app/wallet/store/reducers/crypto.reducer.ts @@ -0,0 +1,34 @@ +import { createReducer, on } from '@ngrx/store'; +import * as CryptoActions from '../actions/crypto.actions'; +import { CryptoData } from '@app/models/crypto-data.model'; + +export interface CryptoState { + data: CryptoData[]; + loading: boolean; + error: any; +} + +const initialState: CryptoState = { + data: [], + loading: false, + error: null, +}; + +export const cryptoReducer = createReducer( + initialState, + on(CryptoActions.loadCryptoData, (state) => ({ + ...state, + loading: true, + error: null, + })), + on(CryptoActions.loadCryptoDataSuccess, (state, { data }) => ({ + ...state, + data, + loading: false, + })), + on(CryptoActions.loadCryptoDataFailure, (state, { error }) => ({ + ...state, + error, + loading: false, + })) +); diff --git a/src/app/wallet/store/selectors/crypto.selectors.ts b/src/app/wallet/store/selectors/crypto.selectors.ts new file mode 100644 index 000000000..ed3a0e906 --- /dev/null +++ b/src/app/wallet/store/selectors/crypto.selectors.ts @@ -0,0 +1,18 @@ + +import { createFeatureSelector, createSelector } from '@ngrx/store'; +import { CryptoState } from '../reducers/crypto.reducer'; + +const selectCryptoState = createFeatureSelector('crypto'); + +export const selectCryptoData = createSelector( + selectCryptoState, + (state) => state.data +); +export const selectCryptoLoading = createSelector( + selectCryptoState, + (state) => state.loading +); +export const selectCryptoError = createSelector( + selectCryptoState, + (state) => state.error +); diff --git a/src/app/wallet/wallet.module.ts b/src/app/wallet/wallet.module.ts index 2ef6d3056..8e208e2f5 100755 --- a/src/app/wallet/wallet.module.ts +++ b/src/app/wallet/wallet.module.ts @@ -21,6 +21,15 @@ import { ZXingScannerModule } from '@zxing/ngx-scanner'; import { FilterBynamePipe } from '@shared/pipes/filter-byname.pipe'; import { MigrationComponent } from './components/migration/migration.component'; import { CryptoMarketCapComponent } from './components/crypto-market-cap/crypto-market-cap.component'; +import { cryptoReducer } from './store/reducers/crypto.reducer'; +import { CryptoEffects } from './store/effects/crypto.effects'; +import { StoreModule } from '@ngrx/store'; +import { EffectsModule } from '@ngrx/effects'; +import { CommonModule } from '@angular/common'; +import { TranslateModule } from '@ngx-translate/core'; +import { ChartsModule } from 'ng2-charts'; +import { ScrollingModule } from '@angular/cdk/scrolling'; + @NgModule({ declarations: [ @@ -41,11 +50,18 @@ import { CryptoMarketCapComponent } from './components/crypto-market-cap/crypto- CryptoMarketCapComponent ], imports: [ + CommonModule, SharedModule, + ScrollingModule, + ChartsModule, WalletRoutingModule, NgxIntlTelInputModule, ChartModule, - ZXingScannerModule + TranslateModule.forChild(), + ZXingScannerModule, + StoreModule.forFeature('crypto', cryptoReducer), + EffectsModule.forFeature([CryptoEffects]), + ], providers: [DecimalPipe, DatePipe, FilterBynamePipe] }) From ed920faa7f9797cdf22feb7b4157572ed014250d Mon Sep 17 00:00:00 2001 From: waelhanfi04 Date: Tue, 19 Sep 2023 15:12:51 +0100 Subject: [PATCH 2/2] fix pagination nulber --- .../crypto-market-cap.component.ts | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) 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 aa7030a89..dd1006f68 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,4 +1,4 @@ -import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; +import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core'; import { ChartOptions, ChartType } from 'chart.js'; import { Router } from '@angular/router'; import { switchMap, take, takeUntil } from 'rxjs/operators'; @@ -34,8 +34,9 @@ export class CryptoMarketCapComponent implements OnInit { public chart: any; maxButtonsPerPage = 15; + + currentPageRangeStart = 1; - currentPageRangeEnd: number = this.maxButtonsPerPage; lineChartOptions: ChartOptions = { aspectRatio: 2.5, @@ -74,6 +75,7 @@ export class CryptoMarketCapComponent implements OnInit { private ngUnsubscribe = new Subject(); prices: any[] | undefined; cryptoIds: any[] = []; + currentPageRangeEnd!: number; constructor( private router: Router, private fetchservice: CryptofetchServiceService, @@ -86,6 +88,8 @@ export class CryptoMarketCapComponent implements OnInit { } ngOnInit(): void { + this.setMaxButtonsPerPage(); + this.paginatedCryptoList = []; this.titleService.setTitle('SaTT-Market Cap'); this.metaService.updateTag({ @@ -139,6 +143,28 @@ export class CryptoMarketCapComponent implements OnInit { } + + @HostListener('window:resize', ['$event']) + onResize(event: Event): void { + this.setMaxButtonsPerPage(); + } + + private setMaxButtonsPerPage(): void { + const screenWidth = window.innerWidth; + if (screenWidth <= 530) { + this.maxButtonsPerPage = 5; + } else if (screenWidth <= 768) { + this.maxButtonsPerPage = 10; + } else if (screenWidth <= 992) { + this.maxButtonsPerPage = 15; + } else { + this.maxButtonsPerPage = 20; + } + + this.currentPageRangeEnd = this.maxButtonsPerPage; + + } + /** * Split an array into chunks of a specific size. * @param arr The original array to split.