From 0498c089ebee1cc7013a8c13b3b0e56d3124ae74 Mon Sep 17 00:00:00 2001 From: MishaZhem Date: Tue, 30 Jul 2024 14:40:07 +0300 Subject: [PATCH 01/22] chore: add swap component --- .../components/swap/swap.component.html | 92 +++++++++++++++ .../components/swap/swap.component.less | 32 +++++ .../crypto/components/swap/swap.component.ts | 111 ++++++++++++++++++ .../crypto/components/swap/swap.service.ts | 19 +++ .../dashboards/crypto/crypto.component.html | 11 +- .../dashboards/crypto/crypto.component.less | 42 +++++++ .../src/dashboards/crypto/crypto.component.ts | 5 +- .../src/services/crypto.service.ts | 48 ++++++++ 8 files changed, 358 insertions(+), 2 deletions(-) create mode 100644 apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html create mode 100644 apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.less create mode 100644 apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.ts create mode 100644 apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.service.ts create mode 100644 apps/taiga-lumbermill/src/dashboards/crypto/crypto.component.less create mode 100644 apps/taiga-lumbermill/src/services/crypto.service.ts diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html new file mode 100644 index 000000000..bbdf552ac --- /dev/null +++ b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html @@ -0,0 +1,92 @@ +@let info = info$ | async; +@if (info) { + @let data = info.data; +
+
+

+ Swap +

+
+ @for (type of swapService; track $index) { +
+
+
{{ type.title }}
+
Balance: 1000 {{ swapService[$index].chosen.toUpperCase() }}
+
+ + } + + + +
+
+ +
+
+ ≈{{ getPrice(data, swapService[$index].chosen, swapForm.controls[$index].value) }}$ +
+
+
+
+ } + +
+} diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.less b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.less new file mode 100644 index 000000000..b9daac2bd --- /dev/null +++ b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.less @@ -0,0 +1,32 @@ +@import '@taiga-ui/core/styles/taiga-ui-local.less'; + +.choose-crypto { + width: min-content; + height: 2rem; +} + +.amount-crypto { + display: flex; + flex-direction: column; +} + +.input-number { + border: 0; + outline: 0; + background: transparent; +} + +.equal-number { + margin-left: auto; + text-align: right; +} + +input[type='number'] { + -moz-appearance: textfield; +} + +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.ts b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.ts new file mode 100644 index 000000000..5fb5cfb3e --- /dev/null +++ b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.ts @@ -0,0 +1,111 @@ +import {CommonModule} from '@angular/common'; +import {ChangeDetectionStrategy, Component, inject} from '@angular/core'; +import {FormArray, FormControl, ReactiveFormsModule} from '@angular/forms'; +import {TuiActiveZone, TuiObscured} from '@taiga-ui/cdk'; +import { + TuiAppearance, + TuiButton, + TuiDataList, + TuiDropdown, + TuiExpand, + TuiIcon, + TuiTextfield, + TuiTitle, +} from '@taiga-ui/core'; +import {TuiAvatar, TuiChevron, TuiFade} from '@taiga-ui/kit'; +import {TuiCardLarge, TuiCell, TuiHeader} from '@taiga-ui/layout'; +import { + TuiInputModule, + TuiInputNumberModule, + TuiTextfieldControllerModule, +} from '@taiga-ui/legacy'; + +import type {PricesData} from '../../../../services/crypto.service'; +import {CryptoService} from '../../../../services/crypto.service'; +import {SwapService} from './swap.service'; + +@Component({ + standalone: true, + selector: 'lmb-swap', + imports: [ + CommonModule, + ReactiveFormsModule, + TuiActiveZone, + TuiAppearance, + TuiAvatar, + TuiButton, + TuiCardLarge, + TuiCell, + TuiChevron, + TuiDataList, + TuiDropdown, + TuiExpand, + TuiFade, + TuiHeader, + TuiIcon, + TuiInputModule, + TuiInputNumberModule, + TuiObscured, + TuiTextfield, + TuiTextfieldControllerModule, + TuiTitle, + ], + templateUrl: './swap.component.html', + styleUrl: './swap.component.less', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SwapComponent { + protected cryptoService = inject(CryptoService); + protected info$ = this.cryptoService.info$; + protected swapService = inject(SwapService).swapData; + protected swapForm = new FormArray([new FormControl(0.22), new FormControl(0.22)]); + + protected openInfo(index: number): void { + this.swapService[index].status = !this.swapService[index].status; + } + + protected newToken(index: number, title: string): void { + this.swapService[index].chosen = title; + } + + protected getPrice(data: PricesData[], title: string, value: number | null): string { + if (value === null) { + return '0'; + } + + for (const token of data) { + if (token && token.symbol.toLowerCase() === title.toLowerCase()) { + return (Number(token.priceUsd) * value).toFixed(2); + } + } + + return value.toFixed(2); + } + + protected newSwap(data: PricesData[], current: number): void { + const opposite = Number(!current); + const curPrice = Number( + this.getPrice( + data, + this.swapService[current].chosen, + this.swapForm.controls[current].value, + ), + ); + let priceOpposite = 1; + + for (const token of data) { + if ( + token && + token.symbol.toLowerCase() === + this.swapService[opposite].chosen.toLowerCase() + ) { + priceOpposite = Number(token.priceUsd); + break; + } + } + + const result = curPrice / priceOpposite; + + this.swapForm.controls[opposite].setValue(result); + } +} diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.service.ts b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.service.ts new file mode 100644 index 000000000..608a9458c --- /dev/null +++ b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.service.ts @@ -0,0 +1,19 @@ +import {Injectable} from '@angular/core'; + +interface SwapData { + readonly title: string; + status: boolean; + chosen: string; +} + +export const INITIAL_DATA: SwapData[] = [ + {title: 'From', status: false, chosen: 'eth'}, + {title: 'To', status: false, chosen: 'btc'}, +]; + +@Injectable({ + providedIn: 'root', +}) +export class SwapService { + public readonly swapData = INITIAL_DATA; +} diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/crypto.component.html b/apps/taiga-lumbermill/src/dashboards/crypto/crypto.component.html index 94d8806d1..2d0eccfd5 100644 --- a/apps/taiga-lumbermill/src/dashboards/crypto/crypto.component.html +++ b/apps/taiga-lumbermill/src/dashboards/crypto/crypto.component.html @@ -1 +1,10 @@ -

crypto

+
+
+
+
+
+ +
+
+
+
diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/crypto.component.less b/apps/taiga-lumbermill/src/dashboards/crypto/crypto.component.less new file mode 100644 index 000000000..c0b759d1d --- /dev/null +++ b/apps/taiga-lumbermill/src/dashboards/crypto/crypto.component.less @@ -0,0 +1,42 @@ +@import '@taiga-ui/core/styles/taiga-ui-local.less'; + +.tiles { + gap: 1rem; +} + +.grow { + width: 100%; +} + +.row { + position: relative; + display: grid; + flex: 0 0 auto; + grid-template-columns: 4fr 6fr 4fr; + gap: 1rem; +} + +@media (max-width: 56.25rem) { + .row { + display: flex; + flex: 1; + flex-wrap: wrap; + } + + .grow { + height: max-content; + } +} + +@media (max-width: 35.625rem) { + .grow { + width: 100%; + } +} + +.column { + display: flex; + gap: 0.625rem; + padding-top: 1.25rem; + flex-direction: column; +} diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/crypto.component.ts b/apps/taiga-lumbermill/src/dashboards/crypto/crypto.component.ts index 1e2edcc5f..c461e44e7 100644 --- a/apps/taiga-lumbermill/src/dashboards/crypto/crypto.component.ts +++ b/apps/taiga-lumbermill/src/dashboards/crypto/crypto.component.ts @@ -1,11 +1,14 @@ import {CommonModule} from '@angular/common'; import {ChangeDetectionStrategy, Component} from '@angular/core'; +import {SwapComponent} from './components/swap/swap.component'; + @Component({ standalone: true, selector: 'lmb-crypto', - imports: [CommonModule], + imports: [CommonModule, SwapComponent], templateUrl: './crypto.component.html', + styleUrl: './crypto.component.less', changeDetection: ChangeDetectionStrategy.OnPush, }) export class CryptoComponent {} diff --git a/apps/taiga-lumbermill/src/services/crypto.service.ts b/apps/taiga-lumbermill/src/services/crypto.service.ts new file mode 100644 index 000000000..33e78d1e2 --- /dev/null +++ b/apps/taiga-lumbermill/src/services/crypto.service.ts @@ -0,0 +1,48 @@ +import {HttpClient} from '@angular/common/http'; +import {inject, Injectable} from '@angular/core'; +import type {Observable} from 'rxjs'; + +export interface PricesData { + readonly id: string; + readonly name: string; + readonly symbol: string; + readonly rank: string; + readonly src: string; + readonly priceUsd: string; + readonly changePercent24Hr: string; +} + +export interface ResponseData { + readonly data: PricesData[]; +} + +export interface HistoryData { + readonly priceUsd: string; + readonly time: number; + readonly date: string; +} + +export interface ResponseHistoryData { + readonly data: HistoryData[]; +} + +@Injectable({ + providedIn: 'root', +}) +export class CryptoService { + private readonly http = inject(HttpClient); + private readonly API = 'https://api.coincap.io/v2/assets'; + public info$: Observable = this.getTokens(); + + public getTokens(): Observable { + return this.http.get(this.API); + } + + public getHistory(id: string, interval: string): Observable { + return this.http.get(`${this.API}/${id}/history`, { + params: { + interval, + }, + }); + } +} From 32c72368c93f3502932509bb47d816da42b7a9ee Mon Sep 17 00:00:00 2001 From: MishaZhem Date: Tue, 30 Jul 2024 14:57:58 +0300 Subject: [PATCH 02/22] chore: remove extra code --- .../components/swap/swap.component.html | 20 +++++++++---------- .../components/swap/swap.component.less | 13 ------------ .../crypto/components/swap/swap.component.ts | 7 +++++-- 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html index bbdf552ac..78652be45 100644 --- a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html +++ b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html @@ -60,16 +60,16 @@ -
- +
+ + +
Date: Thu, 1 Aug 2024 14:57:31 +0300 Subject: [PATCH 03/22] chore: add tuiAmount --- .../crypto/components/swap/swap.component.html | 6 +++++- .../crypto/components/swap/swap.component.ts | 10 ++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html index 78652be45..4675793a7 100644 --- a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html +++ b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html @@ -75,7 +75,11 @@ tuiSubtitle class="equal-number" > - ≈{{ getPrice(data, swapService[$index].chosen, swapForm.controls[$index].value) }}$ + ≈{{ + getPrice(data, swapService[$index].chosen, swapForm.controls[$index].value) + | tuiAmount: 'USD' + | async + }}

diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.ts b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.ts index 0d5a33216..b830524d7 100644 --- a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.ts +++ b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.ts @@ -1,6 +1,7 @@ import {CommonModule} from '@angular/common'; import {ChangeDetectionStrategy, Component, inject} from '@angular/core'; import {FormArray, FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {TuiAmountPipe} from '@taiga-ui/addon-commerce'; import {TuiActiveZone, TuiObscured} from '@taiga-ui/cdk'; import { TuiAppearance, @@ -32,6 +33,7 @@ import {SwapService} from './swap.service'; FormsModule, ReactiveFormsModule, TuiActiveZone, + TuiAmountPipe, TuiAppearance, TuiAvatar, TuiButton, @@ -71,18 +73,18 @@ export class SwapComponent { this.swapService[index].chosen = title; } - protected getPrice(data: PricesData[], title: string, value: number | null): string { + protected getPrice(data: PricesData[], title: string, value: number | null): number { if (value === null) { - return '0'; + return 0; } for (const token of data) { if (token && token.symbol.toLowerCase() === title.toLowerCase()) { - return (Number(token.priceUsd) * value).toFixed(2); + return Number((Number(token.priceUsd) * value).toFixed(2)); } } - return value.toFixed(2); + return Number(value.toFixed(2)); } protected newSwap(data: PricesData[], current: number): void { From 1c3f2c7c3bcc5cc9f8e94c2a4d29e625cc204122 Mon Sep 17 00:00:00 2001 From: MishaZhem Date: Thu, 1 Aug 2024 15:34:05 +0300 Subject: [PATCH 04/22] chore: smaller icons --- .../src/dashboards/crypto/components/swap/swap.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html index 4675793a7..085e412e9 100644 --- a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html +++ b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html @@ -30,7 +30,7 @@ (click)="openInfo($index)" >
{{ type.title }}
-
Balance: 1000 {{ swapService[$index].chosen.toUpperCase() }}
+
Balance: 1000 {{ chosen[$index].toUpperCase() }}

diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.ts b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.ts index b830524d7..e4646f649 100644 --- a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.ts +++ b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.ts @@ -62,15 +62,18 @@ export class SwapComponent { protected cryptoService = inject(CryptoService); protected info$ = this.cryptoService.info$; protected swapService = inject(SwapService).swapData; - protected swapForm = new FormArray([new FormControl(0.22), new FormControl(0.22)]); + protected swapForm = new FormArray([new FormControl(0), new FormControl(0)]); + protected chosen = ['eth', 'btc']; + protected openedDialog = [false, false]; protected val = 0; protected openInfo(index: number): void { - this.swapService[index].status = !this.swapService[index].status; + this.openedDialog[index] = !this.openedDialog[index]; } protected newToken(index: number, title: string): void { - this.swapService[index].chosen = title; + this.chosen[index] = title; + this.openedDialog[index] = false; } protected getPrice(data: PricesData[], title: string, value: number | null): number { @@ -92,7 +95,7 @@ export class SwapComponent { const curPrice = Number( this.getPrice( data, - this.swapService[current].chosen, + this.chosen[current], this.swapForm.controls[current].value, ), ); @@ -101,8 +104,7 @@ export class SwapComponent { for (const token of data) { if ( token && - token.symbol.toLowerCase() === - this.swapService[opposite].chosen.toLowerCase() + token.symbol.toLowerCase() === this.chosen[opposite].toLowerCase() ) { priceOpposite = Number(token.priceUsd); break; diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.service.ts b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.service.ts index 608a9458c..cded8ac52 100644 --- a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.service.ts +++ b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.service.ts @@ -2,14 +2,9 @@ import {Injectable} from '@angular/core'; interface SwapData { readonly title: string; - status: boolean; - chosen: string; } -export const INITIAL_DATA: SwapData[] = [ - {title: 'From', status: false, chosen: 'eth'}, - {title: 'To', status: false, chosen: 'btc'}, -]; +export const INITIAL_DATA: SwapData[] = [{title: 'From'}, {title: 'To'}]; @Injectable({ providedIn: 'root', From 1e80ede14070b5b5c3c0026af103a69e584b3825 Mon Sep 17 00:00:00 2001 From: MishaZhem Date: Thu, 1 Aug 2024 15:59:09 +0300 Subject: [PATCH 06/22] chore: remove extra code #2 --- .../src/dashboards/crypto/components/swap/swap.component.html | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html index 1d5ba8d2e..7c63d8252 100644 --- a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html +++ b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html @@ -85,7 +85,6 @@ From 751fac3de061b088030394ee69c3cae7c9ecb4bf Mon Sep 17 00:00:00 2001 From: MishaZhem Date: Thu, 1 Aug 2024 16:30:20 +0300 Subject: [PATCH 07/22] chore: remove extra code --- .../src/dashboards/crypto/components/swap/swap.component.html | 2 +- .../src/dashboards/crypto/components/swap/swap.component.ts | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html index 7c63d8252..463e54c73 100644 --- a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html +++ b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html @@ -27,7 +27,7 @@ class="choose-crypto" [tuiDropdown]="dropdownContent" [(tuiDropdownOpen)]="openedDialog[$index]" - (click)="openInfo($index)" + (click)="openedDialog[$index] = !openedDialog[$index]" > Date: Fri, 2 Aug 2024 12:17:30 +0300 Subject: [PATCH 08/22] chore: add price signal --- .../components/swap/swap.component.html | 40 +++++++++------ .../crypto/components/swap/swap.component.ts | 49 ++++++++++++------- .../src/services/crypto.service.ts | 7 +-- 3 files changed, 58 insertions(+), 38 deletions(-) diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html index 463e54c73..89882ff1b 100644 --- a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html +++ b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html @@ -1,5 +1,5 @@ -@let info = info$ | async; -@if (info) { +@let info = info$(); +@if (info !== undefined) { @let data = info.data;
{{ type.title }}
-
Balance: 1000 {{ chosen[$index].toUpperCase() }}
+
Balance: 1000 {{ chosen()[$index].toUpperCase() }}

diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.ts b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.ts index e5bc7d607..1e19c2ef9 100644 --- a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.ts +++ b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.ts @@ -60,8 +60,8 @@ export class SwapComponent { protected readonly titles = ['From', 'To']; - protected readonly from = signal('0'); - protected readonly to = signal('0'); + protected readonly from = signal(0); + protected readonly to = signal(0); protected readonly chosenFrom = signal('eth'); protected readonly chosenTo = signal('btc'); protected readonly openedDialog = [false, false]; @@ -76,10 +76,6 @@ export class SwapComponent { this.newSwapTo(); } - protected toNum(val: string): number { - return Number(val); - } - protected getPrice(data: PricesData[] | undefined, title: string): number { return ( Number( @@ -92,13 +88,15 @@ export class SwapComponent { protected newSwapFrom(): void { this.to.set( - ((this.priceFrom() * Number(this.from())) / this.priceTo()).toFixed(2), + Number( + ((this.priceFrom() * Number(this.from())) / this.priceTo()).toFixed(2), + ), ); } protected newSwapTo(): void { this.from.set( - ((this.priceTo() * Number(this.to())) / this.priceFrom()).toFixed(2), + Number(((this.priceTo() * Number(this.to())) / this.priceFrom()).toFixed(2)), ); } } From 98ab0fa849b4bf3b3707b516b3237bbfc38585df Mon Sep 17 00:00:00 2001 From: MishaZhem Date: Wed, 7 Aug 2024 15:09:20 +0300 Subject: [PATCH 20/22] chore: remove extra variables --- .../src/dashboards/crypto/components/swap/swap.component.html | 2 +- .../src/dashboards/crypto/components/swap/swap.component.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html index 4c4787b1d..135dcecb3 100644 --- a/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html +++ b/apps/taiga-lumbermill/src/dashboards/crypto/components/swap/swap.component.html @@ -23,10 +23,10 @@