@inherits LocalizableComponentBase @* The accounts the current persona muted or blocked (/api/v1/mutes, /api/v1/blocks), and the servers it blocked (/api/v1/domain_blocks), each one undone here. A server blocked hides everything from it and removes the persona's followers there. *@ @if (IsLoading) {

@Localizer["loading"]

} else {

@Localizer["Muted accounts"]

@if (mutes.Count == 0) {

@Localizer["Nobody is muted."]

} @foreach (var account in mutes) {
@account.Name @@@account.Acct @Localizer["Unmute"]
} @if (mutesMaxId is not null) { @Localizer["Load more"] }

@Localizer["Blocked accounts"]

@if (blocks.Count == 0) {

@Localizer["Nobody is blocked."]

} @foreach (var account in blocks) {
@account.Name @@@account.Acct @Localizer["Unblock"]
} @if (blocksMaxId is not null) { @Localizer["Load more"] }

@Localizer["Blocked servers"]

@Localizer["Block server"] @if (domains.Count == 0) {

@Localizer["No server is blocked."]

} @foreach (var domain in domains) {
@domain @Localizer["Unblock"]
}
} @code { [Inject] AccountService AccountService { get; set; } sealed class DomainDraft { public string Domain { get; set; } } List mutes = []; List blocks = []; List domains = []; string mutesMaxId; string blocksMaxId; DomainDraft draft = new(); // the accounts and servers whose undo is on its way HashSet busy = []; string loadedPersonaId; protected override async Task OnParametersSetAsync() { if (CascadingState.PersonaId == loadedPersonaId) return; loadedPersonaId = CascadingState.PersonaId; if (CascadingState.IsOffline) { WhenOnline(LoadData); StartOnlinePolling(); IsLoading = false; return; } await LoadData(); IsLoading = false; } async Task LoadData() { mutes = []; blocks = []; mutesMaxId = null; blocksMaxId = null; await Task.WhenAll(MoreMutes(), MoreBlocks()); domains = await AccountService.DomainBlocks(); } async Task MoreMutes() { var result = await AccountService.Mutes(mutesMaxId); if (result.IsInvalid) { Toast.AddResponseError(result); return; } var page = (AccountPage)result.Data; mutes.AddRange(page.Accounts.Where(a => mutes.All(m => m.Id != a.Id))); mutesMaxId = page.MaxId; } async Task MoreBlocks() { var result = await AccountService.Blocks(blocksMaxId); if (result.IsInvalid) { Toast.AddResponseError(result); return; } var page = (AccountPage)result.Data; blocks.AddRange(page.Accounts.Where(a => blocks.All(b => b.Id != a.Id))); blocksMaxId = page.MaxId; } async Task Undo(Account account, AccountAction action) { busy.Add(account.Id); var result = await AccountService.Act(account.Id, action); busy.Remove(account.Id); if (result.IsInvalid) { Toast.AddResponseError(result); return; } if (action is AccountAction.Unmute) mutes.RemoveAll(m => m.Id == account.Id); else blocks.RemoveAll(b => b.Id == account.Id); } // what a person types as a server (a URL, a handle's host, any case) as the bare host PrivaPub keys it by static string Domain(string typed) { var text = typed?.Trim().TrimStart('@') ?? ""; if (Uri.TryCreate(text.Contains("://") ? text : "https://" + text, UriKind.Absolute, out var uri)) text = uri.Host; return text.ToLowerInvariant(); } async Task BlockDomain() { var domain = Domain(draft.Domain); if (domain.Length == 0 || domains.Contains(domain)) { draft = new(); return; } busy.Add(domain); var result = await AccountService.BlockDomain(domain); busy.Remove(domain); if (result.IsInvalid) { Toast.AddResponseError(result); return; } draft = new(); domains = [.. domains.Append(domain).Order()]; Toast.AddResponseSuccess(Localizer["{0} is blocked.", domain]); } async Task UnblockDomain(string domain) { busy.Add(domain); var result = await AccountService.UnblockDomain(domain); busy.Remove(domain); if (result.IsInvalid) { Toast.AddResponseError(result); return; } domains.Remove(domain); } }