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

+28
View File
@@ -0,0 +1,28 @@
"use client";
// A hosted room card's favorite star and rating buttons.
import { Star } from "lucide-react";
import { ActionForm, SubmitButton } from "@/components/forms";
import { cn } from "@/lib/utils";
import { rateRoom, setFavorite } from "./actions";
export function RoomActions({ n, favorite, canRate }: { n: number; favorite: boolean; canRate: boolean }) {
return (
<div className="flex flex-wrap items-center gap-3">
<ActionForm action={setFavorite} fields={{ n, favorite: favorite ? "0" : "1" }} className="space-y-0">
<SubmitButton variant="ghost" size="icon" aria-label={favorite ? "Unstar" : "Star"} title={favorite ? "Unstar" : "Star"}>
<Star className={cn("size-4", favorite && "fill-current text-amber-500")} />
</SubmitButton>
</ActionForm>
{canRate && (
<ActionForm action={rateRoom} fields={{ n }} className="flex items-center gap-0.5 space-y-0">
<span className="mr-1 text-xs text-muted-foreground">Rate</span>
{[1, 2, 3, 4, 5].map((k) => (
<SubmitButton key={k} name="score" value={String(k)} variant="ghost" size="xs" aria-label={`${k} of 5`}>
{k}
</SubmitButton>
))}
</ActionForm>
)}
</div>
);
}