| "use client"; | |
| import { useState, useEffect } from 'react'; | |
| import { useAuth } from '@/contexts/auth-context'; | |
| import { useContacts } from '@/contexts/contacts-context'; | |
| import { useGroups } from '@/contexts/groups-context'; | |
| import { useSettings } from '@/contexts/settings-context'; | |
| import { Button } from '@/components/ui/button'; | |
| import { Input } from '@/components/ui/input'; | |
| import { Label } from '@/components/ui/label'; | |
| import { Checkbox } from './ui/checkbox'; | |
| import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'; | |
| import type { GroupType } from '@/lib/types'; | |
| import { RadioGroup, RadioGroupItem } from './ui/radio-group'; | |
| import { Book, Gamepad2, Users, Heart, ArrowLeft, X } from 'lucide-react'; | |
| import { cn } from '@/lib/utils'; | |
| import { ScrollArea } from './ui/scroll-area'; | |
| export function CreateGroupModal({ isOpen, onClose }: { isOpen: boolean; onClose: () => void }) { | |
| const { currentUser } = useAuth(); | |
| const { contacts } = useContacts(); | |
| const { createGroup } = useGroups(); | |
| const { addToast, t, playSound } = useSettings(); | |
| const [groupName, setGroupName] = useState(''); | |
| const [photoURL, setPhotoURL] = useState(''); | |
| const [selectedContacts, setSelectedContacts] = useState<string[]>([]); | |
| const [groupType, setGroupType] = useState<GroupType>('general'); | |
| const [isLoading, setIsLoading] = useState(false); | |
| useEffect(() => { | |
| if (currentUser && isOpen) { | |
| setSelectedContacts([currentUser.uid]); | |
| setGroupName(''); | |
| setPhotoURL(''); | |
| setGroupType('general'); | |
| } | |
| }, [currentUser, isOpen]); | |
| const handleToggleContact = (uid: string) => { | |
| if (uid === currentUser?.uid) return; | |
| playSound('touch'); | |
| setSelectedContacts(prev => | |
| prev.includes(uid) ? prev.filter(id => id !== uid) : [...prev, uid] | |
| ); | |
| }; | |
| const handleCreate = async () => { | |
| if (!groupName.trim()) { | |
| addToast('Please enter a name for the group.', { variant: 'destructive' }); | |
| return; | |
| } | |
| if (!currentUser) return; | |
| setIsLoading(true); | |
| playSound('send'); | |
| const memberUids = selectedContacts.filter(uid => uid !== currentUser.uid); | |
| await createGroup(groupName, photoURL, memberUids, groupType); | |
| setIsLoading(false); | |
| onClose(); | |
| }; | |
| const groupTypeOptions = [ | |
| { id: 'general', label: t('general') }, | |
| { id: 'study', label: t('study') }, | |
| { id: 'gaming', label: t('gaming') }, | |
| { id: 'friends', label: t('friends') }, | |
| ]; | |
| if (!isOpen || !currentUser) return null; | |
| return ( | |
| <div className="absolute inset-0 z-50 flex flex-col h-full bg-background/80 backdrop-blur-md animate-fade-in md:items-center md:justify-center md:bg-black/50"> | |
| <div className="w-full h-full flex flex-col bg-background md:max-w-2xl md:h-auto md:max-h-[90vh] md:rounded-xl md:border md:shadow-lg"> | |
| <header className="flex-shrink-0 flex items-center justify-between gap-4 p-4 border-b bg-card/80 backdrop-blur-sm z-10 sticky top-0 md:rounded-t-xl"> | |
| <div className='flex items-center gap-2'> | |
| <Button onClick={onClose} variant="ghost" size="icon"> | |
| <X /> | |
| </Button> | |
| <h1 className="text-xl font-bold">{t('createGroupTitle')}</h1> | |
| </div> | |
| <Button onClick={handleCreate} disabled={isLoading || !groupName.trim()} className="btn-gradient"> | |
| {isLoading ? 'Creating...' : t('createGroupTitle')} | |
| </Button> | |
| </header> | |
| <ScrollArea className="flex-1"> | |
| <main className="p-4 md:p-8 w-full space-y-8"> | |
| <div className="space-y-4"> | |
| <div className="space-y-2"> | |
| <Label htmlFor="group-name">{t('groupName')}</Label> | |
| <Input id="group-name" value={groupName} onChange={e => setGroupName(e.target.value)} /> | |
| </div> | |
| <div className="space-y-2"> | |
| <Label htmlFor="group-photo">{t('groupPhotoUrl')}</Label> | |
| <Input id="group-photo" value={photoURL} onChange={e => setPhotoURL(e.target.value)} placeholder="https://example.com/image.png" /> | |
| </div> | |
| <div className="space-y-2"> | |
| <Label>{t('groupType')}</Label> | |
| <RadioGroup value={groupType} onValueChange={(value) => setGroupType(value as GroupType)} className="grid grid-cols-2 lg:grid-cols-4 gap-2"> | |
| {groupTypeOptions.map(option => ( | |
| <Label | |
| key={option.id} | |
| htmlFor={option.id} | |
| className={cn( | |
| "flex items-center gap-3 p-3 border rounded-lg cursor-pointer transition-colors", | |
| "hover:bg-muted", | |
| groupType === option.id && "bg-primary text-primary-foreground border-primary" | |
| )} | |
| > | |
| <RadioGroupItem value={option.id as string} id={option.id} className="sr-only"/> | |
| {option.id === 'general' && <Users className="h-5 w-5" />} | |
| {option.id === 'study' && <Book className="h-5 w-5" />} | |
| {option.id === 'gaming' && <Gamepad2 className="h-5 w-5" />} | |
| {option.id === 'friends' && <Heart className="h-5 w-5" />} | |
| <span>{option.label}</span> | |
| </Label> | |
| ))} | |
| </RadioGroup> | |
| </div> | |
| <div> | |
| <Label>{t('inviteMembers')}</Label> | |
| <div className="max-h-60 overflow-y-auto border rounded-lg p-2 mt-2 space-y-2"> | |
| <div className="flex items-center justify-between p-2 rounded-lg bg-muted/50"> | |
| <Label htmlFor={`contact-${currentUser.uid}`} className="flex items-center gap-3 cursor-not-allowed"> | |
| <Avatar> | |
| <AvatarImage src={currentUser.photoURL} alt={currentUser.displayName} /> | |
| <AvatarFallback>{currentUser.displayName.charAt(0)}</AvatarFallback> | |
| </Avatar> | |
| <span className="font-medium">{currentUser.displayName} {t('you')}</span> | |
| </Label> | |
| <Checkbox | |
| id={`contact-${currentUser.uid}`} | |
| checked={true} | |
| disabled | |
| /> | |
| </div> | |
| {contacts.length > 0 ? contacts.map(contact => ( | |
| <div key={contact.uid} className="flex items-center justify-between p-2 rounded-lg hover:bg-muted"> | |
| <Label htmlFor={`contact-${contact.uid}`} className="flex items-center gap-3 cursor-pointer flex-1"> | |
| <Avatar> | |
| <AvatarImage src={contact.photoURL} alt={contact.name} /> | |
| <AvatarFallback>{contact.name.charAt(0)}</AvatarFallback> | |
| </Avatar> | |
| <span className="font-medium">{contact.name}</span> | |
| </Label> | |
| <Checkbox | |
| id={`contact-${contact.uid}`} | |
| checked={selectedContacts.includes(contact.uid)} | |
| onCheckedChange={() => handleToggleContact(contact.uid)} | |
| /> | |
| </div> | |
| )) : <p className="text-muted-foreground text-center text-sm p-4">{t('noContactsToInvite')}</p>} | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| </ScrollArea> | |
| </div> | |
| </div> | |
| ); | |
| } | |