File size: 4,169 Bytes
00a912e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | import { useEffect, useState } from 'react'
import { Lock, Music, Loader2 } from 'lucide-react'
import { LIMITS } from '@music-together/shared'
import {
ResponsiveDialog,
ResponsiveDialogBody,
ResponsiveDialogContent,
ResponsiveDialogHeader,
ResponsiveDialogTitle,
} from '@/components/ui/responsive-dialog'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import { Switch } from '@/components/ui/switch'
import { Label } from '@/components/ui/label'
interface CreateRoomDialogProps {
open: boolean
onOpenChange: (open: boolean) => void
onCreateRoom: (nickname: string, roomName?: string, password?: string) => void
defaultNickname: string
isLoading: boolean
}
export function CreateRoomDialog({
open,
onOpenChange,
onCreateRoom,
defaultNickname,
isLoading,
}: CreateRoomDialogProps) {
const [nickname, setNickname] = useState(defaultNickname)
const [roomName, setRoomName] = useState('')
const [passwordEnabled, setPasswordEnabled] = useState(false)
const [password, setPassword] = useState('')
useEffect(() => {
if (!open) return
const frame = requestAnimationFrame(() => setNickname(defaultNickname))
return () => cancelAnimationFrame(frame)
}, [open, defaultNickname])
const canSubmit = nickname.trim() && !(passwordEnabled && !password.trim())
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
if (!canSubmit) return
onCreateRoom(
nickname.trim(),
roomName.trim() || undefined,
passwordEnabled && password.trim() ? password.trim() : undefined,
)
}
return (
<ResponsiveDialog open={open} onOpenChange={onOpenChange}>
<ResponsiveDialogContent className="sm:max-w-md">
<ResponsiveDialogHeader>
<ResponsiveDialogTitle className="flex items-center gap-2 text-lg">
<Music className="h-5 w-5 text-primary" />
创建房间
</ResponsiveDialogTitle>
</ResponsiveDialogHeader>
<ResponsiveDialogBody>
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label className="text-sm font-medium text-foreground/80">昵称</Label>
<Input
placeholder="你的昵称..."
value={nickname}
onChange={(e) => setNickname(e.target.value)}
maxLength={LIMITS.NICKNAME_MAX_LENGTH}
autoFocus
/>
</div>
<div className="space-y-2">
<Label className="text-sm font-medium text-foreground/80">房间名 (可选)</Label>
<Input
placeholder="给房间起个名字..."
value={roomName}
onChange={(e) => setRoomName(e.target.value)}
maxLength={LIMITS.ROOM_NAME_MAX_LENGTH}
/>
</div>
<div className="space-y-3">
<div className="flex items-center gap-2">
<Switch id="password-toggle" checked={passwordEnabled} onCheckedChange={setPasswordEnabled} />
<Label
htmlFor="password-toggle"
className="flex cursor-pointer items-center gap-1.5 text-sm text-muted-foreground"
>
<Lock className="h-3.5 w-3.5" />
设置密码
</Label>
</div>
{passwordEnabled && (
<Input
type="password"
placeholder="设置房间密码..."
value={password}
onChange={(e) => setPassword(e.target.value)}
maxLength={LIMITS.ROOM_PASSWORD_MAX_LENGTH}
autoFocus
/>
)}
</div>
<Button type="submit" className="w-full" size="lg" disabled={isLoading || !canSubmit}>
{isLoading ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : null}
创建房间
</Button>
</form>
</ResponsiveDialogBody>
</ResponsiveDialogContent>
</ResponsiveDialog>
)
}
|