feat: report page, take action on reports

This commit is contained in:
sam 2025-02-03 17:03:32 +01:00
parent a0ba712632
commit cacd3a30b7
Signed by: sam
GPG key ID: B4EF20DDE721CAA1
14 changed files with 502 additions and 14 deletions

View file

@ -0,0 +1,73 @@
<script lang="ts">
import { ClearableField } from "$api/models/moderation";
import FormStatusMarker, { type FormError } from "$components/editor/FormStatusMarker.svelte";
import { TabContent, TabPane } from "@sveltestrap/sveltestrap";
let {
userId,
reportId,
memberId,
form,
}: { userId: string; reportId?: string; memberId?: string; form: FormError } = $props();
let fields = $derived.by(() => {
const fields = [];
for (const value of Object.values(ClearableField)) {
fields.push({ value });
}
return fields;
});
</script>
<form method="POST">
<input type="hidden" name="user" value={userId} />
{#if memberId}
<input type="hidden" name="member" value={memberId} />
{/if}
{#if reportId}
<input type="hidden" name="report" value={reportId} />
{/if}
<FormStatusMarker {form} />
<textarea name="reason" class="form-control" style="height: 200px;"></textarea>
<TabContent>
{#if reportId}
<TabPane tabId="ignore" tab="Ignore">
<button type="submit" formaction="?/ignore" class="btn btn-secondary">Ignore report</button>
</TabPane>
{/if}
<TabPane tabId="warn" tab="Warn" active>
<div class="row row-cols-1 row-cols-lg-2">
{#each fields as field}
<div class="form-check">
<input
class="form-check-input"
type="checkbox"
name="clear-fields"
value={field.value}
id="reason-{field.value}"
/>
<label class="form-check-label" for="reason-{field.value}">
<code>{field.value}</code>
</label>
</div>
{/each}
</div>
<div>
<button type="submit" formaction="?/warn" class="btn btn-danger">Warn user</button>
</div>
</TabPane>
<TabPane tabId="suspend" tab="Suspend">
<div class="form-check">
<input
class="form-check-input"
type="checkbox"
value="yes"
name="clear-profile"
id="clear-profile"
/>
<label class="form-check-label" for="clear-profile">Clear the user's profile?</label>
</div>
<button type="submit" formaction="?/suspend" class="btn btn-danger">Suspend user</button>
</TabPane>
</TabContent>
</form>

View file

@ -0,0 +1,29 @@
<script lang="ts">
import type { PartialUser } from "$api/models";
import Avatar from "$components/Avatar.svelte";
import { idTimestamp } from "$lib";
import { t } from "$lib/i18n";
import { DateTime } from "luxon";
type Props = { user: PartialUser };
let { user }: Props = $props();
let createdAt = $derived(idTimestamp(user.id).toLocaleString(DateTime.DATETIME_SHORT));
</script>
<div class="text-center">
<a href="/@{user.username}">
<Avatar
name={user.username}
url={user.avatar_url}
lazyLoad
alt={$t("avatar-tooltip", { name: "@" + user.username })}
/>
</a>
<p class="m-2">
<a class="text-reset fs-5 text-break" href="/@{user.username}">
@{user.username}
</a>
</p>
<p>Created {createdAt}</p>
</div>

View file

@ -1,10 +1,14 @@
<script module lang="ts">
export type FormError = { error: RawApiError | null; ok: boolean } | null;
</script>
<script lang="ts">
import { Icon } from "@sveltestrap/sveltestrap";
import { t } from "$lib/i18n";
import type { RawApiError } from "$api/error";
import ErrorAlert from "$components/ErrorAlert.svelte";
type Props = { form: { error: RawApiError | null; ok: boolean } | null; successMessage?: string };
type Props = { form: FormError | null; successMessage?: string };
let { form, successMessage }: Props = $props();
</script>