From 8e419443a4534c1a13e08c2295db60ec9421f618 Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Fri, 22 Nov 2024 06:24:49 +0000 Subject: [PATCH] BNS domains that resolve to addresses now searchable --- angular.json | 5 ++++- .../search-bar/search-bar.component.ts | 4 ++-- src/app/pages/account/account.component.ts | 21 +++++++++++++++---- src/app/services/api/api.service.ts | 11 ++++++++++ src/app/services/search/search.service.ts | 10 +++++++-- 5 files changed, 42 insertions(+), 9 deletions(-) diff --git a/angular.json b/angular.json index 6f5cf1c..c2d22a3 100644 --- a/angular.json +++ b/angular.json @@ -151,5 +151,8 @@ } } }, - "defaultProject": "yellow-spyglass-client" + "defaultProject": "yellow-spyglass-client", + "cli": { + "analytics": false + } } diff --git a/src/app/navigation/search-bar/search-bar.component.ts b/src/app/navigation/search-bar/search-bar.component.ts index 2c93ce5..4f09450 100644 --- a/src/app/navigation/search-bar/search-bar.component.ts +++ b/src/app/navigation/search-bar/search-bar.component.ts @@ -60,7 +60,7 @@ export let APP_SEARCH_BAR_ID = 0; export class SearchBarComponent implements OnInit, AfterViewInit, AfterViewChecked { @ViewChild(MatMenuTrigger) trigger: MatMenuTrigger; - @Input() placeholder: string = 'Search by Address, Block or Alias'; + @Input() placeholder: string = 'Search by Address, Block, BNS, or Alias'; @Input() toolbarTitle: string; /** This input is used to turn off the autofocus logic. Home page search does not need autofocus, but app-bar search does. */ @@ -127,7 +127,7 @@ export class SearchBarComponent implements OnInit, AfterViewInit, AfterViewCheck return this.invalidSearch.emit(); } - if (this._searchService.isValidAddress(value) || this._searchService.isValidBlock(value)) { + if (this._searchService.isValidAddress(value) || this._searchService.isValidBlock(value) || this._searchService.isValidBNSDomain(value)) { return this._emitSearch(value, controlKey); } diff --git a/src/app/pages/account/account.component.ts b/src/app/pages/account/account.component.ts index 47a6f7f..3d447c1 100644 --- a/src/app/pages/account/account.component.ts +++ b/src/app/pages/account/account.component.ts @@ -9,7 +9,7 @@ import { OnlineRepsService } from '@app/services/online-reps/online-reps.service import { NavigationEnd, Router } from '@angular/router'; import { Subscription } from 'rxjs'; import { AliasService } from '@app/services/alias/alias.service'; -import { APP_NAV_ITEMS, hashNavItem } from '../../navigation/nav-items'; +import { APP_NAV_ITEMS, accountNavItem, hashNavItem } from '../../navigation/nav-items'; import { environment } from '../../../environments/environment'; import { DelegatorsTabService } from '@app/pages/account/tabs/delegators/delegators-tab.service'; import { InsightsTabService } from '@app/pages/account/tabs/insights/insights-tab.service'; @@ -64,12 +64,12 @@ export class AccountComponent implements OnDestroy { private readonly _insightsTabService: InsightsTabService, private readonly _delegatorsTabService: DelegatorsTabService ) { - this.routeListener = this._router.events.subscribe((route) => { + this.routeListener = this._router.events.subscribe(async (route) => { if (route instanceof NavigationEnd) { const splitUrl = this._router.url.replace('/history', '').split('/'); const path = splitUrl[splitUrl.length - 1]; const address = path.substring(0, 64); - this._searchAccount(address); + await this._searchAccount(address); } }); @@ -111,13 +111,26 @@ export class AccountComponent implements OnDestroy { void this._router.navigate([`/${hashNavItem.route}/${hash}`], { replaceUrl: true }); } + /** Call this method whenever someone has enters a BNS domain, and it is resolved to a Banano address. */ + private _redirectToAccountPage(account: string): void { + void this._router.navigate([`/${accountNavItem.route}/${account}`], { replaceUrl: true }); + } + /** Given a ban address, searches for account. */ - private _searchAccount(address): void { + private async _searchAccount(address): Promise { if (!address) { return; } if (!address.startsWith('ban_')) { + const parts = address.split("."); + if (parts.length === 2) { + //search in api + const domain = await this.apiService.fetchBNSDomain(parts[0], parts[1]); + if (domain.domain?.resolved_address) { + return this._redirectToAccountPage(domain.domain?.resolved_address); + } + } this._redirectToHashPage(address); } diff --git a/src/app/services/api/api.service.ts b/src/app/services/api/api.service.ts index ef96eab..ada9718 100644 --- a/src/app/services/api/api.service.ts +++ b/src/app/services/api/api.service.ts @@ -204,6 +204,17 @@ export class ApiService { .toPromise(); } + /** Fetch/query BNS domain. */ + async fetchBNSDomain(domain_name: string, tld: string): Promise { + await this._hasPingedApi(); + return this._http + .post(`${this.httpApi}/v1/account/bns`, { + domain_name, + tld, + }) + .toPromise(); + } + /** Fetches monitored representatives stats. */ async fetchMonitoredRepresentatives(): Promise { await this._hasPingedApi(); diff --git a/src/app/services/search/search.service.ts b/src/app/services/search/search.service.ts index e81980a..b89f500 100644 --- a/src/app/services/search/search.service.ts +++ b/src/app/services/search/search.service.ts @@ -12,14 +12,14 @@ export class SearchService { constructor(router: Router) { this.searchEvents().subscribe((data: { search: string; openInNewWindow: boolean }) => { if (data.openInNewWindow) { - if (data.search.startsWith('ban_')) { + if (data.search.startsWith('ban_') || this.isValidBNSDomain(data.search)) { const origin = window.location.origin; window.open(`${origin}/${APP_NAV_ITEMS.account.route}/${data.search}`, '_blank'); } else { window.open(`${origin}/${APP_NAV_ITEMS.hash.route}/${data.search}`, '_blank'); } } else { - if (data.search.startsWith('ban_')) { + if (data.search.startsWith('ban_') || this.isValidBNSDomain(data.search)) { void router.navigate([`${APP_NAV_ITEMS.account.route}/${data.search}`]); } else { void router.navigate([`${APP_NAV_ITEMS.hash.route}/${data.search}`]); @@ -47,4 +47,10 @@ export class SearchService { isValidBlock(block: string): boolean { return block && block.length === 64; } + + isValidBNSDomain(bns: string): boolean { + const parts = bns.split("."); + //later, can also check for illegal characters once that is more settled + return parts.length === 2 && parts[0].length <= 32; + } }