Support deletion of pics/statuses

This commit is contained in:
Gordon Pedersen 2024-06-20 16:46:12 +10:00
parent 518f181c4f
commit 295ea4834e
7 changed files with 142 additions and 13 deletions

View file

@ -13,7 +13,18 @@
<label>Description</label> <label>Description</label>
</div> </div>
</div> </div>
<nav class="right-align no-space"> <nav class="no-space">
@if (confirmDelete) {
<button @onclick="ConfirmDeletePic" disabled="@loading" class="red-7-bg white-fg">
<i class="fa-solid fa-exclamation-triangle"></i> <span>Are you sure?</span>
</button>
}
else {
<button @onclick="DeletePic" disabled="@loading" class="red-7-bg white-fg">
<i class="fa-solid fa-trash"></i> <span>Delete</span>
</button>
}
<div class="max"></div>
<button class="transparent link" data-ui="#@id" disabled="@loading">Cancel</button> <button class="transparent link" data-ui="#@id" disabled="@loading">Cancel</button>
<button @onclick="PostPic" disabled="@loading"> <button @onclick="PostPic" disabled="@loading">
@if (loading) { @if (loading) {
@ -42,11 +53,38 @@
private bool loading = false; private bool loading = false;
[Parameter] [Parameter]
public string id { get; set; } public string id { get; set; }
private bool confirmDelete { get; set; }
protected override async Task OnInitializedAsync() { protected override async Task OnInitializedAsync() {
Description = Pic?.Description; Description = Pic?.Description;
} }
public async Task DeletePic() {
if (!confirmDelete) confirmDelete = true;
await InvokeAsync(StateHasChanged);
}
public async Task ConfirmDeletePic() {
if (confirmDelete) {
loading = true;
await InvokeAsync(StateHasChanged);
if (!string.IsNullOrEmpty(Pic?.Id)) {
await api.DeletePic(State.SelectedAddressName, Pic.Id);
await State.RefreshPics();
await InvokeAsync(StateHasChanged);
}
await JS.InvokeVoidAsync("ui", "#" + id);
// clear input
Description = string.Empty;
Pic = null;
loading = false;
confirmDelete = false;
await InvokeAsync(StateHasChanged);
}
}
public async Task PostPic() { public async Task PostPic() {
loading = true; loading = true;
await InvokeAsync(StateHasChanged); await InvokeAsync(StateHasChanged);
@ -62,6 +100,7 @@
Description = string.Empty; Description = string.Empty;
Pic = null; Pic = null;
loading = false; loading = false;
confirmDelete = false;
await InvokeAsync(StateHasChanged); await InvokeAsync(StateHasChanged);
} }

View file

@ -29,7 +29,18 @@
<label>Status</label> <label>Status</label>
</div> </div>
</div> </div>
<nav class="right-align no-space"> <nav class="no-space">
@if (confirmDelete) {
<button @onclick="ConfirmDeleteStatus" disabled="@loading" class="red-7-bg white-fg">
<i class="fa-solid fa-exclamation-triangle"></i> <span>Are you sure?</span>
</button>
}
else {
<button @onclick="DeleteStatus" disabled="@loading" class="red-7-bg white-fg">
<i class="fa-solid fa-trash"></i> <span>Delete</span>
</button>
}
<div class="max"></div>
<InputText id="status-emoji-input" class="invisible" @bind-Value="Emoji"></InputText> <InputText id="status-emoji-input" class="invisible" @bind-Value="Emoji"></InputText>
<button class="transparent link" data-ui="#@id" disabled="@loading">Cancel</button> <button class="transparent link" data-ui="#@id" disabled="@loading">Cancel</button>
<button @onclick="PatchStatus" disabled="@loading"> <button @onclick="PatchStatus" disabled="@loading">
@ -60,12 +71,40 @@
private bool loading = false; private bool loading = false;
[Parameter] [Parameter]
public string id { get; set; } public string id { get; set; }
private bool confirmDelete { get; set; }
protected override async Task OnInitializedAsync() { protected override async Task OnInitializedAsync() {
Content = Status?.Content; Content = Status?.Content;
Emoji = Status?.Emoji; Emoji = Status?.Emoji;
} }
public async Task DeleteStatus() {
if (!confirmDelete) confirmDelete = true;
await InvokeAsync(StateHasChanged);
}
public async Task ConfirmDeleteStatus() {
if(confirmDelete) {
loading = true;
await InvokeAsync(StateHasChanged);
if (!string.IsNullOrEmpty(Status?.Id)) {
await api.DeleteStatus(State.SelectedAddressName, Status.Id);
await State.RefreshStatuses();
await InvokeAsync(StateHasChanged);
}
await JS.InvokeVoidAsync("ui", "#" + id);
// clear input
Content = string.Empty;
Emoji = string.Empty;
Status = null;
loading = false;
confirmDelete = false;
await InvokeAsync(StateHasChanged);
}
}
public async Task PatchStatus() { public async Task PatchStatus() {
loading = true; loading = true;
await InvokeAsync(StateHasChanged); await InvokeAsync(StateHasChanged);
@ -82,6 +121,7 @@
Emoji = string.Empty; Emoji = string.Empty;
Status = null; Status = null;
loading = false; loading = false;
confirmDelete = false;
await InvokeAsync(StateHasChanged); await InvokeAsync(StateHasChanged);
} }

View file

@ -9,15 +9,15 @@
<div class="row"> <div class="row">
<div class="min square extra"> <div class="min square extra">
<button class="transparent square extra no-margin"> <button class="transparent square extra no-margin">
<object id="status-emoji" class="large emoji @(Emoji == null ? "animated" : string.Empty)" data-emoji="@(Emoji ?? "🫥")">@(Emoji ?? "🫥")</object> <object id="new-status-emoji" class="large emoji @(Emoji == null ? "animated" : string.Empty)" data-emoji="@(Emoji ?? "🫥")">@(Emoji ?? "🫥")</object>
<menu class="no-wrap"> <menu class="no-wrap">
<script type="module" src="https://cdn.jsdelivr.net/npm/emoji-picker-element@@^1/index.js"></script> <script type="module" src="https://cdn.jsdelivr.net/npm/emoji-picker-element@@^1/index.js"></script>
<emoji-picker emoji-version="15.1"></emoji-picker> <emoji-picker emoji-version="15.1"></emoji-picker>
<script> <script>
document.querySelector('emoji-picker') document.querySelector('emoji-picker')
.addEventListener('emoji-click', event => { .addEventListener('emoji-click', event => {
document.getElementById('status-emoji').setAttribute('data-emoji', event.detail.unicode) document.getElementById('new-status-emoji').setAttribute('data-emoji', event.detail.unicode)
const input = document.getElementById('status-emoji-input') const input = document.getElementById('new-status-emoji-input')
input.value = event.detail.unicode input.value = event.detail.unicode
var event = new Event('change'); var event = new Event('change');
input.dispatchEvent(event); input.dispatchEvent(event);
@ -37,7 +37,7 @@
<span>Post this to Mastodon</span> <span>Post this to Mastodon</span>
</label> </label>
} }
<InputText id="status-emoji-input" class="invisible" @bind-Value="Emoji"></InputText> <InputText id="new-status-emoji-input" class="invisible" @bind-Value="Emoji"></InputText>
<button class="transparent link" data-ui="#@id" disabled="@loading">Cancel</button> <button class="transparent link" data-ui="#@id" disabled="@loading">Cancel</button>
<button @onclick="PostStatus" disabled="@loading"> <button @onclick="PostStatus" disabled="@loading">
@if (loading) { @if (loading) {

View file

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Neighbourhood.omg.lol.Models {
public class DeleteResponseData : IOmgLolResponseData {
public string Message { get; set; }
}
}

View file

@ -15,7 +15,7 @@ namespace Neighbourhood.omg.lol.Models {
// Account data // Account data
public AccountResponseData? AccountInfo { get; set; } public AccountResponseData? AccountInfo { get; set; }
public AddressResponseList? AddressList { get; set; } public AddressResponseList? AddressList { get; set; }
public string? Name { get => AccountInfo?.Name; } public string? Name { get => AccountInfo?.Name; }
public string? Email { get => AccountInfo?.Email; } public string? Email { get => AccountInfo?.Email; }
public IEnumerable<string>? AddressNames { get => AddressList?.Select(a => a.Address); } public IEnumerable<string>? AddressNames { get => AddressList?.Select(a => a.Address); }
@ -44,7 +44,7 @@ namespace Neighbourhood.omg.lol.Models {
// share intent stuff // share intent stuff
public event EventHandler<EventArgs>? IntentReceived; public event EventHandler<EventArgs>? IntentReceived;
private string? _shareString; private string? _shareString;
public string? ShareString { public string? ShareString {
get => _shareString; get => _shareString;
set { set {
_shareString = value; _shareString = value;
@ -139,7 +139,7 @@ namespace Neighbourhood.omg.lol.Models {
} }
public async Task<List<MarkupString>?> GetEphemeralMessages(bool forceRefresh = false) { public async Task<List<MarkupString>?> GetEphemeralMessages(bool forceRefresh = false) {
if(forceRefresh || this.EphemeralMessages == null || this.EphemeralMessages.Count == 0) { if (forceRefresh || this.EphemeralMessages == null || this.EphemeralMessages.Count == 0) {
this.EphemeralMessages = await api.Ephemeral(); this.EphemeralMessages = await api.Ephemeral();
} }
return this.EphemeralMessages; return this.EphemeralMessages;
@ -179,7 +179,7 @@ namespace Neighbourhood.omg.lol.Models {
} }
public async Task<List<Pic>?> GetPics(bool forceRefresh = false) { public async Task<List<Pic>?> GetPics(bool forceRefresh = false) {
if(forceRefresh || this.Pics == null || this.Pics.Count == 0) { if (forceRefresh || this.Pics == null || this.Pics.Count == 0) {
this.Pics = await api.SomePics(); this.Pics = await api.SomePics();
} }
return this.Pics; return this.Pics;
@ -193,8 +193,16 @@ namespace Neighbourhood.omg.lol.Models {
return CachedAddressPics; return CachedAddressPics;
} }
public async Task RefreshStatuses() => await GetStatuses(forceRefresh: true); public async Task RefreshStatuses() {
public async Task RefreshPics() => await GetPics(forceRefresh: true); await GetStatuses(forceRefresh: true);
if(SelectedAddressName != null)
await GetStatuses(SelectedAddressName, forceRefresh: true);
}
public async Task RefreshPics() {
await GetPics(forceRefresh: true);
if (SelectedAddressName != null)
await GetPics(SelectedAddressName, forceRefresh: true );
}
public async Task RefreshNow() => await GetNowGarden(forceRefresh: true); public async Task RefreshNow() => await GetNowGarden(forceRefresh: true);
} }

View file

@ -117,6 +117,31 @@ namespace Neighbourhood.omg.lol {
return responseData; return responseData;
} }
private async Task<T?> Delete<T>(string uri, CancellationToken cancellationToken = default) where T : IOmgLolResponseData {
T? responseData = default(T);
try {
HttpResponseMessage response = await _client.DeleteAsync(uri, cancellationToken: cancellationToken);
if (response.IsSuccessStatusCode) {
string str = await response.Content.ReadAsStringAsync();
try {
OmgLolResponse<T>? responseObj = await response.Content.ReadFromJsonAsync<OmgLolResponse<T>>(_serializerOptions, cancellationToken: cancellationToken);
if (responseObj != null && responseObj.Request.Success) {
responseData = responseObj.Response;
}
}
catch (JsonException ex) {
Debug.WriteLine(@"\tERROR {0}", ex.Message);
Debug.WriteLine(str);
}
}
}
catch (Exception ex) {
Debug.WriteLine(@"\tERROR {0}", ex.Message);
}
return responseData;
}
public async Task<List<Status>> StatuslogLatest() => public async Task<List<Status>> StatuslogLatest() =>
(await Get<StatusResponseData>("/statuslog/latest"))?.Statuses ?? new List<Status>(); (await Get<StatusResponseData>("/statuslog/latest"))?.Statuses ?? new List<Status>();
@ -170,10 +195,16 @@ namespace Neighbourhood.omg.lol {
public async Task<PutPicResponseData?> PostPicDescription(string address, string id, string description) => public async Task<PutPicResponseData?> PostPicDescription(string address, string id, string description) =>
(await Post<PutPicResponseData, PostPic>($"/address/{address}/pics/{id}", new PostPic { Description = description })); (await Post<PutPicResponseData, PostPic>($"/address/{address}/pics/{id}", new PostPic { Description = description }));
public async Task<DeleteResponseData?> DeletePic(string address, string id) =>
(await Delete<DeleteResponseData>($"/address/{address}/pics/{id}"));
public async Task<PatchStatusResponseData?> PatchStatus(string address, string id, string content, string? emoji) => public async Task<PatchStatusResponseData?> PatchStatus(string address, string id, string content, string? emoji) =>
(await Patch<PatchStatusResponseData, PatchStatus>($"/address/{address}/statuses/", new PatchStatus { Id = id, Content = content, Emoji = emoji })); (await Patch<PatchStatusResponseData, PatchStatus>($"/address/{address}/statuses/", new PatchStatus { Id = id, Content = content, Emoji = emoji }));
public async Task<DeleteResponseData?> DeleteStatus(string address, string id) =>
(await Delete<DeleteResponseData>($"/address/{address}/statuses/{id}"));
public async Task<List<NowData>?> NowGarden() => public async Task<List<NowData>?> NowGarden() =>
(await Get<NowResponseData>($"/now/garden"))?.Garden ?? new List<NowData>(); (await Get<NowResponseData>($"/now/garden"))?.Garden ?? new List<NowData>();

View file

@ -91,7 +91,7 @@ img {
text-indent: -10px; text-indent: -10px;
} }
.status .emoji, #status-emoji { .status .emoji, #status-emoji, #new-status-emoji {
margin-bottom: auto; margin-bottom: auto;
inline-size: 3.5rem; inline-size: 3.5rem;
block-size: 3.5rem; block-size: 3.5rem;