From 003829589d3c4cff1c5c64cd774d5c038f9308a3 Mon Sep 17 00:00:00 2001 From: waelhanfi04 <79511539+waelhanfi04@users.noreply.github.com> Date: Tue, 19 Sep 2023 14:31:03 +0100 Subject: [PATCH] Tokeninfo (#533) 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 | 302 ++++++++++-------- .../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, 447 insertions(+), 232 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 b2fb3c86c..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 0fb0c99c5..aa7030a89 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, ElementRef, OnInit, ViewChild } from '@angular/core'; import { ChartOptions, ChartType } from 'chart.js'; import { Router } from '@angular/router'; -import { debounceTime, distinctUntilChanged, 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,17 +16,27 @@ import { Title, Meta } from '@angular/platform-browser'; styleUrls: ['./crypto-market-cap.component.scss'] }) export class CryptoMarketCapComponent implements OnInit { + cryptoLists: any; + cryptoData$ = this.store.select(selectCryptoData); filteredCryptoListId: any[] = []; sparklineIn7dCryptoList: any[] = []; - currentPage: number = 1; - calculetPage: number = 1; - totalPages = 90; + virtualScrollerData: any[] = []; + filteredCryptoList: any[] | undefined; + currentPage = 1; + itemsPerPage = 100; + totalItems = 0; + paginatedCryptoList: any[] = []; pagesPerPage = 8; - pageWindows: number[]; data: any; globalMarketCap: any; + searchQuery: string = ''; public chart: any; + + maxButtonsPerPage = 15; + currentPageRangeStart = 1; + currentPageRangeEnd: number = this.maxButtonsPerPage; + lineChartOptions: ChartOptions = { aspectRatio: 2.5, responsive: true, @@ -57,30 +71,22 @@ export class CryptoMarketCapComponent implements OnInit { }; lineChartType: ChartType = 'line'; lineChartLegend = false; - - searchQuery: string = ''; - private searchQueryChanged: Subject = new Subject(); - @ViewChild('searchInput') - searchInput!: ElementRef; - private ngUnsubscribe = new Subject(); - onSearchQueryData: any; + prices: any[] | undefined; + cryptoIds: any[] = []; constructor( private router: Router, private fetchservice: CryptofetchServiceService, private titleService: Title, - private metaService: Meta + private metaService: Meta, + private store: Store ) { - this.pageWindows = this.getPageWindow(this.currentPage); - - this.searchQueryChanged - .pipe(debounceTime(300), distinctUntilChanged()) - .subscribe((query) => { - this.onSearchQueryChange(query); - }); + this.cryptoIds = []; + // this.pageWindows = this.getPageWindow(this.currentPage); } ngOnInit(): void { + this.paginatedCryptoList = []; this.titleService.setTitle('SaTT-Market Cap'); this.metaService.updateTag({ name: 'description', @@ -99,20 +105,40 @@ export class CryptoMarketCapComponent implements OnInit { name: 'twitter:card', content: 'assets/Images/global-market-cap-cov.png' }); - this.getTable(this.currentPage); - this.fetchservice - .getGlobalCryptoMarketInfo() + this.cryptoData$ = this.store.select(selectCryptoData); + + this.cryptoData$ .pipe(takeUntil(this.ngUnsubscribe)) - .subscribe( - (res: any) => { - this.globalMarketCap = res; - }, - (error) => { - console.error(error); + .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. @@ -128,23 +154,88 @@ export class CryptoMarketCapComponent implements OnInit { 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() { - console.log("this.cryptoLists;,this.cryptoLists;",this.cryptoLists) + // 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 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 this.onSearchQueryData; + return of(this.cryptoIds); } + + + // 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'); @@ -153,6 +244,11 @@ export class CryptoMarketCapComponent implements OnInit { }); } + + getCryptoLabels(): string[] { + return this.paginatedCryptoList.map((crypto) => crypto[0]); + } + getColor(variation: number) { return variation > 0 ? '#00CC9E' : '#F52079'; } @@ -182,99 +278,55 @@ export class CryptoMarketCapComponent implements OnInit { return '0'; } - onInputChange(event: Event): void { - const inputElement = event.target as HTMLInputElement; - if (inputElement) { - this.searchQueryChanged.next(inputElement.value); - } + totalPages(): number { + return Math.ceil(this.totalItems / this.itemsPerPage); } - 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 - } - ); - } else { - // If the query is empty, display the full list. - this.onSearchQueryData = this.cryptoLists; + goToPage(pageNumber: number): void { + if (pageNumber >= 1 && pageNumber <= this.totalPages()) { + this.currentPage = pageNumber; + this.filterCryptos(); } } - 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); - } + 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(); } - 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 - ); + + prevPage() { + if (this.currentPageRangeStart > 1) { + this.currentPageRangeEnd = this.currentPageRangeStart - 1; + this.currentPageRangeStart = Math.max( + this.currentPageRangeStart - this.maxButtonsPerPage, + 1 + ); + } + this.currentPage--; + this.filterCryptos(); } + - 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); + pageNumbers(): number[] { + const pageRange = []; + for ( + let i = this.currentPageRangeStart; + i <= this.currentPageRangeEnd; + i++ + ) { + pageRange.push(i); } + return pageRange; } + + 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] })