diff --git a/src/Blockcore.Explorer/ClientApp/src/app/app.module.ts b/src/Blockcore.Explorer/ClientApp/src/app/app.module.ts
index d22920e..4f4660e 100644
--- a/src/Blockcore.Explorer/ClientApp/src/app/app.module.ts
+++ b/src/Blockcore.Explorer/ClientApp/src/app/app.module.ts
@@ -43,6 +43,9 @@ import { ContractListComponent } from './explorer/contract-list/contract-list.co
import { ContractListByTypeComponent } from './explorer/contract-listbytype/contract-listbytype.component';
import { ContractNonFungibleTokenComponent } from './explorer/contract-nonfungibletoken/contract-nonfungibletoken.component';
+import { AngorProjects } from './explorer/angor-projects/angor-projects.component';
+import { AngorProject } from './explorer/angor-project/angor-project.component';
+
const routes: Routes = [
{
path: '', component: HomeComponent, pathMatch: 'full', resolve: {
@@ -159,6 +162,17 @@ const routes: Routes = [
chain: LoadingResolverService
}
},
+
+ {
+ path: ':chain/explorer/angor-projects', component: AngorProjects, resolve: {
+ chain: LoadingResolverService
+ }
+ },
+ {
+ path: ':chain/explorer/angor-project/:projectid', component: AngorProject, resolve: {
+ chain: LoadingResolverService
+ }
+ },
];
@NgModule({
@@ -201,7 +215,9 @@ const routes: Routes = [
ContractStandardTokenComponent,
ContractListComponent,
ContractListByTypeComponent,
- ContractNonFungibleTokenComponent
+ ContractNonFungibleTokenComponent,
+ AngorProjects,
+ AngorProject,
],
imports: [
BrowserModule,
diff --git a/src/Blockcore.Explorer/ClientApp/src/app/explorer/angor-project/angor-project.component.html b/src/Blockcore.Explorer/ClientApp/src/app/explorer/angor-project/angor-project.component.html
new file mode 100644
index 0000000..02ac2e6
--- /dev/null
+++ b/src/Blockcore.Explorer/ClientApp/src/app/explorer/angor-project/angor-project.component.html
@@ -0,0 +1,45 @@
+
+
+
+
Project Details
+
Loading project details...
+
+
+ Error: {{error.message}}
+ {{error | json}}
+
+
+
+
Project Identifier: {{ project.projectIdentifier }}
+
Founder Key: {{ project.founderKey }}
+
Nostr Pub Key: {{ project.nostrPubKey }}
+
Created On Block: {{ project.createdOnBlock }}
+
+ Transaction id:
+ {{ project.trxId | slice:0:30 }}
+
+
Total Investments Count: {{ project.totalInvestmentsCount }}
+
+
Investments
+
+
+
diff --git a/src/Blockcore.Explorer/ClientApp/src/app/explorer/angor-project/angor-project.component.ts b/src/Blockcore.Explorer/ClientApp/src/app/explorer/angor-project/angor-project.component.ts
new file mode 100644
index 0000000..cfff63c
--- /dev/null
+++ b/src/Blockcore.Explorer/ClientApp/src/app/explorer/angor-project/angor-project.component.ts
@@ -0,0 +1,180 @@
+import { Component, HostBinding, OnInit, OnDestroy, HostListener } from '@angular/core';
+import { ActivatedRoute, Route, Router } from '@angular/router';
+import { ApiComponent } from 'src/app/api/api.component';
+import { ApiService, HttpError } from 'src/app/services/api.service';
+import { SetupService } from 'src/app/services/setup.service';
+import { ScrollEvent } from 'src/app/shared/scroll.directive';
+
+@Component({
+ selector: 'angor-project-component',
+ templateUrl: './angor-project.component.html'
+})
+export class AngorProject implements OnInit, OnDestroy {
+ @HostBinding('class.content-centered-top') hostClass = true;
+
+ info: any;
+ node: any;
+ blockchain: any;
+ network: any;
+ configuration: any;
+ consensus: any;
+ peers: any;
+ blocks: any;
+ project: any;
+ investments: any
+
+ timerInfo: any;
+ timerBlocks: any;
+ timerTransactions: any;
+ contractType: any;
+ balance: any;
+ detailsVisible = false;
+ lastBlockHeight: number;
+ subscription: any;
+ limit = 10;
+ loading = false;
+ count = 0;
+ total: any;
+ link: string;
+ error: any;
+ errorTransactions: any;
+ navPath: any;
+
+ constructor(
+ private api: ApiService,
+ private router: Router,
+ public setup: SetupService,
+ private activatedRoute: ActivatedRoute) {
+
+ this.activatedRoute.paramMap.subscribe(async params => {
+
+
+ const id: any = params.get('projectid');
+ this.project = null;
+
+ try {
+
+ this.navPath = "../../";
+
+ await this.getProject('/api/query/Angor/projects/' + id);
+
+ await this.getInvestments('/api/query/Angor/projects/' + id + '/investments??offset=&limit=' + this.limit);
+
+ } catch (err) {
+ if (err.message[0] === '{') {
+ this.errorTransactions = JSON.parse(err.message);
+ } else {
+ this.errorTransactions = err;
+ }
+ }
+ });
+ }
+
+ async ngOnInit() {
+
+ }
+
+ toggleDetails() {
+ this.detailsVisible = !this.detailsVisible;
+ }
+
+ ngOnDestroy(): void {
+
+ }
+
+ async getProject(url) {
+ // If no URL, then likely reached the end.
+ if (!url) {
+ return;
+ }
+
+ const baseUrl = this.api.baseUrl.replace('/api', '');
+ // For the block scrolling (using link http header), we must manually set full URL.
+ const response = await this.api.request(baseUrl + url);
+
+ // When the offset is not set (0), we should reverse the order of items.
+ const list = await response.json();
+
+ if (response.status !== 200) {
+ if (list && list.status) {
+ throw new HttpError(list.status, url, JSON.stringify(list));
+ } else {
+ throw new HttpError(response.status, url, response.statusText);
+ }
+ }
+
+ this.project = list;
+ }
+
+ async getInvestments(url) {
+ // If no URL, then likely reached the end.
+ if (!url) {
+ return;
+ }
+
+ const baseUrl = this.api.baseUrl.replace('/api', '');
+ // For the block scrolling (using link http header), we must manually set full URL.
+ const response = await this.api.request(baseUrl + url);
+
+ // When the offset is not set (0), we should reverse the order of items.
+ const list = await response.json();
+
+ if (response.status !== 200) {
+ if (list && list.status) {
+ throw new HttpError(list.status, url, JSON.stringify(list));
+ } else {
+ throw new HttpError(response.status, url, response.statusText);
+ }
+ }
+
+ list.sort((b, a) => {
+ if (a.createdOnBlock === b.createdOnBlock) {
+ return 0;
+ }
+ if (a.createdOnBlock < b.createdOnBlock) {
+ return -1;
+ }
+ if (a.createdOnBlock > b.createdOnBlock) {
+ return 1;
+ }
+ });
+
+
+ this.total = response.headers.get('Pagination-Total');
+ const linkHeader = response.headers.get('Link');
+ const links = this.api.parseLinkHeader(linkHeader);
+
+ // This will be set to undefined/null when no more next links is available.
+ this.link = links['previous'];
+
+ if (!this.investments) {
+ this.investments = [];
+ }
+
+ this.investments = [...this.investments, ...list];
+ this.count++;
+ }
+
+ async onScroll(event: ScrollEvent) {
+ console.log('scroll occurred', event);
+
+ if (event.isReachingBottom) {
+ console.log(`the user is reaching the bottom`);
+
+ this.loading = true;
+
+ setTimeout(async () => {
+ await this.getInvestments(this.link);
+ this.loading = false;
+ });
+
+ }
+ if (event.isReachingTop) {
+ console.log(`the user is reaching the top`);
+ }
+ if (event.isWindowEvent) {
+ console.log(`This event is fired on Window not on an element.`);
+ }
+ }
+}
+
diff --git a/src/Blockcore.Explorer/ClientApp/src/app/explorer/angor-projects/angor-projects.component.html b/src/Blockcore.Explorer/ClientApp/src/app/explorer/angor-projects/angor-projects.component.html
new file mode 100644
index 0000000..8d9d276
--- /dev/null
+++ b/src/Blockcore.Explorer/ClientApp/src/app/explorer/angor-projects/angor-projects.component.html
@@ -0,0 +1,34 @@
+
+
+
+
Projects
+
Loading projects...
+
+
+ Error: {{error.message}}
+ {{error | json}}
+
+
+
+
diff --git a/src/Blockcore.Explorer/ClientApp/src/app/explorer/angor-projects/angor-projects.component.ts b/src/Blockcore.Explorer/ClientApp/src/app/explorer/angor-projects/angor-projects.component.ts
new file mode 100644
index 0000000..4e06e21
--- /dev/null
+++ b/src/Blockcore.Explorer/ClientApp/src/app/explorer/angor-projects/angor-projects.component.ts
@@ -0,0 +1,155 @@
+import { Component, HostBinding, OnInit, OnDestroy, HostListener } from '@angular/core';
+import { ActivatedRoute, Route, Router } from '@angular/router';
+import { ApiComponent } from 'src/app/api/api.component';
+import { ApiService, HttpError } from 'src/app/services/api.service';
+import { SetupService } from 'src/app/services/setup.service';
+import { ScrollEvent } from 'src/app/shared/scroll.directive';
+
+@Component({
+ selector: 'angor-projects-component',
+ templateUrl: './angor-projects.component.html'
+})
+export class AngorProjects implements OnInit, OnDestroy {
+ @HostBinding('class.content-centered-top') hostClass = true;
+
+ info: any;
+ node: any;
+ blockchain: any;
+ network: any;
+ configuration: any;
+ consensus: any;
+ peers: any;
+ blocks: any;
+ projects: any;
+
+ timerInfo: any;
+ timerBlocks: any;
+ timerTransactions: any;
+ contractType: any;
+ balance: any;
+ detailsVisible = false;
+ lastBlockHeight: number;
+ subscription: any;
+ limit = 10;
+ loading = false;
+ count = 0;
+ total: any;
+ link: string;
+ error: any;
+ errorTransactions: any;
+ navPath: any;
+
+ constructor(
+ private api: ApiService,
+ private router: Router,
+ public setup: SetupService,
+ private activatedRoute: ActivatedRoute) {
+
+ this.activatedRoute.paramMap.subscribe(async params => {
+
+
+ this.projects = null;
+
+ try {
+
+ this.navPath = "../../";
+
+ await this.getProjects('/api/query/Angor/projects/?offset=&limit=' + this.limit);
+
+ } catch (err) {
+ if (err.message[0] === '{') {
+ this.errorTransactions = JSON.parse(err.message);
+ } else {
+ this.errorTransactions = err;
+ }
+ }
+ });
+ }
+
+ async ngOnInit() {
+
+ }
+
+ toggleDetails() {
+ this.detailsVisible = !this.detailsVisible;
+ }
+
+ ngOnDestroy(): void {
+
+ }
+
+
+ async getProjects(url) {
+ // If no URL, then likely reached the end.
+ if (!url) {
+ return;
+ }
+
+ const baseUrl = this.api.baseUrl.replace('/api', '');
+ // For the block scrolling (using link http header), we must manually set full URL.
+ const response = await this.api.request(baseUrl + url);
+
+ // When the offset is not set (0), we should reverse the order of items.
+ const list = await response.json();
+
+ if (response.status !== 200) {
+ if (list && list.status) {
+ throw new HttpError(list.status, url, JSON.stringify(list));
+ } else {
+ throw new HttpError(response.status, url, response.statusText);
+ }
+ }
+
+ list.sort((b, a) => {
+ if (a.createdOnBlock === b.createdOnBlock) {
+ return 0;
+ }
+ if (a.createdOnBlock < b.createdOnBlock) {
+ return -1;
+ }
+ if (a.createdOnBlock > b.createdOnBlock) {
+ return 1;
+ }
+ });
+
+
+ this.total = response.headers.get('Pagination-Total');
+ const linkHeader = response.headers.get('Link');
+ const links = this.api.parseLinkHeader(linkHeader);
+
+ // This will be set to undefined/null when no more next links is available.
+ this.link = links['previous'];
+
+
+
+ if (!this.projects) {
+ this.projects = [];
+ }
+
+ this.projects = [...this.projects, ...list];
+ this.count++;
+ }
+
+ async onScroll(event: ScrollEvent) {
+ console.log('scroll occurred', event);
+
+ if (event.isReachingBottom) {
+ console.log(`the user is reaching the bottom`);
+
+ this.loading = true;
+
+ setTimeout(async () => {
+ await this.getProjects(this.link);
+ this.loading = false;
+ });
+
+ }
+ if (event.isReachingTop) {
+ console.log(`the user is reaching the top`);
+ }
+ if (event.isWindowEvent) {
+ console.log(`This event is fired on Window not on an element.`);
+ }
+ }
+}
+
diff --git a/src/Blockcore.Explorer/ClientApp/src/app/nav-menu/nav-menu.component.html b/src/Blockcore.Explorer/ClientApp/src/app/nav-menu/nav-menu.component.html
index e732d8a..b64d1ec 100644
--- a/src/Blockcore.Explorer/ClientApp/src/app/nav-menu/nav-menu.component.html
+++ b/src/Blockcore.Explorer/ClientApp/src/app/nav-menu/nav-menu.component.html
@@ -13,28 +13,31 @@
diff --git a/src/Blockcore.Explorer/ClientApp/src/app/services/setup.service.ts b/src/Blockcore.Explorer/ClientApp/src/app/services/setup.service.ts
index 6568533..ea339fb 100644
--- a/src/Blockcore.Explorer/ClientApp/src/app/services/setup.service.ts
+++ b/src/Blockcore.Explorer/ClientApp/src/app/services/setup.service.ts
@@ -111,6 +111,10 @@ export class SetupService {
return null;
}
+ isBitcoin() {
+ return this.Chain.Symbol.includes('BTC');
+ }
+
featureEnabled(feature) {
// If feature is something and it is explicit set to false, hide.
if (feature === false) {
diff --git a/src/Blockcore.Explorer/Properties/launchSettings.json b/src/Blockcore.Explorer/Properties/launchSettings.json
index 3c7c144..00d19e4 100644
--- a/src/Blockcore.Explorer/Properties/launchSettings.json
+++ b/src/Blockcore.Explorer/Properties/launchSettings.json
@@ -17,6 +17,15 @@
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
+ "TBTC": {
+ "commandName": "Project",
+ "commandLineArgs": "--chain=TBTC",
+ "launchBrowser": true,
+ "applicationUrl": "http://localhost:9911",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
"CITY": {
"commandName": "Project",
"commandLineArgs": "--chain=CITY",