Hosted rooms phase 2: moderators, bans, privacy, invites, images, favorites, ratings, recent rooms, occupancy watch
CI / test (push) Successful in 1m10s

Moderators (up to 20 IMVU accounts, set by ID or name) and the owner account boot
and ban over realtime (room.boot); bans are listed and lifted over REST. Private
rooms are unlisted and joined by the owner, moderators and holders of an accepted
invite (room.invite / room.invited / room.invite_reply / room.invite_answer).
Room images (PNG/JPEG by magic bytes, up to 512 KB) are stored in the database
and served with cache headers. Per-person favorites, ratings and recent rooms.
room.watch pushes room.occupancy; participants carry their IMVU name, and
GET .../participants lists them. Contract in docs/hosted-rooms.md, "Phase 2".

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
dhkatzandClaude Opus 5.5 committed 2026-10-30 06:07:41 -07:00
1 parent 43183ec7ee
commit 76c8e0342e
16 files changed
+3851 -73

No files matched your search

+19 -1
View File
@@ -5,7 +5,10 @@ import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select"
import { Textarea } from "@/components/ui/textarea";
import type { HostedRoom } from "@/lib/api";
export function RoomFields({ room, canAdult }: { room?: HostedRoom; canAdult: boolean }) {
/** The moderators as the edit field shows them: names where known, else IDs. */
const moderatorList = (room: HostedRoom) => room.moderators.map((id, i) => room.moderatorNames[i] || String(id)).join(", ");
export function RoomFields({ room, canAdult, moderators }: { room?: HostedRoom; canAdult: boolean; moderators?: boolean }) {
return (
<>
<Field>
@@ -55,6 +58,21 @@ export function RoomFields({ room, canAdult }: { room?: HostedRoom; canAdult: bo
/>
</Field>
</div>
<Field>
<FieldLabel htmlFor="privacy">Privacy</FieldLabel>
<NativeSelect id="privacy" name="privacy" defaultValue={room?.privacy ?? "public"} className="w-64">
<NativeSelectOption value="public">Public</NativeSelectOption>
<NativeSelectOption value="private">Private</NativeSelectOption>
</NativeSelect>
<FieldDescription>Private: unlisted; only you, moderators and people invited get in.</FieldDescription>
</Field>
{moderators && room && (
<Field>
<FieldLabel htmlFor="moderators">Moderators</FieldLabel>
<Input id="moderators" name="moderators" defaultValue={moderatorList(room)} placeholder="IMVU names or IDs" />
<FieldDescription>Up to 20, comma-separated. They can boot and ban.</FieldDescription>
</Field>
)}
</>
);
}