[frontend/components] Update NoteDetails to use PaginationWrapper

This commit is contained in:
Lilian 2024-10-17 03:19:14 +02:00
parent 9cd2f4f530
commit fb0586ecba
No known key found for this signature in database
3 changed files with 133 additions and 39 deletions

View file

@ -8,7 +8,7 @@
@if (State is State.Loaded) @if (State is State.Loaded)
{ {
<div class="likes"> <div class="likes">
@if (LikedBy != null) @foreach (var el in LikedBy) @foreach (var el in LikedBy)
{ {
<div @onclick="() => OpenProfile(el.Username, el.Host)" class="like-entry"> <div @onclick="() => OpenProfile(el.Username, el.Host)" class="like-entry">
<img class="icon" src="@el.AvatarUrl"/> <img class="icon" src="@el.AvatarUrl"/>
@ -18,6 +18,10 @@
</div> </div>
</div> </div>
} }
@if (EndReached == false)
{
<ScrollEnd IntersectionChange="LoadMore" ManualLoad="LoadMore"/>
}
</div> </div>
} }
@if (State is State.Loading) @if (State is State.Loading)
@ -33,13 +37,25 @@
@code { @code {
[Parameter, EditorRequired] public required string NoteId { get; set; } [Parameter, EditorRequired] public required string NoteId { get; set; }
private State State { get; set; } private State State { get; set; }
private List<UserResponse>? LikedBy { get; set; } = []; private List<UserResponse> LikedBy { get; set; } = [];
private PaginationData Pd { get; set; } = null!;
private bool EndReached { get; set; } = false;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
try try
{ {
LikedBy = await Api.Notes.GetNoteLikes(NoteId); var pq = new PaginationQuery { Limit = 20 };
var res = await Api.Notes.GetNoteLikes(NoteId, pq);
if (res is null)
{
State = State.NotFound;
Logger.LogWarning($"Likes for '{NoteId}' not found.");
return;
}
if (res.Links.Next is null) EndReached = true;
LikedBy = res.Data;
State = State.Loaded; State = State.Loaded;
} }
catch (ApiException e) catch (ApiException e)
@ -49,6 +65,35 @@
} }
} }
private async Task<PaginationWrapper<List<UserResponse>>?> FetchMore(PaginationData data)
{
if (data.Next is null) return null;
var pq = new PaginationQuery { MaxId = data.Next?.Split('=')[1], Limit = 20 };
var res = await Api.Notes.GetNoteLikes(NoteId, pq);
return res;
}
private async Task LoadMore()
{
if (EndReached) return;
try
{
var res = await FetchMore(Pd);
if (res is null)
{
EndReached = true;
return;
}
Pd = res.Links;
LikedBy.AddRange(res.Data);
}
catch (ApiException e)
{
Logger.LogError(e, $"Failed to load likes");
}
}
private void OpenProfile(string username, string? host) private void OpenProfile(string username, string? host)
{ {
var path = $"@{username}"; var path = $"@{username}";

View file

@ -15,7 +15,7 @@
<Note NoteResponse="el"/> <Note NoteResponse="el"/>
</div> </div>
} }
@if (_end is false) @if (EndReached is false)
{ {
<ScrollEnd ManualLoad="LoadMore" IntersectionChange="LoadMore"/> <ScrollEnd ManualLoad="LoadMore" IntersectionChange="LoadMore"/>
} }
@ -26,27 +26,24 @@
[Parameter, EditorRequired] public required string NoteId { get; set; } [Parameter, EditorRequired] public required string NoteId { get; set; }
private State State { get; set; } private State State { get; set; }
private List<NoteResponse> Quotes { get; set; } = []; private List<NoteResponse> Quotes { get; set; } = [];
private string? _minId; private PaginationData Pd { get; set; } = null!;
private string? _maxId; private bool EndReached { get; set; } = false;
private bool _end = false;
private int _limit = 40;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
try try
{ {
var res = await Api.Notes.GetQuotes(NoteId, new PaginationQuery { Limit = _limit }); var res = await Api.Notes.GetQuotes(NoteId, new PaginationQuery { Limit = 20 });
if (res is not null && res.Count > 0) if (res is null)
{ {
Quotes = res; State = State.NotFound;
_minId = Quotes.Last().Id; Logger.LogWarning($"Quotes for '{NoteId}' not found.");
_maxId = Quotes.First().Id; return;
if (res.Count < _limit)
{
_end = true;
}
} }
if (res.Links.Next is null) EndReached = true;
Quotes = res.Data;
Pd = res.Links;
State = State.Loaded; State = State.Loaded;
} }
catch (ApiException e) catch (ApiException e)
@ -56,26 +53,32 @@
} }
} }
private async void LoadMore() private async Task<PaginationWrapper<List<NoteResponse>>?> FetchMore(PaginationData data)
{ {
var pq = new PaginationQuery { MaxId = _minId, Limit = 40 }; if (data.Next is null) return null;
var pq = new PaginationQuery { MaxId = data.Next?.Split('=')[1], Limit = 20 };
var res = await Api.Notes.GetQuotes(NoteId, pq);
return res;
}
private async Task LoadMore()
{
if (EndReached) return;
try try
{ {
var res = await Api.Notes.GetQuotes(NoteId, pq); var res = await FetchMore(Pd);
if (res is null) return; // If server returns null here, the note was likely deleted. if (res is null)
if (res.Count < 1)
{ {
_end = true; EndReached = true;
return; return;
} }
if (res.Count < _limit) _end = true; Pd = res.Links;
_minId = res.Last().Id; Quotes.AddRange(res.Data);
Quotes.AddRange(res);
} }
catch (ApiException e) catch (ApiException e)
{ {
Logger.LogError(e, "Failed to load more quotes"); Logger.LogError(e, "Failed to load Quotes");
} }
} }
} }

View file

@ -8,7 +8,7 @@
@if (State is State.Loaded) @if (State is State.Loaded)
{ {
<div class="renotes"> <div class="renotes">
@if (RenotedBy != null) @foreach (var el in RenotedBy) @foreach (var el in RenotedBy)
{ {
<div @onclick="() => OpenProfile(el.Username, el.Host)" class="renote-entry"> <div @onclick="() => OpenProfile(el.Username, el.Host)" class="renote-entry">
<img class="icon" src="@el.AvatarUrl"/> <img class="icon" src="@el.AvatarUrl"/>
@ -18,6 +18,10 @@
</div> </div>
</div> </div>
} }
@if (EndReached == false)
{
<ScrollEnd IntersectionChange="LoadMore" ManualLoad="LoadMore"/>
}
</div> </div>
} }
@if (State is State.Loading) @if (State is State.Loading)
@ -33,13 +37,26 @@
@code { @code {
[Parameter, EditorRequired] public required string NoteId { get; set; } [Parameter, EditorRequired] public required string NoteId { get; set; }
private State State { get; set; } private State State { get; set; }
private List<UserResponse>? RenotedBy { get; set; } = []; private List<UserResponse> RenotedBy { get; set; } = [];
private PaginationData Pd { get; set; } = null!;
private bool EndReached { get; set; }
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
try try
{ {
RenotedBy = await Api.Notes.GetRenotes(NoteId); var pq = new PaginationQuery { Limit = 20 };
var res = await Api.Notes.GetRenotes(NoteId, pq);
if (res is null)
{
State = State.NotFound;
Logger.LogWarning($"Renotes for '{NoteId}' not found.");
return;
}
if (res.Links.Next is null) EndReached = true;
RenotedBy = res.Data;
Pd = res.Links;
State = State.Loaded; State = State.Loaded;
} }
catch (ApiException e) catch (ApiException e)
@ -49,6 +66,35 @@
} }
} }
private async Task<PaginationWrapper<List<UserResponse>>?> FetchMore(PaginationData data)
{
if (data.Next is null) return null;
var pq = new PaginationQuery { MaxId = data.Next?.Split('=')[1], Limit = 20 };
var res = await Api.Notes.GetRenotes(NoteId, pq);
return res;
}
private async Task LoadMore()
{
if (EndReached) return;
try
{
var res = await FetchMore(Pd);
if (res is null)
{
EndReached = true;
return;
}
Pd = res.Links;
RenotedBy.AddRange(res.Data);
}
catch (ApiException e)
{
Logger.LogError(e, "Failed to load renotes");
}
}
private void OpenProfile(string username, string? host) private void OpenProfile(string username, string? host)
{ {
var path = $"@{username}"; var path = $"@{username}";