Skip to content

Commit

Permalink
Merge pull request #1363 from numbersprotocol/feature-add-wallet-page
Browse files Browse the repository at this point in the history
feat: add wallets page and support transfer NUM between asset and int…
  • Loading branch information
ruizehung authored Mar 14, 2022
2 parents 1ee1c0b + 5f3b87e commit 88af6d8
Show file tree
Hide file tree
Showing 35 changed files with 1,416 additions and 188 deletions.
7 changes: 7 additions & 0 deletions src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ const routes: Routes = [
m => m.ContactsPageModule
),
},
{
path: 'wallets',
loadChildren: () =>
import('./features/wallets/wallets.module').then(
m => m.WalletsPageModule
),
},
];
@NgModule({
imports: [
Expand Down
5 changes: 4 additions & 1 deletion src/app/features/home/details/actions/actions.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,10 @@ export class ActionsPage {
catchError((err: unknown) => {
if (err instanceof HttpErrorResponse) {
const errorType = err.error.error?.type;
if (errorType === 'insufficient_fund')
if (
errorType === 'insufficient_fund' ||
errorType === 'order_expired'
)
return this.errorService.toastError$(
this.translocoService.translate(`error.diaBackend.${errorType}`)
);
Expand Down
5 changes: 5 additions & 0 deletions src/app/features/home/home.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
{{ t('contacts') }}
</a>
</mat-list-item>
<mat-list-item>
<a routerLink="/wallets" (click)="sidenav.close()" mat-list-item>
{{ t('wallets.wallets') }}
</a>
</mat-list-item>
<mat-list-item>
<a routerLink="/settings" (click)="sidenav.close()" mat-list-item>
{{ t('settings') }}
Expand Down
23 changes: 19 additions & 4 deletions src/app/features/home/home.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { ConfirmAlert } from '../../shared/confirm-alert/confirm-alert.service';
import { DiaBackendAssetRepository } from '../../shared/dia-backend/asset/dia-backend-asset-repository.service';
import { DiaBackendAuthService } from '../../shared/dia-backend/auth/dia-backend-auth.service';
import { DiaBackendTransactionRepository } from '../../shared/dia-backend/transaction/dia-backend-transaction-repository.service';
import { DiaBackendWalletService } from '../../shared/dia-backend/wallet/dia-backend-wallet.service';
import { ErrorService } from '../../shared/error/error.service';
import { MigrationService } from '../../shared/migration/service/migration.service';
import { OnboardingService } from '../../shared/onboarding/onboarding.service';
Expand Down Expand Up @@ -69,7 +70,8 @@ export class HomePage {
private readonly cameraService: CameraService,
private readonly actionSheetController: ActionSheetController,
private readonly alertController: AlertController,
private readonly goProBluetoothService: GoProBluetoothService
private readonly goProBluetoothService: GoProBluetoothService,
private readonly diaBackendWalletService: DiaBackendWalletService
) {
this.downloadExpiredPostCaptures();
}
Expand All @@ -78,9 +80,6 @@ export class HomePage {
of(this.onboardingService.isNewLogin)
.pipe(
concatMap(isNewLogin => this.migrationService.migrate$(isNewLogin)),
concatMap(() =>
this.migrationService.createOrImportDiaBackendAssetWallet$()
),
catchError(() => VOID$),
switchTapTo(defer(() => this.onboardingRedirect())),
catchError((err: unknown) => this.errorService.toastError$(err)),
Expand All @@ -96,6 +95,22 @@ export class HomePage {
});
}
this.onboardingService.isNewLogin = false;

if (!(await this.onboardingService.hasCreatedOrImportedIntegrityWallet())) {
this.migrationService
.createOrImportDiaBackendIntegrityWallet$()
.toPromise()
.then(() =>
this.onboardingService.setHasCreatedOrImportedIntegrityWallet(true)
);
}
if (!(await this.onboardingService.hasSyncAssetWalletBalance())) {
this.diaBackendWalletService
.syncAssetWalletBalance$()
.toPromise()
.then(() => this.onboardingService.setHasSyncAssetWalletBalance(true));
}

if (
!(await this.onboardingService.hasPrefetchedDiaBackendAssets()) &&
(await this.diaBackendAssetRepository.fetchOriginallyOwnedCount$
Expand Down
62 changes: 0 additions & 62 deletions src/app/features/profile/profile.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,6 @@
</div>
<div *transloco="let t" class="page-content">
<mat-list>
<mat-list-item>
<ion-icon mat-list-icon src="/assets/images/num-icon.svg"></ion-icon>
<div mat-line>NUM {{ t('balance') }}</div>
<div mat-line>
ERC20
<a (click)="openNUMTransactionHistory('erc20')">{{
t('numTransactionHistory')
}}</a>
</div>
<div class="num-balance">
<ng-container *ngIf="networkConnected$ | ngrxPush; else balanceOffline">
<ng-container
*ngIf="!(isLoadingBalance$ | ngrxPush); else balanceLoading"
>
$ {{ ethNumBalance$ | ngrxPush | number: '1.2-2' }}
</ng-container>
</ng-container>
<ng-template #balanceOffline> --offline-- </ng-template>
<ng-template #balanceLoading>
<mat-spinner diameter="30"></mat-spinner>
</ng-template>
</div>
</mat-list-item>
<mat-list-item>
<ion-icon mat-list-icon src="/assets/images/num-icon.svg"></ion-icon>
<div mat-line>NUM {{ t('balance') }}</div>
<div mat-line>
BEP20
<a (click)="openNUMTransactionHistory('bep20')">{{
t('numTransactionHistory')
}}</a>
</div>
<div class="num-balance">
<ng-container *ngIf="networkConnected$ | ngrxPush; else balanceOffline">
<ng-container
*ngIf="!(isLoadingBalance$ | ngrxPush); else balanceLoading"
>
$ {{ bscNumBalance$ | ngrxPush | number: '1.2-2' }}
</ng-container>
</ng-container>
</div>
</mat-list-item>
<mat-list-item>
<mat-icon mat-list-icon>account_circle</mat-icon>
<div mat-line>{{ t('username') }}</div>
Expand Down Expand Up @@ -126,27 +84,7 @@
<div mat-line>{{ t('email') }}</div>
<div mat-line>{{ email$ | ngrxPush }}</div>
</mat-list-item>
<mat-list-item>
<mat-icon mat-list-icon>lock</mat-icon>
<div mat-line>{{ t('walletAddress') }}</div>
<div mat-line>{{ publicKey$ | ngrxPush }}</div>
<button
*ngIf="publicKey$ | ngrxPush as publicKey"
(click)="copyToClipboard(publicKey)"
mat-icon-button
>
<mat-icon>content_copy</mat-icon>
</button>
</mat-list-item>
</mat-list>
<button
(click)="exportPrivateKey()"
class="expand"
color="primary"
mat-stroked-button
>
{{ t('exportPrivateKey') }}
</button>
<button (click)="logout()" class="expand" color="primary" mat-stroked-button>
{{ t('logout') }}
</button>
Expand Down
89 changes: 3 additions & 86 deletions src/app/features/profile/profile.page.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,19 @@
import { Component } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router';
import { Plugins } from '@capacitor/core';
import { AlertController } from '@ionic/angular';
import { TranslocoService } from '@ngneat/transloco';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { defer, forkJoin, iif } from 'rxjs';
import {
catchError,
concatMap,
concatMapTo,
first,
switchMap,
} from 'rxjs/operators';
import { catchError, concatMap, concatMapTo } from 'rxjs/operators';
import { BlockingActionService } from '../../shared/blocking-action/blocking-action.service';
import { WebCryptoApiSignatureProvider } from '../../shared/collector/signature/web-crypto-api-signature-provider/web-crypto-api-signature-provider.service';
import { ConfirmAlert } from '../../shared/confirm-alert/confirm-alert.service';
import { Database } from '../../shared/database/database.service';
import { DiaBackendAuthService } from '../../shared/dia-backend/auth/dia-backend-auth.service';
import { DiaBackendWalletService } from '../../shared/dia-backend/wallet/dia-backend-wallet.service';
import { ErrorService } from '../../shared/error/error.service';
import { ExportPrivateKeyModalComponent } from '../../shared/export-private-key-modal/export-private-key-modal.component';
import { MediaStore } from '../../shared/media/media-store/media-store.service';
import { PreferenceManager } from '../../shared/preference-manager/preference-manager.service';

const { Browser, Clipboard } = Plugins;

@UntilDestroy({ checkProperties: true })
@Component({
selector: 'app-profile',
Expand All @@ -36,22 +23,9 @@ const { Browser, Clipboard } = Plugins;
export class ProfilePage {
readonly username$ = this.diaBackendAuthService.username$;
readonly email$ = this.diaBackendAuthService.email$;
readonly publicKey$ = this.webCryptoApiSignatureProvider.publicKey$;
readonly privateKey$ = this.webCryptoApiSignatureProvider.privateKey$;
readonly phoneVerified$ = this.diaBackendAuthService.phoneVerified$;
readonly emailVerified$ = this.diaBackendAuthService.emailVerified$;
readonly ethNumBalance$ = this.diaBackendWalletService.ethNumBalance$;
readonly bscNumBalance$ = this.diaBackendWalletService.bscNumBalance$;
readonly networkConnected$ = this.diaBackendWalletService.networkConnected$;
readonly isLoadingBalance$ = this.diaBackendWalletService.isLoadingBalance$;

readonly contractAddressNUMERC20 =
'0x3496b523e5c00a4b4150d6721320cddb234c3079';
readonly contractAddressNUMBEP20 =
'0xeceb87cf00dcbf2d4e2880223743ff087a995ad9';

readonly domainEtherScan = 'etherscan.io';
readonly domainBscScan = 'bscscan.com';

constructor(
private readonly database: Database,
Expand All @@ -60,47 +34,20 @@ export class ProfilePage {
private readonly blockingActionService: BlockingActionService,
private readonly errorService: ErrorService,
private readonly translocoService: TranslocoService,
private readonly snackBar: MatSnackBar,
private readonly diaBackendAuthService: DiaBackendAuthService,
private readonly webCryptoApiSignatureProvider: WebCryptoApiSignatureProvider,
private readonly confirmAlert: ConfirmAlert,
private readonly alertController: AlertController,
private readonly router: Router,
private readonly route: ActivatedRoute,
private readonly diaBackendWalletService: DiaBackendWalletService,
private readonly dialog: MatDialog
private readonly diaBackendWalletService: DiaBackendWalletService
) {}

ionViewWillEnter() {
forkJoin([
this.diaBackendAuthService.syncProfile$(),
this.diaBackendWalletService.syncCaptBalance$(),
])
forkJoin([this.diaBackendAuthService.syncProfile$()])
.pipe(untilDestroyed(this))
.subscribe();
}

openNUMTransactionHistory(standard: 'erc20' | 'bep20') {
const domain =
standard == 'erc20' ? this.domainEtherScan : this.domainBscScan;
const contractAddress =
standard == 'erc20'
? this.contractAddressNUMERC20
: this.contractAddressNUMBEP20;
this.diaBackendWalletService.numWalletAddr$
.pipe(
first(),
switchMap(address =>
Browser.open({
url: `https://${domain}/token/${contractAddress}?a=${address}`,
toolbarColor: '#564dfc',
})
),
untilDestroyed(this)
)
.subscribe();
}

async editUsername() {
const alert = await this.alertController.create({
header: this.translocoService.translate('editUsername'),
Expand Down Expand Up @@ -147,36 +94,6 @@ export class ProfilePage {
});
}

async copyToClipboard(value: string) {
await Clipboard.write({ string: value });
this.snackBar.open(
this.translocoService.translate('message.copiedToClipboard')
);
}

exportPrivateKey() {
this.privateKey$
.pipe(
first(),
concatMap(async privateKey => {
const result = await this.confirmAlert.present({
message: this.translocoService.translate(
'message.confirmCopyPrivateKey'
),
});
if (result)
this.dialog.open<ExportPrivateKeyModalComponent>(
ExportPrivateKeyModalComponent,
{
data: { privateKey },
}
);
}),
untilDestroyed(this)
)
.subscribe();
}

logout() {
const action$ = defer(() => this.mediaStore.clear()).pipe(
concatMapTo(defer(() => this.database.clear())),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<div *transloco="let t">
<ion-row>
<ion-col *ngIf="mode === 'withdraw'" size="3">
<ion-icon id="wallet-icon" name="wallet"></ion-icon>
</ion-col>
<ion-col *ngIf="mode === 'deposit'" id="num-icon-col" size="3">
<ion-img src="../../../assets/images/num-icon.svg"></ion-img>
</ion-col>
<ion-col>
<ion-row id="forward-icons-row">
<ion-img
class="arrow-img"
src="../../../assets/images/transfer_arrow.svg"
></ion-img>
<ion-img
class="arrow-img"
src="../../../assets/images/transfer_arrow.svg"
></ion-img>
<ion-img
class="arrow-img"
src="../../../assets/images/transfer_arrow.svg"
></ion-img>
</ion-row>
<h4>
{{ t('wallets.' + mode) }}
</h4>
</ion-col>
<ion-col *ngIf="mode === 'deposit'" size="3">
<ion-icon id="wallet-icon" name="wallet"></ion-icon>
</ion-col>
<ion-col *ngIf="mode === 'withdraw'" id="num-icon-col" size="3">
<ion-img src="../../../assets/images/num-icon.svg"></ion-img>
</ion-col>
</ion-row>
</div>
Loading

0 comments on commit 88af6d8

Please sign in to comment.