'use client' import { useState, useEffect, useCallback } from 'react' import { useTranslations } from 'next-intl' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Badge } from '@/components/ui/badge' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { useToast } from '@/components/ui/use-toast' import { useCompany } from '@/contexts/CompanyContext' import { formatDateLong } from '@/lib/utils' import { Loader2, Plus, Trash2, Mail, Clock, Users } from 'lucide-react' interface CompanyMemberItem { id: string user_id: string email: string role: string source: 'direct' | 'team' joined_at: string is_current_user: boolean } interface CompanyInvitation { id: string email: string role: string status: string expires_at: string created_at: string } export function CompanyMembersSection() { const t = useTranslations('settings_company') const { toast } = useToast() const { company } = useCompany() const roleLabels: Record = { owner: t('members_role_owner'), admin: t('members_role_admin'), member: t('members_role_member'), viewer: t('members_role_viewer'), } const [isLoading, setIsLoading] = useState(true) const [members, setMembers] = useState([]) const [invitations, setInvitations] = useState([]) const [inviteEmail, setInviteEmail] = useState('') const [inviteRole, setInviteRole] = useState('viewer') const [isSending, setIsSending] = useState(false) const [removingId, setRemovingId] = useState(null) const [revokingId, setRevokingId] = useState(null) const [canInvite, setCanInvite] = useState(false) const fetchMembers = useCallback(async () => { try { const res = await fetch('/api/company/members') const data = await res.json() if (res.ok) { setMembers(data.data.members) setInvitations(data.data.invitations) setCanInvite(data.data.canInvite) } } catch { // Silently fail } finally { setIsLoading(false) } }, []) useEffect(() => { fetchMembers() }, [fetchMembers]) const handleInvite = async (e: React.FormEvent) => { e.preventDefault() const email = inviteEmail.trim().toLowerCase() if (!email) return setIsSending(true) try { const res = await fetch('/api/company/members/invite', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, role: inviteRole }), }) const data = await res.json() if (!res.ok) { toast({ title: data.error, variant: 'destructive' }) return } if (data.data.inviteUrl) { console.log('[DEV] Company invite URL:', data.data.inviteUrl) } toast({ title: t('members_invite_sent_title'), description: data.data.inviteUrl ? t('members_invite_sent_dev_url') : t('members_invite_sent_description', { email }), }) setInviteEmail('') setInviteRole('viewer') fetchMembers() } catch { toast({ title: t('members_invite_failed'), variant: 'destructive' }) } finally { setIsSending(false) } } const handleRemoveMember = async (memberId: string) => { setRemovingId(memberId) try { const res = await fetch(`/api/company/members/${memberId}`, { method: 'DELETE' }) const data = await res.json() if (!res.ok) { toast({ title: data.error, variant: 'destructive' }) return } toast({ title: t('members_removed') }) fetchMembers() } catch { toast({ title: t('members_remove_failed'), variant: 'destructive' }) } finally { setRemovingId(null) } } const handleRevokeInvite = async (inviteId: string) => { setRevokingId(inviteId) try { const res = await fetch(`/api/company/members/invite/${inviteId}`, { method: 'DELETE' }) const data = await res.json() if (!res.ok) { toast({ title: data.error, variant: 'destructive' }) return } toast({ title: t('members_invite_revoked') }) fetchMembers() } catch { toast({ title: t('members_invite_revoke_failed'), variant: 'destructive' }) } finally { setRevokingId(null) } } if (isLoading) { return (
) } return (
{/* Invite form */} {canInvite && ( {t('members_invite_title', { companyName: company?.name ?? '' })} {t('members_invite_description')}
setInviteEmail(e.target.value)} disabled={isSending} required />
)} {/* Members list */} {t('members_title')} {t('members_count', { count: members.length, companyName: company?.name ?? '' })}
{members.map((member) => (
{member.email.charAt(0).toUpperCase()}

{member.email} {member.is_current_user && ( {t('members_you')} )}

{roleLabels[member.role] || member.role} {member.source === 'team' && ( {t('members_team_badge')} )}
{canInvite && !member.is_current_user && member.role !== 'owner' && member.source !== 'team' && ( )}
))}
{/* Pending invitations */} {invitations.length > 0 && ( {t('invitations_pending_title')}
{invitations.map((inv) => (

{inv.email}

{t('invitations_expires', { date: formatDateLong(inv.expires_at) })}
{roleLabels[inv.role] || inv.role} {canInvite && ( )}
))}
)}
) }