From 7d1feb2675a39c51ff6f9bfbeb59a4e5ec5bbfe6 Mon Sep 17 00:00:00 2001 From: dangershony Date: Fri, 29 Dec 2023 19:09:51 +0000 Subject: [PATCH 1/5] allow to fetch a project and also use paging on browse --- src/Angor/Client/Pages/Browse.razor | 79 ++++++++++++++++++--- src/Angor/Shared/Services/IndexerService.cs | 12 ++-- 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/src/Angor/Client/Pages/Browse.razor b/src/Angor/Client/Pages/Browse.razor index e89e7275..e7efd42a 100644 --- a/src/Angor/Client/Pages/Browse.razor +++ b/src/Angor/Client/Pages/Browse.razor @@ -15,21 +15,40 @@
+ + +
+ + +
+ + @if (findInProgress) + { +
+
+
+ } - -
-
- - + + @if (findProject != null) + { +
+
+
@findProject.ProjectIdentifier
+

Nostr ID: @(NostrPublicKey.FromHex(findProject.NostrPubKey).Bech32)

+ +
- -

- + } + +
Search Projects
@if (searchInProgress) { -
+
+
+
} else { @@ -39,7 +58,7 @@ } else { - foreach (var project in projects.OrderByDescending(project => project.CreatedOnBlock)) + foreach (var project in projects.OrderBy(project => project.CreatedOnBlock)) {
@@ -51,6 +70,10 @@ } } } + +
+ +
@@ -59,6 +82,9 @@ NotificationComponent notificationComponent; private string searchQuery; bool searchInProgress = false; + bool findInProgress = false; + + ProjectIndexerData? findProject = null; private List projects = new(); @@ -67,11 +93,42 @@ projects = SessionStorage.GetProjectIndexerData() ?? new(); } + private async Task FindProject() + { + findProject = projects.FirstOrDefault(_ => _.ProjectIdentifier == searchQuery); + + if (findProject != null) + { + return; + } + + findInProgress = true; + + findProject = await _IndexerService.GetProjectByIdAsync(searchQuery); + + if (findProject != null) + { + projects.Add(findProject); + SessionStorage.SetProjectIndexerData(projects); + + _RelayService.LookupProjectsInfoByPubKeys(_ => + { + if (!SessionStorage.IsProjectInStorageById(_.ProjectIdentifier)) + SessionStorage.StoreProjectInfo(_); + }, + OnEndOfStreamAction: () => + { + }, + nostrPubKey: new[] { findProject.NostrPubKey }); + } + + findInProgress = false; + } private async Task SearchProjects() { searchInProgress = true; - var blockchainProjects = await _IndexerService.GetProjectsAsync(); + var blockchainProjects = await _IndexerService.GetProjectsAsync(projects.Count, 20); var projectsNotInList = blockchainProjects .Where(blockchainProject => projects.All(_ => _.ProjectIdentifier != blockchainProject.ProjectIdentifier)) diff --git a/src/Angor/Shared/Services/IndexerService.cs b/src/Angor/Shared/Services/IndexerService.cs index f5327531..72e2a67a 100644 --- a/src/Angor/Shared/Services/IndexerService.cs +++ b/src/Angor/Shared/Services/IndexerService.cs @@ -9,7 +9,7 @@ namespace Angor.Client.Services { public interface IIndexerService { - Task> GetProjectsAsync(); + Task> GetProjectsAsync(int? offset, int limit); Task GetProjectByIdAsync(string projectId); Task> GetInvestmentsAsync(string projectId); Task PublishTransactionAsync(string trxHex); @@ -58,11 +58,10 @@ public IndexerService(INetworkConfiguration networkConfiguration, HttpClient htt _networkService = networkService; } - public async Task> GetProjectsAsync() + public async Task> GetProjectsAsync(int? offset, int limit) { var indexer = _networkService.GetPrimaryIndexer(); - // todo: dan - make this proper paging - var response = await _httpClient.GetAsync($"{indexer.Url}/api/query/Angor/projects?offset=0&limit=50"); + var response = await _httpClient.GetAsync($"{indexer.Url}/api/query/Angor/projects?offset={offset}&limit={limit}"); _networkService.CheckAndHandleError(response); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync>(); @@ -70,6 +69,11 @@ public async Task> GetProjectsAsync() public async Task GetProjectByIdAsync(string projectId) { + if (string.IsNullOrEmpty(projectId)) + { + return null; + } + var indexer = _networkService.GetPrimaryIndexer(); var response = await _httpClient.GetAsync($"{indexer.Url}/api/query/Angor/projects/{projectId}"); _networkService.CheckAndHandleError(response); From 798d0af5d6d5adaee67e4e4af0f9893991d209be Mon Sep 17 00:00:00 2001 From: dangershony Date: Sat, 30 Dec 2023 12:21:59 +0000 Subject: [PATCH 2/5] For now only fetch the last 20 project form the relay or allow the user to search for a project with the project id --- src/Angor/Client/Pages/Browse.razor | 35 +++++++++++++++++------------ 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/Angor/Client/Pages/Browse.razor b/src/Angor/Client/Pages/Browse.razor index e7efd42a..a12aad39 100644 --- a/src/Angor/Client/Pages/Browse.razor +++ b/src/Angor/Client/Pages/Browse.razor @@ -36,12 +36,22 @@
@findProject.ProjectIdentifier

Nostr ID: @(NostrPublicKey.FromHex(findProject.NostrPubKey).Bech32)

- + + @if (SessionStorage.IsProjectInStorageById(findProject.ProjectIdentifier)) + { + + } + else + { +

Project not found in any relay!

+ }
} -
Search Projects
+
+ +
@if (searchInProgress) @@ -54,7 +64,9 @@ { @if (projects.Count == 0) { -

No projects found.

+
+

No projects found.

+
} else { @@ -71,9 +83,7 @@ } } -
- -
+
@@ -108,18 +118,15 @@ if (findProject != null) { - projects.Add(findProject); - SessionStorage.SetProjectIndexerData(projects); - _RelayService.LookupProjectsInfoByPubKeys(_ => { if (!SessionStorage.IsProjectInStorageById(_.ProjectIdentifier)) SessionStorage.StoreProjectInfo(_); }, - OnEndOfStreamAction: () => - { - }, - nostrPubKey: new[] { findProject.NostrPubKey }); + OnEndOfStreamAction: () => + { + }, + nostrPubKey: new[] { findProject.NostrPubKey }); } findInProgress = false; @@ -128,7 +135,7 @@ { searchInProgress = true; - var blockchainProjects = await _IndexerService.GetProjectsAsync(projects.Count, 20); + var blockchainProjects = await _IndexerService.GetProjectsAsync(null, 20); var projectsNotInList = blockchainProjects .Where(blockchainProject => projects.All(_ => _.ProjectIdentifier != blockchainProject.ProjectIdentifier)) From d306b7f9384ac7284e293a7c92e86b301fca9392 Mon Sep 17 00:00:00 2001 From: dangershony Date: Sat, 30 Dec 2023 12:22:22 +0000 Subject: [PATCH 3/5] change text color --- src/Angor/Client/Pages/Browse.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Angor/Client/Pages/Browse.razor b/src/Angor/Client/Pages/Browse.razor index a12aad39..5b07a4c6 100644 --- a/src/Angor/Client/Pages/Browse.razor +++ b/src/Angor/Client/Pages/Browse.razor @@ -43,7 +43,7 @@ } else { -

Project not found in any relay!

+

Project not found in any relay!

} From 224ba089a843f40d0c697bf4bc8ab2f56623b96f Mon Sep 17 00:00:00 2001 From: dangershony Date: Sat, 30 Dec 2023 22:57:00 +0000 Subject: [PATCH 4/5] Adding metadata --- src/Angor/Client/Pages/Browse.razor | 120 ++++++++++++++---- src/Angor/Client/Pages/View.razor | 11 ++ .../Client/Storage/LocalSessionStorage.cs | 17 +++ .../Models/ProjectMetadata.cs | 2 +- src/Angor/Shared/Services/ICacheStorage.cs | 3 + 5 files changed, 130 insertions(+), 23 deletions(-) rename src/Angor/{Client => Shared}/Models/ProjectMetadata.cs (98%) diff --git a/src/Angor/Client/Pages/Browse.razor b/src/Angor/Client/Pages/Browse.razor index 5b07a4c6..db20785d 100644 --- a/src/Angor/Client/Pages/Browse.razor +++ b/src/Angor/Client/Pages/Browse.razor @@ -3,6 +3,9 @@ @using Angor.Shared.Models @using Angor.Shared.Services @using Nostr.Client.Keys +@using Nostr.Client.Messages +@using System.Text.Json +@using Angor.Client.Models @inject ICacheStorage SessionStorage; @inject NavigationManager NavigationManager @inject IRelayService _RelayService @@ -35,10 +38,21 @@
@findProject.ProjectIdentifier
-

Nostr ID: @(NostrPublicKey.FromHex(findProject.NostrPubKey).Bech32)

+

Nostr ID: @(NostrPublicKey.FromHex(findProject.NostrPubKey).Bech32)

@if (SessionStorage.IsProjectInStorageById(findProject.ProjectIdentifier)) { + @if (SessionStorage.IsProjectMetadataStorageByPubkey(findProject.NostrPubKey)) + { + var metadata = SessionStorage.GetProjectMetadataByPubkey(findProject.NostrPubKey); +
+

@metadata?.Name

+

@metadata?.About

+
+ } + + //var info = SessionStorage.GetProjectById(findProject.ProjectIdentifier); + } else @@ -75,8 +89,27 @@
@project.ProjectIdentifier
-

Nostr ID: @(NostrPublicKey.FromHex(project.NostrPubKey).Bech32)

- +

Nostr ID: @(NostrPublicKey.FromHex(project.NostrPubKey).Bech32)

+ + @if (SessionStorage.IsProjectInStorageById(project.ProjectIdentifier)) + { + @if (SessionStorage.IsProjectMetadataStorageByPubkey(project.NostrPubKey)) + { + var metadata = SessionStorage.GetProjectMetadataByPubkey(project.NostrPubKey); +
+

@metadata?.Name

+

@metadata?.About

+
+ } + + //var info = SessionStorage.GetProjectById(project.ProjectIdentifier); + + + } + else + { +

Project not found in any relay!

+ }
} @@ -118,15 +151,36 @@ if (findProject != null) { - _RelayService.LookupProjectsInfoByPubKeys(_ => + _RelayService.RequestProjectCreateEventsByPubKey(e => { - if (!SessionStorage.IsProjectInStorageById(_.ProjectIdentifier)) - SessionStorage.StoreProjectInfo(_); - }, - OnEndOfStreamAction: () => + switch (e) + { + case { Kind: NostrKind.Metadata }: + var nostrMetadata = JsonSerializer.Deserialize(e.Content, Angor.Shared.Services.RelayService.settings); + if (!SessionStorage.IsProjectMetadataStorageByPubkey(e.Pubkey)) + SessionStorage.StoreProjectMetadata(e.Pubkey, nostrMetadata); + break; + case { Kind: NostrKind.ApplicationSpecificData }: + var projectInfo = JsonSerializer.Deserialize(e.Content, Angor.Shared.Services.RelayService.settings); + if (!SessionStorage.IsProjectInStorageById(projectInfo.ProjectIdentifier)) + SessionStorage.StoreProjectInfo(projectInfo); + break; + } + }, () => { - }, - nostrPubKey: new[] { findProject.NostrPubKey }); + StateHasChanged(); + }, + new[] { findProject.NostrPubKey }); + + //_RelayService.LookupProjectsInfoByPubKeys(_ => + //{ + // if (!SessionStorage.IsProjectInStorageById(_.ProjectIdentifier)) + // SessionStorage.StoreProjectInfo(_); + //}, + //OnEndOfStreamAction: () => + //{ + //}, + //nostrPubKey: new[] { findProject.NostrPubKey }); } findInProgress = false; @@ -152,22 +206,44 @@ .ToArray(); if (projectsForLookup.Any()) - _RelayService.LookupProjectsInfoByPubKeys(_ => + _RelayService.RequestProjectCreateEventsByPubKey(e => { - if (!SessionStorage.IsProjectInStorageById(_.ProjectIdentifier)) - SessionStorage.StoreProjectInfo(_); - }, - OnEndOfStreamAction: () => + switch (e) { - projects = projects //Remove projects that were not found on the relays - .Where(_ => SessionStorage.IsProjectInStorageById(_.ProjectIdentifier)) - .ToList(); + case { Kind: NostrKind.Metadata }: + var nostrMetadata = JsonSerializer.Deserialize(e.Content, Angor.Shared.Services.RelayService.settings); + SessionStorage.StoreProjectMetadata(e.Pubkey, nostrMetadata); + break; + case { Kind: NostrKind.ApplicationSpecificData }: + var projectInfo = JsonSerializer.Deserialize(e.Content, Angor.Shared.Services.RelayService.settings); + if (!SessionStorage.IsProjectInStorageById(projectInfo.ProjectIdentifier)) + SessionStorage.StoreProjectInfo(projectInfo); + break; + } + }, () => + { + searchInProgress = false; + StateHasChanged(); + }, + projectsForLookup); + + //if (projectsForLookup.Any()) + // _RelayService.LookupProjectsInfoByPubKeys(_ => + // { + // if (!SessionStorage.IsProjectInStorageById(_.ProjectIdentifier)) + // SessionStorage.StoreProjectInfo(_); + // }, + // OnEndOfStreamAction: () => + // { + // projects = projects //Remove projects that were not found on the relays + // .Where(_ => SessionStorage.IsProjectInStorageById(_.ProjectIdentifier)) + // .ToList(); - SessionStorage.SetProjectIndexerData(projects); + // SessionStorage.SetProjectIndexerData(projects); - StateHasChanged(); - }, - nostrPubKey: projectsForLookup); + // StateHasChanged(); + // }, + // nostrPubKey: projectsForLookup); StateHasChanged(); } diff --git a/src/Angor/Client/Pages/View.razor b/src/Angor/Client/Pages/View.razor index 77560a6b..6b9fd3ad 100644 --- a/src/Angor/Client/Pages/View.razor +++ b/src/Angor/Client/Pages/View.razor @@ -35,6 +35,17 @@
Project Identifier: @project.ProjectIdentifier
+ + @if (SessionStorage.IsProjectMetadataStorageByPubkey(project.NostrPubKey)) + { + var metadata = SessionStorage.GetProjectMetadataByPubkey(project.NostrPubKey); + +
+

@metadata?.Name

+

@metadata?.About

+
+ } + View the transaction on the explorer.

Founder Key: @project.FounderKey

Start Date: @project.StartDate.ToString("dd/MM/yyyy")

diff --git a/src/Angor/Client/Storage/LocalSessionStorage.cs b/src/Angor/Client/Storage/LocalSessionStorage.cs index eb8136ec..d98a038c 100644 --- a/src/Angor/Client/Storage/LocalSessionStorage.cs +++ b/src/Angor/Client/Storage/LocalSessionStorage.cs @@ -1,3 +1,4 @@ +using Angor.Client.Models; using Angor.Client.Services; using Angor.Shared.Models; using Angor.Shared.Services; @@ -21,10 +22,26 @@ public void StoreProjectInfo(ProjectInfo project) _sessionStorageService.SetItem(project.ProjectIdentifier,project); } + public ProjectMetadata? GetProjectMetadataByPubkey(string pubkey) + { + return _sessionStorageService.GetItem(pubkey); + } + + public void StoreProjectMetadata(string pubkey, ProjectMetadata projectMetadata) + { + _sessionStorageService.SetItem(pubkey, projectMetadata); + } + + public bool IsProjectMetadataStorageByPubkey(string pubkey) + { + return _sessionStorageService.ContainKey(pubkey); + } + public ProjectInfo? GetProjectById(string projectId) { return _sessionStorageService.GetItem(projectId); } + public bool IsProjectInStorageById(string projectId) { return _sessionStorageService.ContainKey(projectId); diff --git a/src/Angor/Client/Models/ProjectMetadata.cs b/src/Angor/Shared/Models/ProjectMetadata.cs similarity index 98% rename from src/Angor/Client/Models/ProjectMetadata.cs rename to src/Angor/Shared/Models/ProjectMetadata.cs index cc6e02b1..06c64a7f 100644 --- a/src/Angor/Client/Models/ProjectMetadata.cs +++ b/src/Angor/Shared/Models/ProjectMetadata.cs @@ -1,6 +1,6 @@ using Nostr.Client.Messages.Metadata; -namespace Angor.Client.Models; +namespace Angor.Shared.Models; public class ProjectMetadata { diff --git a/src/Angor/Shared/Services/ICacheStorage.cs b/src/Angor/Shared/Services/ICacheStorage.cs index 079e0a6d..3cd57606 100644 --- a/src/Angor/Shared/Services/ICacheStorage.cs +++ b/src/Angor/Shared/Services/ICacheStorage.cs @@ -8,6 +8,9 @@ public interface ICacheStorage void StoreProjectInfo(ProjectInfo project); ProjectInfo? GetProjectById(string projectId); bool IsProjectInStorageById(string projectId); + ProjectMetadata? GetProjectMetadataByPubkey(string pubkey); + void StoreProjectMetadata(string pubkey, ProjectMetadata projectMetadata); + bool IsProjectMetadataStorageByPubkey(string pubkey); List? GetProjectIndexerData(); void SetProjectIndexerData(List list); List GetUnconfirmedInboundFunds(); From c5b3f1505acc4d045f40743ca1809de54f783660 Mon Sep 17 00:00:00 2001 From: dangershony Date: Sat, 30 Dec 2023 23:04:43 +0000 Subject: [PATCH 5/5] Fix chronological stages bug --- src/Angor/Client/Pages/Create.razor | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Angor/Client/Pages/Create.razor b/src/Angor/Client/Pages/Create.razor index 283eee4b..179c0255 100644 --- a/src/Angor/Client/Pages/Create.razor +++ b/src/Angor/Client/Pages/Create.razor @@ -348,7 +348,12 @@ foreach (var stage in project.Stages) { if ((stage.ReleaseDate - prev).Days < 0) + { notificationComponent.ShowErrorMessage("Stages must be chronological"); + return; + } + + prev = stage.ReleaseDate; } var operationResult = await notificationComponent.LongOperation(async () =>