Files
decePubClient/Components/ReportDialog.razor
T
thepraandClaude Opus 5.5 6731077191 Dialogs close from a button and rise from the bottom on phones
DModal draws a close button (✕, named by CloseText) beside its heading, in a header that stays in view while the box
scrolls; a long list of who liked a post left only the thin margins around the box to tap out of it. A new
ResponsiveBottom placement makes the box a sheet from the bottom below md and keeps it in the middle from md; the
report, liked-by and boosted-by, edit history and public notice dialogs use it. Boxes are at most 100dvh tall, so a
phone's browser bars don't cut them, and a bottom sheet leaves 3rem above itself and clears the home indicator. The
report dialog gets a Cancel button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
2026-10-06 22:43:35 +02:00

66 lines
2.8 KiB
Plaintext

@inherits LocalizableComponentBase
@* Reports an account, and the post it was opened from, to the persona's server's moderators (/api/v1/reports).
Forwarded, a remote account's server gets the report too, from PrivaPub's own actor: it never names the persona. *@
<DModal Placement="DModalPlacement.ResponsiveBottom" IsOpen="true" IsOpenChanged="Closed" CloseText="@Localizer["Close"]" data-report-dialog>
<Heading>@Localizer["Report {0}", Account.Name]</Heading>
<ChildContent>
<EditForm Model="form" OnValidSubmit="Send" class="flex flex-col gap-3 mt-3">
<DataAnnotationsValidator />
<ErrorViewer AdditionalError="@error" />
<DSelect TValue="ReportCategory" @bind-Value="form.Category" data-report-category>
<option value="@ReportCategory.Spam">@Localizer[nameof(ReportCategory.Spam)]</option>
<option value="@ReportCategory.Legal">@Localizer[nameof(ReportCategory.Legal)]</option>
<option value="@ReportCategory.Other">@Localizer[nameof(ReportCategory.Other)]</option>
</DSelect>
<DTextarea TValue="string" @bind-Value="form.Comment" Immediate="true" rows="3" autocomplete="off" maxlength="@ReportForm.CommentLength"
placeholder="@Localizer["What is wrong with it?"]" data-report-comment />
@if (Host is { } host)
{
<DCheckbox @bind-Value="form.Forward" LabelText="@Localizer["Send a copy to {0}", host]" data-report-forward />
<p class="text-xs opacity-70">@Localizer["The copy comes from the server, never from you."]</p>
}
<div class="flex justify-end gap-2">
<DButton OnClick="() => Closed(false)" data-report-cancel>@Localizer["Cancel"]</DButton>
<DButton Type="submit" Color="DColor.Error" Disabled="@(IsDefaultDisabled || isSending)" data-report-send>@Localizer["Report"]</DButton>
</div>
</EditForm>
</ChildContent>
</DModal>
@code {
[Inject] AccountService AccountService { get; set; }
[Parameter, EditorRequired] public Account Account { get; set; }
/// <summary>The post it was opened from, sent with the report.</summary>
[Parameter] public Status Post { get; set; }
[Parameter] public EventCallback OnClosed { get; set; }
ReportForm form = new();
bool isSending;
string error;
// the account's own server, for a remote account
string Host => Account.Acct?.Split('@') is [_, { Length: > 0 } host] ? host : null;
protected override void OnInitialized() => IsLoading = false;
async Task Send()
{
isSending = true;
error = null;
var result = await AccountService.Report(Account.Id, Post is null ? [] : [Post.Id], form.Comment, form.Category, Host is not null && form.Forward);
isSending = false;
if (result.IsInvalid)
{
Toast.AddResponseError(result);
return;
}
Toast.AddResponseSuccess(Localizer["Report sent to the moderators."]);
await OnClosed.InvokeAsync();
}
Task Closed(bool open) => open ? Task.CompletedTask : OnClosed.InvokeAsync();
}