fix(housekeeping): address task 14 review round 1

This commit is contained in:
Simo committed 2026-08-30 10:53:50 +02:00
1 parent fd68819d9b
commit d09eaa33d6
23 files changed
+2503 -488

No files matched your search

@@ -1,34 +1,407 @@
import { PERMS } from "@/lib/permission-slugs";
import type { HousekeepingPageInput } from "../../../route-handlers";
import { contentQuery } from "../queries/content-queries";
import { ContentCommandForm } from "./content-command-form";
import { ContentPageFrame, type ContentPageProps, parseContentListInput } from "./content-page-frame";
import {
type ContentCommandField,
ContentCommandForm,
} from "./content-command-form";
import {
ContentPageFrame,
type ContentPageProps,
parseContentListInput,
} from "./content-page-frame";
export function ContentEngagementPage({ context, result, routeId }: ContentPageProps) {
export function ContentEngagementPage({
context,
result,
routeId,
}: ContentPageProps) {
const canEvents = context.has(PERMS.EVENTS_EDIT);
const canPolls = context.has(PERMS.POLLS_EDIT);
const canPrefixes = context.has(PERMS.PREFIXES_EDIT);
return <ContentPageFrame title="Engagement" description="Manage events, polls, and community prefixes." result={result} forms={<div className="grid gap-3 lg:grid-cols-2">
{canEvents && routeId === "content.engagement.event-types" ? <ContentCommandForm commandId="content.engagement.event-type.change" buttonLabel="Save event type" input={{ action: "update" }} fields={[{ name: "id", label: "Type ID", type: "identifier" }, { name: "name", label: "Name", type: "text", required: true, maxLength: 255 }]} /> : null}
{canEvents && routeId?.includes("event") && routeId !== "content.engagement.event-types" ? <>
<ContentCommandForm commandId="content.engagement.event.change" buttonLabel="Save event" input={{ action: routeId.endsWith("create") ? "create" : "update" }} fields={[{ name: "id", label: "Event ID", type: "identifier" }, { name: "title", label: "Title", type: "text", required: true, maxLength: 255 }]} />
<ContentCommandForm commandId="content.engagement.event-prize.change" buttonLabel="Save prize" input={{ action: "create" }} fields={[{ name: "eventId", label: "Event ID", type: "identifier", required: true }, { name: "prize", label: "Prize", type: "text", required: true, maxLength: 255 }]} />
<ContentCommandForm commandId="content.engagement.event-winner.add" buttonLabel="Add winner" input={{}} fields={[{ name: "eventId", label: "Event ID", type: "identifier", required: true }, { name: "userId", label: "User ID", type: "identifier", required: true }]} />
</> : null}
{canPolls && routeId?.includes("poll") ? <>
<ContentCommandForm commandId="content.engagement.poll.change" buttonLabel="Save poll" input={{ action: routeId.endsWith("create") ? "create" : "update" }} fields={[{ name: "id", label: "Poll ID", type: "identifier" }, { name: "title", label: "Title", type: "text", required: true, maxLength: 255 }]} />
<ContentCommandForm commandId="content.engagement.poll-question.change" buttonLabel="Save question" input={{ action: "create" }} fields={[{ name: "pollId", label: "Poll ID", type: "identifier", required: true }, { name: "question", label: "Question", type: "text", required: true, maxLength: 500 }]} />
</> : null}
{canPrefixes && routeId === "content.engagement.prefixes" ? <>
<ContentCommandForm commandId="content.engagement.prefix.change" buttonLabel="Save prefix" input={{ action: "update" }} fields={[{ name: "id", label: "Prefix ID", type: "identifier" }, { name: "text", label: "Text", type: "text", required: true, maxLength: 64 }]} />
<ContentCommandForm commandId="content.engagement.prefix-blacklist.change" buttonLabel="Update blacklist" input={{ action: "add" }} fields={[{ name: "word", label: "Word", type: "text", required: true, maxLength: 255 }]} />
<ContentCommandForm commandId="content.engagement.prefix-settings.update" buttonLabel="Save prefix settings" input={{}} fields={[{ name: "enabled", label: "Enable prefixes", type: "checkbox" }]} />
</> : null}
</div>} />;
const creatingEvent = routeId === "content.engagement.event-create";
const creatingPoll = routeId === "content.engagement.poll-create";
const eventFields: readonly ContentCommandField[] = [
{
name: "id",
label: "Event ID",
type: "identifier",
required: !creatingEvent,
},
{
name: "title",
label: "Title",
type: "text",
required: creatingEvent,
maxLength: 255,
},
{
name: "description",
label: "Description",
type: "textarea",
required: creatingEvent,
maxLength: 20_000,
},
{
name: "typeId",
label: "Event type ID",
type: "identifier",
required: creatingEvent,
},
{ name: "roomId", label: "Room ID", type: "identifier" },
{
name: "startsAt",
label: "Starts at",
type: "text",
required: creatingEvent,
maxLength: 50,
},
{ name: "endsAt", label: "Ends at", type: "text", maxLength: 50 },
{ name: "maxPlayers", label: "Maximum players", type: "number", min: 1 },
{ name: "isRecurring", label: "Recurring", type: "checkbox" },
{
name: "recurrenceRule",
label: "Recurrence rule",
type: "text",
maxLength: 255,
},
{
name: "status",
label: "Status",
type: "select",
options: [
{ value: "draft", label: "Draft" },
{ value: "published", label: "Published" },
{ value: "cancelled", label: "Cancelled" },
{ value: "completed", label: "Completed" },
],
},
{ name: "image", label: "Image URL", type: "text", maxLength: 500 },
];
const pollFields: readonly ContentCommandField[] = [
{
name: "id",
label: "Poll ID",
type: "identifier",
required: !creatingPoll,
},
{
name: "title",
label: "Title",
type: "text",
required: creatingPoll,
maxLength: 255,
},
{
name: "description",
label: "Description",
type: "textarea",
maxLength: 2_000,
},
{
name: "status",
label: "Status",
type: "select",
options: [
{ value: "draft", label: "Draft" },
{ value: "active", label: "Active" },
{ value: "closed", label: "Closed" },
],
},
{ name: "showResults", label: "Show results", type: "checkbox" },
{
name: "multipleChoice",
label: "Allow multiple choices",
type: "checkbox",
},
{ name: "startsAt", label: "Starts at", type: "text", maxLength: 50 },
{ name: "endsAt", label: "Ends at", type: "text", maxLength: 50 },
];
return (
<ContentPageFrame
title="Engagement"
description="Manage events, polls, and community prefixes."
result={result}
forms={
<div className="grid gap-3 lg:grid-cols-2">
{canEvents && routeId === "content.engagement.event-types" ? (
<ContentCommandForm
commandId="content.engagement.event-type.change"
buttonLabel="Save event type"
input={{ action: "update" }}
fields={[
{
name: "id",
label: "Type ID",
type: "identifier",
required: true,
},
{ name: "name", label: "Name", type: "text", maxLength: 100 },
{ name: "slug", label: "Slug", type: "text", maxLength: 100 },
{
name: "description",
label: "Description",
type: "textarea",
maxLength: 500,
},
{ name: "color", label: "Color", type: "text", maxLength: 20 },
{ name: "icon", label: "Icon", type: "text", maxLength: 50 },
{ name: "isActive", label: "Active", type: "checkbox" },
{
name: "minRank",
label: "Minimum rank",
type: "number",
min: 0,
max: 7,
},
]}
/>
) : null}
{canEvents &&
routeId?.includes("event") &&
routeId !== "content.engagement.event-types" ? (
<>
<ContentCommandForm
commandId="content.engagement.event.change"
buttonLabel="Save event"
input={{ action: creatingEvent ? "create" : "update" }}
fields={eventFields}
/>
<ContentCommandForm
commandId="content.engagement.event-prize.change"
buttonLabel="Save prize"
input={{ action: "create" }}
fields={[
{
name: "eventId",
label: "Event ID",
type: "identifier",
required: true,
},
{
name: "position",
label: "Position",
type: "number",
min: 1,
defaultValue: 1,
},
{
name: "prizeType",
label: "Prize type",
type: "select",
options: [
{ value: "badge", label: "Badge" },
{ value: "credits", label: "Credits" },
{ value: "pixels", label: "Pixels" },
{ value: "points", label: "Points" },
{ value: "item", label: "Item" },
],
},
{
name: "badgeCode",
label: "Badge code",
type: "text",
maxLength: 50,
},
{
name: "credits",
label: "Credits",
type: "number",
min: 0,
defaultValue: 0,
},
{
name: "pixels",
label: "Pixels",
type: "number",
min: 0,
defaultValue: 0,
},
{
name: "points",
label: "Points",
type: "number",
min: 0,
defaultValue: 0,
},
{ name: "itemId", label: "Item ID", type: "identifier" },
{
name: "description",
label: "Description",
type: "text",
maxLength: 255,
},
]}
/>
<ContentCommandForm
commandId="content.engagement.event-winner.add"
buttonLabel="Add winner"
input={{}}
fields={[
{
name: "eventId",
label: "Event ID",
type: "identifier",
required: true,
},
{
name: "userId",
label: "User ID",
type: "identifier",
required: true,
},
{
name: "position",
label: "Position",
type: "number",
min: 1,
defaultValue: 1,
},
]}
/>
</>
) : null}
{canPolls && routeId?.includes("poll") ? (
<>
<ContentCommandForm
commandId="content.engagement.poll.change"
buttonLabel="Save poll"
input={{ action: creatingPoll ? "create" : "update" }}
fields={pollFields}
/>
<ContentCommandForm
commandId="content.engagement.poll-question.change"
buttonLabel="Save question"
input={{ action: "create" }}
fields={[
{
name: "pollId",
label: "Poll ID",
type: "identifier",
required: true,
},
{
name: "question",
label: "Question",
type: "text",
required: true,
maxLength: 500,
},
{
name: "type",
label: "Question type",
type: "select",
options: [
{ value: "single", label: "Single choice" },
{ value: "multiple", label: "Multiple choice" },
{ value: "text", label: "Free text" },
],
},
{
name: "sortOrder",
label: "Sort order",
type: "number",
min: 0,
defaultValue: 0,
},
{
name: "options",
label: "Options",
type: "textarea",
required: true,
maxLength: 20_000,
},
]}
/>
</>
) : null}
{canPrefixes && routeId === "content.engagement.prefixes" ? (
<>
<ContentCommandForm
commandId="content.engagement.prefix.change"
buttonLabel="Save prefix"
input={{ action: "update" }}
fields={[
{
name: "id",
label: "Prefix ID",
type: "identifier",
required: true,
},
{
name: "text",
label: "Text",
type: "text",
required: true,
maxLength: 255,
},
{
name: "color",
label: "Color",
type: "text",
required: true,
maxLength: 32,
},
{ name: "icon", label: "Icon", type: "text", maxLength: 255 },
{
name: "effect",
label: "Effect",
type: "text",
maxLength: 255,
},
{ name: "active", label: "Active", type: "checkbox" },
]}
/>
<ContentCommandForm
commandId="content.engagement.prefix-blacklist.change"
buttonLabel="Update blacklist"
input={{ action: "add" }}
fields={[
{
name: "word",
label: "Word",
type: "text",
required: true,
maxLength: 255,
},
]}
/>
<ContentCommandForm
commandId="content.engagement.prefix-settings.update"
buttonLabel="Save prefix settings"
input={{}}
fields={[
{
name: "settings",
label: "Prefix settings JSON",
type: "json",
required: true,
maxLength: 20_000,
},
]}
/>
</>
) : null}
</div>
}
/>
);
}
export async function renderContentEngagementPage(input: HousekeepingPageInput) {
export async function renderContentEngagementPage(
input: HousekeepingPageInput,
) {
const routeId = input.match.routeId as ContentPageProps["routeId"];
const result = await contentQuery.run(input.context, { routeId: routeId ?? "content.engagement.events", params: input.match.params, list: parseContentListInput(input.searchParams ?? {}) });
return <ContentEngagementPage context={input.context} result={result} routeId={routeId} />;
const result = await contentQuery.run(input.context, {
routeId: routeId ?? "content.engagement.events",
params: input.match.params,
list: parseContentListInput(input.searchParams ?? {}),
});
return (
<ContentEngagementPage
context={input.context}
result={result}
routeId={routeId}
/>
);
}