"use client" import { useState } from "react" import { Copy, Check, RefreshCw, Loader2, Crown, Shield, UserMinus, ArrowUp, ArrowDown, LogOut, Trash2, } from "lucide-react" import { GlassModal, fieldClass, labelClass } from "./glass-modal" import * as api from "@/lib/api" import { ApiError } from "@/lib/api" import type { Room } from "@/lib/types" import { useRoomMembers } from "@/lib/hooks" const ROLE_LEVEL = { owner: 3, admin: 2, member: 1 } as const interface RoomSettingsDialogProps { room: Room currentUserId: number onClose: () => void onChanged: () => void onLeftOrDeleted: () => void } export function RoomSettingsDialog({ room, currentUserId, onClose, onChanged, onLeftOrDeleted, }: RoomSettingsDialogProps) { const { members, mutate: mutateMembers } = useRoomMembers(room.id) const [name, setName] = useState(room.name) const [inviteCode, setInviteCode] = useState(room.invite_code) const [copied, setCopied] = useState(false) const [busy, setBusy] = useState(null) const [error, setError] = useState(null) const isOwner = room.role === "owner" const isAdmin = room.role === "admin" || isOwner const myLevel = ROLE_LEVEL[room.role] const run = async (key: string, fn: () => Promise, opts?: { refetchMembers?: boolean }) => { setBusy(key) setError(null) try { await fn() if (opts?.refetchMembers) await mutateMembers() onChanged() } catch (err) { setError(err instanceof ApiError ? err.message : "Action failed.") } finally { setBusy(null) } } const copyCode = async () => { try { await navigator.clipboard.writeText(inviteCode) setCopied(true) setTimeout(() => setCopied(false), 1500) } catch { /* clipboard unavailable */ } } const regenerate = () => run("regen", async () => { const res = await api.regenerateInviteCode(room.id) setInviteCode(res.invite_code) }) const rename = () => run("rename", () => api.renameRoom(room.id, name.trim())) const changeRole = (userId: number, role: "member" | "admin") => run(`role-${userId}`, () => api.updateMemberRole(room.id, userId, role), { refetchMembers: true, }) const remove = (userId: number) => run(`remove-${userId}`, () => api.removeMember(room.id, userId), { refetchMembers: true }) const leave = () => run("leave", async () => { await api.leaveRoom(room.id) onLeftOrDeleted() onClose() }) const destroy = () => run("delete", async () => { await api.deleteRoom(room.id) onLeftOrDeleted() onClose() }) return (
{/* Name */}
setName(e.target.value)} disabled={!isAdmin} className={fieldClass} /> {isAdmin && ( )}
{/* Invite code */}
{inviteCode}
{isAdmin && ( )}
{/* Members */}
{members.map((m) => { const targetLevel = ROLE_LEVEL[m.role] const isSelf = m.id === currentUserId const canManageTarget = isAdmin && !isSelf && myLevel > targetLevel return (
{m.username.charAt(0).toUpperCase()}
{m.username} {isSelf && (you)} {m.role === "owner" && } {m.role === "admin" && } {m.role} {/* Owner can promote/demote between member and admin */} {isOwner && !isSelf && m.role === "member" && ( )} {isOwner && !isSelf && m.role === "admin" && ( )} {canManageTarget && ( )}
) })}
{error && (
{error}
)} {/* Danger zone */}
{isOwner && ( )}
) }