From a97252efd940044840f6b555e493e449f1f638f6 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Tue, 10 Jan 2023 21:16:15 +0800 Subject: [PATCH 01/19] feat(menu): reorder menu items accroding to UX --- src/app/features/home/home.page.html | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/app/features/home/home.page.html b/src/app/features/home/home.page.html index 7ed66e0d0..8be7216d8 100644 --- a/src/app/features/home/home.page.html +++ b/src/app/features/home/home.page.html @@ -8,28 +8,28 @@ - - {{ t('profile') }} + + {{ t('wallets.wallets') }} - - {{ t('contacts') }} + + {{ t('invitation.invitation') }} - - {{ t('wallets.wallets') }} + + {{ t('settings') }} - - {{ t('settings') }} + + {{ t('contacts') }} - - {{ t('invitation.invitation') }} + + {{ t('profile') }} From 973732ef723549ad08e0aa09cc24329a56e2ade5 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Tue, 10 Jan 2023 21:16:59 +0800 Subject: [PATCH 02/19] feat(menu): rename "Invitation" to "Invite friends" --- src/app/features/home/home.page.html | 12 ++++++++++-- src/app/features/home/home.page.scss | 14 ++++++++++++++ src/assets/i18n/en-us.json | 2 ++ src/assets/i18n/zh-tw.json | 2 ++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/app/features/home/home.page.html b/src/app/features/home/home.page.html index 8be7216d8..baa1de9f8 100644 --- a/src/app/features/home/home.page.html +++ b/src/app/features/home/home.page.html @@ -13,9 +13,17 @@ - - {{ t('invitation.invitation') }} + + {{ t('invitation.inviteFriends') }} +

+ {{ t('invitation.inviteFriendsBenefit') }} +

diff --git a/src/app/features/home/home.page.scss b/src/app/features/home/home.page.scss index 92ea433a5..b9ebe8d41 100644 --- a/src/app/features/home/home.page.scss +++ b/src/app/features/home/home.page.scss @@ -19,6 +19,20 @@ mat-sidenav-content { flex-direction: column; } +mat-list-item { + .title { + padding-left: 16px; + } + + .subtitle { + margin-top: 4px; + opacity: 0.7; + font-size: 12px; + padding-left: 16px; + white-space: pre-line; + } +} + .tab-action-button-icon { height: 24px; width: 24px; diff --git a/src/assets/i18n/en-us.json b/src/assets/i18n/en-us.json index 42481779f..138cc5049 100644 --- a/src/assets/i18n/en-us.json +++ b/src/assets/i18n/en-us.json @@ -336,6 +336,8 @@ }, "invitation": { "invitation": "Invitation", + "inviteFriends": "Invite friends", + "inviteFriendsBenefit": "Get 5 credits for each accepted invitation", "shareInvitationCode": "Share invitation code", "shareToGetRewarded": "Share to get rewarded", "useMyReferralCodeToSignUpForCaptureAppPassVerificationAndWeBothGetNumPointsReward": "Use my referral code {{referralCode}} to sign up for Capture App, pass verification and we both get NUM Points reward!" diff --git a/src/assets/i18n/zh-tw.json b/src/assets/i18n/zh-tw.json index 93349c621..07765b3a3 100644 --- a/src/assets/i18n/zh-tw.json +++ b/src/assets/i18n/zh-tw.json @@ -336,6 +336,8 @@ }, "invitation": { "invitation": "邀請", + "inviteFriends": "邀請好友", + "inviteFriendsBenefit": "每個接受的邀請可獲得 5 個積分", "shareInvitationCode": "分享邀請碼", "shareToGetRewarded": "分享以獲得獎勵", "useMyReferralCodeToSignUpForCaptureAppPassVerificationAndWeBothGetNumPointsReward": "透過我的推薦碼 {{referralCode}} 在 Capture App 註冊,一起獲得 NUM Points!" From a76d2d7ab3dfc583001db562d7e438732455edb9 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Tue, 10 Jan 2023 16:00:00 +0800 Subject: [PATCH 03/19] feat(menu): rename "Contacts" to "Friends" --- src/app/features/contacts/contacts.page.html | 2 +- src/app/features/home/home.page.html | 2 +- src/assets/i18n/en-us.json | 2 +- src/assets/i18n/zh-tw.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/features/contacts/contacts.page.html b/src/app/features/contacts/contacts.page.html index 68ddfe709..d474de92f 100644 --- a/src/app/features/contacts/contacts.page.html +++ b/src/app/features/contacts/contacts.page.html @@ -2,7 +2,7 @@ - {{ t('contacts') }} + {{ t('friends') }} diff --git a/src/app/features/home/home.page.html b/src/app/features/home/home.page.html index baa1de9f8..d06a8382b 100644 --- a/src/app/features/home/home.page.html +++ b/src/app/features/home/home.page.html @@ -32,7 +32,7 @@ - {{ t('contacts') }} + {{ t('friends') }} diff --git a/src/assets/i18n/en-us.json b/src/assets/i18n/en-us.json index 138cc5049..9df3f6eab 100644 --- a/src/assets/i18n/en-us.json +++ b/src/assets/i18n/en-us.json @@ -90,7 +90,7 @@ "editUsername": "Edit Username", "forgotPassword": "Forgot Password", "resetPassword": "Reset Password", - "contacts": "Contacts", + "friends": "Friends", "takePicture": "Take Picture", "recordVideo": "Record Video", "videoLimitation": "Video Limitation", diff --git a/src/assets/i18n/zh-tw.json b/src/assets/i18n/zh-tw.json index 07765b3a3..1bbe87038 100644 --- a/src/assets/i18n/zh-tw.json +++ b/src/assets/i18n/zh-tw.json @@ -90,7 +90,7 @@ "editUsername": "修改使用者名稱", "forgotPassword": "忘記密碼", "resetPassword": "重設密碼", - "contacts": "聯絡人", + "friends": "好友", "takePicture": "拍攝照片", "recordVideo": "錄製影片", "videoLimitation": "影片錄製限制", From 3fb7bf483500a62e5f54dbe9b2e69e2c6df9b193 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Tue, 10 Jan 2023 18:45:27 +0800 Subject: [PATCH 04/19] feat(menu): remove unused menu items --- src/app/features/home/home.page.html | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/app/features/home/home.page.html b/src/app/features/home/home.page.html index d06a8382b..9895231b9 100644 --- a/src/app/features/home/home.page.html +++ b/src/app/features/home/home.page.html @@ -35,21 +35,6 @@ {{ t('friends') }} - - - {{ t('profile') }} - - - - - {{ t('privacy') }} - - - - - {{ t('about') }} - -
From 6c6d81d3d815718fa9daa71c9c56cc883be1b96b Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Thu, 19 Jan 2023 18:15:36 +0800 Subject: [PATCH 05/19] feat(menu): add Data policy menu item + page --- src/app/app-routing.module.ts | 7 +++ .../data-policy/data-policy-routing.module.ts | 17 +++++++ .../data-policy/data-policy.module.ts | 12 +++++ .../data-policy/data-policy.page.html | 27 +++++++++++ .../data-policy/data-policy.page.scss | 39 ++++++++++++++++ .../data-policy/data-policy.page.spec.ts | 26 +++++++++++ .../features/data-policy/data-policy.page.ts | 45 +++++++++++++++++++ src/app/features/home/home.page.html | 5 +++ src/assets/i18n/en-us.json | 1 + src/assets/i18n/zh-tw.json | 1 + 10 files changed, 180 insertions(+) create mode 100644 src/app/features/data-policy/data-policy-routing.module.ts create mode 100644 src/app/features/data-policy/data-policy.module.ts create mode 100644 src/app/features/data-policy/data-policy.page.html create mode 100644 src/app/features/data-policy/data-policy.page.scss create mode 100644 src/app/features/data-policy/data-policy.page.spec.ts create mode 100644 src/app/features/data-policy/data-policy.page.ts diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index a9e9495ab..459856be1 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -82,6 +82,13 @@ const routes: Routes = [ m => m.InvitationPageModule ), }, + { + path: 'data-policy', + loadChildren: () => + import('./features/data-policy/data-policy.module').then( + m => m.DataPolicyPageModule + ), + }, ]; @NgModule({ imports: [ diff --git a/src/app/features/data-policy/data-policy-routing.module.ts b/src/app/features/data-policy/data-policy-routing.module.ts new file mode 100644 index 000000000..33bd162b5 --- /dev/null +++ b/src/app/features/data-policy/data-policy-routing.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { DataPolicyPage } from './data-policy.page'; + +const routes: Routes = [ + { + path: '', + component: DataPolicyPage, + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class DataPolicyPageRoutingModule {} diff --git a/src/app/features/data-policy/data-policy.module.ts b/src/app/features/data-policy/data-policy.module.ts new file mode 100644 index 000000000..f8440e0c3 --- /dev/null +++ b/src/app/features/data-policy/data-policy.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; + +import { DataPolicyPageRoutingModule } from './data-policy-routing.module'; + +import { SharedModule } from '../../shared/shared.module'; +import { DataPolicyPage } from './data-policy.page'; + +@NgModule({ + imports: [SharedModule, DataPolicyPageRoutingModule], + declarations: [DataPolicyPage], +}) +export class DataPolicyPageModule {} diff --git a/src/app/features/data-policy/data-policy.page.html b/src/app/features/data-policy/data-policy.page.html new file mode 100644 index 000000000..79b948a2b --- /dev/null +++ b/src/app/features/data-policy/data-policy.page.html @@ -0,0 +1,27 @@ + + + + {{ 'dataPolicy' | transloco }} + +
+ {{ 'message.networkNotConnected' | transloco }} +
+
+ + + + + diff --git a/src/app/features/data-policy/data-policy.page.scss b/src/app/features/data-policy/data-policy.page.scss new file mode 100644 index 000000000..044c5df02 --- /dev/null +++ b/src/app/features/data-policy/data-policy.page.scss @@ -0,0 +1,39 @@ +mat-toolbar { + span { + padding-right: 40px; + font-style: normal; + font-weight: 500; + font-size: 16px; + line-height: 21px; + text-align: center; + color: white; + } + + .capture-rebranded-button { + margin: 0 4px; + background: #ffffff40 !important; /* stylelint-disable-line declaration-no-important */ + color: white !important; /* stylelint-disable-line declaration-no-important */ + backdrop-filter: blur(4px); + box-shadow: none; + } +} + +.no-network-text { + font-size: 18px; + margin: auto; +} + +.bubble-iframe { + background-color: black; + width: 100vw; + height: 100vh; + border: 0; +} + +ion-spinner { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + scale: 1.5; +} diff --git a/src/app/features/data-policy/data-policy.page.spec.ts b/src/app/features/data-policy/data-policy.page.spec.ts new file mode 100644 index 000000000..ba45e8616 --- /dev/null +++ b/src/app/features/data-policy/data-policy.page.spec.ts @@ -0,0 +1,26 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { SharedTestingModule } from '../../shared/shared-testing.module'; + +import { DataPolicyPage } from './data-policy.page'; + +describe('DataPolicyPage', () => { + let component: DataPolicyPage; + let fixture: ComponentFixture; + + beforeEach( + waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [DataPolicyPage], + imports: [SharedTestingModule], + }).compileComponents(); + + fixture = TestBed.createComponent(DataPolicyPage); + component = fixture.componentInstance; + fixture.detectChanges(); + }) + ); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/data-policy/data-policy.page.ts b/src/app/features/data-policy/data-policy.page.ts new file mode 100644 index 000000000..386baa86d --- /dev/null +++ b/src/app/features/data-policy/data-policy.page.ts @@ -0,0 +1,45 @@ +import { Component } from '@angular/core'; +import { NavController } from '@ionic/angular'; +import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; +import { BehaviorSubject, fromEvent } from 'rxjs'; +import { tap } from 'rxjs/operators'; +import { BUBBLE_IFRAME_URL } from '../../shared/dia-backend/secret'; +import { NetworkService } from '../../shared/network/network.service'; + +@UntilDestroy() +@Component({ + selector: 'app-data-policy', + templateUrl: './data-policy.page.html', + styleUrls: ['./data-policy.page.scss'], +}) +export class DataPolicyPage { + readonly networkConnected$ = this.networkService.connected$; + readonly dataPolicyUrl = `${BUBBLE_IFRAME_URL}/data_policy`; + readonly iframeLoaded$ = new BehaviorSubject(false); + + constructor( + private readonly networkService: NetworkService, + private readonly navController: NavController + ) {} + + ionViewDidEnter() { + this.processIframeEvents(); + } + + processIframeEvents() { + fromEvent(window, 'message') + .pipe( + tap(event => { + const postMessageEvent = event as MessageEvent; + if (postMessageEvent.data === 'iframe-on-load') { + this.iframeLoaded$.next(true); + } + if (postMessageEvent.data === 'iframeBackButtonClicked') { + this.navController.back(); + } + }), + untilDestroyed(this) + ) + .subscribe(); + } +} diff --git a/src/app/features/home/home.page.html b/src/app/features/home/home.page.html index 9895231b9..23ae053d3 100644 --- a/src/app/features/home/home.page.html +++ b/src/app/features/home/home.page.html @@ -35,6 +35,11 @@ {{ t('friends') }} + + + {{ t('dataPolicy') }} + + diff --git a/src/assets/i18n/en-us.json b/src/assets/i18n/en-us.json index 9df3f6eab..7c7c0f0b9 100644 --- a/src/assets/i18n/en-us.json +++ b/src/assets/i18n/en-us.json @@ -91,6 +91,7 @@ "forgotPassword": "Forgot Password", "resetPassword": "Reset Password", "friends": "Friends", + "dataPolicy": "Data policy", "takePicture": "Take Picture", "recordVideo": "Record Video", "videoLimitation": "Video Limitation", diff --git a/src/assets/i18n/zh-tw.json b/src/assets/i18n/zh-tw.json index 1bbe87038..acc0b5f84 100644 --- a/src/assets/i18n/zh-tw.json +++ b/src/assets/i18n/zh-tw.json @@ -91,6 +91,7 @@ "forgotPassword": "忘記密碼", "resetPassword": "重設密碼", "friends": "好友", + "dataPolicy": "數據政策", "takePicture": "拍攝照片", "recordVideo": "錄製影片", "videoLimitation": "影片錄製限制", From 45109709260b491fed315db67b6f402c5ef08824 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Thu, 19 Jan 2023 18:16:34 +0800 Subject: [PATCH 06/19] feat(menu): add Terms of use menu item + page --- src/app/app-routing.module.ts | 7 +++ src/app/features/home/home.page.html | 5 +++ .../terms-of-use-routing.module.ts | 17 +++++++ .../terms-of-use/terms-of-use.module.ts | 12 +++++ .../terms-of-use/terms-of-use.page.html | 27 +++++++++++ .../terms-of-use/terms-of-use.page.scss | 39 ++++++++++++++++ .../terms-of-use/terms-of-use.page.spec.ts | 26 +++++++++++ .../terms-of-use/terms-of-use.page.ts | 45 +++++++++++++++++++ src/assets/i18n/en-us.json | 1 + src/assets/i18n/zh-tw.json | 1 + 10 files changed, 180 insertions(+) create mode 100644 src/app/features/terms-of-use/terms-of-use-routing.module.ts create mode 100644 src/app/features/terms-of-use/terms-of-use.module.ts create mode 100644 src/app/features/terms-of-use/terms-of-use.page.html create mode 100644 src/app/features/terms-of-use/terms-of-use.page.scss create mode 100644 src/app/features/terms-of-use/terms-of-use.page.spec.ts create mode 100644 src/app/features/terms-of-use/terms-of-use.page.ts diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 459856be1..b40f8bd48 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -89,6 +89,13 @@ const routes: Routes = [ m => m.DataPolicyPageModule ), }, + { + path: 'terms-of-use', + loadChildren: () => + import('./features/terms-of-use/terms-of-use.module').then( + m => m.TermsOfUsePageModule + ), + }, ]; @NgModule({ imports: [ diff --git a/src/app/features/home/home.page.html b/src/app/features/home/home.page.html index 23ae053d3..10ebd0c98 100644 --- a/src/app/features/home/home.page.html +++ b/src/app/features/home/home.page.html @@ -40,6 +40,11 @@ {{ t('dataPolicy') }} + + + {{ t('termsOfUse') }} + + diff --git a/src/app/features/terms-of-use/terms-of-use-routing.module.ts b/src/app/features/terms-of-use/terms-of-use-routing.module.ts new file mode 100644 index 000000000..23f6ba3ae --- /dev/null +++ b/src/app/features/terms-of-use/terms-of-use-routing.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { TermsOfUsePage } from './terms-of-use.page'; + +const routes: Routes = [ + { + path: '', + component: TermsOfUsePage, + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class TermsOfUsePageRoutingModule {} diff --git a/src/app/features/terms-of-use/terms-of-use.module.ts b/src/app/features/terms-of-use/terms-of-use.module.ts new file mode 100644 index 000000000..5b053ed88 --- /dev/null +++ b/src/app/features/terms-of-use/terms-of-use.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; + +import { TermsOfUsePageRoutingModule } from './terms-of-use-routing.module'; + +import { SharedModule } from '../../shared/shared.module'; +import { TermsOfUsePage } from './terms-of-use.page'; + +@NgModule({ + imports: [SharedModule, TermsOfUsePageRoutingModule], + declarations: [TermsOfUsePage], +}) +export class TermsOfUsePageModule {} diff --git a/src/app/features/terms-of-use/terms-of-use.page.html b/src/app/features/terms-of-use/terms-of-use.page.html new file mode 100644 index 000000000..b062c5a41 --- /dev/null +++ b/src/app/features/terms-of-use/terms-of-use.page.html @@ -0,0 +1,27 @@ + + + + {{ 'termsOfUse' | transloco }} + +
+ {{ 'message.networkNotConnected' | transloco }} +
+
+ + + + + diff --git a/src/app/features/terms-of-use/terms-of-use.page.scss b/src/app/features/terms-of-use/terms-of-use.page.scss new file mode 100644 index 000000000..044c5df02 --- /dev/null +++ b/src/app/features/terms-of-use/terms-of-use.page.scss @@ -0,0 +1,39 @@ +mat-toolbar { + span { + padding-right: 40px; + font-style: normal; + font-weight: 500; + font-size: 16px; + line-height: 21px; + text-align: center; + color: white; + } + + .capture-rebranded-button { + margin: 0 4px; + background: #ffffff40 !important; /* stylelint-disable-line declaration-no-important */ + color: white !important; /* stylelint-disable-line declaration-no-important */ + backdrop-filter: blur(4px); + box-shadow: none; + } +} + +.no-network-text { + font-size: 18px; + margin: auto; +} + +.bubble-iframe { + background-color: black; + width: 100vw; + height: 100vh; + border: 0; +} + +ion-spinner { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + scale: 1.5; +} diff --git a/src/app/features/terms-of-use/terms-of-use.page.spec.ts b/src/app/features/terms-of-use/terms-of-use.page.spec.ts new file mode 100644 index 000000000..f7c9ada81 --- /dev/null +++ b/src/app/features/terms-of-use/terms-of-use.page.spec.ts @@ -0,0 +1,26 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { SharedTestingModule } from '../../shared/shared-testing.module'; + +import { TermsOfUsePage } from './terms-of-use.page'; + +describe('TermsOfUsePage', () => { + let component: TermsOfUsePage; + let fixture: ComponentFixture; + + beforeEach( + waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [TermsOfUsePage], + imports: [SharedTestingModule], + }).compileComponents(); + + fixture = TestBed.createComponent(TermsOfUsePage); + component = fixture.componentInstance; + fixture.detectChanges(); + }) + ); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/features/terms-of-use/terms-of-use.page.ts b/src/app/features/terms-of-use/terms-of-use.page.ts new file mode 100644 index 000000000..b4734ce11 --- /dev/null +++ b/src/app/features/terms-of-use/terms-of-use.page.ts @@ -0,0 +1,45 @@ +import { Component } from '@angular/core'; +import { NavController } from '@ionic/angular'; +import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; +import { BehaviorSubject, fromEvent } from 'rxjs'; +import { tap } from 'rxjs/operators'; +import { BUBBLE_IFRAME_URL } from '../../shared/dia-backend/secret'; +import { NetworkService } from '../../shared/network/network.service'; + +@UntilDestroy() +@Component({ + selector: 'app-terms-of-use', + templateUrl: './terms-of-use.page.html', + styleUrls: ['./terms-of-use.page.scss'], +}) +export class TermsOfUsePage { + readonly networkConnected$ = this.networkService.connected$; + readonly termsOfUseUrl = `${BUBBLE_IFRAME_URL}/terms_of_use`; + readonly iframeLoaded$ = new BehaviorSubject(false); + + constructor( + private readonly networkService: NetworkService, + private readonly navController: NavController + ) {} + + ionViewDidEnter() { + this.processIframeEvents(); + } + + processIframeEvents() { + fromEvent(window, 'message') + .pipe( + tap(event => { + const postMessageEvent = event as MessageEvent; + if (postMessageEvent.data === 'iframe-on-load') { + this.iframeLoaded$.next(true); + } + if (postMessageEvent.data === 'iframeBackButtonClicked') { + this.navController.back(); + } + }), + untilDestroyed(this) + ) + .subscribe(); + } +} diff --git a/src/assets/i18n/en-us.json b/src/assets/i18n/en-us.json index 7c7c0f0b9..28d0dac86 100644 --- a/src/assets/i18n/en-us.json +++ b/src/assets/i18n/en-us.json @@ -92,6 +92,7 @@ "resetPassword": "Reset Password", "friends": "Friends", "dataPolicy": "Data policy", + "termsOfUse": "Terms of use", "takePicture": "Take Picture", "recordVideo": "Record Video", "videoLimitation": "Video Limitation", diff --git a/src/assets/i18n/zh-tw.json b/src/assets/i18n/zh-tw.json index acc0b5f84..2882d309d 100644 --- a/src/assets/i18n/zh-tw.json +++ b/src/assets/i18n/zh-tw.json @@ -92,6 +92,7 @@ "resetPassword": "重設密碼", "friends": "好友", "dataPolicy": "數據政策", + "termsOfUse": "使用條款", "takePicture": "拍攝照片", "recordVideo": "錄製影片", "videoLimitation": "影片錄製限制", From 119d330d681e4df384e02a42a19d402b80567167 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Thu, 19 Jan 2023 18:18:30 +0800 Subject: [PATCH 07/19] feat(menu): add logout button --- src/app/features/home/home.page.html | 5 +++++ src/app/features/home/home.page.scss | 4 ++++ src/app/features/home/home.page.ts | 33 +++++++++++++++++++++++++++- src/assets/i18n/en-us.json | 2 +- 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/app/features/home/home.page.html b/src/app/features/home/home.page.html index 10ebd0c98..162d697c2 100644 --- a/src/app/features/home/home.page.html +++ b/src/app/features/home/home.page.html @@ -45,6 +45,11 @@ {{ t('termsOfUse') }} + + + {{ t('logout') }} + + diff --git a/src/app/features/home/home.page.scss b/src/app/features/home/home.page.scss index b9ebe8d41..1b3f7296f 100644 --- a/src/app/features/home/home.page.scss +++ b/src/app/features/home/home.page.scss @@ -31,6 +31,10 @@ mat-list-item { padding-left: 16px; white-space: pre-line; } + + .logout { + color: var(--ion-color-primary); + } } .tab-action-button-icon { diff --git a/src/app/features/home/home.page.ts b/src/app/features/home/home.page.ts index 3d208ac5d..45abf4142 100644 --- a/src/app/features/home/home.page.ts +++ b/src/app/features/home/home.page.ts @@ -14,6 +14,7 @@ import { combineLatest, defer, EMPTY, iif, of } from 'rxjs'; import { catchError, concatMap, + concatMapTo, first, map, startWith, @@ -21,9 +22,11 @@ import { tap, } from 'rxjs/operators'; import { AndroidBackButtonService } from '../../shared/android-back-button/android-back-button.service'; +import { BlockingActionService } from '../../shared/blocking-action/blocking-action.service'; import { CameraService } from '../../shared/camera/camera.service'; import { CaptureService, Media } from '../../shared/capture/capture.service'; import { ConfirmAlert } from '../../shared/confirm-alert/confirm-alert.service'; +import { Database } from '../../shared/database/database.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 { DiaBackendService } from '../../shared/dia-backend/service/dia-backend-service.service'; @@ -31,9 +34,12 @@ import { DiaBackendTransactionRepository } from '../../shared/dia-backend/transa import { DiaBackendWalletService } from '../../shared/dia-backend/wallet/dia-backend-wallet.service'; import { ErrorService } from '../../shared/error/error.service'; import { IframeService } from '../../shared/iframe/iframe.service'; +import { MediaStore } from '../../shared/media/media-store/media-store.service'; import { MigrationService } from '../../shared/migration/service/migration.service'; import { OnboardingService } from '../../shared/onboarding/onboarding.service'; +import { PreferenceManager } from '../../shared/preference-manager/preference-manager.service'; import { UserGuideService } from '../../shared/user-guide/user-guide.service'; +import { reloadApp } from '../../utils/miscellaneous'; import { switchTapTo, VOID$ } from '../../utils/rx-operators/rx-operators'; import { getAppDownloadLink } from '../../utils/url'; import { GoProBluetoothService } from '../settings/go-pro/services/go-pro-bluetooth.service'; @@ -89,7 +95,11 @@ export class HomePage { private readonly userGuideService: UserGuideService, private readonly platform: Platform, private readonly iframeService: IframeService, - private readonly androidBackButtonService: AndroidBackButtonService + private readonly androidBackButtonService: AndroidBackButtonService, + private readonly database: Database, + private readonly preferenceManager: PreferenceManager, + private readonly mediaStore: MediaStore, + private readonly blockingActionService: BlockingActionService ) { this.downloadExpiredPostCaptures(); } @@ -370,4 +380,25 @@ export class HomePage { await this.userGuideService.showUserGuidesOnInboxTab(); await this.userGuideService.setHasOpenedInboxTab(true); } + + logout() { + const action$ = defer(() => this.mediaStore.clear()).pipe( + concatMapTo(defer(() => this.database.clear())), + concatMapTo(defer(() => this.preferenceManager.clear())), + concatMapTo(defer(reloadApp)), + catchError((err: unknown) => this.errorService.toastError$(err)) + ); + return defer(() => + this.confirmAlert.present({ + message: this.translocoService.translate('message.confirmLogout'), + }) + ) + .pipe( + concatMap(result => + iif(() => result, this.blockingActionService.run$(action$)) + ), + untilDestroyed(this) + ) + .subscribe(); + } } diff --git a/src/assets/i18n/en-us.json b/src/assets/i18n/en-us.json index 28d0dac86..81a3700fd 100644 --- a/src/assets/i18n/en-us.json +++ b/src/assets/i18n/en-us.json @@ -48,7 +48,7 @@ "signup": "Sign Up", "resendActivationEmail": "Resend Activation Email", "alreadyHaveAnAccount": "Already Have an Account", - "logout": "Log Out", + "logout": "Logout", "moreInformation": "More Information", "mediaId": "Media ID", "media": "Media", From 19092019939dc5384d56f251fe212ddf2a8c4086 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Thu, 19 Jan 2023 18:19:39 +0800 Subject: [PATCH 08/19] fix(menu): make "Get 5 credits ..." text clickable --- src/app/features/home/home.page.html | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/app/features/home/home.page.html b/src/app/features/home/home.page.html index 162d697c2..d69dfdcb7 100644 --- a/src/app/features/home/home.page.html +++ b/src/app/features/home/home.page.html @@ -12,13 +12,8 @@ {{ t('wallets.wallets') }} - - + + {{ t('invitation.inviteFriends') }}

From 67b573ce15662c3406599a01d9508eee320e496b Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Thu, 19 Jan 2023 18:27:03 +0800 Subject: [PATCH 09/19] refactor(settings.page): move device, location prefs from privacy page to settings page --- src/app/features/privacy/privacy.page.html | 19 +------------------ src/app/features/privacy/privacy.page.ts | 20 +------------------- src/app/features/settings/settings.page.html | 16 ++++++++++++++++ src/app/features/settings/settings.page.ts | 19 ++++++++++++++++++- 4 files changed, 36 insertions(+), 38 deletions(-) diff --git a/src/app/features/privacy/privacy.page.html b/src/app/features/privacy/privacy.page.html index 1a87edcc9..51bd4cb4f 100644 --- a/src/app/features/privacy/privacy.page.html +++ b/src/app/features/privacy/privacy.page.html @@ -6,22 +6,5 @@

- - - perm_device_information -
{{ t('collectDeviceInfo') }}
- -
- - my_location -
{{ t('collectLocationInfo') }}
- -
-
+
diff --git a/src/app/features/privacy/privacy.page.ts b/src/app/features/privacy/privacy.page.ts index 46a222844..8ebc58f24 100644 --- a/src/app/features/privacy/privacy.page.ts +++ b/src/app/features/privacy/privacy.page.ts @@ -1,6 +1,5 @@ import { Component } from '@angular/core'; import { UntilDestroy } from '@ngneat/until-destroy'; -import { CapacitorFactsProvider } from '../../shared/collector/facts/capacitor-facts-provider/capacitor-facts-provider.service'; @UntilDestroy({ checkProperties: true }) @Component({ @@ -8,21 +7,4 @@ import { CapacitorFactsProvider } from '../../shared/collector/facts/capacitor-f templateUrl: './privacy.page.html', styleUrls: ['./privacy.page.scss'], }) -export class PrivacyPage { - readonly isDeviceInfoCollectionEnabled$ = - this.capacitorFactsProvider.isDeviceInfoCollectionEnabled$; - readonly isLocationInfoCollectionEnabled$ = - this.capacitorFactsProvider.isGeolocationInfoCollectionEnabled$; - - constructor( - private readonly capacitorFactsProvider: CapacitorFactsProvider - ) {} - - async setDeviceInfoCollection(enable: boolean) { - return this.capacitorFactsProvider.setDeviceInfoCollection(enable); - } - - async setLocationInfoCollection(enable: boolean) { - return this.capacitorFactsProvider.setGeolocationInfoCollection(enable); - } -} +export class PrivacyPage {} diff --git a/src/app/features/settings/settings.page.html b/src/app/features/settings/settings.page.html index c71022506..c2c6bc3ba 100644 --- a/src/app/features/settings/settings.page.html +++ b/src/app/features/settings/settings.page.html @@ -22,6 +22,22 @@ + + {{ t('collectDeviceInfo') }} + + + + {{ t('collectLocationInfo') }} + + (); private readonly requiredClicks = 7; showHiddenOption = false; @@ -44,7 +50,8 @@ export class SettingsPage { private readonly errorService: ErrorService, private readonly translocoService: TranslocoService, private readonly diaBackendAuthService: DiaBackendAuthService, - private readonly confirmAlert: ConfirmAlert + private readonly confirmAlert: ConfirmAlert, + private readonly capacitorFactsProvider: CapacitorFactsProvider ) {} ionViewDidEnter() { @@ -69,6 +76,16 @@ export class SettingsPage { this.hiddenOptionClicks$.next(); } + async setDeviceInfoCollection(event: any) { + const enable = Boolean(event.detail.checked); + return this.capacitorFactsProvider.setDeviceInfoCollection(enable); + } + + async setLocationInfoCollection(event: any) { + const enable = Boolean(event.detail.checked); + return this.capacitorFactsProvider.setGeolocationInfoCollection(enable); + } + /** * // TODO: Integrate Storage Backend delete function after it's ready. * Delete user account from Storage Backend. From fee283b98758eafd9339d8abf623610884ed24a7 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Thu, 19 Jan 2023 18:27:24 +0800 Subject: [PATCH 10/19] refactor(settings.page): move version, contact us items from about page to settings page --- src/app/features/about/about.page.html | 17 +---------------- src/app/features/about/about.page.ts | 7 +------ src/app/features/settings/settings.page.html | 12 ++++++++++++ src/app/features/settings/settings.page.scss | 5 +++++ src/app/features/settings/settings.page.ts | 6 +++++- 5 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/app/features/about/about.page.html b/src/app/features/about/about.page.html index ac00ad057..79dedc4c4 100644 --- a/src/app/features/about/about.page.html +++ b/src/app/features/about/about.page.html @@ -6,20 +6,5 @@
- - - update -
{{ t('version') }}
-
{{ version$ | ngrxPush }}
-
- - help -
{{ t('contactUs') }}
- -
-
+
diff --git a/src/app/features/about/about.page.ts b/src/app/features/about/about.page.ts index b316b05ce..a88ef4ad2 100644 --- a/src/app/features/about/about.page.ts +++ b/src/app/features/about/about.page.ts @@ -1,6 +1,5 @@ import { Component } from '@angular/core'; import { UntilDestroy } from '@ngneat/until-destroy'; -import { VersionService } from '../../shared/version/version.service'; @UntilDestroy({ checkProperties: true }) @Component({ @@ -8,8 +7,4 @@ import { VersionService } from '../../shared/version/version.service'; templateUrl: './about.page.html', styleUrls: ['./about.page.scss'], }) -export class AboutPage { - readonly version$ = this.versionService.version$; - - constructor(private readonly versionService: VersionService) {} -} +export class AboutPage {} diff --git a/src/app/features/settings/settings.page.html b/src/app/features/settings/settings.page.html index c2c6bc3ba..eba5579df 100644 --- a/src/app/features/settings/settings.page.html +++ b/src/app/features/settings/settings.page.html @@ -38,6 +38,18 @@ slot="end" >
+ + {{ t('version') }} + {{ version$ | ngrxPush }} + + + {{ t('contactUs') }} + + + service@numbersprotocol.io + + + (); private readonly requiredClicks = 7; showHiddenOption = false; @@ -51,7 +54,8 @@ export class SettingsPage { private readonly translocoService: TranslocoService, private readonly diaBackendAuthService: DiaBackendAuthService, private readonly confirmAlert: ConfirmAlert, - private readonly capacitorFactsProvider: CapacitorFactsProvider + private readonly capacitorFactsProvider: CapacitorFactsProvider, + private readonly versionService: VersionService ) {} ionViewDidEnter() { From 9dea3e4d5a06b604adcafc2bae317f07da594d41 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Fri, 6 Jan 2023 14:54:45 +0800 Subject: [PATCH 11/19] fix(settings.page): toggle buttons to match figma --- src/app/features/settings/settings.page.html | 1 + src/app/features/settings/settings.page.scss | 24 ++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/app/features/settings/settings.page.html b/src/app/features/settings/settings.page.html index eba5579df..ebcef84bd 100644 --- a/src/app/features/settings/settings.page.html +++ b/src/app/features/settings/settings.page.html @@ -33,6 +33,7 @@ {{ t('collectLocationInfo') }} Date: Fri, 6 Jan 2023 15:04:02 +0800 Subject: [PATCH 12/19] fix(settings.page): add lines to fit figma --- src/app/features/settings/settings.page.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/features/settings/settings.page.html b/src/app/features/settings/settings.page.html index ebcef84bd..2ae3a268d 100644 --- a/src/app/features/settings/settings.page.html +++ b/src/app/features/settings/settings.page.html @@ -6,8 +6,8 @@ - - + + {{ t('languages') }} Date: Thu, 19 Jan 2023 18:28:20 +0800 Subject: [PATCH 13/19] fix: remove country name from language --- src/app/shared/language/transloco/transloco-root.module.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/shared/language/transloco/transloco-root.module.ts b/src/app/shared/language/transloco/transloco-root.module.ts index dd962e183..112085c38 100644 --- a/src/app/shared/language/transloco/transloco-root.module.ts +++ b/src/app/shared/language/transloco/transloco-root.module.ts @@ -12,8 +12,8 @@ import { import { environment } from '../../../../environments/environment'; export const languages: { [key: string]: string } = { - 'en-us': 'English (United State)', - 'zh-tw': '繁體中文(台灣)', + 'en-us': 'English', + 'zh-tw': '繁體中文', }; export const defaultLanguage = From 9f2edc2199bf22204e67c8759ed095c782e50219 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Fri, 6 Jan 2023 15:08:39 +0800 Subject: [PATCH 14/19] fix(translations-en): for settings page, uppercase only first letter --- src/assets/i18n/en-us.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/assets/i18n/en-us.json b/src/assets/i18n/en-us.json index 42481779f..3202771bd 100644 --- a/src/assets/i18n/en-us.json +++ b/src/assets/i18n/en-us.json @@ -26,8 +26,8 @@ "about": "About", "version": "Version", "informationProvider": "Information Provider", - "collectDeviceInfo": "Collect Device Info", - "collectLocationInfo": "Collect Location Info", + "collectDeviceInfo": "Collect device info", + "collectLocationInfo": "Collect location info", "publisher": "Publisher", "username": "Username", "signUp": "Sign Up", @@ -59,7 +59,7 @@ "preview": "Preview", "owner": "Owner", "digitalAsset": "Digital Asset", - "delete": "Delete Account", + "delete": "Delete account", "share": "Share", "saveToLocal": "Save to Local", "copyCertificate": "Copy Certificate", @@ -86,7 +86,7 @@ "restorePhotos": "Restore Captures", "restore": "Restore", "skip": "Skip", - "contactUs": "Contact Us", + "contactUs": "Contact us", "editUsername": "Edit Username", "forgotPassword": "Forgot Password", "resetPassword": "Reset Password", From 1e062d3300258ff5a59ac37a1e00032f5a6ef1e9 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Fri, 6 Jan 2023 15:29:28 +0800 Subject: [PATCH 15/19] fix(settings.page): app bar to fit figma design --- src/app/features/settings/settings.page.html | 9 +++++++-- src/app/features/settings/settings.page.scss | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/app/features/settings/settings.page.html b/src/app/features/settings/settings.page.html index 2ae3a268d..93785f6b2 100644 --- a/src/app/features/settings/settings.page.html +++ b/src/app/features/settings/settings.page.html @@ -1,6 +1,11 @@ - {{ t('settings') }} diff --git a/src/app/features/settings/settings.page.scss b/src/app/features/settings/settings.page.scss index cc021a9de..bbb0e3d52 100644 --- a/src/app/features/settings/settings.page.scss +++ b/src/app/features/settings/settings.page.scss @@ -1,6 +1,20 @@ mat-toolbar { span { padding-right: 40px; + font-style: normal; + font-weight: 500; + font-size: 16px; + line-height: 21px; + text-align: center; + color: white; + } + + .capture-rebranded-button { + margin: 0 4px; + background: #ffffff40 !important; /* stylelint-disable-line declaration-no-important */ + color: white !important; /* stylelint-disable-line declaration-no-important */ + backdrop-filter: blur(4px); + box-shadow: none; } } From 5df39f039405bc8f44f73fd24dec4c7fcc27ae44 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Thu, 19 Jan 2023 18:35:23 +0800 Subject: [PATCH 16/19] feat(settings.page): move email verification to settings page --- .../profile/profile-routing.module.ts | 7 ---- .../email-verification-routing.module.ts | 0 .../email-verification.module.ts | 0 .../email-verification.page.html | 0 .../email-verification.page.scss | 0 .../email-verification.page.spec.ts | 0 .../email-verification.page.ts | 0 .../settings/settings-routing.module.ts | 7 ++++ src/app/features/settings/settings.page.html | 9 +++++ src/app/features/settings/settings.page.ts | 35 +++++++++++++++++-- 10 files changed, 49 insertions(+), 9 deletions(-) rename src/app/features/{profile => settings}/email-verification/email-verification-routing.module.ts (100%) rename src/app/features/{profile => settings}/email-verification/email-verification.module.ts (100%) rename src/app/features/{profile => settings}/email-verification/email-verification.page.html (100%) rename src/app/features/{profile => settings}/email-verification/email-verification.page.scss (100%) rename src/app/features/{profile => settings}/email-verification/email-verification.page.spec.ts (100%) rename src/app/features/{profile => settings}/email-verification/email-verification.page.ts (100%) diff --git a/src/app/features/profile/profile-routing.module.ts b/src/app/features/profile/profile-routing.module.ts index 9ab4ba250..32f8c21ed 100644 --- a/src/app/features/profile/profile-routing.module.ts +++ b/src/app/features/profile/profile-routing.module.ts @@ -14,13 +14,6 @@ const routes: Routes = [ m => m.PhoneVerificationPageModule ), }, - { - path: 'email-verification', - loadChildren: () => - import('./email-verification/email-verification.module').then( - m => m.EmailVerificationPageModule - ), - }, ]; @NgModule({ diff --git a/src/app/features/profile/email-verification/email-verification-routing.module.ts b/src/app/features/settings/email-verification/email-verification-routing.module.ts similarity index 100% rename from src/app/features/profile/email-verification/email-verification-routing.module.ts rename to src/app/features/settings/email-verification/email-verification-routing.module.ts diff --git a/src/app/features/profile/email-verification/email-verification.module.ts b/src/app/features/settings/email-verification/email-verification.module.ts similarity index 100% rename from src/app/features/profile/email-verification/email-verification.module.ts rename to src/app/features/settings/email-verification/email-verification.module.ts diff --git a/src/app/features/profile/email-verification/email-verification.page.html b/src/app/features/settings/email-verification/email-verification.page.html similarity index 100% rename from src/app/features/profile/email-verification/email-verification.page.html rename to src/app/features/settings/email-verification/email-verification.page.html diff --git a/src/app/features/profile/email-verification/email-verification.page.scss b/src/app/features/settings/email-verification/email-verification.page.scss similarity index 100% rename from src/app/features/profile/email-verification/email-verification.page.scss rename to src/app/features/settings/email-verification/email-verification.page.scss diff --git a/src/app/features/profile/email-verification/email-verification.page.spec.ts b/src/app/features/settings/email-verification/email-verification.page.spec.ts similarity index 100% rename from src/app/features/profile/email-verification/email-verification.page.spec.ts rename to src/app/features/settings/email-verification/email-verification.page.spec.ts diff --git a/src/app/features/profile/email-verification/email-verification.page.ts b/src/app/features/settings/email-verification/email-verification.page.ts similarity index 100% rename from src/app/features/profile/email-verification/email-verification.page.ts rename to src/app/features/settings/email-verification/email-verification.page.ts diff --git a/src/app/features/settings/settings-routing.module.ts b/src/app/features/settings/settings-routing.module.ts index 9ed9bdb57..24be9c042 100644 --- a/src/app/features/settings/settings-routing.module.ts +++ b/src/app/features/settings/settings-routing.module.ts @@ -7,6 +7,13 @@ const routes: Routes = [ path: '', component: SettingsPage, }, + { + path: 'email-verification', + loadChildren: () => + import('./email-verification/email-verification.module').then( + m => m.EmailVerificationPageModule + ), + }, { path: 'go-pro', loadChildren: () => diff --git a/src/app/features/settings/settings.page.html b/src/app/features/settings/settings.page.html index 93785f6b2..052a913cf 100644 --- a/src/app/features/settings/settings.page.html +++ b/src/app/features/settings/settings.page.html @@ -71,6 +71,15 @@ User Guide Preferences + + {{ email$ | async }} + + {{ 'delete' | transloco }} diff --git a/src/app/features/settings/settings.page.ts b/src/app/features/settings/settings.page.ts index 7d5b2bdfa..b95e40c96 100644 --- a/src/app/features/settings/settings.page.ts +++ b/src/app/features/settings/settings.page.ts @@ -1,12 +1,16 @@ import { Component } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; import { TranslocoService } from '@ngneat/transloco'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; -import { defer, iif, Subject } from 'rxjs'; +import { defer, EMPTY, iif, Subject } from 'rxjs'; import { catchError, concatMap, concatMapTo, count, + first, + map, + switchMap, take, tap, } from 'rxjs/operators'; @@ -38,6 +42,17 @@ export class SettingsPage { readonly isLocationInfoCollectionEnabled$ = this.capacitorFactsProvider.isGeolocationInfoCollectionEnabled$; + readonly email$ = this.diaBackendAuthService.email$; + readonly emailVerified$ = this.diaBackendAuthService.emailVerified$; + readonly emailVerifiedIcon$ = this.emailVerified$.pipe( + map(verified => + verified ? 'checkmark-done-circle-outline' : 'alert-circle-outline' + ) + ); + readonly emailVerifiedIconColor$ = this.emailVerified$.pipe( + map(verified => (verified ? 'primary' : 'danger')) + ); + readonly version$ = this.versionService.version$; readonly hiddenOptionClicks$ = new Subject(); @@ -55,7 +70,9 @@ export class SettingsPage { private readonly diaBackendAuthService: DiaBackendAuthService, private readonly confirmAlert: ConfirmAlert, private readonly capacitorFactsProvider: CapacitorFactsProvider, - private readonly versionService: VersionService + private readonly versionService: VersionService, + private readonly router: Router, + private readonly route: ActivatedRoute ) {} ionViewDidEnter() { @@ -90,6 +107,20 @@ export class SettingsPage { return this.capacitorFactsProvider.setGeolocationInfoCollection(enable); } + emailVerification() { + this.emailVerified$ + .pipe( + first(), + switchMap(emailVerified => { + if (emailVerified) return EMPTY; + return this.router.navigate(['email-verification'], { + relativeTo: this.route, + }); + }) + ) + .subscribe(); + } + /** * // TODO: Integrate Storage Backend delete function after it's ready. * Delete user account from Storage Backend. From a45473256b5eb5bc6f9f4bffdb5f59303daa2510 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Thu, 19 Jan 2023 19:17:44 +0800 Subject: [PATCH 17/19] feat(settings.page): ask user to backup private key before deletion --- src/app/features/home/home.page.html | 2 +- src/app/features/settings/settings.page.html | 31 +++++++++- src/app/features/settings/settings.page.scss | 28 +++++++++ src/app/features/settings/settings.page.ts | 62 +++++++++++++++----- src/assets/i18n/en-us.json | 6 +- src/assets/i18n/zh-tw.json | 6 +- 6 files changed, 115 insertions(+), 20 deletions(-) diff --git a/src/app/features/home/home.page.html b/src/app/features/home/home.page.html index 7ed66e0d0..cd3b7fbf6 100644 --- a/src/app/features/home/home.page.html +++ b/src/app/features/home/home.page.html @@ -24,7 +24,7 @@
- {{ t('settings') }} + {{ t('settings.settings') }} diff --git a/src/app/features/settings/settings.page.html b/src/app/features/settings/settings.page.html index c71022506..f58c2bf6e 100644 --- a/src/app/features/settings/settings.page.html +++ b/src/app/features/settings/settings.page.html @@ -2,7 +2,7 @@ - {{ t('settings') }} + {{ t('settings.settings') }} @@ -37,8 +37,35 @@ User Guide Preferences - + {{ 'delete' | transloco }} + + + + + +
+ {{ t('settings.pleasePressThePrivateKeyBelowToCopy') }} +
+ + + + {{ privateKeyTruncated$ | async }} + + + + + + {{ t('settings.iHaveCopiedMyPrivateKey') }} + +
+
+
+
diff --git a/src/app/features/settings/settings.page.scss b/src/app/features/settings/settings.page.scss index 3ff7b559d..7a0c19e40 100644 --- a/src/app/features/settings/settings.page.scss +++ b/src/app/features/settings/settings.page.scss @@ -7,3 +7,31 @@ mat-toolbar { ion-select { width: auto; } + +ion-modal#backup-private-key-modal { + margin: 8px; + + --width: fit-content; + --min-width: 250px; + --height: fit-content; + + ion-card { + padding: 8px; + + ion-card-content { + .backup-modal-warning-text { + font-size: 14px; + padding-bottom: 24px; + } + + ion-item { + margin-bottom: 24px; + + ion-label { + display: flex; + justify-content: center; + } + } + } + } +} diff --git a/src/app/features/settings/settings.page.ts b/src/app/features/settings/settings.page.ts index d5f4d0421..fe8825254 100644 --- a/src/app/features/settings/settings.page.ts +++ b/src/app/features/settings/settings.page.ts @@ -1,16 +1,22 @@ -import { Component } from '@angular/core'; +import { Component, ViewChild } from '@angular/core'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { Clipboard } from '@capacitor/clipboard'; +import { IonModal } from '@ionic/angular'; import { TranslocoService } from '@ngneat/transloco'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; -import { defer, iif, Subject } from 'rxjs'; +import { defer, Subject } from 'rxjs'; import { catchError, - concatMap, concatMapTo, count, + first, + map, + switchMap, take, tap, } 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'; @@ -35,6 +41,16 @@ export class SettingsPage { private readonly requiredClicks = 7; showHiddenOption = false; + private readonly privateKey$ = this.webCryptoApiSignatureProvider.privateKey$; + readonly privateKeyTruncated$ = this.privateKey$.pipe( + map(key => { + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + return `${key.slice(0, 6)}******${key.slice(key.length - 6)}`; + }) + ); + + @ViewChild('modal') modal?: IonModal; + constructor( private readonly languageService: LanguageService, private readonly database: Database, @@ -44,7 +60,9 @@ export class SettingsPage { private readonly errorService: ErrorService, private readonly translocoService: TranslocoService, private readonly diaBackendAuthService: DiaBackendAuthService, - private readonly confirmAlert: ConfirmAlert + private readonly confirmAlert: ConfirmAlert, + private readonly webCryptoApiSignatureProvider: WebCryptoApiSignatureProvider, + private readonly snackBar: MatSnackBar ) {} ionViewDidEnter() { @@ -69,6 +87,28 @@ export class SettingsPage { this.hiddenOptionClicks$.next(); } + async confirmDelete() { + const confirmed = await this.confirmAlert.present({ + message: this.translocoService.translate('message.confirmDelete'), + }); + if (!confirmed) return; + this.modal?.present(); + } + + async copyPrivateKeyToClipboard() { + return this.privateKey$ + .pipe( + first(), + switchMap(privateKey => Clipboard.write({ string: privateKey })), + tap(() => { + this.snackBar.open( + this.translocoService.translate('message.copiedToClipboard') + ); + }) + ) + .subscribe(); + } + /** * // TODO: Integrate Storage Backend delete function after it's ready. * Delete user account from Storage Backend. @@ -85,17 +125,9 @@ export class SettingsPage { catchError((err: unknown) => this.errorService.toastError$(err)) ); - return defer(() => - this.confirmAlert.present({ - message: this.translocoService.translate('message.confirmDelete'), - }) - ) - .pipe( - concatMap(result => - iif(() => result, this.blockingActionService.run$(action$)) - ), - untilDestroyed(this) - ) + return this.blockingActionService + .run$(action$) + .pipe(untilDestroyed(this)) .subscribe(); } } diff --git a/src/assets/i18n/en-us.json b/src/assets/i18n/en-us.json index 42481779f..a4da409bf 100644 --- a/src/assets/i18n/en-us.json +++ b/src/assets/i18n/en-us.json @@ -1,7 +1,6 @@ { "capture": "Capture", "profile": "Profile", - "settings": "Settings", "privacy": "Privacy", "informationDetails": "Information Details", "caption": "Caption", @@ -334,6 +333,11 @@ "inAppProductsNotAvailableYetPleaseTryAgainLater": "In App Products are not available yet. Try again later." } }, + "settings": { + "settings": "Settings", + "pleasePressThePrivateKeyBelowToCopy": "Please press the private key below to copy. It is important to keep your private key in a safe place.", + "iHaveCopiedMyPrivateKey": "I have copied my private key" + }, "invitation": { "invitation": "Invitation", "shareInvitationCode": "Share invitation code", diff --git a/src/assets/i18n/zh-tw.json b/src/assets/i18n/zh-tw.json index 93349c621..817230281 100644 --- a/src/assets/i18n/zh-tw.json +++ b/src/assets/i18n/zh-tw.json @@ -1,7 +1,6 @@ { "capture": "Capture", "profile": "個人資料", - "settings": "設定", "privacy": "隱私", "informationDetails": "詳細資訊", "caption": "標題", @@ -334,6 +333,11 @@ "inAppProductsNotAvailableYetPleaseTryAgainLater": "App 內購買目前無法使用,請稍後再試." } }, + "settings": { + "settings": "設定", + "pleasePressThePrivateKeyBelowToCopy": "請點擊下方私鑰複製,並妥善保存您的私鑰,私鑰遺失您將會永久失去該錢包的存取權。", + "iHaveCopiedMyPrivateKey": "我已複製私鑰,並已了解遺失私鑰的風險" + }, "invitation": { "invitation": "邀請", "shareInvitationCode": "分享邀請碼", From 298d01d9953e88c01a7baca510b23d6c960ee417 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Fri, 6 Jan 2023 16:31:10 +0800 Subject: [PATCH 18/19] fix(translations): `Gas Fee` to `Est. Gas Fee` --- src/app/features/wallets/transfer/transfer.page.html | 4 ++-- src/app/features/wallets/transfer/transfer.page.scss | 9 ++++++--- .../order-detail-dialog.component.html | 2 +- src/assets/i18n/en-us.json | 5 +++-- src/assets/i18n/zh-tw.json | 5 +++-- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/app/features/wallets/transfer/transfer.page.html b/src/app/features/wallets/transfer/transfer.page.html index 41391ec00..9c366c74b 100644 --- a/src/app/features/wallets/transfer/transfer.page.html +++ b/src/app/features/wallets/transfer/transfer.page.html @@ -139,7 +139,7 @@
- {{ t('wallets.gasFee') }}: + {{ t('wallets.estimatedGasFee') }}: {{ gasFee > 0 ? (gasFee | number: '1.2-2') : t('wallets.pending') }} @@ -154,7 +154,7 @@

fill="outline" expand="block" (click)="calculateGasFee()" - >{{ t('wallets.calculateGasFee') }}{{ t('wallets.calculateEstimatedGasFee') }} {{ t('payment.confirmPayment') }}

- {{ t('payment.fee') }} + {{ t('payment.estimatedFee') }} {{ orderStatus.fee | number: '1.2-2' }} NUM diff --git a/src/assets/i18n/en-us.json b/src/assets/i18n/en-us.json index 42481779f..cca611ab3 100644 --- a/src/assets/i18n/en-us.json +++ b/src/assets/i18n/en-us.json @@ -258,6 +258,7 @@ "confirmPayment": "Your Order", "price": "Fee", "fee": "Gas", + "estimatedFee": "Est. Gas Fee", "totalCost": "Total Cost" }, "home": { @@ -319,10 +320,10 @@ "moveNumBetweenAssetWallet": "Move NUM between asset wallet", "andIntegrityWallet": "and integrity wallet", "requestSent": "request sent", - "gasFee": "Gas Fee", + "estimatedGasFee": "Est. Gas Fee", "pending": "Pending", "total": "Total", - "calculateGasFee": "Calculate Gas", + "calculateEstimatedGasFee": "Calculate Est. Gas", "buyCredits": { "credits": "Credits", "buyCredits": "Buy Credits", diff --git a/src/assets/i18n/zh-tw.json b/src/assets/i18n/zh-tw.json index 93349c621..b61d7de2e 100644 --- a/src/assets/i18n/zh-tw.json +++ b/src/assets/i18n/zh-tw.json @@ -258,6 +258,7 @@ "confirmPayment": "你的訂單", "price": "費用", "fee": "油費", + "estimatedFee": "預估礦工費", "totalCost": "總額" }, "home": { @@ -319,10 +320,10 @@ "viewOnBscScan": "在 BscScan 上查看", "viewOnExplore": "在 Explore 上查看", "exportIntegrityKey": "匯出完整性錢包", - "gasFee": "油費", + "estimatedGasFee": "預估礦工費", "pending": "待計算", "total": "總額", - "calculateGasFee": "計算油費", + "calculateEstimatedGasFee": "計算預估礦工費", "buyCredits": { "credits": "點數", "buyCredits": "購買點數", From ca11e9b27abd0e5e67c6e6199f8c267deb0f7f72 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Mon, 9 Jan 2023 17:21:29 +0800 Subject: [PATCH 19/19] fix(details.page): prevent collected captures to edit, unpublish --- src/app/features/home/details/details.page.ts | 116 ++++++++++-------- 1 file changed, 67 insertions(+), 49 deletions(-) diff --git a/src/app/features/home/details/details.page.ts b/src/app/features/home/details/details.page.ts index 6fd40480f..e280d273a 100644 --- a/src/app/features/home/details/details.page.ts +++ b/src/app/features/home/details/details.page.ts @@ -184,6 +184,10 @@ export class DetailsPage { ) ); + readonly isCollectedCapture$ = this.type$.pipe( + map(type => type === 'post-capture') + ); + readonly iframeUrl$ = this.activeDetailedCapture$.pipe( distinctUntilChanged(), map(detailedCapture => { @@ -427,55 +431,69 @@ export class DetailsPage { async openOptionsMenuEvenOffline() { this.userGuideService.setHasClickedDetailsPageOptionsMenu(true); - return new Promise(resolve => { - const buttons: ActionSheetButton[] = []; - - buttons.push({ - text: this.translocoService.translate('details.actions.edit'), - handler: () => { - this.handleEditAction(); - resolve(); - }, - }); - - // Temporarely remove Mint & Share button - // buttons.push({ - // text: this.translocoService.translate('details.actions.mintAndShare'), - // handler: () => { - // this.handleMintAndShareAction(); - // resolve(); - // }, - // }); - - buttons.push({ - text: this.translocoService.translate('details.actions.unpublish'), - handler: () => { - this.handleUnpublishAction(); - resolve(); - }, - }); - - buttons.push({ - text: this.translocoService.translate('details.actions.networkActions'), - handler: () => { - this.handleOpenNetworkActions(); - resolve(); - }, - }); - - buttons.push({ - text: this.translocoService.translate('details.actions.remove'), - cssClass: 'details-page-options-menu-remove-button', - handler: () => { - this.handleRemoveAction(); - resolve(); - }, - }); - - this.actionSheetController - .create({ buttons }) - .then(sheet => sheet.present()); - }); + this.isCollectedCapture$ + .pipe( + first(), + map(isCollectedCapture => { + return new Promise(resolve => { + const buttons: ActionSheetButton[] = []; + + if (!isCollectedCapture) { + buttons.push({ + text: this.translocoService.translate('details.actions.edit'), + handler: () => { + this.handleEditAction(); + resolve(); + }, + }); + } + // Temporarely remove Mint & Share button + // buttons.push({ + // text: this.translocoService.translate('details.actions.mintAndShare'), + // handler: () => { + // this.handleMintAndShareAction(); + // resolve(); + // }, + // }); + + if (!isCollectedCapture) { + buttons.push({ + text: this.translocoService.translate( + 'details.actions.unpublish' + ), + handler: () => { + this.handleUnpublishAction(); + resolve(); + }, + }); + } + + buttons.push({ + text: this.translocoService.translate( + 'details.actions.networkActions' + ), + handler: () => { + this.handleOpenNetworkActions(); + resolve(); + }, + }); + + buttons.push({ + text: this.translocoService.translate('details.actions.remove'), + cssClass: 'details-page-options-menu-remove-button', + handler: () => { + this.handleRemoveAction(); + resolve(); + }, + }); + + this.actionSheetController + .create({ buttons }) + .then(sheet => sheet.present()); + }); + }) + ) + .subscribe(); } private handleEditAction() {