diff --git a/src/app/_services/user.service.ts b/src/app/_services/user.service.ts index cf6a044..cddbae3 100644 --- a/src/app/_services/user.service.ts +++ b/src/app/_services/user.service.ts @@ -82,7 +82,7 @@ export class UserService { location: string, locationType: string, oldPhoneNumber: string - ): Promise { + ): Promise { const accountInfo = await this.loadChangesToAccountStructure( name, phoneNumber, @@ -96,53 +96,64 @@ export class UserService { locationType ); const accountKey: string = await User.toKey(address); - this.getAccountDetailsFromMeta(accountKey) - .pipe(first()) - .subscribe( - async (res) => { - const syncableAccount: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap(); - const update: Array = []; - for (const prop of Object.keys(accountInfo)) { - update.push(new ArgPair(prop, accountInfo[prop])); + return new Promise((resolve) => { + let status: boolean = false; + this.getAccountDetailsFromMeta(accountKey) + .pipe(first()) + .subscribe( + async (res) => { + const syncableAccount: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap(); + const update: Array = []; + for (const prop of Object.keys(accountInfo)) { + update.push(new ArgPair(prop, accountInfo[prop])); + } + updateSyncable(update, 'client-branch', syncableAccount); + await personValidation(syncableAccount.m.data); + status = await this.updateMeta(syncableAccount, accountKey, this.headers); + if (status && phoneNumber !== oldPhoneNumber) { + await this.updatePhonePointers(address, oldPhoneNumber, phoneNumber); + } + resolve(status); + }, + async (error) => { + this.loggingService.sendErrorLevelMessage( + 'Cannot find account info in meta service', + this, + { error } + ); + const syncableAccount: Syncable = new Syncable(accountKey, accountInfo); + status = await this.updateMeta(syncableAccount, accountKey, this.headers); + if (status && phoneNumber !== oldPhoneNumber) { + await this.updatePhonePointers(address, oldPhoneNumber, phoneNumber); + } + resolve(status); } - updateSyncable(update, 'client-branch', syncableAccount); - await personValidation(syncableAccount.m.data); - await this.updateMeta(syncableAccount, accountKey, this.headers); - }, - async (error) => { - this.loggingService.sendErrorLevelMessage( - 'Cannot find account info in meta service', - this, - { error } - ); - const syncableAccount: Syncable = new Syncable(accountKey, accountInfo); - await this.updateMeta(syncableAccount, accountKey, this.headers); - } - ); - if (phoneNumber !== oldPhoneNumber) { - const oldPhoneKey: string = await Phone.toKey(oldPhoneNumber); - const newPhoneKey: string = await Phone.toKey(phoneNumber); - const newPhoneData: Syncable = new Syncable(newPhoneKey, strip0x(address)); - await this.updateMeta(newPhoneData, newPhoneKey, this.headers); - const oldPhoneData: Syncable = new Syncable(oldPhoneKey, ''); - await this.updateMeta(oldPhoneData, oldPhoneKey, this.headers); - } - return accountKey; + ); + }); } async updateMeta( syncableAccount: Syncable, accountKey: string, headers: HttpHeaders - ): Promise { + ): Promise { const envelope: Envelope = await this.wrap(syncableAccount, this.signer); const reqBody: string = envelope.toJSON(); - this.httpClient - .put(`${environment.cicMetaUrl}/${accountKey}`, reqBody, { headers }) - .pipe(first()) - .subscribe((res) => { - this.loggingService.sendInfoLevelMessage(`Response: ${res}`); - }); + return new Promise((resolve) => { + this.httpClient + .put(`${environment.cicMetaUrl}/${accountKey}`, reqBody, { headers }) + .pipe(first()) + .subscribe( + (res) => { + this.loggingService.sendInfoLevelMessage(`Response: ${res}`); + resolve(true); + }, + (error) => { + this.loggingService.sendErrorLevelMessage('Metadata update failed!', this, { error }); + resolve(false); + } + ); + }); } getActions(): void { @@ -198,7 +209,7 @@ export class UserService { ); } }); - this.addAccount(data, limit); + this.addAccount(data, limit, false); } }; worker.postMessage({ @@ -211,7 +222,7 @@ export class UserService { 'Web workers are not supported in this environment' ); for (const accountAddress of accountAddresses.slice(offset, offset + limit)) { - await this.getAccountByAddress(accountAddress, limit); + await this.getAccountByAddress(accountAddress, limit, false, false); } } } catch (error) { @@ -223,7 +234,8 @@ export class UserService { async getAccountByAddress( accountAddress: string, limit: number = 100, - history: boolean = false + history: boolean = false, + top: boolean = true ): Promise> { const accountSubject: Subject = new Subject(); this.getAccountDetailsFromMeta(await User.toKey(add0x(accountAddress))) @@ -249,7 +261,7 @@ export class UserService { }); accountInfo.vcard = vCard.parse(atob(accountInfo.vcard)); await vcardValidation(accountInfo.vcard); - this.addAccount(accountInfo, limit); + this.addAccount(accountInfo, limit, top); accountSubject.next(accountInfo); }); return accountSubject.asObservable(); @@ -310,21 +322,34 @@ export class UserService { return this.httpClient.get(`${environment.cicMetaUrl}/genders`); } - addAccount(account: AccountDetails, cacheSize: number): void { + addAccount(account: AccountDetails, cacheSize: number, top: boolean = true): void { const savedIndex = this.accounts.findIndex( (acc) => acc.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0] === account.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0] ); - if (savedIndex === 0) { - return; - } - if (savedIndex > 0) { - this.accounts.splice(savedIndex, 1); - } - this.accounts.unshift(account); - if (this.accounts.length > cacheSize) { - this.accounts.length = Math.min(this.accounts.length, cacheSize); + if (top) { + if (savedIndex === 0) { + return; + } + if (savedIndex > 0) { + this.accounts.splice(savedIndex, 1); + } + this.accounts.unshift(account); + if (this.accounts.length > cacheSize) { + this.accounts.length = Math.min(this.accounts.length, cacheSize); + } + } else { + if ( + this.accounts.length >= cacheSize || + (savedIndex !== -1 && savedIndex === this.accounts.length - 1) + ) { + return; + } + if (savedIndex !== -1 && savedIndex < this.accounts.length - 1) { + this.accounts.splice(savedIndex, 1); + } + this.accounts.push(account); } this.accountsList.next(this.accounts); } @@ -384,4 +409,26 @@ export class UserService { accountInfo.vcard = btoa(vCard.generate(accountInfo.vcard)); return accountInfo; } + + async updatePhonePointers( + address: string, + oldPhoneNumber: string, + newPhoneNumber: string + ): Promise { + const oldPhoneKey: string = await Phone.toKey(oldPhoneNumber); + const newPhoneKey: string = await Phone.toKey(newPhoneNumber); + const newPhoneData: Syncable = new Syncable(newPhoneKey, strip0x(address)); + const newPhoneSetStatus = await this.updateMeta(newPhoneData, newPhoneKey, this.headers); + if (!newPhoneSetStatus) { + const error = `Failed to update new phone number pointer: ${newPhoneNumber}`; + this.loggingService.sendErrorLevelMessage(error, this, { error }); + } else { + const oldPhoneData: Syncable = new Syncable(oldPhoneKey, ''); + const oldPhoneSetStatus = await this.updateMeta(oldPhoneData, oldPhoneKey, this.headers); + if (!oldPhoneSetStatus) { + const error = `Failed to update old phone number pointer: ${oldPhoneNumber}`; + this.loggingService.sendErrorLevelMessage(error, this, { error }); + } + } + } } diff --git a/src/app/_workers/fetch-accounts.worker.ts b/src/app/_workers/fetch-accounts.worker.ts index ed11dec..8f28221 100644 --- a/src/app/_workers/fetch-accounts.worker.ts +++ b/src/app/_workers/fetch-accounts.worker.ts @@ -32,8 +32,9 @@ async function getAccountByAddress( token: string ): Promise { const userKey = await User.toKey(add0x(accountAddress)); - - headers['Authorization'] = 'Bearer ' + token; + if (token) { + headers['Authorization'] = 'Bearer ' + token; + } const response = await fetch(`${metaUrl}/${userKey}`, options) .then((res) => { if (res.ok) { diff --git a/src/app/pages/accounts/account-details/account-details.component.ts b/src/app/pages/accounts/account-details/account-details.component.ts index 85e44e7..dde50bf 100644 --- a/src/app/pages/accounts/account-details/account-details.component.ts +++ b/src/app/pages/accounts/account-details/account-details.component.ts @@ -56,8 +56,8 @@ export class AccountDetailsComponent implements OnInit, AfterViewInit { 'dependencies', 'timestamp', ]; - historyDefaultPageSize: number = 10; - historyPageSizeOptions: Array = [10, 20, 50, 100]; + historyDefaultPageSize: number = 5; + historyPageSizeOptions: Array = [5, 10, 20, 50, 100]; @ViewChild('HistoryTablePaginator', { static: true }) historyTablePaginator: MatPaginator; @ViewChild('HistoryTableSort', { static: true }) historyTableSort: MatSort; @@ -114,22 +114,7 @@ export class AccountDetailsComponent implements OnInit, AfterViewInit { this.transactionService.resetTransactionsList(); await this.blockSyncService.blockSync(this.accountAddress); this.userService.resetAccountsList(); - (await this.userService.getAccountByAddress(this.accountAddress, 100, true)).subscribe( - async (res) => { - if (res !== undefined) { - this.account = res; - this.cdr.detectChanges(); - this.queryLocationAndCategory(this.account); - this.populateAccountsInfoForm(this.account); - this.userService - .getAccountStatus(this.account.vcard?.tel[0].value) - .pipe(first()) - .subscribe((response) => (this.accountStatus = response.status)); - } else { - alert('Account not found!'); - } - } - ); + await this.loadAccount(); this.populateDataTables(); this.loadSearchData(); this.tokenService.load.subscribe(async (status: boolean) => { @@ -185,7 +170,7 @@ export class AccountDetailsComponent implements OnInit, AfterViewInit { if (this.accountInfoForm.invalid || !confirm(`Change user's profile information?`)) { return; } - const accountKey = await this.userService.changeAccountInfo( + const status = await this.userService.changeAccountInfo( this.accountAddress, this.accountInfoFormStub.firstName.value + ', ' + this.accountInfoFormStub.lastName.value, this.accountInfoFormStub.phoneNumber.value, @@ -199,6 +184,9 @@ export class AccountDetailsComponent implements OnInit, AfterViewInit { this.accountInfoFormStub.locationType.value, this.account.vcard?.tel[0].value ); + if (status) { + await this.loadAccount(); + } this.submitted = false; } @@ -374,4 +362,23 @@ export class AccountDetailsComponent implements OnInit, AfterViewInit { .pipe(first()) .subscribe((res) => (this.genders = res)); } + + async loadAccount(): Promise { + (await this.userService.getAccountByAddress(this.accountAddress, 100, true)).subscribe( + async (res) => { + if (res !== undefined) { + this.account = res; + this.cdr.detectChanges(); + this.queryLocationAndCategory(this.account); + this.populateAccountsInfoForm(this.account); + this.userService + .getAccountStatus(this.account.vcard?.tel[0].value) + .pipe(first()) + .subscribe((response) => (this.accountStatus = response.status)); + } else { + alert('Account not found!'); + } + } + ); + } }