1
0
Fork 0
forked from lthn/blockchain

Status setting wallet fix (#265)

* Status setting wallet (#1)

* add disabled btn setting_wallet

* add build html

* fix update status wallet

* add context copy seed_phrase

* fix bug

* fix wallet status

* update

* Create wallet

* fix wallet login and add seed block in create wallet
This commit is contained in:
Nazar 2020-12-09 22:32:46 +02:00 committed by GitHub
parent 1e0d085727
commit 7b4a6fa90a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 1087 additions and 415 deletions

View file

@ -33,6 +33,9 @@ $themes: (
accountBackgroundColor: rgba(43, 54, 68, 0.5),
accountHoverBackgroundColor: rgba(58, 69, 85, 0.5),
accountMainTextColor: #e0e0e0,
securedSeed: #e0e0e0,
seedItemText: #e0e0e0,
seedItemBackgroundColor: #18202a,
accountOptionalTextColor: #556576,
accountIndicatorTextColor: #111921,
accountSwitchBackgroundColor: #000000,
@ -90,6 +93,9 @@ $themes: (
accountBackgroundColor: rgba(37, 40, 43, 0.5),
accountHoverBackgroundColor: rgba(58, 62, 66, 0.5),
accountMainTextColor: #e0e0e0,
securedSeed: #e0e0e0,
seedItemText: #e0e0e0,
seedItemBackgroundColor: #292d31,
accountOptionalTextColor: #565c62,
accountIndicatorTextColor: #1a1a1a,
accountSwitchBackgroundColor: #000000,
@ -147,6 +153,9 @@ $themes: (
accountBackgroundColor: rgba(30, 136, 229, 1),
accountHoverBackgroundColor: rgba(240, 240, 240, 0.5),
accountMainTextColor: #ffffff,
securedSeed: #a0a5ab,
seedItemText: #43454b,
seedItemBackgroundColor: #e6e6e6,
accountOptionalTextColor: #91baf1,
accountIndicatorTextColor: #43454b,
accountSwitchBackgroundColor: #ffffff,

View file

@ -0,0 +1,258 @@
.form-details {
margin-top: 1.8rem;
.input-block {
&:first-child {
width: 50%;
}
}
.wallet-buttons {
display: flex;
align-items: center;
justify-content: space-between;
button {
margin: 2.9rem 0;
width: 100%;
max-width: 15rem;
}
}
}
.form-seed {
label {
@include themify($themes) {
color: themed(optionalTextColor);
}
font-size: 1.3rem;
line-height: 2.4rem;
}
.form-content {
@include themify($themes) {
border: 2px solid themed(transparentButtonBorderColor);
}
display: flex;
justify-content: center;
padding: 3rem;
width: 100%;
}
.text-coral {
@include themify($themes) {
color: themed(blueTextColor);
}
text-decoration: none;
}
.seed-phrase-form {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
max-width: 38rem;
width: 100%;
.input-block,
button {
width: 100%;
}
.error-message {
margin-top: 1rem;
@include themify($themes) {
color: themed(orangeTextColor);
}
}
.secured-seed {
@include themify($themes) {
color: themed(securedSeed);
}
font-size: 1.2rem;
line-height: 2.4rem;
text-decoration: none;
display: flex;
align-items: center;
cursor: pointer;
.icon {
margin-right: 1.2rem;
}
}
button {
display: flex;
justify-content: center;
align-items: center;
margin-top: 3rem;
margin-bottom: 2rem;
.icon {
margin-right: 1.2rem;
}
}
}
}
.seed-phrase {
display: flex;
flex-direction: column;
width: 100%;
background-color: transparent !important;
&-title {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
@include themify($themes) {
color: themed(optionalTextColor);
}
.right-part {
display: inline-flex;
align-items: center;
.icon {
cursor: pointer;
width: 1.7rem;
height: 1.7rem;
&.copy {
@include themify($themes) {
background-color: themed(blueTextColor);
}
margin-right: 1.2rem;
mask: url(~src/assets/icons/copy.svg) no-repeat center;
&:hover {
opacity: 0.75;
}
}
&.copied {
@include themify($themes) {
background-color: themed(blueTextColor);
}
margin-right: 1.2rem;
mask: url(~src/assets/icons/complete-testwallet.svg) no-repeat center;
}
&.secured,
&.unsecured {
margin-left: 1.2rem;
}
}
span {
font-size: 1.3rem;
line-height: 2.4rem;
display: inline-flex;
align-items: center;
.icon {
margin-left: 1.2rem;
}
}
}
}
&-content {
@include themify($themes) {
border-top: 2px solid themed(transparentButtonBorderColor);
border-bottom: 2px solid themed(transparentButtonBorderColor);
}
padding: 1rem 0 1rem;
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
margin-bottom: 1rem;
.item {
@include themify($themes) {
color: themed(seedItemText);
}
display: flex;
align-items: center;
padding: 0 2rem;
width: calc(100% / 7);
min-height: 35px;
font-size: 1.3rem;
&.dark {
@include themify($themes) {
background-color: themed(seedItemBackgroundColor);
}
}
}
}
&-footer {
text-align: center;
.title {
@include themify($themes) {
color: themed(seedItemText);
}
font-size: 1.3rem;
line-height: 2.4rem;
}
}
}
.icon {
display: inline-flex;
width: 1.6rem;
height: 1.6rem;
&.secured {
@include themify($themes) {
background-color: themed(greenTextColor);
}
mask: url(~src/assets/icons/secured.svg) no-repeat center;
}
&.info {
@include themify($themes) {
background-color: themed(blueTextColor);
}
mask: url(~src/assets/icons/info.svg) no-repeat center;
}
&.unsecured {
@include themify($themes) {
background-color: themed(orangeTextColor);
}
mask: url(~src/assets/icons/unsecured.svg) no-repeat center;
}
&.safety {
@include themify($themes) {
background-color: themed(alternativeTextColor);
}
mask: url(~src/assets/icons/safety.svg) no-repeat center;
}
}
.wrap-buttons {
display: flex;
.seed-phrase-button {
margin: 2.8rem 0;
width: 25%;
min-width: 1.5rem;
}
.copy-button {
margin: 2.8rem 1rem;
width: 25%;
min-width: 1.5rem;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -59,4 +59,4 @@
</div>
<app-progress-container [width]="progressWidth" [labels]="['PROGRESS.ADD_WALLET', 'PROGRESS.SELECT_LOCATION', 'PROGRESS.CREATE_WALLET']"></app-progress-container>
<app-progress-container [width]="progressWidth" [labels]="['PROGRESS.ADD_WALLET', 'PROGRESS.SELECT_LOCATION', 'Seed Phrase', 'PROGRESS.CREATE_WALLET']"></app-progress-container>

View file

@ -84,7 +84,7 @@ export class CreateWalletComponent implements OnInit {
this.variablesService.opening_wallet.currentPage = 1;
this.ngZone.run(() => {
this.walletSaved = true;
this.progressWidth = '50%';
this.progressWidth = '33%';
});
} else {
if (errorCode && errorCode === 'ALREADY_EXISTS') {

View file

@ -3,7 +3,7 @@
<form class="open-form" (ngSubmit)="openWallet()">
<div class="wallet-path">{{ wallet.name }}</div>
<div class="wallet-path">{{ wallet.path }}</div>
<div class="input-block" *ngIf="!wallet.notFound && !wallet.emptyPass">
<div class="input-block" *ngIf="!wallet.notFound">
<label for="password">{{ 'OPEN_WALLET.MODAL.LABEL' | translate }}</label>
<input type="password" id="password" name="password" [(ngModel)]="wallet.pass" (contextmenu)="variablesService.onContextMenuPasteSelect($event)"/>
</div>

View file

@ -35,18 +35,6 @@ export class OpenWalletModalComponent implements OnInit {
if (this.wallets.length) {
this.wallet = this.wallets[0];
this.wallet.pass = '';
this.backend.openWallet(this.wallet.path, '', this.variablesService.count, true, (status, data, error) => {
if (error === 'FILE_NOT_FOUND') {
this.wallet.notFound = true;
}
if (status) {
this.wallet.pass = '';
this.wallet.emptyPass = true;
this.backend.closeWallet(data.wallet_id);
this.openWallet();
}
});
}
}
@ -56,6 +44,9 @@ export class OpenWalletModalComponent implements OnInit {
}
this.backend.openWallet(this.wallet.path, this.wallet.pass, this.variablesService.count, false, (open_status, open_data, open_error) => {
if (open_error && open_error === 'FILE_NOT_FOUND') {
this.ngZone.run(() => {
this.wallet.notFound = true;
});
let error_translate = this.translate.instant('OPEN_WALLET.FILE_NOT_FOUND1');
error_translate += ':<br>' + this.wallet.path;
error_translate += this.translate.instant('OPEN_WALLET.FILE_NOT_FOUND2');

View file

@ -7,7 +7,7 @@ import { ModalService } from '../_helpers/services/modal.service';
import { Wallet } from '../_helpers/models/wallet.model';
import { TranslateService } from '@ngx-translate/core';
import { Subject } from 'rxjs/internal/Subject';
import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators';
import { debounceTime, distinctUntilChanged, pairwise, startWith, takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-restore-wallet',
@ -74,12 +74,12 @@ export class RestoreWalletComponent implements OnInit, OnDestroy {
changeDetectionSeedPhrasePassword() {
this.restoreForm.controls.seedPassword.valueChanges
.pipe(debounceTime(0), distinctUntilChanged(), takeUntil(this.unsubscribeAll))
.pipe(startWith(null), pairwise(), takeUntil(this.unsubscribeAll))
.subscribe(() => {
this.checkValidSeedPhrasePassword();
});
this.restoreForm.controls.key.valueChanges
.pipe(debounceTime(0), distinctUntilChanged(), takeUntil(this.unsubscribeAll))
.pipe(startWith(null), pairwise(), takeUntil(this.unsubscribeAll))
.subscribe(() => {
this.checkValidSeedPhrasePassword();
});
@ -89,7 +89,9 @@ export class RestoreWalletComponent implements OnInit, OnDestroy {
const seed_password = this.restoreForm.controls.seedPassword.value;
const seed_phrase = this.restoreForm.controls.key.value;
this.backend.getSeedPhraseInfo({seed_phrase, seed_password}, (status, data) => {
this.seedPhraseInfo = data;
this.ngZone.run(() => {
this.seedPhraseInfo = data;
});
});
}

View file

@ -1,5 +1,5 @@
<div class="content">
<!-- breadcrumbs -->
<div class="head">
<div class="breadcrumbs">
<span [routerLink]="['/main']">{{ 'BREADCRUMBS.ADD_WALLET' | translate }}</span>
@ -10,19 +10,103 @@
<span>{{ 'COMMON.BACK' | translate }}</span>
</button>
</div>
<!-- /breadcrumbs -->
<h3 class="seed-phrase-title">{{ 'SEED_PHRASE.TITLE' | translate }}</h3>
<div class="scrolled-content">
<!-- form detail -->
<form class="form-details" [formGroup]="detailsForm">
<div class="input-block">
<label for="wallet-name">{{ 'WALLET_DETAILS.LABEL_NAME' | translate }}</label>
<input type="text" id="wallet-name" formControlName="name" [maxLength]="variablesService.maxWalletNameLength"
(contextmenu)="variablesService.onContextMenu($event)" readonly>
<div class="error-block"
*ngIf="detailsForm.controls['name'].invalid && (detailsForm.controls['name'].dirty || detailsForm.controls['name'].touched)">
<div *ngIf="detailsForm.controls['name'].errors['required']">
{{ 'WALLET_DETAILS.FORM_ERRORS.NAME_REQUIRED' | translate }}
</div>
<div *ngIf="detailsForm.controls['name'].errors['duplicate']">
{{ 'WALLET_DETAILS.FORM_ERRORS.NAME_DUPLICATE' | translate }}
</div>
</div>
<div class="error-block" *ngIf="detailsForm.get('name').value.length >= variablesService.maxWalletNameLength">
{{ 'WALLET_DETAILS.FORM_ERRORS.MAX_LENGTH' | translate }}
</div>
</div>
<div class="seed-phrase-content" (contextmenu)="variablesService.onContextMenuOnlyCopy($event, seedPhrase)">
<ng-container *ngFor="let word of seedPhrase.split(' '); let index = index">
<div class="word">{{(index + 1) + '. ' + word}}</div>
<div class="input-block">
<label for="wallet-location">{{ 'WALLET_DETAILS.LABEL_FILE_LOCATION' | translate }}</label>
<input type="text" id="wallet-location" formControlName="path" readonly>
</div>
</form>
<!-- /from detail -->
<!-- form seed pasword -->
<ng-container *ngIf="!showSeed else seedPhraseContent">
<form class="form-seed mt-2" [formGroup]="seedPhraseForm" (ngSubmit)="onSubmitSeed()">
<label>{{ 'WALLET_DETAILS.LABEL_SEED_PHRASE' | translate }}</label>
<div class="form-content">
<div class="seed-phrase-form">
<div class="input-block">
<label for="create-password">{{ 'WALLET_DETAILS.CREATE_PASSWORD_SECURE' | translate }} (<a
class="text-coral">{{ 'WALLET_DETAILS.INFO' | translate }}</a>)</label>
<input type="password" id="create-password" formControlName="password">
</div>
<div class="input-block">
<label for="confirm-password">{{ 'WALLET_DETAILS.FORM.CONFIRM_PASSWORD' | translate }}</label>
<input type="password" id="confirm-password" formControlName="confirmPassword">
</div>
<span class="error-message" *ngIf="!seedPhraseForm.valid">
{{ 'WALLET_DETAILS.FORM_ERRORS.PASSWORDS_DONT_MATCH' | translate }}
</span>
<button type="submit" class="blue-button" [disabled]="!seedPhraseForm.valid"><i class="icon safety"></i>
{{ 'WALLET_DETAILS.FORM.GENERATE_SECURE_SEED' | translate }}</button>
<a class="secured-seed"><i
class="icon info"></i>{{ 'WALLET_DETAILS.FORM.SECURED_SEED_WILL_REQUIRE' | translate }}</a>
</div>
</div>
</form>
</ng-container>
</div>
<!-- /form seed pasword -->
<div class="wrap-buttons">
<button type="button" class="blue-button seed-phrase-button" (click)="runWallet()">{{ 'SEED_PHRASE.BUTTON_CREATE_ACCOUNT' | translate }}</button>
<button type="button" class="blue-button copy-button" (click)="copySeedPhrase()">{{ 'SEED_PHRASE.BUTTON_COPY' | translate }}</button>
<!-- seed phrase -->
<ng-template #seedPhraseContent>
<div class="seed-phrase mt-2">
<div class="seed-phrase-title">
<span>{{ 'WALLET_DETAILS.LABEL_SEED_PHRASE' | translate }}</span>
<p class="right-part">
<span
*ngIf="seedPhraseForm.controls.password.value.length == 0">{{ 'WALLET_DETAILS.SEED_IS_UNSECURED' | translate }}
<i class="icon unsecured"></i></span>
<span
*ngIf="seedPhraseForm.controls.password.value.length > 0">{{ 'WALLET_DETAILS.SEED_IS_SECURED' | translate }}
<i class="icon secured"></i></span>
</p>
</div>
<div class="seed-phrase-content" (contextmenu)="variablesService.onContextMenuOnlyCopy($event, seedPhrase)">
<ng-container *ngFor="let word of seedPhrase.split(' '); let index = index">
<div class="item"
[class.dark]="(index + 1) >= 1 && (index + 1) <= 7 || (index + 1) >= 15 && (index + 1) <= 21">
{{(index + 1) + '. ' + word}}</div>
</ng-container>
</div>
<div class="seed-phrase-footer" *ngIf="seedPhraseForm.controls.password.value.length > 0">
<span class="title">{{ 'WALLET_DETAILS.REMEMBER_YOU_WILL_REQUIRE' | translate }}</span>
</div>
</div>
</ng-template>
<!-- /seed phrase -->
<div class="wrap-buttons" *ngIf="showSeed">
<button type="button" class="blue-button seed-phrase-button"
(click)="runWallet()">{{ 'SEED_PHRASE.BUTTON_CREATE_ACCOUNT' | translate }}</button>
<button type="button" class="blue-button copy-button"
(click)="copySeedPhrase()">{{ 'SEED_PHRASE.BUTTON_COPY' | translate }}</button>
</div>
</div>
</div>
<app-progress-container [width]="'100%'" [labels]="['PROGRESS.ADD_WALLET', 'PROGRESS.SELECT_LOCATION', 'PROGRESS.CREATE_WALLET']"></app-progress-container>
<app-progress-container [width]="progressWidth"
[labels]="['PROGRESS.ADD_WALLET', 'PROGRESS.SELECT_LOCATION', 'Seed Phrase', 'PROGRESS.CREATE_WALLET']">
</app-progress-container>

View file

@ -2,38 +2,15 @@
position: relative;
}
.seed-phrase-title {
line-height: 2.2rem;
padding: 2.2rem 0;
.content {
padding: 3.2rem 3rem 3rem;
}
.scrolled-content, .content {
height: 100%;
overflow-y: auto;
}
.seed-phrase-content {
display: flex;
flex-direction: column;
flex-wrap: wrap;
padding: 1.4rem;
width: 100%;
height: 12rem;
.word {
line-height: 2.2rem;
max-width: 13rem;
}
}
.wrap-buttons {
display: flex;
.seed-phrase-button {
margin: 2.8rem 0;
width: 25%;
min-width: 1.5rem;
}
.copy-button {
margin: 2.8rem 1rem;
width: 25%;
min-width: 1.5rem;
}
.mt-2 {
margin-top: 2rem;
}

View file

@ -4,6 +4,7 @@ import {BackendService} from '../_helpers/services/backend.service';
import {ActivatedRoute, Router} from '@angular/router';
import {VariablesService} from '../_helpers/services/variables.service';
import {ModalService} from '../_helpers/services/modal.service';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-seed-phrase',
@ -14,8 +15,53 @@ export class SeedPhraseComponent implements OnInit, OnDestroy {
queryRouting;
seedPhrase = '';
showSeed = false;
wallet_id: number;
seedPhraseCopied = false;
progressWidth = '66%';
detailsForm = new FormGroup({
name: new FormControl('', [
Validators.required,
(g: FormControl) => {
for (let i = 0; i < this.variablesService.wallets.length; i++) {
if (g.value === this.variablesService.wallets[i].name) {
if (
this.variablesService.wallets[i].wallet_id ===
this.variablesService.currentWallet.wallet_id
) {
return { same: true };
} else {
return { duplicate: true };
}
}
}
return null;
},
]),
path: new FormControl(''),
});
seedPhraseForm = new FormGroup(
{
password: new FormControl(
'',
Validators.pattern(this.variablesService.pattern)
),
confirmPassword: new FormControl(
'',
Validators.pattern(this.variablesService.pattern)
),
},
{ validators: this.checkPasswords }
);
checkPasswords(group: FormGroup) {
const pass = group.controls.password.value;
const confirmPass = group.controls.confirmPassword.value;
return pass === confirmPass ? null : { notSame: true };
}
constructor(
private route: ActivatedRoute,
@ -28,16 +74,24 @@ export class SeedPhraseComponent implements OnInit, OnDestroy {
) {}
ngOnInit() {
this.showSeed = false;
this.getWalletId();
this.setWalletInfoNamePath();
}
private setWalletInfoNamePath() {
this.detailsForm
.get('name')
.setValue(this.variablesService.opening_wallet.name);
this.detailsForm
.get('path')
.setValue(this.variablesService.opening_wallet.path);
}
private getWalletId() {
this.queryRouting = this.route.queryParams.subscribe(params => {
if (params.wallet_id) {
this.wallet_id = params.wallet_id;
this.backend.getSmartWalletInfo(params.wallet_id, (status, data) => {
if (data.hasOwnProperty('seed_phrase')) {
this.ngZone.run(() => {
this.seedPhrase = data['seed_phrase'].trim();
});
}
});
}
});
}
@ -86,8 +140,30 @@ export class SeedPhraseComponent implements OnInit, OnDestroy {
this.location.back();
}
showSeedPhrase() {
this.showSeed = true;
this.progressWidth = '100%';
}
onSubmitSeed() {
if (this.seedPhraseForm.valid) {
this.showSeedPhrase();
const wallet_id = this.wallet_id;
const seed_password = this.seedPhraseForm.controls.password.value;
this.backend.getSmartWalletInfo(
{ wallet_id, seed_password },
(status, data) => {
if (data.hasOwnProperty('seed_phrase')) {
this.ngZone.run(() => {
this.seedPhrase = data['seed_phrase'].trim();
});
}
}
);
}
}
ngOnDestroy() {
this.queryRouting.unsubscribe();
}
}

View file

@ -68,14 +68,13 @@
<div class="seed-phrase-title">
<span>{{ 'WALLET_DETAILS.LABEL_SEED_PHRASE' | translate }}</span>
<p class="right-part">
<i class="icon" [class.copy]="!copyAnimation" [class.copied]="copyAnimation" (click)="copySeedPhrase()"></i>
<span
*ngIf="seedPhraseForm.controls.password.value.length == 0">{{ 'WALLET_DETAILS.SEED_IS_UNSECURED' | translate }} <i class="icon unsecured"></i></span>
<span
*ngIf="seedPhraseForm.controls.password.value.length > 0">{{ 'WALLET_DETAILS.SEED_IS_SECURED' | translate }} <i class="icon secured"></i></span>
</p>
</div>
<div class="seed-phrase-content">
<div class="seed-phrase-content" (contextmenu)="variablesService.onContextMenuOnlyCopy($event, seedPhrase)">
<ng-container *ngFor="let word of seedPhrase.split(' '); let index = index">
<div class="item"
[class.dark]="(index + 1) >= 1 && (index + 1) <= 7 || (index + 1) >= 15 && (index + 1) <= 21">

View file

@ -24,185 +24,3 @@
.mt-2 {
margin-top: 2rem;
}
.form-seed {
label {
color: #556576;
font-size: 1.3rem;
line-height: 2.4rem;
}
.form-content {
border: 2px solid #2b3644;
display: flex;
justify-content: center;
padding: 3rem;
width: 100%;
}
.text-coral {
color: #4db1ff;
text-decoration: none;
}
.seed-phrase-form {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
max-width: 38rem;
width: 100%;
.input-block,
button {
width: 100%;
}
.error-message {
margin-top: 1rem;
color: #ff6f00;
}
.secured-seed {
color: #e0e0e0;
font-size: 1.2rem;
line-height: 2.4rem;
text-decoration: none;
display: flex;
align-items: center;
cursor: pointer;
.icon {
margin-right: 1.2rem;
}
}
button {
display: flex;
justify-content: center;
align-items: center;
margin-top: 3rem;
margin-bottom: 2rem;
.icon {
margin-right: 1.2rem;
}
}
}
}
.seed-phrase {
display: flex;
flex-direction: column;
width: 100%;
background-color: transparent !important;
&-title {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.right-part {
display: inline-flex;
align-items: center;
.icon {
cursor: pointer;
width: 1.7rem;
height: 1.7rem;
&.copy {
background-color: #4caefb;
margin-right: 1.2rem;
mask: url(~src/assets/icons/copy.svg) no-repeat center;
&:hover {
opacity: 0.75;
}
}
&.copied {
margin-right: 1.2rem;
background-color: #4caefb;
mask: url(~src/assets/icons/complete-testwallet.svg) no-repeat center;
}
&.secured, &.unsecured {
margin-left: 1.2rem;
}
}
span {
color: #556576;
font-size: 1.3rem;
line-height: 2.4rem;
display: inline-flex;
align-items: center;
.icon {
margin-left: 1.2rem;
}
}
}
}
&-content {
border-top: 2px solid #2b3644;
border-bottom: 2px solid #2b3644;
padding: 1rem 0 1rem;
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
margin-bottom: 1rem;
.item {
display: flex;
align-items: center;
padding: 0 2rem;
width: calc(100% / 7);
min-height: 35px;
font-size: 1.3rem;
color: #e0e0e0;
&.dark {
background-color: #18202a;
}
}
}
&-footer {
text-align: center;
.title {
color: #556576;
font-size: 1.3rem;
line-height: 2.4rem;
}
}
}
.icon {
display: inline-flex;
width: 1.6rem;
height: 1.6rem;
&.secured {
background-color: #5cda9d;
mask: url(~src/assets/icons/secured.svg) no-repeat center;
}
&.info {
background-color: #4caefb;
mask: url(~src/assets/icons/info.svg) no-repeat center;
}
&.unsecured {
background-color: #ff6f00;
mask: url(~src/assets/icons/unsecured.svg) no-repeat center;
}
&.safety {
background-color: #111921;
mask: url(~src/assets/icons/safety.svg) no-repeat center;
}
}

View file

@ -14,7 +14,6 @@ export class WalletDetailsComponent implements OnInit, OnDestroy {
seedPhrase = '';
showSeed = false;
copyAnimation = false;
copyAnimationTimeout;
detailsForm = new FormGroup({
name: new FormControl('', [
@ -145,15 +144,7 @@ export class WalletDetailsComponent implements OnInit, OnDestroy {
this.location.back();
}
copySeedPhrase() {
this.backend.setClipboard(this.seedPhrase);
this.copyAnimation = true;
this.copyAnimationTimeout = window.setTimeout(() => {
this.copyAnimation = false;
}, 2000);
}
ngOnDestroy() {
clearTimeout(this.copyAnimationTimeout);
}
}

View file

@ -1,18 +1,25 @@
import { Component, OnInit, OnDestroy, NgZone, ViewChild, ElementRef } from '@angular/core';
import {
Component,
OnInit,
OnDestroy,
NgZone,
ViewChild,
ElementRef,
} from '@angular/core';
import { ActivatedRoute, Router, RoutesRecognized } from '@angular/router';
import { VariablesService } from '../_helpers/services/variables.service';
import { BackendService } from '../_helpers/services/backend.service';
import { TranslateService } from '@ngx-translate/core';
import { IntToMoneyPipe } from '../_helpers/pipes/int-to-money.pipe';
import {Subscription} from 'rxjs';
import { Subscription } from 'rxjs';
import { LOCKED_BALANCE_HELP_PAGE } from '../_shared/constants';
import icons from '../../assets/icons/icons.json';
import {PaginationService} from '../_helpers/services/pagination.service';
import {PaginationStore} from '../_helpers/services/pagination.store';
import {Store, Sync} from 'store';
import {Wallet} from '../_helpers/models/wallet.model';
import {distinctUntilChanged, filter} from 'rxjs/operators';
import { PaginationService } from '../_helpers/services/pagination.service';
import { PaginationStore } from '../_helpers/services/pagination.store';
import { Store, Sync } from 'store';
import { Wallet } from '../_helpers/models/wallet.model';
import { distinctUntilChanged, filter } from 'rxjs/operators';
@Component({
selector: 'app-wallet',
@ -45,7 +52,7 @@ export class WalletComponent implements OnInit, OnDestroy {
indicator: false,
active: true,
animated: icons.history,
itemHovered: false
itemHovered: false,
},
{
title: 'WALLET.TABS.SEND',
@ -54,7 +61,7 @@ export class WalletComponent implements OnInit, OnDestroy {
indicator: false,
active: false,
animated: icons.send,
itemHovered: false
itemHovered: false,
},
{
title: 'WALLET.TABS.RECEIVE',
@ -63,7 +70,7 @@ export class WalletComponent implements OnInit, OnDestroy {
indicator: false,
active: false,
animated: icons.receive,
itemHovered: false
itemHovered: false,
},
{
title: 'WALLET.TABS.CONTRACTS',
@ -72,7 +79,7 @@ export class WalletComponent implements OnInit, OnDestroy {
indicator: 1,
active: false,
animated: icons.contracts,
itemHovered: false
itemHovered: false,
},
/*{
title: 'WALLET.TABS.MESSAGES',
@ -90,8 +97,8 @@ export class WalletComponent implements OnInit, OnDestroy {
indicator: false,
active: false,
animated: icons.staking,
itemHovered: false
}
itemHovered: false,
},
];
aliasSubscription: Subscription;
walletsSubscription: Subscription;
@ -106,54 +113,71 @@ export class WalletComponent implements OnInit, OnDestroy {
private intToMoneyPipe: IntToMoneyPipe,
private pagination: PaginationService,
private paginationStore: PaginationStore,
private store: Store,
) { }
private store: Store
) {}
ngOnInit() {
this.subRouting1 = this.route.params.subscribe(params => {
this.subRouting1 = this.route.params.subscribe((params) => {
// set current wallet only by user click to avoid after sync show synchronized data
this.walletID = +params['id'];
this.walletLoaded = this.variablesService.getWallet(this.walletID).loaded;
this.variablesService.setCurrentWallet(this.walletID);
this.walletsSubscription = this.store.select('sync').pipe(
filter(Boolean),
distinctUntilChanged(),
).subscribe(value => {
const data = value.filter((item: Sync) => item.wallet_id === this.walletID)[0];
if (data && !data.sync) {
let in_progress;
const values = this.store.value.sync;
if (values && values.length) {
in_progress = values.filter(item => item.sync);
this.variablesService.sync_started = !!(in_progress && in_progress.length);
if (!in_progress) {
this.walletsSubscription = this.store
.select('sync')
.pipe(filter(Boolean), distinctUntilChanged())
.subscribe((value) => {
const data = value.filter(
(item: Sync) => item.wallet_id === this.walletID
)[0];
if (data && !data.sync) {
let in_progress;
const values = this.store.value.sync;
if (values && values.length) {
in_progress = values.filter((item) => item.sync);
this.variablesService.sync_started = !!(
in_progress && in_progress.length
);
if (!in_progress) {
this.variablesService.sync_started = false;
}
} else {
this.variablesService.sync_started = false;
}
} else {
this.variablesService.sync_started = false;
}
}
let restore = false;
if (this.variablesService.after_sync_request.hasOwnProperty(this.walletID)) {
restore = this.variablesService.after_sync_request[this.walletID];
}
if (!this.variablesService.sync_started && restore && this.walletID === (data && data.wallet_id)) {
this.wallet = this.variablesService.getNotLoadedWallet();
if (this.wallet) {
this.tick();
let restore = false;
if (
this.variablesService.after_sync_request.hasOwnProperty(
this.walletID
)
) {
restore = this.variablesService.after_sync_request[this.walletID];
}
// if this is was restore wallet and it was selected on moment when sync completed
this.getRecentTransfers();
this.variablesService.after_sync_request[this.walletID] = false;
}
});
let after_sync_request = false;
if (this.variablesService.after_sync_request.hasOwnProperty(this.walletID)) {
after_sync_request = this.variablesService.after_sync_request[this.walletID];
}
if (after_sync_request && !this.variablesService.sync_started) {
// if user click on the wallet at the first time after restore.
if (
!this.variablesService.sync_started &&
restore &&
this.walletID === (data && data.wallet_id)
) {
this.wallet = this.variablesService.getNotLoadedWallet();
if (this.wallet) {
this.tick();
}
// if this is was restore wallet and it was selected on moment when sync completed
this.getRecentTransfers();
this.variablesService.after_sync_request[this.walletID] = false;
}
});
let after_sync_request = false;
if (
this.variablesService.after_sync_request.hasOwnProperty(this.walletID)
) {
after_sync_request = this.variablesService.after_sync_request[
this.walletID
];
}
if (after_sync_request && !this.variablesService.sync_started) {
// if user click on the wallet at the first time after restore.
this.getRecentTransfers();
}
if (this.variablesService.stop_paginate.hasOwnProperty(this.walletID)) {
this.stop_paginate = this.variablesService.stop_paginate[this.walletID];
@ -171,23 +195,27 @@ export class WalletComponent implements OnInit, OnDestroy {
this.copyAnimation = false;
this.mining = this.variablesService.currentWallet.exclude_mining_txs;
if (this.variablesService.wallets.length === 1) {
this.walletID = +params['id'];
this.variablesService.setCurrentWallet(this.walletID);
}
});
this.subRouting2 = this.router.events.subscribe(val => {
this.subRouting2 = this.router.events.subscribe((val) => {
if (val instanceof RoutesRecognized) {
this.activeTab = val.urlAfterRedirects.replace('?sidenav=true', '').split('/').pop();
this.activeTab = val.urlAfterRedirects
.replace('?sidenav=true', '')
.split('/')
.pop();
if (val.state.root.firstChild && val.state.root.firstChild.firstChild) {
for (let i = 0; i < this.tabs.length; i++) {
this.tabs[i].active = (this.tabs[i].link === '/' + val.state.root.firstChild.firstChild.url[0].path);
this.tabs[i].active =
this.tabs[i].link ===
'/' + val.state.root.firstChild.firstChild.url[0].path;
}
}
}
});
this.queryRouting = this.route.queryParams.subscribe(params => {
this.queryRouting = this.route.queryParams.subscribe((params) => {
if (params.send) {
this.tabs.forEach((tab, index) => {
if (tab.link === '/send') {
@ -199,33 +227,54 @@ export class WalletComponent implements OnInit, OnDestroy {
if (this.variablesService.currentWallet.alias.hasOwnProperty('name')) {
this.variablesService.currentWallet.wakeAlias = false;
}
this.aliasSubscription = this.variablesService.getAliasChangedEvent.subscribe(() => {
if (this.variablesService.currentWallet.alias.hasOwnProperty('name')) {
this.variablesService.currentWallet.wakeAlias = false;
this.aliasSubscription = this.variablesService.getAliasChangedEvent.subscribe(
() => {
if (this.variablesService.currentWallet.alias.hasOwnProperty('name')) {
this.variablesService.currentWallet.wakeAlias = false;
}
}
});
);
this.updateWalletStatus();
}
resetPaginationValues() {
this.ngZone.run(() => {
const total_history_item = this.variablesService.currentWallet.total_history_item;
const total_history_item = this.variablesService.currentWallet
.total_history_item;
const count = this.variablesService.count;
this.variablesService.currentWallet.totalPages = Math.ceil( total_history_item / count);
this.variablesService.currentWallet.totalPages = Math.ceil(
total_history_item / count
);
this.variablesService.currentWallet.exclude_mining_txs = this.mining;
this.variablesService.currentWallet.currentPage = 1;
if (!this.variablesService.currentWallet.totalPages) {
this.variablesService.currentWallet.totalPages = 1;
}
this.variablesService.currentWallet.totalPages > this.variablesService.maxPages
? this.variablesService.currentWallet.pages = new Array(5).fill(1).map((value, index) => value + index)
: this.variablesService.currentWallet.pages = new Array(this.variablesService.currentWallet.totalPages).fill(1).map((value, index) => value + index);
})
this.variablesService.currentWallet.totalPages >
this.variablesService.maxPages
? (this.variablesService.currentWallet.pages = new Array(5)
.fill(1)
.map((value, index) => value + index))
: (this.variablesService.currentWallet.pages = new Array(
this.variablesService.currentWallet.totalPages
)
.fill(1)
.map((value, index) => value + index));
});
}
changeTab(index) {
if (((this.tabs[index].link === '/send' || this.tabs[index].link === '/contracts' || this.tabs[index].link === '/staking') && (this.variablesService.daemon_state !== 2 || !this.variablesService.currentWallet.loaded))
|| ((this.tabs[index].link === '/send' || this.tabs[index].link === '/contracts') && this.variablesService.currentWallet.is_watch_only && this.variablesService.currentWallet.is_auditable)) {
if (
((this.tabs[index].link === '/send' ||
this.tabs[index].link === '/contracts' ||
this.tabs[index].link === '/staking') &&
(this.variablesService.daemon_state !== 2 ||
!this.variablesService.currentWallet.loaded)) ||
((this.tabs[index].link === '/send' ||
this.tabs[index].link === '/contracts') &&
this.variablesService.currentWallet.is_watch_only &&
this.variablesService.currentWallet.is_auditable)
) {
return;
}
this.tabs.forEach((tab) => {
@ -254,11 +303,23 @@ export class WalletComponent implements OnInit, OnDestroy {
this.balanceTooltip = document.createElement('div');
const available = document.createElement('span');
available.setAttribute('class', 'available');
available.innerHTML = this.translate.instant('WALLET.AVAILABLE_BALANCE', { available: this.intToMoneyPipe.transform(this.variablesService.currentWallet.unlocked_balance), currency: this.variablesService.defaultCurrency });
available.innerHTML = this.translate.instant('WALLET.AVAILABLE_BALANCE', {
available: this.intToMoneyPipe.transform(
this.variablesService.currentWallet.unlocked_balance
),
currency: this.variablesService.defaultCurrency,
});
this.balanceTooltip.appendChild(available);
const locked = document.createElement('span');
locked.setAttribute('class', 'locked');
locked.innerHTML = this.translate.instant('WALLET.LOCKED_BALANCE', { locked: this.intToMoneyPipe.transform(this.variablesService.currentWallet.balance.minus(this.variablesService.currentWallet.unlocked_balance)), currency: this.variablesService.defaultCurrency });
locked.innerHTML = this.translate.instant('WALLET.LOCKED_BALANCE', {
locked: this.intToMoneyPipe.transform(
this.variablesService.currentWallet.balance.minus(
this.variablesService.currentWallet.unlocked_balance
)
),
currency: this.variablesService.defaultCurrency,
});
this.balanceTooltip.appendChild(locked);
const link = document.createElement('span');
link.setAttribute('class', 'link');
@ -280,7 +341,10 @@ export class WalletComponent implements OnInit, OnDestroy {
public setPage(pageNumber: number) {
// this is will allow pagination for wallets that was open from existed wallets'
if (this.variablesService.currentWallet.open_from_exist && !this.variablesService.currentWallet.updated) {
if (
this.variablesService.currentWallet.open_from_exist &&
!this.variablesService.currentWallet.updated
) {
this.variablesService.get_recent_transfers = false;
this.variablesService.currentWallet.updated = true;
}
@ -302,7 +366,7 @@ export class WalletComponent implements OnInit, OnDestroy {
if (!value) {
this.paginationStore.setPage(1, 0, this.walletID); // add back page for the first page
} else {
const pages = value.filter(item => item.walletID === this.walletID);
const pages = value.filter((item) => item.walletID === this.walletID);
if (!pages.length) {
this.paginationStore.setPage(1, 0, this.walletID); // add back page for the first page
}
@ -322,27 +386,44 @@ export class WalletComponent implements OnInit, OnDestroy {
}, 1000);
}
getRecentTransfers () {
getRecentTransfers() {
const offset = this.pagination.getOffset(this.walletID);
const value = this.paginationStore.value;
const pages = value ? value.filter(item => item.walletID === this.walletID) : [];
const pages = value
? value.filter((item) => item.walletID === this.walletID)
: [];
this.backend.getRecentTransfers(
this.walletID,
offset,
this.variablesService.count, this.variablesService.currentWallet.exclude_mining_txs, (status, data) => {
const isForward = this.paginationStore.isForward(pages, this.variablesService.currentWallet.currentPage);
this.variablesService.count,
this.variablesService.currentWallet.exclude_mining_txs,
(status, data) => {
const isForward = this.paginationStore.isForward(
pages,
this.variablesService.currentWallet.currentPage
);
if (this.mining && isForward && pages && pages.length === 1) {
this.variablesService.currentWallet.currentPage = 1; // set init page after navigation back
}
const history = (data && data.history);
this.variablesService.stop_paginate[this.walletID] = history && history.length < this.variablesService.count || !history;
const history = data && data.history;
this.variablesService.stop_paginate[this.walletID] =
(history && history.length < this.variablesService.count) || !history;
this.stop_paginate = this.variablesService.stop_paginate[this.walletID];
if (!this.variablesService.stop_paginate[this.walletID]) {
const page = this.variablesService.currentWallet.currentPage + 1;
if (isForward && this.mining && history && history.length === this.variablesService.count) {
this.paginationStore.setPage(page, data.last_item_index, this.walletID); // add back page for current page
if (
isForward &&
this.mining &&
history &&
history.length === this.variablesService.count
) {
this.paginationStore.setPage(
page,
data.last_item_index,
this.walletID
); // add back page for current page
}
}
@ -351,13 +432,18 @@ export class WalletComponent implements OnInit, OnDestroy {
this.ngZone.run(() => {
this.variablesService.get_recent_transfers = false;
if (this.variablesService.after_sync_request.hasOwnProperty(this.walletID)) {
if (
this.variablesService.after_sync_request.hasOwnProperty(
this.walletID
)
) {
// this is will complete get_recent_transfers request
// this will switch of
this.variablesService.after_sync_request[this.walletID] = false;
}
});
});
}
);
}
ngOnDestroy() {
@ -372,12 +458,28 @@ export class WalletComponent implements OnInit, OnDestroy {
}
updateWalletStatus() {
this.backend.eventSubscribe('wallet_sync_progress', (data) => {
const wallet_id = data.wallet_id;
if (wallet_id === this.walletID) {
this.ngZone.run(() => {
this.walletLoaded = false;
});
}
});
this.backend.eventSubscribe('update_wallet_status', (data) => {
const wallet_state = data.wallet_state;
this.walletLoaded = false;
if (wallet_state === 2) {
this.walletLoaded = true;
}
const wallet_id = data.wallet_id;
this.ngZone.run(() => {
if (wallet_state === 2 && wallet_id === this.walletID) {
this.walletLoaded =
this.variablesService.getWallet(this.walletID) !== null &&
this.variablesService.getWallet(this.walletID).loaded
? true
: false;
} else {
this.walletLoaded = false;
}
});
});
}
}

View file

@ -33,6 +33,9 @@ $themes: (
accountBackgroundColor: rgba(43, 54, 68, 0.5),
accountHoverBackgroundColor: rgba(58, 69, 85, 0.5),
accountMainTextColor: #e0e0e0,
securedSeed: #e0e0e0,
seedItemText: #e0e0e0,
seedItemBackgroundColor: #18202a,
accountOptionalTextColor: #556576,
accountIndicatorTextColor: #111921,
accountSwitchBackgroundColor: #000000,
@ -90,6 +93,9 @@ $themes: (
accountBackgroundColor: rgba(37, 40, 43, 0.5),
accountHoverBackgroundColor: rgba(58, 62, 66, 0.5),
accountMainTextColor: #e0e0e0,
securedSeed: #e0e0e0,
seedItemText: #e0e0e0,
seedItemBackgroundColor: #292d31,
accountOptionalTextColor: #565c62,
accountIndicatorTextColor: #1a1a1a,
accountSwitchBackgroundColor: #000000,
@ -147,6 +153,9 @@ $themes: (
accountBackgroundColor: rgba(30, 136, 229, 1),
accountHoverBackgroundColor: rgba(240, 240, 240, 0.5),
accountMainTextColor: #ffffff,
securedSeed: #a0a5ab,
seedItemText: #43454b,
seedItemBackgroundColor: #e6e6e6,
accountOptionalTextColor: #91baf1,
accountIndicatorTextColor: #43454b,
accountSwitchBackgroundColor: #ffffff,

View file

@ -0,0 +1,258 @@
.form-details {
margin-top: 1.8rem;
.input-block {
&:first-child {
width: 50%;
}
}
.wallet-buttons {
display: flex;
align-items: center;
justify-content: space-between;
button {
margin: 2.9rem 0;
width: 100%;
max-width: 15rem;
}
}
}
.form-seed {
label {
@include themify($themes) {
color: themed(optionalTextColor);
}
font-size: 1.3rem;
line-height: 2.4rem;
}
.form-content {
@include themify($themes) {
border: 2px solid themed(transparentButtonBorderColor);
}
display: flex;
justify-content: center;
padding: 3rem;
width: 100%;
}
.text-coral {
@include themify($themes) {
color: themed(blueTextColor);
}
text-decoration: none;
}
.seed-phrase-form {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
max-width: 38rem;
width: 100%;
.input-block,
button {
width: 100%;
}
.error-message {
margin-top: 1rem;
@include themify($themes) {
color: themed(orangeTextColor);
}
}
.secured-seed {
@include themify($themes) {
color: themed(securedSeed);
}
font-size: 1.2rem;
line-height: 2.4rem;
text-decoration: none;
display: flex;
align-items: center;
cursor: pointer;
.icon {
margin-right: 1.2rem;
}
}
button {
display: flex;
justify-content: center;
align-items: center;
margin-top: 3rem;
margin-bottom: 2rem;
.icon {
margin-right: 1.2rem;
}
}
}
}
.seed-phrase {
display: flex;
flex-direction: column;
width: 100%;
background-color: transparent !important;
&-title {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
@include themify($themes) {
color: themed(optionalTextColor);
}
.right-part {
display: inline-flex;
align-items: center;
.icon {
cursor: pointer;
width: 1.7rem;
height: 1.7rem;
&.copy {
@include themify($themes) {
background-color: themed(blueTextColor);
}
margin-right: 1.2rem;
mask: url(~src/assets/icons/copy.svg) no-repeat center;
&:hover {
opacity: 0.75;
}
}
&.copied {
@include themify($themes) {
background-color: themed(blueTextColor);
}
margin-right: 1.2rem;
mask: url(~src/assets/icons/complete-testwallet.svg) no-repeat center;
}
&.secured,
&.unsecured {
margin-left: 1.2rem;
}
}
span {
font-size: 1.3rem;
line-height: 2.4rem;
display: inline-flex;
align-items: center;
.icon {
margin-left: 1.2rem;
}
}
}
}
&-content {
@include themify($themes) {
border-top: 2px solid themed(transparentButtonBorderColor);
border-bottom: 2px solid themed(transparentButtonBorderColor);
}
padding: 1rem 0 1rem;
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
margin-bottom: 1rem;
.item {
@include themify($themes) {
color: themed(seedItemText);
}
display: flex;
align-items: center;
padding: 0 2rem;
width: calc(100% / 7);
min-height: 35px;
font-size: 1.3rem;
&.dark {
@include themify($themes) {
background-color: themed(seedItemBackgroundColor);
}
}
}
}
&-footer {
text-align: center;
.title {
@include themify($themes) {
color: themed(seedItemText);
}
font-size: 1.3rem;
line-height: 2.4rem;
}
}
}
.icon {
display: inline-flex;
width: 1.6rem;
height: 1.6rem;
&.secured {
@include themify($themes) {
background-color: themed(greenTextColor);
}
mask: url(~src/assets/icons/secured.svg) no-repeat center;
}
&.info {
@include themify($themes) {
background-color: themed(blueTextColor);
}
mask: url(~src/assets/icons/info.svg) no-repeat center;
}
&.unsecured {
@include themify($themes) {
background-color: themed(orangeTextColor);
}
mask: url(~src/assets/icons/unsecured.svg) no-repeat center;
}
&.safety {
@include themify($themes) {
background-color: themed(alternativeTextColor);
}
mask: url(~src/assets/icons/safety.svg) no-repeat center;
}
}
.wrap-buttons {
display: flex;
.seed-phrase-button {
margin: 2.8rem 0;
width: 25%;
min-width: 1.5rem;
}
.copy-button {
margin: 2.8rem 1rem;
width: 25%;
min-width: 1.5rem;
}
}

View file

@ -11,6 +11,7 @@
@import 'assets/scss/layout/status';
@import 'assets/scss/layout/wallet';
@import 'assets/scss/layout/contact';
@import 'assets/scss/layout/seed-phrase';
// MODULES
@import 'assets/scss/modules/head';