Skip to content

Commit

Permalink
Improving the user experience of the project section (#94)
Browse files Browse the repository at this point in the history
* Implement auto-loading of projects from indexer when absent in browser storage

This commit introduces a crucial enhancement to our Blazer application's functionality. By leveraging the @Attribute [StreamRendering(true)] directive, we've enabled automatic loading of projects directly from the indexer if they are not found in the browser storage. This ensures a seamless experience for users, even if they haven't explicitly saved their projects locally. This improvement streamlines the user journey, reducing friction and enhancing overall usability.

* Applied minor changes to project list display

* Fix cy test

* Remove @Attribute [StreamRendering(true)]

* Fix search project

* Update browse.cy.js

* Update Browse.razor

* Update browse.cy.js
  • Loading branch information
miladsoft committed May 16, 2024
1 parent eb0e493 commit a8bb6e2
Show file tree
Hide file tree
Showing 6 changed files with 283 additions and 249 deletions.
230 changes: 115 additions & 115 deletions src/Angor/Client/Pages/Browse.razor
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
@inject NavigationManager NavigationManager
@inject IRelayService _RelayService
@inject IIndexerService _IndexerService
@inject IJSRuntime JS

<NotificationComponent @ref="notificationComponent" />

Expand Down Expand Up @@ -45,61 +46,24 @@
<div class="d-flex align-items-center">
<!-- Search Section -->
<div class="input-group">
<input type="text" class="form-control" placeholder="Enter Angor project identifier" id="searchQuery" @bind="searchQuery">
<button class="btn btn-primary" type="button" @onclick="FindProject" disabled="@findInProgress" data-cy="find-button">Find</button>
<input type="text" class="form-control" placeholder="Enter Angor project identifier" id="searchQuery" @bind="searchQuery" @onkeydown="HandleKeyDown">
<button class="btn btn-primary" type="button" @onclick="SearchProject" disabled="@searchInProgress" data-cy="find-button">Find</button>
</div>
</div>
</div>

</div>

@if (findInProgress)
{
<div class="d-flex justify-content-center mt-4">
<div class="loader"></div>
</div>
}

<!-- Search Result -->
@if (findProject != null)
{
<div class="card mt-4" data-cy="searchedProject">
<div class="card-body">
@if (SessionStorage.IsProjectInStorageById(findProject.ProjectIdentifier))
{
var project = SessionStorage.GetProjectById(findProject.ProjectIdentifier);
if (project?.Metadata != null)
{
<h3 class="card-title" data-cy="searchedTitle">@project.Metadata.Name</h3>
<p class="card-subtitle" data-cy="searchedSubTitle">@project.Metadata.About</p>
<hr>
}
}
else
{
<p class="text-warning-emphasis">Project not found in any relay!</p>
}
<p data-cy="project-info">
Project ID:@findProject.ProjectIdentifier
<br />
Nostr ID :@(NostrPublicKey.FromHex(findProject.NostrPubKey).Bech32)
</p>
<button @onclick="() => ViewProjectDetails(findProject.ProjectIdentifier)" class="btn btn-primary card-">View</button>

</div>
</div>
}


@if (projects.Count == 0)
@if (!projects.Any() && !searchInProgress)
{
<div class="row mt-4">
<div class="card card-body">
<div class="card card-body angor-alert-info pt-2 pb-2">
<div class="d-flex align-items-center">
<span class="material-icons opacity-10 fs-1 me-3 btn-angor user-select-none">
<span class="material-icons opacity-10 fs-1 me-3 text-white user-select-none">
info
</span>
<span class="text-warning" data-cy="projectsGrid">No projects found.</span>
<span class="text-white" data-cy="projectsGrid">No projects found.</span>
</div>
</div>
</div>
Expand All @@ -109,21 +73,21 @@ else

@if (isGridView)
{
<div class="row row-cols-1 row-cols-sm-1 row-cols-md-2 row-cols-lg-3">
<div class="row row-cols-1 row-cols-sm-1 row-cols-md-2 row-cols-lg-3 project-wrapper">
@foreach (var indexerData in projects.OrderByDescending(project => project.CreatedOnBlock))
{
<div class="col d-flex align-items-stretch">
<div class="card mt-4 w-100">
<a class="d-block blur-shadow-image">
@if (!nostrSearchInProgress && SessionStorage.IsProjectInStorageById(indexerData.ProjectIdentifier))
{
var project = SessionStorage.GetProjectById(indexerData.ProjectIdentifier);
<div class="card mt-4 w-100 project-card">
<a class="d-block blur-shadow-image">
@if (!nostrSearchInProgress && SessionStorage.IsProjectInStorageById(indexerData.ProjectIdentifier))
{
var project = SessionStorage.GetProjectById(indexerData.ProjectIdentifier);
<img class="card-img-top" src="@(project?.Metadata?.Banner ?? "/assets/img/no-image.jpg")" alt="@(project?.Metadata?.Banner != null ? "" : "no-image")" onerror="this.onerror=null; this.src='/assets/img/no-image.jpg';" />

}
</a>
<div class="card-body text-center">
}
</a>

<div class="card-body text-center">
@if (nostrSearchInProgress)
{
<div class="p-3">
Expand Down Expand Up @@ -154,62 +118,73 @@ else
}
else
{
@foreach (var indexerData in projects.OrderByDescending(project => project.CreatedOnBlock))
{
<div class="card mt-4">
<div class="row g-0">
<div class="col-md-4">
<div class="img-responsive img-responsive-16by9 position-relative" role="button" @onclick="() => ViewProjectDetails(indexerData.ProjectIdentifier)">
@if (!nostrSearchInProgress && SessionStorage.IsProjectInStorageById(indexerData.ProjectIdentifier))
{
var project = SessionStorage.GetProjectById(indexerData.ProjectIdentifier);
<div class="card-header card-header-img">
<img class="img-responsive-item" src="@(project?.Metadata?.Banner ?? "/assets/img/no-image.jpg")" alt="@(project?.Metadata?.Banner != null ? "" : "no-image")" onerror="this.onerror=null; this.src='/assets/img/no-image.jpg';" />
</div>
}
</div>
</div>
<div class="col-md-8 d-flex align-items-center justify-content-center position-relative">
<div class="card-body card-loader loading">

@if (nostrSearchInProgress)
{
<div class="p-3">
<div class="loader-small m-auto"></div>
</div>
}
else
{
@if (SessionStorage.IsProjectInStorageById(indexerData.ProjectIdentifier))
<div class="project-wrapper">
@foreach (var indexerData in projects.OrderByDescending(project => project.CreatedOnBlock))
{

<div class="card mt-4 project-card ">
<div class="row g-0">
<div class="col-md-4">
<div class="img-responsive img-responsive-16by9 position-relative" role="button" @onclick="() => ViewProjectDetails(indexerData.ProjectIdentifier)">
@if (!nostrSearchInProgress && SessionStorage.IsProjectInStorageById(indexerData.ProjectIdentifier))
{
var project = SessionStorage.GetProjectById(indexerData.ProjectIdentifier);
if (project?.Metadata != null)
{
<h5 class="card-title text-center" role="button" @onclick="() => ViewProjectDetails(indexerData.ProjectIdentifier)">@project.Metadata.Name</h5>
<p class="card-text text-center line-clamp-3" role="button" @onclick="() => ViewProjectDetails(indexerData.ProjectIdentifier)">@((MarkupString)project.Metadata.About)</p>
}
<div class="card-header card-header-img">
<img class="img-responsive-item" src="@(project?.Metadata?.Banner ?? "/assets/img/no-image.jpg")" alt="@(project?.Metadata?.Banner != null ? "" : "no-image")" onerror="this.onerror=null; this.src='/assets/img/no-image.jpg';" />
</div>
}
</div>
</div>
<div class="col-md-8 d-flex align-items-center justify-content-center position-relative">
<div class="card-body card-loader loading">

@if (nostrSearchInProgress)
{
<div class="p-3">
<div class="loader-small m-auto"></div>
</div>
}
else
{
<p class="text-warning-emphasis">Project not found in any relay!</p>
@if (SessionStorage.IsProjectInStorageById(indexerData.ProjectIdentifier))
{
var project = SessionStorage.GetProjectById(indexerData.ProjectIdentifier);
if (project?.Metadata != null)
{
<h5 class="card-title text-center" role="button" @onclick="() => ViewProjectDetails(indexerData.ProjectIdentifier)">@project.Metadata.Name</h5>
<p class="card-text text-center line-clamp-3" role="button" @onclick="() => ViewProjectDetails(indexerData.ProjectIdentifier)">@((MarkupString)project.Metadata.About)</p>
}
}
else
{
<p class="text-warning-emphasis">Project not found in any relay!</p>
}
}
}
</div>
</div>
</div>
</div>
</div>
}
}

}

}

<div class="d-flex justify-content-center mt-4">
<button class="btn btn-secondary my-3" @onclick="SearchProjects">Fetch Projects</button>
</div>
</div>


}
}
@if (!searchInProgress)
{
<div class="d-flex justify-content-center mt-4">
<a class="btn btn-secondary my-3" href="https://browse.angor.io" target="_blank">
<i class="material-icons opacity-10">search</i>
<span class="nav-link-text ms-1">Project Explorer</span>
</a>
</div>
}
@if (searchInProgress)
{
<div class="d-flex justify-content-center">
<div class="d-flex justify-content-center mt-4">
<div class="loader"></div>
</div>
}
Expand All @@ -222,8 +197,7 @@ else
private string searchQuery;
bool searchInProgress = false;
bool nostrSearchInProgress;
bool findInProgress = false;
bool isGridView = true;
bool isGridView = true;
string viewModeIcon = "grid_view";

ProjectIndexerData? findProject = null;
Expand All @@ -233,50 +207,68 @@ else
protected override async Task OnInitializedAsync()
{
projects = SessionStorage.GetProjectIndexerData() ?? new();
if (!projects.Any())
{
await GetAllProjects();
}
// Handle '/' key press for focusing search input
await JS.InvokeVoidAsync("angor.initSearchFocus", "searchQuery");
}

// protected override async Task OnAfterRenderAsync(bool firstRender)
// {
// if (firstRender)
// {
// await SearchProjects();
// }
// }

void ToggleView()
{
isGridView = !isGridView;
viewModeIcon = isGridView ? "grid_view" : "view_list";
}

private async Task FindProject()
private async Task SearchProject()
{
if (string.IsNullOrEmpty(searchQuery))
{
await GetAllProjects();
return;
}

findProject = projects.FirstOrDefault(_ => _.ProjectIdentifier == searchQuery);

if (findProject != null)
{
projects = new List<ProjectIndexerData> { findProject };
StateHasChanged();
return;
}

findInProgress = true;
searchInProgress = true;

findProject = await _IndexerService.GetProjectByIdAsync(searchQuery);
try
{
findProject = await _IndexerService.GetProjectByIdAsync(searchQuery);

if (findProject != null)
if (findProject != null)
{
_RelayService.RequestProjectCreateEventsByPubKey(HandleProjectEvents(), StateHasChanged, new[] { findProject.NostrPubKey });
projects = new List<ProjectIndexerData> { findProject };
}
else
{
projects.Clear();
StateHasChanged();
}
}
finally
{
_RelayService.RequestProjectCreateEventsByPubKey(HandleProjectEvents(),
StateHasChanged,
new[] { findProject.NostrPubKey });
searchInProgress = false;
StateHasChanged();
}

findInProgress = false;
}

private async Task SearchProjects()

private async Task GetAllProjects()
{
searchInProgress = true;

var blockchainProjects = await _IndexerService.GetProjectsAsync(null, 20);
var blockchainProjects = await _IndexerService.GetProjectsAsync(null, 21);

var projectsNotInList = blockchainProjects
.Where(blockchainProject => projects.All(_ => _.ProjectIdentifier != blockchainProject.ProjectIdentifier))
Expand Down Expand Up @@ -364,4 +356,12 @@ else
notificationComponent.ShowNotificationMessage("The project was not loaded from the relay yet");
}
}

private async Task HandleKeyDown(KeyboardEventArgs e)
{
if (e.Key == "Enter")
{
await SearchProject();
}
}
}
8 changes: 4 additions & 4 deletions src/Angor/Client/Pages/Wallet.razor
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@

<!-- No Wallet found -->
<div class="row mt-4">
<div class="card card-body">
<div class="card card-body angor-alert-info pt-2 pb-2">
<div class="d-flex align-items-center">
<span class="material-icons opacity-10 fs-1 me-3 btn-angor user-select-none">
<span class="material-icons opacity-10 fs-1 me-3 text-white user-select-none">
info
</span>
<span class="text-warning">No Wallet Found</span>
<span class="text-white">No Wallet Found</span>
</div>
</div>
</div>
Expand Down Expand Up @@ -115,7 +115,7 @@
@if (isNewWallet)
{
<div class="mb-2">
<button class="btn btn-primary w-100" @onclick="GenerateNewWalletWords">
<button class="btn btn-secondary w-100" @onclick="GenerateNewWalletWords">
<div class="d-flex align-items-center justify-content-center">
<span class="material-icons opacity-10 me-1" data-cy="generate-wallet-words">
add
Expand Down
4 changes: 2 additions & 2 deletions src/Angor/Client/Shared/NotificationComponent.razor
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<div class="col z-index-4">
<div class="row justify-content-center">
<div class="col-lg-8 col-md-10">
<div class="alert alert-info fixed-bottom w-70 d-flex justify-content-between align-items-center alert-message" role="alert" data-cy="alert" >
<div class="alert alert-info angor-alert-info fixed-bottom w-50 d-flex justify-content-between align-items-center alert-message" role="alert" data-cy="alert">
@notificationMessage
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close" @onclick="closeAlert"></button>
</div>
Expand All @@ -39,7 +39,7 @@
<div class="col">
<div class="modal-wrapper">
<div class="modal show d-block" tabindex="-1" style="background-color: rgba(0,0,0,0.5);">
<div class="modal-dialog modal-dialog-centered modal-sm">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header bg-danger text-white">
<h5 class="modal-title">
Expand Down
Loading

0 comments on commit a8bb6e2

Please sign in to comment.