Skip to content

Commit

Permalink
Added creating the founder project data on login in a new browser (#17)
Browse files Browse the repository at this point in the history
* Added lookup for projects on founder page

* Changing the founder page to reload missing projects and check for pending investor signatures

* Moved the component to component folder

* Moved the founder list to a separate component, added close subscription call when disposed and added data to the founder project

* Fixed  typo

* Fixed issue with null in the metadata

* Fixed from review

* Fix from review
  • Loading branch information
DavidGershony authored Nov 21, 2023
1 parent 75dfa63 commit 40b6b70
Show file tree
Hide file tree
Showing 15 changed files with 322 additions and 127 deletions.
57 changes: 57 additions & 0 deletions src/Angor/Client/Components/FounderProjectItem.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
@using Angor.Shared.Services
@using Angor.Client.Models
@using Nostr.Client.Messages
@using Nostr.Client.Messages.Metadata

@inject IRelayService RelayService;

<div class="card mb-3">
@if (InvestmentRequests)
{
<div class="card-header bg-success">
<h4 class="d-flex justify-content-center align-items-center">Pending investment requests</h4>
</div>
}
<div class="card-body">
<h1 class="card-title">@FounderProject.Metadata?.Name</h1>
<h2 class="card-subtitle">@FounderProject.ProjectInfo.ProjectIdentifier</h2>
<p class="card-text">Nostr ID: <a href="/" target="_blank">@FounderProject.ProjectInfo.NostrPubKey</a></p>
<NavLink href=@($"/view/{FounderProject.ProjectInfo.ProjectIdentifier}") class="btn btn-primary">View Project</NavLink>
</div>
</div>

@code {

[Parameter]
public FounderProject FounderProject { get; set; }

public bool InvestmentRequests { get; set; }

protected override async Task OnInitializedAsync()
{
await RelayService.ConnectToRelaysAsync();

if (FounderProject.Metadata == null)
{
await RelayService.RequestProjectCreateEventsByPubKeyAsync(FounderProject.ProjectInfo.NostrPubKey, _ =>
{
if (_.Kind != NostrKind.Metadata)
return;

var metadata = System.Text.Json.JsonSerializer.Deserialize<NostrMetadata>(_.Content, Angor.Shared.Services.RelayService.settings);
FounderProject.Metadata = ProjectMetadata.Parse(metadata);
StateHasChanged();
});
}

await RelayService.LookupDirectMessagesForPubKeyAsync(FounderProject.ProjectInfo.NostrPubKey, FounderProject.LastRequestForSignaturesTime, 1,
_ =>
{
if (InvestmentRequests)
return;

InvestmentRequests = true;
StateHasChanged();
});
}
}
10 changes: 10 additions & 0 deletions src/Angor/Client/Models/FounderProject.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Angor.Shared.Models;

namespace Angor.Client.Models;

public class FounderProject
{
public ProjectMetadata? Metadata { get; set; }
public ProjectInfo ProjectInfo { get; set; }
public DateTime? LastRequestForSignaturesTime { get; set; }
}
55 changes: 55 additions & 0 deletions src/Angor/Client/Models/ProjectMetadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using Nostr.Client.Messages.Metadata;

namespace Angor.Client.Models;

public class ProjectMetadata
{
private const string displayName = "display_name";

public string Name { get; set; }
public string Website { get; set; }
public string About { get; set; }
public string Picture { get; set; }
public string Nip05 { get; set; }
public string Lud16 { get; set; }
public string Banner { get; set; }
public string Nip57 { get; set; }

public static ProjectMetadata Parse(NostrMetadata nostrMetadata)
{
var project = new ProjectMetadata
{
Nip57 = nostrMetadata.Nip57,
Lud16 = nostrMetadata.Nip57,
Nip05 = nostrMetadata.Nip57,
About = nostrMetadata.About,
Banner = nostrMetadata.Banner,
Picture = nostrMetadata.Picture
};
if (nostrMetadata.AdditionalData.ContainsKey(nameof(project.Website)))
project.Website = nostrMetadata.AdditionalData[nameof(project.Website)].ToString();
if (nostrMetadata.AdditionalData.ContainsKey(displayName))
project.Name = nostrMetadata.AdditionalData[displayName].ToString();
return project;
}

public NostrMetadata ToNostrMetadata()
{
var nostr = new NostrMetadata
{
About = About,
Banner = Banner,
Lud16 = Lud16,
Name = Name,
Nip05 = Nip05,
Nip57 = Nip57,
Picture = Picture,
AdditionalData = new (){{displayName,Name}}
};

if (Website != null)
nostr.AdditionalData.Add("website",Website);

return nostr;
}
}
53 changes: 15 additions & 38 deletions src/Angor/Client/Pages/Create.razor
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
@using Angor.Shared.Services
@using Blockcore.NBitcoin
@using Blockcore.NBitcoin.DataEncoders
@using Nostr.Client.Json
@using Nostr.Client.Messages
@using Nostr.Client.Messages.Metadata
@using Angor.Client.Models

@implements IDisposable
@inherits BaseComponent
Expand Down Expand Up @@ -225,19 +225,7 @@
}
};

private class NostrMetadataCollection
{
public string Name { get; set; }
public string Website { get; set; }
public string About { get; set; }
public string Picture { get; set; }
public string Nip05 { get; set; }
public string Lud16 { get; set; }
public string Banner { get; set; }
public string Nip57 { get; set; }
}

NostrMetadataCollection NostrMetadata = new ();
ProjectMetadata NostrMetadata = new ();
bool nostrProfileCreated;
bool applicationDataOnNostr;

Expand All @@ -249,8 +237,8 @@
{
var projects = storage.GetFounderProjects();
var keys = storage.GetFounderKeys();
var latestProject = projects.MaxBy(p => p.ProjectIndex);
var projectsKeys = _derivationOperations.GetProjectKey(keys, latestProject?.ProjectIndex + 1 ?? 1);
var latestProject = projects.MaxBy(p => p.ProjectInfo.ProjectIndex);
var projectsKeys = _derivationOperations.GetProjectKey(keys, latestProject?.ProjectInfo.ProjectIndex + 1 ?? 1);

project.ProjectIndex = projectsKeys.Index;
project.FounderKey = projectsKeys.FounderKey;
Expand All @@ -261,16 +249,18 @@

await _RelayService.ConnectToRelaysAsync();

await _RelayService.RequestProjectEventsoByPubKeyAsync(project.NostrPubKey, _ =>
await _RelayService.RequestProjectCreateEventsByPubKeyAsync(project.NostrPubKey, _ =>
{
nostrProfileCreated = _.Kind == NostrKind.Metadata;

if (_.Kind == NostrKind.ApplicationSpecificData) //In case of a crashed application in the middle of the call
{
var nostrProject = Newtonsoft.Json.JsonConvert.DeserializeObject<ProjectInfo>(_.Content!, NostrSerializer.Settings);
var findProject = storage.GetFounderProjects().FirstOrDefault(p => p.ProjectIdentifier == nostrProject!.ProjectIdentifier);
if (_.Content == null)
return;
var nostrProject = System.Text.Json.JsonSerializer.Deserialize<ProjectInfo>(_.Content, RelayService.settings);
var findProject = storage.GetFounderProjects().FirstOrDefault(p => p.ProjectInfo.ProjectIdentifier == nostrProject!.ProjectIdentifier);
if (findProject == null)
storage.AddFounderProject(nostrProject!);
storage.AddFounderProject(new FounderProject{ProjectInfo = nostrProject});
NavigationManager.NavigateTo($"/view/{nostrProject.ProjectIdentifier}");
}

Expand All @@ -282,21 +272,8 @@
{
var nostrKey = _derivationOperations.DeriveProjectNostrPrivateKey(_walletStorage.GetWallet(), project.ProjectIndex);

var resultId = await _RelayService.CreateNostrProfileAsync(new NostrMetadata
{
About = NostrMetadata.About,
Banner = NostrMetadata.Banner,
Lud16 = NostrMetadata.Lud16,
Name = NostrMetadata.Name,
Nip05 = NostrMetadata.Nip05,
Nip57 = NostrMetadata.Nip57,
Picture = NostrMetadata.Picture,
AdditionalData = new Dictionary<string, object>
{
{"website",NostrMetadata.Website},
{"display_name",NostrMetadata.Name}
}
}, NBitcoin.DataEncoders.Encoders.Hex.EncodeData((byte[])nostrKey.ToBytes()));
var resultId = await _RelayService.CreateNostrProfileAsync( NostrMetadata.ToNostrMetadata(),
NBitcoin.DataEncoders.Encoders.Hex.EncodeData((byte[])nostrKey.ToBytes()));

_RelayService.RegisterOKMessageHandler(resultId, _ =>
{
Expand Down Expand Up @@ -325,7 +302,7 @@

var projects = storage.GetFounderProjects();

if (projects.Any(a => project.ProjectIdentifier == a.ProjectIdentifier))
if (projects.Any(a => project.ProjectIdentifier == a.ProjectInfo.ProjectIdentifier))
{
notificationComponent.ShowErrorMessage("This wallet already has a project with this index");
return;
Expand Down Expand Up @@ -409,8 +386,8 @@
//storage.AddFounderProject(project); TODO remove from storage
return response;
}
storage.AddFounderProject(project);

storage.AddFounderProject(new FounderProject { ProjectInfo = project });

_RelayService.RegisterOKMessageHandler(resultId, _ =>
{
Expand Down
103 changes: 81 additions & 22 deletions src/Angor/Client/Pages/Founder.razor
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
@page "/founder"
@using Angor.Shared
@using Angor.Client.Storage
@using Angor.Shared.Models
@inject HttpClient Http
@using Angor.Shared.Services
@using Angor.Client.Services
@using Angor.Client.Models
@using Angor.Client.Components
@inject NavigationManager NavigationManager
@inject IWalletStorage _walletStorage;
@inject IClientStorage storage;
@inject IRelayService RelayService;
@inject IIndexerService _IndexerService

@if (!hasWallet)
{
Expand All @@ -24,49 +28,104 @@

<p>Creating a project requires an on-chain transaction and a nostr did</p>

@if (founderprojects.Count == 0)
{
<p>No projects found.</p>
}
else
{
foreach (var project in founderprojects)
</div>
</div>

@if (founderProjects.Count == 0)
{
<p>No projects found.</p>

<div class="row">
<div class="col">
@if (scanningForProjects)
{
<div class="card mb-3">
<div class="card-body">
<h5 class="card-title">@project.ProjectIdentifier</h5>
<p class="card-text">Nostr ID: <a href="/" target="_blank">@(new Blockcore.NBitcoin.Key().PubKey.ToHex())</a></p>
<NavLink href=@($"/view/{project.ProjectIdentifier}") class="btn btn-primary">View Project</NavLink>
</div>
</div>
<div class="small loader"></div>
}
}

else
{
<button class="btn btn-primary mb-4" @onclick="LookupProjectKeysOnIndexerAsync">Scan for founder projects</button>
<br/>
}
</div>
</div>

}
else
{
foreach (var project in founderProjects)
{
<div class="row">
<div class="col">
<FounderProjectItem FounderProject="@project"></FounderProjectItem>
</div>
</div>
}
}

<div class="row">
<div class="col">
<button class="btn btn-primary mb-3" @onclick="NavigateToCreateProject">Create Project</button>

</div>
</div>
</div>

@code {

@code {
private string founderKey;
private string projectId;
private List<ProjectInfo> founderprojects = new();
private List<FounderProject> founderProjects = new();
private bool hasWallet;
bool scanningForProjects;

private NotificationComponent notificationComponent;




protected override async Task OnInitializedAsync()
{
hasWallet = _walletStorage.HasWallet();

if (hasWallet)
{
founderprojects = storage.GetFounderProjects();
founderProjects = storage.GetFounderProjects();
}
}

private async Task LookupProjectKeysOnIndexerAsync()
{
scanningForProjects = true;
await RelayService.ConnectToRelaysAsync();

var keys = storage.GetFounderKeys();

var founderProjectsToLookup = new List<string>();

foreach (var key in keys.Keys)
{
if (founderProjects.Exists(_ => _.ProjectInfo.ProjectIdentifier == key.ProjectIdentifier))
continue;

var indexerProject = await _IndexerService.GetProjectByIdAsync(key.ProjectIdentifier);

if (indexerProject == null)
break;

founderProjectsToLookup.Add(key.NostrPubKey);
}

if (founderProjectsToLookup.Any())
await RelayService.LookupProjectsInfoByPubKeysAsync<ProjectInfo>(_ =>
{
var founderProject = new FounderProject { ProjectInfo = _ };
storage.AddFounderProject(founderProject);
founderProjects.Add(founderProject);
scanningForProjects = false;
StateHasChanged();

}, founderProjectsToLookup.ToArray());
}

private void NavigateToCreateProject()
{
NavigationManager.NavigateTo("/create");
Expand Down
2 changes: 1 addition & 1 deletion src/Angor/Client/Pages/Invest.razor
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@
}
else
{
findProject = storage.GetFounderProjects().FirstOrDefault(p => p.ProjectIdentifier == ProjectId);
findProject = storage.GetFounderProjects().FirstOrDefault(p => p.ProjectInfo.ProjectIdentifier == ProjectId).ProjectInfo;

if (findProject != null)
{
Expand Down
Loading

0 comments on commit 40b6b70

Please sign in to comment.