Spaces:
Sleeping
Sleeping
| import React, { useState } from 'react'; | |
| import { Users, MailPlus } from 'lucide-react'; | |
| import { Badge } from './ui/badge'; | |
| import { Button } from './ui/button'; | |
| import { Input } from './ui/input'; | |
| import { toast } from 'sonner'; | |
| import { | |
| Dialog, | |
| DialogContent, | |
| DialogDescription, | |
| DialogFooter, | |
| DialogHeader, | |
| DialogTitle, | |
| } from './ui/dialog'; | |
| import clareAvatar from '../assets/dfe44dab3ad8cd93953eac4a3e68bd1a5f999653.png'; | |
| import type { GroupMember } from '../App'; | |
| interface GroupMembersProps { | |
| members: GroupMember[]; | |
| } | |
| export function GroupMembers({ members }: GroupMembersProps) { | |
| const [inviteOpen, setInviteOpen] = useState(false); | |
| const [inviteEmail, setInviteEmail] = useState(''); | |
| const handleSendInvite = () => { | |
| if (!inviteEmail.trim()) { | |
| toast.error('Please enter an email to invite'); | |
| return; | |
| } | |
| toast.success(`Invitation sent to ${inviteEmail}`); | |
| setInviteEmail(''); | |
| setInviteOpen(false); | |
| }; | |
| return ( | |
| <div className="space-y-3"> | |
| <div className="flex items-center justify-between gap-2"> | |
| <div className="flex items-center gap-2"> | |
| <Users className="h-4 w-4 text-muted-foreground" /> | |
| <h3 className="text-sm">Group Members ({members.length})</h3> | |
| </div> | |
| <Button | |
| size="sm" | |
| variant="secondary" | |
| className="h-8 gap-2" | |
| onClick={() => setInviteOpen(true)} | |
| > | |
| <MailPlus className="h-4 w-4" /> | |
| <span className="text-xs font-medium">Invite</span> | |
| </Button> | |
| </div> | |
| <div className="space-y-2"> | |
| {members.map((member) => { | |
| const isAI = !!member.isAI; | |
| return ( | |
| <div | |
| key={member.id} | |
| className="flex items-center gap-3 p-2 rounded-lg hover:bg-muted/50 transition-colors" | |
| > | |
| {/* Avatar */} | |
| <div className={`w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0 ${ | |
| isAI | |
| ? 'overflow-hidden bg-white' | |
| : 'bg-muted' | |
| }`}> | |
| {isAI ? ( | |
| <img src={clareAvatar} alt="Clare" className="w-full h-full object-cover" /> | |
| ) : ( | |
| <span className="text-sm"> | |
| {member.name.split(' ').map(n => n[0]).join('').toUpperCase()} | |
| </span> | |
| )} | |
| </div> | |
| {/* Member Info */} | |
| <div className="flex-1 min-w-0"> | |
| <div className="flex items-center gap-2"> | |
| <p className="text-sm truncate">{member.name}</p> | |
| {isAI && ( | |
| <Badge variant="secondary" className="text-xs">AI</Badge> | |
| )} | |
| </div> | |
| <p className="text-xs text-muted-foreground truncate">{member.email}</p> | |
| </div> | |
| {/* Online Status */} | |
| <div className="w-2 h-2 rounded-full bg-green-500 flex-shrink-0" title="Online" /> | |
| </div> | |
| )})} | |
| </div> | |
| <Dialog open={inviteOpen} onOpenChange={setInviteOpen}> | |
| <DialogContent className="w-[600px] max-w-[600px] sm:max-w-[600px]" style={{ maxWidth: 600 }}> | |
| <DialogHeader> | |
| <DialogTitle>Invite member</DialogTitle> | |
| <DialogDescription>Send a quick email invite with the team details.</DialogDescription> | |
| </DialogHeader> | |
| <div className="space-y-3"> | |
| <Input | |
| type="email" | |
| placeholder="name@example.com" | |
| value={inviteEmail} | |
| onChange={(e) => setInviteEmail(e.target.value)} | |
| /> | |
| <p className="text-xs text-muted-foreground"> | |
| An invitation email with a join link will be sent to this address. | |
| </p> | |
| </div> | |
| <DialogFooter> | |
| <Button variant="outline" onClick={() => setInviteOpen(false)}>Cancel</Button> | |
| <Button onClick={handleSendInvite}>Send invite</Button> | |
| </DialogFooter> | |
| </DialogContent> | |
| </Dialog> | |
| </div> | |
| ); | |
| } |