CreateChannelDialog.tsx raw
1 import { useChat } from '@/providers/ChatProvider'
2 import { TAccessMode } from '@/services/chat.service'
3 import { Globe, Loader2, Lock, LockOpen } from 'lucide-react'
4 import { useState } from 'react'
5 import { Button } from '../ui/button'
6
7 const accessModes: { mode: TAccessMode; label: string; icon: React.ReactNode; desc: string }[] = [
8 { mode: 'open', label: 'Open', icon: <Globe className="size-3" />, desc: 'Anyone authenticated can read and write' },
9 { mode: 'whitelist', label: 'Whitelist', icon: <Lock className="size-3" />, desc: 'Only listed members can access' },
10 { mode: 'blacklist', label: 'Blacklist', icon: <LockOpen className="size-3" />, desc: 'Everyone except excluded users can access' }
11 ]
12
13 export default function CreateChannelDialog({
14 open,
15 onOpenChange
16 }: {
17 open: boolean
18 onOpenChange: (open: boolean) => void
19 }) {
20 const { createChannel } = useChat()
21 const [name, setName] = useState('')
22 const [about, setAbout] = useState('')
23 const [accessMode, setAccessMode] = useState<TAccessMode>('open')
24 const [isCreating, setIsCreating] = useState(false)
25
26 if (!open) return null
27
28 const handleCreate = async () => {
29 if (!name.trim()) return
30 setIsCreating(true)
31 try {
32 await createChannel(name.trim(), about.trim(), accessMode)
33 setName('')
34 setAbout('')
35 setAccessMode('open')
36 onOpenChange(false)
37 } finally {
38 setIsCreating(false)
39 }
40 }
41
42 const current = accessModes.find((m) => m.mode === accessMode)!
43
44 return (
45 <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50" onClick={() => onOpenChange(false)}>
46 <div
47 className="bg-background border rounded-lg p-4 w-80 space-y-3"
48 onClick={(e) => e.stopPropagation()}
49 >
50 <h3 className="font-semibold">Create Channel</h3>
51 <input
52 type="text"
53 placeholder="Channel name"
54 value={name}
55 onChange={(e) => setName(e.target.value)}
56 className="w-full px-3 py-2 text-sm border rounded-md bg-background"
57 autoFocus
58 onKeyDown={(e) => e.key === 'Enter' && handleCreate()}
59 />
60 <input
61 type="text"
62 placeholder="Description (optional)"
63 value={about}
64 onChange={(e) => setAbout(e.target.value)}
65 className="w-full px-3 py-2 text-sm border rounded-md bg-background"
66 onKeyDown={(e) => e.key === 'Enter' && handleCreate()}
67 />
68 <div className="space-y-1.5">
69 <span className="text-xs text-muted-foreground">Access mode</span>
70 <div className="flex gap-1">
71 {accessModes.map(({ mode, label, icon }) => (
72 <button
73 key={mode}
74 className={`text-xs px-3 py-1.5 rounded border flex items-center gap-1.5 ${accessMode === mode ? 'bg-primary text-primary-foreground border-primary' : 'border-border'}`}
75 onClick={() => setAccessMode(mode)}
76 >
77 {icon} {label}
78 </button>
79 ))}
80 </div>
81 <div className="text-[10px] text-muted-foreground">{current.desc}</div>
82 </div>
83 <div className="flex justify-end gap-2">
84 <Button variant="ghost" size="sm" onClick={() => onOpenChange(false)}>
85 Cancel
86 </Button>
87 <Button size="sm" onClick={handleCreate} disabled={!name.trim() || isCreating}>
88 {isCreating ? <Loader2 className="size-4 animate-spin" /> : 'Create'}
89 </Button>
90 </div>
91 </div>
92 </div>
93 )
94 }
95